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