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