afs: clarify cold and warm shutdown logic
[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      [OBSOLETE] 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 (default).
33   *     -settime    [IGNORED] Keep checking the time to avoid drift.
34   *     -rxmaxmtu   Set the max mtu to help with VPN issues.
35   *     -verbose    Be chatty.
36   *     -disable-dynamic-vcaches     Disable the use of -stat value as the starting size of
37   *                          the size of the vcache/stat cache pool,
38   *                          but increase that pool dynamically as needed.
39   *     -debug     Print out additional debugging info.
40   *     -kerndev    [OBSOLETE] The kernel device for AFS.
41   *     -dontfork   [OBSOLETE] Don't fork off as a new process.
42   *     -daemons   The number of background daemons to start (Default: 2).
43   *     -rmtsys    Also fires up an afs remote sys call (e.g. pioctl, setpag)
44   *                support daemon
45   *     -chunksize [n]   2^n is the chunksize to be used.  0 is default.
46   *     -dcache    The number of data cache entries.
47   *     -volumes    The number of volume entries.
48   *     -biods     Number of bkg I/O daemons (AIX3.1 only)
49   *     -prealloc  Number of preallocated "small" memory blocks
50   *     -logfile    [IGNORED] Place where to put the logfile (default in
51   *                <cache>/etc/AFSLog.
52   *     -waitclose make close calls always synchronous (slows em down, tho)
53   *     -files_per_subdir [n]   number of files per cache subdir. (def=2048)
54   *     -shutdown  Shutdown afs daemons
55   *     -enable_peer_stats      Collect RPC statistics by peer.
56   *     -enable_process_stats   Collect RPC statistics for this process.
57   *     -mem_alloc_sleep [IGNORED] Sleep when allocating memory.
58   *     -afsdb      Enable AFSDB support.
59   *     -dynroot        Enable dynroot support.
60   *     -dynroot-sparse Enable dynroot support with minimal cell list.
61   *     -fakestat       Enable fake stat() for cross-cell mounts.
62   *     -fakestat-all   Enable fake stat() for all mounts.
63   *     -nomount    Do not mount /afs.
64   *     -backuptree Prefer backup volumes for mountpoints in backup volumes.
65   *     -rxbind     Bind the rx socket.
66   *     -rxpck      Value for rx_extraPackets.
67   *     -splitcache RW/RO ratio for cache.
68   *     -rxmaxfrags Max number of UDP fragments per rx packet.
69   *     -inumcalc  inode number calculation method; 0=compat, 1=MD5 digest
70   *     -volume-ttl vldb cache timeout in seconds
71   *---------------------------------------------------------------------------*/
72
73 #include <afsconfig.h>
74 #include <afs/param.h>
75 /* darwin dirent.h doesn't give us the prototypes we want if KERNEL is
76  * defined, and roken includes dirent */
77 #if defined(UKERNEL) && defined(AFS_USR_DARWIN_ENV)
78 # undef KERNEL
79 # include <roken.h>
80 # define KERNEL
81 #else
82 # include <roken.h>
83 #endif
84
85 #define VFS 1
86
87 #include <afs/stds.h>
88 #include <afs/opr.h>
89 #include <afs/opr_assert.h>
90
91 #include <afs/cmd.h>
92
93 #include "afsd.h"
94
95 #include <afs/afsutil.h>
96
97 #include <sys/file.h>
98 #include <sys/wait.h>
99 #include <hcrypto/rand.h>
100
101 /* darwin dirent.h doesn't give us the prototypes we want if KERNEL is
102  * defined */
103 #if defined(UKERNEL) && defined(AFS_USR_DARWIN_ENV)
104 # undef KERNEL
105 # include <dirent.h>
106 # define KERNEL
107 #else
108 # include <dirent.h>
109 #endif
110
111 #ifdef HAVE_SYS_FS_TYPES_H
112 #include <sys/fs_types.h>
113 #endif
114
115 #if defined(HAVE_SYS_MOUNT_H) && !defined(AFS_ARM_DARWIN_ENV)
116 #include <sys/mount.h>
117 #endif
118
119 #ifdef HAVE_SYS_FCNTL_H
120 #include <sys/fcntl.h>
121 #endif
122
123 #ifdef HAVE_SYS_MNTTAB_H
124 #include <sys/mnttab.h>
125 #endif
126
127 #ifdef HAVE_SYS_MNTENT_H
128 #include <sys/mntent.h>
129 #endif
130
131 #ifdef HAVE_MNTENT_H
132 #include <mntent.h>
133 #endif
134
135 #ifdef HAVE_SYS_VFS_H
136 #include <sys/vfs.h>
137 #endif
138
139 #ifdef HAVE_SYS_FSTYP_H
140 #include <sys/fstyp.h>
141 #endif
142
143 #include <ctype.h>
144
145 #include <afs/afs_args.h>
146 #include <afs/cellconfig.h>
147 #include <afs/afssyscalls.h>
148 #include <afs/afsutil.h>
149 #include <afs/sys_prototypes.h>
150
151 #if defined(AFS_SGI62_ENV) && !defined(AFS_SGI65_ENV)
152 #include <sym.h>
153 #include <symconst.h>
154 #endif
155 #ifdef AFS_SGI65_ENV
156 #include <sched.h>
157 #endif
158
159 #ifdef AFS_DARWIN_ENV
160 #ifdef AFS_DARWIN80_ENV
161 #include <sys/xattr.h>
162 #endif
163 #include <CoreFoundation/CoreFoundation.h>
164
165 static int event_pid;
166 #ifndef AFS_ARM_DARWIN_ENV
167 #define MACOS_EVENT_HANDLING 1
168 #endif
169 #endif /* AFS_DARWIN_ENV */
170
171 #if AFS_HAVE_STATVFS || defined(HAVE_SYS_STATVFS_H)
172 #include <sys/statvfs.h>
173 #else
174 #if defined(AFS_SUN_ENV)
175 #include <sys/vfs.h>
176 #else
177 #ifdef HAVE_SYS_STATFS_H
178 #include <sys/statfs.h>
179 #endif
180 #endif
181 #endif
182
183 #undef  VIRTUE
184 #undef  VICE
185
186 #ifdef AFS_SOCKPROXY_ENV
187 # include <sys/types.h>
188 # include <sys/socket.h>
189 #endif
190
191 #define CACHEINFOFILE   "cacheinfo"
192 #define DCACHEFILE      "CacheItems"
193 #define VOLINFOFILE     "VolumeItems"
194 #define CELLINFOFILE    "CellItems"
195
196 #define MAXIPADDRS 1024
197
198 char LclCellName[64];
199
200 #define MAX_CACHE_LOOPS 4
201
202
203 /*
204  * Internet address (old style... should be updated).  This was pulled out of the old 4.2
205  * version of <netinet/in.h>, since it's still useful.
206  */
207 struct in_addr_42 {
208     union {
209         struct {
210             u_char s_b1, s_b2, s_b3, s_b4;
211         } S_un_b;
212         struct {
213             u_short s_w1, s_w2;
214         } S_un_w;
215         afs_uint32 S_addr;
216     } S_un;
217 };
218
219 #define mPrintIPAddr(ipaddr)  printf("[%d.%d.%d.%d] ",          \
220       ((struct in_addr_42 *) &(ipaddr))->S_un.S_un_b.s_b1,      \
221       ((struct in_addr_42 *) &(ipaddr))->S_un.S_un_b.s_b2,      \
222       ((struct in_addr_42 *) &(ipaddr))->S_un.S_un_b.s_b3,      \
223       ((struct in_addr_42 *) &(ipaddr))->S_un.S_un_b.s_b4)
224
225 /*
226  * Global configuration variables.
227  */
228 static int enable_rxbind = 0;
229 static int cacheBlocks;         /*Num blocks in the cache */
230 static int cacheFiles;          /*Optimal # of files in workstation cache */
231 static int rwpct = 0;
232 static int ropct = 0;
233 static int cacheStatEntries;    /*Number of stat cache entries */
234 static char *cacheBaseDir;      /*Where the workstation AFS cache lives */
235 static char *confDir;           /*Where the workstation AFS configuration lives */
236 static char fullpn_DCacheFile[1024];    /*Full pathname of DCACHEFILE */
237 static char fullpn_VolInfoFile[1024];   /*Full pathname of VOLINFOFILE */
238 static char fullpn_CellInfoFile[1024];  /*Full pathanem of CELLINFOFILE */
239 static char fullpn_CacheInfo[1024];     /*Full pathname of CACHEINFO */
240 static char fullpn_VFile[1024]; /*Full pathname of data cache files */
241 static char *vFilePtr;                  /*Ptr to the number part of above pathname */
242 static int sawCacheMountDir = 0;        /* from cmd line */
243 static int sawCacheBaseDir = 0;
244 static int sawCacheBlocks = 0;
245 static int sawDCacheSize = 0;
246 #ifdef AFS_AIX32_ENV
247 static int sawBiod = 0;
248 #endif
249 static int sawCacheStatEntries = 0;
250 char *afsd_cacheMountDir;
251 static char *rootVolume = NULL;
252 #ifdef AFS_XBSD_ENV
253 static int createAndTrunc = O_RDWR | O_CREAT | O_TRUNC; /*Create & truncate on open */
254 #else
255 static int createAndTrunc = O_CREAT | O_TRUNC;  /*Create & truncate on open */
256 #endif
257 static int ownerRWmode = 0600;          /*Read/write OK by owner */
258 static int filesSet = 0;        /*True if number of files explicitly set */
259 static int nFilesPerDir = 2048; /* # files per cache dir */
260 #if defined(AFS_CACHE_BYPASS)
261 #define AFSD_NDAEMONS 4
262 #else
263 #define AFSD_NDAEMONS 2
264 #endif
265 static int nDaemons = AFSD_NDAEMONS;    /* Number of background daemons */
266 static int chunkSize = 0;       /* 2^chunkSize bytes per chunk */
267 static int dCacheSize;          /* # of dcache entries */
268 static int vCacheSize = 200;    /* # of volume cache entries */
269 static int rootVolSet = 0;      /*True if root volume name explicitly set */
270 int addrNum;                    /*Cell server address index being printed */
271 static int cacheFlags = 0;      /*Flags to cache manager */
272 #ifdef AFS_AIX32_ENV
273 static int nBiods = 5;          /* AIX3.1 only */
274 #endif
275 static int preallocs = 400;     /* Def # of allocated memory blocks */
276 static int enable_peer_stats = 0;       /* enable rx stats */
277 static int enable_process_stats = 0;    /* enable rx stats */
278 static int enable_afsdb = 0;    /* enable AFSDB support */
279 static int enable_dynroot = 0;  /* enable dynroot support */
280 static int enable_fakestat = 0; /* enable fakestat support */
281 static int enable_backuptree = 0;       /* enable backup tree support */
282 static int enable_nomount = 0;  /* do not mount */
283 static int enable_splitcache = 0;
284 static char *inumcalc = NULL;        /* inode number calculation method */
285 static int afsd_dynamic_vcaches = 0;    /* Enable dynamic-vcache support */
286 int afsd_verbose = 0;           /*Are we being chatty? */
287 int afsd_debug = 0;             /*Are we printing debugging info? */
288 static int afsd_CloseSynch = 0; /*Are closes synchronous or not? */
289 static int rxmaxmtu = 0;       /* Are we forcing a limit on the mtu? */
290 static int rxmaxfrags = 0;      /* Are we forcing a limit on frags? */
291 static int volume_ttl = 0;      /* enable vldb cache timeout support */
292
293 #ifdef AFS_SGI62_ENV
294 #define AFSD_INO_T ino64_t
295 #else
296 #define AFSD_INO_T afs_uint32
297 #endif
298 struct afsd_file_list {
299     int fileNum;
300     struct afsd_file_list *next;
301 };
302 struct afsd_file_list **cache_dir_filelist = NULL;
303 int *cache_dir_list = NULL;     /* Array of cache subdirs */
304 int *dir_for_V = NULL;          /* Array: dir of each cache file.
305                                  * -1: file does not exist
306                                  * -2: file exists in top-level
307                                  * >=0: file exists in Dxxx
308                                  */
309 #if !defined(AFS_CACHE_VNODE_PATH) && !defined(AFS_LINUX26_ENV)
310 AFSD_INO_T *inode_for_V;        /* Array of inodes for desired
311                                  * cache files */
312 #endif
313 int missing_DCacheFile = 1;     /*Is the DCACHEFILE missing? */
314 int missing_VolInfoFile = 1;    /*Is the VOLINFOFILE missing? */
315 int missing_CellInfoFile = 1;   /*Is the CELLINFOFILE missing? */
316 int afsd_rmtsys = 0;            /* Default: don't support rmtsys */
317 struct afs_cacheParams cparams; /* params passed to cache manager */
318
319 int PartSizeOverflow(char *path, int cs);
320
321 static int afsd_syscall(int code, ...);
322
323 #if defined(AFS_SUN510_ENV) && defined(RXK_LISTENER_ENV)
324 static void fork_rx_syscall_wait(const char *rn, int syscall, ...);
325 #endif
326 static void fork_rx_syscall(const char *rn, int syscall, ...);
327 static void fork_syscall(const char *rn, int syscall, ...);
328
329 enum optionsList {
330     OPT_blocks,
331     OPT_files,
332     OPT_rootvol,
333     OPT_stat,
334     OPT_memcache,
335     OPT_cachedir,
336     OPT_mountdir,
337     OPT_daemons,
338     OPT_nosettime,
339     OPT_verbose,
340     OPT_rmtsys,
341     OPT_debug,
342     OPT_chunksize,
343     OPT_dcache,
344     OPT_volumes,
345     OPT_biods,
346     OPT_prealloc,
347     OPT_confdir,
348     OPT_logfile,
349     OPT_waitclose,
350     OPT_shutdown,
351     OPT_peerstats,
352     OPT_processstats,
353     OPT_memallocsleep,
354     OPT_afsdb,
355     OPT_filesdir,
356     OPT_dynroot,
357     OPT_fakestat,
358     OPT_fakestatall,
359     OPT_nomount,
360     OPT_backuptree,
361     OPT_rxbind,
362     OPT_settime,
363     OPT_rxpck,
364     OPT_splitcache,
365     OPT_nodynvcache,
366     OPT_rxmaxmtu,
367     OPT_dynrootsparse,
368     OPT_rxmaxfrags,
369     OPT_inumcalc,
370     OPT_volume_ttl,
371 };
372
373 #ifdef MACOS_EVENT_HANDLING
374 #include <SystemConfiguration/SystemConfiguration.h>
375 #include <SystemConfiguration/SCDynamicStore.h>
376
377 #include <IOKit/pwr_mgt/IOPMLib.h>
378 #include <IOKit/IOMessage.h>
379
380 static io_connect_t root_port;
381 static IONotificationPortRef notify;
382 static io_object_t iterator;
383 static CFRunLoopSourceRef source;
384
385 static void
386 afsd_sleep_callback(void * refCon, io_service_t service,
387                     natural_t messageType, void * messageArgument )
388 {
389     switch (messageType) {
390     case kIOMessageCanSystemSleep:
391         /* Idle sleep is about to kick in; can
392            prevent sleep by calling IOCancelPowerChange, otherwise
393            if we don't ack in 30s the system sleeps anyway */
394
395         /* allow it */
396         IOAllowPowerChange(root_port, (long)messageArgument);
397         break;
398
399     case kIOMessageSystemWillSleep:
400         /* The system WILL go to sleep. Ack or suffer delay */
401
402         IOAllowPowerChange(root_port, (long)messageArgument);
403         break;
404
405     case kIOMessageSystemWillRestart:
406         /* The system WILL restart. Ack or suffer delay */
407
408         IOAllowPowerChange(root_port, (long)messageArgument);
409         break;
410
411     case kIOMessageSystemWillPowerOn:
412     case kIOMessageSystemHasPoweredOn:
413         /* coming back from sleep */
414
415         IOAllowPowerChange(root_port, (long)messageArgument);
416         break;
417
418     default:
419         IOAllowPowerChange(root_port, (long)messageArgument);
420         break;
421     }
422 }
423
424 static void
425 afsd_update_addresses(CFRunLoopTimerRef timer, void *info)
426 {
427     /* parse multihomed address files */
428     afs_uint32 addrbuf[MAXIPADDRS], maskbuf[MAXIPADDRS],
429         mtubuf[MAXIPADDRS];
430     char reason[1024];
431     int code;
432
433     code = afsconf_ParseNetFiles(addrbuf, maskbuf, mtubuf, MAXIPADDRS,
434                                  reason, AFSDIR_CLIENT_NETINFO_FILEPATH,
435                                  AFSDIR_CLIENT_NETRESTRICT_FILEPATH);
436
437     if (code > 0) {
438         /* Note we're refreshing */
439         code = code | 0x40000000;
440         afsd_syscall(AFSOP_ADVISEADDR, code, addrbuf, maskbuf, mtubuf);
441     } else
442         printf("ADVISEADDR: Error in specifying interface addresses:%s\n",
443                reason);
444
445     /* Since it's likely this means our DNS server changed, reinit now */
446     if (enable_afsdb)
447         res_init();
448 }
449
450 /* This function is called when the system's ip addresses may have changed. */
451 static void
452 afsd_ipaddr_callback (SCDynamicStoreRef store, CFArrayRef changed_keys, void *info)
453 {
454       CFRunLoopTimerRef timer;
455
456       timer = CFRunLoopTimerCreate (NULL, CFAbsoluteTimeGetCurrent () + 1.0,
457                                     0.0, 0, 0, afsd_update_addresses, NULL);
458       CFRunLoopAddTimer (CFRunLoopGetCurrent (), timer,
459                          kCFRunLoopDefaultMode);
460       CFRelease (timer);
461 }
462
463 static void
464 afsd_event_cleanup(int signo) {
465
466     CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
467     CFRelease (source);
468     IODeregisterForSystemPower(&iterator);
469     IOServiceClose(root_port);
470     IONotificationPortDestroy(notify);
471     exit(0);
472 }
473
474 /* Adapted from "Living in a Dynamic TCP/IP Environment" technote. */
475 static void
476 afsd_install_events(void)
477 {
478     SCDynamicStoreContext ctx = {0};
479     SCDynamicStoreRef store;
480
481     root_port = IORegisterForSystemPower(0,&notify,afsd_sleep_callback,&iterator);
482
483     if (root_port) {
484         CFRunLoopAddSource(CFRunLoopGetCurrent(),
485                            IONotificationPortGetRunLoopSource(notify),
486                            kCFRunLoopDefaultMode);
487     }
488
489
490     store = SCDynamicStoreCreate (NULL,
491                                   CFSTR ("AddIPAddressListChangeCallbackSCF"),
492                                   afsd_ipaddr_callback, &ctx);
493
494     if (store) {
495         const void *keys[1];
496
497         /* Request IPV4 address change notification */
498         keys[0] = (SCDynamicStoreKeyCreateNetworkServiceEntity
499                    (NULL, kSCDynamicStoreDomainState,
500                     kSCCompAnyRegex, kSCEntNetIPv4));
501
502         if (keys[0] != NULL) {
503             CFArrayRef pattern_array;
504
505             pattern_array = CFArrayCreate (NULL, keys, 1,
506                                            &kCFTypeArrayCallBacks);
507
508             if (pattern_array != NULL)
509             {
510                 SCDynamicStoreSetNotificationKeys (store, NULL, pattern_array);
511                 source = SCDynamicStoreCreateRunLoopSource (NULL, store, 0);
512
513                 CFRelease (pattern_array);
514             }
515
516             if (keys[0] != NULL)
517                 CFRelease (keys[0]);
518         }
519
520         CFRelease (store);
521     }
522
523     if (source != NULL) {
524         CFRunLoopAddSource (CFRunLoopGetCurrent(),
525                             source, kCFRunLoopDefaultMode);
526     }
527
528     signal(SIGTERM, afsd_event_cleanup);
529
530     CFRunLoopRun();
531 }
532 #endif
533
534 /* ParseArgs is now obsolete, being handled by cmd */
535
536 /*------------------------------------------------------------------------------
537   * ParseCacheInfoFile
538   *
539   * Description:
540   *     Open the file containing the description of the workstation's AFS cache
541   *     and pull out its contents.  The format of this file is as follows:
542   *
543   *         cacheMountDir:cacheBaseDir:cacheBlocks
544   *
545   * Arguments:
546   *     None.
547   *
548   * Returns:
549   *     0 if everything went well,
550   *     1 otherwise.
551   *
552   * Environment:
553   *     Nothing interesting.
554   *
555   *  Side Effects:
556   *     Sets globals.
557   *---------------------------------------------------------------------------*/
558
559 int
560 ParseCacheInfoFile(void)
561 {
562     static char rn[] = "ParseCacheInfoFile";    /*This routine's name */
563     FILE *cachefd;              /*Descriptor for cache info file */
564     int parseResult;            /*Result of our fscanf() */
565     int tCacheBlocks;
566     char tCacheBaseDir[1024], *tbd, tCacheMountDir[1024], *tmd;
567
568     if (afsd_debug)
569         printf("%s: Opening cache info file '%s'...\n", rn, fullpn_CacheInfo);
570
571     cachefd = fopen(fullpn_CacheInfo, "r");
572     if (!cachefd) {
573         printf("%s: Can't read cache info file '%s'\n", rn, fullpn_CacheInfo);
574         return (1);
575     }
576
577     /*
578      * Parse the contents of the cache info file.  All chars up to the first
579      * colon are the AFS mount directory, all chars to the next colon are the
580      * full path name of the workstation cache directory and all remaining chars
581      * represent the number of blocks in the cache.
582      */
583     tCacheMountDir[0] = tCacheBaseDir[0] = '\0';
584     parseResult =
585         fscanf(cachefd, "%1024[^:]:%1024[^:]:%d", tCacheMountDir,
586                tCacheBaseDir, &tCacheBlocks);
587
588     /*
589      * Regardless of how the parse went, we close the cache info file.
590      */
591     fclose(cachefd);
592
593     if (parseResult == EOF || parseResult < 3) {
594         printf("%s: Format error in cache info file!\n", rn);
595         if (parseResult == EOF)
596             printf("\tEOF encountered before any field parsed.\n");
597         else
598             printf("\t%d out of 3 fields successfully parsed.\n",
599                    parseResult);
600
601         return (1);
602     }
603
604     for (tmd = tCacheMountDir; *tmd == '\n' || *tmd == ' ' || *tmd == '\t';
605          tmd++);
606     for (tbd = tCacheBaseDir; *tbd == '\n' || *tbd == ' ' || *tbd == '\t';
607          tbd++);
608     /* now copy in the fields not explicitly overridden by cmd args */
609     if (!sawCacheMountDir)
610         afsd_cacheMountDir = strdup(tmd);
611     if (!sawCacheBaseDir)
612         cacheBaseDir = strdup(tbd);
613     if (!sawCacheBlocks)
614         cacheBlocks = tCacheBlocks;
615
616     if (afsd_debug) {
617         printf("%s: Cache info file successfully parsed:\n", rn);
618         printf
619             ("\tcacheMountDir: '%s'\n\tcacheBaseDir: '%s'\n\tcacheBlocks: %d\n",
620              tmd, tbd, tCacheBlocks);
621     }
622     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
623         return (PartSizeOverflow(tbd, cacheBlocks));
624     }
625
626     return (0);
627 }
628
629 /*
630  * All failures to open the partition are ignored. Also if the cache dir
631  * isn't a mounted partition it's also ignored since we can't guarantee
632  * what will be stored afterwards. Too many if's. This is now purely
633  * advisory. ODS with over 2G partition also gives warning message.
634  *
635  * Returns:
636  *      0 if everything went well,
637  *      1 otherwise.
638  */
639 int
640 PartSizeOverflow(char *path, int cs)
641 {
642   int bsize = -1;
643   afs_int64 totalblks, mint;
644 #if AFS_HAVE_STATVFS || defined(HAVE_SYS_STATVFS_H)
645     struct statvfs statbuf;
646
647     if (statvfs(path, &statbuf) != 0) {
648         if (afsd_debug)
649             printf
650                 ("statvfs failed on %s; skip checking for adequate partition space\n",
651                  path);
652         return 0;
653     }
654     totalblks = statbuf.f_blocks;
655     bsize = statbuf.f_frsize;
656 #if AFS_AIX51_ENV
657     if (strcmp(statbuf.f_basetype, "jfs")) {
658         fprintf(stderr, "Cache filesystem '%s' must be jfs (now %s)\n",
659                 path, statbuf.f_basetype);
660         return 1;
661     }
662 #endif /* AFS_AIX51_ENV */
663
664 #else /* AFS_HAVE_STATVFS */
665     struct statfs statbuf;
666
667     if (statfs(path, &statbuf) < 0) {
668         if (afsd_debug)
669             printf
670                 ("statfs failed on %s; skip checking for adequate partition space\n",
671                  path);
672         return 0;
673     }
674     totalblks = statbuf.f_blocks;
675     bsize = statbuf.f_bsize;
676 #endif
677     if (bsize == -1)
678         return 0;               /* success */
679
680     /* now free and totalblks are in fragment units, but we want them in 1K units */
681     if (bsize >= 1024) {
682         totalblks *= (bsize / 1024);
683     } else {
684         totalblks /= (1024 / bsize);
685     }
686
687     mint = totalblks / 100 * 95;
688     if (cs > mint) {
689         printf
690             ("Cache size (%d) must be less than 95%% of partition size (which is %lld). Lower cache size\n",
691              cs, mint);
692         return 1;
693     }
694
695     return 0;
696 }
697
698 /*-----------------------------------------------------------------------------
699   * GetVFileNumber
700   *
701   * Description:
702   *     Given the final component of a filename expected to be a data cache file,
703   *     return the integer corresponding to the file.  Note: we reject names that
704   *     are not a ``V'' followed by an integer.  We also reject those names having
705   *     the right format but lying outside the range [0..cacheFiles-1].
706   *
707   * Arguments:
708   *     fname : Char ptr to the filename to parse.
709   *     max   : integer for the highest number to accept
710   *
711   * Returns:
712   *     >= 0 iff the file is really a data cache file numbered from 0 to cacheFiles-1, or
713   *     -1      otherwise.
714   *
715   * Environment:
716   *     Nothing interesting.
717   *
718   * Side Effects:
719   *     None.
720   *---------------------------------------------------------------------------*/
721
722 static int
723 doGetXFileNumber(char *fname, char filechar, int maxNum)
724 {
725     int computedVNumber;        /*The computed file number we return */
726     int filenameLen;            /*Number of chars in filename */
727     int currDigit;              /*Current digit being processed */
728
729     /*
730      * The filename must have at least two characters, the first of which must be a ``filechar''
731      * and the second of which cannot be a zero unless the file is exactly two chars long.
732      */
733     filenameLen = strlen(fname);
734     if (filenameLen < 2)
735         return (-1);
736     if (fname[0] != filechar)
737         return (-1);
738     if ((filenameLen > 2) && (fname[1] == '0'))
739         return (-1);
740
741     /*
742      * Scan through the characters in the given filename, failing immediately if a non-digit
743      * is found.
744      */
745     for (currDigit = 1; currDigit < filenameLen; currDigit++)
746         if (isdigit(fname[currDigit]) == 0)
747             return (-1);
748
749     /*
750      * All relevant characters are digits.  Pull out the decimal number they represent.
751      * Reject it if it's out of range, otherwise return it.
752      */
753     computedVNumber = atoi(++fname);
754     if (computedVNumber < cacheFiles)
755         return (computedVNumber);
756     else
757         return (-1);
758 }
759
760 int
761 GetVFileNumber(char *fname, int maxFile)
762 {
763     return doGetXFileNumber(fname, 'V', maxFile);
764 }
765
766 int
767 GetDDirNumber(char *fname, int maxDir)
768 {
769     return doGetXFileNumber(fname, 'D', maxDir);
770 }
771
772
773 /*-----------------------------------------------------------------------------
774   * CreateCacheFile
775   *
776   * Description:
777   *     Given a full pathname for a file we need to create for the workstation AFS
778   *     cache, go ahead and create the file.
779   *
780   * Arguments:
781   *     fname : Full pathname of file to create.
782   *     statp : A pointer to a stat buffer which, if NON-NULL, will be
783   *             filled by fstat()
784   *
785   * Returns:
786   *     0   iff the file was created,
787   *     -1  otherwise.
788   *
789   * Environment:
790   *     The given cache file has been found to be missing.
791   *
792   * Side Effects:
793   *     As described.
794   *---------------------------------------------------------------------------*/
795
796 static int
797 CreateCacheSubDir(char *basename, int dirNum)
798 {
799     static char rn[] = "CreateCacheSubDir";     /* Routine Name */
800     char dir[1024];
801     int ret;
802
803     /* Build the new cache subdirectory */
804     sprintf(dir, "%s/D%d", basename, dirNum);
805
806     if (afsd_debug)
807         printf("%s: Creating cache subdir '%s'\n", rn, dir);
808
809     if ((ret = mkdir(dir, 0700)) != 0) {
810         printf("%s: Can't create '%s', error return is %d (%d)\n", rn, dir,
811                ret, errno);
812         if (errno != EEXIST)
813             return (-1);
814     }
815
816     /* Mark this directory as created */
817     cache_dir_list[dirNum] = 0;
818
819     /* And return success */
820     return (0);
821 }
822
823 static void
824 SetNoBackupAttr(char *fullpn)
825 {
826 #ifdef AFS_DARWIN80_ENV
827     int ret;
828
829     ret = setxattr(fullpn, "com.apple.metadata:com_apple_backup_excludeItem",
830                    "com.apple.backupd", strlen("com.apple.backupd"), 0,
831                    XATTR_CREATE);
832     if(ret < 0)
833     {
834         if(errno != EEXIST)
835             fprintf(stderr, "afsd: Warning: failed to set attribute to preclude cache backup: %s\n", strerror(errno));
836     }
837 #endif
838     return;
839 }
840
841 static int
842 MoveCacheFile(char *basename, int fromDir, int toDir, int cacheFile,
843               int maxDir)
844 {
845     static char rn[] = "MoveCacheFile";
846     char from[1024], to[1024];
847     int ret;
848
849     if (cache_dir_list[toDir] < 0
850         && (ret = CreateCacheSubDir(basename, toDir))) {
851         printf("%s: Can't create directory '%s/D%d'\n", rn, basename, toDir);
852         return ret;
853     }
854
855     /* Build the from,to dir */
856     if (fromDir < 0) {
857         /* old-style location */
858         snprintf(from, sizeof(from), "%s/V%d", basename, cacheFile);
859     } else {
860         snprintf(from, sizeof(from), "%s/D%d/V%d", basename, fromDir,
861                  cacheFile);
862     }
863
864     snprintf(to, sizeof(from), "%s/D%d/V%d", basename, toDir, cacheFile);
865
866     if (afsd_verbose)
867         printf("%s: Moving cacheFile from '%s' to '%s'\n", rn, from, to);
868
869     if ((ret = rename(from, to)) != 0) {
870         printf("%s: Can't rename '%s' to '%s', error return is %d (%d)\n", rn,
871                from, to, ret, errno);
872         return -1;
873     }
874     SetNoBackupAttr(to);
875
876     /* Reset directory pointer; fix file counts */
877     dir_for_V[cacheFile] = toDir;
878     cache_dir_list[toDir]++;
879     if (fromDir < maxDir && fromDir >= 0)
880         cache_dir_list[fromDir]--;
881
882     return 0;
883 }
884
885 int
886 CreateCacheFile(char *fname, struct stat *statp)
887 {
888     static char rn[] = "CreateCacheFile";       /*Routine name */
889     int cfd;                    /*File descriptor to AFS cache file */
890     int closeResult;            /*Result of close() */
891
892     if (afsd_debug)
893         printf("%s: Creating cache file '%s'\n", rn, fname);
894     cfd = open(fname, createAndTrunc, ownerRWmode);
895     if (cfd <= 0) {
896         printf("%s: Can't create '%s', error return is %d (%d)\n", rn, fname,
897                cfd, errno);
898         return (-1);
899     }
900     if (statp != NULL) {
901         closeResult = fstat(cfd, statp);
902         if (closeResult) {
903             printf
904                 ("%s: Can't stat newly-created AFS cache file '%s' (code %d)\n",
905                  rn, fname, errno);
906             return (-1);
907         }
908     }
909     closeResult = close(cfd);
910     if (closeResult) {
911         printf
912             ("%s: Can't close newly-created AFS cache file '%s' (code %d)\n",
913              rn, fname, errno);
914         return (-1);
915     }
916
917     return (0);
918 }
919
920 static void
921 CreateFileIfMissing(char *fullpn, int missing)
922 {
923     if (missing) {
924         if (CreateCacheFile(fullpn, NULL))
925             printf("CreateFileIfMissing: Can't create '%s'\n", fullpn);
926     }
927 }
928
929 static void
930 UnlinkUnwantedFile(char *rn, char *fullpn_FileToDelete, char *fileToDelete)
931 {
932     if (unlink(fullpn_FileToDelete)) {
933         if ((errno == EISDIR || errno == EPERM) && *fileToDelete == 'D') {
934             if (rmdir(fullpn_FileToDelete)) {
935                 printf("%s: Can't rmdir '%s', errno is %d\n", rn,
936                        fullpn_FileToDelete, errno);
937             }
938         } else
939             printf("%s: Can't unlink '%s', errno is %d\n", rn,
940                    fullpn_FileToDelete, errno);
941     }
942 }
943
944 /*-----------------------------------------------------------------------------
945   * SweepAFSCache
946   *
947   * Description:
948   *     Sweep through the AFS cache directory, recording the inode number for
949   *     each valid data cache file there.  Also, delete any file that doesn't belong
950   *     in the cache directory during this sweep, and remember which of the other
951   *     residents of this directory were seen.  After the sweep, we create any data
952   *     cache files that were missing.
953   *
954   * Arguments:
955   *     vFilesFound : Set to the number of data cache files found.
956   *
957   * Returns:
958   *     0   if everything went well,
959   *     -1 otherwise.
960   *
961   * Environment:
962   *     This routine may be called several times.  If the number of data cache files
963   *     found is less than the global cacheFiles, then the caller will need to call it
964   *     again to record the inodes of the missing zero-length data cache files created
965   *     in the previous call.
966   *
967   * Side Effects:
968   *     Fills up the global inode_for_V array, may create and/or delete files as
969   *     explained above.
970   *---------------------------------------------------------------------------*/
971
972
973 static int
974 doSweepAFSCache(int *vFilesFound,
975                 char *directory,        /* /path/to/cache/directory */
976                 int dirNum,             /* current directory number */
977                 int maxDir)             /* maximum directory number */
978 {
979     static char rn[] = "doSweepAFSCache";       /* Routine Name */
980     char fullpn_FileToDelete[1024];     /*File to be deleted from cache */
981     char *fileToDelete;         /*Ptr to last component of above */
982     DIR *cdirp;                 /*Ptr to cache directory structure */
983 #ifdef AFS_SGI62_ENV
984     struct dirent64 *currp;     /*Current directory entry */
985 #else
986     struct dirent *currp;       /*Current directory entry */
987 #endif
988     int vFileNum;               /*Data cache file's associated number */
989     int thisDir;                /* A directory number */
990     int highDir = 0;
991
992     if (afsd_debug)
993         printf("%s: Opening cache directory '%s'\n", rn, directory);
994
995     if (chmod(directory, 0700)) {       /* force it to be 700 */
996         printf("%s: Can't 'chmod 0700' the cache dir, '%s'.\n", rn,
997                directory);
998         return (-1);
999     }
1000     cdirp = opendir(directory);
1001     if (cdirp == (DIR *) 0) {
1002         printf("%s: Can't open AFS cache directory, '%s'.\n", rn, directory);
1003         return (-1);
1004     }
1005
1006     /*
1007      * Scan the directory entries, remembering data cache file inodes
1008      * and the existance of other important residents.  Recurse into
1009      * the data subdirectories.
1010      *
1011      * Delete all files and directories that don't belong here.
1012      */
1013     sprintf(fullpn_FileToDelete, "%s/", directory);
1014     fileToDelete = fullpn_FileToDelete + strlen(fullpn_FileToDelete);
1015
1016 #ifdef AFS_SGI62_ENV
1017     for (currp = readdir64(cdirp); currp; currp = readdir64(cdirp))
1018 #else
1019     for (currp = readdir(cdirp); currp; currp = readdir(cdirp))
1020 #endif
1021     {
1022         if (afsd_debug) {
1023             printf("%s: Current directory entry:\n", rn);
1024 #if defined(AFS_SGI62_ENV) || defined(AFS_DARWIN90_ENV)
1025             printf("\tinode=%" AFS_INT64_FMT ", reclen=%d, name='%s'\n", currp->d_ino,
1026                    currp->d_reclen, currp->d_name);
1027 #elif defined(AFS_DFBSD_ENV) || defined(AFS_USR_DFBSD_ENV)
1028             printf("\tinode=%ld, name='%s'\n", (long)currp->d_ino, currp->d_name);
1029 #else
1030             printf("\tinode=%ld, reclen=%d, name='%s'\n", (long)currp->d_ino,
1031                    currp->d_reclen, currp->d_name);
1032 #endif
1033         }
1034
1035         /*
1036          * If dirNum < 0, we are a top-level cache directory and should
1037          * only contain sub-directories and other sundry files.  Therefore,
1038          * V-files are valid only if dirNum >= 0, and Directories are only
1039          * valid if dirNum < 0.
1040          */
1041
1042         if (*(currp->d_name) == 'V'
1043             && ((vFileNum = GetVFileNumber(currp->d_name, cacheFiles)) >=
1044                 0)) {
1045             /*
1046              * Found a valid data cache filename.  Remember this
1047              * file's inode, directory, and bump the number of files found
1048              * total and in this directory.
1049              */
1050 #if !defined(AFS_CACHE_VNODE_PATH) && !defined(AFS_LINUX26_ENV)
1051             inode_for_V[vFileNum] = currp->d_ino;
1052 #endif
1053             dir_for_V[vFileNum] = dirNum;       /* remember this directory */
1054
1055             if (!maxDir) {
1056                 /* If we're in a real subdir, mark this file to be moved
1057                  * if we've already got too many files in this directory
1058                  */
1059                 assert(dirNum >= 0);
1060                 cache_dir_list[dirNum]++;       /* keep directory's file count */
1061                 if (cache_dir_list[dirNum] > nFilesPerDir) {
1062                     /* Too many files -- add to filelist */
1063                     struct afsd_file_list *tmp = malloc(sizeof(*tmp));
1064                     if (!tmp)
1065                         printf
1066                             ("%s: MALLOC FAILED allocating file_list entry\n",
1067                              rn);
1068                     else {
1069                         tmp->fileNum = vFileNum;
1070                         tmp->next = cache_dir_filelist[dirNum];
1071                         cache_dir_filelist[dirNum] = tmp;
1072                     }
1073                 }
1074             }
1075             (*vFilesFound)++;
1076         } else if (dirNum < 0 && (*(currp->d_name) == 'D')
1077                    && GetDDirNumber(currp->d_name, 1 << 30) >= 0) {
1078             int retval = 0;
1079             if ((vFileNum = GetDDirNumber(currp->d_name, maxDir)) >= 0) {
1080                 /* Found a valid cachefile sub-Directory.  Remember this number
1081                  * and recurse into it.  Note that subdirs cannot have subdirs.
1082                  */
1083                 retval = 1;
1084             } else if ((vFileNum = GetDDirNumber(currp->d_name, 1 << 30)) >=
1085                        0) {
1086                 /* This directory is going away, but figure out if there
1087                  * are any cachefiles in here that should be saved by
1088                  * moving them to other cache directories.  This directory
1089                  * will be removed later.
1090                  */
1091                 retval = 2;
1092             }
1093
1094             /* Save the highest directory number we've seen */
1095             if (vFileNum > highDir)
1096                 highDir = vFileNum;
1097
1098             /* If this directory is staying, be sure to mark it as 'found' */
1099             if (retval == 1)
1100                 cache_dir_list[vFileNum] = 0;
1101
1102             /* Print the dirname for recursion */
1103             sprintf(fileToDelete, "%s", currp->d_name);
1104
1105             /* Note: vFileNum is the directory number */
1106             retval =
1107                 doSweepAFSCache(vFilesFound, fullpn_FileToDelete, vFileNum,
1108                                 (retval == 1 ? 0 : -1));
1109             if (retval) {
1110                 printf("%s: Recursive sweep failed on directory %s\n", rn,
1111                        currp->d_name);
1112                 return retval;
1113             }
1114         } else if (dirNum < 0 && strcmp(currp->d_name, DCACHEFILE) == 0) {
1115             /*
1116              * Found the file holding the dcache entries.
1117              */
1118             missing_DCacheFile = 0;
1119             SetNoBackupAttr(fullpn_DCacheFile);
1120         } else if (dirNum < 0 && strcmp(currp->d_name, VOLINFOFILE) == 0) {
1121             /*
1122              * Found the file holding the volume info.
1123              */
1124             missing_VolInfoFile = 0;
1125             SetNoBackupAttr(fullpn_VolInfoFile);
1126         } else if (dirNum < 0 && strcmp(currp->d_name, CELLINFOFILE) == 0) {
1127             /*
1128              * Found the file holding the cell info.
1129              */
1130             missing_CellInfoFile = 0;
1131             SetNoBackupAttr(fullpn_CellInfoFile);
1132         } else if ((strcmp(currp->d_name, ".") == 0)
1133                    || (strcmp(currp->d_name, "..") == 0) ||
1134 #ifdef AFS_LINUX22_ENV
1135                    /* this is the ext3 journal file */
1136                    (strcmp(currp->d_name, ".journal") == 0) ||
1137 #endif
1138                    (strcmp(currp->d_name, "lost+found") == 0)) {
1139             /*
1140              * Don't do anything - this file is legit, and is to be left alone.
1141              */
1142         } else {
1143             /*
1144              * This file/directory doesn't belong in the cache.  Nuke it.
1145              */
1146             sprintf(fileToDelete, "%s", currp->d_name);
1147             if (afsd_verbose)
1148                 printf("%s: Deleting '%s'\n", rn, fullpn_FileToDelete);
1149             UnlinkUnwantedFile(rn, fullpn_FileToDelete, fileToDelete);
1150         }
1151     }
1152
1153     if (dirNum < 0) {
1154
1155         /*
1156          * Create all the cache files that are missing.
1157          */
1158         CreateFileIfMissing(fullpn_DCacheFile, missing_DCacheFile);
1159         CreateFileIfMissing(fullpn_VolInfoFile, missing_VolInfoFile);
1160         CreateFileIfMissing(fullpn_CellInfoFile, missing_CellInfoFile);
1161
1162         /* ADJUST CACHE FILES */
1163
1164         /* First, let's walk through the list of files and figure out
1165          * if there are any leftover files in extra directories or
1166          * missing files.  Move the former and create the latter in
1167          * subdirs with extra space.
1168          */
1169
1170         thisDir = 0;            /* Keep track of which subdir has space */
1171
1172         for (vFileNum = 0; vFileNum < cacheFiles; vFileNum++) {
1173             if (dir_for_V[vFileNum] == -1) {
1174                 /* This file does not exist.  Create it in the first
1175                  * subdir that still has extra space.
1176                  */
1177                 while (thisDir < maxDir
1178                        && cache_dir_list[thisDir] >= nFilesPerDir)
1179                     thisDir++;
1180                 if (thisDir >= maxDir)
1181                     printf("%s: can't find directory to create V%d\n", rn,
1182                            vFileNum);
1183                 else {
1184                     struct stat statb;
1185 #if !defined(AFS_CACHE_VNODE_PATH) && !defined(AFS_LINUX26_ENV)
1186                     assert(inode_for_V[vFileNum] == (AFSD_INO_T) 0);
1187 #endif
1188                     sprintf(vFilePtr, "D%d/V%d", thisDir, vFileNum);
1189                     if (afsd_verbose)
1190                         printf("%s: Creating '%s'\n", rn, fullpn_VFile);
1191                     if (cache_dir_list[thisDir] < 0
1192                         && CreateCacheSubDir(directory, thisDir))
1193                         printf("%s: Can't create directory for '%s'\n", rn,
1194                                fullpn_VFile);
1195                     if (CreateCacheFile(fullpn_VFile, &statb))
1196                         printf("%s: Can't create '%s'\n", rn, fullpn_VFile);
1197                     else {
1198 #if !defined(AFS_CACHE_VNODE_PATH) && !defined(AFS_LINUX26_ENV)
1199                         inode_for_V[vFileNum] = statb.st_ino;
1200 #endif
1201                         dir_for_V[vFileNum] = thisDir;
1202                         cache_dir_list[thisDir]++;
1203                         (*vFilesFound)++;
1204                     }
1205                     SetNoBackupAttr(fullpn_VFile);
1206                 }
1207
1208             } else if (dir_for_V[vFileNum] >= maxDir
1209                        || dir_for_V[vFileNum] == -2) {
1210                 /* This file needs to move; move it to the first subdir
1211                  * that has extra space.  (-2 means it's in the toplevel)
1212                  */
1213                 while (thisDir < maxDir
1214                        && cache_dir_list[thisDir] >= nFilesPerDir)
1215                     thisDir++;
1216                 if (thisDir >= maxDir)
1217                     printf("%s: can't find directory to move V%d\n", rn,
1218                            vFileNum);
1219                 else {
1220                     if (MoveCacheFile
1221                         (directory, dir_for_V[vFileNum], thisDir, vFileNum,
1222                          maxDir)) {
1223                         /* Cannot move.  Ignore this file??? */
1224                         /* XXX */
1225                     }
1226                 }
1227             }
1228         }                       /* for */
1229
1230         /* At this point, we've moved all of the valid cache files
1231          * into the valid subdirs, and created all the extra
1232          * cachefiles we need to create.  Next, rebalance any subdirs
1233          * with too many cache files into the directories with not
1234          * enough cache files.  Note that thisDir currently sits at
1235          * the lowest subdir that _may_ have room.
1236          */
1237
1238         for (dirNum = 0; dirNum < maxDir; dirNum++) {
1239             struct afsd_file_list *thisFile;
1240
1241             for (thisFile = cache_dir_filelist[dirNum];
1242                  thisFile && cache_dir_list[dirNum] >= nFilesPerDir;
1243                  thisFile = thisFile->next) {
1244                 while (thisDir < maxDir
1245                        && cache_dir_list[thisDir] >= nFilesPerDir)
1246                     thisDir++;
1247                 if (thisDir >= maxDir)
1248                     printf("%s: can't find directory to move V%d\n", rn,
1249                            vFileNum);
1250                 else {
1251                     if (MoveCacheFile
1252                         (directory, dirNum, thisDir, thisFile->fileNum,
1253                          maxDir)) {
1254                         /* Cannot move.  Ignore this file??? */
1255                         /* XXX */
1256                     }
1257                 }
1258             }                   /* for each file to move */
1259         }                       /* for each directory */
1260
1261         /* Remove any directories >= maxDir -- they should be empty */
1262         for (; highDir >= maxDir; highDir--) {
1263             sprintf(fileToDelete, "D%d", highDir);
1264             UnlinkUnwantedFile(rn, fullpn_FileToDelete, fileToDelete);
1265         }
1266     }
1267
1268     /* dirNum < 0 */
1269     /*
1270      * Close the directory, return success.
1271      */
1272     if (afsd_debug)
1273         printf("%s: Closing cache directory.\n", rn);
1274     closedir(cdirp);
1275     return (0);
1276 }
1277
1278 char *
1279 CheckCacheBaseDir(char *dir)
1280 {
1281     struct stat statbuf;
1282
1283     if (!dir) {
1284         return "cache base dir not specified";
1285     }
1286     if (stat(dir, &statbuf) != 0) {
1287         return "unable to stat cache base directory";
1288     }
1289
1290     /* might want to check here for anything else goofy, like cache pointed at a non-dedicated directory, etc */
1291
1292 #ifdef AFS_LINUX24_ENV
1293     {
1294         int res;
1295         struct statfs statfsbuf;
1296
1297         res = statfs(dir, &statfsbuf);
1298         if (res != 0) {
1299             return "unable to statfs cache base directory";
1300         }
1301 #if !defined(AFS_LINUX26_ENV)
1302         if (statfsbuf.f_type == 0x52654973) {   /* REISERFS_SUPER_MAGIC */
1303             return "cannot use reiserfs as cache partition";
1304         } else if (statfsbuf.f_type == 0x58465342) {    /* XFS_SUPER_MAGIC */
1305             return "cannot use xfs as cache partition";
1306         } else if (statfsbuf.f_type == 0x01021994) {    /* TMPFS_SUPER_MAGIC */
1307             return "cannot use tmpfs as cache partition";
1308         } else if (statfsbuf.f_type != 0xEF53) {
1309             return "must use ext2 or ext3 for cache partition";
1310         }
1311 #endif
1312     }
1313 #endif
1314
1315 #ifdef AFS_HPUX_ENV
1316     {
1317         int res;
1318         struct statfs statfsbuf;
1319         char name[FSTYPSZ];
1320
1321         res = statfs(dir, &statfsbuf);
1322         if (res != 0) {
1323             return "unable to statfs cache base directory";
1324         }
1325
1326         if (sysfs(GETFSTYP, statfsbuf.f_fsid[1], name) != 0) {
1327             return "unable to determine filesystem type for cache base dir";
1328         }
1329
1330         if (strcmp(name, "hfs")) {
1331             return "can only use hfs filesystem for cache partition on hpux";
1332         }
1333     }
1334 #endif
1335
1336 #ifdef AFS_SUN5_ENV
1337     {
1338         FILE *vfstab;
1339         struct mnttab mnt;
1340         struct stat statmnt, statci;
1341
1342         if ((stat(dir, &statci) == 0)
1343             && ((vfstab = fopen(MNTTAB, "r")) != NULL)) {
1344             while (getmntent(vfstab, &mnt) == 0) {
1345                 if (strcmp(dir, mnt.mnt_mountp) != 0) {
1346                     char *cp;
1347                     int rdev = 0;
1348
1349                     if (cp = hasmntopt(&mnt, "dev="))
1350                         rdev =
1351                             (int)strtol(cp + strlen("dev="), NULL,
1352                                         16);
1353
1354                     if ((rdev == 0) && (stat(mnt.mnt_mountp, &statmnt) == 0))
1355                         rdev = statmnt.st_dev;
1356
1357                     if ((rdev == statci.st_dev)
1358                         && (hasmntopt(&mnt, "logging") != NULL)) {
1359
1360                         fclose(vfstab);
1361                         return
1362                             "mounting a multi-use partition which contains the AFS cache with the\n\"logging\" option may deadlock your system.\n\n";
1363                     }
1364                 }
1365             }
1366
1367             fclose(vfstab);
1368         }
1369     }
1370 #endif
1371
1372     return NULL;
1373 }
1374
1375 int
1376 SweepAFSCache(int *vFilesFound)
1377 {
1378     static char rn[] = "SweepAFSCache"; /*Routine name */
1379     int maxDir = (cacheFiles + nFilesPerDir - 1) / nFilesPerDir;
1380     int i;
1381
1382     *vFilesFound = 0;
1383
1384     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
1385         if (afsd_debug)
1386             printf("%s: Memory Cache, no cache sweep done\n", rn);
1387         return 0;
1388     }
1389
1390     if (cache_dir_list == NULL) {
1391         cache_dir_list = malloc(maxDir * sizeof(*cache_dir_list));
1392         if (cache_dir_list == NULL) {
1393             printf("%s: Malloc Failed!\n", rn);
1394             return (-1);
1395         }
1396         for (i = 0; i < maxDir; i++)
1397             cache_dir_list[i] = -1;     /* Does not exist */
1398     }
1399
1400     if (cache_dir_filelist == NULL) {
1401         cache_dir_filelist = calloc(maxDir, sizeof(*cache_dir_filelist));
1402         if (cache_dir_filelist == NULL) {
1403             printf("%s: Malloc Failed!\n", rn);
1404             return (-1);
1405         }
1406     }
1407
1408     if (dir_for_V == NULL) {
1409         dir_for_V = malloc(cacheFiles * sizeof(*dir_for_V));
1410         if (dir_for_V == NULL) {
1411             printf("%s: Malloc Failed!\n", rn);
1412             return (-1);
1413         }
1414         for (i = 0; i < cacheFiles; i++)
1415             dir_for_V[i] = -1;  /* Does not exist */
1416     }
1417
1418     /* Note, setting dirNum to -2 here will cause cachefiles found in
1419      * the toplevel directory to be marked in directory "-2".  This
1420      * allows us to differentiate between 'file not seen' (-1) and
1421      * 'file seen in top-level' (-2).  Then when we try to move the
1422      * file into a subdirectory, we know it's in the top-level instead
1423      * of some other cache subdir.
1424      */
1425     return doSweepAFSCache(vFilesFound, cacheBaseDir, -2, maxDir);
1426 }
1427
1428 static int
1429 ConfigCell(struct afsconf_cell *aci, void *arock, struct afsconf_dir *adir)
1430 {
1431     int isHomeCell;
1432     int i, code;
1433     int cellFlags = 0;
1434     afs_int32 hosts[MAXHOSTSPERCELL];
1435
1436     /* figure out if this is the home cell */
1437     isHomeCell = (strcmp(aci->name, LclCellName) == 0);
1438     if (!isHomeCell) {
1439         cellFlags = 2;          /* not home, suid is forbidden */
1440         if (enable_dynroot == 2)
1441             cellFlags |= 8; /* don't display foreign cells until looked up */
1442     }
1443     /* build address list */
1444     for (i = 0; i < MAXHOSTSPERCELL; i++)
1445         memcpy(&hosts[i], &aci->hostAddr[i].sin_addr, sizeof(afs_int32));
1446
1447     if (aci->linkedCell)
1448         cellFlags |= 4;         /* Flag that linkedCell arg exists,
1449                                  * for upwards compatibility */
1450
1451     /* configure one cell */
1452     code = afsd_syscall(AFSOP_ADDCELL2, hosts,  /* server addresses */
1453                         aci->name,      /* cell name */
1454                         cellFlags,      /* is this the home cell? */
1455                         aci->linkedCell);       /* Linked cell, if any */
1456     if (code)
1457         printf("Adding cell '%s': error %d\n", aci->name, code);
1458     return 0;
1459 }
1460
1461 static int
1462 ConfigCellAlias(struct afsconf_cellalias *aca,
1463                 void *arock, struct afsconf_dir *adir)
1464 {
1465     /* push the alias into the kernel */
1466     afsd_syscall(AFSOP_ADDCELLALIAS, aca->aliasName, aca->realName);
1467     return 0;
1468 }
1469
1470 static void
1471 AfsdbLookupHandler(void)
1472 {
1473     afs_int32 kernelMsg[64];
1474     char acellName[128];
1475     afs_int32 code;
1476     struct afsconf_cell acellInfo;
1477     int i;
1478
1479     kernelMsg[0] = 0;
1480     kernelMsg[1] = 0;
1481     acellName[0] = '\0';
1482
1483 #ifdef MACOS_EVENT_HANDLING
1484     /* Fork the event handler also. */
1485     code = fork();
1486     if (code == 0) {
1487         afsd_install_events();
1488         return;
1489     } else if (code != -1) {
1490         event_pid = code;
1491     }
1492 #endif
1493     while (1) {
1494         /* On some platforms you only get 4 args to an AFS call */
1495         int sizeArg = ((sizeof acellName) << 16) | (sizeof kernelMsg);
1496         code =
1497             afsd_syscall(AFSOP_AFSDB_HANDLER, acellName, kernelMsg, sizeArg);
1498         if (code) {             /* Something is wrong? */
1499             sleep(1);
1500             continue;
1501         }
1502
1503         if (*acellName == 1)    /* Shutting down */
1504             break;
1505
1506         code = afsconf_GetAfsdbInfo(acellName, 0, &acellInfo);
1507         if (code) {
1508             kernelMsg[0] = 0;
1509             kernelMsg[1] = 0;
1510         } else {
1511             kernelMsg[0] = acellInfo.numServers;
1512             if (acellInfo.timeout)
1513                 kernelMsg[1] = acellInfo.timeout - time(0);
1514             else
1515                 kernelMsg[1] = 0;
1516             for (i = 0; i < acellInfo.numServers; i++)
1517                 kernelMsg[i + 2] = acellInfo.hostAddr[i].sin_addr.s_addr;
1518             strncpy(acellName, acellInfo.name, sizeof(acellName));
1519             acellName[sizeof(acellName) - 1] = '\0';
1520         }
1521     }
1522 #ifdef AFS_DARWIN_ENV
1523     kill(event_pid, SIGTERM);
1524 #endif
1525 }
1526
1527 #ifdef AFS_NEW_BKG
1528 static void
1529 BkgHandler(void)
1530 {
1531     afs_int32 code;
1532     struct afs_uspc_param *uspc;
1533     char srcName[256];
1534     char dstName[256];
1535
1536     uspc = calloc(1, sizeof(struct afs_uspc_param));
1537     memset(srcName, 0, sizeof(srcName));
1538     memset(dstName, 0, sizeof(dstName));
1539
1540     /* brscount starts at 0 */
1541     uspc->ts = -1;
1542
1543     while (1) {
1544         /* pushing in a buffer this large */
1545         uspc->bufSz = 256;
1546
1547         code = afsd_syscall(AFSOP_BKG_HANDLER, uspc, srcName, dstName);
1548         if (code) {             /* Something is wrong? */
1549             if (code == -2) {
1550                 /*
1551                  * Before AFS_USPC_SHUTDOWN existed, the kernel module used to
1552                  * indicate it was shutting down by returning -2. Treat this
1553                  * like a AFS_USPC_SHUTDOWN, in case we're running with an
1554                  * older kernel module.
1555                  */
1556                 return;
1557             }
1558
1559             sleep(1);
1560             uspc->retval = -1;
1561             continue;
1562         }
1563
1564         switch (uspc->reqtype) {
1565         case AFS_USPC_SHUTDOWN:
1566             /* Client is shutting down */
1567             return;
1568
1569         case AFS_USPC_NOOP:
1570             /* noop */
1571             memset(srcName, 0, sizeof(srcName));
1572             memset(dstName, 0, sizeof(dstName));
1573             break;
1574
1575 # ifdef AFS_DARWIN_ENV
1576         case AFS_USPC_UMV:
1577             {
1578                 pid_t child = 0;
1579                 int status;
1580                 char srcpath[BUFSIZ];
1581                 char dstpath[BUFSIZ];
1582                 snprintf(srcpath, BUFSIZ, "/afs/.:mount/%d:%d:%d:%d/%s",
1583                          uspc->req.umv.sCell, uspc->req.umv.sVolume,
1584                          uspc->req.umv.sVnode, uspc->req.umv.sUnique, srcName);
1585                 snprintf(dstpath, BUFSIZ, "/afs/.:mount/%d:%d:%d:%d/%s",
1586                          uspc->req.umv.dCell, uspc->req.umv.dVolume,
1587                          uspc->req.umv.dVnode, uspc->req.umv.dUnique, dstName);
1588                 if ((child = fork()) == 0) {
1589                     /* first child does cp; second, rm. mv would re-enter. */
1590
1591                     switch (uspc->req.umv.idtype) {
1592                     case IDTYPE_UID:
1593                         if (setuid(uspc->req.umv.id) != 0) {
1594                             exit(-1);
1595                         }
1596                         break;
1597                     default:
1598                         exit(-1);
1599                         break; /* notreached */
1600                     }
1601                     execl("/bin/cp", "(afsd EXDEV helper)", "-PRp", "--", srcpath,
1602                           dstpath, (char *) NULL);
1603                 }
1604                 if (child == (pid_t) -1) {
1605                     uspc->retval = -1;
1606                     continue;
1607                 }
1608
1609                 if (waitpid(child, &status, 0) == -1)
1610                     uspc->retval = EIO;
1611                 else if (WIFEXITED(status) != 0 && WEXITSTATUS(status) == 0) {
1612                     if ((child = fork()) == 0) {
1613                         switch (uspc->req.umv.idtype) {
1614                         case IDTYPE_UID:
1615                             if (setuid(uspc->req.umv.id) != 0) {
1616                                 exit(-1);
1617                             }
1618                             break;
1619                         default:
1620                             exit(-1);
1621                             break; /* notreached */
1622                         }
1623                         execl("/bin/rm", "(afsd EXDEV helper)", "-rf", "--",
1624                               srcpath, (char *) NULL);
1625                     }
1626                     if (child == (pid_t) -1) {
1627                         uspc->retval = -1;
1628                         continue;
1629                     }
1630                     if (waitpid(child, &status, 0) == -1)
1631                         uspc->retval = EIO;
1632                     else if (WIFEXITED(status) != 0) {
1633                         /* rm exit status */
1634                         uspc->retval = WEXITSTATUS(status);
1635                     } else {
1636                         /* rm signal status */
1637                         uspc->retval = -(WTERMSIG(status));
1638                     }
1639                 } else {
1640                     /* error from cp: exit or signal status */
1641                     uspc->retval = (WIFEXITED(status) != 0) ?
1642                         WEXITSTATUS(status) : -(WTERMSIG(status));
1643                 }
1644             }
1645             memset(srcName, 0, sizeof(srcName));
1646             memset(dstName, 0, sizeof(dstName));
1647             break;
1648 # endif /* AFS_DARWIN_ENV */
1649
1650         default:
1651             /* unknown req type */
1652             uspc->retval = -1;
1653             break;
1654         }
1655     }
1656 }
1657 #endif
1658
1659 #ifdef AFS_SOCKPROXY_ENV
1660
1661 # define AFS_SOCKPROXY_RECV_IDX 0
1662 # define AFS_SOCKPROXY_INIT_IDX 1
1663
1664 /*
1665  * Must be less than or equal to the limits supported by libafs:
1666  * AFS_SOCKPROXY_PKT_MAX and AFS_SOCKPROXY_PAYLOAD_MAX.
1667  */
1668 # define AFS_SOCKPROXY_PKT_ALLOC        32
1669 # define AFS_SOCKPROXY_PAYLOAD_ALLOC    2832
1670
1671 /**
1672  * Create socket, set send and receive buffer size, and bind a name to it.
1673  *
1674  * @param[in]  a_addr  address to be assigned to the socket
1675  * @param[in]  a_port  port to be assigned to the socket
1676  * @param[out] a_sock  socket
1677  *
1678  * @return 0 on success; errno otherwise.
1679  */
1680 static int
1681 SockProxyStart(afs_int32 a_addr, afs_int32 a_port, int *a_sock)
1682 {
1683     int code;
1684     int attempt_i;
1685     int blen, bsize;
1686     int sock;
1687     struct sockaddr_in ip4;
1688
1689     *a_sock = -1;
1690
1691     /* create an endpoint for communication */
1692     sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1693     if (sock < 0) {
1694         code = errno;
1695         goto done;
1696     }
1697
1698     /* set options on socket */
1699     blen = 50000;
1700     bsize = sizeof(blen);
1701     for (attempt_i = 0; attempt_i < 2; attempt_i++) {
1702         code  = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &blen, bsize);
1703         code |= setsockopt(sock, SOL_SOCKET, SO_RCVBUF, &blen, bsize);
1704         if (code == 0) {
1705             break;
1706         }
1707         /* setsockopt didn't succeed. try a smaller size. */
1708         blen = 32766;
1709     }
1710     if (code != 0) {
1711         code = EINVAL;
1712         goto done;
1713     }
1714     /* assign addr to the socket */
1715     ip4.sin_family = AF_INET;
1716     ip4.sin_port = a_port;
1717     ip4.sin_addr.s_addr = a_addr;
1718
1719     code = bind(sock, (struct sockaddr *)&ip4, sizeof(ip4));
1720     if (code != 0) {
1721         code = errno;
1722         goto done;
1723     }
1724
1725     /* success */
1726     *a_sock = sock;
1727     sock = -1;
1728
1729   done:
1730     if (sock >= 0) {
1731         close(sock);
1732     }
1733     return code;
1734 }
1735
1736 /**
1737  * Create and initialize socket with address received from kernel-space.
1738  *
1739  * @param[in]  a_idx   index of the process responsible for this task
1740  * @param[out] a_sock  socket
1741  */
1742 static void
1743 SockProxyStartProc(int a_idx, int *a_sock)
1744 {
1745     int code, initialized;
1746     struct afs_uspc_param uspc;
1747
1748     initialized = 0;
1749
1750     memset(&uspc, 0, sizeof(uspc));
1751     uspc.req.usp.idx = a_idx;
1752
1753     while (!initialized) {
1754         uspc.reqtype = AFS_USPC_SOCKPROXY_START;
1755
1756         code = afsd_syscall(AFSOP_SOCKPROXY_HANDLER, &uspc, NULL);
1757         if (code) {
1758             /* Error; try again. */
1759             uspc.retval = -1;
1760             sleep(10);
1761             continue;
1762         }
1763
1764         switch (uspc.reqtype) {
1765         case AFS_USPC_SHUTDOWN:
1766             exit(0);
1767             break;
1768
1769         case AFS_USPC_SOCKPROXY_START:
1770             uspc.retval =
1771                 SockProxyStart(uspc.req.usp.addr, uspc.req.usp.port, a_sock);
1772             if (uspc.retval == 0) {
1773                 /* We've setup the socket successfully. */
1774                 initialized = 1;
1775             }
1776             break;
1777
1778         default:
1779             /* Error; try again. We must handle AFS_USPC_SOCKPROXY_START before
1780              * doing anything else. */
1781             uspc.retval = -1;
1782             sleep(10);
1783         }
1784     }
1785     /* Startup is done. */
1786 }
1787
1788 /**
1789  * Send list of packets received from kernel-space.
1790  *
1791  * @param[in]  a_sock     socket
1792  * @param[in]  a_pktlist  list of packets
1793  * @param[in]  a_npkts    number of packets
1794  *
1795  * @return number of packets successfully sent; -1 if couldn't send any packet.
1796  */
1797 static int
1798 SockProxySend(int a_sock, struct afs_pkt_hdr *a_pktlist, int a_npkts)
1799 {
1800     int code;
1801     int pkt_i, n_sent;
1802
1803     n_sent = 0;
1804
1805     for (pkt_i = 0; pkt_i < a_npkts; pkt_i++) {
1806         struct afs_pkt_hdr *pkt = &a_pktlist[pkt_i];
1807         struct sockaddr_in addr;
1808         struct iovec iov;
1809         struct msghdr msg;
1810
1811         memset(&iov, 0, sizeof(iov));
1812         memset(&msg, 0, sizeof(msg));
1813         memset(&addr, 0, sizeof(addr));
1814
1815         addr.sin_addr.s_addr = pkt->addr;
1816         addr.sin_port = pkt->port;
1817
1818         iov.iov_base = pkt->payload;
1819         iov.iov_len = pkt->size;
1820
1821         msg.msg_name = &addr;
1822         msg.msg_namelen = sizeof(addr);
1823         msg.msg_iov = &iov;
1824         msg.msg_iovlen = 1;
1825
1826         code = sendmsg(a_sock, &msg, 0);
1827         if (code < 0) {
1828             break;
1829         }
1830         n_sent++;
1831     }
1832
1833     if (n_sent > 0) {
1834         return n_sent;
1835     }
1836     return -1;
1837 }
1838
1839 /**
1840  * Alloc maximum number of packets, each with the largest payload possible.
1841  *
1842  * @param[out]  a_pktlist  allocated packets
1843  * @param[out]  a_npkts    number of packets allocated
1844  */
1845 static void
1846 pkts_alloc(struct afs_pkt_hdr **a_pktlist, int *a_npkts)
1847 {
1848     int pkt_i, n_pkts;
1849     struct afs_pkt_hdr *pktlist;
1850
1851     n_pkts = AFS_SOCKPROXY_PKT_ALLOC;
1852     pktlist = calloc(n_pkts, sizeof(pktlist[0]));
1853     opr_Assert(pktlist != NULL);
1854
1855     for (pkt_i = 0; pkt_i < n_pkts; pkt_i++) {
1856         struct afs_pkt_hdr *pkt = &pktlist[pkt_i];
1857         pkt->size = AFS_SOCKPROXY_PAYLOAD_ALLOC;
1858
1859         pkt->payload = calloc(1, pkt->size);
1860         opr_Assert(pkt->payload != NULL);
1861     }
1862
1863     *a_pktlist = pktlist;
1864     *a_npkts = n_pkts;
1865 }
1866
1867 /**
1868  * Reset pkt->size for all packets.
1869  *
1870  * @param[in]  a_pktlist  list of packets
1871  * @param[in]  a_npkts    number of packets
1872  */
1873 static void
1874 pkts_resetsize(struct afs_pkt_hdr *a_pktlist, int a_npkts)
1875 {
1876     int pkt_i;
1877
1878     for (pkt_i = 0; pkt_i < a_npkts; pkt_i++) {
1879         struct afs_pkt_hdr *pkt = &a_pktlist[pkt_i];
1880         pkt->size = AFS_SOCKPROXY_PAYLOAD_ALLOC;
1881     }
1882 }
1883
1884 /**
1885  * Serve packet sending requests from kernel-space.
1886  *
1887  * @param[in]  a_sock     socket
1888  * @param[in]  a_idx      index of the process responsible for this task
1889  * @param[in]  a_recvpid  pid of process responsible for receiving packets
1890  *                        (used to simplify shutdown procedures)
1891  */
1892 static void
1893 SockProxySendProc(int a_sock, int a_idx, int a_recvpid)
1894 {
1895     int code, n_pkts;
1896     struct afs_pkt_hdr *pktlist;
1897     struct afs_uspc_param uspc;
1898
1899     n_pkts = 0;
1900     pktlist = NULL;
1901     memset(&uspc, 0, sizeof(uspc));
1902
1903     pkts_alloc(&pktlist, &n_pkts);
1904     uspc.reqtype = AFS_USPC_SOCKPROXY_SEND;
1905     uspc.req.usp.idx = a_idx;
1906
1907     while (1) {
1908         uspc.req.usp.npkts = n_pkts;
1909         pkts_resetsize(pktlist, n_pkts);
1910
1911         code = afsd_syscall(AFSOP_SOCKPROXY_HANDLER, &uspc, pktlist);
1912         if (code) {
1913             uspc.retval = -1;
1914             sleep(10);
1915             continue;
1916         }
1917
1918         switch (uspc.reqtype) {
1919         case AFS_USPC_SHUTDOWN:
1920             if (a_recvpid != 0) {
1921                 /*
1922                  * We're shutting down, so kill the SockProxyReceiveProc
1923                  * process. We don't wait for that process to get its own
1924                  * AFS_USPC_SHUTDOWN response, since it may be stuck in
1925                  * recvmsg() waiting for packets from the net.
1926                  */
1927                 kill(a_recvpid, SIGKILL);
1928             }
1929             exit(0);
1930             break;
1931
1932         case AFS_USPC_SOCKPROXY_SEND:
1933             uspc.retval = SockProxySend(a_sock, pktlist, uspc.req.usp.npkts);
1934             break;
1935
1936         default:
1937             /* Some other operation? */
1938             uspc.retval = -1;
1939             sleep(10);
1940         }
1941     }
1942     /* never reached */
1943 }
1944
1945 /**
1946  * Receive list of packets from the socket received as an argument.
1947  *
1948  * @param[in]   a_sock     socket
1949  * @param[out]  a_pkts     packets received
1950  * @param[in]   a_maxpkts  maximum number of packets we can receive
1951  *
1952  * @return number of packets received.
1953  */
1954 static int
1955 SockProxyRecv(int a_sock, struct afs_pkt_hdr *a_pkts, int a_maxpkts)
1956 {
1957     int pkt_i, n_recv;
1958     int flags;
1959
1960     struct iovec iov;
1961     struct msghdr msg;
1962     struct sockaddr_in from;
1963
1964     n_recv = 0;
1965     flags = 0;
1966
1967     for (pkt_i = 0; pkt_i < a_maxpkts; pkt_i++) {
1968         struct afs_pkt_hdr *pkt = &a_pkts[pkt_i];
1969         ssize_t nbytes;
1970
1971         pkt->size = AFS_SOCKPROXY_PAYLOAD_ALLOC;
1972
1973         memset(&iov, 0, sizeof(iov));
1974         iov.iov_base = pkt->payload;
1975         iov.iov_len = pkt->size;
1976
1977         memset(&from, 0, sizeof(from));
1978         memset(&msg, 0, sizeof(msg));
1979         msg.msg_name = &from;
1980         msg.msg_namelen = sizeof(from);
1981         msg.msg_iov = &iov;
1982         msg.msg_iovlen = 1;
1983
1984         nbytes = recvmsg(a_sock, &msg, flags);
1985         if (nbytes < 0) {
1986             break;
1987         }
1988
1989         pkt->size = nbytes;
1990         pkt->addr = from.sin_addr.s_addr;
1991         pkt->port = from.sin_port;
1992
1993         n_recv++;
1994         flags = MSG_DONTWAIT;
1995     }
1996     return n_recv;
1997 }
1998
1999 /**
2000  * Receive packets addressed to kernel-space and deliver those packages to it.
2001  *
2002  * @param[in]  a_sock  socket
2003  * @param[in]  a_idx   index of the process responsible for this task
2004  */
2005 static void
2006 SockProxyReceiveProc(int a_sock, int a_idx)
2007 {
2008     int code, n_pkts;
2009     struct afs_pkt_hdr *pktlist;
2010     struct afs_uspc_param uspc;
2011
2012     n_pkts = 0;
2013     pktlist = NULL;
2014     pkts_alloc(&pktlist, &n_pkts);
2015
2016     memset(&uspc, 0, sizeof(uspc));
2017     uspc.req.usp.idx = a_idx;
2018     uspc.req.usp.npkts = 0;
2019
2020     while (1) {
2021         uspc.reqtype = AFS_USPC_SOCKPROXY_RECV;
2022
2023         code = afsd_syscall(AFSOP_SOCKPROXY_HANDLER, &uspc, pktlist);
2024         if (code) {
2025             uspc.retval = -1;
2026             sleep(10);
2027             continue;
2028         }
2029
2030         switch (uspc.reqtype) {
2031         case AFS_USPC_SHUTDOWN:
2032             exit(0);
2033             break;
2034
2035         case AFS_USPC_SOCKPROXY_RECV:
2036             uspc.req.usp.npkts = SockProxyRecv(a_sock, pktlist, n_pkts);
2037             uspc.retval = 0;
2038             break;
2039
2040         default:
2041             /* Some other operation? */
2042             uspc.retval = -1;
2043             uspc.req.usp.npkts = 0;
2044             sleep(10);
2045         }
2046     }
2047     /* never reached */
2048 }
2049
2050 /**
2051  * Start processes responsible for sending and receiving packets for libafs.
2052  *
2053  * @param[in]  a_rock  not used
2054  */
2055 static void *
2056 sockproxy_thread(void *a_rock)
2057 {
2058     int idx;
2059     int sock;
2060     int recvpid;
2061
2062     sock = -1;
2063     /*
2064      * Since the socket proxy handler runs as a user process,
2065      * need to drop the controlling TTY, etc.
2066      */
2067     if (afsd_daemon(0, 0) == -1) {
2068         printf("Error starting socket proxy handler: %s\n", strerror(errno));
2069         exit(1);
2070     }
2071
2072     /*
2073      * Before we do anything else, we must first wait for a
2074      * AFS_USPC_SOCKPROXY_START request to setup our udp socket.
2075      */
2076     SockProxyStartProc(AFS_SOCKPROXY_INIT_IDX, &sock);
2077
2078     /* Now fork our AFS_USPC_SOCKPROXY_RECV process. */
2079     recvpid = fork();
2080     opr_Assert(recvpid >= 0);
2081     if (recvpid == 0) {
2082         SockProxyReceiveProc(sock, AFS_SOCKPROXY_RECV_IDX);
2083         exit(1);
2084     }
2085
2086     /* Now fork our AFS_USPC_SOCKPROXY_SEND processes. */
2087     for (idx = 0; idx < AFS_SOCKPROXY_NPROCS; idx++) {
2088         pid_t child;
2089
2090         if (idx == AFS_SOCKPROXY_RECV_IDX) {
2091             /* Receiver already forked. */
2092             continue;
2093         }
2094         if (idx == AFS_SOCKPROXY_INIT_IDX) {
2095             /* We'll start the handler for this index in this process, below. */
2096             continue;
2097         }
2098
2099         child = fork();
2100         opr_Assert(child >= 0);
2101         if (child == 0) {
2102             SockProxySendProc(sock, idx, 0);
2103             exit(1);
2104         }
2105     }
2106     SockProxySendProc(sock, AFS_SOCKPROXY_INIT_IDX, recvpid);
2107
2108     return NULL;
2109 }
2110 #endif  /* AFS_SOCKPROXY_ENV */
2111
2112 static void *
2113 afsdb_thread(void *rock)
2114 {
2115     /* Since the AFSDB lookup handler runs as a user process,
2116      * need to drop the controlling TTY, etc.
2117      */
2118     if (afsd_daemon(0, 0) == -1) {
2119         printf("Error starting AFSDB lookup handler: %s\n",
2120                strerror(errno));
2121         exit(1);
2122     }
2123     AfsdbLookupHandler();
2124     return NULL;
2125 }
2126
2127 static void *
2128 daemon_thread(void *rock)
2129 {
2130 #ifdef AFS_NEW_BKG
2131     /* Since the background daemon runs as a user process,
2132      * need to drop the controlling TTY, etc.
2133      */
2134     if (afsd_daemon(0, 0) == -1) {
2135         printf("Error starting background daemon: %s\n",
2136                strerror(errno));
2137         exit(1);
2138     }
2139     BkgHandler();
2140 #else
2141     afsd_syscall(AFSOP_START_BKG, 0);
2142 #endif
2143     return NULL;
2144 }
2145
2146 #ifndef UKERNEL
2147 static void *
2148 rmtsysd_thread(void *rock)
2149 {
2150     rmtsysd();
2151     return NULL;
2152 }
2153 #endif /* !UKERNEL */
2154
2155 /**
2156  * Check the command line and cacheinfo options.
2157  *
2158  * @param[in] as  parsed command line arguments
2159  *
2160  * @note Invokes the shutdown syscall and exits with 0 when
2161  *       -shutdown is given.
2162  */
2163 static int
2164 CheckOptions(struct cmd_syndesc *as)
2165 {
2166     afs_int32 code;             /*Result of fork() */
2167 #ifdef  AFS_SUN5_ENV
2168     struct stat st;
2169 #endif
2170 #ifdef AFS_SGI65_ENV
2171     struct sched_param sp;
2172 #endif
2173
2174 #ifdef AFS_SGI_VNODE_GLUE
2175     if (afs_init_kernel_config(-1) < 0) {
2176         printf("Can't determine NUMA configuration, not starting AFS.\n");
2177         exit(1);
2178     }
2179 #endif
2180
2181     cmd_OpenConfigFile(AFSDIR_CLIENT_CONFIG_FILE_FILEPATH);
2182     cmd_SetCommandName("afsd");
2183
2184     /* call atoi on the appropriate parsed results */
2185     if (cmd_OptionAsInt(as, OPT_blocks, &cacheBlocks) == 0)
2186         sawCacheBlocks = 1;
2187
2188     if (cmd_OptionAsInt(as, OPT_files, &cacheFiles) == 0)
2189         filesSet = 1;
2190
2191     if (cmd_OptionAsString(as, OPT_rootvol, &rootVolume) == 0)
2192         rootVolSet = 1;
2193
2194     if (cmd_OptionAsInt(as, OPT_stat, &cacheStatEntries) == 0)
2195         sawCacheStatEntries = 1;
2196
2197     if (cmd_OptionPresent(as, OPT_memcache)) {
2198         cacheBaseDir = NULL;
2199         sawCacheBaseDir = 1;
2200         cacheFlags |= AFSCALL_INIT_MEMCACHE;
2201     }
2202
2203     if (cmd_OptionAsString(as, OPT_cachedir, &cacheBaseDir) == 0)
2204         sawCacheBaseDir = 1;
2205
2206     if (cmd_OptionAsString(as, OPT_mountdir, &afsd_cacheMountDir) == 0)
2207         sawCacheMountDir = 1;
2208
2209     cmd_OptionAsInt(as, OPT_daemons, &nDaemons);
2210
2211     afsd_verbose = cmd_OptionPresent(as, OPT_verbose);
2212
2213     if (cmd_OptionPresent(as, OPT_rmtsys)) {
2214         afsd_rmtsys = 1;
2215 #ifdef UKERNEL
2216         printf("-rmtsys not supported for UKERNEL\n");
2217         return -1;
2218 #endif
2219     }
2220
2221     if (cmd_OptionPresent(as, OPT_debug)) {
2222         afsd_debug = 1;
2223         afsd_verbose = 1;
2224     }
2225
2226     if (cmd_OptionAsInt(as, OPT_chunksize, &chunkSize) == 0) {
2227         if (chunkSize < 0 || chunkSize > 30) {
2228             printf
2229                 ("afsd:invalid chunk size (not in range 0-30), using default\n");
2230             chunkSize = 0;
2231         }
2232     }
2233
2234     if (cmd_OptionAsInt(as, OPT_dcache, &dCacheSize) == 0)
2235         sawDCacheSize = 1;
2236
2237     cmd_OptionAsInt(as, OPT_volumes, &vCacheSize);
2238
2239     if (cmd_OptionPresent(as, OPT_biods)) {
2240         /* -biods */
2241 #ifndef AFS_AIX32_ENV
2242         printf
2243             ("afsd: [-biods] currently only enabled for aix3.x VM supported systems\n");
2244 #else
2245         cmd_OptionAsInt(as, OPT_biods, &nBiods);
2246 #endif
2247     }
2248     cmd_OptionAsInt(as, OPT_prealloc, &preallocs);
2249
2250     if (cmd_OptionAsString(as, OPT_confdir, &confDir) == CMD_MISSING) {
2251         confDir = strdup(AFSDIR_CLIENT_ETC_DIRPATH);
2252     }
2253     sprintf(fullpn_CacheInfo, "%s/%s", confDir, CACHEINFOFILE);
2254
2255     if (cmd_OptionPresent(as, OPT_logfile)) {
2256         printf("afsd: Ignoring obsolete -logfile flag\n");
2257     }
2258
2259     afsd_CloseSynch = cmd_OptionPresent(as, OPT_waitclose);
2260
2261     if (cmd_OptionPresent(as, OPT_shutdown)) {
2262         /* -shutdown */
2263         /*
2264          * Cold shutdown is the default
2265          */
2266         printf("afsd: Shutting down all afs processes and afs state\n");
2267         code = afsd_syscall(AFSOP_SHUTDOWN, 1);         /* always AFS_COLD */
2268         if (code) {
2269             printf("afsd: AFS still mounted; Not shutting down\n");
2270             exit(1);
2271         }
2272         exit(0);
2273     }
2274
2275     enable_peer_stats = cmd_OptionPresent(as, OPT_peerstats);
2276     enable_process_stats = cmd_OptionPresent(as, OPT_processstats);
2277
2278     if (cmd_OptionPresent(as, OPT_memallocsleep)) {
2279         printf("afsd: -mem_alloc_sleep is deprecated -- ignored\n");
2280     }
2281
2282     enable_afsdb = cmd_OptionPresent(as, OPT_afsdb);
2283     if (cmd_OptionPresent(as, OPT_filesdir)) {
2284         /* -files_per_subdir */
2285         int res;
2286         cmd_OptionAsInt(as, OPT_filesdir, &res);
2287         if (res < 10 || res > (1 << 30)) {
2288             printf
2289                 ("afsd:invalid number of files per subdir, \"%s\". Ignored\n",
2290                  as->parms[25].items->data);
2291         } else {
2292             nFilesPerDir = res;
2293         }
2294     }
2295     enable_dynroot = cmd_OptionPresent(as, OPT_dynroot);
2296
2297     if (cmd_OptionPresent(as, OPT_fakestat)) {
2298         enable_fakestat = 2;
2299     }
2300     if (cmd_OptionPresent(as, OPT_fakestatall)) {
2301         enable_fakestat = 1;
2302     }
2303     if (cmd_OptionPresent(as, OPT_settime)) {
2304         /* -settime */
2305         printf("afsd: -settime ignored\n");
2306         printf("afsd: the OpenAFS client no longer sets the system time; "
2307                "please use NTP or\n");
2308         printf("afsd: another such system to synchronize client time\n");
2309     }
2310
2311     enable_nomount = cmd_OptionPresent(as, OPT_nomount);
2312     enable_backuptree = cmd_OptionPresent(as, OPT_backuptree);
2313     enable_rxbind = cmd_OptionPresent(as, OPT_rxbind);
2314
2315     /* set rx_extraPackets */
2316     if (cmd_OptionPresent(as, OPT_rxpck)) {
2317         /* -rxpck */
2318         int rxpck;
2319         cmd_OptionAsInt(as, OPT_rxpck, &rxpck);
2320         printf("afsd: set rxpck = %d\n", rxpck);
2321         code = afsd_syscall(AFSOP_SET_RXPCK, rxpck);
2322         if (code) {
2323             printf("afsd: failed to set rxpck\n");
2324             exit(1);
2325         }
2326     }
2327     if (cmd_OptionPresent(as, OPT_splitcache)) {
2328         char *c;
2329         char *var = NULL;
2330
2331         cmd_OptionAsString(as, OPT_splitcache, &var);
2332
2333         if (var == NULL || ((c = strchr(var, '/')) == NULL))
2334             printf
2335                 ("ignoring splitcache (specify as RW/RO percentages: 60/40)\n");
2336         else {
2337             ropct = atoi(c + 1);
2338             *c = '\0';
2339             rwpct = atoi(var);
2340             if ((rwpct != 0) && (ropct != 0) && (ropct + rwpct == 100)) {
2341                 /* -splitcache */
2342                 enable_splitcache = 1;
2343             }
2344         }
2345         free(var);
2346     }
2347     if (cmd_OptionPresent(as, OPT_nodynvcache)) {
2348 #ifdef AFS_MAXVCOUNT_ENV
2349        afsd_dynamic_vcaches = 0;
2350 #else
2351        printf("afsd: Error toggling flag, dynamically allocated vcaches not supported on your platform\n");
2352        exit(1);
2353 #endif
2354     }
2355 #ifdef AFS_MAXVCOUNT_ENV
2356     else {
2357        /* -dynamic-vcaches */
2358        afsd_dynamic_vcaches = 1;
2359     }
2360
2361     if (afsd_verbose)
2362     printf("afsd: %s dynamically allocated vcaches\n", ( afsd_dynamic_vcaches ? "enabling" : "disabling" ));
2363 #endif
2364
2365     cmd_OptionAsInt(as, OPT_rxmaxmtu, &rxmaxmtu);
2366
2367     if (cmd_OptionPresent(as, OPT_dynrootsparse)) {
2368         enable_dynroot = 2;
2369     }
2370
2371     cmd_OptionAsInt(as, OPT_rxmaxfrags, &rxmaxfrags);
2372     if (cmd_OptionPresent(as, OPT_inumcalc)) {
2373         cmd_OptionAsString(as, OPT_inumcalc, &inumcalc);
2374     }
2375     cmd_OptionAsInt(as, OPT_volume_ttl, &volume_ttl);
2376
2377     /* parse cacheinfo file if this is a diskcache */
2378     if (ParseCacheInfoFile()) {
2379         exit(1);
2380     }
2381
2382     return 0;
2383 }
2384
2385 int
2386 afsd_run(void)
2387 {
2388     static char rn[] = "afsd";  /*Name of this routine */
2389     struct afsconf_dir *cdir;   /* config dir */
2390     int lookupResult;           /*Result of GetLocalCellName() */
2391     int i;
2392     int code;                   /*Result of fork() */
2393     char *fsTypeMsg = NULL;
2394     int cacheIteration;         /*How many times through cache verification */
2395     int vFilesFound;            /*How many data cache files were found in sweep */
2396     int currVFile;              /*Current AFS cache file number passed in */
2397
2398         /*
2399      * Pull out all the configuration info for the workstation's AFS cache and
2400      * the cellular community we're willing to let our users see.
2401      */
2402     cdir = afsconf_Open(confDir);
2403     if (!cdir) {
2404         printf("afsd: some file missing or bad in %s\n", confDir);
2405         exit(1);
2406     }
2407
2408     lookupResult =
2409         afsconf_GetLocalCell(cdir, LclCellName, sizeof(LclCellName));
2410     if (lookupResult) {
2411         printf("%s: Can't get my home cell name!  [Error is %d]\n", rn,
2412                lookupResult);
2413     } else {
2414         if (afsd_verbose)
2415             printf("%s: My home cell is '%s'\n", rn, LclCellName);
2416     }
2417
2418     if (!enable_nomount) {
2419         if (afsd_check_mount(rn, afsd_cacheMountDir)) {
2420             return -1;
2421         }
2422     }
2423
2424     /* do some random computations in memcache case to get things to work
2425      * reasonably no matter which parameters you set.
2426      */
2427     if (cacheFlags & AFSCALL_INIT_MEMCACHE) {
2428         /* memory cache: size described either as blocks or dcache entries, but
2429          * not both.
2430          */
2431         if (filesSet) {
2432             fprintf(stderr, "%s: -files ignored with -memcache\n", rn);
2433         }
2434         if (sawDCacheSize) {
2435             if (chunkSize == 0) {
2436                 chunkSize = 13; /* 8k default chunksize for memcache */
2437             }
2438             if (sawCacheBlocks) {
2439                 printf
2440                     ("%s: can't set cache blocks and dcache size simultaneously when diskless.\n",
2441                      rn);
2442                 exit(1);
2443             }
2444             /* compute the cache size based on # of chunks times the chunk size */
2445             i = (1 << chunkSize);       /* bytes per chunk */
2446             cacheBlocks = i * dCacheSize;
2447             sawCacheBlocks = 1; /* so that ParseCacheInfoFile doesn't overwrite */
2448         } else {
2449             if (chunkSize == 0) {
2450                 /* Try to autotune the memcache chunksize based on size
2451                  * of memcache. This is done on the assumption that approx
2452                  * 1024 chunks is suitable, it's a balance between enough
2453                  * chunks to be useful and ramping up nicely when using larger
2454                  * memcache to improve bulk read/write performance
2455                  */
2456                 for (i = 14;
2457                      i <= 21 && (1 << i) / 1024 < (cacheBlocks / 1024); i++);
2458                 chunkSize = i - 1;
2459             }
2460             /* compute the dcache size from overall cache size and chunk size */
2461             if (chunkSize > 10) {
2462                 dCacheSize = (cacheBlocks >> (chunkSize - 10));
2463             } else if (chunkSize < 10) {
2464                 dCacheSize = (cacheBlocks << (10 - chunkSize));
2465             } else {
2466                 dCacheSize = cacheBlocks;
2467             }
2468             /* don't have to set sawDCacheSize here since it isn't overwritten
2469              * by ParseCacheInfoFile.
2470              */
2471         }
2472         if (afsd_verbose)
2473             printf("%s: chunkSize autotuned to %d\n", rn, chunkSize);
2474
2475         /* kernel computes # of dcache entries as min of cacheFiles and
2476          * dCacheSize, so we now make them equal.
2477          */
2478         cacheFiles = dCacheSize;
2479     } else {
2480         /* Disk cache:
2481          * Compute the number of cache files based on cache size,
2482          * but only if -files isn't given on the command line.
2483          * Don't let # files be so small as to prevent full utilization
2484          * of the cache unless user has explicitly asked for it.
2485          */
2486         if (chunkSize == 0) {
2487             /* Set chunksize to 256kB - 1MB depending on cache size */
2488             if (cacheBlocks < 500000) {
2489                 chunkSize = 18;
2490             } else if (cacheBlocks < 1000000) {
2491                 chunkSize = 19;
2492             } else {
2493                 chunkSize = 20;
2494             }
2495         }
2496
2497         if (!filesSet) {
2498             cacheFiles = cacheBlocks / 32;      /* Assume 32k avg filesize */
2499
2500             cacheFiles = max(cacheFiles, 1000);
2501
2502             /* Always allow more files than chunks.  Presume average V-file
2503              * is ~67% of a chunk...  (another guess, perhaps Honeyman will
2504              * have a grad student write a paper).  i is KILOBYTES.
2505              */
2506             i = 1 << (chunkSize < 10 ? 0 : chunkSize - 10);
2507             cacheFiles = max(cacheFiles, 1.5 * (cacheBlocks / i));
2508
2509             /* never permit more files than blocks, while leaving space for
2510              * VolumeInfo and CacheItems files.  VolumeInfo is usually 20K,
2511              * CacheItems is 50 Bytes / file (== 1K/20)
2512              */
2513 #define CACHEITMSZ (cacheFiles / 20)
2514 #define VOLINFOSZ 50            /* 40kB has been seen, be conservative */
2515 #define CELLINFOSZ 4            /* Assuming disk block size is 4k ... */
2516 #define INFOSZ (VOLINFOSZ+CELLINFOSZ+CACHEITMSZ)
2517
2518             /* Sanity check: If the obtained number of disk cache files
2519              * is larger than the number of available (4k) disk blocks, we're
2520              * doing something wrong. Fail hard so we can fix the bug instead
2521              * of silently hiding it like before */
2522
2523             if (cacheFiles > (cacheBlocks - INFOSZ) / 4) {
2524                 fprintf(stderr,
2525                         "%s: ASSERT: cacheFiles %d  diskblocks %d\n",
2526                         rn, cacheFiles, (cacheBlocks - INFOSZ) / 4);
2527                 exit(1);
2528             }
2529             if (cacheFiles < 100)
2530                 fprintf(stderr, "%s: WARNING: cache probably too small!\n",
2531                         rn);
2532
2533             if (afsd_verbose)
2534                 printf("%s: cacheFiles autotuned to %d\n", rn, cacheFiles);
2535         }
2536         if (!sawDCacheSize) {
2537             dCacheSize = cacheFiles / 2;
2538             if (dCacheSize > 10000) {
2539                 dCacheSize = 10000;
2540             }
2541             if (dCacheSize < 2000) {
2542                 dCacheSize = 2000;
2543             }
2544             if (afsd_verbose)
2545                 printf("%s: dCacheSize autotuned to %d\n", rn, dCacheSize);
2546         }
2547     }
2548     if (!sawCacheStatEntries) {
2549         if (chunkSize <= 13) {
2550             cacheStatEntries = dCacheSize / 4;
2551         } else if (chunkSize >= 16) {
2552             cacheStatEntries = dCacheSize * 1.5;
2553         } else {
2554             cacheStatEntries = dCacheSize;
2555         }
2556         if (afsd_verbose)
2557             printf("%s: cacheStatEntries autotuned to %d\n", rn,
2558                    cacheStatEntries);
2559     }
2560
2561 #if !defined(AFS_CACHE_VNODE_PATH) && !defined(AFS_LINUX26_ENV)
2562     /*
2563      * Create and zero the inode table for the desired cache files.
2564      */
2565     inode_for_V = calloc(cacheFiles, sizeof(AFSD_INO_T));
2566     if (inode_for_V == (AFSD_INO_T *) 0) {
2567         printf
2568             ("%s: malloc() failed for cache file inode table with %d entries.\n",
2569              rn, cacheFiles);
2570         exit(1);
2571     }
2572     if (afsd_debug)
2573         printf("%s: %d inode_for_V entries at %p, %lu bytes\n", rn,
2574                cacheFiles, inode_for_V,
2575                (unsigned long)cacheFiles * sizeof(AFSD_INO_T));
2576 #endif
2577
2578     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
2579         /*
2580          * Set up all the pathnames we'll need for later.
2581          */
2582         sprintf(fullpn_DCacheFile, "%s/%s", cacheBaseDir, DCACHEFILE);
2583         sprintf(fullpn_VolInfoFile, "%s/%s", cacheBaseDir, VOLINFOFILE);
2584         sprintf(fullpn_CellInfoFile, "%s/%s", cacheBaseDir, CELLINFOFILE);
2585         sprintf(fullpn_VFile, "%s/", cacheBaseDir);
2586         vFilePtr = fullpn_VFile + strlen(fullpn_VFile);
2587
2588         fsTypeMsg = CheckCacheBaseDir(cacheBaseDir);
2589         if (fsTypeMsg) {
2590 #ifdef AFS_SUN5_ENV
2591             printf("%s: WARNING: Cache dir check failed (%s)\n", rn, fsTypeMsg);
2592 #else
2593             printf("%s: ERROR: Cache dir check failed (%s)\n", rn, fsTypeMsg);
2594             exit(1);
2595 #endif
2596         }
2597     }
2598
2599     /*
2600      * Set up all the kernel processes needed for AFS.
2601      */
2602 #ifdef mac2
2603     setpgrp(getpid(), 0);
2604 #endif /* mac2 */
2605
2606     /*
2607      * Set the primary cell name.
2608      */
2609     afsd_syscall(AFSOP_SET_THISCELL, LclCellName);
2610
2611     /* Initialize RX daemons and services */
2612
2613     /* initialize the rx random number generator from user space */
2614     {
2615         /* rand-fortuna wants at least 128 bytes of seed; be generous. */
2616         unsigned char seedbuf[256];
2617         if (RAND_bytes(seedbuf, sizeof(seedbuf)) != 1) {
2618             printf("SEED_ENTROPY: Error retrieving seed entropy\n");
2619         }
2620         afsd_syscall(AFSOP_SEED_ENTROPY, seedbuf, sizeof(seedbuf));
2621         memset(seedbuf, 0, sizeof(seedbuf));
2622         /* parse multihomed address files */
2623         afs_uint32 addrbuf[MAXIPADDRS], maskbuf[MAXIPADDRS],
2624             mtubuf[MAXIPADDRS];
2625         char reason[1024];
2626         code = afsconf_ParseNetFiles(addrbuf, maskbuf, mtubuf, MAXIPADDRS, reason,
2627                                      AFSDIR_CLIENT_NETINFO_FILEPATH,
2628                                      AFSDIR_CLIENT_NETRESTRICT_FILEPATH);
2629         if (code > 0) {
2630             if (enable_rxbind)
2631                 code = code | 0x80000000;
2632             afsd_syscall(AFSOP_ADVISEADDR, code, addrbuf, maskbuf, mtubuf);
2633         } else
2634             printf("ADVISEADDR: Error in specifying interface addresses:%s\n",
2635                    reason);
2636     }
2637
2638     /* Set realtime priority for most threads to same as for biod's. */
2639     afsd_set_afsd_rtpri();
2640
2641     /* Start listener, then callback listener. Lastly, start rx event daemon.
2642      * Change in ordering is so that Linux port has socket fd in listener
2643      * process.
2644      * preallocs are passed for both listener and callback server. Only
2645      * the one which actually does the initialization uses them though.
2646      */
2647     if (preallocs < cacheStatEntries + 50)
2648         preallocs = cacheStatEntries + 50;
2649 #ifdef RXK_LISTENER_ENV
2650     if (afsd_verbose)
2651         printf("%s: Forking rx listener daemon.\n", rn);
2652 # ifdef AFS_SUN510_ENV
2653     fork_rx_syscall_wait(rn, AFSOP_RXLISTENER_DAEMON, preallocs,
2654                          enable_peer_stats, enable_process_stats);
2655 # else /* !AFS_SUN510_ENV */
2656     fork_rx_syscall(rn, AFSOP_RXLISTENER_DAEMON, preallocs, enable_peer_stats,
2657                     enable_process_stats);
2658 # endif /* !AFS_SUN510_ENV */
2659 #endif
2660     if (afsd_verbose)
2661         printf("%s: Forking rx callback listener.\n", rn);
2662 #ifndef RXK_LISTENER_ENV
2663     fork_rx_syscall(rn, AFSOP_START_RXCALLBACK, preallocs, enable_peer_stats,
2664                     enable_process_stats);
2665 #else
2666     fork_syscall(rn, AFSOP_START_RXCALLBACK, preallocs, 0, 0);
2667 #endif
2668 #if defined(AFS_SUN5_ENV) || defined(RXK_LISTENER_ENV) || defined(RXK_UPCALL_ENV)
2669     if (afsd_verbose)
2670         printf("%s: Forking rxevent daemon.\n", rn);
2671     fork_rx_syscall(rn, AFSOP_RXEVENT_DAEMON);
2672 #endif
2673
2674 #ifdef AFS_SOCKPROXY_ENV
2675     if (afsd_verbose)
2676         printf("%s: Forking socket proxy handlers.\n", rn);
2677     afsd_fork(0, sockproxy_thread, NULL);
2678 #endif
2679
2680     if (enable_afsdb) {
2681         if (afsd_verbose)
2682             printf("%s: Forking AFSDB lookup handler.\n", rn);
2683         afsd_fork(0, afsdb_thread, NULL);
2684     }
2685     code = afsd_syscall(AFSOP_BASIC_INIT, 1);
2686     if (code) {
2687         printf("%s: Error %d in basic initialization.\n", rn, code);
2688         exit(1);
2689     }
2690
2691     /*
2692      * Tell the kernel some basic information about the workstation's cache.
2693      */
2694     if (afsd_verbose)
2695         printf
2696             ("%s: Calling AFSOP_CACHEINIT: %d stat cache entries, %d optimum cache files, %d blocks in the cache, flags = 0x%x, dcache entries %d\n",
2697              rn, cacheStatEntries, cacheFiles, cacheBlocks, cacheFlags,
2698              dCacheSize);
2699     memset(&cparams, '\0', sizeof(cparams));
2700     cparams.cacheScaches = cacheStatEntries;
2701     cparams.cacheFiles = cacheFiles;
2702     cparams.cacheBlocks = cacheBlocks;
2703     cparams.cacheDcaches = dCacheSize;
2704     cparams.cacheVolumes = vCacheSize;
2705     cparams.chunkSize = chunkSize;
2706     cparams.setTimeFlag = 0;
2707     cparams.memCacheFlag = cacheFlags;
2708     cparams.dynamic_vcaches = afsd_dynamic_vcaches;
2709     code = afsd_syscall(AFSOP_CACHEINIT, &cparams);
2710     if (code) {
2711         printf("%s: Error %d during cache init.\n", rn, code);
2712         exit(1);
2713     }
2714
2715     /* do it before we init the cache inodes */
2716     if (enable_splitcache) {
2717         afsd_syscall(AFSOP_BUCKETPCT, 1, rwpct);
2718         afsd_syscall(AFSOP_BUCKETPCT, 2, ropct);
2719     }
2720
2721     if (afsd_CloseSynch)
2722         afsd_syscall(AFSOP_CLOSEWAIT);
2723
2724     /*
2725      * Sweep the workstation AFS cache directory, remembering the inodes of
2726      * valid files and deleting extraneous files.  Keep sweeping until we
2727      * have the right number of data cache files or we've swept too many
2728      * times.
2729      *
2730      * This also creates files in the cache directory like VolumeItems and
2731      * CellItems, and thus must be ran before those are sent to the kernel.
2732      */
2733     if (afsd_verbose)
2734         printf("%s: Sweeping workstation's AFS cache directory.\n", rn);
2735     cacheIteration = 0;
2736     /* Memory-cache based system doesn't need any of this */
2737     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
2738         do {
2739             cacheIteration++;
2740             if (SweepAFSCache(&vFilesFound)) {
2741                 printf("%s: Error on sweep %d of workstation AFS cache \
2742                        directory.\n", rn, cacheIteration);
2743                 exit(1);
2744             }
2745             if (afsd_verbose)
2746                 printf
2747                     ("%s: %d out of %d data cache files found in sweep %d.\n",
2748                      rn, vFilesFound, cacheFiles, cacheIteration);
2749         } while ((vFilesFound < cacheFiles)
2750                  && (cacheIteration < MAX_CACHE_LOOPS));
2751     } else if (afsd_verbose)
2752         printf("%s: Using memory cache, not swept\n", rn);
2753
2754     /*
2755      * Pass the kernel the name of the workstation cache file holding the
2756      * dcache entries.
2757      */
2758     if (afsd_debug)
2759         printf("%s: Calling AFSOP_CACHEINFO: dcache file is '%s'\n", rn,
2760                fullpn_DCacheFile);
2761     /* once again, meaningless for a memory-based cache. */
2762     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))
2763         afsd_syscall(AFSOP_CACHEINFO, fullpn_DCacheFile);
2764
2765     /*
2766      * Pass the kernel the name of the workstation cache file holding the
2767      * cell information.
2768      */
2769     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
2770         if (afsd_debug)
2771             printf("%s: Calling AFSOP_CELLINFO: cell info file is '%s'\n", rn,
2772                    fullpn_CellInfoFile);
2773         afsd_syscall(AFSOP_CELLINFO, fullpn_CellInfoFile);
2774     }
2775
2776     if (rxmaxfrags) {
2777         if (afsd_verbose)
2778             printf("%s: Setting rxmaxfrags in kernel = %d\n", rn, rxmaxfrags);
2779         code = afsd_syscall(AFSOP_SET_RXMAXFRAGS, rxmaxfrags);
2780         if (code)
2781             printf("%s: Error seting rxmaxfrags\n", rn);
2782     }
2783
2784     if (rxmaxmtu) {
2785         if (afsd_verbose)
2786             printf("%s: Setting rxmaxmtu in kernel = %d\n", rn, rxmaxmtu);
2787         code = afsd_syscall(AFSOP_SET_RXMAXMTU, rxmaxmtu);
2788         if (code)
2789             printf("%s: Error seting rxmaxmtu\n", rn);
2790     }
2791
2792     if (inumcalc != NULL) {
2793         if (strcmp(inumcalc, "compat") == 0) {
2794             if (afsd_verbose) {
2795                 printf("%s: Setting original inode number calculation method in kernel.\n",
2796                        rn);
2797             }
2798             code = afsd_syscall(AFSOP_SET_INUMCALC, AFS_INUMCALC_COMPAT);
2799             if (code) {
2800                 printf("%s: Error setting inode calculation method: code=%d.\n",
2801                        rn, code);
2802             }
2803         } else if (strcmp(inumcalc, "md5") == 0) {
2804             if (afsd_verbose) {
2805                 printf("%s: Setting md5 digest inode number calculation in kernel.\n",
2806                        rn);
2807             }
2808             code = afsd_syscall(AFSOP_SET_INUMCALC, AFS_INUMCALC_MD5);
2809             if (code) {
2810                 printf("%s: Error setting inode calculation method: code=%d.\n",
2811                        rn, code);
2812             }
2813         } else {
2814             printf("%s: Unknown value for -inumcalc: %s."
2815                    "Using default inode calculation method.\n", rn, inumcalc);
2816         }
2817     }
2818
2819     if (enable_dynroot) {
2820         if (afsd_verbose)
2821             printf("%s: Enabling dynroot support in kernel%s.\n", rn,
2822                    (enable_dynroot==2)?", not showing cells.":"");
2823         code = afsd_syscall(AFSOP_SET_DYNROOT, 1);
2824         if (code)
2825             printf("%s: Error enabling dynroot support.\n", rn);
2826     }
2827
2828     if (enable_fakestat) {
2829         if (afsd_verbose)
2830             printf("%s: Enabling fakestat support in kernel%s.\n", rn,
2831                    (enable_fakestat==1)?" for all mountpoints."
2832                    :" for crosscell mountpoints");
2833         code = afsd_syscall(AFSOP_SET_FAKESTAT, enable_fakestat);
2834         if (code)
2835             printf("%s: Error enabling fakestat support.\n", rn);
2836     }
2837
2838     if (enable_backuptree) {
2839         if (afsd_verbose)
2840             printf("%s: Enabling backup tree support in kernel.\n", rn);
2841         code = afsd_syscall(AFSOP_SET_BACKUPTREE, enable_backuptree);
2842         if (code)
2843             printf("%s: Error enabling backup tree support.\n", rn);
2844     }
2845
2846     /*
2847      * Tell the kernel about each cell in the configuration.
2848      */
2849     afsconf_CellApply(cdir, ConfigCell, NULL);
2850     afsconf_CellAliasApply(cdir, ConfigCellAlias, NULL);
2851
2852     /* Initialize AFS daemon threads. */
2853     if (afsd_verbose)
2854         printf("%s: Forking AFS daemon.\n", rn);
2855     fork_syscall(rn, AFSOP_START_AFS);
2856
2857     if (afsd_verbose)
2858         printf("%s: Forking Check Server Daemon.\n", rn);
2859     fork_syscall(rn, AFSOP_START_CS);
2860
2861     if (afsd_verbose)
2862         printf("%s: Forking %d background daemons.\n", rn, nDaemons);
2863 #if defined(AFS_SGI_ENV) && defined(AFS_SGI_SHORTSTACK)
2864     /* Add one because for sgi we always "steal" the first daemon for a
2865      * different task if we only have a 4K stack.
2866      */
2867     nDaemons++;
2868 #endif
2869     for (i = 0; i < nDaemons; i++) {
2870         afsd_fork(0, daemon_thread, NULL);
2871     }
2872 #ifdef  AFS_AIX32_ENV
2873     if (!sawBiod)
2874         nBiods = nDaemons * 2;
2875     if (nBiods < 5)
2876         nBiods = 5;
2877     for (i = 0; i < nBiods; i++) {
2878         fork_syscall(rn, AFSOP_START_BKG, nBiods);
2879     }
2880 #endif
2881
2882     /*
2883      * If the root volume has been explicitly set, tell the kernel.
2884      */
2885     if (rootVolSet) {
2886         if (afsd_verbose)
2887             printf("%s: Calling AFSOP_ROOTVOLUME with '%s'\n", rn,
2888                    rootVolume);
2889         afsd_syscall(AFSOP_ROOTVOLUME, rootVolume);
2890     }
2891
2892     if (volume_ttl != 0) {
2893         if (afsd_verbose)
2894             printf("%s: Calling AFSOP_SET_VOLUME_TTL with '%d'\n", rn, volume_ttl);
2895         code = afsd_syscall(AFSOP_SET_VOLUME_TTL, volume_ttl);
2896         if (code == EFAULT) {
2897             if (volume_ttl < AFS_MIN_VOLUME_TTL)
2898                 printf("%s: Failed to set volume ttl to %d seconds; "
2899                        "value is too low.\n", rn, volume_ttl);
2900             else if (volume_ttl > AFS_MAX_VOLUME_TTL)
2901                 printf("%s: Failed to set volume ttl to %d seconds; "
2902                        "value is too high.\n", rn, volume_ttl);
2903             else
2904                 printf("%s: Failed to set volume ttl to %d seconds; "
2905                        "value is out of range.\n", rn, volume_ttl);
2906         } else if (code != 0) {
2907             printf("%s: Failed to set volume ttl to %d seconds; "
2908                    "code=%d.\n", rn, volume_ttl, code);
2909         }
2910     }
2911
2912     /*
2913      * Pass the kernel the name of the workstation cache file holding the
2914      * volume information.
2915      */
2916     if (afsd_debug)
2917         printf("%s: Calling AFSOP_VOLUMEINFO: volume info file is '%s'\n", rn,
2918                fullpn_VolInfoFile);
2919     /* once again, meaningless for a memory-based cache. */
2920     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE))
2921         afsd_syscall(AFSOP_VOLUMEINFO, fullpn_VolInfoFile);
2922
2923     /*
2924      * Give the kernel the names of the AFS files cached on the workstation's
2925      * disk.
2926      */
2927     if (!(cacheFlags & AFSCALL_INIT_MEMCACHE)) {
2928         int nocachefile = 0;
2929         if (afsd_debug)
2930             printf
2931                 ("%s: Calling AFSOP_CACHEFILE for each of the %d files in '%s'\n",
2932                  rn, cacheFiles, cacheBaseDir);
2933         /* ... and again ... */
2934         for (currVFile = 0; currVFile < cacheFiles; currVFile++) {
2935             if (!nocachefile) {
2936                 sprintf(fullpn_VFile, "%s/D%d/V%d", cacheBaseDir, dir_for_V[currVFile], currVFile);
2937                 code = afsd_syscall(AFSOP_CACHEFILE, fullpn_VFile);
2938                 if (code) {
2939                     if (currVFile == 0) {
2940                         if (afsd_debug)
2941                             printf
2942                                 ("%s: Calling AFSOP_CACHEINODE for each of the %d files in '%s'\n",
2943                                  rn, cacheFiles, cacheBaseDir);
2944                         nocachefile = 1;
2945                     } else {
2946                         printf
2947                             ("%s: Error calling AFSOP_CACHEFILE for '%s'\n",
2948                              rn, fullpn_VFile);
2949                         exit(1);
2950                     }
2951                 } else {
2952                     continue;
2953                 }
2954                 /* fall through to setup-by-inode */
2955             }
2956 #if defined(AFS_SGI62_ENV) || !(defined(AFS_LINUX26_ENV) || defined(AFS_CACHE_VNODE_PATH))
2957             afsd_syscall(AFSOP_CACHEINODE, inode_for_V[currVFile]);
2958 #else
2959             printf
2960                 ("%s: Error calling AFSOP_CACHEINODE: not configured\n",
2961                  rn);
2962             exit(1);
2963 #endif
2964         }
2965     }
2966     /*end for */
2967     /*
2968      * All the necessary info has been passed into the kernel to run an AFS
2969      * system.  Give the kernel our go-ahead.
2970      */
2971     if (afsd_debug)
2972         printf("%s: Calling AFSOP_GO with cacheSetTime = %d\n", rn,
2973                0);
2974     afsd_syscall(AFSOP_GO, 0);
2975
2976     /*
2977      * At this point, we have finished passing the kernel all the info
2978      * it needs to set up the AFS.  Mount the AFS root.
2979      */
2980     printf("%s: All AFS daemons started.\n", rn);
2981
2982     if (afsd_verbose)
2983         printf("%s: Forking trunc-cache daemon.\n", rn);
2984     fork_syscall(rn, AFSOP_START_TRUNCDAEMON);
2985
2986     if (!enable_nomount) {
2987         afsd_mount_afs(rn, afsd_cacheMountDir);
2988     }
2989
2990 #ifndef UKERNEL
2991     if (afsd_rmtsys) {
2992         if (afsd_verbose)
2993             printf("%s: Forking 'rmtsys' daemon.\n", rn);
2994         afsd_fork(0, rmtsysd_thread, NULL);
2995         code = afsd_syscall(AFSOP_SET_RMTSYS_FLAG, 1);
2996         if (code)
2997             printf("%s: Error enabling rmtsys support.\n", rn);
2998     }
2999 #endif /* !UKERNEL */
3000     /*
3001      * Exit successfully.
3002      */
3003     return 0;
3004 }
3005
3006 #ifndef UKERNEL
3007 #include "AFS_component_version_number.c"
3008 #endif
3009
3010 void
3011 afsd_init(void)
3012 {
3013     struct cmd_syndesc *ts;
3014
3015     ts = cmd_CreateSyntax(NULL, NULL, NULL, 0, "start AFS");
3016
3017     /* 0 - 10 */
3018     cmd_AddParmAtOffset(ts, OPT_blocks, "-blocks", CMD_SINGLE,
3019                         CMD_OPTIONAL, "1024 byte blocks in cache");
3020     cmd_AddParmAtOffset(ts, OPT_files, "-files", CMD_SINGLE,
3021                         CMD_OPTIONAL, "files in cache");
3022     cmd_AddParmAtOffset(ts, OPT_rootvol, "-rootvol", CMD_SINGLE,
3023                         CMD_OPTIONAL, "name of AFS root volume");
3024     cmd_AddParmAtOffset(ts, OPT_stat, "-stat", CMD_SINGLE,
3025                         CMD_OPTIONAL, "number of stat entries");
3026     cmd_AddParmAtOffset(ts, OPT_memcache, "-memcache", CMD_FLAG,
3027                         CMD_OPTIONAL, "run diskless");
3028     cmd_AddParmAtOffset(ts, OPT_cachedir, "-cachedir", CMD_SINGLE,
3029                         CMD_OPTIONAL, "cache directory");
3030     cmd_AddParmAtOffset(ts, OPT_mountdir, "-mountdir", CMD_SINGLE,
3031                         CMD_OPTIONAL, "mount location");
3032     cmd_AddParmAtOffset(ts, OPT_daemons, "-daemons", CMD_SINGLE,
3033                         CMD_OPTIONAL, "number of daemons to use");
3034     cmd_AddParmAtOffset(ts, OPT_nosettime, "-nosettime", CMD_FLAG,
3035                         CMD_OPTIONAL, "don't set the time");
3036     cmd_AddParmAtOffset(ts, OPT_verbose, "-verbose", CMD_FLAG,
3037                         CMD_OPTIONAL, "display lots of information");
3038     cmd_AddParmAtOffset(ts, OPT_rmtsys, "-rmtsys", CMD_FLAG,
3039                         CMD_OPTIONAL, "start NFS rmtsysd program");
3040     cmd_AddParmAtOffset(ts, OPT_debug, "-debug", CMD_FLAG,
3041                         CMD_OPTIONAL, "display debug info");
3042     cmd_AddParmAtOffset(ts, OPT_chunksize, "-chunksize", CMD_SINGLE,
3043                         CMD_OPTIONAL, "log(2) of chunk size");
3044     cmd_AddParmAtOffset(ts, OPT_dcache, "-dcache", CMD_SINGLE,
3045                         CMD_OPTIONAL, "number of dcache entries");
3046     cmd_AddParmAtOffset(ts, OPT_volumes, "-volumes", CMD_SINGLE,
3047                         CMD_OPTIONAL, "number of volume entries");
3048     cmd_AddParmAtOffset(ts, OPT_biods, "-biods", CMD_SINGLE,
3049                         CMD_OPTIONAL, "number of bkg I/O daemons (aix vm)");
3050     cmd_AddParmAtOffset(ts, OPT_prealloc, "-prealloc", CMD_SINGLE,
3051                         CMD_OPTIONAL, "number of 'small' preallocated blocks");
3052     cmd_AddParmAtOffset(ts, OPT_confdir, "-confdir", CMD_SINGLE,
3053                         CMD_OPTIONAL, "configuration directory");
3054     cmd_AddParmAtOffset(ts, OPT_logfile, "-logfile", CMD_SINGLE,
3055                         CMD_OPTIONAL, "Place to keep the CM log");
3056     cmd_AddParmAtOffset(ts, OPT_waitclose, "-waitclose", CMD_FLAG,
3057                         CMD_OPTIONAL, "make close calls synchronous");
3058     cmd_AddParmAtOffset(ts, OPT_shutdown, "-shutdown", CMD_FLAG,
3059                         CMD_OPTIONAL, "Shutdown all afs state");
3060     cmd_AddParmAtOffset(ts, OPT_peerstats, "-enable_peer_stats", CMD_FLAG,
3061                         CMD_OPTIONAL, "Collect rpc statistics by peer");
3062     cmd_AddParmAtOffset(ts, OPT_processstats, "-enable_process_stats",
3063                         CMD_FLAG, CMD_OPTIONAL, "Collect rpc statistics for this process");
3064     cmd_AddParmAtOffset(ts, OPT_memallocsleep, "-mem_alloc_sleep",
3065                         CMD_FLAG, CMD_OPTIONAL | CMD_HIDE,
3066                         "Allow sleeps when allocating memory cache");
3067     cmd_AddParmAtOffset(ts, OPT_afsdb, "-afsdb", CMD_FLAG,
3068                         CMD_OPTIONAL, "Enable AFSDB support");
3069     cmd_AddParmAtOffset(ts, OPT_filesdir, "-files_per_subdir", CMD_SINGLE,
3070                         CMD_OPTIONAL,
3071                         "log(2) of the number of cache files per "
3072                         "cache subdirectory");
3073     cmd_AddParmAtOffset(ts, OPT_dynroot, "-dynroot", CMD_FLAG,
3074                         CMD_OPTIONAL, "Enable dynroot support");
3075     cmd_AddParmAtOffset(ts, OPT_fakestat, "-fakestat", CMD_FLAG,
3076                         CMD_OPTIONAL,
3077                         "Enable fakestat support for cross-cell mounts");
3078     cmd_AddParmAtOffset(ts, OPT_fakestatall, "-fakestat-all", CMD_FLAG,
3079                         CMD_OPTIONAL,
3080                         "Enable fakestat support for all mounts");
3081     cmd_AddParmAtOffset(ts, OPT_nomount, "-nomount", CMD_FLAG,
3082                         CMD_OPTIONAL, "Do not mount AFS");
3083     cmd_AddParmAtOffset(ts, OPT_backuptree, "-backuptree", CMD_FLAG,
3084                         CMD_OPTIONAL,
3085                         "Prefer backup volumes for mountpoints in backup "
3086                         "volumes");
3087     cmd_AddParmAtOffset(ts, OPT_rxbind, "-rxbind", CMD_FLAG,
3088                         CMD_OPTIONAL,
3089                         "Bind the Rx socket (one interface only)");
3090     cmd_AddParmAtOffset(ts, OPT_settime, "-settime", CMD_FLAG,
3091                         CMD_OPTIONAL, "set the time");
3092     cmd_AddParmAtOffset(ts, OPT_rxpck, "-rxpck", CMD_SINGLE, CMD_OPTIONAL,
3093                         "set rx_extraPackets to this value");
3094     cmd_AddParmAtOffset(ts, OPT_splitcache, "-splitcache", CMD_SINGLE,
3095                         CMD_OPTIONAL,
3096                         "Percentage RW versus RO in cache (specify as 60/40)");
3097     cmd_AddParmAtOffset(ts, OPT_nodynvcache, "-disable-dynamic-vcaches",
3098                         CMD_FLAG, CMD_OPTIONAL,
3099                         "disable stat/vcache cache growing as needed");
3100     cmd_AddParmAtOffset(ts, OPT_rxmaxmtu, "-rxmaxmtu", CMD_SINGLE,
3101                         CMD_OPTIONAL, "set rx max MTU to use");
3102     cmd_AddParmAtOffset(ts, OPT_dynrootsparse, "-dynroot-sparse", CMD_FLAG,
3103                         CMD_OPTIONAL,
3104                         "Enable dynroot support with minimal cell list");
3105     cmd_AddParmAtOffset(ts, OPT_rxmaxfrags, "-rxmaxfrags", CMD_SINGLE,
3106                         CMD_OPTIONAL,
3107                         "Set the maximum number of UDP fragments Rx should "
3108                         "send/receive per Rx packet");
3109     cmd_AddParmAtOffset(ts, OPT_inumcalc, "-inumcalc", CMD_SINGLE, CMD_OPTIONAL,
3110                         "Set inode number calculation method");
3111     cmd_AddParmAtOffset(ts, OPT_volume_ttl, "-volume-ttl", CMD_SINGLE,
3112                         CMD_OPTIONAL,
3113                         "Set the vldb cache timeout value in seconds.");
3114 }
3115
3116 /**
3117  * Parse and check the command line options.
3118  *
3119  * @note The -shutdown command is handled in CheckOptions().
3120  */
3121 int
3122 afsd_parse(int argc, char **argv)
3123 {
3124     struct cmd_syndesc *ts = NULL;
3125     int code;
3126
3127     code = cmd_Parse(argc, argv, &ts);
3128     if (code) {
3129         return code;
3130     }
3131     code = CheckOptions(ts);
3132     cmd_FreeOptions(&ts);
3133     return code;
3134 }
3135
3136 /**
3137  * entry point for calling a syscall from another proc/thread.
3138  *
3139  * @param[in] rock  a struct afsd_syscall_args* specifying what syscall to call
3140  *
3141  * @return unused
3142  *   @retval NULL always
3143  */
3144 static void *
3145 call_syscall_thread(void *rock)
3146 {
3147     struct afsd_syscall_args *args = rock;
3148     int code;
3149
3150     if (args->rxpri) {
3151         afsd_set_rx_rtpri();
3152     }
3153
3154     code = afsd_call_syscall(args);
3155     if (code && args->syscall == AFSOP_START_CS) {
3156         printf("%s: No check server daemon in client.\n", args->rn);
3157     }
3158
3159     free(args);
3160
3161     return NULL;
3162 }
3163
3164 static void
3165 afsd_syscall_populate(struct afsd_syscall_args *args, int syscall, va_list ap)
3166 {
3167     afsd_syscall_param_t *params;
3168
3169     memset(args, 0, sizeof(struct afsd_syscall_args));
3170
3171     args->syscall = syscall;
3172     params = args->params;
3173
3174     switch (syscall) {
3175     case AFSOP_RXEVENT_DAEMON:
3176     case AFSOP_CLOSEWAIT:
3177     case AFSOP_START_AFS:
3178     case AFSOP_START_CS:
3179     case AFSOP_START_TRUNCDAEMON:
3180         break;
3181     case AFSOP_START_BKG:
3182     case AFSOP_SHUTDOWN:
3183     case AFSOP_SET_RXPCK:
3184     case AFSOP_BASIC_INIT:
3185     case AFSOP_SET_RXMAXFRAGS:
3186     case AFSOP_SET_RXMAXMTU:
3187     case AFSOP_SET_DYNROOT:
3188     case AFSOP_SET_FAKESTAT:
3189     case AFSOP_SET_BACKUPTREE:
3190     case AFSOP_BUCKETPCT:
3191     case AFSOP_GO:
3192     case AFSOP_SET_RMTSYS_FLAG:
3193     case AFSOP_SET_INUMCALC:
3194     case AFSOP_SET_VOLUME_TTL:
3195         params[0] = CAST_SYSCALL_PARAM((va_arg(ap, int)));
3196         break;
3197     case AFSOP_SET_THISCELL:
3198     case AFSOP_ROOTVOLUME:
3199     case AFSOP_VOLUMEINFO:
3200     case AFSOP_CACHEFILE:
3201     case AFSOP_CACHEINFO:
3202     case AFSOP_CACHEINIT:
3203     case AFSOP_CELLINFO:
3204         params[0] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3205         break;
3206     case AFSOP_ADDCELLALIAS:
3207 #ifdef AFS_SOCKPROXY_ENV
3208     case AFSOP_SOCKPROXY_HANDLER:
3209 #endif
3210         params[0] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3211         params[1] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3212         break;
3213     case AFSOP_AFSDB_HANDLER:
3214         params[0] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3215         params[1] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3216         params[2] = CAST_SYSCALL_PARAM((va_arg(ap, int)));
3217         break;
3218     case AFSOP_BKG_HANDLER:
3219         params[0] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3220         params[1] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3221         params[2] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3222         break;
3223     case AFSOP_RXLISTENER_DAEMON:
3224     case AFSOP_START_RXCALLBACK:
3225         params[0] = CAST_SYSCALL_PARAM((va_arg(ap, int)));
3226         params[1] = CAST_SYSCALL_PARAM((va_arg(ap, int)));
3227         params[2] = CAST_SYSCALL_PARAM((va_arg(ap, int)));
3228         break;
3229     case AFSOP_ADVISEADDR:
3230         params[0] = CAST_SYSCALL_PARAM((va_arg(ap, int)));
3231         params[1] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3232         params[2] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3233         params[3] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3234         break;
3235     case AFSOP_ADDCELL2:
3236         params[0] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3237         params[1] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3238         params[2] = CAST_SYSCALL_PARAM((va_arg(ap, afs_int32)));
3239         params[3] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3240         break;
3241     case AFSOP_CACHEINODE:
3242 #if defined AFS_SGI62_ENV
3243         {
3244             afs_int64 tmp = va_arg(ap, afs_int64);
3245             params[0] = CAST_SYSCALL_PARAM((afs_uint32)(tmp >> 32));
3246             params[1] = CAST_SYSCALL_PARAM((afs_uint32)(tmp & 0xffffffff));
3247         }
3248 #else
3249         params[0] = CAST_SYSCALL_PARAM((va_arg(ap, afs_uint32)));
3250 #endif
3251         break;
3252     case AFSOP_SEED_ENTROPY:
3253         params[0] = CAST_SYSCALL_PARAM((va_arg(ap, void *)));
3254         params[1] = CAST_SYSCALL_PARAM((va_arg(ap, afs_uint32)));
3255         break;
3256     default:
3257         printf("Unknown syscall enountered: %d\n", syscall);
3258         opr_Assert(0);
3259     }
3260 }
3261
3262 /**
3263  * common code for calling a syscall in another proc/thread.
3264  *
3265  * @param[in] rx   1 if this is a thread for RX stuff, 0 otherwise
3266  * @param[in] wait 1 if we should wait for the new proc/thread to finish, 0 to
3267  *                 let it run in the background
3268  * @param[in] rn   the name of the running program
3269  * @param[in] syscall syscall to run
3270  */
3271 static void
3272 fork_syscall_impl(int rx, int wait, const char *rn, int syscall, va_list ap)
3273 {
3274     struct afsd_syscall_args *args;
3275
3276     args = malloc(sizeof(*args));
3277     afsd_syscall_populate(args, syscall, ap);
3278     args->rxpri = rx;
3279     args->rn = rn;
3280
3281     afsd_fork(wait, call_syscall_thread, args);
3282 }
3283
3284 /**
3285  * call a syscall in another process or thread.
3286  */
3287 static void
3288 fork_syscall(const char *rn, int syscall, ...)
3289 {
3290     va_list ap;
3291
3292     va_start(ap, syscall);
3293     fork_syscall_impl(0, 0, rn, syscall, ap);
3294     va_end(ap);
3295 }
3296
3297 /**
3298  * call a syscall in another process or thread, and give it RX priority.
3299  */
3300 static void
3301 fork_rx_syscall(const char *rn, int syscall, ...)
3302 {
3303     va_list ap;
3304
3305     va_start(ap, syscall);
3306     fork_syscall_impl(1, 0, rn, syscall, ap);
3307     va_end(ap);
3308 }
3309
3310 #if defined(AFS_SUN510_ENV) && defined(RXK_LISTENER_ENV)
3311 /**
3312  * call a syscall in another process or thread, give it RX priority, and wait
3313  * for it to finish before returning.
3314  */
3315 static void
3316 fork_rx_syscall_wait(const char *rn, int syscall, ...)
3317 {
3318     va_list ap;
3319
3320     va_start(ap, syscall);
3321     fork_syscall_impl(1, 1, rn, syscall, ap);
3322     va_end(ap);
3323 }
3324 #endif /* AFS_SUN510_ENV && RXK_LISTENER_ENV */
3325
3326 static int
3327 afsd_syscall(int syscall, ...)
3328 {
3329     va_list ap;
3330     struct afsd_syscall_args args;
3331
3332     va_start(ap, syscall);
3333     afsd_syscall_populate(&args, syscall, ap);
3334     va_end(ap);
3335
3336     return afsd_call_syscall(&args);
3337 }