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