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