2 * Copyright 2000, International Business Machines Corporation and others.
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
10 /* viced.c - File Server main loop */
14 /* Function - This routine has the initialization code for */
17 /* ********************************************************************** */
19 #include <afsconfig.h>
20 #include <afs/param.h>
27 #include <sys/types.h>
28 #include <afs/procmgmt.h> /* signal(), kill(), wait(), etc. */
34 #include <WINNT/afsevent.h>
37 #include <netinet/in.h>
39 #include <unistd.h> /* sysconf() */
51 #endif /* ITIMER_REAL */
52 #include <sys/resource.h>
53 #endif /* AFS_NT40_ENV */
58 #ifdef AFS_PTHREAD_ENV
60 #else /* AFS_PTHREAD_ENV */
61 #include <afs/assert.h>
62 #endif /* AFS_PTHREAD_ENV */
65 #include <afs/ptclient.h>
66 #include <afs/afsint.h>
67 #include <afs/vldbint.h>
68 #include <afs/errors.h>
69 #include <afs/ihandle.h>
70 #include <afs/vnode.h>
71 #include <afs/volume.h>
73 #include <afs/cellconfig.h>
75 #include <afs/prs_fs.h>
79 #include <afs/afs_args.h>
80 #include <afs/vlserver.h>
81 #include <afs/afsutil.h>
82 #include <afs/fileutil.h>
84 #include <afs/netutils.h>
88 #if defined(AFS_SGI_ENV)
89 #include "sys/schedctl.h"
92 #include <rx/rx_globals.h>
95 extern int BreakVolumeCallBacks(), InitCallBack();
96 extern int LogLevel, etext;
97 extern afs_int32 BlocksSpare, PctSpare;
100 static void ClearXStatValues(), NewParms(), PrintCounters();
101 static void ResetCheckDescriptors(void), ResetCheckSignal(void);
102 static void CheckSignal(void);
103 extern int GetKeysFromToken();
104 extern int RXAFS_ExecuteRequest();
105 extern int RXSTATS_ExecuteRequest();
107 int eventlog = 0, rxlog = 0;
109 FILE * console = NULL;
112 #define AFS_QUIETFS_ENV 1
113 #define NT_OPEN_MAX 1024 /* This is an arbitrary no. we came up with for
114 * now. We hope this will be replaced by a more
115 * intelligent estimate later. */
118 int SystemId; /* ViceID of "Administrators"*/
119 int SystemAnyUser; /* Viceid of "System:AnyUser" */
120 prlist SystemAnyUserCPS; /* CPS for "system:AnyUser */
121 int AnonymousID = 0; /* ViceId of "Anonymous"*/
122 prlist AnonCPS; /* CPS for "Anonymous"*/
124 struct afsconf_dir *confDir; /* Configuration dir object */
126 int restartMode = RESTART_ORDINARY;
128 int Testing = 0; /* for ListViceInodes */
131 * Home for the performance statistics.
133 struct afs_PerfStats afs_perfstats;
136 extern int Statistics;
143 int rxJumbograms = 1; /* default is to send and receive jumbograms. */
144 afs_int32 implicitAdminRights = PRSFS_LOOKUP; /* The ADMINISTER right is
146 afs_int32 readonlyServer = 0;
149 int stackSize = 24000;
150 int fiveminutes = 300; /* 5 minutes. Change this for debugging only */
151 int CurrentConnections = 0;
152 int hostaclRefresh = 7200; /* refresh host clients' acls every 2 hrs */
153 #if defined(AFS_SGI_ENV)
158 int rxpackets = 150; /* 100 */
159 int nSmallVns = 400; /* 200 */
160 int large = 400; /* 200 */
161 int volcache = 400; /* 400 */
162 int numberofcbs = 60000; /* 60000 */
163 int lwps = 9; /* 6 */
164 int buffs = 90; /* 70 */
165 int novbc = 0; /* Enable Volume Break calls */
166 int busy_threshold = 600;
167 int udpBufSize = 0; /* UDP buffer size for receive*/
172 * FileServer's name and IP address, both network byte order and
175 #define ADDRSPERSITE 16 /* Same global is in rx/rx_user.c */
177 char FS_HostName[128] = "localhost";
178 afs_uint32 FS_HostAddr_NBO;
179 afs_uint32 FS_HostAddr_HBO;
180 afs_uint32 FS_HostAddrs[ADDRSPERSITE], FS_HostAddr_cnt = 0, FS_registered=0;
181 /* All addresses in FS_HostAddrs are in NBO */
184 static void FlagMsg();
187 * Home for the performance statistics.
191 static void CheckDescriptors()
195 register int tsize = getdtablesize();
197 for (i = 0; i<tsize; i++) {
198 if (fstat(i, &status) != -1) {
199 printf("%d: dev %x, inode %u, length %u, type/mode %x\n",
200 i, status.st_dev, status.st_ino,
201 status.st_size, status.st_mode);
205 ResetCheckDescriptors();
207 } /*CheckDescriptors*/
210 #ifdef AFS_PTHREAD_ENV
211 void CheckSignal_Signal(x) {CheckSignal();}
212 void ShutDown_Signal(x) {ShutDown();}
213 void CheckDescriptors_Signal(x) {CheckDescriptors();}
214 #else /* AFS_PTHREAD_ENV */
215 void CheckSignal_Signal(x) {IOMGR_SoftSig(CheckSignal, 0);}
216 void ShutDown_Signal(x) {IOMGR_SoftSig(ShutDown, 0);}
217 void CheckDescriptors_Signal(x) {IOMGR_SoftSig(CheckDescriptors, 0);}
218 #endif /* AFS_PTHREAD_ENV */
220 /* check whether caller is authorized to manage RX statistics */
221 int fs_rxstat_userok(struct rx_call *call)
223 return afsconf_SuperUser(confDir, call, NULL);
226 static void ResetCheckSignal(void)
229 signal(SIGPOLL, CheckSignal_Signal);
232 signal(SIGUSR2, CheckSignal_Signal);
234 signal(SIGXCPU, CheckSignal_Signal);
239 static void ResetCheckDescriptors(void)
242 signal(SIGTERM, CheckDescriptors_Signal);
247 /* proc called by rxkad module to get a key */
248 static int get_key(char *arock, register afs_int32 akvno, char *akey)
251 static struct afsconf_key tkey;
252 register afs_int32 code;
255 ViceLog(0, ("conf dir not open\n"));
258 code = afsconf_GetKey(confDir, akvno, tkey.key);
261 memcpy(akey, tkey.key, sizeof(tkey.key));
267 int viced_syscall(afs_uint32 a3, afs_uint32 a4, void * a5)
272 #ifndef AFS_LINUX20_ENV
273 old = (void (*)())signal(SIGSYS, SIG_IGN);
275 rcode = syscall (AFS_SYSCALL, 28 /* AFSCALL_CALL */, a3, a4, a5);
276 #ifndef AFS_LINUX20_ENV
284 #if !defined(AFS_NT40_ENV)
285 #include "AFS_component_version_number.c"
286 #endif /* !AFS_NT40_ENV */
288 #define MAXADMINNAME 64
289 char adminName[MAXADMINNAME];
297 if ((stat("/AdminName", &status)) || /* if file does not exist */
298 (status.st_size <= 0) || /* or it is too short */
299 (status.st_size >= (MAXADMINNAME)) || /* or it is too long */
300 !(fd = open("/AdminName", O_RDONLY, 0))) { /* or the open fails */
301 strcpy(adminName, "System:Administrators"); /* use the default name */
304 read(fd, adminName, status.st_size); /* use name from the file */
307 close(fd); /* close fd if it was opened */
312 /* This LWP does things roughly every 5 minutes */
313 static void FiveMinuteCheckLWP()
318 ViceLog(1, ("Starting five minute check process\n"));
320 #ifdef AFS_PTHREAD_ENV
322 #else /* AFS_PTHREAD_ENV */
323 IOMGR_Sleep(fiveminutes);
324 #endif /* AFS_PTHREAD_ENV */
326 /* close the log so it can be removed */
327 ReOpenLog(AFSDIR_SERVER_FILELOG_FILEPATH); /* don't trunc, just append */
328 ViceLog(2, ("Cleaning up timed out callbacks\n"));
329 if(CleanupTimedOutCallBacks())
330 ViceLog(5,("Timed out callbacks deleted\n"));
331 ViceLog(2, ("Set disk usage statistics\n"));
333 if (FS_registered == 1) Do_VLRegisterRPC();
334 if(printBanner && (++msg&1)) { /* Every 10 minutes */
335 time_t now = FT_ApproxTime();
336 if (console != NULL) {
337 #ifndef AFS_QUIETFS_ENV
338 fprintf(console,"File server is running at %s\r",
339 afs_ctime(&now, tbuffer, sizeof(tbuffer)));
340 #endif /* AFS_QUIETFS_ENV */
341 ViceLog(2, ("File server is running at %s\n",
342 afs_ctime(&now, tbuffer, sizeof(tbuffer))));
346 } /*FiveMinuteCheckLWP*/
349 /* This LWP does host checks every 5 minutes: it should not be used for
350 * other 5 minute activities because it may be delayed by timeouts when
351 * it probes the workstations
353 static void HostCheckLWP()
355 ViceLog(1, ("Starting Host check process\n"));
357 #ifdef AFS_PTHREAD_ENV
359 #else /* AFS_PTHREAD_ENV */
360 IOMGR_Sleep(fiveminutes);
361 #endif /* AFS_PTHREAD_ENV */
362 ViceLog(2, ("Checking for dead venii & clients\n"));
368 /*------------------------------------------------------------------------
369 * PRIVATE ClearXStatValues
372 * Initialize all of the values collected via the xstat
382 * Must be called during File Server initialization.
386 *------------------------------------------------------------------------*/
388 static void ClearXStatValues()
389 { /*ClearXStatValues*/
391 struct fs_stats_opTimingData *opTimeP; /*Ptr to timing struct*/
392 struct fs_stats_xferData *opXferP; /*Ptr to xfer struct*/
393 int i; /*Loop counter*/
396 * Zero all xstat-related structures.
398 memset((char *)(&afs_perfstats), 0, sizeof(struct afs_PerfStats));
399 #if FS_STATS_DETAILED
400 memset((char *)(&afs_FullPerfStats), 0, sizeof(struct fs_stats_FullPerfStats));
403 * That's not enough. We have to set reasonable minima for
404 * time and xfer values in the detailed stats.
406 opTimeP = &(afs_FullPerfStats.det.rpcOpTimes[0]);
407 for (i = 0; i < FS_STATS_NUM_RPC_OPS; i++, opTimeP++)
408 opTimeP->minTime.tv_sec = 999999;
410 opXferP = &(afs_FullPerfStats.det.xferOpTimes[0]);
411 for (i = 0; i < FS_STATS_NUM_XFER_OPS; i++, opXferP++) {
412 opXferP->minTime.tv_sec = 999999;
413 opXferP->minBytes = 999999999;
417 * There's more. We have to set our unique system identifier, as
418 * declared in param.h. If such a thing is not defined, we bitch
419 * and declare ourselves to be an unknown system type.
422 afs_perfstats.sysname_ID = SYS_NAME_ID;
425 ViceLog(0, ("Sys name ID constant not defined in param.h!!\n"));
426 ViceLog(0, ("[Choosing ``undefined'' sys name ID.\n"));
428 afs_perfstats.sysname_ID = SYS_NAME_ID_UNDEFINED;
429 #endif /* SYS_NAME_ID */
432 } /*ClearXStatValues*/
435 static void PrintCounters()
437 int dirbuff, dircall, dirio;
439 int workstations, activeworkstations, delworkstations;
443 TM_GetTimeOfDay(&tpl, 0);
445 ViceLog(0, ("Vice was last started at %s\n",
446 afs_ctime(&StartTime, tbuffer, sizeof(tbuffer))));
450 DStat(&dirbuff, &dircall, &dirio);
451 ViceLog(0,("With %d directory buffers; %d reads resulted in %d read I/Os\n",
452 dirbuff, dircall, dirio));
453 rx_PrintStats(stderr);
455 PrintCallBackStats();
457 processSize = -1; /* TODO: */
459 processSize = (int)((long) sbrk(0) >> 10);
461 ViceLog(0,("There are %d connections, process size %d\n", CurrentConnections, processSize));
462 h_GetWorkStats(&workstations, &activeworkstations, &delworkstations,
465 ("There are %d workstations, %d are active (req in < 15 mins), %d marked \"down\"\n",
466 workstations, activeworkstations, delworkstations));
473 static void CheckSignal()
475 if (FS_registered > 0) {
477 * We have proper ip addresses; tell the vlserver what we got; the following
478 * routine will do the proper reporting for us
490 void ShutDownAndCore(int dopanic)
492 time_t now = time(0);
496 ViceLog(0, ("Shutting down file server at %s",
497 afs_ctime(&now, tbuffer, sizeof(tbuffer))));
499 ViceLog(0, ("ABNORMAL SHUTDOWN, see core file.\n"));
500 #ifndef AFS_QUIETFS_ENV
501 if (console != NULL) {
502 fprintf(console,"File server restart/shutdown received at %s\r",
503 afs_ctime(&now, tbuffer, sizeof(tbuffer)));
509 /* do not allows new reqests to be served from now on, all new requests
510 are returned with an error code of RX_RESTARTING ( transient failure ) */
511 rx_SetRxTranquil(); /* dhruba */
515 rx_PrintStats(debugFile);
518 if (console != NULL) {
521 #ifndef AFS_QUIETFS_ENV
522 fprintf(console, "File server has terminated abnormally at %s\r",
523 afs_ctime(&now, tbuffer, sizeof(tbuffer)));
525 ViceLog(0, ("File server has terminated abnormally at %s\n",
526 afs_ctime(&now, tbuffer, sizeof(tbuffer))));
528 #ifndef AFS_QUIETFS_ENV
529 fprintf(console, "File server has terminated normally at %s\r",
530 afs_ctime(&now, tbuffer, sizeof(tbuffer)));
532 ViceLog(0, ("File server has terminated normally at %s\n",
533 afs_ctime(&now, tbuffer, sizeof(tbuffer))));
541 void ShutDown(void) /* backward compatibility */
543 ShutDownAndCore(DONTPANIC);
547 static void FlagMsg()
551 /* default supports help flag */
553 strcpy(buffer, "Usage: fileserver ");
554 strcat(buffer, "[-d <debug level>] ");
555 strcat(buffer, "[-p <number of processes>] ");
556 strcat(buffer, "[-spare <number of spare blocks>] ");
557 strcat(buffer, "[-pctspare <percentage spare>] ");
558 strcat(buffer, "[-b <buffers>] ");
559 strcat(buffer, "[-l <large vnodes>] ");
560 strcat(buffer, "[-s <small vnodes>] ");
561 strcat(buffer, "[-vc <volume cachesize>] ");
562 strcat(buffer, "[-w <call back wait interval>] ");
563 strcat(buffer, "[-cb <number of call backs>] ");
564 strcat(buffer, "[-banner (print banner every 10 minutes)] ");
565 strcat(buffer, "[-novbc (whole volume cbs disabled)] ");
566 strcat(buffer, "[-implicit <admin mode bits: rlidwka>] ");
567 strcat(buffer, "[-readonly (read-only file server)] ");
568 strcat(buffer, "[-hr <number of hours between refreshing the host cps>] ");
569 strcat(buffer, "[-busyat <redirect clients when queue > n>] ");
570 strcat(buffer, "[-rxpck <number of rx extra packets>] ");
571 strcat(buffer, "[-rxdbg (enable rx debugging)] ");
572 strcat(buffer, "[-rxdbge (enable rxevent debugging)] ");
574 strcat(buffer, "[-m <min percentage spare in partition>] ");
576 #if defined(AFS_SGI_ENV)
577 strcat(buffer, "[-lock (keep fileserver from swapping)] ");
579 strcat(buffer, "[-L (large server conf)] ");
580 strcat(buffer, "[-S (small server conf)] ");
581 strcat(buffer, "[-k <stack size>] ");
582 strcat(buffer, "[-realm <Kerberos realm name>] ");
583 strcat(buffer, "[-udpsize <size of socket buffer in bytes>] ");
584 /* strcat(buffer, "[-enable_peer_stats] "); */
585 /* strcat(buffer, "[-enable_process_stats] "); */
586 strcat(buffer, "[-help]\n");
588 ViceLog(0, ("%s", buffer));
597 static afs_int32 ParseRights(char *arights)
603 if (!arights || !strcmp(arights, "")) {
604 printf("Missing list of mode bits on -implicit option\n");
607 if (!strcmp(arights, "none"))
609 else if (!strcmp(arights, "read"))
610 mode = PRSFS_READ | PRSFS_LOOKUP;
611 else if (!strcmp(arights, "write"))
612 mode = PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT |
613 PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK;
614 else if (!strcmp(arights, "all"))
615 mode = PRSFS_READ | PRSFS_LOOKUP | PRSFS_INSERT |
616 PRSFS_DELETE | PRSFS_WRITE | PRSFS_LOCK | PRSFS_ADMINISTER;
618 len = strlen(arights);
621 if (tc == 'r') mode |= PRSFS_READ;
622 else if (tc == 'l') mode |= PRSFS_LOOKUP;
623 else if (tc == 'i') mode |= PRSFS_INSERT;
624 else if (tc == 'd') mode |= PRSFS_DELETE;
625 else if (tc == 'w') mode |= PRSFS_WRITE;
626 else if (tc == 'k') mode |= PRSFS_LOCK;
627 else if (tc == 'a') mode |= PRSFS_ADMINISTER;
628 else if (tc == 'A') mode |= PRSFS_USR0;
629 else if (tc == 'B') mode |= PRSFS_USR1;
630 else if (tc == 'C') mode |= PRSFS_USR2;
631 else if (tc == 'D') mode |= PRSFS_USR3;
632 else if (tc == 'E') mode |= PRSFS_USR4;
633 else if (tc == 'F') mode |= PRSFS_USR5;
634 else if (tc == 'G') mode |= PRSFS_USR6;
635 else if (tc == 'H') mode |= PRSFS_USR7;
637 printf("Illegal -implicit rights character '%c'.\n", tc);
646 * Limit MAX_FILESERVER_THREAD by the system limit on the number of
647 * pthreads (sysconf(_SC_THREAD_THREADS_MAX)), if applicable and
650 * AIX: sysconf() limit is real
651 * HP-UX: sysconf() limit is real
652 * IRIX: sysconf() limit is apparently NOT real -- too small
653 * DUX: sysconf() limit is apparently NOT real -- too big
654 * Linux: sysconf() limit is apparently NOT real -- too big
655 * Solaris: no sysconf() limit
658 max_fileserver_thread(void)
660 #if defined(AFS_PTHREAD_ENV)
661 #if defined(AFS_AIX_ENV) || defined(AFS_HPUX_ENV)
664 ans = sysconf(_SC_THREAD_THREADS_MAX);
665 if (0 < ans && ans < MAX_FILESERVER_THREAD)
668 #endif /* defined(AFS_PTHREAD_ENV) */
669 return MAX_FILESERVER_THREAD;
672 static int ParseArgs(int argc, char *argv[])
674 int SawL=0, SawS=0, SawVC=0;
675 int Sawrxpck = 0, Sawsmall=0, Sawlarge=0, Sawcbs=0, Sawlwps=0, Sawbufs=0;
678 int bufSize = 0; /* temp variable to read in udp socket buf size*/
680 for (i = 1; i < argc; i++) {
681 if (!strcmp(argv[i], "-d")) {
682 debuglevel = atoi(argv[++i]);
683 LogLevel = debuglevel;
686 if (!strcmp(argv[i], "-banner")) {
689 if (!strcmp(argv[i], "-implicit")) {
690 implicitAdminRights = ParseRights(argv[++i]);
691 if (implicitAdminRights < 0) return implicitAdminRights;
693 if (!strcmp(argv[i], "-readonly")) {
696 if (!strcmp(argv[i], "-L")) {
699 if (!strcmp(argv[i], "-S")) {
703 if (!strcmp(argv[i], "-p")) {
704 int lwps_max = max_fileserver_thread() - FILESERVER_HELPER_THREADS;
706 lwps = atoi(argv[++i]);
713 if (!strcmp(argv[i], "-b")) {
715 buffs = atoi(argv[++i]);
718 if (!strcmp(argv[i], "-l")) {
720 large = atoi(argv[++i]);
723 if (!strcmp(argv[i], "-vc")) {
725 volcache = atoi(argv[++i]);
728 if (!strcmp(argv[i], "-novbc")) {
732 if (!strcmp(argv[i], "-rxpck")) {
734 rxpackets = atoi(argv[++i]);
737 if (!strcmp(argv[i], "-s")) {
739 nSmallVns = atoi(argv[++i]);
742 if (!strcmp(argv[i], "-k"))
743 stack = atoi(argv[++i]);
744 #if defined(AFS_SGI_ENV)
746 if (!strcmp(argv[i], "-lock")) {
751 if (!strcmp(argv[i], "-spare")) {
752 BlocksSpare = atoi(argv[++i]);
756 if (!strcmp(argv[i], "-pctspare")) {
757 PctSpare = atoi(argv[++i]);
758 BlocksSpare = 0; /* has non-zero default */
762 if (!strcmp(argv[i], "-w"))
763 fiveminutes = atoi(argv[++i]);
765 if (!strcmp(argv[i], "-hr")) {
766 int hr = atoi(argv[++i]);
767 if ((hr < 1) || (hr > 36)) {
768 printf("host acl refresh interval of %d hours is invalid; hours must be between 1 and 36\n\n",
772 hostaclRefresh = hr*60*60;
774 if (!strcmp(argv[i], "-rxdbg"))
777 if (!strcmp(argv[i], "-rxdbge"))
780 if (!strcmp(argv[i], "-cb")) {
782 numberofcbs = atoi(argv[++i]);
783 if ((numberofcbs < 10000) || (numberofcbs > 2147483647)) {
784 printf("number of cbs %d invalid; must be between 10000 and 2147483647\n",
790 if (!strcmp(argv[i], "-busyat")) {
792 busy_threshold = atoi(argv[++i]);
793 if (busy_threshold < 10) {
794 printf("Busy threshold %d is too low, will compute default.\n",
801 if (!strcmp(argv[i], "-m")) {
802 extern int aixlow_water;
803 aixlow_water = atoi(argv[++i]);
804 if ((aixlow_water < 0) || (aixlow_water > 30)) {
805 printf("space reserved %d% invalid; must be between 0-30%\n", aixlow_water);
811 if (!strcmp(argv[i], "-nojumbo")) {
815 if (!strcmp(argv[i], "-realm")) {
816 extern char local_realm[AFS_REALM_SZ];
817 if (strlen(argv[++i]) >= AFS_REALM_SZ) {
818 printf("-realm argument must contain fewer than %d characters.\n",AFS_REALM_SZ);
821 strncpy (local_realm, argv[i], AFS_REALM_SZ);
824 if ( !strcmp(argv[i], "-udpsize")) {
825 if ( (i+1) >= argc ) {
826 printf("You have to specify -udpsize <integer value>\n");
829 bufSize = atoi(argv[++i]);
830 if ( bufSize < rx_GetMinUdpBufSize() )
831 printf("Warning:udpsize %d is less than minimum %d; ignoring\n",
832 bufSize, rx_GetMinUdpBufSize() );
834 udpBufSize = bufSize;
837 if (!strcmp(argv[i], "-enable_peer_stats")) {
838 rx_enablePeerRPCStats();
841 if (!strcmp(argv[i], "-enable_process_stats")) {
842 rx_enableProcessRPCStats();
846 if (strcmp(argv[i], "-syslog")==0) {
847 /* set syslog logging flag */
851 if (strncmp(argv[i], "-syslog=", 8)==0) {
853 serverLogSyslogFacility = atoi(argv[i]+8);
861 printf("Only one of -L, or -S must be specified\n");
865 if (!Sawrxpck) rxpackets = 100;
866 if (!Sawsmall) nSmallVns = 200;
867 if (!Sawlarge) large = 200;
868 if (!Sawcbs) numberofcbs = 20000;
869 if (!Sawlwps) lwps = 6;
870 if (!Sawbufs) buffs = 70;
871 if (!SawVC) volcache = 200;
874 if (!Sawrxpck) rxpackets = 200;
875 if (!Sawsmall) nSmallVns = 600;
876 if (!Sawlarge) large = 600;
877 if (!Sawcbs) numberofcbs = 64000;
878 if (!Sawlwps) lwps = 12;
879 if (!Sawbufs) buffs = 120;
880 if (!SawVC) volcache = 600;
883 busy_threshold = 3*rxpackets/2;
892 static void NewParms(int initializing)
894 static struct stat sbuf;
897 char *argv[MAXPARMS];
900 if (!(stat("/vice/file/parms",&sbuf))) {
901 parms = (char *)malloc(sbuf.st_size);
903 fd = open("parms", O_RDONLY, 0666);
905 ViceLog(0, ("Open for parms failed with errno = %d\n", errno));
909 i = read(fd, parms, sbuf.st_size);
911 if(i != sbuf.st_size) {
913 ViceLog(0, ("Read on parms failed with errno = %d\n", errno));
916 ("Read on parms failed; expected %d bytes but read %d\n",
923 for (i = 0;i < MAXPARMS; argv[i++] = 0 );
925 for (argc = i = 0; i < sbuf.st_size; i++) {
926 if ((*(parms + i) != ' ') && (*(parms + i) != '\n')){
927 if(argv[argc] == 0) argv[argc] = (parms+i);
931 if(argv[argc] != 0) {
932 if(++argc == MAXPARMS) break;
934 while ((*(parms + i + 1) == ' ') || (*(parms + i + 1) == '\n'))
938 if(ParseArgs(argc, argv) == 0) {
939 ViceLog(0, ("Change parameters to:"));
941 ViceLog(0, ("Invalid parameter in:"));
943 for(i = 0; i < argc; i++) {
944 ViceLog(0, (" %s", argv[i]));
951 ViceLog(0, ("Received request to change parms but no parms file exists\n"));
956 /* Miscellaneous routines */
959 ViceLog (0,("%s\n", msg));
970 * If this fails, it's because something major is wrong, and is not
971 * likely to be time dependent.
973 code = pr_Initialize(2, AFSDIR_SERVER_ETC_DIRPATH, 0);
975 ViceLog(0, ("Couldn't initialize protection library; code=%d.\n", code));
978 SystemId = SYSADMINID;
979 SystemAnyUser = ANYUSERID;
980 SystemAnyUserCPS.prlist_len = 0;
981 SystemAnyUserCPS.prlist_val = NULL;
982 AnonCPS.prlist_len = 0;
983 AnonCPS.prlist_val = NULL;
985 code = pr_GetCPS(SystemAnyUser, &SystemAnyUserCPS);
988 ("Couldn't get CPS for AnyUser, will try again in 30 seconds; code=%d.\n",
992 code = pr_GetCPS(ANONYMOUSID,&AnonCPS);
994 ViceLog(0,("Couldn't get Anonymous CPS, exiting; code=%d.\n", code));
997 AnonymousID = ANONYMOUSID;
1000 #ifdef AFS_PTHREAD_ENV
1002 #else /* AFS_PTHREAD_ENV */
1004 #endif /* AFS_PTHREAD_ENV */
1008 struct rx_connection *serverconns[MAXSERVERS];
1009 struct ubik_client *cstruct;
1011 afs_int32 vl_Initialize(char *confDir)
1012 { afs_int32 code, scIndex = 0, i;
1013 struct afsconf_dir *tdir;
1014 struct rx_securityClass *sc;
1015 struct afsconf_cell info;
1017 tdir = afsconf_Open(confDir);
1019 ViceLog(0, ("Could not open configuration directory (%s).\n", confDir));
1022 code = afsconf_ClientAuth(tdir, &sc, &scIndex);
1024 ViceLog(0, ("Could not get security object for localAuth\n"));
1027 code = afsconf_GetCellInfo(tdir,NULL, AFSCONF_VLDBSERVICE, &info);
1028 if (info.numServers > MAXSERVERS) {
1029 ViceLog(0, ("vl_Initialize: info.numServers=%d (> MAXSERVERS=%d)\n",info.numServers, MAXSERVERS));
1032 for (i = 0;i<info.numServers;i++)
1033 serverconns[i] = rx_NewConnection(info.hostAddr[i].sin_addr.s_addr, info.hostAddr[i].sin_port,
1034 USER_SERVICE_ID, sc, scIndex);
1035 code = ubik_ClientInit(serverconns, &cstruct);
1037 ViceLog(0, ("vl_Initialize: ubik client init failed.\n"));
1043 #define SYSIDMAGIC 0x88aabbcc
1044 #define SYSIDVERSION 1
1048 afs_int32 fd, nentries, i;
1049 struct versionStamp vsn;
1053 if ((stat(AFSDIR_SERVER_SYSID_FILEPATH, &status)) || (status.st_size <= 0)) {
1054 ViceLog(0, ("%s: doesn't exist\n", AFSDIR_SERVER_SYSID_FILEPATH));
1057 if (!(fd = open(AFSDIR_SERVER_SYSID_FILEPATH, O_RDONLY, 0))) {
1058 ViceLog(0, ("%s: can't open (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno));
1061 if ((i = read(fd, (char *)&vsn, sizeof(vsn))) != sizeof(vsn)) {
1062 ViceLog(0, ("%s: Read failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno));
1065 if (vsn.magic != SYSIDMAGIC) {
1066 ViceLog(0, ("%s: wrong magic %x (we support %x)\n", AFSDIR_SERVER_SYSID_FILEPATH, vsn.magic, SYSIDMAGIC));
1069 if (vsn.version != SYSIDVERSION) {
1070 ViceLog(0, ("%s: wrong version %d (we support %d)\n", AFSDIR_SERVER_SYSID_FILEPATH, vsn.version, SYSIDVERSION));
1073 if ((i = read(fd, (char *)&uuid, sizeof(struct afsUUID))) != sizeof(struct afsUUID)) {
1074 ViceLog(0, ("%s: read of uuid failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno));
1077 afs_ntohuuid(&uuid);
1079 if ((i = read(fd, (char *)&nentries, sizeof(afs_int32))) != sizeof(afs_int32)) {
1080 ViceLog(0, ("%s: Read of entries failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno));
1083 if (nentries <= 0 || nentries > ADDRSPERSITE) {
1084 ViceLog(0, ("%s: invalid num of interfaces: %d\n", AFSDIR_SERVER_SYSID_FILEPATH, nentries));
1087 FS_HostAddr_cnt = nentries;
1088 for (i = 0; i < nentries; i++) {
1089 if (read(fd, (char *)&FS_HostAddrs[i], sizeof(afs_int32)) != sizeof(afs_int32)) {
1090 ViceLog(0, ("%s: Read of addresses failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno));
1091 FS_HostAddr_cnt = 0; /* reset it */
1101 afs_int32 fd, nentries, i;
1102 struct versionStamp vsn;
1106 if (!stat(AFSDIR_SERVER_SYSID_FILEPATH, &status)) {
1108 * File exists; keep the old one around
1110 renamefile(AFSDIR_SERVER_SYSID_FILEPATH, AFSDIR_SERVER_OLDSYSID_FILEPATH);
1112 fd = open(AFSDIR_SERVER_SYSID_FILEPATH, O_WRONLY|O_TRUNC|O_CREAT, 0666);
1114 ViceLog(0, ("%s: can't create (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno));
1117 vsn.magic = SYSIDMAGIC;
1119 if ((i = write(fd, (char *)&vsn, sizeof(vsn))) != sizeof(vsn)) {
1120 ViceLog(0, ("%s: write failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno));
1124 afs_htonuuid(&uuid);
1125 if ((i = write(fd, (char *)&uuid, sizeof(struct afsUUID))) != sizeof(struct afsUUID)) {
1126 ViceLog(0, ("%s: write of uuid failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno));
1129 if ((i = write(fd, (char *)&FS_HostAddr_cnt, sizeof(afs_int32))) != sizeof(afs_int32)) {
1130 ViceLog(0, ("%s: write of # of entries failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno));
1133 for (i = 0; i < FS_HostAddr_cnt; i++) {
1134 if (write(fd, (char *)&FS_HostAddrs[i], sizeof(afs_int32)) != sizeof(afs_int32)) {
1135 ViceLog(0, ("%s: write of addresses failed (%d)\n", AFSDIR_SERVER_SYSID_FILEPATH, errno));
1145 * This routine sets up the buffers for the VL_RegisterAddrs RPC. All addresses
1146 * in FS_HostAddrs[] are in NBO, while the RPC treats them as a "blob" of data
1147 * and so we need to convert each of them into HBO which is what the extra
1148 * array called FS_HostAddrs_HBO is used here.
1151 Do_VLRegisterRPC() {
1154 extern int VL_RegisterAddrs();
1155 afs_uint32 FS_HostAddrs_HBO[ADDRSPERSITE];
1158 for (i=0; i < FS_HostAddr_cnt ; i++)
1159 FS_HostAddrs_HBO[i]=ntohl(FS_HostAddrs[i]);
1160 addrs.bulkaddrs_len = FS_HostAddr_cnt;
1161 addrs.bulkaddrs_val = (afs_uint32 *)FS_HostAddrs_HBO;
1162 code = ubik_Call(VL_RegisterAddrs, cstruct, 0, &FS_HostUUID, 0, &addrs);
1164 if (code == VL_MULTIPADDR) {
1165 ViceLog(0, ("VL_RegisterAddrs rpc failed; The ethernet address exist on a different server; repair it\n"));
1166 ViceLog(0, ("VL_RegisterAddrs rpc failed; See VLLog for details\n"));
1168 } else if (code == RXGEN_OPCODE) {
1169 ViceLog(0, ("vlserver doesn't support VL_RegisterAddrs rpc; ignored\n"));
1170 FS_registered = 2; /* So we don't have to retry in the gc daemon */
1172 ViceLog(0, ("VL_RegisterAddrs rpc failed; will retry periodically (code=%d, err=%d)\n",
1176 FS_registered = 2; /* So we don't have to retry in the gc daemon */
1184 static int AddrsEqual(cnt, addr1, addr2)
1186 afs_int32 *addr1, *addr2;
1190 for (i = 0; i < cnt; i++) {
1191 for (j = 0; j < cnt; j++) {
1192 if (addr1[i] == addr2[j]) break;
1194 if (j == cnt) return 0;
1205 extern int rxi_numNetAddrs;
1206 extern afs_uint32 rxi_NetAddrs[];
1209 * If this fails, it's because something major is wrong, and is not
1210 * likely to be time dependent.
1212 code = vl_Initialize(AFSDIR_SERVER_ETC_DIRPATH);
1214 ViceLog(0, ("Couldn't initialize protection library; code=%d.\n", code));
1218 /* Read or create the sysid file and register the fileserver's
1219 * IP addresses with the vlserver.
1221 code = ReadSysIdFile();
1223 /* Need to create the file */
1224 ViceLog(0, ("Creating new SysID file\n"));
1225 if ((code = afs_uuid_create(&FS_HostUUID))) {
1226 ViceLog(0, ("Failed to create new uuid: %d\n", code));
1230 /* A good sysid file exists; inform the vlserver. If any conflicts,
1231 * we always use the latest interface available as the real truth.
1233 #ifndef AFS_NT40_ENV
1234 if(AFSDIR_SERVER_NETRESTRICT_FILEPATH || AFSDIR_SERVER_NETINFO_FILEPATH) {
1236 * Find addresses we are supposed to register as per the netrestrict
1237 * and netinfo files (/usr/afs/local/NetInfo and
1238 * /usr/afs/local/NetRestict)
1241 afs_int32 code = parseNetFiles(FS_HostAddrs,NULL, NULL,
1242 ADDRSPERSITE, reason,
1243 AFSDIR_SERVER_NETINFO_FILEPATH,
1244 AFSDIR_SERVER_NETRESTRICT_FILEPATH);
1246 ViceLog(0,("Can't register any valid addresses: %s\n",reason));
1249 FS_HostAddr_cnt = (afs_uint32) code;
1254 FS_HostAddr_cnt = rx_getAllAddr(FS_HostAddrs, ADDRSPERSITE);
1258 code = Do_VLRegisterRPC();
1263 main(int argc, char * argv[])
1269 struct rx_securityClass *sc[4];
1270 struct rx_service *tservice;
1271 #ifdef AFS_PTHREAD_ENV
1272 pthread_t parentPid, serverPid;
1273 pthread_attr_t tattr;
1275 #else /* AFS_PTHREAD_ENV */
1276 PROCESS parentPid, serverPid;
1277 #endif /* AFS_PTHREAD_ENV */
1279 int minVnodesRequired; /* min size of vnode cache */
1280 #ifndef AFS_NT40_ENV
1281 struct rlimit rlim; /* max number of open file descriptors */
1285 #ifdef AFS_AIX32_ENV
1286 struct sigaction nsa;
1288 sigemptyset(&nsa.sa_mask);
1289 nsa.sa_handler = SIG_DFL;
1290 nsa.sa_flags = SA_FULLDUMP;
1291 sigaction(SIGABRT, &nsa, NULL);
1292 sigaction(SIGSEGV, &nsa, NULL);
1295 /* Initialize dirpaths */
1296 if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
1298 ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0],0);
1300 fprintf(stderr,"%s: Unable to obtain AFS server directory.\n", argv[0]);
1304 #ifndef AFS_QUIETFS_ENV
1305 console = fopen("/dev/console","w");
1308 if(ParseArgs(argc,argv)) {
1313 #ifdef AFS_PTHREAD_ENV
1314 assert(pthread_mutex_init(&fileproc_glock_mutex, NULL) == 0);
1315 #endif /* AFS_PTHREAD_ENV */
1317 #ifdef AFS_SGI_VNODE_GLUE
1318 if (afs_init_kernel_config(-1) <0) {
1319 printf("Can't determine NUMA configuration, not starting fileserver.\n");
1323 confDir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
1325 fprintf(stderr, "Unable to open config directory %s\n",
1326 AFSDIR_SERVER_ETC_DIRPATH);
1332 /* Open FileLog on stdout, stderr, fd 1 and fd2 (for perror), sigh. */
1333 OpenLog(AFSDIR_SERVER_FILELOG_FILEPATH);
1336 if (SawSpare && SawPctSpare) {
1337 ViceLog(0, ("Both -spare and -pctspare specified, exiting.\n"));
1341 #ifdef AFS_SGI_XFS_IOPS_ENV
1342 ViceLog(0, ("XFS/EFS File server starting\n"));
1344 ViceLog(0, ("File server starting\n"));
1347 /* install signal handlers for controlling the fileserver process */
1348 ResetCheckSignal(); /* set CheckSignal_Signal() sig handler */
1349 ResetCheckDescriptors(); /* set CheckDescriptors_Signal() sig handler */
1351 #if defined(AFS_SGI_ENV)
1352 /* give this guy a non-degrading priority so help busy servers */
1353 schedctl(NDPRI, 0, NDPNORMMAX);
1357 #ifndef AFS_NT40_ENV
1358 nice(-5); /* TODO: */
1361 assert(DInit(buffs) == 0);
1364 if (afs_winsockInit()<0) {
1365 ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0);
1366 ViceLog(0, ("File server failed to intialize winsock.\n"));
1372 /* if we support more than 16 threads, then we better have the ability
1373 ** to keep open a large number of files simultaneously
1375 #if defined(AFS_AIX_ENV) && !defined(AFS_AIX42_ENV)
1376 curLimit = OPEN_MAX; /* for pre AIX 4.2 systems */
1377 #elif defined(AFS_NT40_ENV)
1378 curLimit = NT_OPEN_MAX; /* open file descriptor limit on NT */
1381 curLimit = 0; /* the number of open file descriptors */
1382 code = getrlimit(RLIMIT_NOFILE, &rlim);
1384 curLimit = rlim.rlim_cur;
1385 rlim.rlim_cur = rlim.rlim_max;
1386 code = setrlimit(RLIMIT_NOFILE, &rlim);
1388 curLimit = rlim.rlim_max;
1391 ViceLog(0, ("Failed to increase open file limit, using default\n"));
1393 #endif /* defined(AFS_AIX_ENV) && !defined(AFS_AIX42_ENV) */
1395 curLimit -= 32; /* leave a slack of 32 file descriptors */
1396 if ( lwps > curLimit ) {
1399 else if ( lwps > 16 )
1400 lwps = 16; /* default to a maximum of 16 threads */
1401 ViceLog(0, ("The system supports a max of %d open files and we are starting %d threads\n", curLimit, lwps));
1405 #ifndef AFS_PTHREAD_ENV
1406 assert(LWP_InitializeProcessSupport(LWP_MAX_PRIORITY - 2, &parentPid) == LWP_SUCCESS);
1407 #endif /* !AFS_PTHREAD_ENV */
1409 /* Initialize volume support */
1411 V_BreakVolumeCallbacks = BreakVolumeCallBacks;
1414 /* initialize libacl routines */
1415 acl_Initialize(ACL_VERSION);
1417 /* initialize RX support */
1418 #ifndef AFS_NT40_ENV
1419 rxi_syscallp = viced_syscall;
1421 rx_extraPackets = rxpackets;
1422 rx_extraQuota = 4; /* for outgoing prserver calls from R threads */
1423 rx_SetBusyThreshold(busy_threshold, VBUSY);
1424 rx_SetCallAbortThreshold(10);
1425 rx_SetConnAbortThreshold(10);
1426 stackSize = lwps * 4000;
1427 if (stackSize < 32000)
1429 else if (stackSize > 44000)
1431 #if defined(AFS_HPUX_ENV) || defined(AFS_SUN_ENV) || defined(AFS_SGI51_ENV)
1432 rx_SetStackSize(1, stackSize);
1435 rx_SetUdpBufSize(udpBufSize);/* set the UDP buffer size for receive */
1436 if (rx_Init((int)htons(7000))<0) {
1437 ViceLog(0, ("Cannot initialize RX\n"));
1440 if (!rxJumbograms) {
1441 /* Don't send and don't allow 3.4 clients to send jumbograms. */
1445 rx_SetRxDeadTime(30);
1446 sc[0] = rxnull_NewServerSecurityObject();
1447 sc[1] = 0; /* rxvab_NewServerSecurityObject(key1, 0) */
1448 sc[2] = rxkad_NewServerSecurityObject (rxkad_clear, NULL,
1450 sc[3] = rxkad_NewServerSecurityObject (rxkad_crypt, NULL,
1452 tservice = rx_NewService
1453 (/* port */ 0, /* service id */ 1, /*service name */ "AFS",
1454 /* security classes */ sc, /* numb sec classes */ 4,
1455 RXAFS_ExecuteRequest);
1457 ViceLog(0, ("Failed to initialize RX, probably two servers running.\n"));
1460 rx_SetDestroyConnProc(tservice, (void (*)())h_FreeConnection);
1461 rx_SetMinProcs(tservice, 3);
1462 rx_SetMaxProcs(tservice, lwps);
1463 rx_SetCheckReach(tservice, 1);
1465 tservice = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", sc, 4, RXSTATS_ExecuteRequest);
1467 ViceLog(0, ("Failed to initialize rpc stat service.\n"));
1470 rx_SetMinProcs(tservice, 2);
1471 rx_SetMaxProcs(tservice, 4);
1474 * Enable RX hot threads, which allows the listener thread to trade
1475 * places with an idle thread and moves the context switch from listener
1476 * to worker out of the critical path.
1478 rx_EnableHotThread();
1480 /* Some rx debugging */
1481 if (rxlog || eventlog) {
1482 debugFile = fopen("rx_dbg", "w");
1483 if (rxlog) rx_debugFile = debugFile;
1484 if (eventlog) rxevent_debugFile = debugFile;
1487 h_InitHostPackage(); /* set up local cellname and realmname */
1488 InitCallBack(numberofcbs);
1493 ViceLog(0,("Fatal error in library initialization, exiting!!\n"));
1499 ViceLog(0,("Fatal error in protection initialization, exiting!!\n"));
1503 /* allow super users to manage RX statistics */
1504 rx_SetRxStatUserOk(fs_rxstat_userok);
1506 rx_StartServer(0); /* now start handling requests */
1508 /* we ensure that there is enough space in the vnode buffer to satisfy
1509 ** requests from all concurrent threads.
1510 ** the maximum number of vnodes used by a single thread at any one time
1511 ** is three ( "link" uses three vnodes simultaneously, one vLarge and
1512 ** two vSmall for linking files and two vLarge and one vSmall for linking
1515 minVnodesRequired = 2 * lwps + 1;
1516 if ( minVnodesRequired > nSmallVns ) {
1517 nSmallVns = minVnodesRequired;
1518 ViceLog(0, ("Overriding -s command line parameter with %d\n",
1521 if ( minVnodesRequired > large ) {
1522 large = minVnodesRequired;
1523 ViceLog(0, ("Overriding -l command line parameter with %d\n", large));
1526 /* We now do this after getting the listener up and running, so that client
1527 connections don't timeout (maybe) if a file server is restarted, since it
1528 will be available "real soon now". Worry about whether we can satisfy the
1529 calls in the volume package itself.
1531 if (VInitVolumePackage(fileServer,large,nSmallVns,0, volcache)) {
1532 ViceLog(0, ("Shutting down: errors encountered initializing volume package\n"));
1538 * We are done calling fopen/fdopen. It is safe to use a large
1539 * of the file descriptor cache.
1543 #ifdef AFS_PTHREAD_ENV
1544 assert(pthread_attr_init(&tattr) == 0);
1545 assert(pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED) == 0);
1546 /* Block signals in the threads */
1548 assert(pthread_create(&serverPid, &tattr, (void *)FiveMinuteCheckLWP, &fiveminutes) == 0);
1549 assert(pthread_create(&serverPid, &tattr, (void *)HostCheckLWP, &fiveminutes) == 0);
1550 AFS_SIGSET_RESTORE();
1551 #else /* AFS_PTHREAD_ENV */
1552 assert(LWP_CreateProcess(FiveMinuteCheckLWP, stack*1024, LWP_MAX_PRIORITY - 2,
1553 (void *) &fiveminutes, "FiveMinuteChecks", &serverPid) == LWP_SUCCESS);
1555 assert(LWP_CreateProcess(HostCheckLWP, stack*1024, LWP_MAX_PRIORITY - 2,
1556 (void *) &fiveminutes, "HostCheck", &serverPid) == LWP_SUCCESS);
1557 #endif /* AFS_PTHREAD_ENV */
1559 TM_GetTimeOfDay(&tp, 0);
1561 #ifndef AFS_QUIETFS_ENV
1562 if (console != NULL) {
1563 fprintf(console, "File server has started at %s\r",
1564 afs_ctime(&tp.tv_sec, tbuffer, sizeof(tbuffer)));
1569 * Figure out the FileServer's name and primary address.
1571 ViceLog(0, ("Getting FileServer name...\n"));
1572 code = gethostname(FS_HostName, 64);
1574 ViceLog(0, ("gethostname() failed\n"));
1576 ViceLog(0, ("FileServer host name is '%s'\n", FS_HostName));
1578 ViceLog(0, ("Getting FileServer address...\n"));
1579 he = gethostbyname(FS_HostName);
1581 ViceLog(0, ("Can't find address for FileServer '%s'\n", FS_HostName));
1585 memcpy(&FS_HostAddr_NBO, he->h_addr, 4);
1586 afs_inet_ntoa_r(FS_HostAddr_NBO, hoststr);
1587 FS_HostAddr_HBO = ntohl(FS_HostAddr_NBO);
1588 ViceLog(0,("FileServer %s has address %s (0x%x or 0x%x in host byte order)\n",
1589 FS_HostName, hoststr, FS_HostAddr_NBO, FS_HostAddr_HBO));
1592 /* Install handler to catch the shutdown signal */
1593 signal(SIGQUIT, ShutDown_Signal); /* bosserver assumes SIGQUIT shutdown */
1595 ViceLog(0,("File Server started %s",
1596 afs_ctime(&tp.tv_sec, tbuffer, sizeof(tbuffer))));
1597 #if FS_STATS_DETAILED
1598 afs_FullPerfStats.det.epoch.tv_sec = StartTime = tp.tv_sec;
1600 #ifdef AFS_PTHREAD_ENV
1602 sleep(1000); /* long time */
1604 #else /* AFS_PTHREAD_ENV */
1605 assert(LWP_WaitProcess(&parentPid) == LWP_SUCCESS);
1606 #endif /* AFS_PTHREAD_ENV */