This is mostly a rewrite of src/afs/afs_cell.c, and associated changes
[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 = 1;
1341     }
1342
1343     /*
1344      * Pull out all the configuration info for the workstation's AFS cache and
1345      * the cellular community we're willing to let our users see.
1346      */
1347     cdir = afsconf_Open(confDir);
1348     if (!cdir) {
1349         printf("afsd: some file missing or bad in %s\n", confDir);
1350         exit(1);
1351     }
1352
1353     lookupResult = afsconf_GetLocalCell(cdir, LclCellName, sizeof(LclCellName));
1354     if (lookupResult) {
1355         printf("%s: Can't get my home cell name!  [Error is %d]\n",
1356                rn, lookupResult);
1357     }
1358     else {
1359         if (afsd_verbose)
1360             printf("%s: My home cell is '%s'\n",
1361                    rn, LclCellName);
1362     }
1363
1364     /* parse cacheinfo file if this is a diskcache */
1365     if (ParseCacheInfoFile()) {
1366         exit(1);
1367     }
1368
1369     if ((logfd = fopen(fullpn_AFSLogFile,"r+")) == 0) {
1370         if (afsd_verbose)  printf("%s: Creating '%s'\n",  rn, fullpn_AFSLogFile);
1371         if (CreateCacheFile(fullpn_AFSLogFile, NULL)) {
1372             printf("%s: Can't create '%s' (You may want to use the -logfile option)\n",  rn, fullpn_AFSLogFile);
1373             exit(1);
1374         }
1375     } else
1376         fclose(logfd);
1377
1378     /* do some random computations in memcache case to get things to work
1379      * reasonably no matter which parameters you set.
1380      */
1381     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1382         /* memory cache: size described either as blocks or dcache entries, but
1383          * not both.
1384          */
1385         if (sawDCacheSize) {
1386             if (sawCacheBlocks) {
1387                 printf("%s: can't set cache blocks and dcache size simultaneously when diskless.\n", rn);
1388                 exit(1);
1389             }
1390             /* compute the cache size based on # of chunks times the chunk size */
1391             i = (chunkSize == 0? 13 : chunkSize);
1392             i = (1<<i); /* bytes per chunk */
1393             cacheBlocks = i * dCacheSize;
1394             sawCacheBlocks = 1; /* so that ParseCacheInfoFile doesn't overwrite */
1395         }
1396         else {
1397             /* compute the dcache size from overall cache size and chunk size */
1398             i = (chunkSize == 0? 13 : chunkSize);
1399             /* dCacheSize = (cacheBlocks << 10) / (1<<i); */
1400             if (i > 10) {
1401                 dCacheSize = (cacheBlocks >> (i-10));
1402             } else if (i < 10) {
1403                 dCacheSize = (cacheBlocks << (10-i));
1404             } else {
1405                 dCacheSize = cacheBlocks;
1406             }
1407             /* don't have to set sawDCacheSize here since it isn't overwritten
1408              * by ParseCacheInfoFile.
1409              */
1410         }
1411         /* kernel computes # of dcache entries as min of cacheFiles and dCacheSize,
1412          * so we now make them equal.
1413          */
1414         cacheFiles = dCacheSize;
1415     }
1416     else {
1417         /* Disk cache:
1418          * Compute the number of cache files based on cache size,
1419          * but only if -files isn't given on the command line.
1420          * Don't let # files be so small as to prevent full utilization 
1421          * of the cache unless user has explicitly asked for it.
1422          * average V-file is ~10K, according to tentative empirical studies.
1423          */
1424         if (!filesSet) {
1425             cacheFiles = cacheBlocks / 10;       
1426             if (cacheFiles <  100) cacheFiles =  100;
1427             /* Always allow more files than chunks.  Presume average V-file 
1428              * is ~67% of a chunk...  (another guess, perhaps Honeyman will
1429              * have a grad student write a paper).  i is KILOBYTES.
1430              */
1431             i = 1 << (chunkSize == 0? 6 : (chunkSize<10 ? 0 : chunkSize -10));
1432             cacheFiles = max(cacheFiles, 1.5 * (cacheBlocks / i));
1433             /* never permit more files than blocks, while leaving space for
1434              * VolumeInfo and CacheItems files.  VolumeInfo is usually 20K,
1435              * CacheItems is 50 Bytes / file (== 1K/20)
1436              */
1437 #define VOLINFOSZ 20
1438 #define CACHEITMSZ (cacheFiles / 20)
1439 #ifdef AFS_AIX_ENV
1440             cacheFiles= min(cacheFiles,(cacheBlocks -VOLINFOSZ -CACHEITMSZ)/4);
1441 #else
1442             cacheFiles = min(cacheFiles, cacheBlocks - VOLINFOSZ - CACHEITMSZ);
1443 #endif
1444             if (cacheFiles <  100) 
1445               fprintf (stderr, "%s: WARNING: cache probably too small!\n", rn);
1446         }
1447         if (!sawDCacheSize) {
1448             if ((cacheFiles / 2) > dCacheSize)
1449                 dCacheSize = cacheFiles / 2;
1450             if (dCacheSize > 2000)
1451                 dCacheSize = 2000;
1452         }
1453     }
1454
1455     /*
1456      * Create and zero the inode table for the desired cache files.
1457      */
1458     inode_for_V = (AFSD_INO_T *) malloc(cacheFiles * sizeof(AFSD_INO_T));
1459     if (inode_for_V == (AFSD_INO_T *)0) {
1460         printf("%s: malloc() failed for cache file inode table with %d entries.\n",
1461                rn, cacheFiles);
1462         exit(1);
1463     }
1464     memset(inode_for_V, '\0', (cacheFiles * sizeof(AFSD_INO_T)));
1465     if (afsd_debug)
1466         printf("%s: %d inode_for_V entries at 0x%x, %d bytes\n",
1467                rn, cacheFiles, inode_for_V,
1468                (cacheFiles * sizeof(AFSD_INO_T)));
1469
1470     /*
1471      * Set up all the pathnames we'll need for later.
1472      */
1473     sprintf(fullpn_DCacheFile,   "%s/%s", cacheBaseDir, DCACHEFILE);
1474     sprintf(fullpn_VolInfoFile,  "%s/%s", cacheBaseDir, VOLINFOFILE);
1475     sprintf(fullpn_CellInfoFile, "%s/%s", cacheBaseDir, CELLINFOFILE);
1476     sprintf(fullpn_VFile,       "%s/",  cacheBaseDir);
1477     vFilePtr = fullpn_VFile + strlen(fullpn_VFile);
1478
1479 #if 0
1480     fputs(AFS_GOVERNMENT_MESSAGE, stdout); 
1481     fflush(stdout);
1482 #endif
1483
1484     /*
1485      * Set up all the kernel processes needed for AFS.
1486      */
1487 #ifdef mac2
1488     setpgrp(getpid(), 0);
1489 #endif /* mac2 */
1490
1491     /* Initialize RX daemons and services */
1492
1493     /* initialize the rx random number generator from user space */
1494     {
1495       /* parse multihomed address files */
1496       afs_int32 addrbuf[MAXIPADDRS],maskbuf[MAXIPADDRS],mtubuf[MAXIPADDRS];
1497       char reason[1024];
1498       code=parseNetFiles(addrbuf,maskbuf,mtubuf,MAXIPADDRS,reason,
1499                     AFSDIR_CLIENT_NETINFO_FILEPATH,
1500                     AFSDIR_CLIENT_NETRESTRICT_FILEPATH);
1501       if(code>0) 
1502         call_syscall(AFSOP_ADVISEADDR, code, addrbuf, maskbuf, mtubuf);
1503       else 
1504         printf("ADVISEADDR: Error in specifying interface addresses:%s\n",reason);
1505     }
1506
1507     /* Set realtime priority for most threads to same as for biod's. */
1508     SET_AFSD_RTPRI();
1509
1510 #ifdef  AFS_SGI53_ENV
1511 #ifdef AFS_SGI61_ENV
1512     set_staticaddrs();
1513 #else /* AFS_SGI61_ENV */
1514     code = get_nfsstaticaddr();
1515     if (code)
1516         call_syscall(AFSOP_NFSSTATICADDR, code);
1517 #endif /* AFS_SGI61_ENV */
1518 #endif /* AFS_SGI_53_ENV */
1519
1520     /* Start listener, then callback listener. Lastly, start rx event daemon.
1521      * Change in ordering is so that Linux port has socket fd in listener
1522      * process.
1523      * preallocs are passed for both listener and callback server. Only
1524      * the one which actually does the initialization uses them though.
1525      */
1526     if (preallocs < cacheStatEntries+50)
1527         preallocs = cacheStatEntries+50;
1528 #ifdef RXK_LISTENER_ENV
1529     if (afsd_verbose)
1530         printf("%s: Forking rx listener daemon.\n", rn);
1531     code = fork();
1532     if (code == 0) {
1533         /* Child */
1534         SET_RX_RTPRI(); /* max advised for non-interrupts */
1535         call_syscall(AFSOP_RXLISTENER_DAEMON,
1536                      preallocs,
1537                      enable_peer_stats,
1538                      enable_process_stats);
1539         exit(1);
1540     }
1541 #endif
1542     if (afsd_verbose)
1543         printf("%s: Forking rx callback listener.\n", rn);
1544     code = fork();
1545     if (code == 0) {
1546         /* Child */
1547         call_syscall(AFSOP_START_RXCALLBACK, preallocs);
1548         exit(1);
1549     }
1550 #if defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV)
1551     if (afsd_verbose)
1552         printf("%s: Forking rxevent daemon.\n", rn);
1553     code = fork();
1554     if (code == 0) {
1555         /* Child */
1556         SET_RX_RTPRI(); /* max advised for non-interrupts */
1557         call_syscall(AFSOP_RXEVENT_DAEMON);
1558         exit(1);
1559     }
1560 #endif
1561
1562 #ifdef AFS_AFSDB_ENV
1563     if (enable_afsdb) {
1564         if (afsd_verbose)
1565             printf("%s: Forking AFSDB lookup handler.\n", rn);
1566         code = fork();
1567         if (code == 0) {
1568             AfsdbLookupHandler();
1569             exit(1);
1570         }
1571     }
1572 #endif
1573
1574     code = call_syscall(AFSOP_BASIC_INIT, 1);
1575     if (code)
1576         printf("%s: Error %d in basic initialization.\n", rn, code);
1577
1578     /*
1579      * Tell the kernel some basic information about the workstation's cache.
1580      */
1581     if (afsd_verbose)
1582         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",
1583                rn, cacheStatEntries, cacheFiles, cacheBlocks, cacheFlags,
1584                dCacheSize);
1585     memset(&cparams, '\0', sizeof(cparams));
1586     cparams.cacheScaches = cacheStatEntries;
1587     cparams.cacheFiles = cacheFiles;
1588     cparams.cacheBlocks = cacheBlocks;
1589     cparams.cacheDcaches = dCacheSize;
1590     cparams.cacheVolumes = vCacheSize;
1591     cparams.chunkSize = chunkSize;
1592     cparams.setTimeFlag = cacheSetTime;
1593     cparams.memCacheFlag = cacheFlags;
1594 #ifdef notdef
1595     cparams.inodes       = inodes;
1596 #endif
1597     call_syscall(AFSOP_CACHEINIT, &cparams);
1598     if (afsd_CloseSynch) 
1599         call_syscall(AFSOP_CLOSEWAIT);
1600
1601     /*
1602      * Sweep the workstation AFS cache directory, remembering the inodes of
1603      * valid files and deleting extraneous files.  Keep sweeping until we
1604      * have the right number of data cache files or we've swept too many
1605      * times.
1606      *
1607      * This also creates files in the cache directory like VolumeItems and
1608      * CellItems, and thus must be ran before those are sent to the kernel.
1609      */
1610     if (afsd_verbose)
1611         printf("%s: Sweeping workstation's AFS cache directory.\n",
1612                rn);
1613     cacheIteration = 0;
1614     /* Memory-cache based system doesn't need any of this */
1615     if(!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
1616         do {
1617             cacheIteration++;
1618             if (SweepAFSCache(&vFilesFound)) {
1619                 printf("%s: Error on sweep %d of workstation AFS cache \
1620                        directory.\n", rn, cacheIteration);
1621                 exit(1);
1622             }
1623             if (afsd_verbose)
1624                 printf("%s: %d out of %d data cache files found in sweep %d.\n",
1625                        rn, vFilesFound, cacheFiles, cacheIteration);
1626         } while ((vFilesFound < cacheFiles) &&
1627                  (cacheIteration < MAX_CACHE_LOOPS));
1628     } else if(afsd_verbose)
1629         printf("%s: Using memory cache, not swept\n", rn);
1630
1631     /*
1632      * Pass the kernel the name of the workstation cache file holding the 
1633      * dcache entries.
1634      */
1635     if (afsd_debug)
1636         printf("%s: Calling AFSOP_CACHEINFO: dcache file is '%s'\n",
1637                rn, fullpn_DCacheFile);
1638     /* once again, meaningless for a memory-based cache. */
1639     if(!(cacheFlags & AFSCALL_INIT_MEMCACHE))
1640         call_syscall(AFSOP_CACHEINFO, fullpn_DCacheFile);
1641
1642     /*
1643      * Pass the kernel the name of the workstation cache file holding the
1644      * cell information.
1645      */
1646     if (afsd_debug)
1647         printf("%s: Calling AFSOP_CELLINFO: cell info file is '%s'\n",
1648                rn, fullpn_CellInfoFile);
1649     call_syscall(AFSOP_CELLINFO, fullpn_CellInfoFile);
1650
1651     if (enable_dynroot) {
1652         if (afsd_verbose)
1653             printf("%s: Enabling dynroot support in kernel.\n", rn);
1654         code = call_syscall(AFSOP_SET_DYNROOT, 1);
1655         if (code)
1656             printf("%s: Error enabling dynroot support.\n", rn);
1657     }
1658
1659     if (enable_fakestat) {
1660         if (afsd_verbose)
1661             printf("%s: Enabling fakestat support in kernel.\n", rn);
1662         code = call_syscall(AFSOP_SET_FAKESTAT, 1);
1663         if (code)
1664             printf("%s: Error enabling fakestat support.\n", rn);
1665     }
1666
1667     /* Initialize AFS daemon threads. */
1668     if (afsd_verbose)
1669         printf("%s: Forking AFS daemon.\n", rn);
1670     code = fork();
1671     if (code == 0) {
1672         /* Child */
1673         call_syscall(AFSOP_START_AFS);
1674         exit(1);
1675     }
1676
1677     if (afsd_verbose)
1678         printf("%s: Forking Check Server Daemon.\n", rn);
1679     code = fork();
1680     if (code == 0) {
1681         /* Child */
1682         code = call_syscall(AFSOP_START_CS);
1683         if (code)
1684             printf("%s: No check server daemon in client.\n", rn);
1685         exit(1);
1686     }
1687
1688     if (afsd_verbose)
1689         printf("%s: Forking %d background daemons.\n", rn, nDaemons);
1690 #if defined(AFS_SGI_ENV) && defined(AFS_SGI_SHORTSTACK)
1691     /* Add one because for sgi we always "steal" the first daemon for a
1692      * different task if we only have a 4K stack.
1693      */
1694     nDaemons++;
1695 #endif
1696     for (i=0;i<nDaemons;i++) {
1697         code = fork();
1698         if (code == 0) {
1699             /* Child */
1700 #ifdef  AFS_AIX32_ENV
1701             call_syscall(AFSOP_START_BKG, 0);
1702 #else
1703             call_syscall(AFSOP_START_BKG);
1704 #endif
1705             exit(1);
1706         }
1707     }
1708 #ifdef  AFS_AIX32_ENV
1709     if (!sawBiod) 
1710         nBiods = nDaemons * 2;
1711     if (nBiods < 5)
1712         nBiods = 5;
1713     for (i=0; i< nBiods;i++) {
1714         code = fork();
1715         if (code == 0) {        /* Child */
1716             call_syscall(AFSOP_START_BKG, nBiods);
1717             exit(1);
1718         }
1719     }
1720 #endif
1721
1722     /*
1723      * Tell the kernel about each cell in the configuration.
1724      */
1725     afsconf_CellApply(cdir, ConfigCell, NULL);
1726     afsconf_CellAliasApply(cdir, ConfigCellAlias, NULL);
1727
1728     /*
1729      * Set the primary cell name.
1730      */
1731     call_syscall(AFSOP_SET_THISCELL, LclCellName);
1732
1733     /*
1734      * If the root volume has been explicitly set, tell the kernel.
1735      */
1736     if (rootVolSet) {
1737         if (afsd_verbose)
1738             printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n",
1739               rn, rootVolume);
1740         call_syscall(AFSOP_ROOTVOLUME, rootVolume);
1741     }
1742
1743     /*
1744      * Pass the kernel the name of the workstation cache file holding the
1745      * volume information.
1746      */
1747     if (afsd_debug)
1748         printf("%s: Calling AFSOP_VOLUMEINFO: volume info file is '%s'\n",
1749                rn, fullpn_VolInfoFile);
1750     call_syscall(AFSOP_VOLUMEINFO,fullpn_VolInfoFile);
1751
1752     /*
1753      * Pass the kernel the name of the afs logging file holding the volume
1754      * information.
1755      */
1756     if (afsd_debug)
1757         printf("%s: Calling AFSOP_AFSLOG: volume info file is '%s'\n",
1758                rn, fullpn_AFSLogFile);
1759 #if defined(AFS_SGI_ENV)
1760     /* permit explicit -logfile argument to enable logging on memcache systems */
1761     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE) || as->parms[18].items)
1762 #else
1763     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) /* ... nor this ... */
1764 #endif
1765         call_syscall(AFSOP_AFSLOG,fullpn_AFSLogFile);
1766
1767     /*
1768      * Give the kernel the names of the AFS files cached on the workstation's
1769      * disk.
1770      */
1771     if (afsd_debug)
1772         printf("%s: Calling AFSOP_CACHEINODE for each of the %d files in '%s'\n",
1773                rn, cacheFiles, cacheBaseDir);
1774     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) /* ... and again ... */
1775         for (currVFile = 0; currVFile < cacheFiles; currVFile++) {
1776 #ifdef AFS_SGI62_ENV
1777             call_syscall(AFSOP_CACHEINODE,
1778                          (afs_uint32)(inode_for_V[currVFile]>>32),
1779                          (afs_uint32)(inode_for_V[currVFile] & 0xffffffff));
1780 #else
1781             call_syscall(AFSOP_CACHEINODE, inode_for_V[currVFile]);
1782 #endif
1783         } /*end for*/
1784
1785
1786     /*
1787      * All the necessary info has been passed into the kernel to run an AFS
1788      * system.  Give the kernel our go-ahead.
1789      */
1790     if (afsd_debug)
1791          printf("%s: Calling AFSOP_GO with cacheSetTime = %d\n",
1792                 rn, cacheSetTime);
1793      call_syscall(AFSOP_GO, cacheSetTime);
1794
1795     /*
1796      * At this point, we have finished passing the kernel all the info 
1797      * it needs to set up the AFS.  Mount the AFS root.
1798      */
1799     printf("%s: All AFS daemons started.\n", rn);
1800
1801     if (afsd_verbose)
1802         printf("%s: Forking trunc-cache daemon.\n", rn);
1803     code = fork();
1804     if (code == 0) {
1805         /* Child */
1806         call_syscall(AFSOP_START_TRUNCDAEMON);
1807         exit(1);
1808     }
1809
1810     mountFlags = 0;     /* Read/write file system, can do setuid() */
1811 #if     defined(AFS_SUN_ENV) || defined(AFS_SUN5_ENV)
1812 #ifdef  AFS_SUN5_ENV
1813     mountFlags |= MS_DATA;
1814 #else
1815     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... */
1816 #endif
1817 #endif
1818
1819 #if defined(AFS_HPUX100_ENV)
1820         mountFlags |= MS_DATA;
1821 #endif
1822
1823     if (afsd_verbose)
1824         printf("%s: Mounting the AFS root on '%s', flags: %d.\n",
1825                rn, cacheMountDir, mountFlags);
1826 #ifdef AFS_DEC_ENV
1827     if ((mount("AFS",cacheMountDir,mountFlags,GT_AFS,(caddr_t) 0)) < 0) {
1828 #else
1829 #ifdef AFS_FBSD_ENV
1830     if ((mount("AFS",cacheMountDir,mountFlags,(caddr_t) 0)) < 0) {
1831 #else
1832 #ifdef  AFS_AUX_ENV
1833     if ((fsmount(MOUNT_AFS,cacheMountDir,mountFlags,(caddr_t) 0)) < 0)  {
1834 #else
1835 #ifdef  AFS_AIX_ENV
1836     if (aix_vmount()) {
1837 #else
1838 #if defined(AFS_HPUX100_ENV)
1839     if ((mount("",cacheMountDir,mountFlags,"afs", NULL, 0)) < 0) {
1840 #else
1841 #ifdef  AFS_HPUX_ENV
1842 #if     defined(AFS_HPUX90_ENV)
1843     { 
1844         char buffer[80];
1845         int code;
1846
1847         strcpy(buffer, "afs");
1848         code = vfsmount(-1,cacheMountDir,mountFlags,(caddr_t) buffer);
1849         sscanf(buffer, "%d", &vfs1_type);
1850         if (code < 0) {
1851             printf("Can't find 'afs' type in the registered filesystem table!\n");
1852             exit(1);
1853         }
1854         sscanf(buffer, "%d", &vfs1_type);
1855         if (afsd_verbose)
1856             printf("AFS vfs slot number is %d\n", vfs1_type);
1857     }
1858     if ((vfsmount(vfs1_type,cacheMountDir,mountFlags,(caddr_t) 0)) < 0) {
1859 #else
1860     if (call_syscall(AFSOP_AFS_VFSMOUNT, MOUNT_AFS, cacheMountDir,
1861                      mountFlags, (caddr_t)NULL) < 0) {
1862 #endif
1863 #else
1864 #ifdef  AFS_SUN5_ENV
1865     if ((mount("AFS",cacheMountDir,mountFlags,"afs", NULL, 0)) < 0) {
1866 #else
1867 #if defined(AFS_SGI_ENV)
1868     mountFlags = MS_FSS;
1869     if ((mount(MOUNT_AFS,cacheMountDir,mountFlags,(caddr_t) MOUNT_AFS)) < 0) {
1870 #else
1871 #ifdef AFS_LINUX20_ENV
1872     if ((mount("AFS", cacheMountDir, MOUNT_AFS, 0, NULL))<0) {
1873 #else
1874 /* This is the standard mount used by the suns and rts */
1875     if ((mount(MOUNT_AFS,cacheMountDir,mountFlags,(caddr_t) 0)) < 0) {
1876 #endif /* AFS_LINUX20_ENV */
1877 #endif /* AFS_SGI_ENV */
1878 #endif /* AFS_SUN5_ENV */
1879 #endif /* AFS_HPUX100_ENV */
1880 #endif /* AFS_HPUX_ENV */
1881 #endif /* AFS_AIX_ENV */
1882 #endif /* AFS_AUX_ENV */
1883 #endif /* AFS_FBSD_ENV */
1884 #endif /* AFS_DEC_ENV */
1885          printf("%s: Can't mount AFS on %s(%d)\n",
1886                    rn, cacheMountDir, errno);
1887          exit(1);
1888     }
1889
1890     HandleMTab();
1891
1892     if (afsd_rmtsys) {
1893         if (afsd_verbose)
1894             printf("%s: Forking 'rmtsys' daemon.\n", rn);
1895         code = fork();
1896         if (code == 0) {
1897             /* Child */
1898             rmtsysd();
1899             exit(1);
1900         }
1901     }
1902     /*
1903      * Exit successfully.
1904      */
1905     exit(0);
1906 }
1907
1908 #include "AFS_component_version_number.c"
1909
1910
1911
1912 main(argc, argv)
1913 int argc;
1914 char **argv; {
1915     register struct cmd_syndesc *ts;
1916
1917     ts = cmd_CreateSyntax(NULL, mainproc, NULL, "start AFS");
1918     cmd_AddParm(ts, "-blocks", CMD_SINGLE, CMD_OPTIONAL, "1024 byte blocks in cache");
1919     cmd_AddParm(ts, "-files", CMD_SINGLE, CMD_OPTIONAL, "files in cache");
1920     cmd_AddParm(ts, "-rootvol", CMD_SINGLE, CMD_OPTIONAL, "name of AFS root volume");
1921     cmd_AddParm(ts, "-stat", CMD_SINGLE, CMD_OPTIONAL, "number of stat entries");
1922     cmd_AddParm(ts, "-memcache", CMD_FLAG, CMD_OPTIONAL, "run diskless");
1923     cmd_AddParm(ts, "-cachedir", CMD_SINGLE, CMD_OPTIONAL, "cache directory");
1924     cmd_AddParm(ts, "-mountdir", CMD_SINGLE, CMD_OPTIONAL, "mount location");
1925     cmd_AddParm(ts, "-daemons", CMD_SINGLE, CMD_OPTIONAL, "number of daemons to use");
1926     cmd_AddParm(ts, "-nosettime", CMD_FLAG, CMD_OPTIONAL, "don't set the time");
1927     cmd_AddParm(ts, "-verbose", CMD_FLAG, CMD_OPTIONAL, "display lots of information");
1928     cmd_AddParm(ts, "-rmtsys", CMD_FLAG, CMD_OPTIONAL, "start NFS rmtsysd program");
1929     cmd_AddParm(ts, "-debug", CMD_FLAG, CMD_OPTIONAL, "display debug info");
1930     cmd_AddParm(ts, "-chunksize", CMD_SINGLE, CMD_OPTIONAL, "log(2) of chunk size");
1931     cmd_AddParm(ts, "-dcache", CMD_SINGLE, CMD_OPTIONAL, "number of dcache entries");
1932     cmd_AddParm(ts, "-volumes", CMD_SINGLE, CMD_OPTIONAL, "number of volume entries");
1933     cmd_AddParm(ts, "-biods", CMD_SINGLE, CMD_OPTIONAL, "number of bkg I/O daemons (aix vm)");
1934
1935     cmd_AddParm(ts, "-prealloc", CMD_SINGLE, CMD_OPTIONAL, "number of 'small' preallocated blocks");
1936 #ifdef notdef
1937     cmd_AddParm(ts, "-pininodes", CMD_SINGLE, CMD_OPTIONAL, "number of inodes to hog"); 
1938 #endif
1939     cmd_AddParm(ts, "-confdir", CMD_SINGLE, CMD_OPTIONAL, "configuration directory");
1940     cmd_AddParm(ts, "-logfile", CMD_SINGLE, CMD_OPTIONAL, "Place to keep the CM log");
1941     cmd_AddParm(ts, "-waitclose", CMD_FLAG, CMD_OPTIONAL, "make close calls synchronous");
1942     cmd_AddParm(ts, "-shutdown", CMD_FLAG, CMD_OPTIONAL, "Shutdown all afs state");
1943     cmd_AddParm(ts, "-enable_peer_stats", CMD_FLAG, CMD_OPTIONAL|CMD_HIDE, "Collect rpc statistics by peer");
1944     cmd_AddParm(ts, "-enable_process_stats", CMD_FLAG, CMD_OPTIONAL|CMD_HIDE, "Collect rpc statistics for this process");
1945     cmd_AddParm(ts, "-mem_alloc_sleep", CMD_FLAG, (CMD_OPTIONAL | CMD_HIDE), "Allow sleeps when allocating memory cache");
1946     cmd_AddParm(ts, "-afsdb", CMD_FLAG, (CMD_OPTIONAL
1947 #ifndef AFS_AFSDB_ENV
1948                 | CMD_HIDE
1949 #endif
1950                 ), "Enable AFSDB support");
1951     cmd_AddParm(ts, "-files_per_subdir", CMD_SINGLE, CMD_OPTIONAL, "log(2) of the number of cache files per cache subdirectory");
1952     cmd_AddParm(ts, "-dynroot", CMD_FLAG, CMD_OPTIONAL, "Enable dynroot support");
1953     cmd_AddParm(ts, "-fakestat", CMD_FLAG, CMD_OPTIONAL, "Enable fakestat support");
1954     return (cmd_Dispatch(argc, argv));
1955 }
1956
1957
1958 #ifdef  AFS_HPUX_ENV
1959 #define MOUNTED_TABLE   MNT_MNTTAB
1960 #else
1961 #ifdef  AFS_SUN5_ENV
1962 #define MOUNTED_TABLE   MNTTAB
1963 #else
1964 #define MOUNTED_TABLE   MOUNTED
1965 #endif
1966 #endif
1967
1968 static int HandleMTab() {
1969 #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)
1970     FILE *tfilep;
1971 #ifdef  AFS_SUN5_ENV
1972     char tbuf[16];
1973     struct mnttab tmntent;
1974
1975     memset(&tmntent, '\0', sizeof(struct mnttab));
1976     if (!(tfilep = fopen(MOUNTED_TABLE, "a+"))) {
1977         printf("Can't open %s\n", MOUNTED_TABLE);
1978         perror(MNTTAB);
1979         exit(-1);
1980     }
1981     tmntent.mnt_special = "AFS";
1982     tmntent.mnt_mountp = cacheMountDir;
1983     tmntent.mnt_fstype = "xx";
1984     tmntent.mnt_mntopts = "rw";
1985     sprintf(tbuf, "%ld", (long)time((time_t *)0));
1986     tmntent.mnt_time = tbuf;
1987     putmntent(tfilep, &tmntent);
1988     fclose(tfilep);
1989 #else
1990 #if defined(AFS_SGI_ENV) || defined(AFS_LINUX20_ENV)
1991     struct mntent tmntent;
1992
1993     tfilep = setmntent("/etc/mtab", "a+");
1994     tmntent.mnt_fsname = "AFS";
1995     tmntent.mnt_dir = cacheMountDir;
1996     tmntent.mnt_type = "afs";
1997     tmntent.mnt_opts = "rw";
1998     tmntent.mnt_freq = 1;
1999     tmntent.mnt_passno = 3;
2000     addmntent(tfilep, &tmntent);
2001     endmntent(tfilep);
2002 #else
2003     struct mntent tmntent;
2004
2005     memset(&tmntent, '\0', sizeof(struct mntent));
2006     tfilep = setmntent(MOUNTED_TABLE, "a+");
2007     if (!tfilep) {
2008         printf("Can't open %s for write; Not adding afs entry to it\n",
2009                MOUNTED_TABLE);
2010         return 1;
2011     }
2012     tmntent.mnt_fsname = "AFS";
2013     tmntent.mnt_dir = cacheMountDir;
2014     tmntent.mnt_type = "xx";
2015     tmntent.mnt_opts = "rw";
2016     tmntent.mnt_freq = 1;
2017     tmntent.mnt_passno = 3;
2018 #ifdef  AFS_HPUX_ENV
2019     tmntent.mnt_time = time(0);
2020     tmntent.mnt_cnode = 0;
2021 #endif
2022     addmntent(tfilep, &tmntent);
2023     endmntent(tfilep);
2024 #endif  /* AFS_SGI_ENV */
2025 #endif  /* AFS_SUN5_ENV */
2026 #endif  /* unreasonable systems */
2027     return 0;
2028 }
2029
2030 #if !defined(AFS_SGI_ENV) && !defined(AFS_AIX32_ENV)
2031 call_syscall(param1, param2, param3, param4, param5, param6, param7)
2032 long param1, param2, param3, param4, param5, param6, param7;
2033 {
2034     int error;
2035 #ifdef AFS_LINUX20_ENV
2036     long eparm[4];
2037
2038     eparm[0] = param4;
2039     eparm[1] = param5;
2040     eparm[2] = param6;
2041     eparm[3] = param7;
2042
2043     param4 = eparm;
2044 #endif
2045
2046     error = syscall(AFS_SYSCALL, AFSCALL_CALL, param1, param2, param3, param4, param5, param6, param7);
2047     if (afsd_verbose) printf("SScall(%d, %d, %d)=%d ", AFS_SYSCALL, AFSCALL_CALL, param1, error);
2048     return (error);
2049 }
2050 #else   /* AFS_AIX32_ENV */
2051 #if defined(AFS_SGI_ENV)
2052 call_syscall(call, parm0, parm1, parm2, parm3, parm4)
2053 {
2054
2055         int error;
2056
2057         error = afs_syscall(call, parm0, parm1, parm2, parm3, parm4);
2058         if (afsd_verbose) printf("SScall(%d, %d)=%d ", call, parm0, error);
2059
2060         return error;
2061 }
2062 #else
2063 call_syscall(call, parm0, parm1, parm2, parm3, parm4, parm5, parm6) {
2064
2065     return syscall(AFSCALL_CALL, call, parm0, parm1, parm2, parm3, parm4, parm5, parm6);
2066 }
2067 #endif /* AFS_SGI_ENV */
2068 #endif /* AFS_AIX32_ENV */
2069
2070
2071 #ifdef  AFS_AIX_ENV
2072 /* Special handling for AIX's afs mount operation since they require much more miscl. information before making the vmount(2) syscall */
2073 #include <sys/vfs.h>
2074
2075 #define ROUNDUP(x)  (((x) + 3) & ~3)
2076
2077 aix_vmount() {
2078     struct vmount   *vmountp;
2079     int size, error;
2080
2081     size = sizeof(struct vmount) + ROUNDUP(strlen(cacheMountDir)+1) + 5*4;
2082     /* Malloc the vmount structure */
2083     if ((vmountp = (struct vmount *)malloc(size)) == (struct vmount *)NULL) {
2084          printf("Can't allocate space for the vmount structure (AIX)\n");
2085          exit(1);
2086     }
2087
2088     /* zero out the vmount structure */
2089     memset(vmountp, '\0', size);
2090  
2091     /* transfer info into the vmount structure */
2092     vmountp->vmt_revision = VMT_REVISION;
2093     vmountp->vmt_length = size;
2094     vmountp->vmt_fsid.fsid_dev = 0;
2095     vmountp->vmt_fsid.fsid_type = AFS_MOUNT_AFS;
2096     vmountp->vmt_vfsnumber = 0;
2097     vmountp->vmt_time = 0;/* We'll put the time soon! */
2098     vmountp->vmt_flags = VFS_DEVMOUNT;  /* read/write permission */
2099     vmountp->vmt_gfstype = AFS_MOUNT_AFS;
2100     vmountdata(vmountp, "AFS", cacheMountDir, "", "", "", "rw");
2101     
2102     /* Do the actual mount system call */
2103     error = vmount(vmountp, size);
2104     free(vmountp);
2105     return(error);
2106 }
2107
2108 vmountdata(vmtp, obj, stub, host, hostsname, info, args)
2109 struct vmount   *vmtp;
2110 char    *obj, *stub, *host, *hostsname, *info, *args;
2111 {
2112         register struct data {
2113                                 short   vmt_off;
2114                                 short   vmt_size;
2115                         } *vdp, *vdprev;
2116         register int    size;
2117
2118         vdp = (struct data *)vmtp->vmt_data;
2119         vdp->vmt_off = sizeof(struct vmount);
2120         size = ROUNDUP(strlen(obj) + 1);
2121         vdp->vmt_size = size;
2122         strcpy(vmt2dataptr(vmtp, VMT_OBJECT), obj);
2123
2124         vdprev = vdp;
2125         vdp++;
2126         vdp->vmt_off =  vdprev->vmt_off + size;
2127         size = ROUNDUP(strlen(stub) + 1);
2128         vdp->vmt_size = size;
2129         strcpy(vmt2dataptr(vmtp, VMT_STUB), stub);
2130
2131         vdprev = vdp;
2132         vdp++;
2133         vdp->vmt_off = vdprev->vmt_off + size;
2134         size = ROUNDUP(strlen(host) + 1);
2135         vdp->vmt_size = size;
2136         strcpy(vmt2dataptr(vmtp, VMT_HOST), host);
2137
2138         vdprev = vdp;
2139         vdp++;
2140         vdp->vmt_off = vdprev->vmt_off + size;
2141         size = ROUNDUP(strlen(hostsname) + 1);
2142         vdp->vmt_size = size;
2143         strcpy(vmt2dataptr(vmtp, VMT_HOSTNAME), hostsname);
2144
2145
2146         vdprev = vdp;
2147         vdp++;
2148         vdp->vmt_off =  vdprev->vmt_off + size;
2149         size = ROUNDUP(strlen(info) + 1);
2150         vdp->vmt_size = size;
2151         strcpy(vmt2dataptr(vmtp, VMT_INFO), info);
2152
2153         vdprev = vdp;
2154         vdp++;
2155         vdp->vmt_off =  vdprev->vmt_off + size;
2156         size = ROUNDUP(strlen(args) + 1);
2157         vdp->vmt_size = size;
2158         strcpy(vmt2dataptr(vmtp, VMT_ARGS), args);
2159 }
2160 #endif /* AFS_AIX_ENV */
2161
2162 #ifdef  AFS_SGI53_ENV
2163 #ifdef AFS_SGI61_ENV
2164 /* The dwarf structures are searched to find entry points of static functions
2165  * and the addresses of static variables. The file name as well as the
2166  * sybmol name is reaquired.
2167  */
2168
2169 /* Contains list of names to find in given file. */
2170 typedef struct {
2171     char *name;         /* Name of variable or function. */
2172     afs_hyper_t addr;   /* Address of function, undefined if not found. */
2173     Dwarf_Half type; /* DW_AT_location for vars, DW_AT_lowpc for func's */
2174     char found;         /* set if found. */
2175 } staticAddrList;
2176
2177 typedef struct  {
2178     char *file;                 /* Name of file containing vars or funcs */
2179     staticAddrList *addrList;   /* List of vars and/or funcs. */
2180     int nAddrs;                 /* # of addrList's */
2181     int found;                  /* set if we've found this file already. */
2182 } staticNameList;
2183
2184 /* routines used to find addresses in /unix */
2185 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
2186 void findMDebugStaticAddresses(staticNameList *, int, int);
2187 #endif
2188 void findDwarfStaticAddresses(staticNameList *, int);
2189 void findElfAddresses(Dwarf_Debug, Dwarf_Die, staticNameList *);
2190 void getElfAddress(Dwarf_Debug, Dwarf_Die, staticAddrList *);
2191
2192 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
2193 #define AFS_N_FILELISTS 2
2194 #define AFS_SYMS_NEEDED 3
2195 #else /* AFS_SGI62_ENV */
2196 #define AFS_N_FILELISTS 1
2197 #endif /* AFS_SGI62_ENV */
2198
2199
2200
2201 void set_staticaddrs(void)
2202 {
2203     staticNameList fileList[AFS_N_FILELISTS];
2204
2205     fileList[0].addrList = (staticAddrList*)calloc(1, sizeof(staticAddrList));
2206     if (!fileList[0].addrList) {
2207         printf("set_staticaddrs: Can't calloc fileList[0].addrList\n");
2208         return;
2209     }
2210     fileList[0].file = "nfs_server.c";
2211     fileList[0].found = 0;
2212     fileList[0].nAddrs = 1;
2213     fileList[0].addrList[0].name = "rfsdisptab_v2";
2214     fileList[0].addrList[0].type = DW_AT_location;
2215     fileList[0].addrList[0].found = 0;
2216
2217 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
2218     fileList[1].addrList = (staticAddrList*)calloc(2, sizeof(staticAddrList));
2219     if (!fileList[1].addrList) {
2220         printf("set_staticaddrs: Can't malloc fileList[1].addrList\n");
2221         return;
2222     }
2223     fileList[1].file = "uipc_socket.c";
2224     fileList[1].found = 0;
2225     fileList[1].nAddrs = 2;
2226     fileList[1].addrList[0].name = "sblock";
2227     fileList[1].addrList[0].type = DW_AT_low_pc;
2228     fileList[1].addrList[0].found = 0;
2229     fileList[1].addrList[1].name = "sbunlock";
2230     fileList[1].addrList[1].type = DW_AT_low_pc;
2231     fileList[1].addrList[1].found = 0;
2232
2233     if (64 != sysconf(_SC_KERN_POINTERS))
2234         findMDebugStaticAddresses(fileList, AFS_N_FILELISTS, AFS_SYMS_NEEDED);
2235     else
2236 #endif /* AFS_SGI62_ENV */
2237         findDwarfStaticAddresses(fileList, AFS_N_FILELISTS);
2238
2239     if (fileList[0].addrList[0].found) {
2240         call_syscall(AFSOP_NFSSTATICADDR2, fileList[0].addrList[0].addr.high,
2241                      fileList[0].addrList[0].addr.low);
2242     }
2243     else {
2244         if (afsd_verbose)
2245             printf("NFS V2 is not present in the kernel.\n");
2246     }
2247     free(fileList[0].addrList);
2248 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
2249     if (fileList[1].addrList[0].found && fileList[1].addrList[1].found) {
2250         call_syscall(AFSOP_SBLOCKSTATICADDR2,
2251                      fileList[1].addrList[0].addr.high,
2252                      fileList[1].addrList[0].addr.low,
2253                      fileList[1].addrList[1].addr.high,
2254                      fileList[1].addrList[1].addr.low);
2255     }
2256     else {
2257         if (!fileList[1].addrList[0].found)
2258             printf("Can't find %s in kernel. Exiting.\n",
2259                    fileList[1].addrList[0].name);
2260         if (!fileList[1].addrList[0].found)
2261             printf("Can't find %s in kernel. Exiting.\n",
2262                    fileList[1].addrList[1].name);
2263         exit(1);
2264     }
2265     free(fileList[1].addrList);
2266 #endif /* AFS_SGI62_ENV */
2267 }
2268
2269
2270 /* Find addresses for static variables and functions. */
2271 void
2272 findDwarfStaticAddresses(staticNameList * nameList, int nLists)
2273 {
2274     int fd;
2275     int i;
2276     int found = 0;
2277     int code;
2278     char *s;
2279     char *hname = (char*)0;
2280     Dwarf_Unsigned dwarf_access = O_RDONLY;
2281     Dwarf_Debug dwarf_debug;
2282     Dwarf_Error dwarf_error;
2283     Dwarf_Unsigned dwarf_cu_header_length;
2284     Dwarf_Unsigned dwarf_abbrev_offset;
2285     Dwarf_Half dwarf_address_size;
2286     Dwarf_Unsigned next_cu_header;
2287     Dwarf_Die dwarf_die;
2288     Dwarf_Die dwarf_next_die;
2289     Dwarf_Die dwarf_child_die;
2290
2291     if (elf_version(EV_CURRENT) == EV_NONE) {
2292         printf("findDwarfStaticAddresses: Bad elf version.\n");
2293         return;
2294     }
2295
2296     if ((fd=open("/unix", O_RDONLY,0))<0) {
2297         printf("findDwarfStaticAddresses: Failed to open /unix.\n");
2298         return;
2299     }
2300     code = dwarf_init(fd, dwarf_access, NULL, NULL, &dwarf_debug,
2301                       &dwarf_error);
2302     if (code != DW_DLV_OK) {
2303         /* Nope hope for the elves and dwarves, try intermediate code. */
2304         close(fd);
2305         return;
2306     }
2307
2308     found = 0;
2309     while (1) {
2310         /* Run through the headers until we find ones for files we've
2311          * specified in nameList.
2312          */
2313         code = dwarf_next_cu_header(dwarf_debug,
2314                                     &dwarf_cu_header_length, NULL,
2315                                     &dwarf_abbrev_offset,
2316                                     &dwarf_address_size,
2317                                     &next_cu_header,
2318                                     &dwarf_error);
2319         if (code == DW_DLV_NO_ENTRY) {
2320             break;
2321         }
2322         else if (code == DW_DLV_ERROR) {
2323             printf("findDwarfStaticAddresses: Error reading headers: %s\n",
2324                    dwarf_errmsg(dwarf_error));
2325             break;
2326         }
2327
2328         code = dwarf_siblingof(dwarf_debug, NULL, &dwarf_die, &dwarf_error);
2329         if (code != DW_DLV_OK) {
2330             printf("findDwarfStaticAddresses: Can't get first die. %s\n",
2331                    (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
2332             break;
2333         }
2334
2335         /* This is the header, test the name. */
2336         code = dwarf_diename(dwarf_die, &hname, &dwarf_error);
2337         if (code == DW_DLV_OK) {
2338             s = strrchr(hname, '/');
2339             for (i=0; i<nLists; i++) {
2340                 if (s && !strcmp(s+1, nameList[i].file)) {
2341                     findElfAddresses(dwarf_debug, dwarf_die, &nameList[i]);
2342                     found ++;
2343                     break;
2344                 }
2345             }
2346         }
2347         else {
2348             printf("findDwarfStaticAddresses: Can't get name of current header. %s\n",
2349                    (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
2350             break;
2351         }
2352         dwarf_dealloc(dwarf_debug, hname, DW_DLA_STRING);
2353         hname = (char*)0;
2354         if (found >= nLists) { /* we're done */
2355             break;
2356         }
2357     }
2358
2359      /* Frees up all allocated space. */
2360     (void) dwarf_finish(dwarf_debug, &dwarf_error);
2361     close(fd);
2362 }
2363
2364 void
2365 findElfAddresses(Dwarf_Debug dwarf_debug, Dwarf_Die dwarf_die,
2366                  staticNameList * nameList)
2367 {
2368     int i;
2369     Dwarf_Error dwarf_error;
2370     Dwarf_Die dwarf_next_die;
2371     Dwarf_Die dwarf_child_die;
2372     Dwarf_Attribute dwarf_return_attr;
2373     char *vname = (char*)0;
2374     int found = 0;
2375     int code;
2376     
2377     /* Drop into this die to find names in addrList. */
2378     code = dwarf_child(dwarf_die, &dwarf_child_die, &dwarf_error);
2379     if (code != DW_DLV_OK) {
2380         printf("findElfAddresses: Can't get child die. %s\n",
2381                (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
2382         return;
2383     }
2384
2385     /* Try to find names in each sibling. */
2386     dwarf_next_die = (Dwarf_Die)0;
2387     do {
2388         code = dwarf_diename(dwarf_child_die, &vname,
2389                              &dwarf_error);
2390         /* It's possible that some siblings don't have names. */
2391         if (code == DW_DLV_OK) {
2392             for (i=0; i<nameList->nAddrs; i++) {
2393                 if (!nameList->addrList[i].found) {
2394                     if (!strcmp(vname, nameList->addrList[i].name)) {
2395                         getElfAddress(dwarf_debug, dwarf_child_die,
2396                                           &(nameList->addrList[i]));
2397                         found ++;
2398                         break;
2399                     }
2400                 }
2401             }
2402         }
2403         if (dwarf_next_die)
2404             dwarf_dealloc(dwarf_debug, dwarf_next_die, DW_DLA_DIE);
2405
2406         if (found >= nameList->nAddrs) { /* we're done. */
2407             break;
2408         }
2409
2410         dwarf_next_die = dwarf_child_die;
2411         code = dwarf_siblingof(dwarf_debug, dwarf_next_die,
2412                                &dwarf_child_die,
2413                                &dwarf_error);
2414      
2415     } while(code == DW_DLV_OK);
2416 }
2417
2418 /* Get address out of current die. */
2419 void
2420 getElfAddress(Dwarf_Debug dwarf_debug,
2421               Dwarf_Die dwarf_child_die, staticAddrList *addrList)
2422 {
2423     int i;
2424     Dwarf_Error dwarf_error;
2425     Dwarf_Attribute dwarf_return_attr;
2426     Dwarf_Bool dwarf_return_bool;
2427     Dwarf_Locdesc *llbuf = NULL;
2428     Dwarf_Signed listlen;
2429     off64_t addr = (off64_t)0;
2430     int code;
2431
2432     code = dwarf_hasattr(dwarf_child_die, addrList->type,
2433                          &dwarf_return_bool, &dwarf_error);
2434     if ((code !=  DW_DLV_OK) || (!dwarf_return_bool)) {
2435         printf("getElfAddress: no address given for %s. %s\n",
2436                addrList->name, (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
2437         return;
2438     }
2439     code = dwarf_attr(dwarf_child_die, addrList->type,
2440                       &dwarf_return_attr,  &dwarf_error);
2441     if (code !=  DW_DLV_OK) {
2442         printf("getElfAddress: Can't get attribute. %s\n",
2443                (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
2444         return;
2445     }
2446
2447     switch (addrList->type) {
2448     case DW_AT_location:
2449         code = dwarf_loclist(dwarf_return_attr, &llbuf,
2450                              &listlen, &dwarf_error);
2451         if (code !=   DW_DLV_OK) {
2452             printf("getElfAddress: Can't get location for %s. %s\n",
2453                    addrList->name,
2454                    (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
2455             return;
2456         }
2457         if ((listlen != 1) || (llbuf[0].ld_cents != 1)) {
2458             printf("getElfAddress: %s has more than one address.\n",
2459                    addrList->name);
2460             return;
2461         }
2462         addr = llbuf[0].ld_s[0].lr_number;
2463         break;
2464
2465     case DW_AT_low_pc:
2466         code = dwarf_lowpc(dwarf_child_die, (Dwarf_Addr*)&addr, &dwarf_error);
2467         if ( code !=  DW_DLV_OK) {
2468             printf("getElfAddress: Can't get lowpc for %s. %s\n",
2469                    addrList->name,
2470                    (code == DW_DLV_ERROR) ? dwarf_errmsg(dwarf_error) : "");
2471             return;
2472         }
2473         break;
2474         
2475     default:
2476         printf("getElfAddress: Bad case %d in switch.\n", addrList->type);
2477         return;
2478     }
2479
2480     addrList->addr.high = (addr>>32) & 0xffffffff;
2481     addrList->addr.low  = addr & 0xffffffff;
2482     addrList->found = 1;
2483 }
2484
2485 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
2486 /* Find symbols in the .mdebug section for 32 bit kernels. */
2487 /*
2488  * do_mdebug()
2489  * On 32bit platforms, we're still using the ucode compilers to build
2490  * the kernel, so we need to get our static text/data from the .mdebug
2491  * section instead of the .dwarf sections.
2492  */
2493 /* SearchNameList searches our bizarre structs for the given string.
2494  * If found, sets the found bit and the address and returns 1.
2495  * Not found returns 0.
2496  */
2497 int SearchNameList(char *name, afs_uint32 addr, staticNameList *nameList,
2498                    int nLists)
2499 {
2500     int i, j;                   
2501     for (i=0; i<nLists; i++) {
2502         for (j=0; j<nameList[i].nAddrs; j++) {
2503             if (nameList[i].addrList[j].found)
2504                 continue;
2505             if (!strcmp(name, nameList[i].addrList[j].name)) {
2506                 nameList[i].addrList[j].addr.high = 0;
2507                 nameList[i].addrList[j].addr.low = addr;
2508                 nameList[i].addrList[j].found = 1;
2509                 return 1;
2510             }
2511         }
2512     }
2513     return 0;
2514 }
2515                                         
2516 static void
2517 SearchMDebug(Elf_Scn *scnp, Elf32_Shdr *shdrp, staticNameList * nameList,
2518              int nLists, int needed)
2519 {
2520     long *buf = (long *)(elf_getdata(scnp, NULL)->d_buf); 
2521     u_long addr, mdoff = shdrp->sh_offset;
2522     HDRR *hdrp;
2523     SYMR *symbase, *symp, *symend;
2524     FDR *fdrbase, *fdrp;
2525     int i, j;
2526     char *strbase, *str;
2527     int ifd;
2528     int nFound = 0;
2529     
2530     /* get header */
2531     addr = (__psunsigned_t)buf;
2532     hdrp = (HDRR *)addr;
2533     
2534     /* setup base addresses */
2535     addr = (u_long)buf + (u_long)(hdrp->cbFdOffset - mdoff);
2536     fdrbase = (FDR *)addr;
2537     addr = (u_long)buf + (u_long)(hdrp->cbSymOffset - mdoff);
2538     symbase = (SYMR *)addr;
2539     addr = (u_long)buf + (u_long)(hdrp->cbSsOffset - mdoff);
2540     strbase = (char *)addr;
2541     
2542 #define KEEPER(a,b)     ((a == stStaticProc && b == scText) || \
2543                          (a == stStatic && (b == scData || b == scBss || \
2544                                             b == scSBss || b == scSData)))
2545         
2546     for (fdrp = fdrbase; fdrp < &fdrbase[hdrp->ifdMax]; fdrp++) {
2547         str = strbase + fdrp->issBase + fdrp->rss;
2548         
2549         /* local symbols for each fd */
2550         for (symp = &symbase[fdrp->isymBase];
2551              symp < &symbase[fdrp->isymBase+fdrp->csym];
2552              symp++) {
2553             if (KEEPER(symp->st, symp->sc)) {
2554                 if (symp->value == 0)
2555                     continue;
2556                 
2557                 str = strbase + fdrp->issBase + symp->iss;
2558                 /* Look for AFS symbols of interest */
2559                 if (SearchNameList(str, symp->value,
2560                                    nameList, nLists)) {
2561                     nFound ++;
2562                     if (nFound >= needed)
2563                         return;
2564                 }
2565             }
2566         }
2567     }
2568 }
2569     
2570 /*
2571  * returns section with the name of scn_name, & puts its header in shdr64 or
2572  * shdr32 based on elf's file type
2573  *
2574  */
2575 Elf_Scn *
2576 findMDebugSection(Elf *elf, char *scn_name)
2577 {
2578         Elf64_Ehdr *ehdr64;
2579         Elf32_Ehdr *ehdr32;
2580         Elf_Scn *scn = NULL;
2581         Elf64_Shdr *shdr64;
2582         Elf32_Shdr *shdr32;
2583
2584         if ((ehdr32 = elf32_getehdr(elf)) == NULL)
2585                 return(NULL);
2586         do {
2587                 if ((scn = elf_nextscn(elf, scn)) == NULL)
2588                         break;
2589                 if ((shdr32 = elf32_getshdr(scn)) == NULL)
2590                         return(NULL);
2591         } while (strcmp(scn_name, elf_strptr(elf, ehdr32->e_shstrndx,
2592                                                   shdr32->sh_name)));
2593
2594         return(scn);    
2595 }
2596
2597
2598 void findMDebugStaticAddresses(staticNameList * nameList, int nLists,
2599                                int needed)
2600 {
2601     int fd;
2602     Elf *elf;
2603     Elf_Scn *mdebug_scn;
2604     Elf32_Shdr *mdebug_shdr;
2605     char *names;
2606
2607     if ((fd = open("/unix", O_RDONLY)) == -1) {
2608         printf("findMDebugStaticAddresses: Failed to open /unix.\n");
2609         return;
2610     }
2611
2612     (void)elf_version(EV_CURRENT);
2613     if((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
2614         printf("findMDebugStaticAddresses: /unix doesn't seem to be an elf file\n");
2615         close(fd);
2616         return;
2617     }
2618     mdebug_scn = findMDebugSection(elf, ".mdebug");
2619     if (!mdebug_scn) {
2620         printf("findMDebugStaticAddresses: Can't find .mdebug section.\n");
2621         goto find_end;
2622     }
2623     mdebug_shdr = elf32_getshdr(mdebug_scn);
2624     if (!mdebug_shdr) {
2625         printf("findMDebugStaticAddresses: Can't find .mdebug header.\n");
2626         goto find_end;
2627     }
2628
2629     (void) SearchMDebug(mdebug_scn, mdebug_shdr, nameList, nLists, needed);
2630
2631  find_end:
2632     elf_end(elf);
2633     close(fd);
2634 }
2635 #endif /* AFS_SGI62_ENV */
2636
2637 #else /* AFS_SGI61_ENV */
2638 #include <nlist.h>
2639 struct  nlist nlunix[] = {
2640    { "rfsdisptab_v2" },
2641    { 0 },
2642 };
2643
2644 get_nfsstaticaddr() {
2645     int i, j, kmem, count;
2646
2647     if ((kmem = open("/dev/kmem", O_RDONLY)) < 0) {
2648         printf("Warning: can't open /dev/kmem\n");
2649         return 0;
2650     }
2651     if ((j = nlist("/unix", nlunix)) < 0) {
2652         printf("Warning: can't nlist /unix\n");
2653         return 0;
2654     }
2655     i = nlunix[0].n_value;
2656     if (lseek(kmem, i, L_SET/*0*/) != i) {
2657         printf("Warning: can't lseek to %x\n", i);      
2658         return 0;
2659     }
2660     if ((j = read(kmem, &count, sizeof count)) != sizeof count) {
2661         printf("WARNING: kmem read at %x failed\n", i);
2662         return 0;
2663     }
2664     return i;
2665 }
2666 #endif /* AFS_SGI61_ENV */
2667 #endif /* AFS_SGI53_ENV */