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