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