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