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