07d69588c1c7d522fe39eb5a34c623531cf11654
[openafs.git] / src / afsd / afsd.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 /*
11   *         Information Technology Center
12   *         October 1987
13   *
14   * Description:
15   *     The Andrew File System startup process.  It is responsible for
16   * reading and parsing the various configuration files, starting up
17   * the kernel processes required by AFS and feeding the configuration
18   * information to the kernel.
19   *
20   * Recognized flags are:
21   *     -blocks     The number of blocks available in the workstation cache.
22   *     -files      The target number of files in the workstation cache (Default:
23   *                 1000).
24   *     -rootvol            The name of the root volume to use.
25   *     -stat       The number of stat cache entries.
26   *     -hosts      List of servers to check for volume location info FOR THE
27   *                 HOME CELL.
28   *     -memcache   Use an in-memory cache rather than disk.
29   *     -cachedir    The base directory for the workstation cache.
30   *     -mountdir   The directory on which the AFS is to be mounted.
31   *     -confdir    The configuration directory .
32   *     -nosettime  Don't keep checking the time to avoid drift (default).
33   *     -settime    Keep checking the time to avoid drift.
34   *     -verbose     Be chatty.
35   *     -debug     Print out additional debugging info.
36   *     -kerndev    [OBSOLETE] The kernel device for AFS.
37   *     -dontfork   [OBSOLETE] Don't fork off as a new process.
38   *     -daemons   The number of background daemons to start (Default: 2).
39   *     -rmtsys    Also fires up an afs remote sys call (e.g. pioctl, setpag)
40   *                support daemon 
41   *     -chunksize [n]   2^n is the chunksize to be used.  0 is default.
42   *     -dcache    The number of data cache entries.
43   *     -biods     Number of bkg I/O daemons (AIX3.1 only)
44   *     -prealloc  Number of preallocated "small" memory blocks
45   *     -pininodes Number of inodes which can be spared from inode[] for 
46   *                pointing at Vfiles.  If this is set too high, you may have
47   *                system problems, which can only be ameliorated by changing
48   *                NINODE (or equivalent) and rebuilding the kernel.
49   *                This option is now disabled.
50   *     -logfile   [OBSOLETE] Place where to put the logfile (default in
51   *                <cache>/etc/AFSLog.
52   *     -waitclose make close calls always synchronous (slows em down, tho)
53   *     -files_per_subdir [n]   number of files per cache subdir. (def=2048)
54   *     -shutdown  Shutdown afs daemons
55   *---------------------------------------------------------------------------*/
56
57 #include <afsconfig.h>
58 #include <afs/param.h>
59
60 RCSID
61     ("$Header$");
62
63 #define VFS 1
64
65 #include <afs/cmd.h>
66
67 #include <assert.h>
68 #include <potpourri.h>
69 #include <afs/afsutil.h>
70 #include <stdlib.h>
71 #include <stdio.h>
72 #include <signal.h>
73 #include <string.h>
74 #include <stdlib.h>
75 #include <time.h>
76 #include <sys/types.h>
77 #include <sys/stat.h>
78 #include <sys/file.h>
79 #include <errno.h>
80 #include <sys/time.h>
81 #include <dirent.h>
82 #include <sys/wait.h>
83
84
85 #ifdef HAVE_SYS_PARAM_H
86 #include <sys/param.h>
87 #endif
88
89 #ifdef HAVE_SYS_FS_TYPES_H
90 #include <sys/fs_types.h>
91 #endif
92
93 #ifdef HAVE_SYS_MOUNT_H
94 #include <sys/mount.h>
95 #endif
96
97 #ifdef HAVE_SYS_FCNTL_H
98 #include <sys/fcntl.h>
99 #endif
100
101 #ifdef HAVE_SYS_MNTTAB_H
102 #include <sys/mnttab.h>
103 #endif
104
105 #ifdef HAVE_SYS_MNTENT_H
106 #include <sys/mntent.h>
107 #endif
108
109 #ifdef HAVE_MNTENT_H
110 #include <mntent.h>
111 #endif
112
113 #ifdef HAVE_SYS_MOUNT_H
114 #include <sys/mount.h>
115 #endif
116
117 #ifdef HAVE_SYS_VFS_H
118 #include <sys/vfs.h>
119 #endif
120
121 #ifdef HAVE_SYS_FSTYP_H
122 #include <sys/fstyp.h>
123 #endif
124
125 #ifdef HAVE_UNISTD_H
126 #include <unistd.h>
127 #endif
128
129 #ifdef HAVE_FCNTL_H
130 #include <fcntl.h>
131 #endif
132
133 #include <netinet/in.h>
134 #include <afs/afs_args.h>
135 #include <afs/cellconfig.h>
136 #include <ctype.h>
137 #include <afs/afssyscalls.h>
138 #include <afs/afsutil.h>
139
140 #ifdef AFS_SGI61_ENV
141 #include <unistd.h>
142 #include <libelf.h>
143 #include <dwarf.h>
144 #include <libdwarf.h>
145 void set_staticaddrs(void);
146 #endif /* AFS_SGI61_ENV */
147 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
148 #include <sym.h>
149 #include <symconst.h>
150 #endif
151 #ifdef AFS_SGI65_ENV
152 #include <sched.h>
153 #endif
154 #ifdef AFS_LINUX20_ENV
155 #include <sys/resource.h>
156 #endif
157 #ifdef AFS_DARWIN_ENV
158 #ifdef AFS_DARWIN80_ENV
159 #include <sys/ioctl.h>
160 #endif
161 #include <mach/mach.h>
162 /* Symbols from the DiskArbitration framework */
163 kern_return_t DiskArbStart(mach_port_t *);
164 kern_return_t DiskArbDiskAppearedWithMountpointPing_auto(char *, unsigned int,
165                                                          char *);
166 #define DISK_ARB_NETWORK_DISK_FLAG 8
167
168 #include <mach/mach_port.h>
169 #include <mach/mach_interface.h>
170 #include <mach/mach_init.h>
171
172 #include <CoreFoundation/CoreFoundation.h>
173
174 #include <SystemConfiguration/SystemConfiguration.h>
175 #include <SystemConfiguration/SCDynamicStore.h>
176
177 #include <IOKit/pwr_mgt/IOPMLib.h>
178 #include <IOKit/IOMessage.h>
179
180 #include <dns_sd.h>
181
182 typedef struct DNSSDState
183 {
184     DNSServiceRef       service;
185     CFRunLoopSourceRef  source;
186     CFSocketRef         socket;
187 } DNSSDState;
188
189 static io_connect_t root_port;
190 static IONotificationPortRef notify;
191 static io_object_t iterator;
192 static CFRunLoopSourceRef source;
193 static DNSSDState dnsstate;
194
195 static int event_pid;
196
197 #endif /* AFS_DARWIN_ENV */
198
199 #ifndef MOUNT_AFS
200 #define MOUNT_AFS AFS_MOUNT_AFS
201 #endif /* MOUNT_AFS */
202
203 #if AFS_HAVE_STATVFS
204 #include <sys/statvfs.h>
205 #else
206 #if defined(AFS_SUN_ENV)
207 #include <sys/vfs.h>
208 #else
209 #if !defined(AFS_OSF_ENV) && !defined(AFS_DARWIN_ENV) && !defined(AFS_XBSD_ENV)
210 #include <sys/statfs.h>
211 #endif
212 #endif
213 #endif
214
215
216 #undef  VIRTUE
217 #undef  VICE
218
219
220 #define CACHEINFOFILE   "cacheinfo"
221 #define DCACHEFILE      "CacheItems"
222 #define VOLINFOFILE     "VolumeItems"
223 #define CELLINFOFILE    "CellItems"
224
225 #define MAXIPADDRS 1024
226
227 char LclCellName[64];
228
229 #define MAX_CACHE_LOOPS 4
230
231
232 /*
233  * Internet address (old style... should be updated).  This was pulled out of the old 4.2
234  * version of <netinet/in.h>, since it's still useful.
235  */
236 struct in_addr_42 {
237     union {
238         struct {
239             u_char s_b1, s_b2, s_b3, s_b4;
240         } S_un_b;
241         struct {
242             u_short s_w1, s_w2;
243         } S_un_w;
244         afs_uint32 S_addr;
245     } S_un;
246 #define s_host  S_un.S_un_b.s_b2        /* host on imp */
247 #define s_net   S_un.S_un_b.s_b1        /* network */
248 #define s_imp   S_un.S_un_w.s_w2        /* imp */
249 #define s_impno S_un.S_un_b.s_b4        /* imp # */
250 #define s_lh    S_un.S_un_b.s_b3        /* logical host */
251 };
252
253 #define mPrintIPAddr(ipaddr)  printf("[%d.%d.%d.%d] ",          \
254       ((struct in_addr_42 *) &(ipaddr))->S_un.S_un_b.s_b1,      \
255       ((struct in_addr_42 *) &(ipaddr))->S_un.S_un_b.s_b2,      \
256       ((struct in_addr_42 *) &(ipaddr))->S_un.S_un_b.s_b3,      \
257       ((struct in_addr_42 *) &(ipaddr))->S_un.S_un_b.s_b4)
258
259 /*
260  * Global configuration variables.
261  */
262 afs_int32 enable_rxbind = 0;
263 afs_int32 afs_shutdown = 0;
264 afs_int32 cacheBlocks;          /*Num blocks in the cache */
265 afs_int32 cacheFiles;           /*Optimal # of files in workstation cache */
266 afs_int32 rwpct = 0;
267 afs_int32 ropct = 0;
268 afs_int32 cacheStatEntries;     /*Number of stat cache entries */
269 char cacheBaseDir[1024];        /*Where the workstation AFS cache lives */
270 char confDir[1024];             /*Where the workstation AFS configuration lives */
271 char fullpn_DCacheFile[1024];   /*Full pathname of DCACHEFILE */
272 char fullpn_VolInfoFile[1024];  /*Full pathname of VOLINFOFILE */
273 char fullpn_CellInfoFile[1024]; /*Full pathanem of CELLINFOFILE */
274 char fullpn_CacheInfo[1024];    /*Full pathname of CACHEINFO */
275 char fullpn_VFile[1024];        /*Full pathname of data cache files */
276 char *vFilePtr;                 /*Ptr to the number part of above pathname */
277 int sawCacheMountDir = 0;       /* from cmd line */
278 int sawCacheBaseDir = 0;
279 int sawCacheBlocks = 0;
280 int sawDCacheSize = 0;
281 int sawBiod = 0;
282 int sawCacheStatEntries = 0;
283 char cacheMountDir[1024];       /*Mount directory for AFS */
284 char rootVolume[64] = "root.afs";       /*AFS root volume name */
285 afs_int32 cacheSetTime = FALSE; /*Keep checking time to avoid drift? */
286 afs_int32 isHomeCell;           /*Is current cell info for the home cell? */
287 #ifdef AFS_XBSD_ENV
288 int createAndTrunc = O_RDWR | O_CREAT | O_TRUNC;        /*Create & truncate on open */
289 #else
290 int createAndTrunc = O_CREAT | O_TRUNC; /*Create & truncate on open */
291 #endif
292 int ownerRWmode = 0600;         /*Read/write OK by owner */
293 static int filesSet = 0;        /*True if number of files explicitly set */
294 static int nFilesPerDir = 2048; /* # files per cache dir */
295 #if defined(AFS_CACHE_BYPASS)
296 #define AFSD_NDAEMONS 4
297 #else
298 #define AFSD_NDAEMONS 2
299 #endif
300 static int nDaemons = AFSD_NDAEMONS;    /* Number of background daemons */
301 static int chunkSize = 0;       /* 2^chunkSize bytes per chunk */
302 static int dCacheSize;          /* # of dcache entries */
303 static int vCacheSize = 200;    /* # of volume cache entries */
304 static int rootVolSet = 0;      /*True if root volume name explicitly set */
305 int addrNum;                    /*Cell server address index being printed */
306 static int cacheFlags = 0;      /*Flags to cache manager */
307 static int nBiods = 5;          /* AIX3.1 only */
308 static int preallocs = 400;     /* Def # of allocated memory blocks */
309 static int enable_peer_stats = 0;       /* enable rx stats */
310 static int enable_process_stats = 0;    /* enable rx stats */
311 #ifdef AFS_AFSDB_ENV
312 static int enable_afsdb = 0;    /* enable AFSDB support */
313 #endif
314 static int enable_dynroot = 0;  /* enable dynroot support */
315 static int enable_fakestat = 0; /* enable fakestat support */
316 static int enable_backuptree = 0;       /* enable backup tree support */
317 static int enable_nomount = 0;  /* do not mount */
318 static int enable_splitcache = 0;
319 #ifdef notdef
320 static int inodes = 60;         /* VERY conservative, but has to be */
321 #endif
322 int afsd_verbose = 0;           /*Are we being chatty? */
323 int afsd_debug = 0;             /*Are we printing debugging info? */
324 int afsd_CloseSynch = 0;        /*Are closes synchronous or not? */
325
326 #ifdef AFS_SGI62_ENV
327 #define AFSD_INO_T ino64_t
328 #else
329 #define AFSD_INO_T afs_uint32
330 #endif
331 struct afsd_file_list {
332     int fileNum;
333     struct afsd_file_list *next;
334 };
335 struct afsd_file_list **cache_dir_filelist = NULL;
336 int *cache_dir_list = NULL;     /* Array of cache subdirs */
337 int *dir_for_V = NULL;          /* Array: dir of each cache file.
338                                  * -1: file does not exist
339                                  * -2: file exists in top-level
340                                  * >=0: file exists in Dxxx
341                                  */
342 #ifndef AFS_CACHE_VNODE_PATH
343 AFSD_INO_T *inode_for_V;        /* Array of inodes for desired
344                                  * cache files */
345 #endif
346 int missing_DCacheFile = 1;     /*Is the DCACHEFILE missing? */
347 int missing_VolInfoFile = 1;    /*Is the VOLINFOFILE missing? */
348 int missing_CellInfoFile = 1;   /*Is the CELLINFOFILE missing? */
349 int afsd_rmtsys = 0;            /* Default: don't support rmtsys */
350 struct afs_cacheParams cparams; /* params passed to cache manager */
351
352 static int HandleMTab();
353
354 #ifdef AFS_DARWIN_ENV
355 static void
356 afsd_sleep_callback(void * refCon, io_service_t service, 
357                     natural_t messageType, void * messageArgument )
358 {
359     afs_int32 code;
360     
361     switch (messageType) {
362     case kIOMessageCanSystemSleep:
363         /* Idle sleep is about to kick in; can 
364            prevent sleep by calling IOCancelPowerChange, otherwise 
365            if we don't ack in 30s the system sleeps anyway */
366         
367         /* allow it */
368         IOAllowPowerChange(root_port, (long)messageArgument);
369         break;
370         
371     case kIOMessageSystemWillSleep:
372         /* The system WILL go to sleep. Ack or suffer delay */
373         
374         IOAllowPowerChange(root_port, (long)messageArgument);
375         break;
376         
377     case kIOMessageSystemWillRestart:
378         /* The system WILL restart. Ack or suffer delay */
379         
380         IOAllowPowerChange(root_port, (long)messageArgument);
381         break;
382         
383     case kIOMessageSystemWillPowerOn:
384     case kIOMessageSystemHasPoweredOn:
385         /* coming back from sleep */
386         
387         IOAllowPowerChange(root_port, (long)messageArgument);
388         break;
389         
390     default:
391         IOAllowPowerChange(root_port, (long)messageArgument);
392         break;
393     }
394 }
395
396 static void
397 afsd_update_addresses(CFRunLoopTimerRef timer, void *info)
398 {
399     /* parse multihomed address files */
400     afs_int32 addrbuf[MAXIPADDRS], maskbuf[MAXIPADDRS],
401         mtubuf[MAXIPADDRS];
402     char reason[1024];
403     afs_int32 code;
404
405     code =
406         parseNetFiles(addrbuf, maskbuf, mtubuf, MAXIPADDRS, reason,
407                       AFSDIR_CLIENT_NETINFO_FILEPATH,
408                       AFSDIR_CLIENT_NETRESTRICT_FILEPATH);
409
410     if (code > 0) {
411         /* Note we're refreshing */
412         code = code | 0x40000000;
413         call_syscall(AFSOP_ADVISEADDR, code, addrbuf, maskbuf, mtubuf);
414     } else
415         printf("ADVISEADDR: Error in specifying interface addresses:%s\n",
416                reason);
417 }
418
419 /* This function is called when the system's ip addresses may have changed. */
420 static void
421 afsd_ipaddr_callback (SCDynamicStoreRef store, CFArrayRef changed_keys, void *info)
422 {
423       CFRunLoopTimerRef timer;
424
425       timer = CFRunLoopTimerCreate (NULL, CFAbsoluteTimeGetCurrent () + 1.0,
426                                     0.0, 0, 0, afsd_update_addresses, NULL);
427       CFRunLoopAddTimer (CFRunLoopGetCurrent (), timer,
428                          kCFRunLoopDefaultMode);
429       CFRelease (timer);
430 }
431
432 static void 
433 afsd_event_cleanup(int signo) {
434     DNSSDState *query = &dnsstate;
435
436     CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
437     CFRelease (source);
438     IODeregisterForSystemPower(&iterator);
439     IOServiceClose(root_port);
440     IONotificationPortDestroy(notify);
441
442     exit(0);
443 }
444
445 /* Adapted from "Living in a Dynamic TCP/IP Environment" technote. */
446 static Boolean
447 afsd_install_events(void)
448 {
449     SCDynamicStoreContext ctx = {0};
450     SCDynamicStoreRef store;
451
452     root_port = IORegisterForSystemPower(0,&notify,afsd_sleep_callback,&iterator);
453     
454     if (root_port) {
455         CFRunLoopAddSource(CFRunLoopGetCurrent(),
456                            IONotificationPortGetRunLoopSource(notify),
457                            kCFRunLoopDefaultMode);
458     }
459     
460     
461     store = SCDynamicStoreCreate (NULL,
462                                   CFSTR ("AddIPAddressListChangeCallbackSCF"),
463                                   afsd_ipaddr_callback, &ctx);
464     
465     if (store) {
466         const void *keys[1];
467         
468         /* Request IPV4 address change notification */
469         keys[0] = (SCDynamicStoreKeyCreateNetworkServiceEntity
470                    (NULL, kSCDynamicStoreDomainState,
471                     kSCCompAnyRegex, kSCEntNetIPv4));
472         
473 #if 0
474         /* This should tell us when the hostname(s) change. do we care? */
475         keys[N] = SCDynamicStoreKeyCreateHostNames (NULL);
476 #endif
477         
478         if (keys[0] != NULL) {
479             CFArrayRef pattern_array;
480             
481             pattern_array = CFArrayCreate (NULL, keys, 1,
482                                            &kCFTypeArrayCallBacks);
483             
484             if (pattern_array != NULL)
485             {
486                 SCDynamicStoreSetNotificationKeys (store, NULL, pattern_array);
487                 source = SCDynamicStoreCreateRunLoopSource (NULL, store, 0);
488                 
489                 CFRelease (pattern_array);
490             }
491             
492             if (keys[0] != NULL)
493                 CFRelease (keys[0]);
494         }
495         
496         CFRelease (store); 
497     }
498     
499     if (source != NULL) {
500         CFRunLoopAddSource (CFRunLoopGetCurrent(),
501                             source, kCFRunLoopDefaultMode);
502     }
503     
504     signal(SIGTERM, afsd_event_cleanup);
505
506     CFRunLoopRun();
507 }
508 #endif
509
510 /* ParseArgs is now obsolete, being handled by cmd */
511
512 /*------------------------------------------------------------------------------
513   * ParseCacheInfoFile
514   *
515   * Description:
516   *     Open the file containing the description of the workstation's AFS cache
517   *     and pull out its contents.  The format of this file is as follows:
518   *
519   *         cacheMountDir:cacheBaseDir:cacheBlocks
520   *
521   * Arguments:
522   *     None.
523   *
524   * Returns:
525   *     0 if everything went well,
526   *     1 otherwise.
527   *
528   * Environment:
529   *     Nothing interesting.
530   *
531   *  Side Effects:
532   *     Sets globals.
533   *---------------------------------------------------------------------------*/
534
535 int
536 ParseCacheInfoFile(void)
537 {
538     static char rn[] = "ParseCacheInfoFile";    /*This routine's name */
539     FILE *cachefd;              /*Descriptor for cache info file */
540     int parseResult;            /*Result of our fscanf() */
541     afs_int32 tCacheBlocks;
542     char tCacheBaseDir[1024], *tbd, tCacheMountDir[1024], *tmd;
543
544     if (afsd_debug)
545         printf("%s: Opening cache info file '%s'...\n", rn, fullpn_CacheInfo);
546
547     cachefd = fopen(fullpn_CacheInfo, "r");
548     if (!cachefd) {
549         printf("%s: Can't read cache info file '%s'\n", rn, fullpn_CacheInfo);
550         return (1);
551     }
552
553     /*
554      * Parse the contents of the cache info file.  All chars up to the first
555      * colon are the AFS mount directory, all chars to the next colon are the
556      * full path name of the workstation cache directory and all remaining chars
557      * represent the number of blocks in the cache.
558      */
559     tCacheMountDir[0] = tCacheBaseDir[0] = '\0';
560     parseResult =
561         fscanf(cachefd, "%1024[^:]:%1024[^:]:%d", tCacheMountDir,
562                tCacheBaseDir, &tCacheBlocks);
563
564     /*
565      * Regardless of how the parse went, we close the cache info file.
566      */
567     fclose(cachefd);
568
569     if (parseResult == EOF || parseResult < 3) {
570         printf("%s: Format error in cache info file!\n", rn);
571         if (parseResult == EOF)
572             printf("\tEOF encountered before any field parsed.\n");
573         else
574             printf("\t%d out of 3 fields successfully parsed.\n",
575                    parseResult);
576
577         return (1);
578     }
579
580     for (tmd = tCacheMountDir; *tmd == '\n' || *tmd == ' ' || *tmd == '\t';
581          tmd++);
582     for (tbd = tCacheBaseDir; *tbd == '\n' || *tbd == ' ' || *tbd == '\t';
583          tbd++);
584     /* now copy in the fields not explicitly overridden by cmd args */
585     if (!sawCacheMountDir)
586         strcpy(cacheMountDir, tmd);
587     if (!sawCacheBaseDir)
588         strcpy(cacheBaseDir, tbd);
589     if (!sawCacheBlocks)
590         cacheBlocks = tCacheBlocks;
591
592     if (afsd_debug) {
593         printf("%s: Cache info file successfully parsed:\n", rn);
594         printf
595             ("\tcacheMountDir: '%s'\n\tcacheBaseDir: '%s'\n\tcacheBlocks: %d\n",
596              tmd, tbd, tCacheBlocks);
597     }
598     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
599         return (PartSizeOverflow(tbd, cacheBlocks));
600     }
601
602     return (0);
603 }
604
605 /*
606  * All failures to open the partition are ignored. Also if the cache dir 
607  * isn't a mounted partition it's also ignored since we can't guarantee 
608  * what will be stored afterwards. Too many if's. This is now purely
609  * advisory. ODS with over 2G partition also gives warning message.
610  *
611  * Returns:
612  *      0 if everything went well,
613  *      1 otherwise.
614  */
615 int
616 PartSizeOverflow(char *path, int cs)
617 {
618     int bsize = -1, totalblks, mint;
619 #if AFS_HAVE_STATVFS
620     struct statvfs statbuf;
621
622     if (statvfs(path, &statbuf) != 0) {
623         if (afsd_debug)
624             printf
625                 ("statvfs failed on %s; skip checking for adequate partition space\n",
626                  path);
627         return 0;
628     }
629     totalblks = statbuf.f_blocks;
630     bsize = statbuf.f_frsize;
631 #if AFS_AIX51_ENV
632     if (strcmp(statbuf.f_basetype, "jfs")) {
633         fprintf(stderr, "Cache filesystem '%s' must be jfs (now %s)\n",
634                 path, statbuf.f_basetype);
635         return 1;
636     }
637 #endif /* AFS_AIX51_ENV */
638
639 #else /* AFS_HAVE_STATVFS */
640     struct statfs statbuf;
641
642     if (statfs(path, &statbuf) < 0) {
643         if (afsd_debug)
644             printf
645                 ("statfs failed on %s; skip checking for adequate partition space\n",
646                  path);
647         return 0;
648     }
649     totalblks = statbuf.f_blocks;
650     bsize = statbuf.f_bsize;
651 #endif
652     if (bsize == -1)
653         return 0;               /* sucess */
654
655     /* now free and totalblks are in fragment units, but we want them in 1K units */
656     if (bsize >= 1024) {
657         totalblks *= (bsize / 1024);
658     } else {
659         totalblks /= (1024 / bsize);
660     }
661
662     mint = totalblks / 100 * 95;
663     if (cs > mint) {
664         printf
665             ("Cache size (%d) must be less than 95%% of partition size (which is %d). Lower cache size\n",
666              cs, mint);
667         return 1;
668     }
669
670     return 0;
671 }
672
673 /*-----------------------------------------------------------------------------
674   * GetVFileNumber
675   *
676   * Description:
677   *     Given the final component of a filename expected to be a data cache file,
678   *     return the integer corresponding to the file.  Note: we reject names that
679   *     are not a ``V'' followed by an integer.  We also reject those names having
680   *     the right format but lying outside the range [0..cacheFiles-1].
681   *
682   * Arguments:
683   *     fname : Char ptr to the filename to parse.
684   *     max   : integer for the highest number to accept
685   *
686   * Returns:
687   *     >= 0 iff the file is really a data cache file numbered from 0 to cacheFiles-1, or
688   *     -1      otherwise.
689   *
690   * Environment:
691   *     Nothing interesting.
692   *
693   * Side Effects:
694   *     None.
695   *---------------------------------------------------------------------------*/
696
697 static int
698 doGetXFileNumber(fname, filechar, maxNum)
699      char *fname;
700      char filechar;
701      int maxNum;
702 {
703     int computedVNumber;        /*The computed file number we return */
704     int filenameLen;            /*Number of chars in filename */
705     int currDigit;              /*Current digit being processed */
706
707     /*
708      * The filename must have at least two characters, the first of which must be a ``filechar''
709      * and the second of which cannot be a zero unless the file is exactly two chars long.
710      */
711     filenameLen = strlen(fname);
712     if (filenameLen < 2)
713         return (-1);
714     if (fname[0] != filechar)
715         return (-1);
716     if ((filenameLen > 2) && (fname[1] == '0'))
717         return (-1);
718
719     /*
720      * Scan through the characters in the given filename, failing immediately if a non-digit
721      * is found.
722      */
723     for (currDigit = 1; currDigit < filenameLen; currDigit++)
724         if (isdigit(fname[currDigit]) == 0)
725             return (-1);
726
727     /*
728      * All relevant characters are digits.  Pull out the decimal number they represent.
729      * Reject it if it's out of range, otherwise return it.
730      */
731     computedVNumber = atoi(++fname);
732     if (computedVNumber < cacheFiles)
733         return (computedVNumber);
734     else
735         return (-1);
736 }
737
738 int
739 GetVFileNumber(fname, maxFile)
740      char *fname;
741      int maxFile;
742 {
743     return doGetXFileNumber(fname, 'V', maxFile);
744 }
745
746 int
747 GetDDirNumber(fname, maxDir)
748      char *fname;
749      int maxDir;
750 {
751     return doGetXFileNumber(fname, 'D', maxDir);
752 }
753
754
755 /*-----------------------------------------------------------------------------
756   * CreateCacheFile
757   *
758   * Description:
759   *     Given a full pathname for a file we need to create for the workstation AFS
760   *     cache, go ahead and create the file.
761   *
762   * Arguments:
763   *     fname : Full pathname of file to create.
764   *     statp : A pointer to a stat buffer which, if NON-NULL, will be
765   *             filled by fstat()
766   *
767   * Returns:
768   *     0   iff the file was created,
769   *     -1  otherwise.
770   *
771   * Environment:
772   *     The given cache file has been found to be missing.
773   *
774   * Side Effects:
775   *     As described.
776   *---------------------------------------------------------------------------*/
777
778 static int
779 CreateCacheSubDir(basename, dirNum)
780      char *basename;
781      int dirNum;
782 {
783     static char rn[] = "CreateCacheSubDir";     /* Routine Name */
784     char dir[1024];
785     int ret;
786
787     /* Build the new cache subdirectory */
788     sprintf(dir, "%s/D%d", basename, dirNum);
789
790     if (afsd_debug)
791         printf("%s: Creating cache subdir '%s'\n", rn, dir);
792
793     if ((ret = mkdir(dir, 0700)) != 0) {
794         printf("%s: Can't create '%s', error return is %d (%d)\n", rn, dir,
795                ret, errno);
796         if (errno != EEXIST)
797             return (-1);
798     }
799
800     /* Mark this directory as created */
801     cache_dir_list[dirNum] = 0;
802
803     /* And return success */
804     return (0);
805 }
806
807 static int
808 MoveCacheFile(basename, fromDir, toDir, cacheFile, maxDir)
809      char *basename;
810      int fromDir, toDir, cacheFile, maxDir;
811 {
812     static char rn[] = "MoveCacheFile";
813     char from[1024], to[1024];
814     int ret;
815
816     if (cache_dir_list[toDir] < 0
817         && (ret = CreateCacheSubDir(basename, toDir))) {
818         printf("%s: Can't create directory '%s/D%d'\n", rn, basename, toDir);
819         return ret;
820     }
821
822     /* Build the from,to dir */
823     if (fromDir < 0) {
824         /* old-style location */
825         snprintf(from, sizeof(from), "%s/V%d", basename, cacheFile);
826     } else {
827         snprintf(from, sizeof(from), "%s/D%d/V%d", basename, fromDir,
828                  cacheFile);
829     }
830
831     snprintf(to, sizeof(from), "%s/D%d/V%d", basename, toDir, cacheFile);
832
833     if (afsd_verbose)
834         printf("%s: Moving cacheFile from '%s' to '%s'\n", rn, from, to);
835
836     if ((ret = rename(from, to)) != 0) {
837         printf("%s: Can't rename '%s' to '%s', error return is %d (%d)\n", rn,
838                from, to, ret, errno);
839         return -1;
840     }
841
842     /* Reset directory pointer; fix file counts */
843     dir_for_V[cacheFile] = toDir;
844     cache_dir_list[toDir]++;
845     if (fromDir < maxDir && fromDir >= 0)
846         cache_dir_list[fromDir]--;
847
848     return 0;
849 }
850
851 int
852 CreateCacheFile(fname, statp)
853      char *fname;
854      struct stat *statp;
855 {
856     static char rn[] = "CreateCacheFile";       /*Routine name */
857     int cfd;                    /*File descriptor to AFS cache file */
858     int closeResult;            /*Result of close() */
859
860     if (afsd_debug)
861         printf("%s: Creating cache file '%s'\n", rn, fname);
862     cfd = open(fname, createAndTrunc, ownerRWmode);
863     if (cfd <= 0) {
864         printf("%s: Can't create '%s', error return is %d (%d)\n", rn, fname,
865                cfd, errno);
866         return (-1);
867     }
868     if (statp != NULL) {
869         closeResult = fstat(cfd, statp);
870         if (closeResult) {
871             printf
872                 ("%s: Can't stat newly-created AFS cache file '%s' (code %d)\n",
873                  rn, fname, errno);
874             return (-1);
875         }
876     }
877     closeResult = close(cfd);
878     if (closeResult) {
879         printf
880             ("%s: Can't close newly-created AFS cache file '%s' (code %d)\n",
881              rn, fname, errno);
882         return (-1);
883     }
884
885     return (0);
886 }
887
888 static void
889 CreateFileIfMissing(char *fullpn, int missing)
890 {
891     if (missing) {
892         if (CreateCacheFile(fullpn, NULL))
893             printf("CreateFileIfMissing: Can't create '%s'\n", fullpn);
894     }
895 }
896
897 static void
898 UnlinkUnwantedFile(char *rn, char *fullpn_FileToDelete, char *fileToDelete)
899 {
900     if (unlink(fullpn_FileToDelete)) {
901         if ((errno == EISDIR || errno == EPERM) && *fileToDelete == 'D') {
902             if (rmdir(fullpn_FileToDelete)) {
903                 printf("%s: Can't rmdir '%s', errno is %d\n", rn,
904                        fullpn_FileToDelete, errno);
905             }
906         } else
907             printf("%s: Can't unlink '%s', errno is %d\n", rn,
908                    fullpn_FileToDelete, errno);
909     }
910 }
911
912 /*-----------------------------------------------------------------------------
913   * SweepAFSCache
914   *
915   * Description:
916   *     Sweep through the AFS cache directory, recording the inode number for
917   *     each valid data cache file there.  Also, delete any file that doesn't belong
918   *     in the cache directory during this sweep, and remember which of the other
919   *     residents of this directory were seen.  After the sweep, we create any data
920   *     cache files that were missing.
921   *
922   * Arguments:
923   *     vFilesFound : Set to the number of data cache files found.
924   *
925   * Returns:
926   *     0   if everything went well,
927   *     -1 otherwise.
928   *
929   * Environment:
930   *     This routine may be called several times.  If the number of data cache files
931   *     found is less than the global cacheFiles, then the caller will need to call it
932   *     again to record the inodes of the missing zero-length data cache files created
933   *     in the previous call.
934   *
935   * Side Effects:
936   *     Fills up the global inode_for_V array, may create and/or delete files as
937   *     explained above.
938   *---------------------------------------------------------------------------*/
939
940
941 static int
942 doSweepAFSCache(vFilesFound, directory, dirNum, maxDir)
943      int *vFilesFound;
944      char *directory;           /* /path/to/cache/directory */
945      int dirNum;                /* current directory number */
946      int maxDir;                /* maximum directory number */
947 {
948     static char rn[] = "doSweepAFSCache";       /* Routine Name */
949     char fullpn_FileToDelete[1024];     /*File to be deleted from cache */
950     char *fileToDelete;         /*Ptr to last component of above */
951     DIR *cdirp;                 /*Ptr to cache directory structure */
952 #ifdef AFS_SGI62_ENV
953     struct dirent64 *currp;     /*Current directory entry */
954 #else
955     struct dirent *currp;       /*Current directory entry */
956 #endif
957     int vFileNum;               /*Data cache file's associated number */
958     int thisDir;                /* A directory number */
959     int highDir = 0;
960
961     if (afsd_debug)
962         printf("%s: Opening cache directory '%s'\n", rn, directory);
963
964     if (chmod(directory, 0700)) {       /* force it to be 700 */
965         printf("%s: Can't 'chmod 0700' the cache dir, '%s'.\n", rn,
966                directory);
967         return (-1);
968     }
969     cdirp = opendir(directory);
970     if (cdirp == (DIR *) 0) {
971         printf("%s: Can't open AFS cache directory, '%s'.\n", rn, directory);
972         return (-1);
973     }
974
975     /*
976      * Scan the directory entries, remembering data cache file inodes
977      * and the existance of other important residents.  Recurse into
978      * the data subdirectories.
979      *
980      * Delete all files and directories that don't belong here.
981      */
982     sprintf(fullpn_FileToDelete, "%s/", directory);
983     fileToDelete = fullpn_FileToDelete + strlen(fullpn_FileToDelete);
984
985 #ifdef AFS_SGI62_ENV
986     for (currp = readdir64(cdirp); currp; currp = readdir64(cdirp))
987 #else
988     for (currp = readdir(cdirp); currp; currp = readdir(cdirp))
989 #endif
990     {
991         if (afsd_debug) {
992             printf("%s: Current directory entry:\n", rn);
993 #ifdef AFS_SGI62_ENV
994             printf("\tinode=%lld, reclen=%d, name='%s'\n", currp->d_ino,
995                    currp->d_reclen, currp->d_name);
996 #else
997             printf("\tinode=%d, reclen=%d, name='%s'\n", currp->d_ino,
998                    currp->d_reclen, currp->d_name);
999 #endif
1000         }
1001
1002         /*
1003          * If dirNum < 0, we are a top-level cache directory and should
1004          * only contain sub-directories and other sundry files.  Therefore,
1005          * V-files are valid only if dirNum >= 0, and Directories are only
1006          * valid if dirNum < 0.
1007          */
1008
1009         if (*(currp->d_name) == 'V'
1010             && ((vFileNum = GetVFileNumber(currp->d_name, cacheFiles)) >=
1011                 0)) {
1012             /*
1013              * Found a valid data cache filename.  Remember this
1014              * file's inode, directory, and bump the number of files found
1015              * total and in this directory.
1016              */
1017 #ifndef AFS_CACHE_VNODE_PATH
1018             inode_for_V[vFileNum] = currp->d_ino;
1019 #endif
1020             dir_for_V[vFileNum] = dirNum;       /* remember this directory */
1021
1022             if (!maxDir) {
1023                 /* If we're in a real subdir, mark this file to be moved
1024                  * if we've already got too many files in this directory
1025                  */
1026                 assert(dirNum >= 0);
1027                 cache_dir_list[dirNum]++;       /* keep directory's file count */
1028                 if (cache_dir_list[dirNum] > nFilesPerDir) {
1029                     /* Too many files -- add to filelist */
1030                     struct afsd_file_list *tmp = (struct afsd_file_list *)
1031                         malloc(sizeof(*tmp));
1032                     if (!tmp)
1033                         printf
1034                             ("%s: MALLOC FAILED allocating file_list entry\n",
1035                              rn);
1036                     else {
1037                         tmp->fileNum = vFileNum;
1038                         tmp->next = cache_dir_filelist[dirNum];
1039                         cache_dir_filelist[dirNum] = tmp;
1040                     }
1041                 }
1042             }
1043             (*vFilesFound)++;
1044         } else if (dirNum < 0 && (*(currp->d_name) == 'D')
1045                    && GetDDirNumber(currp->d_name, 1 << 30) >= 0) {
1046             int retval = 0;
1047             if ((vFileNum = GetDDirNumber(currp->d_name, maxDir)) >= 0) {
1048                 /* Found a valid cachefile sub-Directory.  Remember this number
1049                  * and recurse into it.  Note that subdirs cannot have subdirs.
1050                  */
1051                 retval = 1;
1052             } else if ((vFileNum = GetDDirNumber(currp->d_name, 1 << 30)) >=
1053                        0) {
1054                 /* This directory is going away, but figure out if there
1055                  * are any cachefiles in here that should be saved by
1056                  * moving them to other cache directories.  This directory
1057                  * will be removed later.
1058                  */
1059                 retval = 2;
1060             }
1061
1062             /* Save the highest directory number we've seen */
1063             if (vFileNum > highDir)
1064                 highDir = vFileNum;
1065
1066             /* If this directory is staying, be sure to mark it as 'found' */
1067             if (retval == 1)
1068                 cache_dir_list[vFileNum] = 0;
1069
1070             /* Print the dirname for recursion */
1071             sprintf(fileToDelete, "%s", currp->d_name);
1072
1073             /* Note: vFileNum is the directory number */
1074             retval =
1075                 doSweepAFSCache(vFilesFound, fullpn_FileToDelete, vFileNum,
1076                                 (retval == 1 ? 0 : -1));
1077             if (retval) {
1078                 printf("%s: Recursive sweep failed on directory %s\n", rn,
1079                        currp->d_name);
1080                 return retval;
1081             }
1082         } else if (dirNum < 0 && strcmp(currp->d_name, DCACHEFILE) == 0) {
1083             /*
1084              * Found the file holding the dcache entries.
1085              */
1086             missing_DCacheFile = 0;
1087         } else if (dirNum < 0 && strcmp(currp->d_name, VOLINFOFILE) == 0) {
1088             /*
1089              * Found the file holding the volume info.
1090              */
1091             missing_VolInfoFile = 0;
1092         } else if (dirNum < 0 && strcmp(currp->d_name, CELLINFOFILE) == 0) {
1093             /*
1094              * Found the file holding the cell info.
1095              */
1096             missing_CellInfoFile = 0;
1097         } else if ((strcmp(currp->d_name, ".") == 0)
1098                    || (strcmp(currp->d_name, "..") == 0) ||
1099 #ifdef AFS_DECOSF_ENV
1100                    /* these are magic AdvFS files */
1101                    (strcmp(currp->d_name, ".tags") == 0)
1102                    || (strcmp(currp->d_name, "quota.user") == 0)
1103                    || (strcmp(currp->d_name, "quota.group") == 0) ||
1104 #endif
1105 #ifdef AFS_LINUX22_ENV
1106                    /* this is the ext3 journal file */
1107                    (strcmp(currp->d_name, ".journal") == 0) ||
1108 #endif
1109                    (strcmp(currp->d_name, "lost+found") == 0)) {
1110             /*
1111              * Don't do anything - this file is legit, and is to be left alone.
1112              */
1113         } else {
1114             /*
1115              * This file/directory doesn't belong in the cache.  Nuke it.
1116              */
1117             sprintf(fileToDelete, "%s", currp->d_name);
1118             if (afsd_verbose)
1119                 printf("%s: Deleting '%s'\n", rn, fullpn_FileToDelete);
1120             UnlinkUnwantedFile(rn, fullpn_FileToDelete, fileToDelete);
1121         }
1122     }
1123
1124     if (dirNum < 0) {
1125
1126         /*
1127          * Create all the cache files that are missing.
1128          */
1129         CreateFileIfMissing(fullpn_DCacheFile, missing_DCacheFile);
1130         CreateFileIfMissing(fullpn_VolInfoFile, missing_VolInfoFile);
1131         CreateFileIfMissing(fullpn_CellInfoFile, missing_CellInfoFile);
1132
1133         /* ADJUST CACHE FILES */
1134
1135         /* First, let's walk through the list of files and figure out
1136          * if there are any leftover files in extra directories or
1137          * missing files.  Move the former and create the latter in
1138          * subdirs with extra space.
1139          */
1140
1141         thisDir = 0;            /* Keep track of which subdir has space */
1142
1143         for (vFileNum = 0; vFileNum < cacheFiles; vFileNum++) {
1144             if (dir_for_V[vFileNum] == -1) {
1145                 /* This file does not exist.  Create it in the first
1146                  * subdir that still has extra space.
1147                  */
1148                 while (thisDir < maxDir
1149                        && cache_dir_list[thisDir] >= nFilesPerDir)
1150                     thisDir++;
1151                 if (thisDir >= maxDir)
1152                     printf("%s: can't find directory to create V%d\n", rn,
1153                            vFileNum);
1154                 else {
1155                     struct stat statb;
1156 #ifndef AFS_CACHE_VNODE_PATH
1157                     assert(inode_for_V[vFileNum] == (AFSD_INO_T) 0);
1158 #endif
1159                     sprintf(vFilePtr, "D%d/V%d", thisDir, vFileNum);
1160                     if (afsd_verbose)
1161                         printf("%s: Creating '%s'\n", rn, fullpn_VFile);
1162                     if (cache_dir_list[thisDir] < 0
1163                         && CreateCacheSubDir(directory, thisDir))
1164                         printf("%s: Can't create directory for '%s'\n", rn,
1165                                fullpn_VFile);
1166                     if (CreateCacheFile(fullpn_VFile, &statb))
1167                         printf("%s: Can't create '%s'\n", rn, fullpn_VFile);
1168                     else {
1169 #ifndef AFS_CACHE_VNODE_PATH
1170                         inode_for_V[vFileNum] = statb.st_ino;
1171 #endif
1172                         dir_for_V[vFileNum] = thisDir;
1173                         cache_dir_list[thisDir]++;
1174                         (*vFilesFound)++;
1175                     }
1176                 }
1177
1178             } else if (dir_for_V[vFileNum] >= maxDir
1179                        || dir_for_V[vFileNum] == -2) {
1180                 /* This file needs to move; move it to the first subdir
1181                  * that has extra space.  (-2 means it's in the toplevel)
1182                  */
1183                 while (thisDir < maxDir
1184                        && cache_dir_list[thisDir] >= nFilesPerDir)
1185                     thisDir++;
1186                 if (thisDir >= maxDir)
1187                     printf("%s: can't find directory to move V%d\n", rn,
1188                            vFileNum);
1189                 else {
1190                     if (MoveCacheFile
1191                         (directory, dir_for_V[vFileNum], thisDir, vFileNum,
1192                          maxDir)) {
1193                         /* Cannot move.  Ignore this file??? */
1194                         /* XXX */
1195                     }
1196                 }
1197             }
1198         }                       /* for */
1199
1200         /* At this point, we've moved all of the valid cache files
1201          * into the valid subdirs, and created all the extra
1202          * cachefiles we need to create.  Next, rebalance any subdirs
1203          * with too many cache files into the directories with not
1204          * enough cache files.  Note that thisDir currently sits at
1205          * the lowest subdir that _may_ have room.
1206          */
1207
1208         for (dirNum = 0; dirNum < maxDir; dirNum++) {
1209             struct afsd_file_list *thisFile;
1210
1211             for (thisFile = cache_dir_filelist[dirNum];
1212                  thisFile && cache_dir_list[dirNum] >= nFilesPerDir;
1213                  thisFile = thisFile->next) {
1214                 while (thisDir < maxDir
1215                        && cache_dir_list[thisDir] >= nFilesPerDir)
1216                     thisDir++;
1217                 if (thisDir >= maxDir)
1218                     printf("%s: can't find directory to move V%d\n", rn,
1219                            vFileNum);
1220                 else {
1221                     if (MoveCacheFile
1222                         (directory, dirNum, thisDir, thisFile->fileNum,
1223                          maxDir)) {
1224                         /* Cannot move.  Ignore this file??? */
1225                         /* XXX */
1226                     }
1227                 }
1228             }                   /* for each file to move */
1229         }                       /* for each directory */
1230
1231         /* Remove any directories >= maxDir -- they should be empty */
1232         for (; highDir >= maxDir; highDir--) {
1233             sprintf(fileToDelete, "D%d", highDir);
1234             UnlinkUnwantedFile(rn, fullpn_FileToDelete, fileToDelete);
1235         }
1236     }
1237
1238     /* dirNum < 0 */
1239     /*
1240      * Close the directory, return success.
1241      */
1242     if (afsd_debug)
1243         printf("%s: Closing cache directory.\n", rn);
1244     closedir(cdirp);
1245     return (0);
1246 }
1247
1248 char *
1249 CheckCacheBaseDir(char *dir)
1250 {
1251     struct stat statbuf;
1252
1253     if (!dir) {
1254         return "cache base dir not specified";
1255     }
1256     if (stat(dir, &statbuf) != 0) {
1257         return "unable to stat cache base directory";
1258     }
1259
1260     /* might want to check here for anything else goofy, like cache pointed at a non-dedicated directory, etc */
1261
1262 #ifdef AFS_LINUX24_ENV
1263     {
1264         int res;
1265         struct statfs statfsbuf;
1266
1267         res = statfs(dir, &statfsbuf);
1268         if (res != 0) {
1269             return "unable to statfs cache base directory";
1270         }
1271         if (statfsbuf.f_type == 0x52654973) {   /* REISERFS_SUPER_MAGIC */
1272             return "cannot use reiserfs as cache partition";
1273         } else if (statfsbuf.f_type == 0x58465342) {    /* XFS_SUPER_MAGIC */
1274             return "cannot use xfs as cache partition";
1275         } else if (statfsbuf.f_type == 0x01021994) {    /* TMPFS_SUPER_MAGIC */
1276             return "cannot use tmpfs as cache partition";
1277         } else if (statfsbuf.f_type != 0xEF53) {
1278             return "must use ext2 or ext3 for cache partition";
1279         }
1280     }
1281 #endif
1282
1283 #ifdef AFS_HPUX_ENV
1284     {
1285         int res;
1286         struct statfs statfsbuf;
1287         char name[FSTYPSZ];
1288
1289         res = statfs(dir, &statfsbuf);
1290         if (res != 0) {
1291             return "unable to statfs cache base directory";
1292         }
1293
1294         if (sysfs(GETFSTYP, statfsbuf.f_fsid[1], name) != 0) {
1295             return "unable to determine filesystem type for cache base dir";
1296         }
1297
1298         if (strcmp(name, "hfs")) {
1299             return "can only use hfs filesystem for cache partition on hpux";
1300         }
1301     }
1302 #endif
1303
1304 #ifdef AFS_SUN5_ENV
1305     {
1306         FILE *vfstab;
1307         struct mnttab mnt;
1308         struct stat statmnt, statci;
1309
1310         if ((stat(dir, &statci) == 0)
1311             && ((vfstab = fopen(MNTTAB, "r")) != NULL)) {
1312             while (getmntent(vfstab, &mnt) == 0) {
1313                 if (strcmp(dir, mnt.mnt_mountp) != 0) {
1314                     char *cp;
1315                     int rdev = 0;
1316
1317                     if (cp = hasmntopt(&mnt, "dev="))
1318                         rdev =
1319                             (int)strtol(cp + strlen("dev="), (char **)NULL,
1320                                         16);
1321
1322                     if ((rdev == 0) && (stat(mnt.mnt_mountp, &statmnt) == 0))
1323                         rdev = statmnt.st_dev;
1324
1325                     if ((rdev == statci.st_dev)
1326                         && (hasmntopt(&mnt, "logging") != NULL)) {
1327
1328                         fclose(vfstab);
1329                         return
1330                             "mounting a multi-use partition which contains the AFS cache with the\n\"logging\" option may deadlock your system.\n\n";
1331                     }
1332                 }
1333             }
1334
1335             fclose(vfstab);
1336         }
1337     }
1338 #endif
1339
1340     return NULL;
1341 }
1342
1343 int
1344 SweepAFSCache(vFilesFound)
1345      int *vFilesFound;
1346 {
1347     static char rn[] = "SweepAFSCache"; /*Routine name */
1348     int maxDir = (cacheFiles + nFilesPerDir - 1) / nFilesPerDir;
1349     int i;
1350
1351     *vFilesFound = 0;
1352
1353     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1354         if (afsd_debug)
1355             printf("%s: Memory Cache, no cache sweep done\n", rn);
1356         return 0;
1357     }
1358
1359     if (cache_dir_list == NULL) {
1360         cache_dir_list = (int *)malloc(maxDir * sizeof(*cache_dir_list));
1361         if (cache_dir_list == NULL) {
1362             printf("%s: Malloc Failed!\n", rn);
1363             return (-1);
1364         }
1365         for (i = 0; i < maxDir; i++)
1366             cache_dir_list[i] = -1;     /* Does not exist */
1367     }
1368
1369     if (cache_dir_filelist == NULL) {
1370         cache_dir_filelist = (struct afsd_file_list **)
1371             malloc(maxDir * sizeof(*cache_dir_filelist));
1372         if (cache_dir_filelist == NULL) {
1373             printf("%s: Malloc Failed!\n", rn);
1374             return (-1);
1375         }
1376         memset(cache_dir_filelist, 0, maxDir * sizeof(*cache_dir_filelist));
1377     }
1378
1379     if (dir_for_V == NULL) {
1380         dir_for_V = (int *)malloc(cacheFiles * sizeof(*dir_for_V));
1381         if (dir_for_V == NULL) {
1382             printf("%s: Malloc Failed!\n", rn);
1383             return (-1);
1384         }
1385         for (i = 0; i < cacheFiles; i++)
1386             dir_for_V[i] = -1;  /* Does not exist */
1387     }
1388
1389     /* Note, setting dirNum to -2 here will cause cachefiles found in
1390      * the toplevel directory to be marked in directory "-2".  This
1391      * allows us to differentiate between 'file not seen' (-1) and
1392      * 'file seen in top-level' (-2).  Then when we try to move the
1393      * file into a subdirectory, we know it's in the top-level instead
1394      * of some other cache subdir.
1395      */
1396     return doSweepAFSCache(vFilesFound, cacheBaseDir, -2, maxDir);
1397 }
1398
1399 static int
1400 ConfigCell(struct afsconf_cell *aci, void *arock, struct afsconf_dir *adir)
1401 {
1402     int isHomeCell;
1403     int i, code;
1404     afs_int32 cellFlags = 0;
1405     afs_int32 hosts[MAXHOSTSPERCELL];
1406
1407     /* figure out if this is the home cell */
1408     isHomeCell = (strcmp(aci->name, LclCellName) == 0);
1409     if (!isHomeCell)
1410         cellFlags = 2;          /* not home, suid is forbidden */
1411
1412     /* build address list */
1413     for (i = 0; i < MAXHOSTSPERCELL; i++)
1414         memcpy(&hosts[i], &aci->hostAddr[i].sin_addr, sizeof(afs_int32));
1415
1416     if (aci->linkedCell)
1417         cellFlags |= 4;         /* Flag that linkedCell arg exists,
1418                                  * for upwards compatibility */
1419
1420     /* configure one cell */
1421     code = call_syscall(AFSOP_ADDCELL2, hosts,  /* server addresses */
1422                         aci->name,      /* cell name */
1423                         cellFlags,      /* is this the home cell? */
1424                         aci->linkedCell);       /* Linked cell, if any */
1425     if (code)
1426         printf("Adding cell '%s': error %d\n", aci->name, code);
1427     return 0;
1428 }
1429
1430 static
1431 ConfigCellAlias(struct afsconf_cellalias *aca,
1432                 void *arock, struct afsconf_dir *adir)
1433 {
1434     /* push the alias into the kernel */
1435     call_syscall(AFSOP_ADDCELLALIAS, aca->aliasName, aca->realName);
1436     return 0;
1437 }
1438
1439 #ifdef AFS_AFSDB_ENV
1440 static
1441 AfsdbLookupHandler()
1442 {
1443     afs_int32 kernelMsg[64];
1444     char acellName[128];
1445     afs_int32 code;
1446     struct afsconf_cell acellInfo;
1447     int i;
1448
1449     kernelMsg[0] = 0;
1450     kernelMsg[1] = 0;
1451     acellName[0] = '\0';
1452
1453 #ifdef AFS_DARWIN_ENV
1454     /* Fork the event handler also. */
1455     code = fork();
1456     if (code == 0) {
1457         afsd_install_events();
1458         exit(1);
1459     } else if (code != -1) {
1460         event_pid = code;
1461     }
1462 #endif
1463     while (1) {
1464         /* On some platforms you only get 4 args to an AFS call */
1465         int sizeArg = ((sizeof acellName) << 16) | (sizeof kernelMsg);
1466         code =
1467             call_syscall(AFSOP_AFSDB_HANDLER, acellName, kernelMsg, sizeArg);
1468         if (code) {             /* Something is wrong? */
1469             sleep(1);
1470             continue;
1471         }
1472
1473         if (*acellName == 1)    /* Shutting down */
1474             break;
1475
1476         code = afsconf_GetAfsdbInfo(acellName, 0, &acellInfo);
1477         if (code) {
1478             kernelMsg[0] = 0;
1479             kernelMsg[1] = 0;
1480         } else {
1481             kernelMsg[0] = acellInfo.numServers;
1482             if (acellInfo.timeout)
1483                 kernelMsg[1] = acellInfo.timeout - time(0);
1484             else
1485                 kernelMsg[1] = 0;
1486             for (i = 0; i < acellInfo.numServers; i++)
1487                 kernelMsg[i + 2] = acellInfo.hostAddr[i].sin_addr.s_addr;
1488             strncpy(acellName, acellInfo.name, sizeof(acellName));
1489             acellName[sizeof(acellName) - 1] = '\0';
1490         }
1491     }
1492 #ifdef AFS_DARWIN_ENV
1493     kill(event_pid, SIGTERM);
1494 #endif
1495     exit(1);
1496 }
1497 #endif
1498
1499 #ifdef mac2
1500 #include <sys/ioctl.h>
1501 #endif /* mac2 */
1502
1503 #ifdef AFS_SGI65_ENV
1504 #define SET_RTPRI(P) {  \
1505     struct sched_param sp; \
1506     sp.sched_priority = P; \
1507     if (sched_setscheduler(0, SCHED_RR, &sp)<0) { \
1508         perror("sched_setscheduler"); \
1509     } \
1510 }
1511 #define SET_AFSD_RTPRI() SET_RTPRI(68)
1512 #define SET_RX_RTPRI()   SET_RTPRI(199)
1513 #else
1514 #ifdef AFS_LINUX20_ENV
1515 #define SET_AFSD_RTPRI()
1516 #define SET_RX_RTPRI()  do { if (setpriority(PRIO_PROCESS, 0, -10)<0) \
1517                            perror("setting rx priority"); \
1518                          } while (0)
1519 #else
1520 #define SET_AFSD_RTPRI()
1521 #define SET_RX_RTPRI()
1522 #endif
1523 #endif
1524
1525 mainproc(struct cmd_syndesc *as, void *arock)
1526 {
1527     static char rn[] = "afsd";  /*Name of this routine */
1528     afs_int32 code;             /*Result of fork() */
1529     int i;
1530     int currVFile;              /*Current AFS cache file number passed in */
1531     int mountFlags;             /*Flags passed to mount() */
1532     int lookupResult;           /*Result of GetLocalCellName() */
1533     int cacheIteration;         /*How many times through cache verification */
1534     int vFilesFound;            /*How many data cache files were found in sweep */
1535     struct afsconf_dir *cdir;   /* config dir */
1536     FILE *logfd;
1537     char *fsTypeMsg = NULL;
1538 #ifdef  AFS_SUN5_ENV
1539     struct stat st;
1540 #endif
1541     afs_int32 vfs1_type = -1;
1542 #ifdef AFS_SGI65_ENV
1543     struct sched_param sp;
1544 #endif
1545
1546 #ifdef AFS_SGI_VNODE_GLUE
1547     if (afs_init_kernel_config(-1) < 0) {
1548         printf("Can't determine NUMA configuration, not starting AFS.\n");
1549         exit(1);
1550     }
1551 #endif
1552
1553     /* call atoi on the appropriate parsed results */
1554     if (as->parms[0].items) {
1555         /* -blocks */
1556         cacheBlocks = atoi(as->parms[0].items->data);
1557         sawCacheBlocks = 1;
1558     }
1559     if (as->parms[1].items) {
1560         /* -files */
1561         cacheFiles = atoi(as->parms[1].items->data);
1562         filesSet = 1;           /* set when spec'd on cmd line */
1563     }
1564     if (as->parms[2].items) {
1565         /* -rootvol */
1566         strcpy(rootVolume, as->parms[2].items->data);
1567         rootVolSet = 1;
1568     }
1569     if (as->parms[3].items) {
1570         /* -stat */
1571         cacheStatEntries = atoi(as->parms[3].items->data);
1572         sawCacheStatEntries = 1;
1573     }
1574     if (as->parms[4].items) {
1575         /* -memcache */
1576         cacheBaseDir[0] = '\0';
1577         sawCacheBaseDir = 1;
1578         cacheFlags |= AFSCALL_INIT_MEMCACHE;
1579     }
1580     if (as->parms[5].items) {
1581         /* -cachedir */
1582         strcpy(cacheBaseDir, as->parms[5].items->data);
1583         sawCacheBaseDir = 1;
1584     }
1585     if (as->parms[6].items) {
1586         /* -mountdir */
1587         strcpy(cacheMountDir, as->parms[6].items->data);
1588         sawCacheMountDir = 1;
1589     }
1590     if (as->parms[7].items) {
1591         /* -daemons */
1592         nDaemons = atoi(as->parms[7].items->data);
1593     }
1594     if (as->parms[8].items) {
1595         /* -nosettime */
1596         cacheSetTime = FALSE;
1597     }
1598     if (as->parms[9].items) {
1599         /* -verbose */
1600         afsd_verbose = 1;
1601     }
1602     if (as->parms[10].items) {
1603         /* -rmtsys */
1604         afsd_rmtsys = 1;
1605     }
1606     if (as->parms[11].items) {
1607         /* -debug */
1608         afsd_debug = 1;
1609         afsd_verbose = 1;
1610     }
1611     if (as->parms[12].items) {
1612         /* -chunksize */
1613         chunkSize = atoi(as->parms[12].items->data);
1614         if (chunkSize < 0 || chunkSize > 30) {
1615             printf
1616                 ("afsd:invalid chunk size (not in range 0-30), using default\n");
1617             chunkSize = 0;
1618         }
1619     }
1620     if (as->parms[13].items) {
1621         /* -dcache */
1622         dCacheSize = atoi(as->parms[13].items->data);
1623         sawDCacheSize = 1;
1624     }
1625     if (as->parms[14].items) {
1626         /* -volumes */
1627         vCacheSize = atoi(as->parms[14].items->data);
1628     }
1629     if (as->parms[15].items) {
1630         /* -biods */
1631 #ifndef AFS_AIX32_ENV
1632         printf
1633             ("afsd: [-biods] currently only enabled for aix3.x VM supported systems\n");
1634 #else
1635         nBiods = atoi(as->parms[15].items->data);
1636         sawBiod = 1;
1637 #endif
1638     }
1639     if (as->parms[16].items) {
1640         /* -prealloc */
1641         preallocs = atoi(as->parms[16].items->data);
1642     }
1643 #ifdef notdef
1644     if (as->parms[17].items) {
1645         /* -pininodes */
1646         inodes = atoi(as->parms[17].items->data);
1647     }
1648 #endif
1649     strcpy(confDir, AFSDIR_CLIENT_ETC_DIRPATH);
1650     if (as->parms[17].items) {
1651         /* -confdir */
1652         strcpy(confDir, as->parms[17].items->data);
1653     }
1654     sprintf(fullpn_CacheInfo, "%s/%s", confDir, CACHEINFOFILE);
1655     if (as->parms[18].items) {
1656         /* -logfile */
1657         printf("afsd: Ignoring obsolete -logfile flag\n");
1658     }
1659     if (as->parms[19].items) {
1660         /* -waitclose */
1661         afsd_CloseSynch = 1;
1662     }
1663     if (as->parms[20].items) {
1664         /* -shutdown */
1665         afs_shutdown = 1;
1666         /* 
1667          * Cold shutdown is the default
1668          */
1669         printf("afsd: Shutting down all afs processes and afs state\n");
1670         code = call_syscall(AFSOP_SHUTDOWN, 1);
1671         if (code) {
1672             printf("afsd: AFS still mounted; Not shutting down\n");
1673             exit(1);
1674         }
1675         exit(0);
1676     }
1677     if (as->parms[21].items) {
1678         /* -enable_peer_stats */
1679         enable_peer_stats = 1;
1680     }
1681     if (as->parms[22].items) {
1682         /* -enable_process_stats */
1683         enable_process_stats = 1;
1684     }
1685     if (as->parms[23].items) {
1686         /* -mem_alloc_sleep */
1687         cacheFlags |= AFSCALL_INIT_MEMCACHE_SLEEP;
1688     }
1689     if (as->parms[24].items) {
1690         /* -afsdb */
1691 #ifdef AFS_AFSDB_ENV
1692         enable_afsdb = 1;
1693 #else
1694         printf("afsd: No AFSDB support; ignoring -afsdb");
1695 #endif
1696     }
1697     if (as->parms[25].items) {
1698         /* -files_per_subdir */
1699         int res = atoi(as->parms[25].items->data);
1700         if (res < 10 || res > (1 << 30)) {
1701             printf
1702                 ("afsd:invalid number of files per subdir, \"%s\". Ignored\n",
1703                  as->parms[25].items->data);
1704         } else {
1705             nFilesPerDir = res;
1706         }
1707     }
1708     if (as->parms[26].items) {
1709         /* -dynroot */
1710         enable_dynroot = 1;
1711     }
1712     if (as->parms[27].items) {
1713         /* -fakestat */
1714         enable_fakestat = 2;
1715     }
1716     if (as->parms[28].items) {
1717         /* -fakestat-all */
1718         enable_fakestat = 1;
1719     }
1720     if (as->parms[29].items) {
1721         /* -nomount */
1722         enable_nomount = 1;
1723     }
1724     if (as->parms[30].items) {
1725         /* -backuptree */
1726         enable_backuptree = 1;
1727     }
1728     if (as->parms[31].items) {
1729         /* -rxbind */
1730         enable_rxbind = 1;
1731     }
1732     if (as->parms[32].items) {
1733         /* -settime */
1734         cacheSetTime = TRUE;
1735     }
1736
1737     /* set rx_extraPackets */
1738     if (as->parms[33].items) {
1739         /* -rxpck */
1740         int rxpck = atoi(as->parms[33].items->data);
1741         printf("afsd: set rxpck = %d\n", rxpck);
1742         code = call_syscall(AFSOP_SET_RXPCK, rxpck);
1743         if (code) {
1744             printf("afsd: failed to set rxpck\n");
1745             exit(1);
1746         }
1747     }
1748     if (as->parms[34].items) {
1749         char *c;
1750         if (!as->parms[34].items->data ||
1751             ((c = strchr(as->parms[34].items->data, '/')) == NULL))
1752             printf
1753                 ("ignoring splitcache (specify as RW/RO percentages: 60/40)\n");
1754         else {
1755             ropct = atoi((char *)c + 1);
1756             *c = '\0';
1757             rwpct = atoi((char *)as->parms[30].items->data);
1758             if ((rwpct != 0) && (ropct != 0) && (ropct + rwpct == 100)) {
1759                 /* -splitcache */
1760                 enable_splitcache = 1;
1761             }
1762         }
1763     }
1764     /*
1765      * Pull out all the configuration info for the workstation's AFS cache and
1766      * the cellular community we're willing to let our users see.
1767      */
1768     cdir = afsconf_Open(confDir);
1769     if (!cdir) {
1770         printf("afsd: some file missing or bad in %s\n", confDir);
1771         exit(1);
1772     }
1773
1774     lookupResult =
1775         afsconf_GetLocalCell(cdir, LclCellName, sizeof(LclCellName));
1776     if (lookupResult) {
1777         printf("%s: Can't get my home cell name!  [Error is %d]\n", rn,
1778                lookupResult);
1779     } else {
1780         if (afsd_verbose)
1781             printf("%s: My home cell is '%s'\n", rn, LclCellName);
1782     }
1783
1784     /* parse cacheinfo file if this is a diskcache */
1785     if (ParseCacheInfoFile()) {
1786         exit(1);
1787     }
1788
1789     /* do some random computations in memcache case to get things to work
1790      * reasonably no matter which parameters you set.
1791      */
1792     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1793         /* memory cache: size described either as blocks or dcache entries, but
1794          * not both.
1795          */
1796         if (filesSet) {
1797             fprintf(stderr, "%s: -files ignored with -memcache\n", rn);
1798         }
1799         if (sawDCacheSize) {
1800             if (chunkSize == 0) {
1801                 chunkSize = 13; /* 8k default chunksize for memcache */
1802             }
1803             if (sawCacheBlocks) {
1804                 printf
1805                     ("%s: can't set cache blocks and dcache size simultaneously when diskless.\n",
1806                      rn);
1807                 exit(1);
1808             }
1809             /* compute the cache size based on # of chunks times the chunk size */
1810             i = (1 << chunkSize);       /* bytes per chunk */
1811             cacheBlocks = i * dCacheSize;
1812             sawCacheBlocks = 1; /* so that ParseCacheInfoFile doesn't overwrite */
1813         } else {
1814             if (chunkSize == 0) {
1815                 /* Try to autotune the memcache chunksize based on size
1816                  * of memcache. This is done on the assumption that approx
1817                  * 1024 chunks is suitable, it's a balance between enough
1818                  * chunks to be useful and ramping up nicely when using larger
1819                  * memcache to improve bulk read/write performance
1820                  */
1821                 for (i = 14;
1822                      i <= 21 && (1 << i) / 1024 < (cacheBlocks / 1024); i++);
1823                 chunkSize = i - 1;
1824             }
1825             /* compute the dcache size from overall cache size and chunk size */
1826             if (chunkSize > 10) {
1827                 dCacheSize = (cacheBlocks >> (chunkSize - 10));
1828             } else if (chunkSize < 10) {
1829                 dCacheSize = (cacheBlocks << (10 - chunkSize));
1830             } else {
1831                 dCacheSize = cacheBlocks;
1832             }
1833             /* don't have to set sawDCacheSize here since it isn't overwritten
1834              * by ParseCacheInfoFile.
1835              */
1836         }
1837         if (afsd_verbose)
1838             printf("%s: chunkSize autotuned to %d\n", rn, chunkSize);
1839
1840         /* kernel computes # of dcache entries as min of cacheFiles and
1841          * dCacheSize, so we now make them equal.
1842          */
1843         cacheFiles = dCacheSize;
1844     } else {
1845         /* Disk cache:
1846          * Compute the number of cache files based on cache size,
1847          * but only if -files isn't given on the command line.
1848          * Don't let # files be so small as to prevent full utilization 
1849          * of the cache unless user has explicitly asked for it.
1850          */
1851         if (chunkSize == 0) {
1852             /* Set chunksize to 256kB - 1MB depending on cache size */
1853             if (cacheBlocks < 500000) {
1854                 chunkSize = 18;
1855             } else if (cacheBlocks < 1000000) {
1856                 chunkSize = 19;
1857             } else {
1858                 chunkSize = 20;
1859             }
1860         }
1861         if (!filesSet) {
1862             cacheFiles = cacheBlocks / 32;      /* Assume 32k avg filesize */
1863
1864             cacheFiles = max(cacheFiles, 1000);
1865
1866             /* Always allow more files than chunks.  Presume average V-file 
1867              * is ~67% of a chunk...  (another guess, perhaps Honeyman will
1868              * have a grad student write a paper).  i is KILOBYTES.
1869              */
1870             i = 1 << (chunkSize < 10 ? 0 : chunkSize - 10);
1871             cacheFiles = max(cacheFiles, 1.5 * (cacheBlocks / i));
1872
1873             /* never permit more files than blocks, while leaving space for
1874              * VolumeInfo and CacheItems files.  VolumeInfo is usually 20K,
1875              * CacheItems is 50 Bytes / file (== 1K/20)
1876              */
1877 #define CACHEITMSZ (cacheFiles / 20)
1878 #define VOLINFOSZ 50            /* 40kB has been seen, be conservative */
1879 #define CELLINFOSZ 4            /* Assuming disk block size is 4k ... */
1880 #define INFOSZ (VOLINFOSZ+CELLINFOSZ+CACHEITMSZ)
1881
1882             /* Sanity check: If the obtained number of disk cache files
1883              * is larger than the number of available (4k) disk blocks, we're
1884              * doing something wrong. Fail hard so we can fix the bug instead
1885              * of silently hiding it like before */
1886
1887             if (cacheFiles > (cacheBlocks - INFOSZ) / 4) {
1888                 fprintf(stderr,
1889                         "%s: ASSERT: cacheFiles %d  diskblocks %d\n",
1890                         rn, cacheFiles, (cacheBlocks - INFOSZ) / 4);
1891                 exit(1);
1892             }
1893             if (cacheFiles < 100)
1894                 fprintf(stderr, "%s: WARNING: cache probably too small!\n",
1895                         rn);
1896
1897             if (afsd_verbose)
1898                 printf("%s: cacheFiles autotuned to %d\n", rn, cacheFiles);
1899         }
1900 #if 0
1901        /* This actually needs to
1902           1) use powers of 2
1903           2) not second-guess when a chunksize comes from the command line
1904           3) be less, um, small. 2^2?? 
1905        */
1906         /* Sanity check chunkSize */
1907         i = max(cacheBlocks / 1000, cacheBlocks / cacheFiles);
1908         chunkSize = min(chunkSize, i);
1909         chunkSize = max(chunkSize, 2);
1910         if (afsd_verbose)
1911             printf("%s: chunkSize autotuned to %d\n", rn, chunkSize);
1912 #endif
1913
1914         if (!sawDCacheSize) {
1915             dCacheSize = cacheFiles / 2;
1916             if (dCacheSize > 10000) {
1917                 dCacheSize = 10000;
1918             }
1919             if (dCacheSize < 2000) {
1920                 dCacheSize = 2000;
1921             }
1922             if (afsd_verbose)
1923                 printf("%s: dCacheSize autotuned to %d\n", rn, dCacheSize);
1924         }
1925     }
1926     if (!sawCacheStatEntries) {
1927         if (chunkSize <= 13) {
1928             cacheStatEntries = dCacheSize / 4;
1929         } else if (chunkSize >= 16) {
1930             cacheStatEntries = dCacheSize * 1.5;
1931         } else {
1932             cacheStatEntries = dCacheSize;
1933         }
1934         if (afsd_verbose)
1935             printf("%s: cacheStatEntries autotuned to %d\n", rn,
1936                    cacheStatEntries);
1937     }
1938
1939 #ifndef AFS_CACHE_VNODE_PATH
1940     /*
1941      * Create and zero the inode table for the desired cache files.
1942      */
1943     inode_for_V = (AFSD_INO_T *) malloc(cacheFiles * sizeof(AFSD_INO_T));
1944     if (inode_for_V == (AFSD_INO_T *) 0) {
1945         printf
1946             ("%s: malloc() failed for cache file inode table with %d entries.\n",
1947              rn, cacheFiles);
1948         exit(1);
1949     }
1950     memset(inode_for_V, '\0', (cacheFiles * sizeof(AFSD_INO_T)));
1951     if (afsd_debug)
1952         printf("%s: %d inode_for_V entries at 0x%x, %d bytes\n", rn,
1953                cacheFiles, inode_for_V, (cacheFiles * sizeof(AFSD_INO_T)));
1954 #endif
1955
1956     /*
1957      * Set up all the pathnames we'll need for later.
1958      */
1959     sprintf(fullpn_DCacheFile, "%s/%s", cacheBaseDir, DCACHEFILE);
1960     sprintf(fullpn_VolInfoFile, "%s/%s", cacheBaseDir, VOLINFOFILE);
1961     sprintf(fullpn_CellInfoFile, "%s/%s", cacheBaseDir, CELLINFOFILE);
1962     sprintf(fullpn_VFile, "%s/", cacheBaseDir);
1963     vFilePtr = fullpn_VFile + strlen(fullpn_VFile);
1964
1965     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)
1966         && (fsTypeMsg = CheckCacheBaseDir(cacheBaseDir))) {
1967 #ifdef AFS_SUN5_ENV
1968         printf("%s: WARNING: Cache dir check failed (%s)\n", rn, fsTypeMsg);
1969 #else
1970         printf("%s: ERROR: Cache dir check failed (%s)\n", rn, fsTypeMsg);
1971         exit(1);
1972 #endif
1973     }
1974
1975     /*
1976      * Set up all the kernel processes needed for AFS.
1977      */
1978 #ifdef mac2
1979     setpgrp(getpid(), 0);
1980 #endif /* mac2 */
1981
1982     /* Initialize RX daemons and services */
1983
1984     /* initialize the rx random number generator from user space */
1985     {
1986         /* parse multihomed address files */
1987         afs_int32 addrbuf[MAXIPADDRS], maskbuf[MAXIPADDRS],
1988             mtubuf[MAXIPADDRS];
1989         char reason[1024];
1990         code =
1991             parseNetFiles(addrbuf, maskbuf, mtubuf, MAXIPADDRS, reason,
1992                           AFSDIR_CLIENT_NETINFO_FILEPATH,
1993                           AFSDIR_CLIENT_NETRESTRICT_FILEPATH);
1994         if (code > 0) {
1995             if (enable_rxbind)
1996                 code = code | 0x80000000;
1997             call_syscall(AFSOP_ADVISEADDR, code, addrbuf, maskbuf, mtubuf);
1998         } else
1999             printf("ADVISEADDR: Error in specifying interface addresses:%s\n",
2000                    reason);
2001     }
2002
2003     /* Set realtime priority for most threads to same as for biod's. */
2004     SET_AFSD_RTPRI();
2005
2006 #ifdef  AFS_SGI53_ENV
2007 #ifdef AFS_SGI61_ENV
2008     set_staticaddrs();
2009 #else /* AFS_SGI61_ENV */
2010     code = get_nfsstaticaddr();
2011     if (code)
2012         call_syscall(AFSOP_NFSSTATICADDR, code);
2013 #endif /* AFS_SGI61_ENV */
2014 #endif /* AFS_SGI_53_ENV */
2015
2016     /* Start listener, then callback listener. Lastly, start rx event daemon.
2017      * Change in ordering is so that Linux port has socket fd in listener
2018      * process.
2019      * preallocs are passed for both listener and callback server. Only
2020      * the one which actually does the initialization uses them though.
2021      */
2022     if (preallocs < cacheStatEntries + 50)
2023         preallocs = cacheStatEntries + 50;
2024 #ifdef RXK_LISTENER_ENV
2025     if (afsd_verbose)
2026         printf("%s: Forking rx listener daemon.\n", rn);
2027     code = fork();
2028     if (code == 0) {
2029         /* Child */
2030         SET_RX_RTPRI();         /* max advised for non-interrupts */
2031         call_syscall(AFSOP_RXLISTENER_DAEMON, preallocs, enable_peer_stats,
2032                      enable_process_stats);
2033         exit(1);
2034     }
2035 #ifdef AFS_SUN510_ENV
2036     waitpid((pid_t) -1, NULL, 0);
2037 #endif
2038 #endif
2039     if (afsd_verbose)
2040         printf("%s: Forking rx callback listener.\n", rn);
2041     code = fork();
2042     if (code == 0) {
2043         /* Child */
2044         call_syscall(AFSOP_START_RXCALLBACK, preallocs);
2045         exit(1);
2046     }
2047 #if defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV)
2048     if (afsd_verbose)
2049         printf("%s: Forking rxevent daemon.\n", rn);
2050     code = fork();
2051     if (code == 0) {
2052         /* Child */
2053         SET_RX_RTPRI();         /* max advised for non-interrupts */
2054         call_syscall(AFSOP_RXEVENT_DAEMON);
2055         exit(1);
2056     }
2057 #endif
2058
2059 #ifdef AFS_AFSDB_ENV
2060     if (enable_afsdb) {
2061         if (afsd_verbose)
2062             printf("%s: Forking AFSDB lookup handler.\n", rn);
2063         code = fork();
2064         if (code == 0) {
2065             /* Since the AFSDB lookup handler runs as a user process, 
2066              * need to drop the controlling TTY, etc.
2067              */
2068             if (daemon(0, 0) == -1) {
2069                 printf("Error starting AFSDB lookup handler: %s\n",
2070                        strerror(errno));
2071                 exit(1);
2072             }
2073             AfsdbLookupHandler();
2074             exit(1);
2075         }
2076     }
2077 #endif
2078
2079     code = call_syscall(AFSOP_BASIC_INIT, 1);
2080     if (code) {
2081         printf("%s: Error %d in basic initialization.\n", rn, code);
2082         exit(1);
2083     }
2084
2085     /*
2086      * Tell the kernel some basic information about the workstation's cache.
2087      */
2088     if (afsd_verbose)
2089         printf
2090             ("%s: Calling AFSOP_CACHEINIT: %d stat cache entries, %d optimum cache files, %d blocks in the cache, flags = 0x%x, dcache entries %d\n",
2091              rn, cacheStatEntries, cacheFiles, cacheBlocks, cacheFlags,
2092              dCacheSize);
2093     memset(&cparams, '\0', sizeof(cparams));
2094     cparams.cacheScaches = cacheStatEntries;
2095     cparams.cacheFiles = cacheFiles;
2096     cparams.cacheBlocks = cacheBlocks;
2097     cparams.cacheDcaches = dCacheSize;
2098     cparams.cacheVolumes = vCacheSize;
2099     cparams.chunkSize = chunkSize;
2100     cparams.setTimeFlag = cacheSetTime;
2101     cparams.memCacheFlag = cacheFlags;
2102 #ifdef notdef
2103     cparams.inodes = inodes;
2104 #endif
2105     call_syscall(AFSOP_CACHEINIT, &cparams);
2106
2107     /* do it before we init the cache inodes */
2108     if (enable_splitcache) {
2109         call_syscall(AFSOP_BUCKETPCT, 1, rwpct);
2110         call_syscall(AFSOP_BUCKETPCT, 2, ropct);
2111     }
2112
2113     if (afsd_CloseSynch)
2114         call_syscall(AFSOP_CLOSEWAIT);
2115
2116     /*
2117      * Sweep the workstation AFS cache directory, remembering the inodes of
2118      * valid files and deleting extraneous files.  Keep sweeping until we
2119      * have the right number of data cache files or we've swept too many
2120      * times.
2121      *
2122      * This also creates files in the cache directory like VolumeItems and
2123      * CellItems, and thus must be ran before those are sent to the kernel.
2124      */
2125     if (afsd_verbose)
2126         printf("%s: Sweeping workstation's AFS cache directory.\n", rn);
2127     cacheIteration = 0;
2128     /* Memory-cache based system doesn't need any of this */
2129     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
2130         do {
2131             cacheIteration++;
2132             if (SweepAFSCache(&vFilesFound)) {
2133                 printf("%s: Error on sweep %d of workstation AFS cache \
2134                        directory.\n", rn, cacheIteration);
2135                 exit(1);
2136             }
2137             if (afsd_verbose)
2138                 printf
2139                     ("%s: %d out of %d data cache files found in sweep %d.\n",
2140                      rn, vFilesFound, cacheFiles, cacheIteration);
2141         } while ((vFilesFound < cacheFiles)
2142                  && (cacheIteration < MAX_CACHE_LOOPS));
2143 #ifdef AFS_CACHE_VNODE_PATH
2144         if (afsd_debug)
2145             printf
2146                 ("%s: Calling AFSOP_CACHEBASEDIR with '%s'\n",
2147                  rn, cacheBaseDir);
2148         call_syscall(AFSOP_CACHEBASEDIR, cacheBaseDir);
2149         if (afsd_debug)
2150             printf
2151                 ("%s: Calling AFSOP_CACHEDIRS with %d dirs\n",
2152                  rn, nFilesPerDir);
2153         call_syscall(AFSOP_CACHEDIRS, nFilesPerDir);
2154         if (afsd_debug)
2155             printf
2156                 ("%s: Calling AFSOP_CACHEFILES with %d files\n",
2157                  rn, cacheFiles);
2158         call_syscall(AFSOP_CACHEFILES, cacheFiles);
2159 #endif
2160     } else if (afsd_verbose)
2161         printf("%s: Using memory cache, not swept\n", rn);
2162
2163     /*
2164      * Pass the kernel the name of the workstation cache file holding the 
2165      * dcache entries.
2166      */
2167     if (afsd_debug)
2168         printf("%s: Calling AFSOP_CACHEINFO: dcache file is '%s'\n", rn,
2169                fullpn_DCacheFile);
2170     /* once again, meaningless for a memory-based cache. */
2171     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))
2172         call_syscall(AFSOP_CACHEINFO, fullpn_DCacheFile);
2173
2174     /*
2175      * Pass the kernel the name of the workstation cache file holding the
2176      * cell information.
2177      */
2178     if (afsd_debug)
2179         printf("%s: Calling AFSOP_CELLINFO: cell info file is '%s'\n", rn,
2180                fullpn_CellInfoFile);
2181     call_syscall(AFSOP_CELLINFO, fullpn_CellInfoFile);
2182
2183     if (enable_dynroot) {
2184         if (afsd_verbose)
2185             printf("%s: Enabling dynroot support in kernel.\n", rn);
2186         code = call_syscall(AFSOP_SET_DYNROOT, 1);
2187         if (code)
2188             printf("%s: Error enabling dynroot support.\n", rn);
2189     }
2190
2191     if (enable_fakestat) {
2192         if (afsd_verbose)
2193             printf("%s: Enabling fakestat support in kernel.\n", rn);
2194         code = call_syscall(AFSOP_SET_FAKESTAT, enable_fakestat);
2195         if (code)
2196             printf("%s: Error enabling fakestat support.\n", rn);
2197     }
2198
2199     if (enable_backuptree) {
2200         if (afsd_verbose)
2201             printf("%s: Enabling backup tree support in kernel.\n", rn);
2202         code = call_syscall(AFSOP_SET_BACKUPTREE, enable_backuptree);
2203         if (code)
2204             printf("%s: Error enabling backup tree support.\n", rn);
2205     }
2206
2207     /*
2208      * Tell the kernel about each cell in the configuration.
2209      */
2210     afsconf_CellApply(cdir, ConfigCell, NULL);
2211     afsconf_CellAliasApply(cdir, ConfigCellAlias, NULL);
2212
2213     /*
2214      * Set the primary cell name.
2215      */
2216     call_syscall(AFSOP_SET_THISCELL, LclCellName);
2217
2218     /* Initialize AFS daemon threads. */
2219     if (afsd_verbose)
2220         printf("%s: Forking AFS daemon.\n", rn);
2221     code = fork();
2222     if (code == 0) {
2223         /* Child */
2224         call_syscall(AFSOP_START_AFS);
2225         exit(1);
2226     }
2227
2228     if (afsd_verbose)
2229         printf("%s: Forking Check Server Daemon.\n", rn);
2230     code = fork();
2231     if (code == 0) {
2232         /* Child */
2233         code = call_syscall(AFSOP_START_CS);
2234         if (code)
2235             printf("%s: No check server daemon in client.\n", rn);
2236         exit(1);
2237     }
2238
2239     if (afsd_verbose)
2240         printf("%s: Forking %d background daemons.\n", rn, nDaemons);
2241 #if defined(AFS_SGI_ENV) && defined(AFS_SGI_SHORTSTACK)
2242     /* Add one because for sgi we always "steal" the first daemon for a
2243      * different task if we only have a 4K stack.
2244      */
2245     nDaemons++;
2246 #endif
2247     for (i = 0; i < nDaemons; i++) {
2248         code = fork();
2249         if (code == 0) {
2250             /* Child */
2251 #ifdef  AFS_AIX32_ENV
2252             call_syscall(AFSOP_START_BKG, 0);
2253 #else
2254             call_syscall(AFSOP_START_BKG);
2255 #endif
2256             exit(1);
2257         }
2258     }
2259 #ifdef  AFS_AIX32_ENV
2260     if (!sawBiod)
2261         nBiods = nDaemons * 2;
2262     if (nBiods < 5)
2263         nBiods = 5;
2264     for (i = 0; i < nBiods; i++) {
2265         code = fork();
2266         if (code == 0) {        /* Child */
2267             call_syscall(AFSOP_START_BKG, nBiods);
2268             exit(1);
2269         }
2270     }
2271 #endif
2272
2273     /*
2274      * If the root volume has been explicitly set, tell the kernel.
2275      */
2276     if (rootVolSet) {
2277         if (afsd_verbose)
2278             printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n", rn,
2279                    rootVolume);
2280         call_syscall(AFSOP_ROOTVOLUME, rootVolume);
2281     }
2282
2283     /*
2284      * Pass the kernel the name of the workstation cache file holding the
2285      * volume information.
2286      */
2287     if (afsd_debug)
2288         printf("%s: Calling AFSOP_VOLUMEINFO: volume info file is '%s'\n", rn,
2289                fullpn_VolInfoFile);
2290     /* once again, meaningless for a memory-based cache. */
2291     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))
2292         call_syscall(AFSOP_VOLUMEINFO, fullpn_VolInfoFile);
2293
2294 #ifndef AFS_CACHE_VNODE_PATH
2295     /*
2296      * Give the kernel the names of the AFS files cached on the workstation's
2297      * disk.
2298      */
2299     if (afsd_debug)
2300         printf
2301             ("%s: Calling AFSOP_CACHEINODE for each of the %d files in '%s'\n",
2302              rn, cacheFiles, cacheBaseDir);
2303     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))  /* ... and again ... */
2304         for (currVFile = 0; currVFile < cacheFiles; currVFile++) {
2305 #ifdef AFS_SGI62_ENV
2306             call_syscall(AFSOP_CACHEINODE,
2307                          (afs_uint32) (inode_for_V[currVFile] >> 32),
2308                          (afs_uint32) (inode_for_V[currVFile] & 0xffffffff));
2309 #else
2310             call_syscall(AFSOP_CACHEINODE, inode_for_V[currVFile]);
2311 #endif
2312         }
2313 #endif
2314
2315     /*end for */
2316     /*
2317      * All the necessary info has been passed into the kernel to run an AFS
2318      * system.  Give the kernel our go-ahead.
2319      */
2320     if (afsd_debug)
2321         printf("%s: Calling AFSOP_GO with cacheSetTime = %d\n", rn,
2322                cacheSetTime);
2323     call_syscall(AFSOP_GO, cacheSetTime);
2324
2325     /*
2326      * At this point, we have finished passing the kernel all the info 
2327      * it needs to set up the AFS.  Mount the AFS root.
2328      */
2329     printf("%s: All AFS daemons started.\n", rn);
2330
2331     if (afsd_verbose)
2332         printf("%s: Forking trunc-cache daemon.\n", rn);
2333     code = fork();
2334     if (code == 0) {
2335         /* Child */
2336         call_syscall(AFSOP_START_TRUNCDAEMON);
2337         exit(1);
2338     }
2339
2340     if (!enable_nomount) {
2341
2342         mountFlags = 0;         /* Read/write file system, can do setuid() */
2343 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
2344 #ifdef  AFS_SUN5_ENV
2345         mountFlags |= MS_DATA;
2346 #else
2347         mountFlags |= M_NEWTYPE;        /* This searches by name in vfs_conf.c so don't need to recompile vfs.c because MOUNT_MAXTYPE has changed; it seems that Sun fixed this at last... */
2348 #endif
2349 #endif
2350
2351 #if defined(AFS_HPUX100_ENV)
2352         mountFlags |= MS_DATA;
2353 #endif
2354
2355         if (afsd_verbose)
2356             printf("%s: Mounting the AFS root on '%s', flags: %d.\n", rn,
2357                    cacheMountDir, mountFlags);
2358 #if defined(AFS_FBSD60_ENV)
2359         /* data must be non-NULL but is otherwise ignored */
2360         if ((mount(MOUNT_AFS, cacheMountDir, mountFlags, rn)) < 0) {
2361 #elif defined(AFS_FBSD_ENV)
2362         if ((mount("AFS", cacheMountDir, mountFlags, (caddr_t) 0)) < 0) {
2363 #elif defined(AFS_AIX_ENV)
2364         if (aix_vmount()) {
2365 #elif defined(AFS_HPUX100_ENV)
2366         if ((mount("", cacheMountDir, mountFlags, "afs", NULL, 0)) < 0) {
2367 #elif defined(AFS_SUN5_ENV)
2368         if ((mount("AFS", cacheMountDir, mountFlags, "afs", NULL, 0)) < 0) {
2369 #elif defined(AFS_SGI_ENV)
2370         mountFlags = MS_FSS;
2371         if ((mount(MOUNT_AFS, cacheMountDir, mountFlags, (caddr_t) MOUNT_AFS))
2372             < 0) {
2373 #elif defined(AFS_LINUX20_ENV)
2374         if ((mount("AFS", cacheMountDir, MOUNT_AFS, 0, NULL)) < 0) {
2375 #else
2376 /* This is the standard mount used by the suns and rts */
2377         if ((mount(MOUNT_AFS, cacheMountDir, mountFlags, (caddr_t) 0)) < 0) {
2378 #endif
2379             printf("%s: Can't mount AFS on %s(%d)\n", rn, cacheMountDir,
2380                    errno);
2381             exit(1);
2382         }
2383
2384         HandleMTab();
2385
2386     }
2387
2388     if (afsd_rmtsys) {
2389         if (afsd_verbose)
2390             printf("%s: Forking 'rmtsys' daemon.\n", rn);
2391         code = fork();
2392         if (code == 0) {
2393             /* Child */
2394             rmtsysd();
2395             exit(1);
2396         }
2397     }
2398     /*
2399      * Exit successfully.
2400      */
2401     exit(0);
2402 }
2403
2404 #include "AFS_component_version_number.c"
2405
2406
2407
2408 main(int argc, char **argv)
2409 {
2410     struct cmd_syndesc *ts;
2411
2412     ts = cmd_CreateSyntax(NULL, mainproc, NULL, "start AFS");
2413     cmd_AddParm(ts, "-blocks", CMD_SINGLE, CMD_OPTIONAL,
2414                 "1024 byte blocks in cache");
2415     cmd_AddParm(ts, "-files", CMD_SINGLE, CMD_OPTIONAL, "files in cache");
2416     cmd_AddParm(ts, "-rootvol", CMD_SINGLE, CMD_OPTIONAL,
2417                 "name of AFS root volume");
2418     cmd_AddParm(ts, "-stat", CMD_SINGLE, CMD_OPTIONAL,
2419                 "number of stat entries");
2420     cmd_AddParm(ts, "-memcache", CMD_FLAG, CMD_OPTIONAL, "run diskless");
2421     cmd_AddParm(ts, "-cachedir", CMD_SINGLE, CMD_OPTIONAL, "cache directory");
2422     cmd_AddParm(ts, "-mountdir", CMD_SINGLE, CMD_OPTIONAL, "mount location");
2423     cmd_AddParm(ts, "-daemons", CMD_SINGLE, CMD_OPTIONAL,
2424                 "number of daemons to use");
2425     cmd_AddParm(ts, "-nosettime", CMD_FLAG, CMD_OPTIONAL,
2426                 "don't set the time");
2427     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL,
2428                 "display lots of information");
2429     cmd_AddParm(ts, "-rmtsys", CMD_FLAG, CMD_OPTIONAL,
2430                 "start NFS rmtsysd program");
2431     cmd_AddParm(ts, "-debug", CMD_FLAG, CMD_OPTIONAL, "display debug info");
2432     cmd_AddParm(ts, "-chunksize", CMD_SINGLE, CMD_OPTIONAL,
2433                 "log(2) of chunk size");
2434     cmd_AddParm(ts, "-dcache", CMD_SINGLE, CMD_OPTIONAL,
2435                 "number of dcache entries");
2436     cmd_AddParm(ts, "-volumes", CMD_SINGLE, CMD_OPTIONAL,
2437                 "number of volume entries");
2438     cmd_AddParm(ts, "-biods", CMD_SINGLE, CMD_OPTIONAL,
2439                 "number of bkg I/O daemons (aix vm)");
2440
2441     cmd_AddParm(ts, "-prealloc", CMD_SINGLE, CMD_OPTIONAL,
2442                 "number of 'small' preallocated blocks");
2443 #ifdef notdef
2444     cmd_AddParm(ts, "-pininodes", CMD_SINGLE, CMD_OPTIONAL,
2445                 "number of inodes to hog");
2446 #endif
2447     cmd_AddParm(ts, "-confdir", CMD_SINGLE, CMD_OPTIONAL,
2448                 "configuration directory");
2449     cmd_AddParm(ts, "-logfile", CMD_SINGLE, CMD_OPTIONAL,
2450                 "Place to keep the CM log");
2451     cmd_AddParm(ts, "-waitclose", CMD_FLAG, CMD_OPTIONAL,
2452                 "make close calls synchronous");
2453     cmd_AddParm(ts, "-shutdown", CMD_FLAG, CMD_OPTIONAL,
2454                 "Shutdown all afs state");
2455     cmd_AddParm(ts, "-enable_peer_stats", CMD_FLAG, CMD_OPTIONAL | CMD_HIDE,
2456                 "Collect rpc statistics by peer");
2457     cmd_AddParm(ts, "-enable_process_stats", CMD_FLAG,
2458                 CMD_OPTIONAL | CMD_HIDE,
2459                 "Collect rpc statistics for this process");
2460     cmd_AddParm(ts, "-mem_alloc_sleep", CMD_FLAG, (CMD_OPTIONAL | CMD_HIDE),
2461                 "Allow sleeps when allocating memory cache");
2462     cmd_AddParm(ts, "-afsdb", CMD_FLAG, (CMD_OPTIONAL
2463 #ifndef AFS_AFSDB_ENV
2464                                          | CMD_HIDE
2465 #endif
2466                 ), "Enable AFSDB support");
2467     cmd_AddParm(ts, "-files_per_subdir", CMD_SINGLE, CMD_OPTIONAL,
2468                 "log(2) of the number of cache files per cache subdirectory");
2469     cmd_AddParm(ts, "-dynroot", CMD_FLAG, CMD_OPTIONAL,
2470                 "Enable dynroot support");
2471     cmd_AddParm(ts, "-fakestat", CMD_FLAG, CMD_OPTIONAL,
2472                 "Enable fakestat support for cross-cell mounts");
2473     cmd_AddParm(ts, "-fakestat-all", CMD_FLAG, CMD_OPTIONAL,
2474                 "Enable fakestat support for all mounts");
2475     cmd_AddParm(ts, "-nomount", CMD_FLAG, CMD_OPTIONAL, "Do not mount AFS");
2476     cmd_AddParm(ts, "-backuptree", CMD_FLAG, CMD_OPTIONAL,
2477                 "Prefer backup volumes for mointpoints in backup volumes");
2478     cmd_AddParm(ts, "-rxbind", CMD_FLAG, CMD_OPTIONAL,
2479                 "Bind the Rx socket (one interface only)");
2480     cmd_AddParm(ts, "-settime", CMD_FLAG, CMD_OPTIONAL, "set the time");
2481     cmd_AddParm(ts, "-rxpck", CMD_SINGLE, CMD_OPTIONAL,
2482                 "set rx_extraPackets to this value");
2483     cmd_AddParm(ts, "-splitcache", CMD_SINGLE, CMD_OPTIONAL,
2484                 "Percentage RW versus RO in cache (specify as 60/40)");
2485
2486     return (cmd_Dispatch(argc, argv));
2487 }
2488
2489
2490 #ifdef  AFS_HPUX_ENV
2491 #define MOUNTED_TABLE   MNT_MNTTAB
2492 #else
2493 #ifdef  AFS_SUN5_ENV
2494 #define MOUNTED_TABLE   MNTTAB
2495 #else
2496 #define MOUNTED_TABLE   MOUNTED
2497 #endif
2498 #endif
2499
2500 static int
2501 HandleMTab()
2502 {
2503 #if (defined (AFS_SUN_ENV) || defined (AFS_HPUX_ENV) || defined(AFS_SUN5_ENV) || defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV)) && !defined(AFS_SUN58_ENV)
2504     FILE *tfilep;
2505 #ifdef  AFS_SUN5_ENV
2506     char tbuf[16];
2507     struct mnttab tmntent;
2508
2509     memset(&tmntent, '\0', sizeof(struct mnttab));
2510     if (!(tfilep = fopen(MOUNTED_TABLE, "a+"))) {
2511         printf("Can't open %s\n", MOUNTED_TABLE);
2512         perror(MNTTAB);
2513         exit(-1);
2514     }
2515     tmntent.mnt_special = "AFS";
2516     tmntent.mnt_mountp = cacheMountDir;
2517     tmntent.mnt_fstype = "xx";
2518     tmntent.mnt_mntopts = "rw";
2519     sprintf(tbuf, "%ld", (long)time((time_t *) 0));
2520     tmntent.mnt_time = tbuf;
2521     putmntent(tfilep, &tmntent);
2522     fclose(tfilep);
2523 #else
2524 #if defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV)
2525     struct mntent tmntent;
2526
2527     tfilep = setmntent("/etc/mtab", "a+");
2528     tmntent.mnt_fsname = "AFS";
2529     tmntent.mnt_dir = cacheMountDir;
2530     tmntent.mnt_type = "afs";
2531     tmntent.mnt_opts = "rw";
2532     tmntent.mnt_freq = 1;
2533     tmntent.mnt_passno = 3;
2534     addmntent(tfilep, &tmntent);
2535     endmntent(tfilep);
2536 #else
2537     struct mntent tmntent;
2538
2539     memset(&tmntent, '\0', sizeof(struct mntent));
2540     tfilep = setmntent(MOUNTED_TABLE, "a+");
2541     if (!tfilep) {
2542         printf("Can't open %s for write; Not adding afs entry to it\n",
2543                MOUNTED_TABLE);
2544         return 1;
2545     }
2546     tmntent.mnt_fsname = "AFS";
2547     tmntent.mnt_dir = cacheMountDir;
2548     tmntent.mnt_type = "xx";
2549     tmntent.mnt_opts = "rw";
2550     tmntent.mnt_freq = 1;
2551     tmntent.mnt_passno = 3;
2552 #ifdef  AFS_HPUX_ENV
2553     tmntent.mnt_type = "afs";
2554     tmntent.mnt_time = time(0);
2555     tmntent.mnt_cnode = 0;
2556 #endif
2557     addmntent(tfilep, &tmntent);
2558     endmntent(tfilep);
2559 #endif /* AFS_SGI_ENV */
2560 #endif /* AFS_SUN5_ENV */
2561 #endif /* unreasonable systems */
2562 #ifdef AFS_DARWIN_ENV
2563     mach_port_t diskarb_port;
2564     kern_return_t status;
2565
2566     status = DiskArbStart(&diskarb_port);
2567     if (status == KERN_SUCCESS) {
2568         status =
2569             DiskArbDiskAppearedWithMountpointPing_auto("AFS",
2570                                                        DISK_ARB_NETWORK_DISK_FLAG,
2571                                                        cacheMountDir);
2572     }
2573
2574     return status;
2575 #endif /* AFS_DARWIN_ENV */
2576     return 0;
2577 }
2578
2579 #if !defined(AFS_SGI_ENV) && !defined(AFS_AIX32_ENV)
2580
2581 call_syscall(param1, param2, param3, param4, param5, param6, param7)
2582      long param1, param2, param3, param4, param5, param6, param7;
2583 {
2584     int error;
2585 #ifdef AFS_LINUX20_ENV
2586     long eparm[4];
2587     struct afsprocdata syscall_data;
2588     int fd = open(PROC_SYSCALL_FNAME, O_RDWR);
2589     if (fd < 0)
2590         fd = open(PROC_SYSCALL_ARLA_FNAME, O_RDWR);
2591     eparm[0] = param4;
2592     eparm[1] = param5;
2593     eparm[2] = param6;
2594     eparm[3] = param7;
2595
2596     param4 = (long)eparm;
2597
2598     syscall_data.syscall = AFSCALL_CALL;
2599     syscall_data.param1 = param1;
2600     syscall_data.param2 = param2;
2601     syscall_data.param3 = param3;
2602     syscall_data.param4 = param4;
2603     if (fd > 0) {
2604         error = ioctl(fd, VIOC_SYSCALL, &syscall_data);
2605         close(fd);
2606     } else
2607 #endif
2608 #ifdef AFS_DARWIN80_ENV
2609     struct afssysargs syscall_data;
2610     int fd = open(SYSCALL_DEV_FNAME,O_RDWR);
2611     syscall_data.syscall = AFSCALL_CALL;
2612     syscall_data.param1 = param1;
2613     syscall_data.param2 = param2;
2614     syscall_data.param3 = param3;
2615     syscall_data.param4 = param4;
2616     syscall_data.param5 = param5;
2617     syscall_data.param6 = param6;
2618     if(fd >= 0) {
2619        error = ioctl(fd, VIOC_SYSCALL, &syscall_data);
2620        close(fd);
2621     } else {
2622        error = -1;
2623     }
2624     if (!error)
2625       error=syscall_data.retval;
2626 #else
2627     error =
2628         syscall(AFS_SYSCALL, AFSCALL_CALL, param1, param2, param3, param4,
2629                 param5, param6, param7);
2630 #endif
2631
2632     if (afsd_debug)
2633         printf("SScall(%d, %d, %d)=%d ", AFS_SYSCALL, AFSCALL_CALL, param1,
2634                error);
2635     return (error);
2636 }
2637 #else /* AFS_AIX32_ENV */
2638 #if defined(AFS_SGI_ENV)
2639 call_syscall(call, parm0, parm1, parm2, parm3, parm4)
2640 {
2641
2642     int error;
2643
2644     error = afs_syscall(call, parm0, parm1, parm2, parm3, parm4);
2645     if (afsd_verbose)
2646         printf("SScall(%d, %d)=%d ", call, parm0, error);
2647
2648     return error;
2649 }
2650 #else
2651 call_syscall(call, parm0, parm1, parm2, parm3, parm4, parm5, parm6)
2652 {
2653
2654     return syscall(AFSCALL_CALL, call, parm0, parm1, parm2, parm3, parm4,
2655                    parm5, parm6);
2656 }
2657 #endif /* AFS_SGI_ENV */
2658 #endif /* AFS_AIX32_ENV */
2659
2660
2661 #ifdef  AFS_AIX_ENV
2662 /* Special handling for AIX's afs mount operation since they require much more miscl. information before making the vmount(2) syscall */
2663 #include <sys/vfs.h>
2664
2665 #define ROUNDUP(x)  (((x) + 3) & ~3)
2666
2667 aix_vmount()
2668 {
2669     struct vmount *vmountp;
2670     int size, error;
2671
2672     size = sizeof(struct vmount) + ROUNDUP(strlen(cacheMountDir) + 1) + 5 * 4;
2673     /* Malloc the vmount structure */
2674     if ((vmountp = (struct vmount *)malloc(size)) == (struct vmount *)NULL) {
2675         printf("Can't allocate space for the vmount structure (AIX)\n");
2676         exit(1);
2677     }
2678
2679     /* zero out the vmount structure */
2680     memset(vmountp, '\0', size);
2681
2682     /* transfer info into the vmount structure */
2683     vmountp->vmt_revision = VMT_REVISION;
2684     vmountp->vmt_length = size;
2685     vmountp->vmt_fsid.fsid_dev = 0;
2686     vmountp->vmt_fsid.fsid_type = AFS_MOUNT_AFS;
2687     vmountp->vmt_vfsnumber = 0;
2688     vmountp->vmt_time = 0;      /* We'll put the time soon! */
2689     vmountp->vmt_flags = VFS_DEVMOUNT;  /* read/write permission */
2690     vmountp->vmt_gfstype = AFS_MOUNT_AFS;
2691     vmountdata(vmountp, "AFS", cacheMountDir, "", "", "", "rw");
2692
2693     /* Do the actual mount system call */
2694     error = vmount(vmountp, size);
2695     free(vmountp);
2696     return (error);
2697 }
2698
2699 vmountdata(struct vmount * vmtp, char *obj, char *stub, char *host,
2700            char *hostsname, char *info, char *args)
2701 {
2702     struct data {
2703         short vmt_off;
2704         short vmt_size;
2705     } *vdp, *vdprev;
2706     int size;
2707
2708     vdp = (struct data *)vmtp->vmt_data;
2709     vdp->vmt_off = sizeof(struct vmount);
2710     size = ROUNDUP(strlen(obj) + 1);
2711     vdp->vmt_size = size;
2712     strcpy(vmt2dataptr(vmtp, VMT_OBJECT), obj);
2713
2714     vdprev = vdp;
2715     vdp++;
2716     vdp->vmt_off = vdprev->vmt_off + size;
2717     size = ROUNDUP(strlen(stub) + 1);
2718     vdp->vmt_size = size;
2719     strcpy(vmt2dataptr(vmtp, VMT_STUB), stub);
2720
2721     vdprev = vdp;
2722     vdp++;
2723     vdp->vmt_off = vdprev->vmt_off + size;
2724     size = ROUNDUP(strlen(host) + 1);
2725     vdp->vmt_size = size;
2726     strcpy(vmt2dataptr(vmtp, VMT_HOST), host);
2727
2728     vdprev = vdp;
2729     vdp++;
2730     vdp->vmt_off = vdprev->vmt_off + size;
2731     size = ROUNDUP(strlen(hostsname) + 1);
2732     vdp->vmt_size = size;
2733     strcpy(vmt2dataptr(vmtp, VMT_HOSTNAME), hostsname);
2734
2735
2736     vdprev = vdp;
2737     vdp++;
2738     vdp->vmt_off = vdprev->vmt_off + size;
2739     size = ROUNDUP(strlen(info) + 1);
2740     vdp->vmt_size = size;
2741     strcpy(vmt2dataptr(vmtp, VMT_INFO), info);
2742
2743     vdprev = vdp;
2744     vdp++;
2745     vdp->vmt_off = vdprev->vmt_off + size;
2746     size = ROUNDUP(strlen(args) + 1);
2747     vdp->vmt_size = size;
2748     strcpy(vmt2dataptr(vmtp, VMT_ARGS), args);
2749 }
2750 #endif /* AFS_AIX_ENV */
2751
2752 #ifdef  AFS_SGI53_ENV
2753 #ifdef AFS_SGI61_ENV
2754 /* The dwarf structures are searched to find entry points of static functions
2755  * and the addresses of static variables. The file name as well as the
2756  * sybmol name is reaquired.
2757  */
2758
2759 /* Contains list of names to find in given file. */
2760 typedef struct {
2761     char *name;                 /* Name of variable or function. */
2762     afs_hyper_t addr;           /* Address of function, undefined if not found. */
2763     Dwarf_Half type;            /* DW_AT_location for vars, DW_AT_lowpc for func's */
2764     char found;                 /* set if found. */
2765 } staticAddrList;
2766
2767 typedef struct {
2768     char *file;                 /* Name of file containing vars or funcs */
2769     staticAddrList *addrList;   /* List of vars and/or funcs. */
2770     int nAddrs;                 /* # of addrList's */
2771     int found;                  /* set if we've found this file already. */
2772 } staticNameList;
2773
2774 /* routines used to find addresses in /unix */
2775 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
2776 void findMDebugStaticAddresses(staticNameList *, int, int);
2777 #endif
2778 void findDwarfStaticAddresses(staticNameList *, int);
2779 void findElfAddresses(Dwarf_Debug, Dwarf_Die, staticNameList *);
2780 void getElfAddress(Dwarf_Debug, Dwarf_Die, staticAddrList *);
2781
2782 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
2783 #define AFS_N_FILELISTS 2
2784 #define AFS_SYMS_NEEDED 3
2785 #else /* AFS_SGI62_ENV */
2786 #define AFS_N_FILELISTS 1
2787 #endif /* AFS_SGI62_ENV */
2788
2789
2790
2791 void
2792 set_staticaddrs(void)
2793 {
2794     staticNameList fileList[AFS_N_FILELISTS];
2795
2796     fileList[0].addrList =
2797         (staticAddrList *) calloc(1, sizeof(staticAddrList));
2798     if (!fileList[0].addrList) {
2799         printf("set_staticaddrs: Can't calloc fileList[0].addrList\n");
2800         return;
2801     }
2802     fileList[0].file = "nfs_server.c";
2803     fileList[0].found = 0;
2804     fileList[0].nAddrs = 1;
2805     fileList[0].addrList[0].name = "rfsdisptab_v2";
2806     fileList[0].addrList[0].type = DW_AT_location;
2807     fileList[0].addrList[0].found = 0;
2808
2809 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
2810     fileList[1].addrList =
2811         (staticAddrList *) calloc(2, sizeof(staticAddrList));
2812     if (!fileList[1].addrList) {
2813         printf("set_staticaddrs: Can't malloc fileList[1].addrList\n");
2814         return;
2815     }
2816     fileList[1].file = "uipc_socket.c";
2817     fileList[1].found = 0;
2818     fileList[1].nAddrs = 2;
2819     fileList[1].addrList[0].name = "sblock";
2820     fileList[1].addrList[0].type = DW_AT_low_pc;
2821     fileList[1].addrList[0].found = 0;
2822     fileList[1].addrList[1].name = "sbunlock";
2823     fileList[1].addrList[1].type = DW_AT_low_pc;
2824     fileList[1].addrList[1].found = 0;
2825
2826     if (64 != sysconf(_SC_KERN_POINTERS))
2827         findMDebugStaticAddresses(fileList, AFS_N_FILELISTS, AFS_SYMS_NEEDED);
2828     else
2829 #endif /* AFS_SGI62_ENV */
2830         findDwarfStaticAddresses(fileList, AFS_N_FILELISTS);
2831
2832     if (fileList[0].addrList[0].found) {
2833         call_syscall(AFSOP_NFSSTATICADDR2, fileList[0].addrList[0].addr.high,
2834                      fileList[0].addrList[0].addr.low);
2835     } else {
2836         if (afsd_verbose)
2837             printf("NFS V2 is not present in the kernel.\n");
2838     }
2839     free(fileList[0].addrList);
2840 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
2841     if (fileList[1].addrList[0].found && fileList[1].addrList[1].found) {
2842         call_syscall(AFSOP_SBLOCKSTATICADDR2,
2843                      fileList[1].addrList[0].addr.high,
2844                      fileList[1].addrList[0].addr.low,
2845                      fileList[1].addrList[1].addr.high,
2846                      fileList[1].addrList[1].addr.low);
2847     } else {
2848         if (!fileList[1].addrList[0].found)
2849             printf("Can't find %s in kernel. Exiting.\n",
2850                    fileList[1].addrList[0].name);
2851         if (!fileList[1].addrList[0].found)
2852             printf("Can't find %s in kernel. Exiting.\n",
2853                    fileList[1].addrList[1].name);
2854         exit(1);
2855     }
2856     free(fileList[1].addrList);
2857 #endif /* AFS_SGI62_ENV */
2858 }
2859
2860
2861 /* Find addresses for static variables and functions. */
2862 void
2863 findDwarfStaticAddresses(staticNameList * nameList, int nLists)
2864 {
2865     int fd;
2866     int i;
2867     int found = 0;
2868     int code;
2869     char *s;
2870     char *hname = (char *)0;
2871     Dwarf_Unsigned dwarf_access = O_RDONLY;
2872     Dwarf_Debug dwarf_debug;
2873     Dwarf_Error dwarf_error;
2874     Dwarf_Unsigned dwarf_cu_header_length;
2875     Dwarf_Unsigned dwarf_abbrev_offset;
2876     Dwarf_Half dwarf_address_size;
2877     Dwarf_Unsigned next_cu_header;
2878     Dwarf_Die dwarf_die;
2879     Dwarf_Die dwarf_next_die;
2880     Dwarf_Die dwarf_child_die;
2881
2882     if (elf_version(EV_CURRENT) == EV_NONE) {
2883         printf("findDwarfStaticAddresses: Bad elf version.\n");
2884         return;
2885     }
2886
2887     if ((fd = open("/unix", O_RDONLY, 0)) < 0) {
2888         printf("findDwarfStaticAddresses: Failed to open /unix.\n");
2889         return;
2890     }
2891     code =
2892         dwarf_init(fd, dwarf_access, NULL, NULL, &dwarf_debug, &dwarf_error);
2893     if (code != DW_DLV_OK) {
2894         /* Nope hope for the elves and dwarves, try intermediate code. */
2895         close(fd);
2896         return;
2897     }
2898
2899     found = 0;
2900     while (1) {
2901         /* Run through the headers until we find ones for files we've
2902          * specified in nameList.
2903          */
2904         code =
2905             dwarf_next_cu_header(dwarf_debug, &dwarf_cu_header_length, NULL,
2906                                  &dwarf_abbrev_offset, &dwarf_address_size,
2907                                  &next_cu_header, &dwarf_error);
2908         if (code == DW_DLV_NO_ENTRY) {
2909             break;
2910         } else if (code == DW_DLV_ERROR) {
2911             printf("findDwarfStaticAddresses: Error reading headers: %s\n",
2912                    dwarf_errmsg(dwarf_error));
2913             break;
2914         }
2915
2916         code = dwarf_siblingof(dwarf_debug, NULL, &dwarf_die, &dwarf_error);
2917         if (code != DW_DLV_OK) {
2918             printf("findDwarfStaticAddresses: Can't get first die. %s\n",
2919                    (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
2920             break;
2921         }
2922
2923         /* This is the header, test the name. */
2924         code = dwarf_diename(dwarf_die, &hname, &dwarf_error);
2925         if (code == DW_DLV_OK) {
2926             s = strrchr(hname, '/');
2927             for (i = 0; i < nLists; i++) {
2928                 if (s && !strcmp(s + 1, nameList[i].file)) {
2929                     findElfAddresses(dwarf_debug, dwarf_die, &nameList[i]);
2930                     found++;
2931                     break;
2932                 }
2933             }
2934         } else {
2935             printf
2936                 ("findDwarfStaticAddresses: Can't get name of current header. %s\n",
2937                  (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
2938             break;
2939         }
2940         dwarf_dealloc(dwarf_debug, hname, DW_DLA_STRING);
2941         hname = (char *)0;
2942         if (found >= nLists) {  /* we're done */
2943             break;
2944         }
2945     }
2946
2947     /* Frees up all allocated space. */
2948     (void)dwarf_finish(dwarf_debug, &dwarf_error);
2949     close(fd);
2950 }
2951
2952 void
2953 findElfAddresses(Dwarf_Debug dwarf_debug, Dwarf_Die dwarf_die,
2954                  staticNameList * nameList)
2955 {
2956     int i;
2957     Dwarf_Error dwarf_error;
2958     Dwarf_Die dwarf_next_die;
2959     Dwarf_Die dwarf_child_die;
2960     Dwarf_Attribute dwarf_return_attr;
2961     char *vname = (char *)0;
2962     int found = 0;
2963     int code;
2964
2965     /* Drop into this die to find names in addrList. */
2966     code = dwarf_child(dwarf_die, &dwarf_child_die, &dwarf_error);
2967     if (code != DW_DLV_OK) {
2968         printf("findElfAddresses: Can't get child die. %s\n",
2969                (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
2970         return;
2971     }
2972
2973     /* Try to find names in each sibling. */
2974     dwarf_next_die = (Dwarf_Die) 0;
2975     do {
2976         code = dwarf_diename(dwarf_child_die, &vname, &dwarf_error);
2977         /* It's possible that some siblings don't have names. */
2978         if (code == DW_DLV_OK) {
2979             for (i = 0; i < nameList->nAddrs; i++) {
2980                 if (!nameList->addrList[i].found) {
2981                     if (!strcmp(vname, nameList->addrList[i].name)) {
2982                         getElfAddress(dwarf_debug, dwarf_child_die,
2983                                       &(nameList->addrList[i]));
2984                         found++;
2985                         break;
2986                     }
2987                 }
2988             }
2989         }
2990         if (dwarf_next_die)
2991             dwarf_dealloc(dwarf_debug, dwarf_next_die, DW_DLA_DIE);
2992
2993         if (found >= nameList->nAddrs) {        /* we're done. */
2994             break;
2995         }
2996
2997         dwarf_next_die = dwarf_child_die;
2998         code =
2999             dwarf_siblingof(dwarf_debug, dwarf_next_die, &dwarf_child_die,
3000                             &dwarf_error);
3001
3002     } while (code == DW_DLV_OK);
3003 }
3004
3005 /* Get address out of current die. */
3006 void
3007 getElfAddress(Dwarf_Debug dwarf_debug, Dwarf_Die dwarf_child_die,
3008               staticAddrList * addrList)
3009 {
3010     int i;
3011     Dwarf_Error dwarf_error;
3012     Dwarf_Attribute dwarf_return_attr;
3013     Dwarf_Bool dwarf_return_bool;
3014     Dwarf_Locdesc *llbuf = NULL;
3015     Dwarf_Signed listlen;
3016     off64_t addr = (off64_t) 0;
3017     int code;
3018
3019     code =
3020         dwarf_hasattr(dwarf_child_die, addrList->type, &dwarf_return_bool,
3021                       &dwarf_error);
3022     if ((code != DW_DLV_OK) || (!dwarf_return_bool)) {
3023         printf("getElfAddress: no address given for %s. %s\n", addrList->name,
3024                (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
3025         return;
3026     }
3027     code =
3028         dwarf_attr(dwarf_child_die, addrList->type, &dwarf_return_attr,
3029                    &dwarf_error);
3030     if (code != DW_DLV_OK) {
3031         printf("getElfAddress: Can't get attribute. %s\n",
3032                (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
3033         return;
3034     }
3035
3036     switch (addrList->type) {
3037     case DW_AT_location:
3038         code =
3039             dwarf_loclist(dwarf_return_attr, &llbuf, &listlen, &dwarf_error);
3040         if (code != DW_DLV_OK) {
3041             printf("getElfAddress: Can't get location for %s. %s\n",
3042                    addrList->name,
3043                    (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
3044             return;
3045         }
3046         if ((listlen != 1) || (llbuf[0].ld_cents != 1)) {
3047             printf("getElfAddress: %s has more than one address.\n",
3048                    addrList->name);
3049             return;
3050         }
3051         addr = llbuf[0].ld_s[0].lr_number;
3052         break;
3053
3054     case DW_AT_low_pc:
3055         code =
3056             dwarf_lowpc(dwarf_child_die, (Dwarf_Addr *) & addr, &dwarf_error);
3057         if (code != DW_DLV_OK) {
3058             printf("getElfAddress: Can't get lowpc for %s. %s\n",
3059                    addrList->name,
3060                    (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
3061             return;
3062         }
3063         break;
3064
3065     default:
3066         printf("getElfAddress: Bad case %d in switch.\n", addrList->type);
3067         return;
3068     }
3069
3070     addrList->addr.high = (addr >> 32) & 0xffffffff;
3071     addrList->addr.low = addr & 0xffffffff;
3072     addrList->found = 1;
3073 }
3074
3075 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
3076 /* Find symbols in the .mdebug section for 32 bit kernels. */
3077 /*
3078  * do_mdebug()
3079  * On 32bit platforms, we're still using the ucode compilers to build
3080  * the kernel, so we need to get our static text/data from the .mdebug
3081  * section instead of the .dwarf sections.
3082  */
3083 /* SearchNameList searches our bizarre structs for the given string.
3084  * If found, sets the found bit and the address and returns 1.
3085  * Not found returns 0.
3086  */
3087 int
3088 SearchNameList(char *name, afs_uint32 addr, staticNameList * nameList,
3089                int nLists)
3090 {
3091     int i, j;
3092     for (i = 0; i < nLists; i++) {
3093         for (j = 0; j < nameList[i].nAddrs; j++) {
3094             if (nameList[i].addrList[j].found)
3095                 continue;
3096             if (!strcmp(name, nameList[i].addrList[j].name)) {
3097                 nameList[i].addrList[j].addr.high = 0;
3098                 nameList[i].addrList[j].addr.low = addr;
3099                 nameList[i].addrList[j].found = 1;
3100                 return 1;
3101             }
3102         }
3103     }
3104     return 0;
3105 }
3106
3107 static void
3108 SearchMDebug(Elf_Scn * scnp, Elf32_Shdr * shdrp, staticNameList * nameList,
3109              int nLists, int needed)
3110 {
3111     long *buf = (long *)(elf_getdata(scnp, NULL)->d_buf);
3112     u_long addr, mdoff = shdrp->sh_offset;
3113     HDRR *hdrp;
3114     SYMR *symbase, *symp, *symend;
3115     FDR *fdrbase, *fdrp;
3116     int i, j;
3117     char *strbase, *str;
3118     int ifd;
3119     int nFound = 0;
3120
3121     /* get header */
3122     addr = (__psunsigned_t) buf;
3123     hdrp = (HDRR *) addr;
3124
3125     /* setup base addresses */
3126     addr = (u_long) buf + (u_long) (hdrp->cbFdOffset - mdoff);
3127     fdrbase = (FDR *) addr;
3128     addr = (u_long) buf + (u_long) (hdrp->cbSymOffset - mdoff);
3129     symbase = (SYMR *) addr;
3130     addr = (u_long) buf + (u_long) (hdrp->cbSsOffset - mdoff);
3131     strbase = (char *)addr;
3132
3133 #define KEEPER(a,b)     ((a == stStaticProc && b == scText) || \
3134                          (a == stStatic && (b == scData || b == scBss || \
3135                                             b == scSBss || b == scSData)))
3136
3137     for (fdrp = fdrbase; fdrp < &fdrbase[hdrp->ifdMax]; fdrp++) {
3138         str = strbase + fdrp->issBase + fdrp->rss;
3139
3140         /* local symbols for each fd */
3141         for (symp = &symbase[fdrp->isymBase];
3142              symp < &symbase[fdrp->isymBase + fdrp->csym]; symp++) {
3143             if (KEEPER(symp->st, symp->sc)) {
3144                 if (symp->value == 0)
3145                     continue;
3146
3147                 str = strbase + fdrp->issBase + symp->iss;
3148                 /* Look for AFS symbols of interest */
3149                 if (SearchNameList(str, symp->value, nameList, nLists)) {
3150                     nFound++;
3151                     if (nFound >= needed)
3152                         return;
3153                 }
3154             }
3155         }
3156     }
3157 }
3158
3159 /*
3160  * returns section with the name of scn_name, & puts its header in shdr64 or
3161  * shdr32 based on elf's file type
3162  *
3163  */
3164 Elf_Scn *
3165 findMDebugSection(Elf * elf, char *scn_name)
3166 {
3167     Elf64_Ehdr *ehdr64;
3168     Elf32_Ehdr *ehdr32;
3169     Elf_Scn *scn = NULL;
3170     Elf64_Shdr *shdr64;
3171     Elf32_Shdr *shdr32;
3172
3173     if ((ehdr32 = elf32_getehdr(elf)) == NULL)
3174         return (NULL);
3175     do {
3176         if ((scn = elf_nextscn(elf, scn)) == NULL)
3177             break;
3178         if ((shdr32 = elf32_getshdr(scn)) == NULL)
3179             return (NULL);
3180     } while (strcmp
3181              (scn_name,
3182               elf_strptr(elf, ehdr32->e_shstrndx, shdr32->sh_name)));
3183
3184     return (scn);
3185 }
3186
3187
3188 void
3189 findMDebugStaticAddresses(staticNameList * nameList, int nLists, int needed)
3190 {
3191     int fd;
3192     Elf *elf;
3193     Elf_Scn *mdebug_scn;
3194     Elf32_Shdr *mdebug_shdr;
3195     char *names;
3196
3197     if ((fd = open("/unix", O_RDONLY)) == -1) {
3198         printf("findMDebugStaticAddresses: Failed to open /unix.\n");
3199         return;
3200     }
3201
3202     (void)elf_version(EV_CURRENT);
3203     if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
3204         printf
3205             ("findMDebugStaticAddresses: /unix doesn't seem to be an elf file\n");
3206         close(fd);
3207         return;
3208     }
3209     mdebug_scn = findMDebugSection(elf, ".mdebug");
3210     if (!mdebug_scn) {
3211         printf("findMDebugStaticAddresses: Can't find .mdebug section.\n");
3212         goto find_end;
3213     }
3214     mdebug_shdr = elf32_getshdr(mdebug_scn);
3215     if (!mdebug_shdr) {
3216         printf("findMDebugStaticAddresses: Can't find .mdebug header.\n");
3217         goto find_end;
3218     }
3219
3220     (void)SearchMDebug(mdebug_scn, mdebug_shdr, nameList, nLists, needed);
3221
3222   find_end:
3223     elf_end(elf);
3224     close(fd);
3225 }
3226 #endif /* AFS_SGI62_ENV */
3227
3228 #else /* AFS_SGI61_ENV */
3229 #include <nlist.h>
3230 struct nlist nlunix[] = {
3231     {"rfsdisptab_v2"},
3232     {0},
3233 };
3234
3235 get_nfsstaticaddr()
3236 {
3237     int i, j, kmem, count;
3238
3239     if ((kmem = open("/dev/kmem", O_RDONLY)) < 0) {
3240         printf("Warning: can't open /dev/kmem\n");
3241         return 0;
3242     }
3243     if ((j = nlist("/unix", nlunix)) < 0) {
3244         printf("Warning: can't nlist /unix\n");
3245         return 0;
3246     }
3247     i = nlunix[0].n_value;
3248     if (lseek(kmem, i, L_SET /*0 */ ) != i) {
3249         printf("Warning: can't lseek to %x\n", i);
3250         return 0;
3251     }
3252     if ((j = read(kmem, &count, sizeof count)) != sizeof count) {
3253         printf("WARNING: kmem read at %x failed\n", i);
3254         return 0;
3255     }
3256     return i;
3257 }
3258 #endif /* AFS_SGI61_ENV */
3259 #endif /* AFS_SGI53_ENV */