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