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