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