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