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