ubik-clone-support-20010212
[openafs.git] / src / bozo / bosserver.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 #include <afs/param.h>
11 #include <afs/stds.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <errno.h>
16 #include <string.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #ifdef AFS_NT40_ENV
20 #include <winsock2.h>
21 #include <direct.h>
22 #include <io.h>
23 #include <WINNT/afsevent.h>
24 #else
25 #include <unistd.h>
26 #include <netinet/in.h>
27 #endif /* AFS_NT40_ENV */
28 #include <afs/cellconfig.h>
29 #include <rx/rx.h>
30 #include <rx/xdr.h>
31 #include <rx/rx_globals.h>
32 #include "bosint.h"
33 #include "bnode.h"
34 #include <afs/auth.h>
35 #include <afs/keys.h>
36 #include <afs/ktime.h>
37 #include <afs/afsutil.h>
38 #include <afs/fileutil.h>
39 #include <afs/procmgmt.h>  /* signal(), kill(), wait(), etc. */
40 #if defined(AFS_SGI_ENV)
41 #include <afs/afs_args.h>
42 #endif
43
44
45 #define BOZO_LWP_STACKSIZE      16000
46 extern int BOZO_ExecuteRequest();
47 extern int RXSTATS_ExecuteRequest();
48 extern int afsconf_GetKey();
49 extern struct bnode_ops fsbnode_ops, ezbnode_ops, cronbnode_ops;
50 struct afsconf_dir *bozo_confdir = 0;   /* bozo configuration dir */
51 static char *bozo_pid;
52 struct rx_securityClass *bozo_rxsc[3];
53 const char *bozo_fileName;
54 FILE *bozo_logFile;
55 extern int rx_stackSize;    /* for rx_SetStackSize macro */
56
57 int DoLogging = 0;
58 static afs_int32 nextRestart;
59 static afs_int32 nextDay;
60
61 struct ktime bozo_nextRestartKT, bozo_nextDayKT;
62 int bozo_newKTs;
63 #ifdef BOS_RESTRICTED_MODE
64 int bozo_isrestricted=0;
65 int bozo_restdisable=0;
66
67 void bozo_insecureme(int sig) 
68 {
69      signal(SIGFPE, bozo_insecureme);
70      bozo_isrestricted=0;
71      bozo_restdisable=1;
72 }
73 #endif
74
75 struct bztemp {
76     FILE *file;
77 };
78
79 /* check whether caller is authorized to manage RX statistics */
80 int bozo_rxstat_userok(call)
81     struct rx_call *call;
82 {
83     return afsconf_SuperUser(bozo_confdir, call, (char *)0);
84 }
85
86 /* restart bozo process */
87 bozo_ReBozo() {
88 #ifdef AFS_NT40_ENV
89     /* exit with restart code; SCM integrator process will restart bosserver */
90     int status = BOSEXIT_RESTART;
91
92     /* if noauth flag is set, pass "-noauth" to new bosserver */
93     if (afsconf_GetNoAuthFlag(bozo_confdir)) {
94         status |= BOSEXIT_NOAUTH_FLAG;
95     }
96     /* if logging is on, pass "-log" to new bosserver */
97     if (DoLogging) {
98         status |= BOSEXIT_LOGGING_FLAG;
99     }
100     exit(status);
101 #else
102     /* exec new bosserver process */
103     char *argv[4];
104     int i = 0;
105
106     argv[i] = (char *)AFSDIR_SERVER_BOSVR_FILEPATH;
107     i++;
108
109     /* if noauth flag is set, pass "-noauth" to new bosserver */
110     if (afsconf_GetNoAuthFlag(bozo_confdir)) {
111         argv[i] = "-noauth";
112         i++;
113     }
114     /* if logging is on, pass "-log" to new bosserver */
115     if (DoLogging) {
116         argv[i] = "-log";
117         i++;
118     }
119
120     /* null-terminate argument list */
121     argv[i] = NULL;
122
123     /* close random fd's */
124     for (i = 3; i < 64; i++) {
125         close(i);
126     }
127
128     execv(argv[0], argv);  /* should not return */
129     _exit(1);
130 #endif /* AFS_NT40_ENV */
131 }
132
133 /* make sure a dir exists */
134 static MakeDir(adir)
135 register char *adir; {
136     struct stat tstat;
137     register afs_int32 code;
138     if (stat(adir, &tstat) < 0 || (tstat.st_mode & S_IFMT) != S_IFDIR) {
139         int reqPerm;
140         unlink(adir);
141         reqPerm = GetRequiredDirPerm (adir);
142         if (reqPerm == -1) reqPerm = 0777;
143 #ifdef AFS_NT40_ENV
144         /* underlying filesystem may not support directory protection */
145         code = mkdir(adir);
146 #else
147         code = mkdir(adir, reqPerm);
148 #endif
149         return code;
150     }
151     return 0;
152 }
153
154 /* create all the bozo dirs */
155 static CreateDirs() {
156     
157     MakeDir(AFSDIR_USR_DIRPATH);
158     MakeDir(AFSDIR_SERVER_AFS_DIRPATH);
159     MakeDir(AFSDIR_SERVER_BIN_DIRPATH);
160     MakeDir(AFSDIR_SERVER_ETC_DIRPATH); 
161     MakeDir(AFSDIR_SERVER_LOCAL_DIRPATH);
162     MakeDir(AFSDIR_SERVER_DB_DIRPATH); 
163     MakeDir(AFSDIR_SERVER_LOGS_DIRPATH);
164 #ifndef AFS_NT40_ENV
165     MakeDir(AFSDIR_CLIENT_VICE_DIRPATH);
166     MakeDir(AFSDIR_CLIENT_ETC_DIRPATH);
167
168     symlink(AFSDIR_SERVER_THISCELL_FILEPATH, AFSDIR_CLIENT_THISCELL_FILEPATH); 
169     symlink(AFSDIR_SERVER_CELLSERVDB_FILEPATH, AFSDIR_CLIENT_CELLSERVDB_FILEPATH);
170 #endif /* AFS_NT40_ENV */
171     return 0;
172 }
173
174 /* strip the \\n from the end of the line, if it is present */
175 static StripLine(abuffer)
176 register char *abuffer; {
177     register char *tp;
178     
179     tp = abuffer + strlen(abuffer); /* starts off pointing at the null  */
180     if(tp == abuffer) return 0;     /* null string, no last character to check */
181     tp--;       /* aim at last character */
182     if (*tp == '\n') *tp = 0;
183     return 0;
184 }
185
186 /* write one bnode's worth of entry into the file */
187 static bzwrite(abnode, at)
188 register struct bnode *abnode;
189 register struct bztemp *at; {
190     register int i;
191     char tbuffer[BOZO_BSSIZE];
192     register afs_int32 code;
193
194     if (abnode->notifier)
195         fprintf(at->file, "bnode %s %s %d %s\n", 
196                 abnode->type->name, abnode->name, abnode->fileGoal, abnode->notifier);
197     else
198         fprintf(at->file, "bnode %s %s %d\n", abnode->type->name, abnode->name, abnode->fileGoal);
199     for(i=0;;i++) {
200         code = bnode_GetParm(abnode, i, tbuffer, BOZO_BSSIZE);
201         if (code) {
202             if (code != BZDOM) return code;
203             break;
204         }
205         fprintf(at->file, "parm %s\n", tbuffer);
206     }
207     fprintf(at->file, "end\n");
208     return 0;
209 }
210
211 #define MAXPARMS    20
212 ReadBozoFile(aname)
213 char *aname; {
214     register FILE *tfile;
215     char tbuffer[BOZO_BSSIZE];
216     register char *tp;
217     char *instp, *typep, *notifier, *notp;
218     register afs_int32 code;
219     afs_int32 ktmask, ktday, kthour, ktmin, ktsec;
220     afs_int32 i, goal;
221     struct bnode *tb;
222     char *parms[MAXPARMS];
223 #ifdef BOS_RESTRICTED_MODE
224     int rmode;
225 #endif
226
227     /* rename BozoInit to BosServer for the user */
228     if (!aname) {
229         /* if BozoInit exists and BosConfig doesn't, try a rename */
230         if (access(AFSDIR_SERVER_BOZINIT_FILEPATH, 0) == 0
231             && access(AFSDIR_SERVER_BOZCONF_FILEPATH, 0) != 0) {
232             code = renamefile(AFSDIR_SERVER_BOZINIT_FILEPATH, AFSDIR_SERVER_BOZCONF_FILEPATH);
233             if (code < 0)
234                 perror("bosconfig rename");
235         }
236 #ifdef BOS_NEW_CONFIG
237         if (access(AFSDIR_SERVER_BOZCONFNEW_FILEPATH, 0) == 0) {
238              code = renamefile(AFSDIR_SERVER_BOZCONFNEW_FILEPATH,
239                                AFSDIR_SERVER_BOZCONF_FILEPATH);
240              if (code < 0)
241                   perror("bosconfig rename");
242         }
243 #endif        
244     }
245
246     /* setup default times we want to do restarts */
247     bozo_nextRestartKT.mask = KTIME_HOUR | KTIME_MIN | KTIME_DAY;
248     bozo_nextRestartKT.hour = 4; /* 4 am */
249     bozo_nextRestartKT.min = 0;
250     bozo_nextRestartKT.day =    0;  /* Sunday */
251     bozo_nextDayKT.mask = KTIME_HOUR | KTIME_MIN;
252     bozo_nextDayKT.hour = 5;
253     bozo_nextDayKT.min = 0;
254
255     for(code=0;code<MAXPARMS;code++)
256         parms[code] = (char *) 0;
257     instp = typep = notifier = (char *) 0;
258     tfile = (FILE *) 0;
259     if (!aname) aname = (char *)bozo_fileName;
260     tfile = fopen(aname, "r");
261     if (!tfile) 
262         return 0;       /* -1 */
263     instp = (char *) malloc(BOZO_BSSIZE);
264     typep = (char *) malloc(BOZO_BSSIZE);
265     notifier = notp = (char *) malloc(BOZO_BSSIZE);
266     while (1) {
267         /* ok, read lines giving parms and such from the file */
268         tp = fgets(tbuffer, sizeof(tbuffer), tfile);
269         if (tp == (char *) 0) break;    /* all done */
270
271         if (strncmp(tbuffer, "restarttime", 11) == 0) {
272             code = sscanf(tbuffer, "restarttime %d %d %d %d %d",
273                           &ktmask, &ktday, &kthour, &ktmin, &ktsec);
274             if (code != 5) {
275                 code = -1;
276                 goto fail;
277             }
278             /* otherwise we've read in the proper ktime structure; now assign
279                it and continue processing */
280             bozo_nextRestartKT.mask = ktmask;
281             bozo_nextRestartKT.day = ktday;
282             bozo_nextRestartKT.hour = kthour;
283             bozo_nextRestartKT.min = ktmin;
284             bozo_nextRestartKT.sec = ktsec;
285             continue;
286         }
287
288         if (strncmp(tbuffer, "checkbintime", 12) == 0) {
289             code = sscanf(tbuffer, "checkbintime %d %d %d %d %d",
290                           &ktmask, &ktday, &kthour, &ktmin, &ktsec);
291             if (code != 5) {
292                 code = -1;
293                 goto fail;
294             }
295             /* otherwise we've read in the proper ktime structure; now assign
296                it and continue processing */
297             bozo_nextDayKT.mask = ktmask;       /* time to restart the system */
298             bozo_nextDayKT.day = ktday;
299             bozo_nextDayKT.hour = kthour;
300             bozo_nextDayKT.min = ktmin;
301             bozo_nextDayKT.sec = ktsec;
302             continue;
303         }
304
305 #ifdef BOS_RESTRICTED_MODE
306         if (strncmp(tbuffer, "restrictmode", 12) == 0) {
307             code = sscanf(tbuffer, "restrictmode %d",
308                           &rmode);
309             if (code != 1) {
310                 code = -1;
311                 goto fail;
312             }
313             if (rmode !=0 && rmode != 1) {
314                  code = -1;
315                  goto fail;
316             } 
317             bozo_isrestricted=rmode;
318             continue;
319         }
320 #endif
321         
322         if (strncmp("bnode", tbuffer, 5) != 0) {
323             code = -1;
324             goto fail;
325         }
326         notifier = notp;
327         code = sscanf(tbuffer, "bnode %s %s %d %s", typep, instp, &goal, notifier);
328         if (code < 3) {
329             code = -1;
330             goto fail;
331         } else if (code == 3)
332             notifier = (char *)0;
333         
334         for(i=0;i<MAXPARMS;i++) {
335             /* now read the parms, until we see an "end" line */
336             tp = fgets(tbuffer, sizeof(tbuffer), tfile);
337             if (!tp) {
338                 code = -1;
339                 goto fail;
340             }
341             StripLine(tbuffer);
342             if (!strncmp(tbuffer, "end", 3)) break;
343             if (strncmp(tbuffer, "parm ", 5)) {
344                 code = -1;
345                 goto fail;    /* no "parm " either */
346             }
347             if (!parms[i])  /* make sure there's space */
348                 parms[i] = (char *) malloc(BOZO_BSSIZE);
349             strcpy(parms[i], tbuffer+5);    /* remember the parameter for later */
350         }
351
352         /* ok, we have the type and parms, now create the object */
353         code = bnode_Create(typep, instp, &tb, parms[0], parms[1], parms[2],
354                           parms[3], parms[4], notifier,
355                           goal ? BSTAT_NORMAL : BSTAT_SHUTDOWN);
356         if (code) goto fail;
357
358         /* bnode created in 'temporarily shutdown' state;
359            check to see if we are supposed to run this guy,
360             and if so, start the process up */
361         if (goal) {
362             bnode_SetStat(tb, BSTAT_NORMAL);    /* set goal, taking effect immediately */
363         }
364         else {
365             bnode_SetStat(tb, BSTAT_SHUTDOWN);
366         }
367     }
368     /* all done */
369     code = 0;
370
371 fail:
372     if (instp) free(instp);
373     if (typep) free(typep);
374     for(i=0;i<MAXPARMS;i++) if (parms[i]) free(parms[i]);
375     if (tfile) fclose(tfile);
376     return code;
377 }
378
379 /* write a new bozo file */
380 WriteBozoFile(aname)
381 char *aname; {
382     register FILE *tfile;
383     char tbuffer[AFSDIR_PATH_MAX];
384     register afs_int32 code;
385     struct bztemp btemp;
386
387     if (!aname) aname = (char *)bozo_fileName;
388     strcpy(tbuffer, aname);
389     strcat(tbuffer, ".NBZ");
390     tfile = fopen(tbuffer, "w");
391     if (!tfile) return -1;
392     btemp.file = tfile;
393 #ifdef BOS_RESTRICTED_MODE
394     fprintf(tfile, "restrictmode %d\n", bozo_isrestricted);
395 #endif
396     fprintf(tfile, "restarttime %d %d %d %d %d\n", bozo_nextRestartKT.mask,
397             bozo_nextRestartKT.day, bozo_nextRestartKT.hour, bozo_nextRestartKT.min,
398             bozo_nextRestartKT.sec);
399     fprintf(tfile, "checkbintime %d %d %d %d %d\n", bozo_nextDayKT.mask,
400             bozo_nextDayKT.day, bozo_nextDayKT.hour, bozo_nextDayKT.min,
401             bozo_nextDayKT.sec);
402     code = bnode_ApplyInstance(bzwrite, &btemp);
403     if (code || (code = ferror(tfile))) {       /* something went wrong */
404         fclose(tfile);
405         unlink(tbuffer);
406         return code;
407     }
408     /* close the file, check for errors and snap new file into place */
409     if (fclose(tfile) == EOF) {
410         unlink(tbuffer);
411         return -1;
412     }
413     code = renamefile(tbuffer, aname);
414     if (code) {
415         unlink(tbuffer);
416         return -1;
417     }
418     return 0;
419 }
420
421 static bdrestart(abnode, arock)
422 register struct bnode *abnode;
423 char *arock; {
424     register afs_int32 code;
425     
426     if (abnode->fileGoal != BSTAT_NORMAL || abnode->goal != BSTAT_NORMAL)
427         return 0;       /* don't restart stopped bnodes */
428     bnode_Hold(abnode);
429     code = bnode_RestartP(abnode);
430     if (code) {
431         /* restart the dude */
432         bnode_SetStat(abnode, BSTAT_SHUTDOWN);
433         bnode_WaitStatus(abnode, BSTAT_SHUTDOWN);
434         bnode_SetStat(abnode, BSTAT_NORMAL);
435     }
436     bnode_Release(abnode);
437     return 0;   /* keep trying all bnodes */
438 }
439
440 #define BOZO_MINSKIP 3600           /* minimum to advance clock */
441 /* lwp to handle system restarts */
442 static BozoDaemon() {
443     register afs_int32 now;
444     
445     /* now initialize the values */
446     bozo_newKTs = 1;
447     while (1) {
448         IOMGR_Sleep(60);
449         now = FT_ApproxTime();
450
451 #ifdef BOS_RESTRICTED_MODE
452         if (bozo_restdisable) {
453              bozo_Log("Restricted mode disabled by signal\n");
454              bozo_restdisable=0;
455         }
456 #endif
457         if (bozo_newKTs) {      /* need to recompute restart times */
458             bozo_newKTs = 0;    /* done for a while */
459             nextRestart = ktime_next(&bozo_nextRestartKT, BOZO_MINSKIP);
460             nextDay = ktime_next(&bozo_nextDayKT, BOZO_MINSKIP);
461         }
462
463         /* see if we should do a restart */
464         if (now > nextRestart) {
465             BOZO_ReBozo(0);     /* doesn't come back */
466         }
467         
468         /* see if we should restart a server */
469         if (now > nextDay) {
470             nextDay = ktime_next(&bozo_nextDayKT, BOZO_MINSKIP);
471             
472             /* call the bnode restartp function, and restart all that require it */
473             bnode_ApplyInstance(bdrestart, 0);
474         }
475     }
476 }
477
478 #ifdef AFS_AIX32_ENV
479 static tweak_config()
480 {
481     FILE *f;
482     char c[80];
483     int s, sb_max, ipfragttl;
484
485     sb_max = 131072;
486     ipfragttl = 20;
487     f = popen("/usr/sbin/no -o sb_max", "r");
488     s = fscanf(f, "sb_max = %d", &sb_max);
489     fclose(f);
490     if (s < 1) 
491         return;
492     f = popen("/usr/sbin/no -o ipfragttl", "r");
493     s = fscanf(f, "ipfragttl = %d", &ipfragttl);
494     fclose(f);
495     if (s < 1) 
496         ipfragttl = 20;
497
498     if (sb_max < 131072) 
499         sb_max = 131072;
500     if (ipfragttl > 20)
501         ipfragttl = 20;
502     
503     sprintf(c, "/usr/sbin/no -o sb_max=%d -o ipfragttl=%d", sb_max, ipfragttl);
504     f = popen(c, "r");
505     fclose(f);
506 }
507 #endif
508
509 /*
510  * This routine causes the calling process to go into the background and
511  * to lose its controlling tty.
512  *
513  * It does not close or otherwise alter the standard file descriptors.
514  *
515  * It writes warning messages to the standard error output if certain
516  * fundamental errors occur.
517  *
518  * This routine requires
519  * 
520  * #include <sys/types.h>
521  * #include <sys/stat.h>
522  * #include <fcntl.h>
523  * #include <unistd.h>
524  * #include <stdlib.h>
525  *
526  * and has been tested on:
527  *
528  * AIX 4.2
529  * Digital Unix 4.0D
530  * HP-UX 11.0
531  * IRIX 6.5
532  * Linux 2.1.125
533  * Solaris 2.5
534  * Solaris 2.6
535  */
536
537 #ifndef AFS_NT40_ENV
538 static void
539 background(void)
540 {
541     /* 
542      * A process is a process group leader if its process ID
543      * (getpid()) and its process group ID (getpgrp()) are the same.
544      */
545
546     /*
547      * To create a new session (and thereby lose our controlling
548      * terminal) we cannot be a process group leader.
549      *
550      * To guarantee we are not a process group leader, we fork and
551      * let the parent process exit.
552      */
553
554     if (getpid() == getpgrp()) {
555         pid_t pid;
556         pid = fork();
557         switch(pid) {
558         case -1:
559             abort();    /* leave footprints */
560             break;
561         case 0:         /* child */
562             break;
563         default:        /* parent */
564             exit(0);
565             break;
566         }
567     }
568
569     /*
570      * By here, we are not a process group leader, so we can make a
571      * new session and become the session leader.
572      */
573
574     {
575         pid_t sid = setsid();
576
577         if (sid == -1) {
578             static char err[] = "bosserver: WARNING: setsid() failed\n";
579             write(STDERR_FILENO, err, sizeof err - 1);
580         }
581     }
582
583     /*
584      * Once we create a new session, the current process is a
585      * session leader without a controlling tty.
586      *
587      * On some systems, the first tty device the session leader
588      * opens automatically becomes the controlling tty for the
589      * session.
590      *
591      * So, to guarantee we do not acquire a controlling tty, we fork
592      * and let the parent process exit.  The child process is not a
593      * session leader, and so it will not acquire a controlling tty
594      * even if it should happen to open a tty device.
595      */
596
597     if (getpid() == getpgrp()) {
598         pid_t pid;
599         pid = fork();
600         switch(pid) {
601         case -1:
602             abort();    /* leave footprints */
603             break;
604         case 0:         /* child */
605             break;
606         default:        /* parent */
607             exit(0);
608             break;
609         }
610     }
611
612     /*
613      * check that we no longer have a controlling tty
614      */
615
616     {
617         int fd;
618
619         fd = open("/dev/tty", O_RDONLY);
620
621         if (fd >= 0) {
622             static char err[] = "bosserver: WARNING: /dev/tty still attached\n";
623             close(fd);
624             write(STDERR_FILENO, err, sizeof err - 1);
625         }
626     }
627 }
628 #endif /* ! AFS_NT40_ENV */
629
630 /* start a process and monitor it */
631
632 #include "AFS_component_version_number.c"
633
634
635 main (argc, argv,envp)
636 int argc;
637 char **argv;
638 char **envp;
639 {
640     struct rx_service *tservice;
641     register afs_int32 code;
642     struct afsconf_dir *tdir;
643     int noAuth = 0;
644     struct ktc_encryptionKey tkey;
645     int i;
646     pid_t       newSessionID;
647     char namebuf[AFSDIR_PATH_MAX];
648
649 #ifdef  AFS_AIX32_ENV
650     struct sigaction nsa;
651
652     /* for some reason, this permits user-mode RX to run a lot faster.
653      * we do it here in the bosserver, so we don't have to do it 
654      * individually in each server.
655      */
656     tweak_config();
657
658     /*
659      * The following signal action for AIX is necessary so that in case of a 
660      * crash (i.e. core is generated) we can include the user's data section 
661      * in the core dump. Unfortunately, by default, only a partial core is
662      * generated which, in many cases, isn't too useful.
663      */
664     sigemptyset(&nsa.sa_mask);
665     nsa.sa_handler = SIG_DFL;
666     nsa.sa_flags = SA_FULLDUMP;
667     sigaction(SIGSEGV, &nsa, NULL);
668     sigaction(SIGABRT, &nsa, NULL);
669 #endif
670 #ifdef BOS_RESTRICTED_MODE
671     signal(SIGFPE, bozo_insecureme);
672 #endif
673
674 #ifdef AFS_NT40_ENV
675     /* Initialize winsock */
676     if (afs_winsockInit() < 0) {
677         ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0);
678         fprintf(stderr, "%s: Couldn't initialize winsock.\n", argv[0]);
679         exit(2);
680     }
681 #endif
682
683     /* Initialize dirpaths */
684     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
685 #ifdef AFS_NT40_ENV
686         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
687 #endif
688         fprintf(stderr, "%s: Unable to obtain AFS server directory.\n", argv[0]);
689         exit(2);
690     }
691
692     /* some path inits */
693     bozo_fileName = AFSDIR_SERVER_BOZCONF_FILEPATH;
694
695     /* initialize the list of dirpaths that the bosserver has
696      * an interest in monitoring */
697     initBosEntryStats();
698
699 #if defined(AFS_SGI_ENV)
700     /* offer some protection if AFS isn't loaded */
701     if (syscall(AFS_SYSCALL, AFSOP_ENDLOG) < 0 && errno == ENOPKG) {
702         printf("bosserver: AFS doesn't appear to be configured in O.S..\n");
703         exit(1);
704     }
705 #endif
706
707     /* parse cmd line */
708     for(code=1;code<argc;code++) {
709         if (strcmp(argv[code], "-noauth")==0) {
710             /* set noauth flag */
711             noAuth = 1;
712         }
713         else if (strcmp(argv[code], "-log")==0) {
714             /* set extra logging flag */
715             DoLogging = 1;
716         }
717         else if (strcmp(argv[code], "-enable_peer_stats")==0) {
718             rx_enablePeerRPCStats();
719         }
720         else if (strcmp(argv[code], "-enable_process_stats")==0) {
721             rx_enableProcessRPCStats();
722         }
723 #ifdef BOS_RESTRICTED_MODE
724         else if (strcmp(argv[code], "-restricted")==0) {
725             bozo_isrestricted=1;
726         }
727 #endif
728         else {
729
730             /* hack to support help flag */
731
732             printf("Usage: bosserver [-noauth] [-log] "
733                    /* "[-enable_peer_stats] [-enable_process_stats] " */
734                    "[-help]\n");
735             fflush(stdout);
736
737             exit(0);
738         }
739     }
740
741 #ifndef AFS_NT40_ENV
742     if (geteuid() != 0) {
743         printf("bosserver: must be run as root.\n");
744         exit(1);
745     }
746 #endif
747
748     code = bnode_Init();
749     if (code) {
750         printf("bosserver: could not init bnode package, code %d\n", code);
751         exit(1);
752     }
753
754     bnode_Register("fs", &fsbnode_ops, 3);
755     bnode_Register("simple", &ezbnode_ops, 1);
756     bnode_Register("cron", &cronbnode_ops, 2);
757
758     /* create useful dirs */
759     CreateDirs();
760
761     /* chdir to AFS log directory */
762     chdir(AFSDIR_SERVER_LOGS_DIRPATH);
763
764     fputs(AFS_GOVERNMENT_MESSAGE, stdout);
765     fflush(stdout);
766
767     /* go into the background and remove our controlling tty */
768
769 #ifndef AFS_NT40_ENV
770     background();
771 #endif /* ! AFS_NT40_ENV */
772
773     /* switch to logging information to the BosLog file */
774     strcpy(namebuf, AFSDIR_BOZLOG_FILE);
775     strcat(namebuf, ".old");
776     renamefile(AFSDIR_BOZLOG_FILE, namebuf);    /* try rename first */
777     bozo_logFile = fopen(AFSDIR_BOZLOG_FILE, "a");
778     if (!bozo_logFile) {
779         printf("bosserver: can't initialize log file (%s).\n",
780                AFSDIR_SERVER_BOZLOG_FILEPATH);
781         exit(1);
782     }
783
784     /* keep log closed normally, so can be removed */
785
786     fclose(bozo_logFile);
787
788     /* Write current state of directory permissions to log file */
789     DirAccessOK ();
790
791     for (i=0;i<10;i++) {
792         code = rx_Init(htons(AFSCONF_NANNYPORT));
793         if (code) {
794             bozo_Log("can't initialize rx: code=%d\n",code);
795             sleep(3);
796         }
797         else break;
798     }
799     if (i>=10) {
800         bozo_Log("Bos giving up, can't initialize rx\n");
801         exit(code);
802     }
803
804     code = LWP_CreateProcess(BozoDaemon, BOZO_LWP_STACKSIZE, /* priority */ 1,
805                              /* parm */0, "bozo-the-clown", &bozo_pid);
806
807     /* try to read the key from the config file */
808     tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
809     if (!tdir) {
810         /* try to create local cell config file */
811         struct afsconf_cell tcell;
812         strcpy(tcell.name, "localcell");
813         tcell.numServers = 1;
814         code = gethostname(tcell.hostName[0], MAXHOSTCHARS);
815         if (code) {
816             bozo_Log("failed to get hostname, code %d\n", errno);
817             exit(1);
818         }
819         if (tcell.hostName[0][0] == 0) {
820             bozo_Log("host name not set, can't start\n");
821             bozo_Log("try the 'hostname' command\n");
822             exit(1);
823         }
824         bzero(tcell.hostAddr, sizeof(tcell.hostAddr));  /* not computed */
825         code = afsconf_SetCellInfo(bozo_confdir, AFSDIR_SERVER_ETC_DIRPATH, &tcell);
826         if (code) {
827             bozo_Log("could not create cell database in '%s' (code %d), quitting\n", AFSDIR_SERVER_ETC_DIRPATH, code);
828             exit(1);
829         }
830         tdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
831         if (!tdir) {
832             bozo_Log("failed to open newly-created cell database, quitting\n");
833             exit(1);
834         }
835     }
836
837     /* read init file, starting up programs */
838     if (code=ReadBozoFile(0)) {
839         bozo_Log("bosserver: Something is wrong (%d) with the bos configuration file %s; aborting\n", code, AFSDIR_SERVER_BOZCONF_FILEPATH);
840         exit(code);
841     }
842
843     /* opened the cell databse */
844     bozo_confdir = tdir;
845     code = afsconf_GetKey(tdir, 999, &tkey);
846
847     /* allow super users to manage RX statistics */
848     rx_SetRxStatUserOk(bozo_rxstat_userok);
849
850     /* have bcrypt key now */
851
852     afsconf_SetNoAuthFlag(tdir, noAuth);
853
854     bozo_rxsc[0] = (struct rx_securityClass *) rxnull_NewServerSecurityObject();
855     bozo_rxsc[1] = (struct rx_securityClass *) 0;
856     bozo_rxsc[2] = (struct rx_securityClass *) rxkad_NewServerSecurityObject(
857                                          0, tdir, afsconf_GetKey, (char *) 0);
858
859     /* These two lines disallow jumbograms */
860     rx_maxReceiveSize = OLD_MAX_PACKET_SIZE;
861     rxi_nSendFrags = rxi_nRecvFrags = 1;
862
863     tservice = rx_NewService(/* port */ 0, /* service id */ 1, 
864                   /*service name */ "bozo", /* security classes */ bozo_rxsc,
865                   /* numb sec classes */ 3, BOZO_ExecuteRequest);
866     rx_SetMinProcs(tservice, 2);
867     rx_SetMaxProcs(tservice, 4);
868     rx_SetStackSize(tservice, BOZO_LWP_STACKSIZE); /* so gethostbyname works (in cell stuff) */
869
870     tservice = rx_NewService(0, RX_STATS_SERVICE_ID, "rpcstats", bozo_rxsc,
871                   3, RXSTATS_ExecuteRequest);
872     rx_SetMinProcs(tservice, 2);
873     rx_SetMaxProcs(tservice, 4);
874     rx_StartServer(1);      /* donate this process */
875 }
876
877 bozo_Log(a,b,c,d,e,f)
878 char *a, *b, *c, *d, *e, *f; {
879     char tdate[26];
880     time_t myTime;
881
882     myTime = time(0);
883     strcpy(tdate, ctime(&myTime));      /* copy out of static area asap */
884     tdate[24] = ':';
885
886     /* log normally closed, so can be removed */
887
888     bozo_logFile=fopen(AFSDIR_SERVER_BOZLOG_FILEPATH, "a");
889     if(bozo_logFile == NULL)
890     {
891         printf("bosserver: WARNING: problem with %s", AFSDIR_SERVER_BOZLOG_FILEPATH);
892         fflush(stdout);
893     }
894
895     if (bozo_logFile) {
896         fprintf(bozo_logFile, "%s ", tdate);
897         fprintf(bozo_logFile, a, b, c, d, e, f);
898         fflush(bozo_logFile);
899     }
900     else {
901         printf("%s ", tdate);
902         printf(a, b, c, d, e, f);
903     }
904
905     /* close so rm BosLog works */
906
907     fclose(bozo_logFile);
908 }