rxbind-for-servers-20060620
[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 #ifndef AFS_NT40_ENV
1052         if (AFSDIR_SERVER_NETRESTRICT_FILEPATH || 
1053             AFSDIR_SERVER_NETINFO_FILEPATH) {
1054             char reason[1024];
1055             ccode = parseNetFiles(SHostAddrs, NULL, NULL,
1056                                            ADDRSPERSITE, reason,
1057                                            AFSDIR_SERVER_NETINFO_FILEPATH,
1058                                            AFSDIR_SERVER_NETRESTRICT_FILEPATH);
1059         } else 
1060 #endif  
1061         {
1062             ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
1063         }
1064         if (ccode == 1) 
1065             host = SHostAddrs[0];
1066     }
1067
1068     code = rx_InitHost(host, htons(BC_TAPEPORT + portOffset));
1069     if (code) {
1070         TapeLog(0, 0, code, 0, "rx init failed on port %u\n",
1071                 BC_TAPEPORT + portOffset);
1072         exit(1);
1073     }
1074     rx_SetRxDeadTime(150);
1075
1076     /* Establish connection with the vldb server */
1077     code = vldbClientInit(0, localauth, cellName, &cstruct, &ttoken);
1078     if (code) {
1079         TapeLog(0, 0, code, 0, "Can't access vldb\n");
1080         return code;
1081     }
1082
1083     strcpy(globalCellName, cellName);
1084
1085     /*initialize the dumpNode list */
1086     InitNodeList(portOffset);
1087
1088     deviceLatch =
1089         (struct deviceSyncNode *)(malloc(sizeof(struct deviceSyncNode)));
1090     Lock_Init(&(deviceLatch->lock));
1091     deviceLatch->flags = 0;
1092
1093     /* initialize database support, volume support, and logs */
1094
1095     /* Create a single security object, in this case the null security
1096      * object, for unauthenticated connections, which will be used to control
1097      * security on connections made to this server 
1098      */
1099
1100     securityObjects[0] = rxnull_NewServerSecurityObject();
1101     securityObjects[1] = (struct rx_securityClass *)0;  /* don't bother with rxvab */
1102     if (!securityObjects[0]) {
1103         TLog(0, "rxnull_NewServerSecurityObject");
1104         exit(1);
1105     }
1106
1107     service =
1108         rx_NewServiceHost, (host, 0, 1, "BUTC", securityObjects, 3, TC_ExecuteRequest);
1109     if (!service) {
1110         TLog(0, "rx_NewService");
1111         exit(1);
1112     }
1113     rx_SetMaxProcs(service, 4);
1114
1115     /* Establish connection to the backup database */
1116     code = udbClientInit(0, localauth, cellName);
1117     if (code) {
1118         TapeLog(0, 0, code, 0, "Can't access backup database\n");
1119         exit(1);
1120     }
1121     /* This call is here to verify that we are authentiated.
1122      * The call does nothing and will return BUDB_NOTPERMITTED 
1123      * if we don't belong.
1124      */
1125     code = bcdb_deleteDump(0, 0, 0, 0);
1126     if (code == BUDB_NOTPERMITTED) {
1127         TapeLog(0, 0, code, 0, "Can't access backup database\n");
1128         exit(1);
1129     }
1130
1131     initStatus();
1132 #ifdef AFS_PTHREAD_ENV
1133     code = pthread_attr_init(&tattr);
1134     if (code) {
1135         TapeLog(0, 0, code, 0,
1136                 "Can't pthread_attr_init database monitor task");
1137         exit(1);
1138     }
1139     code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
1140     if (code) {
1141         TapeLog(0, 0, code, 0,
1142                 "Can't pthread_attr_setdetachstate database monitor task");
1143         exit(1);
1144     }
1145     AFS_SIGSET_CLEAR();
1146     code = pthread_create(&dbWatcherPid, &tattr, dbWatcher, (void *)2);
1147     AFS_SIGSET_RESTORE();
1148 #else
1149     code =
1150         LWP_CreateProcess(dbWatcher, 20480, LWP_NORMAL_PRIORITY, (void *)2,
1151                           "dbWatcher", &dbWatcherPid);
1152 #endif
1153     if (code) {
1154         TapeLog(0, 0, code, 0, "Can't create database monitor task");
1155         exit(1);
1156     }
1157
1158     TLog(0, "Starting Tape Coordinator: Port offset %u   Debug level %u\n",
1159          portOffset, debugLevel);
1160     t = ttoken.endTime;
1161     TLog(0, "Token expires: %s\n", cTIME(&t));
1162
1163     rx_StartServer(1);          /* Donate this process to the server process pool */
1164     TLog(0, "Error: StartServer returned");
1165     exit(1);
1166 }
1167
1168 #ifndef AFS_NT40_ENV
1169 #include "AFS_component_version_number.c"
1170 #endif
1171
1172 main(argc, argv)
1173      int argc;
1174      char **argv;
1175 {
1176     register struct cmd_syndesc *ts;
1177     register struct cmd_item *ti;
1178
1179 #ifdef  AFS_AIX32_ENV
1180     /*
1181      * The following signal action for AIX is necessary so that in case of a 
1182      * crash (i.e. core is generated) we can include the user's data section 
1183      * in the core dump. Unfortunately, by default, only a partial core is
1184      * generated which, in many cases, isn't too useful.
1185      */
1186     struct sigaction nsa;
1187
1188     sigemptyset(&nsa.sa_mask);
1189     nsa.sa_handler = SIG_DFL;
1190     nsa.sa_flags = SA_FULLDUMP;
1191     sigaction(SIGSEGV, &nsa, NULL);
1192     sigaction(SIGABRT, &nsa, NULL);
1193 #endif
1194
1195     setlinebuf(stdout);
1196
1197     ts = cmd_CreateSyntax(NULL, WorkerBee, NULL, "tape coordinator");
1198     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "port offset");
1199     cmd_AddParm(ts, "-debuglevel", CMD_SINGLE, CMD_OPTIONAL, "0 | 1 | 2");
1200     cmd_AddParm(ts, "-cell", CMD_SINGLE, CMD_OPTIONAL, "cell name");
1201     cmd_AddParm(ts, "-device", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1202                 "tape device path");
1203     cmd_AddParm(ts, "-noautoquery", CMD_FLAG, CMD_OPTIONAL,
1204                 "do not query operator for first tape");
1205     cmd_AddParm(ts, "-localauth", CMD_FLAG, CMD_OPTIONAL,
1206                 "create tickets from KeyFile");
1207     cmd_AddParm(ts, "-restoretofile", CMD_SINGLE, (CMD_OPTIONAL | CMD_HIDE),
1208                 "file to restore to");
1209     cmd_AddParm(ts, "-xbsaforcemultiple", CMD_FLAG, (CMD_OPTIONAL | CMD_HIDE),
1210                 "Force multiple XBSA server support");
1211     cmd_AddParm(ts, "-rxbind", CMD_FLAG, CMD_OPTIONAL,
1212                 "bind Rx socket");
1213
1214     /* Initialize dirpaths */
1215     if (!(initAFSDirPath() & AFSDIR_SERVER_PATHS_OK)) {
1216 #ifdef AFS_NT40_ENV
1217         ReportErrorEventAlt(AFSEVT_SVR_NO_INSTALL_DIR, 0, argv[0], 0);
1218 #endif
1219         fprintf(stderr, "Unable to obtain AFS server directory.\n");
1220         exit(2);
1221     }
1222
1223     /* setup the file paths */
1224     strcompose(eFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/",
1225                TE_PREFIX, NULL);
1226     strcompose(lFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/",
1227                TL_PREFIX, NULL);
1228     strcompose(pFile, AFSDIR_PATH_MAX, AFSDIR_SERVER_BACKUP_DIRPATH, "/",
1229                CFG_PREFIX, NULL);
1230     strcpy(tapeConfigFile, AFSDIR_SERVER_TAPECONFIG_FILEPATH);
1231
1232     /* special case "no args" case since cmd_dispatch gives help message
1233      * instead
1234      */
1235     if (argc == 1) {
1236         ts = (struct cmd_syndesc *)malloc(sizeof(struct cmd_syndesc));
1237         memset(ts, 0, sizeof(*ts));
1238
1239         ti = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1240         ti->next = 0;
1241         ti->data = "0";
1242         ts->parms[0].items = ti;
1243         ti = (struct cmd_item *)malloc(sizeof(struct cmd_item));
1244         ti->next = 0;
1245         ti->data = "0";
1246         ts->parms[1].items = ti;
1247         ts->parms[2].items = (struct cmd_item *)NULL;
1248         ts->parms[3].items = (struct cmd_item *)NULL;
1249         ts->parms[4].items = (struct cmd_item *)NULL;
1250         ts->parms[5].items = (struct cmd_item *)NULL;
1251         return WorkerBee(ts, NULL);
1252     } else
1253         return cmd_Dispatch(argc, argv);
1254 }