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