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