include-afsconfig-before-param-h-20010712
[openafs.git] / src / butc / tcmain.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 #include <sys/types.h>
16 #include <sys/stat.h>
17 #ifdef AFS_NT40_ENV
18 #include <winsock2.h>
19 #include <WINNT/afsevent.h>
20 #else
21 #include <netinet/in.h>
22 #include <sys/time.h>
23 #endif
24 #include <afs/procmgmt.h>
25 #include <rx/xdr.h>
26 #include <afs/afsint.h>
27 #include <stdio.h>
28 #ifdef AFS_PTHREAD_ENV
29 #include <assert.h>
30 #else
31 #include <afs/assert.h>
32 #endif
33 #include <afs/prs_fs.h>
34 #include <afs/nfs.h>
35 #include <string.h>
36 #include <afs/vlserver.h>
37 #include <lwp.h>
38 #include <lock.h>
39 #include <afs/afsutil.h>
40 #include <rx/rx.h>
41 #include <rx/rx_globals.h>
42 #include <afs/auth.h>
43 #include <rx/rxkad.h>
44 #include <afs/cellconfig.h>
45 #include <afs/keys.h>
46 #include <afs/volser.h>
47 #include <ubik.h>
48 #include <afs/com_err.h>
49 #include <errno.h>
50 #include <afs/cmd.h>
51 #include <afs/tcdata.h>
52 #include <afs/bubasics.h>
53 #include <ctype.h>
54 #include "error_macros.h"
55 #include <afs/budb_errs.h>
56 #include "afs/butx.h"
57 #include "butc_xbsa.h"
58
59 #define N_SECURITY_OBJECTS 3
60 #define ERRCODE_RANGE 8                 /* from error_table.h */
61
62 #define TE_PREFIX  "TE"
63 #define TL_PREFIX  "TL"
64 #define CFG_PREFIX "CFG"
65
66 struct ubik_client *cstruct;
67 extern void TC_ExecuteRequest();
68 extern int  dbWatcher();
69 extern struct rx_securityClass *rxnull_NewServerSecurityObject();
70 extern struct rx_service *rx_NewService();
71 FILE *logIO, *ErrorlogIO, *centralLogIO, *lastLogIO;
72 char lFile[AFSDIR_PATH_MAX];
73 char logFile[256];
74 char ErrorlogFile[256];
75 char lastLogFile[256];
76 char eFile[AFSDIR_PATH_MAX];
77 char tapeConfigFile[AFSDIR_PATH_MAX]; 
78 char pFile[AFSDIR_PATH_MAX];
79 int debugLevel = 0;
80 struct tapeConfig globalTapeConfig;
81 struct deviceSyncNode *deviceLatch;
82 char globalCellName[64];
83 char *whoami = "butc";
84
85 /* GLOBAL CONFIGURATION PARAMETERS */
86 int dump_namecheck;
87 int queryoperator;
88 int autoQuery;
89 int isafile;
90 int tapemounted;
91 char *opencallout;
92 char *closecallout;
93 char *restoretofile;
94 int  forcemultiple;
95
96 /* XBSA Global Parameters */
97 afs_int32 xbsaType;
98 #ifdef xbsa
99 struct butx_transactionInfo butxInfo;
100
101 #define rpc_c_protect_level_default 0
102 afs_uint32 dumpRestAuthnLevel = rpc_c_protect_level_default;
103 char *xbsaObjectOwner;
104 char *appObjectOwner;
105 char *adsmServerName;
106 char *xbsaSecToken;
107 char *xbsalGName;
108 #endif
109
110 int maxpass;
111 #define PASSESMIN  1
112 #define PASSESMAX  10
113 #define PASSESDFLT 2
114 afs_int32 groupId;
115 #define MINGROUPID 0x1
116 #define MAXGROUPID 0x7FFFFFFF
117 afs_int32 statusSize;
118 #define MINSTATUS  1
119 #define MAXSTATUS  0x7fffffff
120 afs_int32 BufferSize;     /* Size in B stored for data */
121 char *centralLogFile;
122 afs_int32 lastLog;           /* Log last pass info */
123
124 /* dummy routine for the audit work.  It should do nothing since audits */
125 /* occur at the server level and bos is not a server. */
126 osi_audit() {return 0;}
127
128 static afs_int32 SafeATOL(anum)
129 register char *anum; {
130     register afs_int32 total;
131     register int tc;
132
133     total = 0;
134     while(tc = *anum) {
135         if (tc < '0' || tc > '9') return -1;
136         total *= 10;
137         total += (tc - '0');
138         anum++;
139     }
140     return total;
141 }
142
143 /* atocl
144  *      Convert a string into an afs_int32.
145  *      Returned afs_int32 is in Bytes, Kb, Mb, Gb, or Tb. Based on crunit char.
146  *      This routine only converts unsigned float values.
147  *      The returned value is a whole number.
148  * entry:
149  *      numstring - text string to be converted.
150  *      crunit - value returned in 'B', 'K', 'M', 'G', 'T'.
151  *               ' ' or NULL ==> 'B' (bytes).
152  * exit:
153  *      number - returned value in requested crunit - rounded
154  *               to nearest whole number.
155  * fn return value:
156  *       0 - conversion ok
157  *      -1 - error in conversion
158  * notes:
159  *      should deal with signed numbers. Should signal error if no digits
160  *      seen.
161  */
162 atocl(numstring, crunit, number)
163      char *numstring;
164      char  crunit;         /* Units to report number in */
165      afs_int32 *number;
166 {
167     float total;
168     afs_int32 runits;
169     char  cunit;
170     afs_int32 units;
171     afs_int32 count;
172     char rest[256];
173
174     /* Determine which units to report in */
175     switch ( crunit ) {
176       case 't':
177       case 'T':
178         runits = 12;
179         break;
180
181       case 'g':
182       case 'G':
183         runits = 9;
184         break;
185
186       case 'm':
187       case 'M':
188         runits = 6;
189         break;
190
191       case 'k':
192       case 'K':
193         runits = 3;
194         break;
195
196       case 'b':
197       case 'B':
198       case ' ':
199       case 0:
200         runits = 0;
201         break;
202
203       default:
204         return(-1);
205     }
206
207     count = sscanf(numstring, "%f%c%s", (unsigned char *)&total, &cunit, rest);
208     if ((count > 2) || (count <= 0))
209        return -1;
210     if (count == 1)
211        cunit = 'B';        /* bytes */
212
213     switch ( cunit ) {
214       case 't':
215       case 'T':
216         units = 12;
217         break;
218
219       case 'g':
220       case 'G':
221         units = 9;
222         break;
223
224       case 'm':
225       case 'M':
226         units = 6;
227         break;
228
229       case 'k':
230       case 'K':
231         units = 3;
232         break;
233
234       case 'b':
235       case 'B':
236       case ' ':
237       case 0:
238         units = 0;
239         break;
240
241       default:
242         return(-1);
243     }
244
245     /* Go to correct unit */
246     for (; units < runits; units += 3)
247        total /= 1024.0;
248     for (; units > runits; units -= 3)
249        total *= 1024.0;
250
251     total += 0.5;              /* Round up */   
252     if ((total > 0x7fffffff) || (total < 0))    /* Don't go over 2G */
253        total = 0x7fffffff;
254
255     *number = total;
256     return(0);
257 }
258
259 /* replace last two ocurrences of / by _ */
260 static stringReplace(name)
261 char *name;
262 {
263     char *pos;
264     int i;
265     char buffer[256];
266
267     pos = strrchr(name,'/');
268     *pos = '_';
269     strcpy(buffer,pos);
270     pos = strrchr(name,'/');
271     *pos = '\0';
272     strcat(name,buffer);
273     return 0;
274 }
275
276 static stringNowReplace (logFile, deviceName)
277 char *logFile, *deviceName;
278
279 {
280     char *pos = 0;
281     char storeDevice[256];
282     int mvFlag = 0, devPrefLen;
283 #ifdef AFS_NT40_ENV
284     char devPrefix[] = "\\\\.";
285 #else
286     char devPrefix[] = "/dev";
287 #endif
288
289     devPrefLen = strlen(devPrefix);
290     strcpy(storeDevice, deviceName);
291     if (strncmp(deviceName, devPrefix, devPrefLen) == 0) {
292         deviceName += devPrefLen;
293         mvFlag++;
294     }
295     while (pos = strchr(deviceName, devPrefix[0])) /* look for / or \ */
296         *pos = '_';
297     strcat (logFile, deviceName);
298     /* now put back deviceName to the way it was */
299     if (mvFlag) {
300         mvFlag = 0;
301         deviceName -= devPrefLen;
302     }
303     strcpy (deviceName, storeDevice);
304
305     return (0);
306 }
307
308
309 /* GetDeviceConfig
310  *      get the configuration information for a particular tape device
311  *      as specified by the portoffset
312  * entry:
313  *      filename - full pathname of file containing the tape device
314  *              configuration information
315  *      config - for return results
316  *      portOffset - for which configuration is required
317  * notes:
318  *      logging not available when this routine is called
319  *      caller return value checks
320  * exit:
321  *      0 => Found entry with same port, return info in config.
322  *     -1 => Error encountered trying to read the file.
323  *      1 => Desired entry does not exist or file does not exist.
324  */
325
326 #define LINESIZE        256
327 static afs_int32 GetDeviceConfig(filename, config, portOffset)
328      char *filename;
329      struct tapeConfig *config;
330      afs_int32 portOffset;
331 {
332     FILE *devFile=0;
333     char line[LINESIZE];
334     char devName[LINESIZE], tcapacity[LINESIZE],
335          tfmsize[LINESIZE], trest[LINESIZE];
336     afs_int32 aport;
337     afs_uint32 capacity;
338     afs_uint32 fmSize;
339     afs_int32 code=0, count;
340
341     /* Initialize the config struct */
342     config->capacity     = 0;
343     config->fileMarkSize = 0;
344     config->portOffset   = portOffset;
345     strcpy(config->device, "");
346
347     devFile = fopen(filename,"r");
348     if (!devFile) {
349         if (errno == ENOENT) ERROR_EXIT(1);
350         fprintf(stderr, "Error %d: Can't open %s\n", errno, filename);
351         ERROR_EXIT(-1);
352     }
353
354     while ( fgets(line,LINESIZE-1,devFile) ) {
355         count = sscanf(line, "%s %s %s %u%s\n",
356                       tcapacity, tfmsize, devName, &aport, trest);
357
358         if (count == 4) {
359             if ( atocl(tcapacity, 'K', &capacity) ) {
360                fprintf(stderr, "tapeconfig: Tape capacity parse error in: %s\n", line);
361                ERROR_EXIT(-1);
362             }
363             if ( atocl(tfmsize, 'B', &fmSize) ) {
364                 fprintf(stderr, "tapeconfig: File-mark size parse error in: %s\n", line);
365                 ERROR_EXIT(-1);
366             }
367         } else {
368             count = sscanf(line, "%s %u%s\n", devName, &aport, trest);
369             if (count == 2) {
370                 capacity = 0x7fffffff;
371                 fmSize = 0;
372             } else {
373                 fprintf(stderr, "tapeconfig: Parse error in: %s\n", line);
374                 ERROR_EXIT(-1);
375             }
376         }
377
378         if ((aport < 0) || (aport > BC_MAXPORTOFFSET)) {
379             fprintf(stderr, "tapeconfig: Port offset parse error in: %s\n", line);
380             ERROR_EXIT(-1);
381         }
382
383         if (aport != portOffset)
384             continue;
385
386         if (fmSize < 0) {
387            fprintf(stderr, "Invalid file mark size, %d, in: %s\n", fmSize, line);
388            ERROR_EXIT(-1);
389         }
390
391         config->capacity     = capacity;
392         config->fileMarkSize = fmSize;
393         config->portOffset   = aport;
394         strncpy(config->device, devName, 100);
395
396         ERROR_EXIT(0);
397     }
398
399     /* fprintf(stderr, "Can't find tapeconfig entry for port offset %d\n", portOffset); */
400     ERROR_EXIT(1);
401
402   error_exit:
403     if (devFile) fclose(devFile);
404     return(code);
405 }
406
407 /* GetConfigParams
408  */
409 static afs_int32 GetConfigParams(filename, port)
410     char *filename;
411     afs_int32 port;
412 {
413     char paramFile[256];
414     FILE *devFile=0;
415     char line[LINESIZE], cmd[LINESIZE], value[LINESIZE];
416     afs_int32 code=0;
417     int cnt;
418
419     /* DEFAULT SETTINGS FOR GLOBAL PARAMETERS */
420     dump_namecheck = 1;                   /* check tape name on dumps */
421     queryoperator  = 1;                   /* can question operator */
422     autoQuery      = 1;                   /* prompt for first tape */
423     isafile        = 0;                   /* Do not dump to a file */
424     opencallout    = (char *)0;           /* open  callout routine */
425     closecallout   = (char *)0;           /* close callout routine */
426     tapemounted    = 0;                   /* tape is not mounted */
427 #ifdef xbsa
428     BufferSize     = (CONF_XBSA ? XBSADFLTBUFFER : BUTM_BLOCKSIZE);
429     dumpRestAuthnLevel = rpc_c_protect_level_default;   
430     xbsaObjectOwner  = (char *)0;         /* bsaObjectOwner */
431     appObjectOwner   = (char *)0;         /* appObjectOwner */
432     adsmServerName   = (char *)0;         /* TSM server name - same as ADSM */
433     xbsaSecToken     = (char *)0;         /* XBSA sercurity token */
434     xbsalGName       = (char *)0;         /* XBSA IGName */
435 #else
436     BufferSize     = BUTM_BLOCKSIZE;
437 #endif /*xbsa*/
438     centralLogFile   = (char *)0;         /* Log for all butcs */
439     centralLogIO = 0;                     /* Log for all butcs */
440     statusSize   = 0;                     /* size before status message */
441     maxpass      = PASSESDFLT;            /* dump passes */
442     lastLog      = 0;                     /* separate log for last pass */
443     lastLogIO    = 0;                     /* separate log for last pass */
444     groupId      = 0;                     /* Group id for multiple dumps */
445
446     /* Try opening the CFG_<port> file */
447     sprintf(paramFile,    "%s_%d", filename, port);
448     devFile = fopen(paramFile, "r");
449     if (devFile) {
450        /* Set log names to TL_<port>, TL_<port>.lp and TE_<port> */
451        sprintf(logFile,      "%s_%d",    lFile, port);
452        sprintf(lastLogFile,  "%s_%d.lp", lFile, port);
453        sprintf(ErrorlogFile, "%s_%d",    eFile, port);
454     } else if (CONF_XBSA) {
455        /* If configured as XBSA, a configuration file CFG_<port> must exist */
456        printf("Cannot open configuration file %s", paramFile);
457        ERROR_EXIT(1);
458     } else {
459        /* Try the CFG_<device> name as the device file */
460        strcpy(paramFile, filename);
461        stringNowReplace(paramFile, globalTapeConfig.device);
462        /* Set log names to TL_<device>, TL_<device> and TE_<device> */
463        strcpy(logFile,lFile);
464        stringNowReplace(logFile,globalTapeConfig.device);
465        strcpy(lastLogFile,lFile);
466        stringNowReplace(lastLogFile,globalTapeConfig.device);
467        strcat(lastLogFile, ".lp");
468        strcpy(ErrorlogFile,eFile);
469        stringNowReplace(ErrorlogFile, globalTapeConfig.device);
470
471        /* Now open the device file */
472        devFile = fopen(paramFile, "r");
473        if (!devFile)
474           ERROR_EXIT(0);/* CFG file doesn't exist for non-XBSA and that's ok */
475     }
476
477     /* Read each line of the Configuration file */
478     while (fgets(line,LINESIZE-1,devFile)) {
479         cnt = sscanf(line, "%s %s", cmd, value);
480         if (cnt != 2)
481         {
482             if (cnt > 0)
483                 printf("Bad line in %s: %s\n", paramFile, line);
484             continue;
485         }
486           
487         for (cnt=0; cnt<strlen(cmd); cnt++)
488           if (islower(cmd[cnt])) cmd[cnt] = toupper(cmd[cnt]);
489
490         if (!strcmp(cmd,"NAME_CHECK"))
491         {
492             if (CONF_XBSA) {
493                 printf("Warning: The %s parameter is ignored with a Backup Service\n", cmd);
494                 continue;
495             }
496
497             for (cnt=0; cnt<strlen(value); cnt++)
498                 if (islower(value[cnt])) value[cnt] = toupper(value[cnt]);
499
500             if (!strcmp(value,"NO"))
501             {
502                 printf("Dump tape name check is disabled\n");
503                 dump_namecheck = 0;
504             }
505             else
506             {
507                 printf("Dump tape name check is enabled\n");
508                 dump_namecheck = 1;
509             }
510         }
511
512         else if (!strcmp(cmd,"MOUNT"))
513         {
514             if (CONF_XBSA) {
515                 printf("Warning: The %s parameter is ignored with a Backup Service\n", cmd);
516                 continue;
517             }
518
519             opencallout = (char*)malloc(strlen(value)+1);
520             strcpy(opencallout, value);
521             printf("Tape mount callout routine is %s\n", opencallout);
522         }
523           
524         else if (!strcmp(cmd,"UNMOUNT"))
525         {
526             if (CONF_XBSA) {
527                 printf("Warning: The %s parameter is ignored with a Backup Service\n", cmd);
528                 continue;
529             }
530
531             closecallout = (char*)malloc(strlen(value)+1);
532             strcpy(closecallout, value);
533             printf("Tape unmount callout routine is %s\n", closecallout);
534         }
535
536         else if (!strcmp(cmd,"ASK"))
537         {
538             for (cnt=0; cnt<strlen(value); cnt++)
539                 if (islower(value[cnt])) value[cnt] = toupper(value[cnt]);
540
541             if (!strcmp(value,"NO"))
542             {
543                 printf("Operator queries are disabled\n");
544                 queryoperator = 0;
545             }
546             else
547             {
548                 printf("Operator queries are enabled\n");
549                 queryoperator = 1;
550             }
551         }
552
553         else if (!strcmp(cmd,"FILE"))
554         {
555             if (CONF_XBSA) {
556                 printf("Warning: The %s parameter is ignored with a Backup Service\n", cmd);
557                 continue;
558             }
559
560             for (cnt=0; cnt<strlen(value); cnt++)
561                 if (islower(value[cnt])) value[cnt] = toupper(value[cnt]);
562
563             if (!strcmp(value,"YES"))
564             {
565                 printf("Will dump to a file\n");
566                 isafile = 1;
567             }
568             else
569             {
570                 printf("Will not dump to a file\n");
571                 isafile = 0;
572             }
573         }
574
575         else if (!strcmp(cmd,"AUTOQUERY"))
576         {
577             if (CONF_XBSA) {
578                 printf("Warning: The %s parameter is ignored with a Backup Service\n", cmd);
579                 continue;
580             }
581
582             for (cnt=0; cnt<strlen(value); cnt++)
583                 if (islower(value[cnt])) value[cnt] = toupper(value[cnt]);
584
585             if (!strcmp(value,"NO"))
586             {
587                 printf("Auto query is disabled\n");
588                 autoQuery = 0;
589             }
590             else
591             {
592                 printf("Auto query is enabled\n");
593                 autoQuery = 1;
594             }
595         }
596
597         else if (!strcmp(cmd,"BUFFERSIZE"))
598         {
599             afs_int32 size;
600             afs_int32 tapeblocks;
601
602             if (!CONF_XBSA) {
603                if ( atocl(value, 'K', &size) ) {
604                   fprintf(stderr, "BUFFERSIZE parse error\n");
605                   size = 0;
606                }
607
608                /* A tapeblock is 16KB. Determine # of tapeblocks. Then
609                 * determine BufferSize needed for that many tapeblocks.
610                 */
611                tapeblocks = size / 16;
612                if (tapeblocks <= 0) tapeblocks = 1;
613                printf("BUFFERSIZE is %u KBytes\n", (tapeblocks*16));
614                BufferSize = tapeblocks * BUTM_BLOCKSIZE;
615             } else {
616 #ifdef xbsa
617                if ( atocl(value, 'B', &size) ) {
618                   fprintf(stderr, "BUFFERSIZE parse error\n");
619                   size = 0;
620                }
621                if (size < XBSAMINBUFFER) size = XBSAMINBUFFER;
622                if (size > XBSAMAXBUFFER) size = XBSAMAXBUFFER;
623                printf("XBSA buffer size is %u Bytes\n", size);
624                BufferSize = size;
625 #endif
626             }
627         }
628
629
630
631
632 #ifndef xbsa
633         /* All the xbsa spacific parameters */
634         else if (!strcmp(cmd,"TYPE")     || !strcmp(cmd,"NODE")     ||
635                  !strcmp(cmd,"SERVER")   || !strcmp(cmd,"PASSWORD") ||
636                  !strcmp(cmd,"PASSFILE") || !strcmp(cmd,"MGMTCLASS"))
637         {
638             printf("This binary does not have XBSA support\n");
639             return 1;
640         }
641 #else
642         else if (!strcmp(cmd,"TYPE"))   /* required for XBSA */
643         {
644             if (!CONF_XBSA) {
645                 printf("Warning: The %s parameter is ignored with a tape drive\n", cmd);
646                 continue;
647             }
648
649             for (cnt=0; (size_t)cnt<strlen(value); cnt++)
650                 if (islower(value[cnt])) value[cnt] = toupper(value[cnt]);
651
652             if (strcmp(value,"TSM") == 0) {
653                 xbsaType = XBSA_SERVER_TYPE_ADSM;     /* Known XBSA server type */
654             } else {
655                 printf("Configuration file error, %s %s is not recognized\n", cmd, value);
656                 xbsaType = XBSA_SERVER_TYPE_UNKNOWN;
657             }
658             printf("XBSA type is %s\n", 
659                    ((xbsaType == XBSA_SERVER_TYPE_UNKNOWN)?"Unknown":value));
660         }
661
662         else if (!strcmp(cmd,"NODE"))
663         {
664             if (!CONF_XBSA) {
665                 printf("Warning: The %s parameter is ignored with a tape drive\n", cmd);
666                 continue;
667             }
668             xbsaObjectOwner = malloc(strlen(value)+1);
669             strcpy(xbsaObjectOwner, value);
670             printf("XBSA node is %s\n", xbsaObjectOwner);
671         }
672
673         else if (!strcmp(cmd,"SERVER")) /* required for XBSA */
674         {
675             if (!CONF_XBSA) {
676                 printf("Warning: The %s parameter is ignored with a tape drive\n", cmd);
677                 continue;
678             }
679             adsmServerName = malloc(strlen(value)+1);
680             strcpy(adsmServerName, value);
681             printf("XBSA server is %s\n", adsmServerName);
682         }
683
684         else if (!strcmp(cmd,"PASSWORD"))  /* This or PASSFILE required for XBSA */
685         {
686             if (!CONF_XBSA) {
687                 printf("Warning: The %s parameter is ignored with a tape drive\n", cmd);
688                 continue;
689             }
690             if (xbsaSecToken) {
691                 printf("Warning: The %s parameter is ignored. Already read password\n", cmd);
692                 continue;
693             }
694
695             xbsaSecToken = malloc(strlen(value)+1);
696             strcpy(xbsaSecToken, value);
697             printf("XBSA Password has been read\n");
698         }
699
700         else if (!strcmp(cmd,"PASSFILE"))  /* This or PASSWORD required for XBSA */
701         {
702             FILE *pwdFile;
703             if (!CONF_XBSA) {
704                 printf("Warning: The %s parameter is ignored with a tape drive\n", cmd);
705                 continue;
706             }
707             if (xbsaSecToken) {
708                 printf("Warning: The %s parameter is ignored. Already read password\n", cmd);
709                 continue;
710             }
711             
712             pwdFile = fopen(value,"r");
713             if (!pwdFile) {
714                printf("Configuration file error, cannot open password file %s\n", value);
715                ERROR_EXIT(1);
716             }
717             xbsaSecToken = malloc(LINESIZE);
718             if (!fscanf(pwdFile, "%s", xbsaSecToken)) {
719                printf("Configuration file error, cannot read password file %s\n", value);
720                ERROR_EXIT(1);
721             }
722             printf("XBSA password retrieved from password file\n");
723         }
724
725         else if (!strcmp(cmd,"MGMTCLASS")) /* XBSA */
726         {
727             if (!CONF_XBSA) {
728                 printf("Warning: The %s parameter is ignored with a tape drive\n", cmd);
729                 continue;
730             }
731             xbsalGName = malloc(strlen(value)+1);
732             strcpy(xbsalGName, value);
733             printf("XBSA management class is %s\n", xbsalGName);
734         }
735 #endif
736
737         else if (!strcmp(cmd,"MAXPASS"))
738         {
739             maxpass = SafeATOL(value);
740             if (maxpass < PASSESMIN) maxpass = PASSESMIN;
741             if (maxpass > PASSESMAX) maxpass = PASSESMAX;
742             printf("MAXPASS is %d\n", maxpass);
743         }
744
745         else if (!strcmp(cmd,"GROUPID"))
746         {
747             groupId = SafeATOL(value);
748             if ((groupId < MINGROUPID) || (groupId > MAXGROUPID)) {
749                 printf("Configuration file error, %s %s is invalid\n", cmd, value);
750                 ERROR_EXIT(1);
751             }
752             printf("Group Id is %d\n", groupId);
753         }
754
755         else if (!strcmp(cmd,"LASTLOG"))
756         {
757             for (cnt=0; (size_t)cnt<strlen(value); cnt++)
758                 if (islower(value[cnt])) value[cnt] = toupper(value[cnt]);
759
760             lastLog = (strcmp(value,"YES") == 0);
761             printf("Will %sgenerate a last log\n", (lastLog?"":"not "));
762         }
763
764         else if (!strcmp(cmd,"CENTRALLOG"))
765         {
766             centralLogFile = malloc(strlen(value)+1);
767             strcpy(centralLogFile, value);
768             printf("Central log file is %s\n", centralLogFile);
769         }
770
771         else if (!strcmp(cmd,"STATUS"))
772         {
773             if (atocl(value, 'B', &statusSize)) {
774                fprintf(stderr, "STATUS parse error\n");
775                statusSize = 0;
776             }
777             if (statusSize < MINSTATUS) statusSize = MINSTATUS;
778             if (statusSize > MAXSTATUS) statusSize = MAXSTATUS;
779         }
780
781         else {
782            printf("Warning: Unrecognized configuration parameter: %s", line);
783         }
784     } /*fgets*/
785
786     if (statusSize) {
787        /* Statussize is in bytes and requires that BufferSize be set first */
788        statusSize *= BufferSize;
789        if (statusSize < 0) statusSize = 0x7fffffff; /*max size*/
790        printf("Status every %ld Bytes\n", statusSize);
791     }
792
793   error_exit:
794     if (devFile) fclose(devFile);
795
796     /* If the butc is configured as XBSA, check for required parameters */
797 #ifdef xbsa
798     if (!code && CONF_XBSA) {
799        if (xbsaType == XBSA_SERVER_TYPE_UNKNOWN) {
800           printf("Configuration file error, the TYPE parameter must be specified, or\n");
801           printf("an entry must exist in %s for port %d\n", tapeConfigFile, port);
802           code = 1;
803        }
804        if (!adsmServerName) {
805           printf("Configuration file error, the SERVER parameter must be specified\n");
806           code = 1;
807        }
808        if (!xbsaSecToken) {
809           printf("Configuration file error, the PASSWORD or PASSFILE parameter must be specified\n");
810           code = 1;
811        }
812     }
813 #endif /*xbsa*/
814     return(code);
815 }
816
817 static WorkerBee(as, arock)
818 struct cmd_syndesc *as;
819 char *arock; {
820     char *pid;
821     register afs_int32 code;
822     struct rx_securityClass *(securityObjects[3]);
823     struct rx_service *service;
824     struct ktc_token ttoken;
825     char cellName[64];
826     int localauth;
827     /*process arguments */
828     afs_int32 portOffset = 0;
829     afs_int32 logIOName;
830 #ifdef AFS_PTHREAD_ENV
831     pthread_t dbWatcherPid;
832     pthread_attr_t tattr;
833     AFS_SIGSET_DECL;
834 #else
835     PROCESS dbWatcherPid;
836 #endif
837
838     debugLevel = 0;
839
840     /*initialize the error tables */
841     initialize_ka_error_table();
842     initialize_rxk_error_table();
843     initialize_ktc_error_table();
844     initialize_acfg_error_table();
845     initialize_cmd_error_table();
846     initialize_vl_error_table();
847     initialize_butm_error_table();
848     initialize_butc_error_table();
849 #ifdef xbsa
850     initialize_butx_error_table();
851 #endif /*xbs*/
852     initialize_vols_error_table();
853     initialize_budb_error_table();
854     initialize_bucd_error_table();
855
856     if (as->parms[0].items)
857     {
858         portOffset = SafeATOL(as->parms[0].items->data);
859         if (portOffset == -1)
860         {
861             fprintf(stderr, "Illegal port offset '%s'\n", as->parms[0].items->data);
862             exit(1);
863         }
864         else if (portOffset > BC_MAXPORTOFFSET)
865         {
866             fprintf(stderr, "%u exceeds max port offset %u\n", portOffset, BC_MAXPORTOFFSET);
867             exit(1);
868         }
869     }
870     
871     xbsaType = XBSA_SERVER_TYPE_NONE; /* default */
872     if (as->parms[3].items) {                           /* -device */
873        globalTapeConfig.capacity     = 0x7fffffff;      /* 2T for max tape capacity */
874        globalTapeConfig.fileMarkSize = 0;
875        globalTapeConfig.portOffset   = portOffset;
876        strncpy(globalTapeConfig.device, as->parms[3].items->data, 100);
877        xbsaType = XBSA_SERVER_TYPE_NONE;                /* Not XBSA */
878     } else {
879        /* Search for an entry in tapeconfig file */
880        code = GetDeviceConfig(tapeConfigFile, &globalTapeConfig, portOffset);
881        if (code == -1) {
882           fprintf(stderr, "Problem in reading config file %s\n", tapeConfigFile);
883           exit(1);
884        }
885        /* Set xbsaType. If code == 1, no entry was found in the tapeconfig file so
886         * it's an XBSA server. Don't know if its ADSM or not so its unknown.
887         */
888        xbsaType = ((code == 1) ? XBSA_SERVER_TYPE_UNKNOWN : XBSA_SERVER_TYPE_NONE);
889     }
890
891     if (as->parms[6].items) {                           /* -restoretofile */
892        int s = strlen(as->parms[6].items->data);
893        restoretofile = malloc(s+1);
894        strncpy(restoretofile, as->parms[6].items->data, s+1);
895        printf("Restore to file '%s'\n", restoretofile);
896     }
897
898     /* Go and read the config file: CFG_<device> or CFG_<port>. We will also set
899      * the exact xbsaType within the call (won't be unknown) - double check.
900      */
901     code = GetConfigParams(pFile, portOffset);
902     if (code) exit(code);
903 #ifdef xbsa
904     if (xbsaType == XBSA_SERVER_TYPE_UNKNOWN) {
905        printf("\nConfiguration file error, the TYPE parameter must be specified, or\n");
906        printf("an entry must exist in %s for port %d\n", tapeConfigFile, portOffset);
907        exit(1);
908     }
909 #else
910     /* Not compiled for XBSA code so we can't support it */
911     if (CONF_XBSA) {
912        printf("\nNo entry found in %s for port %d\n", tapeConfigFile, portOffset);
913        printf("This binary does not have XBSA support\n");
914        exit(1);
915     }
916 #endif
917
918     /* Open the log files. The pathnames were set in GetConfigParams() */
919     logIO = fopen(logFile,"a");
920     if(!logIO){
921         fprintf(stderr,"Failed to open %s\n",logFile);
922         exit(1);
923     }
924     ErrorlogIO = fopen(ErrorlogFile,"a");
925     if(!ErrorlogIO){
926         fprintf(stderr,"Failed to open %s\n",ErrorlogFile);
927         exit(1);
928     }
929     if (lastLog) {
930        lastLogIO = fopen(lastLogFile,"a");
931        if (!lastLogIO) {
932           fprintf(stderr,"Failed to open %s\n", lastLogFile);
933           exit(1);
934        }
935     }
936     if (centralLogFile) {
937        struct stat sbuf;
938        afs_int32 statcode;
939        char path[AFSDIR_PATH_MAX];
940
941        statcode = stat(centralLogFile, &sbuf);
942        centralLogIO = fopen(centralLogFile,"a");
943        if(!centralLogIO){
944           fprintf(stderr,"Failed to open %s; error %d\n",centralLogFile, errno);
945           exit(1);
946        }
947
948 #ifndef AFS_NT40_ENV
949        /* Make sure it is not in AFS, has to have been created first */
950        if (!realpath(centralLogFile, path)) {
951           fprintf(stderr,"Warning: can't determine real path of '%s' (%d)\n", centralLogFile, errno);
952        } else {
953           if (strncmp(path,"/afs/",5) == 0) {
954              fprintf(stderr,"The central log '%s' should not be in AFS\n", centralLogFile);
955              exit(1);
956           }
957        }
958 #endif
959
960        /* Write header if created it */
961        if (statcode) {
962           char *h1="TASK   START DATE/TIME      END DATE/TIME        ELAPSED   VOLUMESET\n";
963           char *h2="-----  -------------------  -------------------  --------  ---------\n";
964           /* File didn't exist before so write the header lines */
965           fwrite(h1, strlen(h1), 1, centralLogIO);
966           fwrite(h2, strlen(h2), 1, centralLogIO);
967           fflush(centralLogIO);
968        }
969     }
970
971     if (as->parms[1].items) 
972     {
973         debugLevel = SafeATOL(as->parms[1].items->data);
974         if(debugLevel == -1)
975         {
976             TLog(0, "Illegal debug level '%s'\n", as->parms[1].items->data);
977             exit(1);
978         }
979     }
980
981 #ifdef xbsa
982     /* Setup XBSA library interface */
983     if (CONF_XBSA) {
984        afs_int32 rc;
985        rc = xbsa_MountLibrary(&butxInfo, xbsaType);
986        if (rc != XBSA_SUCCESS) {
987           TapeLog(0, 0, rc, 0, "Unable to mount the XBSA library\n");
988           return(1);
989        }
990
991        forcemultiple = (as->parms[7].items ? 1 : 0); /*-xbsaforcemultiple */
992        if (forcemultiple)
993           printf("Force XBSA multiple server support\n");
994
995        rc = InitToServer(0/*taskid*/, &butxInfo, adsmServerName);
996        if (rc != XBSA_SUCCESS) return(1);
997    }
998 #endif /*xbsa*/
999
1000     /* cell switch */
1001     if (as->parms[2].items) strncpy(cellName, as->parms[2].items->data, sizeof(cellName));
1002     else                    cellName[0] = '\0';
1003
1004     if (as->parms[4].items) autoQuery = 0;
1005
1006     localauth = (as->parms[5].items ? 1 : 0);
1007
1008     code = rx_Init(htons(BC_TAPEPORT + portOffset));
1009     if (code) 
1010     {
1011         TapeLog(0, 0, code, 0, "rx init failed on port %u\n", BC_TAPEPORT + portOffset);
1012         exit(1);
1013     }
1014     rx_SetRxDeadTime(150);
1015
1016     /* Establish connection with the vldb server */
1017     code = vldbClientInit(0, localauth, cellName, &cstruct, &ttoken);
1018     if (code) 
1019     {
1020         TapeLog(0, 0, code, 0, "Can't access vldb\n");
1021         return code;
1022     }
1023
1024     strcpy(globalCellName, cellName);
1025
1026     /*initialize the dumpNode list */
1027     InitNodeList(portOffset);
1028
1029     deviceLatch = (struct deviceSyncNode *)(malloc (sizeof(struct deviceSyncNode)));
1030     Lock_Init(&(deviceLatch->lock));
1031     deviceLatch->flags = 0;
1032
1033     /* initialize database support, volume support, and logs */
1034
1035     /* Create a single security object, in this case the null security
1036      * object, for unauthenticated connections, which will be used to control
1037      * security on connections made to this server 
1038      */
1039
1040     securityObjects[0] = (struct rx_securityClass *) rxnull_NewServerSecurityObject();
1041     securityObjects[1] = (struct rx_securityClass *) 0; /* don't bother with rxvab */
1042     if ( !securityObjects[0] ) 
1043     {
1044         TLog(0, "rxnull_NewServerSecurityObject");
1045         exit(1);
1046     }
1047
1048     service = rx_NewService(0, 1, "BUTC", securityObjects, 3, TC_ExecuteRequest);
1049     if ( !service ) 
1050     {
1051         TLog(0, "rx_NewService");
1052         exit(1);
1053     }
1054     rx_SetMaxProcs(service, 4);
1055
1056     /* Establish connection to the backup database */
1057     code = udbClientInit(0, localauth, cellName);
1058     if (code) 
1059     {
1060         TapeLog(0, 0, code, 0, "Can't access backup database\n");
1061         exit(1);
1062     }
1063     /* This call is here to verify that we are authentiated.
1064      * The call does nothing and will return BUDB_NOTPERMITTED 
1065      * if we don't belong.
1066      */
1067     code = bcdb_deleteDump(0,0,0,0);
1068     if (code == BUDB_NOTPERMITTED) {
1069         TapeLog(0, 0, code, 0, "Can't access backup database\n");
1070         exit(1);
1071     }
1072     
1073     initStatus();
1074 #ifdef AFS_PTHREAD_ENV
1075     code = pthread_attr_init(&tattr);
1076     if (code)
1077     {
1078         TapeLog(0, 0, code, 0, "Can't pthread_attr_init database monitor task");
1079         exit(1);
1080     }
1081     code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
1082     if (code)
1083     {
1084         TapeLog(0, 0, code, 0, "Can't pthread_attr_setdetachstate database monitor task");
1085         exit(1);
1086     }
1087     AFS_SIGSET_CLEAR();
1088     code = pthread_create(&dbWatcherPid, &tattr, dbWatcher, (void *)2);
1089     AFS_SIGSET_RESTORE();
1090 #else
1091     code = LWP_CreateProcess(dbWatcher, 20480, LWP_NORMAL_PRIORITY, 2, "dbWatcher", &dbWatcherPid);
1092 #endif
1093     if (code)
1094     {
1095         TapeLog(0, 0, code, 0, "Can't create database monitor task");
1096         exit(1);
1097     }
1098
1099     TLog(0, "Starting Tape Coordinator: Port offset %u   Debug level %u\n",
1100              portOffset, debugLevel);
1101     TLog(0, "Token expires: %s\n", cTIME(&ttoken.endTime));
1102
1103     rx_StartServer(1); /* Donate this process to the server process pool */
1104     TLog(0, "Error: StartServer returned");
1105     exit(1);
1106 }
1107
1108 #ifndef AFS_NT40_ENV
1109 #include "AFS_component_version_number.c"
1110 #endif
1111
1112 main(argc, argv)
1113 int argc;
1114 char **argv; 
1115 {
1116     register struct cmd_syndesc *ts;
1117     register struct cmd_item *ti;
1118
1119 #ifdef  AFS_AIX32_ENV
1120     /*
1121      * The following signal action for AIX is necessary so that in case of a 
1122      * crash (i.e. core is generated) we can include the user's data section 
1123      * in the core dump. Unfortunately, by default, only a partial core is
1124      * generated which, in many cases, isn't too useful.
1125      */
1126     struct sigaction nsa;
1127     
1128     sigemptyset(&nsa.sa_mask);
1129     nsa.sa_handler = SIG_DFL;
1130     nsa.sa_flags = SA_FULLDUMP;
1131     sigaction(SIGSEGV, &nsa, NULL);
1132     sigaction(SIGABRT, &nsa, NULL);
1133 #endif
1134
1135     setlinebuf(stdout);
1136
1137     ts = cmd_CreateSyntax((char *) 0, WorkerBee, (char *) 0, "tape coordinator");
1138     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "port offset");
1139     cmd_AddParm(ts, "-debuglevel", CMD_SINGLE, CMD_OPTIONAL, "0 | 1 | 2");
1140     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1141     cmd_AddParm(ts, "-device", CMD_SINGLE, (CMD_OPTIONAL|CMD_HIDE), "tape device path");
1142     cmd_AddParm(ts, "-noautoquery", CMD_FLAG, CMD_OPTIONAL, 
1143                     "do not query operator for first tape");
1144     cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL, "create tickets from KeyFile");
1145     cmd_AddParm(ts, "-restoretofile", CMD_SINGLE, (CMD_OPTIONAL|CMD_HIDE), "file to restore to");
1146     cmd_AddParm(ts, "-xbsaforcemultiple", CMD_FLAG, (CMD_OPTIONAL|CMD_HIDE), "Force multiple XBSA server support");
1147
1148     /* Initialize dirpaths */
1149     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
1150 #ifdef AFS_NT40_ENV
1151         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
1152 #endif
1153         fprintf(stderr,"Unable to obtain AFS server directory.\n");
1154         exit(2);
1155     }
1156
1157     /* setup the file paths */
1158     strcompose(eFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/", TE_PREFIX, NULL);
1159     strcompose(lFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/", TL_PREFIX, NULL);
1160     strcompose(pFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/", CFG_PREFIX, NULL);
1161     strcpy(tapeConfigFile, AFSDIR_SERVER_TAPECONFIG_FILEPATH);
1162
1163     /* special case "no args" case since cmd_dispatch gives help message
1164      * instead
1165      */
1166     if (argc == 1) {
1167         ts = (struct cmd_syndesc *) malloc(sizeof(struct cmd_syndesc));
1168         bzero(ts, sizeof(*ts));
1169         
1170         ti = (struct cmd_item *) malloc(sizeof(struct cmd_item));
1171         ti->next = 0;
1172         ti->data = "0";
1173         ts->parms[0].items = ti;
1174         ti = (struct cmd_item *) malloc(sizeof(struct cmd_item));
1175         ti->next = 0;
1176         ti->data = "0";
1177         ts->parms[1].items = ti;
1178         ts->parms[2].items = (struct cmd_item *) NULL;
1179         ts->parms[3].items = (struct cmd_item *) NULL;
1180         ts->parms[4].items = (struct cmd_item *) NULL;
1181         ts->parms[5].items = (struct cmd_item *) NULL;
1182         return WorkerBee(ts, (char *) 0);
1183     }
1184     else
1185         return cmd_Dispatch(argc, argv);
1186 }