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