d7f2960928ccab620b94653810034832c27489a2
[openafs.git] / src / budb / server.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 <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15
16 #include <fcntl.h>
17
18 #ifdef AFS_NT40_ENV
19 #include <WINNT/afsevent.h>
20 #endif
21 #include <afs/cmd.h>
22 #include <lwp.h>
23 #include <ubik.h>
24 #include <rx/xdr.h>
25 #include <rx/rx.h>
26 #include <rx/rxkad.h>
27 #include <rx/rx_globals.h>
28 #include <afs/cellconfig.h>
29 #include <afs/bubasics.h>
30 #include <afs/afsutil.h>
31 #include <afs/com_err.h>
32 #include <afs/audit.h>
33
34 #include "budb_errs.h"
35 #include "database.h"
36 #include "error_macros.h"
37 #include "budb_internal.h"
38 #include "globals.h"
39
40 struct ubik_dbase *BU_dbase;
41 struct afsconf_dir *BU_conf;    /* for getting cell info */
42
43 int argHandler(struct cmd_syndesc *, void *);
44 int truncateDatabase(void);
45 int parseServerList(struct cmd_item *);
46
47 char lcell[MAXKTCREALMLEN];
48 afs_uint32 myHost = 0;
49 int helpOption;
50
51 /* server's global configuration information. This is exported to other
52  * files/routines
53  */
54
55 buServerConfT globalConf;
56 buServerConfP globalConfPtr = &globalConf;
57 char dbDir[AFSDIR_PATH_MAX], cellConfDir[AFSDIR_PATH_MAX];
58 /* debugging control */
59 int debugging = 0;
60
61 int rxBind = 0;
62 int lwps   = 3;
63
64 #define MINLWP  3
65 #define MAXLWP 16
66
67 #define ADDRSPERSITE 16         /* Same global is in rx/rx_user.c */
68 afs_uint32 SHostAddrs[ADDRSPERSITE];
69
70 /* check whether caller is authorized to manage RX statistics */
71 int
72 BU_rxstat_userok(struct rx_call *call)
73 {
74     return afsconf_SuperUser(BU_conf, call, NULL);
75 }
76
77 int
78 convert_cell_to_ubik(struct afsconf_cell *cellinfo, afs_uint32 *myHost,
79                      afs_uint32 *serverList)
80 {
81     int i;
82     char hostname[64];
83     struct hostent *th;
84
85     /* get this host */
86     gethostname(hostname, sizeof(hostname));
87     th = gethostbyname(hostname);
88     if (!th) {
89         printf("prserver: couldn't get address of this host.\n");
90         BUDB_EXIT(1);
91     }
92     memcpy(myHost, th->h_addr, sizeof(afs_uint32));
93
94     for (i = 0; i < cellinfo->numServers; i++)
95         /* omit my host from serverList */
96         if (cellinfo->hostAddr[i].sin_addr.s_addr != *myHost)
97             *serverList++ = cellinfo->hostAddr[i].sin_addr.s_addr;
98
99     *serverList = 0;            /* terminate list */
100     return 0;
101 }
102
103 /* MyBeforeProc
104  *      The whole purpose of MyBeforeProc is to detect
105  *      if the -help option was not within the command line.
106  *      If it were, this routine would never have been called.
107  */
108 static int
109 MyBeforeProc(struct cmd_syndesc *as, void *arock)
110 {
111     helpOption = 0;
112     return 0;
113 }
114
115 /* initializeCommands
116  *      initialize all the supported commands and their arguments
117  */
118
119 void
120 initializeArgHandler(void)
121 {
122     struct cmd_syndesc *cptr;
123
124     cmd_SetBeforeProc(MyBeforeProc, NULL);
125
126     cptr = cmd_CreateSyntax(NULL, argHandler, NULL, "Backup database server");
127
128     cmd_AddParm(cptr, "-database", CMD_SINGLE, CMD_OPTIONAL,
129                 "database directory");
130
131     cmd_AddParm(cptr, "-cellservdb", CMD_SINGLE, CMD_OPTIONAL,
132                 "cell configuration directory");
133
134     cmd_AddParm(cptr, "-resetdb", CMD_FLAG, CMD_OPTIONAL,
135                 "truncate the database");
136
137     cmd_AddParm(cptr, "-noauth", CMD_FLAG, CMD_OPTIONAL,
138                 "run without authentication");
139
140     cmd_AddParm(cptr, "-smallht", CMD_FLAG, CMD_OPTIONAL,
141                 "use small hash tables");
142
143     cmd_AddParm(cptr, "-servers", CMD_LIST, CMD_OPTIONAL,
144                 "list of ubik database servers");
145
146     cmd_AddParm(cptr, "-ubikbuffers", CMD_SINGLE, CMD_OPTIONAL,
147                 "the number of ubik buffers");
148
149     cmd_AddParm(cptr, "-auditlog", CMD_SINGLE, CMD_OPTIONAL,
150                 "audit log path");
151
152     cmd_AddParm(cptr, "-p", CMD_SINGLE, CMD_OPTIONAL,
153                 "number of processes");
154
155     cmd_AddParm(cptr, "-rxbind", CMD_FLAG, CMD_OPTIONAL,
156                 "bind the Rx socket (primary interface only)");
157
158     cmd_AddParm(cptr, "-audit-interface", CMD_SINGLE, CMD_OPTIONAL,
159                 "audit interface (file or sysvmq)");
160 }
161
162 int
163 argHandler(struct cmd_syndesc *as, void *arock)
164 {
165
166     /* globalConfPtr provides the handle for the configuration information */
167
168     /* database directory */
169     if (as->parms[0].items != 0) {
170         globalConfPtr->databaseDirectory =
171             (char *)malloc(strlen(as->parms[0].items->data) + 1);
172         if (globalConfPtr->databaseDirectory == 0)
173             BUDB_EXIT(-1);
174         strcpy(globalConfPtr->databaseDirectory, as->parms[0].items->data);
175     }
176
177     /* -cellservdb, cell configuration directory */
178     if (as->parms[1].items != 0) {
179         globalConfPtr->cellConfigdir =
180             (char *)malloc(strlen(as->parms[1].items->data) + 1);
181         if (globalConfPtr->cellConfigdir == 0)
182             BUDB_EXIT(-1);
183
184         strcpy(globalConfPtr->cellConfigdir, as->parms[1].items->data);
185
186         globalConfPtr->debugFlags |= DF_RECHECKNOAUTH;
187     }
188
189     /* truncate the database */
190     if (as->parms[2].items != 0)
191         truncateDatabase();
192
193     /* run without authentication */
194     if (as->parms[3].items != 0)
195         globalConfPtr->debugFlags |= DF_NOAUTH;
196
197     /* use small hash tables */
198     if (as->parms[4].items != 0)
199         globalConfPtr->debugFlags |= DF_SMALLHT;
200
201     /* user provided list of ubik database servers */
202     if (as->parms[5].items != 0)
203         parseServerList(as->parms[5].items);
204
205     /* user provided the number of ubik buffers    */
206     if (as->parms[6].items != 0)
207         ubik_nBuffers = atoi(as->parms[6].items->data);
208     else
209         ubik_nBuffers = 0;
210
211     /* param 7 (-auditlog) handled below */
212
213     /* user provided the number of threads    */
214     if (as->parms[8].items != 0) {
215         lwps = atoi(as->parms[8].items->data);
216         if (lwps > MAXLWP) {
217             printf ("Warning: '-p %d' is too big; using %d instead\n",
218                 lwps, MAXLWP);
219             lwps = MAXLWP;
220         }
221         if (lwps < MINLWP) {
222             printf ("Warning: '-p %d' is too small; using %d instead\n",
223                 lwps, MINLWP);
224             lwps = MINLWP;
225         }
226     }
227
228     /* user provided rxbind option    */
229     if (as->parms[9].items != 0) {
230         rxBind = 1;
231     }
232
233     /* -audit-interface */
234     if (as->parms[10].items != 0) {
235         char *interface = as->parms[10].items->data;
236
237         if (osi_audit_interface(interface)) {
238             printf("Invalid audit interface '%s'\n", interface);
239             BUDB_EXIT(-1);
240         }
241     }
242
243     /* -auditlog */
244     /* needs to be after -audit-interface, so we osi_audit_interface
245      * before we osi_audit_file */
246     if (as->parms[7].items != 0) {
247         char *fileName = as->parms[7].items->data;
248
249         osi_audit_file(fileName);
250     }
251
252     return 0;
253 }
254
255 /* --- */
256
257 int
258 parseServerList(struct cmd_item *itemPtr)
259 {
260     struct cmd_item *save;
261     char **serverArgs;
262     char **ptr;
263     afs_int32 nservers = 0;
264     afs_int32 code = 0;
265
266     save = itemPtr;
267
268     /* compute number of servers in the list */
269     while (itemPtr) {
270         nservers++;
271         itemPtr = itemPtr->next;
272     }
273
274     LogDebug(3, "%d servers\n", nservers);
275
276     /* now can allocate the space for the server arguments */
277     serverArgs = (char **)malloc((nservers + 2) * sizeof(char *));
278     if (serverArgs == 0)
279         ERROR(-1);
280
281     ptr = serverArgs;
282     *ptr++ = "";
283     *ptr++ = "-servers";
284
285     /* now go through and construct the list of servers */
286     itemPtr = save;
287     while (itemPtr) {
288         *ptr++ = itemPtr->data;
289         itemPtr = itemPtr->next;
290     }
291
292     code =
293         ubik_ParseServerList(nservers + 2, serverArgs, &globalConfPtr->myHost,
294                              globalConfPtr->serverList);
295     if (code)
296         ERROR(code);
297
298     /* free space for the server args */
299     free((char *)serverArgs);
300
301   error_exit:
302     return (code);
303 }
304
305 /* truncateDatabase
306  *      truncates just the database file.
307  */
308
309 int
310 truncateDatabase(void)
311 {
312     char *path;
313     afs_int32 code = 0;
314     int fd;
315
316     path =
317         (char *)malloc(strlen(globalConfPtr->databaseDirectory) +
318                        strlen(globalConfPtr->databaseName) +
319                        strlen(globalConfPtr->databaseExtension) + 1);
320     if (path == 0)
321         ERROR(-1);
322
323     /* construct the database name */
324     strcpy(path, globalConfPtr->databaseDirectory);
325     strcat(path, globalConfPtr->databaseName);
326     strcat(path, globalConfPtr->databaseExtension);
327
328     fd = open(path, O_RDWR, 0755);
329     if (!fd) {
330         code = errno;
331     } else {
332         if (ftruncate(fd, 0) != 0) {
333             code = errno;
334         } else
335             close(fd);
336     }
337
338   error_exit:
339     return (code);
340 }
341
342
343 /* --- */
344
345 #include "AFS_component_version_number.c"
346
347 int
348 main(int argc, char **argv)
349 {
350     char *whoami = argv[0];
351     char *dbNamePtr = 0;
352     struct afsconf_cell cellinfo;
353     time_t currentTime;
354     afs_int32 code = 0;
355     afs_uint32 host = ntohl(INADDR_ANY);
356
357     char  clones[MAXHOSTSPERCELL];
358
359     struct rx_service *tservice;
360     struct rx_securityClass **securityClasses;
361     afs_int32 numClasses;
362
363     extern int rx_stackSize;
364
365 #ifdef AFS_NT40_ENV
366     /* initialize winsock */
367     if (afs_winsockInit() < 0) {
368         ReportErrorEventAlt(AFSEVT_SVR_WINSOCK_INIT_FAILED, 0, argv[0], 0);
369         fprintf(stderr, "%s: Couldn't initialize winsock.\n", whoami);
370         exit(1);
371     }
372 #endif
373
374 #ifdef  AFS_AIX32_ENV
375     /*
376      * The following signal action for AIX is necessary so that in case of a
377      * crash (i.e. core is generated) we can include the user's data section
378      * in the core dump. Unfortunately, by default, only a partial core is
379      * generated which, in many cases, isn't too useful.
380      */
381     struct sigaction nsa;
382
383     sigemptyset(&nsa.sa_mask);
384     nsa.sa_handler = SIG_DFL;
385     nsa.sa_flags = SA_FULLDUMP;
386     sigaction(SIGSEGV, &nsa, NULL);
387     sigaction(SIGABRT, &nsa, NULL);
388 #endif
389     osi_audit_init();
390     osi_audit(BUDB_StartEvent, 0, AUD_END);
391
392     initialize_BUDB_error_table();
393     initializeArgHandler();
394
395     /* Initialize dirpaths */
396     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
397 #ifdef AFS_NT40_ENV
398         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
399 #endif
400         afs_com_err(whoami, errno, "; Unable to obtain AFS server directory.");
401         exit(2);
402     }
403
404     memset(globalConfPtr, 0, sizeof(*globalConfPtr));
405
406     /* set default configuration values */
407     strcpy(dbDir, AFSDIR_SERVER_DB_DIRPATH);
408     strcat(dbDir, "/");
409     globalConfPtr->databaseDirectory = dbDir;
410     globalConfPtr->databaseName = DEFAULT_DBPREFIX;
411     strcpy(cellConfDir, AFSDIR_SERVER_ETC_DIRPATH);
412     globalConfPtr->cellConfigdir = cellConfDir;
413
414     /* open the log file */
415 /*
416     globalConfPtr->log = fopen(DEFAULT_LOGNAME,"a");
417     if ( globalConfPtr->log == NULL )
418     {
419         printf("Can't open log file %s - aborting\n", DEFAULT_LOGNAME);
420         BUDB_EXIT(-1);
421     }
422 */
423
424     srandom(1);
425
426 #ifdef AFS_PTHREAD_ENV
427     SetLogThreadNumProgram( rx_GetThreadNum );
428 #endif
429
430     /* process the user supplied args */
431     helpOption = 1;
432     code = cmd_Dispatch(argc, argv);
433     if (code)
434         ERROR(code);
435
436     /* exit if there was a help option */
437     if (helpOption)
438         BUDB_EXIT(0);
439
440     /* open the log file */
441     globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
442     if (globalConfPtr->log == NULL) {
443         printf("Can't open log file %s - aborting\n",
444                AFSDIR_SERVER_BUDBLOG_FILEPATH);
445         BUDB_EXIT(-1);
446     }
447
448     /* keep log closed so can remove it */
449
450     fclose(globalConfPtr->log);
451
452     /* open the cell's configuration directory */
453     LogDebug(4, "opening %s\n", globalConfPtr->cellConfigdir);
454
455     BU_conf = afsconf_Open(globalConfPtr->cellConfigdir);
456     if (BU_conf == 0) {
457         LogError(code, "Failed getting cell info\n");
458         afs_com_err(whoami, code, "Failed getting cell info");
459         ERROR(BUDB_NOCELLS);
460     }
461
462     code = afsconf_GetLocalCell(BU_conf, lcell, sizeof(lcell));
463     if (code) {
464         LogError(0, "** Can't determine local cell name!\n");
465         ERROR(code);
466     }
467
468     if (globalConfPtr->myHost == 0) {
469         /* if user hasn't supplied a list of servers, extract server
470          * list from the cell's database
471          */
472
473         LogDebug(1, "Using server list from %s cell database.\n", lcell);
474
475         code = afsconf_GetExtendedCellInfo (BU_conf, lcell, 0, &cellinfo,
476                                             clones);
477         code =
478             convert_cell_to_ubik(&cellinfo, &globalConfPtr->myHost,
479                                  globalConfPtr->serverList);
480         if (code)
481             ERROR(code);
482     }
483
484     /* initialize ubik */
485     ubik_SetClientSecurityProcs(afsconf_ClientAuth, afsconf_UpToDate, BU_conf);
486     ubik_SetServerSecurityProcs(afsconf_BuildServerSecurityObjects,
487                                 afsconf_CheckAuth, BU_conf);
488
489     if (ubik_nBuffers == 0)
490         ubik_nBuffers = 400;
491
492     LogError(0, "Will allocate %d ubik buffers\n", ubik_nBuffers);
493
494     dbNamePtr =
495         (char *)malloc(strlen(globalConfPtr->databaseDirectory) +
496                        strlen(globalConfPtr->databaseName) + 1);
497     if (dbNamePtr == 0)
498         ERROR(-1);
499
500     /* construct the database name */
501     strcpy(dbNamePtr, globalConfPtr->databaseDirectory);
502     strcat(dbNamePtr, globalConfPtr->databaseName);     /* name prefix */
503
504     rx_SetRxDeadTime(60);       /* 60 seconds inactive before timeout */
505
506     if (rxBind) {
507         afs_int32 ccode;
508         if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
509             AFSDIR_SERVER_NETINFO_FILEPATH) {
510             char reason[1024];
511             ccode = parseNetFiles(SHostAddrs, NULL, NULL,
512                                            ADDRSPERSITE, reason,
513                                            AFSDIR_SERVER_NETINFO_FILEPATH,
514                                            AFSDIR_SERVER_NETRESTRICT_FILEPATH);
515         } else
516         {
517             ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
518         }
519         if (ccode == 1) {
520             host = SHostAddrs[0];
521             rx_InitHost(host, htons(AFSCONF_BUDBPORT));
522         }
523     }
524
525     code = ubik_ServerInitByInfo (globalConfPtr->myHost,
526                                   htons(AFSCONF_BUDBPORT),
527                                   &cellinfo,
528                                   clones,
529                                   dbNamePtr,           /* name prefix */
530                                   &BU_dbase);
531
532     if (code) {
533         LogError(code, "Ubik init failed\n");
534         afs_com_err(whoami, code, "Ubik init failed");
535         ERROR(code);
536     }
537
538     afsconf_BuildServerSecurityObjects(BU_conf, &securityClasses, &numClasses);
539
540     /* Disable jumbograms */
541     rx_SetNoJumbo();
542
543     tservice =
544         rx_NewServiceHost(host, 0, BUDB_SERVICE, "BackupDatabase",
545                           securityClasses, numClasses, BUDB_ExecuteRequest);
546
547     if (tservice == (struct rx_service *)0) {
548         LogError(0, "Could not create backup database rx service\n");
549         printf("Could not create backup database rx service\n");
550         BUDB_EXIT(3);
551     }
552     rx_SetMinProcs(tservice, 1);
553     rx_SetMaxProcs(tservice, lwps);
554     rx_SetStackSize(tservice, 10000);
555
556     /* allow super users to manage RX statistics */
557     rx_SetRxStatUserOk(BU_rxstat_userok);
558
559     /* misc. initialization */
560
561     /* database dump synchronization */
562     memset(dumpSyncPtr, 0, sizeof(*dumpSyncPtr));
563     Lock_Init(&dumpSyncPtr->ds_lock);
564
565     rx_StartServer(0);          /* start handling requests */
566
567     code = InitProcs();
568     if (code)
569         ERROR(code);
570
571
572     currentTime = time(0);
573     LogError(0, "Ready to process requests at %s\n", ctime(&currentTime));
574
575     rx_ServerProc(NULL);                /* donate this LWP */
576
577   error_exit:
578     osi_audit(BUDB_FinishEvent, code, AUD_END);
579     return (code);
580 }
581
582 void
583 consistencyCheckDb(void)
584 {
585     /* do consistency checks on structure sizes */
586     if ((sizeof(struct htBlock) > BLOCKSIZE)
587         || (sizeof(struct vfBlock) > BLOCKSIZE)
588         || (sizeof(struct viBlock) > BLOCKSIZE)
589         || (sizeof(struct dBlock) > BLOCKSIZE)
590         || (sizeof(struct tBlock) > BLOCKSIZE)
591         ) {
592         fprintf(stderr, "Block layout error!\n");
593         BUDB_EXIT(99);
594     }
595 }
596
597 void
598 LogDebug(int level, char *fmt, ... )
599 {
600     va_list ap;
601
602     va_start(ap, fmt);
603
604     if (debugging >= level) {
605         /* log normally closed so can remove it */
606         globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
607         if (globalConfPtr->log != NULL) {
608             vfprintf(globalConfPtr->log, fmt, ap);
609             fflush(globalConfPtr->log);
610             fclose(globalConfPtr->log);
611         }
612     }
613     va_end(ap);
614 }
615
616 static char *
617 TimeStamp(time_t t)
618 {
619     struct tm *lt;
620     static char timestamp[20];
621
622     lt = localtime(&t);
623     strftime(timestamp, 20, "%m/%d/%Y %H:%M:%S", lt);
624     return timestamp;
625 }
626
627 void
628 Log(char *fmt, ...)
629 {
630     va_list ap;
631     time_t now;
632
633     va_start(ap, fmt);
634     globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
635     if (globalConfPtr->log != NULL) {
636         now = time(0);
637         fprintf(globalConfPtr->log, "%s ", TimeStamp(now));
638
639         vfprintf(globalConfPtr->log, fmt, ap);
640         fflush(globalConfPtr->log);
641         fclose(globalConfPtr->log);
642     }
643     va_end(ap);
644 }
645
646 void
647 LogError(long code, char *fmt, ... )
648 {
649     va_list ap;
650     time_t now;
651
652     va_start(ap, fmt);
653     globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
654
655     if (globalConfPtr->log != NULL) {
656         now = time(0);
657         fprintf(globalConfPtr->log, "%s ", TimeStamp(now));
658
659         if (code)
660             fprintf(globalConfPtr->log, "%s: %s\n", afs_error_table_name(code),
661                     afs_error_message(code));
662         vfprintf(globalConfPtr->log, fmt, ap );
663         fflush(globalConfPtr->log);
664         fclose(globalConfPtr->log);
665     }
666 }
667
668
669 /*  ----------------
670  * debug
671  * ----------------
672  */
673
674 void
675 LogNetDump(struct dump *dumpPtr)
676 {
677     struct dump hostDump;
678     extern buServerConfP globalConfPtr;
679
680     dump_ntoh(dumpPtr, &hostDump);
681
682     globalConfPtr->log = fopen(AFSDIR_SERVER_BUDBLOG_FILEPATH, "a");
683     if (globalConfPtr->log != NULL) {
684         printDump(globalConfPtr->log, &hostDump);
685         fclose(globalConfPtr->log);
686     }
687 }
688