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