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