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