Пример #1
0
afs_int32
readDbTape(struct butm_tapeInfo *tapeInfoPtr,
	   struct rstTapeInfo *rstTapeInfoPtr, int query)
{
    afs_int32 code = 0;
    int interactiveFlag;
    afs_int32 taskId;
    struct butm_tapeLabel oldTapeLabel;
    char AFStapeName[BU_MAXTAPELEN], tapeName[BU_MAXTAPELEN];
    struct tapeEntryList *endList;
    int tapecount = 1;
    struct budb_dumpEntry de;
    struct budb_tapeEntry te;

    taskId = rstTapeInfoPtr->taskId;
    interactiveFlag = query;

    /* construct the name of the tape */
    sprintf(AFStapeName, "%s.%-d", DUMP_TAPE_NAME, rstTapeInfoPtr->tapeSeq);
    strcpy(tapeName, AFStapeName);

    /* Will prompt for the latest saved database tape, but will accept any one */
    if (rstTapeInfoPtr->tapeSeq == 1) {
	code = bcdb_FindLatestDump("", "", &de);
	if (!code)
	    rstTapeInfoPtr->dumpid = de.id;
    }
    if (rstTapeInfoPtr->dumpid) {
	code =
	    bcdb_FindTapeSeq(rstTapeInfoPtr->dumpid, rstTapeInfoPtr->tapeSeq,
			     &te);
	if (!code)
	    strcpy(tapeName, te.name);
    }
    code = 0;

    while (1) {			/*w */
	if (interactiveFlag) {	/* need a tape to read */
	    code =
		PromptForTape(RESTOREDBOPCODE, tapeName,
			      rstTapeInfoPtr->dumpid, taskId, tapecount);
	    if (code)
		ERROR_EXIT(code);
	}
	interactiveFlag = 1;
	tapecount++;

	code = butm_Mount(tapeInfoPtr, tapeName);
	if (code) {
	    TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
	    goto getNewTape;
	}

	code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1);	/* will rewind the tape */
	if (code) {
	    TapeLog(0, taskId, code, tapeInfoPtr->error,
		    "Can't read tape label\n");
	    goto getNewTape;
	}

	/* Check for name of tape and matching dump id (if applicable). */
	if ((strcmp(oldTapeLabel.AFSName, AFStapeName) != 0)
	    || ((rstTapeInfoPtr->tapeSeq != 1)
		&& (oldTapeLabel.dumpid != rstTapeInfoPtr->dumpid))) {
	    char expTape[BU_MAXTAPELEN + 32];
	    char gotTape[BU_MAXTAPELEN + 32];

	    TAPENAME(expTape, tapeName, rstTapeInfoPtr->dumpid);
	    TAPENAME(gotTape, oldTapeLabel.AFSName, oldTapeLabel.dumpid);

	    TLog(taskId, "Tape label expected %s, label seen %s\n", expTape,
		 gotTape);
	    goto getNewTape;
	}

	if (rstTapeInfoPtr->tapeSeq == 1)	/* Remember this dumpId */
	    rstTapeInfoPtr->dumpid = oldTapeLabel.dumpid;

	break;

      getNewTape:
	unmountTape(taskId, tapeInfoPtr);
    }				/*w */


    /* Initialize a tapeEntry for later inclusion into the database */
    listEntryPtr =
	(struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
    if (!listEntryPtr)
	ERROR_EXIT(TC_NOMEMORY);
    memset(listEntryPtr, 0, sizeof(struct tapeEntryList));

    /* Fill in tape entry so we can save it later */
    strcpy(tapeEntryPtr->name, TNAME(&oldTapeLabel));
    tapeEntryPtr->dump = oldTapeLabel.dumpid;
    tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
    tapeEntryPtr->written = oldTapeLabel.creationTime;
    tapeEntryPtr->expires = oldTapeLabel.expirationDate;
    tapeEntryPtr->seq = extractTapeSeq(oldTapeLabel.AFSName);
    tapeEntryPtr->useCount = oldTapeLabel.useCount;
    tapeEntryPtr->useKBytes = 0;
    tapeEntryPtr->labelpos = 0;

    /* Thread onto end of single-linked list */
    if (listEntryHead) {
	endList = listEntryHead;
	while (endList->next)
	    endList = endList->next;
	endList->next = listEntryPtr;
    } else
	listEntryHead = listEntryPtr;

  error_exit:
    return (code);
}
Пример #2
0
static int
WorkerBee(struct cmd_syndesc *as, void *arock)
{
    afs_int32 code;
    struct rx_securityClass *(securityObjects[3]);
    struct rx_service *service;
    time_t tokenExpires;
    char cellName[64];
    int localauth;
    /*process arguments */
    afs_int32 portOffset = 0;
#ifdef AFS_PTHREAD_ENV
    pthread_t dbWatcherPid;
    pthread_attr_t tattr;
    AFS_SIGSET_DECL;
#else
    PROCESS dbWatcherPid;
#endif
    afs_uint32 host = htonl(INADDR_ANY);

    debugLevel = 0;

    /*initialize the error tables */
    initialize_KA_error_table();
    initialize_RXK_error_table();
    initialize_KTC_error_table();
    initialize_ACFG_error_table();
    initialize_CMD_error_table();
    initialize_VL_error_table();
    initialize_BUTM_error_table();
    initialize_BUTC_error_table();
#ifdef xbsa
    initialize_BUTX_error_table();
#endif /*xbs */
    initialize_VOLS_error_table();
    initialize_BUDB_error_table();
    initialize_BUCD_error_table();

    if (as->parms[0].items) {
	portOffset = SafeATOL(as->parms[0].items->data);
	if (portOffset == -1) {
	    fprintf(stderr, "Illegal port offset '%s'\n",
		    as->parms[0].items->data);
	    exit(1);
	} else if (portOffset > BC_MAXPORTOFFSET) {
	    fprintf(stderr, "%u exceeds max port offset %u\n", portOffset,
		    BC_MAXPORTOFFSET);
	    exit(1);
	}
    }

    xbsaType = XBSA_SERVER_TYPE_NONE;	/* default */
    if (as->parms[3].items) {	/* -device */
	globalTapeConfig.capacity = 0x7fffffff;	/* 2T for max tape capacity */
	globalTapeConfig.fileMarkSize = 0;
	globalTapeConfig.portOffset = portOffset;
	strncpy(globalTapeConfig.device, as->parms[3].items->data, 100);
	xbsaType = XBSA_SERVER_TYPE_NONE;	/* Not XBSA */
    } else {
	/* Search for an entry in tapeconfig file */
	code = GetDeviceConfig(tapeConfigFile, &globalTapeConfig, portOffset);
	if (code == -1) {
	    fprintf(stderr, "Problem in reading config file %s\n",
		    tapeConfigFile);
	    exit(1);
	}
	/* Set xbsaType. If code == 1, no entry was found in the tapeconfig file so
	 * it's an XBSA server. Don't know if its ADSM or not so its unknown.
	 */
	xbsaType =
	    ((code == 1) ? XBSA_SERVER_TYPE_UNKNOWN : XBSA_SERVER_TYPE_NONE);
    }

    if (as->parms[6].items) {	/* -restoretofile */
	int s = strlen(as->parms[6].items->data);
	restoretofile = malloc(s + 1);
	strncpy(restoretofile, as->parms[6].items->data, s + 1);
	printf("Restore to file '%s'\n", restoretofile);
    }

    /* Go and read the config file: CFG_<device> or CFG_<port>. We will also set
     * the exact xbsaType within the call (won't be unknown) - double check.
     */
    code = GetConfigParams(pFile, portOffset);
    if (code)
	exit(code);
#ifdef xbsa
    if (xbsaType == XBSA_SERVER_TYPE_UNKNOWN) {
	printf
	    ("\nConfiguration file error, the TYPE parameter must be specified, or\n");
	printf("an entry must exist in %s for port %d\n", tapeConfigFile,
	       portOffset);
	exit(1);
    }
#else
    /* Not compiled for XBSA code so we can't support it */
    if (CONF_XBSA) {
	printf("\nNo entry found in %s for port %d\n", tapeConfigFile,
	       portOffset);
	printf("This binary does not have XBSA support\n");
	exit(1);
    }
#endif

    /* Open the log files. The pathnames were set in GetConfigParams() */
    logIO = fopen(logFile, "a");
    if (!logIO) {
	fprintf(stderr, "Failed to open %s\n", logFile);
	exit(1);
    }
    ErrorlogIO = fopen(ErrorlogFile, "a");
    if (!ErrorlogIO) {
	fprintf(stderr, "Failed to open %s\n", ErrorlogFile);
	exit(1);
    }
    if (lastLog) {
	lastLogIO = fopen(lastLogFile, "a");
	if (!lastLogIO) {
	    fprintf(stderr, "Failed to open %s\n", lastLogFile);
	    exit(1);
	}
    }
    if (centralLogFile) {
	struct stat sbuf;
	afs_int32 statcode;
#ifndef AFS_NT40_ENV
	char path[AFSDIR_PATH_MAX];
#endif

	statcode = stat(centralLogFile, &sbuf);
	centralLogIO = fopen(centralLogFile, "a");
	if (!centralLogIO) {
	    fprintf(stderr, "Failed to open %s; error %d\n", centralLogFile,
		    errno);
	    exit(1);
	}
#ifndef AFS_NT40_ENV
	/* Make sure it is not in AFS, has to have been created first */
	if (!realpath(centralLogFile, path)) {
	    fprintf(stderr,
		    "Warning: can't determine real path of '%s' (%d)\n",
		    centralLogFile, errno);
	} else {
	    if (strncmp(path, "/afs/", 5) == 0) {
		fprintf(stderr, "The central log '%s' should not be in AFS\n",
			centralLogFile);
		exit(1);
	    }
	}
#endif

	/* Write header if created it */
	if (statcode) {
	    char *h1 =
		"TASK   START DATE/TIME      END DATE/TIME        ELAPSED   VOLUMESET\n";
	    char *h2 =
		"-----  -------------------  -------------------  --------  ---------\n";
	    /* File didn't exist before so write the header lines */
	    fwrite(h1, strlen(h1), 1, centralLogIO);
	    fwrite(h2, strlen(h2), 1, centralLogIO);
	    fflush(centralLogIO);
	}
    }

    if (as->parms[1].items) {
	debugLevel = SafeATOL(as->parms[1].items->data);
	if (debugLevel == -1) {
	    TLog(0, "Illegal debug level '%s'\n", as->parms[1].items->data);
	    exit(1);
	}
    }
#ifdef xbsa
    /* Setup XBSA library interface */
    if (CONF_XBSA) {
	afs_int32 rc;
	rc = xbsa_MountLibrary(&butxInfo, xbsaType);
	if (rc != XBSA_SUCCESS) {
	    TapeLog(0, 0, rc, 0, "Unable to mount the XBSA library\n");
	    return (1);
	}

	forcemultiple = (as->parms[7].items ? 1 : 0);/*-xbsaforcemultiple */
	if (forcemultiple)
	    printf("Force XBSA multiple server support\n");

	rc = InitToServer(0 /*taskid */ , &butxInfo, adsmServerName);
	if (rc != XBSA_SUCCESS)
	    return (1);
    }
#endif /*xbsa */

    /* cell switch */
    if (as->parms[2].items)
	strncpy(cellName, as->parms[2].items->data, sizeof(cellName));
    else
	cellName[0] = '\0';

    if (as->parms[4].items)
	autoQuery = 0;

    localauth = (as->parms[5].items ? 1 : 0);
    rxBind = (as->parms[8].items ? 1 : 0);

    if (rxBind) {
        afs_int32 ccode;
        if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
            AFSDIR_SERVER_NETINFO_FILEPATH) {
            char reason[1024];
            ccode = parseNetFiles(SHostAddrs, NULL, NULL,
                                           ADDRSPERSITE, reason,
                                           AFSDIR_SERVER_NETINFO_FILEPATH,
                                           AFSDIR_SERVER_NETRESTRICT_FILEPATH);
        } else
	{
            ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
        }
        if (ccode == 1)
            host = SHostAddrs[0];
    }

    code = rx_InitHost(host, htons(BC_TAPEPORT + portOffset));
    if (code) {
	TapeLog(0, 0, code, 0, "rx init failed on port %u\n",
		BC_TAPEPORT + portOffset);
	exit(1);
    }
    rx_SetRxDeadTime(150);

    /* Establish connection with the vldb server */
    code = vldbClientInit(0, localauth, cellName, &cstruct, &tokenExpires);
    if (code) {
	TapeLog(0, 0, code, 0, "Can't access vldb\n");
	return code;
    }

    strcpy(globalCellName, cellName);

    /*initialize the dumpNode list */
    InitNodeList(portOffset);

    deviceLatch =
	(struct deviceSyncNode *)(malloc(sizeof(struct deviceSyncNode)));
    Lock_Init(&(deviceLatch->lock));
    deviceLatch->flags = 0;

    /* initialize database support, volume support, and logs */

    /* Create a single security object, in this case the null security
     * object, for unauthenticated connections, which will be used to control
     * security on connections made to this server
     */

    securityObjects[0] = rxnull_NewServerSecurityObject();
    securityObjects[1] = (struct rx_securityClass *)0;	/* don't bother with rxvab */
    if (!securityObjects[0]) {
	TLog(0, "rxnull_NewServerSecurityObject");
	exit(1);
    }

    service =
	rx_NewServiceHost(host, 0, 1, "BUTC", securityObjects, 3, TC_ExecuteRequest);
    if (!service) {
	TLog(0, "rx_NewService");
	exit(1);
    }
    rx_SetMaxProcs(service, 4);

    /* Establish connection to the backup database */
    code = udbClientInit(0, localauth, cellName);
    if (code) {
	TapeLog(0, 0, code, 0, "Can't access backup database\n");
	exit(1);
    }
    /* This call is here to verify that we are authentiated.
     * The call does nothing and will return BUDB_NOTPERMITTED
     * if we don't belong.
     */
    code = bcdb_deleteDump(0, 0, 0, 0);
    if (code == BUDB_NOTPERMITTED) {
	TapeLog(0, 0, code, 0, "Can't access backup database\n");
	exit(1);
    }

    initStatus();
#ifdef AFS_PTHREAD_ENV
    code = pthread_attr_init(&tattr);
    if (code) {
	TapeLog(0, 0, code, 0,
		"Can't pthread_attr_init database monitor task");
	exit(1);
    }
    code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
    if (code) {
	TapeLog(0, 0, code, 0,
		"Can't pthread_attr_setdetachstate database monitor task");
	exit(1);
    }
    AFS_SIGSET_CLEAR();
    code = pthread_create(&dbWatcherPid, &tattr, dbWatcher, (void *)2);
    AFS_SIGSET_RESTORE();
#else
    code =
	LWP_CreateProcess(dbWatcher, 20480, LWP_NORMAL_PRIORITY, (void *)2,
			  "dbWatcher", &dbWatcherPid);
#endif
    if (code) {
	TapeLog(0, 0, code, 0, "Can't create database monitor task");
	exit(1);
    }

    TLog(0, "Starting Tape Coordinator: Port offset %u   Debug level %u\n",
	 portOffset, debugLevel);
    TLog(0, "Token expires: %s\n", cTIME(&tokenExpires));

    rx_StartServer(1);		/* Donate this process to the server process pool */
    TLog(0, "Error: StartServer returned");
    exit(1);
}
Пример #3
0
/* GetDBTape
 *      Load a DB tape, read and over write its label.
 *      Leave the tape mounted.
 */
afs_int32
GetDBTape(afs_int32 taskId, Date expires, struct butm_tapeInfo *tapeInfoPtr,
	  afs_uint32 dumpid, afs_int32 sequence, int queryFlag,
	  int *wroteLabel)
{
    afs_int32 code = 0;
    int interactiveFlag;
    char tapeName[BU_MAXTAPELEN];
    char strlevel[5];
    struct timeval tp;
    struct timezone tzp;
    afs_int32 curTime;
    int tapecount = 1;

    struct butm_tapeLabel oldTapeLabel, newLabel;
    struct tapeEntryList *endList;

    /* construct the name of the tape */
    sprintf(tapeName, "%s.%-d", DUMP_TAPE_NAME, sequence);

    interactiveFlag = queryFlag;
    *wroteLabel = 0;

    while (!*wroteLabel) {	/*w */
	if (interactiveFlag) {	/* need a tape to write */
	    code =
		PromptForTape(SAVEDBOPCODE, tapeName, dumpid, taskId,
			      tapecount);
	    if (code)
		ERROR_EXIT(code);
	}
	interactiveFlag = 1;
	tapecount++;

	code = butm_Mount(tapeInfoPtr, tapeName);
	if (code) {
	    TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
	    goto getNewTape;
	}

	memset(&oldTapeLabel, 0, sizeof(oldTapeLabel));
	code = butm_ReadLabel(tapeInfoPtr, &oldTapeLabel, 1);	/* rewind tape */
	if (code) {
	    oldTapeLabel.useCount = 0;	/* no label exists */
	    oldTapeLabel.structVersion = 0;
	    strcpy(oldTapeLabel.pName, "");
	} else {
	    /* If tape has a name, it must be null or database tape name */
	    if (dump_namecheck && strcmp(oldTapeLabel.AFSName, "")
		&& !databaseTape(oldTapeLabel.AFSName)) {
		char gotName[BU_MAXTAPELEN + 32];

		LABELNAME(gotName, &oldTapeLabel);
		TLog(taskId,
		     "This tape %s must be a database tape or NULL tape\n",
		     gotName);

	      getNewTape:
		unmountTape(taskId, tapeInfoPtr);
		continue;
	    }

	    /* Do not overwrite a tape that belongs to this dump */
	    if (oldTapeLabel.dumpid && (oldTapeLabel.dumpid == dumpid)) {
		ErrorLog(0, taskId, 0, 0,
			 "Can't overwrite tape containing the dump in progress\n");
		goto getNewTape;
	    }

	    /* On first tape, the savedb has not started yet, so the database is not locked 
	     * and we can therefore, access information from it. This is easier to do because
	     * database dumps don't have appended dumps (nor appended).
	     */
	    if (sequence == 1) {
		afs_uint32 dmp;
		struct budb_dumpEntry de, de2;

		/* Verify the tape has not expired
		 * Early database dumps don't have a dumpid 
		 */
		if (!tapeExpired(&oldTapeLabel)) {
		    TLog(taskId, "This tape has not expired\n");
		    goto getNewTape;
		}

		/* Since the dumpset on this tape will be deleted from database, check if
		 * any of the dumps in this dumpset are most-recent-dumps.
		 */
		for (dmp = oldTapeLabel.dumpid; dmp; dmp = de.appendedDumpID) {
		    if (dmp == lastDump.id) {
			memcpy(&de, &lastDump, sizeof(de));
			memcpy(&de2, &lastDump, sizeof(de2));
		    } else {
			code = bcdb_FindDumpByID(dmp, &de);
			if (code)
			    break;
			sprintf(strlevel, "%d", de.level);
			code =
			    bcdb_FindLatestDump(de.volumeSetName, strlevel,
						&de2);
			if (code)
			    continue;
		    }

		    if (de.id == de2.id) {
			if (strcmp(DUMP_TAPE_NAME, de2.name) == 0) {
			    ErrorLog(0, taskId, 0, 0,
				     "Warning: Overwriting most recent dump %s (DumpID %u)\n",
				     de.name, de.id);
			} else {
			    ErrorLog(0, taskId, 0, 0,
				     "Warning: Overwriting most recent dump of the '%s' volumeset: %s (DumpID %u)\n",
				     de.volumeSetName, de.name, de.id);
			}
		    }
		}
	    }

	    /* Otherwise, the savedb is in progress and we can't
	     * access the database (it's locked). So we rely on the 
	     * information available (and not the backup database).
	     */
	    else {
		/* Check the tape's expiration date. Use the expiration on the label */
		gettimeofday(&tp, &tzp);
		curTime = tp.tv_sec;
		if (curTime < oldTapeLabel.expirationDate) {
		    TLog(taskId, "This tape has not expired\n");
		    goto getNewTape;
		}

		/* Check if this previous-dump of the dump-in-progress is on this tape */
		if (oldTapeLabel.dumpid
		    && (oldTapeLabel.dumpid == lastDump.id)) {
		    ErrorLog(0, taskId, 0, 0,
			     "Warning: Overwriting most recent dump %s (DumpID %u)\n",
			     lastDump.name, lastDump.id);
		}

	    }
	}

	GetNewLabel(tapeInfoPtr, oldTapeLabel.pName, tapeName, &newLabel);
	newLabel.expirationDate = expires;
	newLabel.useCount = oldTapeLabel.useCount + 1;
	newLabel.dumpid = dumpid;
	newLabel.size = tapeInfoPtr->tapeSize;

	code = butm_Create(tapeInfoPtr, &newLabel, 1);	/* rewind tape */
	if (code) {
	    TapeLog(0, taskId, code, tapeInfoPtr->error,
		    "Can't label tape\n");
	    goto getNewTape;
	}

	*wroteLabel = 1;

	/* Initialize a tapeEntry for later inclusion into the database */
	listEntryPtr =
	    (struct tapeEntryList *)malloc(sizeof(struct tapeEntryList));
	if (!listEntryPtr)
	    ERROR_EXIT(TC_NOMEMORY);
	memset(listEntryPtr, 0, sizeof(struct tapeEntryList));

	/* Remember dumpid so we can delete it later */
	if ((oldTapeLabel.structVersion >= TAPE_VERSION_3)
	    && oldTapeLabel.dumpid)
	    listEntryPtr->oldDumpId = oldTapeLabel.dumpid;

	/* Fill in tape entry so we can save it later */
	strcpy(tapeEntryPtr->name, TNAME(&newLabel));
	tapeEntryPtr->flags = BUDB_TAPE_BEINGWRITTEN;
	tapeEntryPtr->written = newLabel.creationTime;
	tapeEntryPtr->expires = expires;
	tapeEntryPtr->seq = sequence;
	tapeEntryPtr->useCount = oldTapeLabel.useCount + 1;
	tapeEntryPtr->dump = dumpid;
	tapeEntryPtr->useKBytes = 0;
	tapeEntryPtr->labelpos = 0;

	/* Thread onto end of single-linked list */
	if (listEntryHead) {
	    endList = listEntryHead;
	    while (endList->next)
		endList = endList->next;
	    endList->next = listEntryPtr;
	} else
	    listEntryHead = listEntryPtr;
    }				/*w */

  error_exit:
    return (code);
}
Пример #4
0
void *
saveDbToTape(void *param)
{
    struct saveDbIf *saveDbIfPtr = (struct saveDbIf *)param;
    afs_int32 code = 0;
    afs_int32 i;
    int wroteLabel;
    afs_uint32 taskId;
    Date expires;

    struct butm_tapeInfo tapeInfo;
    struct budb_dumpEntry dumpEntry;

    extern struct deviceSyncNode *deviceLatch;
    extern struct tapeConfig globalTapeConfig;

    expires = (saveDbIfPtr->archiveTime ? NEVERDATE : 0);
    taskId = saveDbIfPtr->taskId;

    setStatus(taskId, DRIVE_WAIT);
    EnterDeviceQueue(deviceLatch);	/* lock tape device */
    clearStatus(taskId, DRIVE_WAIT);

    printf("\n\n");
    TLog(taskId, "SaveDb\n");

    tapeInfo.structVersion = BUTM_MAJORVERSION;
    code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
    if (code) {
	ErrorLog(0, taskId, code, tapeInfo.error,
		 "Can't initialize tape module\n");
	ERROR_EXIT(code);
    }

    /* Determine what the last database dump was */
    memset(&lastDump, 0, sizeof(lastDump));
    code = bcdb_FindLatestDump("", "", &lastDump);
    if (code) {
	if (code != BUDB_NODUMPNAME) {
	    ErrorLog(0, taskId, code, 0, "Can't read backup database\n");
	    ERROR_EXIT(code);
	}
	memset(&lastDump, 0, sizeof(lastDump));
    }

    code = CreateDBDump(&dumpEntry);	/* Create a dump for this tape */
    if (code) {
	ErrorLog(0, taskId, code, 0, "Can't create dump in database\n");
	ERROR_EXIT(code);
    }


    listEntryHead = NULL;

    /* Get the tape and write a new label to it */
    code =
	GetDBTape(taskId, expires, &tapeInfo, dumpEntry.id, 1, autoQuery,
		  &wroteLabel);

    /*
     * If did not write the label, remove created dump 
     * Else if wrote the label, remove old dump from db so it's not saved.
     */
    if (!wroteLabel) {
	i = bcdb_deleteDump(dumpEntry.id, 0, 0, 0);
	dumpEntry.id = 0;
	if (i && (i != BUDB_NOENT))
	    ErrorLog(0, taskId, i, 0, "Unable to delete DB entry %u.\n",
		     dumpEntry.id);
    } else if (listEntryHead->oldDumpId) {
	i = bcdb_deleteDump(listEntryHead->oldDumpId, 0, 0, 0);
	listEntryHead->oldDumpId = 0;
	if (i && (i != BUDB_NOENT)) {
	    ErrorLog(0, taskId, i, 0, "Unable to delete old DB entry %u.\n",
		     listEntryHead->oldDumpId);
	    ERROR_EXIT(i);
	}
    }
    if (code)
	ERROR_EXIT(code);

    TapeLog(1, taskId, 0, 0, "Tape accepted - now dumping database\n");

    /* we have a writable tape */
    code = writeDbDump(&tapeInfo, taskId, expires, dumpEntry.id);
    if (code)
	ERROR_EXIT(code);

    /* Now delete the entries between time 0 and archive-time */
    if (saveDbIfPtr->archiveTime)
	code = bcdb_deleteDump(0, 0, saveDbIfPtr->archiveTime, 0);

  error_exit:
    unmountTape(taskId, &tapeInfo);

    /* Add this dump's tapes to the database and mark it finished */
    if (dumpEntry.id) {
	i = addTapesToDb(taskId);
	if (!code)
	    code = i;

	i = bcdb_FinishDump(&dumpEntry);
	if (!code)
	    code = i;
    }
    freeTapeList();

    if (code == TC_ABORTEDBYREQUEST) {
	TLog(taskId, "SaveDb: Aborted by request\n");
	clearStatus(taskId, ABORT_REQUEST);
	setStatus(taskId, ABORT_DONE);
    } else if (code) {
	TapeLog(0, taskId, code, 0, "SaveDb: Finished with errors\n");
	setStatus(taskId, TASK_ERROR);
    } else {
	TLog(taskId, "SaveDb: Finished\n");
    }
    setStatus(taskId, TASK_DONE);

    free(saveDbIfPtr);
    LeaveDeviceQueue(deviceLatch);
    return (void *)(intptr_t)(code);
}
Пример #5
0
void *
restoreDbFromTape(void *param)
{
    afs_uint32 taskId = (intptr_t) param;
    afs_int32 code = 0;
    afs_int32 i;
    struct butm_tapeInfo tapeInfo;
    struct rstTapeInfo rstTapeInfo;
    struct budb_dumpEntry dumpEntry;

    extern struct tapeConfig globalTapeConfig;
    extern struct deviceSyncNode *deviceLatch;

    setStatus(taskId, DRIVE_WAIT);
    EnterDeviceQueue(deviceLatch);	/* lock tape device */
    clearStatus(taskId, DRIVE_WAIT);

    printf("\n\n");
    TLog(taskId, "RestoreDb\n");

    tapeInfo.structVersion = BUTM_MAJORVERSION;
    code = butm_file_Instantiate(&tapeInfo, &globalTapeConfig);
    if (code) {
	ErrorLog(0, taskId, code, tapeInfo.error,
		 "Can't initialize tape module\n");
	ERROR_EXIT(code);
    }

    listEntryHead = NULL;

    rstTapeInfo.taskId = taskId;
    rstTapeInfo.tapeSeq = 1;
    rstTapeInfo.dumpid = 0;

    code = readDbTape(&tapeInfo, &rstTapeInfo, autoQuery);
    if (code)
	ERROR_EXIT(code);

    code = restoreDbEntries(&tapeInfo, &rstTapeInfo);
    if (code)
	ERROR_EXIT(code);

  error_exit:
    /* Now put this dump into the database */
    /* Make a dump entry from first tape   */
    listEntryPtr = listEntryHead;
    if (listEntryPtr) {
	makeDbDumpEntry(tapeEntryPtr, &dumpEntry);
	if (dumpEntry.id != 0) {
	    i = bcdb_CreateDump(&dumpEntry);
	    if (i) {
		if (i == BUDB_DUMPIDEXISTS)
		    fprintf(stderr,
			    "Dump id %d not added to database - already exists\n",
			    dumpEntry.id);
		else
		    TapeLog(0, taskId, i, 0,
			    "Dump id %d not added to database\n",
			    dumpEntry.id);
	    } else {
		i = addTapesToDb(taskId);
		if (!code)
		    code = i;

		i = bcdb_FinishDump(&dumpEntry);
		if (!code)
		    code = i;
	    }
	}
	freeTapeList();
    }

    unmountTape(taskId, &tapeInfo);
    waitDbWatcher();

    if (code == TC_ABORTEDBYREQUEST) {
	TLog(taskId, "RestoreDb: Aborted by request\n");
	clearStatus(taskId, ABORT_REQUEST);
	setStatus(taskId, ABORT_DONE);
    } else if (code) {
	TapeLog(0, taskId, code, 0, "RestoreDb: Finished with errors\n");
	setStatus(taskId, TASK_ERROR);
    } else {
	TLog(taskId, "RestoreDb: Finished\n");
    }

    LeaveDeviceQueue(deviceLatch);
    setStatus(taskId, TASK_DONE);

    return (void *)(intptr_t)(code);
}
Пример #6
0
afs_int32
getScanTape(afs_int32 taskId, struct butm_tapeInfo *tapeInfoPtr, char *tname,
            afs_int32 tapeId, int prompt, struct butm_tapeLabel *tapeLabelPtr)
{
    afs_int32 code = 0;
    int tapecount = 1;
    afs_int32 curseq;
    char tapename[BU_MAXTAPELEN + 32];
    char gotname[BU_MAXTAPELEN + 32];

    while (1) {
        /* prompt for a tape */
        if (prompt) {
            code =
                PromptForTape(SCANOPCODE, tname, tapeId, taskId, tapecount);
            if (code)
                ERROR_EXIT(code);
        }
        prompt = 1;
        tapecount++;

        code = butm_Mount(tapeInfoPtr, "");	/* open the tape device */
        if (code) {
            TapeLog(0, taskId, code, tapeInfoPtr->error, "Can't open tape\n");
            goto newtape;
        }

        /* read the label on the tape */
        code = butm_ReadLabel(tapeInfoPtr, tapeLabelPtr, 1);	/* rewind tape */
        if (code) {
            ErrorLog(0, taskId, code, tapeInfoPtr->error,
                     "Can't read tape label\n");
            goto newtape;
        }
        tapepos = tapeInfoPtr->position - 1;

        /* Now check that the tape is good */
        TAPENAME(tapename, tname, tapeId);
        TAPENAME(gotname, tapeLabelPtr->AFSName, tapeLabelPtr->dumpid);

        curseq = extractTapeSeq(tapeLabelPtr->AFSName);

        /* Label can't be null or a bad name */
        if (!strcmp(tapeLabelPtr->AFSName, "") || (curseq <= 0)) {
            TLog(taskId, "Expected tape with dump, label seen %s\n", gotname);
            goto newtape;
        }

        /* Label can't be a database tape */
        if (databaseTape(tapeLabelPtr->AFSName)) {
            TLog(taskId,
                 "Expected tape with dump. Can't scan database tape %s\n",
                 gotname);
            goto newtape;
        }

        /* If no name, accept any tape */
        if (strcmp(tname, "") == 0) {
            break;		/* Start scan on any tape */
#ifdef notdef
            if (curseq == 1)
                break;		/* The first tape */
            else {
                TLog(taskId, "Expected first tape of dump, label seen %s\n",
                     gotname);
                goto newtape;
            }
#endif
        }

        if (strcmp(tname, tapeLabelPtr->AFSName)
                || ((tapeLabelPtr->structVersion >= TAPE_VERSION_3)
                    && (tapeLabelPtr->dumpid != tapeId))) {
            TLog(taskId, "Tape label expected %s, label seen %s\n", tapename,
                 gotname);
            goto newtape;
        }

        /* We have the correct tape */
        break;

newtape:
        unmountTape(taskId, tapeInfoPtr);
    }

error_exit:
    return (code);
}
Пример #7
0
static int
readDump(afs_uint32 taskId, struct butm_tapeInfo *tapeInfoPtr,
         struct tapeScanInfo *scanInfoPtr)
{
    int moreTapes = 1;
    afs_int32 flags, seq;
    afs_uint32 nbytes = 0;
    int newDump = 1, newTape = 1;
    afs_int32 tapePosition;
    afs_int32 code = 0, tcode;
    int badscan;
    struct volumeHeader volHeader, volTrailer;
    struct budb_tapeEntry tapeEntry;
    struct budb_volumeEntry volEntry;

    volEntry.dump = 0;
    PrintDumpLabel(&scanInfoPtr->dumpLabel);

    while (moreTapes) {
        /* While there is a tape to read *//*t */
        badscan = 0;
        while (1) {
            /* Read each volume on the tape *//*w */
            moreTapes = -1;
            tapePosition = tapeInfoPtr->position;	/* remember position */

            /*
             * Skip the volume data
             */
            tcode =
                scanVolData(taskId, tapeInfoPtr,
                            scanInfoPtr->tapeLabel.structVersion, &volHeader,
                            &volTrailer, &nbytes);
            if (tcode) {
                badscan++;

                if (tcode == TC_ABORTEDBYREQUEST) {	/* Aborted */
                    ERROR_EXIT(tcode);
                }

                if (tcode == BUTM_EOD) {
                    moreTapes = 0;	/* the end of the dump */
                    break;
                }

                /* Found a volume but it's incomplete. Skip over these */
                if (volHeader.volumeID) {
                    TapeLog(0, taskId, tcode, 0,
                            "Warning: volume %s (%u) ignored. Incomplete\n",
                            volHeader.volumeName, volHeader.volumeID);
                    continue;
                }

                /* No volume was found. We may have hit the EOT or a
                 * bad-spot. Try to skip over this spot.
                 */
                if (badscan < 2) {	/* allow 2 errors, then fail */
                    TapeLog(0, taskId, tcode, 0,
                            "Warning: Error in scanning tape - will try skipping volume\n");
                    continue;
                }
                if (scanInfoPtr->tapeLabel.structVersion >= TAPE_VERSION_4) {
                    TapeLog(0, taskId, tcode, 0,
                            "Warning: Error in scanning tape - end-of-tape inferred\n");
                    moreTapes = 1;	/* then assume next tape */
                } else {
                    ErrorLog(0, taskId, tcode, 0, "Error in scanning tape\n");
                    /* will ask if there is a next tape */
                }
                break;
            }

            PrintVolumeHeader(&volHeader);

            /* If this is not the first volume fragment, make sure it follows
             * the last volume fragment
             */
            if (volEntry.dump) {
                if ((volEntry.dump != volHeader.dumpID)
                        || (volEntry.id != volHeader.volumeID)
                        || (volEntry.seq != volHeader.frag - 2)
                        || (strcmp(volEntry.name, volHeader.volumeName))) {
                    TLog(taskId,
                         "Warning: volume %s (%u) ignored. Incomplete - no last fragment\n",
                         volEntry.name, volEntry.id);

                    if (scanInfoPtr->addDbFlag) {
                        tcode = flushSavedEntries(DUMP_FAILED);
                        if (tcode)
                            ERROR_EXIT(tcode);
                        volEntry.dump = 0;
                    }
                }
            }

            /* If this is the first volume fragment, make sure says so */
            if (scanInfoPtr->addDbFlag && !volEntry.dump
                    && (volHeader.frag != 1)) {
                TLog(taskId,
                     "Warning: volume %s (%u) ignored. Incomplete - no first fragment\n",
                     volHeader.volumeName, volHeader.volumeID);
            }

            /* Check that this volume belongs to the dump we are scanning */
            else if (scanInfoPtr->dumpLabel.dumpid
                     && (volHeader.dumpID != scanInfoPtr->dumpLabel.dumpid)) {
                TLog(taskId,
                     "Warning: volume %s (%u) ignored. Expected DumpId %u, got %u\n",
                     volHeader.volumeName, volHeader.volumeID,
                     scanInfoPtr->dumpLabel.dumpid, volHeader.dumpID);
            }

            /* Passed tests, Now add to the database (if dbadd flag is set) */
            else if (scanInfoPtr->addDbFlag) {
                /* Have enough information to create a dump entry */
                if (newDump) {
                    tcode = RcreateDump(scanInfoPtr, &volHeader);
                    if (tcode) {
                        ErrorLog(0, taskId, tcode, 0,
                                 "Can't add dump %u to database\n",
                                 volHeader.dumpID);
                        ERROR_EXIT(tcode);
                    }
                    newDump = 0;
                }

                /* Have enough information to create a tape entry */
                if (newTape) {
                    seq = extractTapeSeq(scanInfoPtr->tapeLabel.AFSName);
                    if (seq < 0)
                        ERROR_EXIT(TC_INTERNALERROR);

                    tcode =
                        useTape(&tapeEntry, volHeader.dumpID,
                                TNAME(&scanInfoPtr->tapeLabel), seq,
                                scanInfoPtr->tapeLabel.useCount,
                                scanInfoPtr->dumpLabel.creationTime,
                                scanInfoPtr->dumpLabel.expirationDate,
                                tapepos);
                    if (tcode) {
                        char gotName[BU_MAXTAPELEN + 32];

                        LABELNAME(gotName, &scanInfoPtr->tapeLabel);
                        ErrorLog(0, taskId, tcode, 0,
                                 "Can't add tape %s for dump %u to database\n",
                                 gotName, volHeader.dumpID);
                        ERROR_EXIT(tcode);
                    }
                    newTape = 0;
                }

                /* Create the volume entry */
                flags = ((volHeader.frag == 1) ? BUDB_VOL_FIRSTFRAG : 0);
                if (!volTrailer.contd)
                    flags |= BUDB_VOL_LASTFRAG;
                tcode =
                    addVolume(&volEntry, volHeader.dumpID,
                              TNAME(&scanInfoPtr->tapeLabel),
                              volHeader.volumeName, volHeader.volumeID,
                              volHeader.cloneDate, tapePosition, nbytes,
                              (volHeader.frag - 1), flags);
                if (tcode) {
                    ErrorLog(0, taskId, tcode, 0,
                             "Can't add volume %s (%u) for dump %u to database\n",
                             volHeader.volumeName, volHeader.volumeID,
                             volHeader.dumpID);
                    ERROR_EXIT(tcode);
                }
            }

            if (volTrailer.contd) {
                /* No need to read the EOD marker, we know there is a next tape */
                moreTapes = 1;
                break;
            } else {
                if (scanInfoPtr->addDbFlag) {
                    tcode = flushSavedEntries(DUMP_SUCCESS);
                    if (tcode)
                        ERROR_EXIT(tcode);
                    volEntry.dump = 0;
                }
            }
        }			/*w */

        if (!newTape) {
            if (scanInfoPtr->addDbFlag) {
                tcode =
                    finishTape(&tapeEntry,
                               (tapeInfoPtr->kBytes +
                                (tapeInfoPtr->nBytes ? 1 : 0)));
                if (tcode) {
                    char gotName[BU_MAXTAPELEN + 32];

                    LABELNAME(gotName, &scanInfoPtr->tapeLabel);
                    ErrorLog(0, taskId, tcode, 0,
                             "Can't mark tape %s 'completed' for dump %u in database\n",
                             gotName, tapeEntry.dump);
                    ERROR_EXIT(tcode);
                }
            }
        }

        /* Ask if there is another tape if we can't figure it out */
        if (moreTapes == -1)
            moreTapes = (queryoperator ? Ask("Are there more tapes") : 1);

        /* Get the next tape label */
        if (moreTapes) {
            char *tapeName;
            afs_int32 dumpid;

            unmountTape(taskId, tapeInfoPtr);

            tapeName = nextTapeLabel(scanInfoPtr->tapeLabel.AFSName);
            dumpid = scanInfoPtr->tapeLabel.dumpid;
            tcode =
                getScanTape(taskId, tapeInfoPtr, tapeName, dumpid, 1,
                            &scanInfoPtr->tapeLabel);
            if (tcode)
                ERROR_EXIT(tcode);
            newTape = 1;
        }
    }				/*t */

    if (!newDump) {
        if (scanInfoPtr->addDbFlag) {
            tcode = finishDump(&scanInfoPtr->dumpEntry);
            if (tcode) {
                ErrorLog(0, taskId, tcode, 0,
                         "Can't mark dump %u 'completed' in database\n",
                         scanInfoPtr->dumpEntry.id);
            }

            tcode = flushSavedEntries(DUMP_SUCCESS);
            if (tcode)
                ERROR_EXIT(tcode);
        }
    }

error_exit:
    return (code);
}
Пример #8
0
static int
scanVolData(afs_int32 taskId, struct butm_tapeInfo *curTapePtr,
            afs_int32 tapeVersion, struct volumeHeader *volumeHeader,
            struct volumeHeader *volumeTrailer, afs_uint32 *bytesRead)
{
    afs_int32 headBytes, tailBytes;
    char *block = NULL;
    char *buffer[2];
    int hasdata[2], curr, prev;
    afs_uint32 chunkSize = 0;
    afs_int32 nbytes;
    afs_int32 code = 0;
    afs_int32 rcode, tcode;

    memset(volumeHeader, 0, sizeof(struct volumeHeader));

    block = (char *)malloc(2 * BUTM_BLOCKSIZE);
    if (!block)
        return (TC_NOMEMORY);
    buffer[0] = &block[sizeof(struct blockMark)];
    buffer[1] = &block[BUTM_BLOCKSIZE + sizeof(struct blockMark)];
    hasdata[0] = hasdata[1] = 0;
    curr = 0;

    tcode = NextFile(curTapePtr);	/* guarantees we are at a filemark */
    if (tcode)
        ERROR_EXIT(tcode)

        /* Read the FileBegin FileMark */
        code = butm_ReadFileBegin(curTapePtr);
    if (code) {
        /*
         * Tapes made with 3.0 have no software EOT markers. Therefore
         * at this point, we will most likely get a read error, indicating
         * the end of this dump
         */
        if ((tapeVersion == TAPE_VERSION_0)
                || (tapeVersion == TAPE_VERSION_1)) {
            /*
             * then a tape error is possible at this point, and it
             * signals the end of the dump. Tapes that are continued
             * have an EOT marker.
             */
            TapeLog(0, taskId, code, curTapePtr->error,
                    "Read error - end-of-dump inferred\n");
            code = BUTM_EOD;
        }

        if (code != BUTM_EOD)
            ErrorLog(0, taskId, code, curTapePtr->error,
                     "Can't read FileBegin on tape\n");
        ERROR_EXIT(code);
    }

    /* now read the volume header */
    code = ReadVolHeader(taskId, curTapePtr, volumeHeader);
    if (code)
        ERROR_EXIT(code);

    *bytesRead = 0;
    while (1) {			/*w */

        /* Check for abort in the middle of scanning data */
        if (*bytesRead >= chunkSize) {
            if (checkAbortByTaskId(taskId))
                ERROR_EXIT(TC_ABORTEDBYREQUEST);
            chunkSize += BIGCHUNK;
        }

        /*
         * Read volume date - If prematurely hit the HW EOF
         * marker, check to see if data contains a volumetrailer.
         */
        rcode =
            butm_ReadFileData(curTapePtr, buffer[curr], BUTM_BLKSIZE,
                              &nbytes);
        if (rcode) {
            hasdata[curr] = 0;
            if ((rcode == BUTM_EOF) || (rcode == BUTM_ENDVOLUME))
                break;

            ErrorLog(0, taskId, rcode, curTapePtr->error,
                     "Can't read FileData on tape\n");
            ERROR_EXIT(rcode)
        }
        hasdata[curr] = 1;
        *bytesRead += nbytes;

        if ((nbytes != BUTM_BLKSIZE)
                ||
                (FindVolTrailer(buffer[curr], nbytes, &tailBytes, volumeTrailer)))
            break;

        curr = ((curr == 0) ? 1 : 0);	/* Switch buffers */
    }				/*w */

    /* Now verify that there is a volume trailer and its valid and copy it */
    prev = ((curr == 0) ? 1 : 0);
    if (!FindVolTrailer2
            (buffer[prev], (hasdata[prev] ? BUTM_BLKSIZE : 0), &headBytes,
             buffer[curr], nbytes, &tailBytes, volumeTrailer)) {
        code = TC_MISSINGTRAILER;
        ErrorLog(0, taskId, code, 0, "Missing volume trailer on tape\n");
    } else {
        /* subtract size of the volume trailer from data read */
        *bytesRead -= sizeof(struct volumeHeader);
    }

    /*
     * If we didn't hit the EOF while reading data, read FileEnd marker
     * or EOF marker.
     */
    if (!rcode) {
        tcode = butm_ReadFileEnd(curTapePtr);
        if (tcode) {
            ErrorLog(0, taskId, tcode, curTapePtr->error,
                     "Can't read EOF on tape\n");
            ERROR_EXIT(tcode);
        }
    }

error_exit:
    if (block)
        free(block);
    return (code);
}
Пример #9
0
static int
WorkerBee(struct cmd_syndesc *as, void *arock)
{
    afs_int32 code, numClasses;
    struct rx_securityClass *(nullObjects[1]), **secObjs, **allObjs;
    struct rx_service *service;
    time_t tokenExpires;
    char cellName[64];
    int localauth;
    /*process arguments */
    afs_int32 portOffset = 0;
#ifdef AFS_PTHREAD_ENV
    pthread_t dbWatcherPid;
    pthread_attr_t tattr;
    AFS_SIGSET_DECL;
#else
    PROCESS dbWatcherPid;
#endif
    char hoststr[16];
    afs_uint32 host = htonl(INADDR_ANY);
    char *auditFileName = NULL;
    char *auditInterface = NULL;

    debugLevel = 0;

    /*initialize the error tables */
    initialize_KA_error_table();
    initialize_RXK_error_table();
    initialize_KTC_error_table();
    initialize_ACFG_error_table();
    initialize_CMD_error_table();
    initialize_VL_error_table();
    initialize_BUTM_error_table();
    initialize_BUTC_error_table();
#ifdef xbsa
    initialize_BUTX_error_table();
#endif /*xbs */
    initialize_VOLS_error_table();
    initialize_BUDB_error_table();
    initialize_BUCD_error_table();

    if (as->parms[0].items) {
	portOffset = SafeATOL(as->parms[0].items->data);
	if (portOffset == -1) {
	    fprintf(stderr, "Illegal port offset '%s'\n",
		    as->parms[0].items->data);
	    exit(1);
	} else if (portOffset > BC_MAXPORTOFFSET) {
	    fprintf(stderr, "%u exceeds max port offset %u\n", portOffset,
		    BC_MAXPORTOFFSET);
	    exit(1);
	}
    }

    xbsaType = XBSA_SERVER_TYPE_NONE;	/* default */
    if (as->parms[3].items) {	/* -device */
	globalTapeConfig.capacity = 0x7fffffff;	/* 2T for max tape capacity */
	globalTapeConfig.fileMarkSize = 0;
	globalTapeConfig.portOffset = portOffset;
	strncpy(globalTapeConfig.device, as->parms[3].items->data, 100);
	xbsaType = XBSA_SERVER_TYPE_NONE;	/* Not XBSA */
    } else {
	/* Search for an entry in tapeconfig file */
	code = GetDeviceConfig(tapeConfigFile, &globalTapeConfig, portOffset);
	if (code == -1) {
	    fprintf(stderr, "Problem in reading config file %s\n",
		    tapeConfigFile);
	    exit(1);
	}
	/* Set xbsaType. If code == 1, no entry was found in the tapeconfig file so
	 * it's an XBSA server. Don't know if its ADSM or not so its unknown.
	 */
	xbsaType =
	    ((code == 1) ? XBSA_SERVER_TYPE_UNKNOWN : XBSA_SERVER_TYPE_NONE);
    }

    if (as->parms[6].items) {	/* -restoretofile */
	restoretofile = strdup(as->parms[6].items->data);
	printf("Restore to file '%s'\n", restoretofile);
    }

    /* Go and read the config file: CFG_<device> or CFG_<port>. We will also set
     * the exact xbsaType within the call (won't be unknown) - double check.
     */
    code = GetConfigParams(pFile, portOffset);
    if (code)
	exit(code);
#ifdef xbsa
    if (xbsaType == XBSA_SERVER_TYPE_UNKNOWN) {
	printf
	    ("\nConfiguration file error, the TYPE parameter must be specified, or\n");
	printf("an entry must exist in %s for port %d\n", tapeConfigFile,
	       portOffset);
	exit(1);
    }
#else
    /* Not compiled for XBSA code so we can't support it */
    if (CONF_XBSA) {
	printf("\nNo entry found in %s for port %d\n", tapeConfigFile,
	       portOffset);
	printf("This binary does not have XBSA support\n");
	exit(1);
    }
#endif

    /* Open the log files. The pathnames were set in GetConfigParams() */
    logIO = fopen(logFile, "a");
    if (!logIO) {
	fprintf(stderr, "Failed to open %s\n", logFile);
	exit(1);
    }
    ErrorlogIO = fopen(ErrorlogFile, "a");
    if (!ErrorlogIO) {
	fprintf(stderr, "Failed to open %s\n", ErrorlogFile);
	exit(1);
    }
    if (lastLog) {
	lastLogIO = fopen(lastLogFile, "a");
	if (!lastLogIO) {
	    fprintf(stderr, "Failed to open %s\n", lastLogFile);
	    exit(1);
	}
    }
    if (centralLogFile) {
	struct stat sbuf;
	afs_int32 statcode;
#ifndef AFS_NT40_ENV
	char *path;
#endif

	statcode = stat(centralLogFile, &sbuf);
	centralLogIO = fopen(centralLogFile, "a");
	if (!centralLogIO) {
	    fprintf(stderr, "Failed to open %s; error %d\n", centralLogFile,
		    errno);
	    exit(1);
	}
#ifndef AFS_NT40_ENV
	/* Make sure it is not in AFS, has to have been created first */
	path = malloc(AFSDIR_PATH_MAX);
	if (path == NULL || !realpath(centralLogFile, path)) {
	    fprintf(stderr,
		    "Warning: can't determine real path of '%s' (%d)\n",
		    centralLogFile, errno);
	} else {
	    if (strncmp(path, "/afs/", 5) == 0) {
		fprintf(stderr, "The central log '%s' should not be in AFS\n",
			centralLogFile);
		exit(1);
	    }
	}
	free(path);
#endif

	/* Write header if created it */
	if (statcode) {
	    char *h1 =
		"TASK   START DATE/TIME      END DATE/TIME        ELAPSED   VOLUMESET\n";
	    char *h2 =
		"-----  -------------------  -------------------  --------  ---------\n";
	    /* File didn't exist before so write the header lines */
	    fwrite(h1, strlen(h1), 1, centralLogIO);
	    fwrite(h2, strlen(h2), 1, centralLogIO);
	    fflush(centralLogIO);
	}
    }

    /* Open the configuration directory */
    butc_confdir = afsconf_Open(AFSDIR_SERVER_ETC_DIRPATH);
    if (butc_confdir == NULL) {
	TLog(0, "Failed to open server configuration directory");
	exit(1);
    }

    /* Start auditing */
    osi_audit_init();
    if (as->parms[9].items) {
	auditFileName = as->parms[9].items->data;
    }
    if (auditFileName != NULL)
	osi_audit_file(auditFileName);
    if (as->parms[10].items) {
	auditInterface = as->parms[10].items->data;
	if (osi_audit_interface(auditInterface)) {
	    TLog(0, "Invalid audit interface '%s'\n", auditInterface);
	    exit(1);
	}
    }
    osi_audit(TC_StartEvent, 0, AUD_END);
    osi_audit_set_user_check(butc_confdir, tc_IsLocalRealmMatch);

    if (as->parms[1].items) {
	debugLevel = SafeATOL(as->parms[1].items->data);
	if (debugLevel == -1) {
	    TLog(0, "Illegal debug level '%s'\n", as->parms[1].items->data);
	    exit(1);
	}
    }
#ifdef xbsa
    /* Setup XBSA library interface */
    if (CONF_XBSA) {
	afs_int32 rc;
	rc = xbsa_MountLibrary(&butxInfo, xbsaType);
	if (rc != XBSA_SUCCESS) {
	    TapeLog(0, 0, rc, 0, "Unable to mount the XBSA library\n");
	    return (1);
	}

	forcemultiple = (as->parms[7].items ? 1 : 0);/*-xbsaforcemultiple */
	if (forcemultiple)
	    printf("Force XBSA multiple server support\n");

	rc = InitToServer(0 /*taskid */ , &butxInfo, adsmServerName);
	if (rc != XBSA_SUCCESS)
	    return (1);
	(void)signal(SIGINT, xbsa_shutdown);
	(void)signal(SIGHUP, xbsa_shutdown);
    }
#endif /*xbsa */

    /* cell switch */
    if (as->parms[2].items)
	strncpy(cellName, as->parms[2].items->data, sizeof(cellName));
    else
	cellName[0] = '\0';

    if (as->parms[4].items)
	autoQuery = 0;

    localauth = (as->parms[5].items ? 1 : 0);
    rxBind = (as->parms[8].items ? 1 : 0);
    allow_unauth = (as->parms[11].items ? 1 : 0);

    if (!allow_unauth && !localauth) {
	const char *errstr = "Neither -localauth nor -allow_unauthenticated was provided; refusing to start in unintended insecure configuration\n";
	TLog(0, "%s", (char *)errstr);
	exit(1);
    }

    if (rxBind) {
        afs_int32 ccode;
        if (AFSDIR_SERVER_NETRESTRICT_FILEPATH ||
            AFSDIR_SERVER_NETINFO_FILEPATH) {
            char reason[1024];
            ccode = afsconf_ParseNetFiles(SHostAddrs, NULL, NULL,
                                          ADDRSPERSITE, reason,
                                          AFSDIR_SERVER_NETINFO_FILEPATH,
                                          AFSDIR_SERVER_NETRESTRICT_FILEPATH);
        } else
	{
            ccode = rx_getAllAddr(SHostAddrs, ADDRSPERSITE);
        }
        if (ccode == 1)
            host = SHostAddrs[0];
    }

    TLog(0, "butc binding rx to %s:%d\n",
         afs_inet_ntoa_r(host, hoststr), BC_TAPEPORT + portOffset);
    code = rx_InitHost(host, htons(BC_TAPEPORT + portOffset));
    if (code) {
	TapeLog(0, 0, code, 0, "rx init failed on port %u\n",
		BC_TAPEPORT + portOffset);
	exit(1);
    }
    rx_SetRxDeadTime(150);

    /* Establish connection with the vldb server */
    code = vldbClientInit(0, localauth, cellName, &cstruct, &tokenExpires);
    if (code) {
	TapeLog(0, 0, code, 0, "Can't access vldb\n");
	return code;
    }

    strcpy(globalCellName, cellName);

    /*initialize the dumpNode list */
    InitNodeList(portOffset);

    deviceLatch = malloc(sizeof(struct deviceSyncNode));
    Lock_Init(&(deviceLatch->lock));
    deviceLatch->flags = 0;

    /* initialize database support, volume support, and logs */

    /*
     * Create security objects for the Rx server functionality.  Historically
     * this was a single rxnull security object, since the tape controller was
     * run by an operator that had local access to the tape device and some
     * administrative privilege in the cell (to be able to perform volume-level
     * accesses), but on a machine that was not necessarily trusted to hold the
     * cell-wide key.
     *
     * Such a configuration is, of course, insecure because anyone can make
     * inbound RPCs and manipulate the database, including creating bogus
     * dumps and restoring them!  Additionally, in modern usage, butc is
     * frequently run with -localauth to authenticate its outbound connections
     * to the volservers and budb with the cell-wide key, in which case the
     * cell-wide key is present and could be used to authenticate incoming
     * connections as well.
     *
     * If -localauth is in use, create the full barrage of server security
     * objects, including rxkad, so that inbound connections can be verified
     * to only be made by authenticated clients.  Otherwise, only the rxnull
     * class is in use with a single server security object.  Note that butc
     * will refuse to start in this configuration unless the
     * "-allow_unauthenticated" flag is provided, indicating that the operator
     * has ensured that incoming connections are appropriately restricted by
     * firewall configuration or network topology.
     */

    if (allow_unauth) {
	nullObjects[RX_SECIDX_NULL] = rxnull_NewServerSecurityObject();
	if (!nullObjects[RX_SECIDX_NULL]) {
	    TLog(0, "rxnull_NewServerSecurityObject");
	    exit(1);
	}
	numClasses = 1;
	secObjs = nullObjects;
    } else {
	/* Must be -localauth, so the cell keys are available. */
	afsconf_BuildServerSecurityObjects(butc_confdir, &allObjs, &numClasses);
	secObjs = allObjs;
    }

    service =
	rx_NewServiceHost(host, 0, 1, "BUTC", secObjs, numClasses, TC_ExecuteRequest);
    if (!service) {
	TLog(0, "rx_NewService");
	exit(1);
    }
    rx_SetMaxProcs(service, 4);

    /* Establish connection to the backup database */
    code = udbClientInit(0, localauth, cellName);
    if (code) {
	TapeLog(0, 0, code, 0, "Can't access backup database\n");
	exit(1);
    }
    /* This call is here to verify that we are authentiated.
     * The call does nothing and will return BUDB_NOTPERMITTED
     * if we don't belong.
     */
    code = bcdb_deleteDump(0, 0, 0, 0);
    if (code == BUDB_NOTPERMITTED) {
	TapeLog(0, 0, code, 0, "Can't access backup database\n");
	exit(1);
    }

    initStatus();
#ifdef AFS_PTHREAD_ENV
    code = pthread_attr_init(&tattr);
    if (code) {
	TapeLog(0, 0, code, 0,
		"Can't pthread_attr_init database monitor task");
	exit(1);
    }
    code = pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
    if (code) {
	TapeLog(0, 0, code, 0,
		"Can't pthread_attr_setdetachstate database monitor task");
	exit(1);
    }
    AFS_SIGSET_CLEAR();
    code = pthread_create(&dbWatcherPid, &tattr, dbWatcher, (void *)2);
    AFS_SIGSET_RESTORE();
#else
    code =
	LWP_CreateProcess(dbWatcher, 20480, LWP_NORMAL_PRIORITY, (void *)2,
			  "dbWatcher", &dbWatcherPid);
#endif
    if (code) {
	TapeLog(0, 0, code, 0, "Can't create database monitor task");
	exit(1);
    }

    TLog(0, "Starting Tape Coordinator: Port offset %u   Debug level %u\n",
	 portOffset, debugLevel);
    TLog(0, "Token expires: %s\n", cTIME(&tokenExpires));

    rx_StartServer(1);		/* Donate this process to the server process pool */
    TLog(0, "Error: StartServer returned");
    exit(1);
}