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