/* * Copyright 2000, International Business Machines Corporation and others. * All Rights Reserved. * * This software has been released under the terms of the IBM Public * License. For details, see the LICENSE file in the top-level source * directory or online at http://www.openafs.org/dl/license10.html */ /* * ALL RIGHTS RESERVED */ #include #include #include #include #ifdef AFS_NT40_ENV #include #else #include #include #include #include #include #endif #include #include #include #include #include #include /* for checking TC_ABORTFAILED. PA */ #include /* for checking TC_ABORTFAILED. PA */ #include #include "bc.h" #include "error_macros.h" #include "bucoord_internal.h" #include "bucoord_prototypes.h" struct bc_dumpTask bc_dumpTasks[BC_MAXSIMDUMPS]; extern char *whoami; extern afs_int32 lastTaskCode; #define HOSTADDR(sockaddr) (sockaddr)->sin_addr.s_addr /* bc_Dumper * called (indirectly) to make a dump * entry: * aindex - index into dumpTask array, contains all the information * relevant to the dump */ int bc_Dumper(int aindex) { struct rx_connection *tconn; register struct bc_volumeDump *tde; afs_int32 count, port; struct tc_dumpDesc *volDesc = 0; struct tc_dumpArray volArray; char *baseNamePtr; statusP statusPtr; struct tc_dumpInterface dumpInterface; struct tc_dumpInterface *tcdiPtr = &dumpInterface; register struct bc_dumpTask *dumpTaskPtr; register afs_int32 code = 0; dumpTaskPtr = &bc_dumpTasks[aindex]; if (!dumpTaskPtr->portOffset || (dumpTaskPtr->portCount == 0)) port = 0; else port = dumpTaskPtr->portOffset[0]; code = ConnectButc(dumpTaskPtr->config, port, &tconn); if (code) return (code); /* count number of volumes to be dumped and * build array of volumes to be sent to backup system */ for (count = 0, tde = dumpTaskPtr->volumes; tde; tde = tde->next, count++); volDesc = (struct tc_dumpDesc *)malloc(count * sizeof(struct tc_dumpDesc)); if (!volDesc) { afs_com_err(whoami, BC_NOMEM, NULL); ERROR(BC_NOMEM); } for (count = 0, tde = dumpTaskPtr->volumes; tde; tde = tde->next, count++) { strcpy(volDesc[count].name, tde->name); volDesc[count].vid = tde->vid; volDesc[count].vtype = tde->volType; volDesc[count].partition = tde->partition; volDesc[count].hostAddr = HOSTADDR(&tde->server); /* the internet address */ volDesc[count].date = tde->date; volDesc[count].cloneDate = tde->cloneDate; /* Not yet known */ } volArray.tc_dumpArray_len = count; /* element count */ volArray.tc_dumpArray_val = volDesc; /* and data */ baseNamePtr = tailCompPtr(dumpTaskPtr->dumpName); /* setup the interface structure */ memset(tcdiPtr, 0, sizeof(*tcdiPtr)); /* general */ strcpy(tcdiPtr->dumpPath, dumpTaskPtr->dumpName); strcpy(tcdiPtr->volumeSetName, dumpTaskPtr->volSetName); /* tapeset */ strcpy(tcdiPtr->tapeSet.format, dumpTaskPtr->volSetName); strcat(tcdiPtr->tapeSet.format, "."); strcat(tcdiPtr->tapeSet.format, baseNamePtr); strcat(tcdiPtr->tapeSet.format, ".%d"); tcdiPtr->tapeSet.a = 1; tcdiPtr->tapeSet.b = 1; tcdiPtr->tapeSet.maxTapes = 1000000000; tcdiPtr->tapeSet.expDate = dumpTaskPtr->expDate; /* PA */ tcdiPtr->tapeSet.expType = dumpTaskPtr->expType; /* construct dump set name */ strcpy(tcdiPtr->dumpName, dumpTaskPtr->volSetName); strcat(tcdiPtr->dumpName, "."); strcat(tcdiPtr->dumpName, baseNamePtr); tcdiPtr->parentDumpId = dumpTaskPtr->parentDumpID; tcdiPtr->dumpLevel = dumpTaskPtr->dumpLevel; tcdiPtr->doAppend = dumpTaskPtr->doAppend; /* start the dump on the tape coordinator */ printf("Starting dump\n"); code = TC_PerformDump(tconn, tcdiPtr, &volArray, &dumpTaskPtr->dumpID); if (code) { afs_com_err(whoami, code, "; Failed to start dump"); ERROR(code); } afs_com_err(whoami, 0, "Task %u: Dump (%s)", dumpTaskPtr->dumpID, tcdiPtr->dumpName); /* create status monitor block */ statusPtr = createStatusNode(); lock_Status(); statusPtr->taskId = dumpTaskPtr->dumpID; statusPtr->port = port; statusPtr->jobNumber = bc_jobNumber(); statusPtr->volsTotal = volArray.tc_dumpArray_len; statusPtr->flags &= ~STARTING; sprintf(statusPtr->taskName, "Dump (%s.%s)", dumpTaskPtr->volSetName, baseNamePtr); unlock_Status(); error_exit: /* locally allocated resources */ if (volDesc) free(volDesc); if (tconn) rx_DestroyConnection(tconn); return (code); } /* freeDumpTaskVolumeList * free the list of volumes used for dumps */ void freeDumpTaskVolumeList(struct bc_volumeDump *vdptr) { struct bc_volumeDump *nextVdPtr; while (vdptr != 0) { nextVdPtr = vdptr->next; if (vdptr->name) free(vdptr->name); free(vdptr); vdptr = nextVdPtr; } } /* bc_DmpRstStart * The other half of the dump/restore create process call. In bc_StartDmpRst, * we allocated a dumpTask entry. Here we do the task and then free the entry. */ void * bc_DmpRstStart(void *param) { afs_int32 aindex = (intptr_t)param; register struct bc_dumpTask *tdump; register afs_int32 code; tdump = &bc_dumpTasks[aindex]; code = (tdump->callProc) (aindex); if (code) lastTaskCode = code; /* Cleanup allocated data structures */ freeDumpTaskVolumeList(tdump->volumes); tdump->dumpID = 0; if (tdump->dumpName) free(tdump->dumpName); if (tdump->newExt) free(tdump->newExt); if (tdump->volSetName) free(tdump->volSetName); if (tdump->portOffset) free(tdump->portOffset); tdump->flags &= ~BC_DI_INUSE; return (void *)(intptr_t)code; } /* bc_StartDmpRst * function to start dump running. Packages the relevant information * (from params) into any free dumpTask structure (globally allocated), * and then invokes bc_DmpRstStart to do the work, passing it a single * parameter, the index into the dumpTask array. * * entry: * aconfig - normally is bc_globalConfig * aproc - bc_Dumper for doing dumps * bc_Restorer for doing restores */ int bc_StartDmpRst(struct bc_config *aconfig, char *adname, char *avname, struct bc_volumeDump *avolsToDump, struct sockaddr_in *adestServer, afs_int32 adestPartition, afs_int32 afromDate, char *anewExt, int aoldFlag, afs_int32 aparent, afs_int32 alevel, int (*aproc) (int), afs_int32 *ports, afs_int32 portCount, struct bc_dumpSchedule *dsptr, int append, int dontExecute) { register int i; register afs_int32 code; void *junk = NULL; for (i = 0; i < BC_MAXSIMDUMPS; i++) if (!(bc_dumpTasks[i].flags & BC_DI_INUSE)) break; if (i >= BC_MAXSIMDUMPS) { afs_com_err(whoami, BC_NOTLOCKED, "All of the dump/restore slots are in use, try again later"); return (BC_NOTLOCKED); } memset(&bc_dumpTasks[i], 0, sizeof(struct bc_dumpTask)); bc_dumpTasks[i].callProc = aproc; bc_dumpTasks[i].config = aconfig; bc_dumpTasks[i].volumes = avolsToDump; bc_dumpTasks[i].flags = BC_DI_INUSE; bc_dumpTasks[i].dumpName = bc_CopyString(adname); bc_dumpTasks[i].volSetName = bc_CopyString(avname); bc_dumpTasks[i].newExt = bc_CopyString(anewExt); bc_dumpTasks[i].dumpLevel = alevel; bc_dumpTasks[i].parentDumpID = aparent; bc_dumpTasks[i].oldFlag = aoldFlag; bc_dumpTasks[i].fromDate = afromDate; bc_dumpTasks[i].destPartition = adestPartition; bc_dumpTasks[i].portOffset = ports; bc_dumpTasks[i].portCount = portCount; bc_dumpTasks[i].doAppend = append; bc_dumpTasks[i].dontExecute = dontExecute; if (dsptr) { /* This should be specified for dumps, but will be 0 for restores */ bc_dumpTasks[i].expDate = dsptr->expDate; bc_dumpTasks[i].expType = dsptr->expType; } if (adestServer) memcpy(&bc_dumpTasks[i].destServer, adestServer, sizeof(struct sockaddr_in)); else memset(&bc_dumpTasks[i].destServer, 0, sizeof(struct sockaddr_in)); code = LWP_CreateProcess(bc_DmpRstStart, 20480, LWP_NORMAL_PRIORITY, (void *)(intptr_t)i, "helper", junk); if (code) { bc_HandleMisc(code); afs_com_err(whoami, code, "; Can't start thread"); /* Cleanup allocated data structures */ freeDumpTaskVolumeList(bc_dumpTasks[i].volumes); bc_dumpTasks[i].dumpID = 0; if (bc_dumpTasks[i].dumpName) free(bc_dumpTasks[i].dumpName); if (bc_dumpTasks[i].newExt) free(bc_dumpTasks[i].newExt); if (bc_dumpTasks[i].volSetName) free(bc_dumpTasks[i].volSetName); if (bc_dumpTasks[i].portOffset) free(bc_dumpTasks[i].portOffset); bc_dumpTasks[i].flags &= ~BC_DI_INUSE; return (code); } return 0; } #ifdef notdef /* bc_FindDumpSlot * Returns the dump slot of the dump with dumpID * entry: * dumpID - id to look for * port - portoffset for tape coordinator * exit: * 0-n - i.e. 0 or positive number, is the dump slot * -1 - failed to find dumpID */ afs_int32 bc_FindDumpSlot(afs_int32 dumpID, afs_int32 port) { int i; for (i = 0; i < BC_MAXSIMDUMPS; i++) { if ((bc_dumpTasks[i].flags & BC_DI_INUSE) && (bc_dumpTasks[i].dumpID == dumpID) && ((afs_int32) bc_dumpTasks[i].portOffset == port)) { return (i); } } return (-1); } #endif /* bc_LabelTape * opens a connection to the tape coordinator and requests that it * label a tape */ int bc_LabelTape(char *afsname, char *pname, afs_int32 size, struct bc_config *config, afs_int32 port) { struct rx_connection *tconn; afs_int32 code = 0; struct tc_tapeLabel label; statusP statusPtr; afs_uint32 taskId; code = ConnectButc(config, port, &tconn); if (code) return (code); memset(&label, 0, sizeof(label)); if (afsname) strcpy(label.afsname, afsname); if (pname) strcpy(label.pname, (strcmp(pname, "") ? pname : "")); label.size = size; code = TC_LabelTape(tconn, &label, &taskId); if (code) { afs_com_err(whoami, code, "; Failed to start labeltape"); return (code); } /* create status monitor block */ statusPtr = createStatusNode(); lock_Status(); statusPtr->taskId = taskId; statusPtr->port = port; statusPtr->jobNumber = bc_jobNumber(); /* statusPtr->flags |= SILENT; *//* don't report termination */ statusPtr->flags &= ~STARTING; /* ok to examine */ sprintf(statusPtr->taskName, "Labeltape (%s)", (pname ? pname : (afsname ? afsname : ""))); unlock_Status(); return 0; } /* bc_ReadLabel * open a connection to the tape coordinator and read the label on * a tape */ int bc_ReadLabel(struct bc_config *config, afs_int32 port) { struct rx_connection *tconn; struct tc_tapeLabel label; afs_uint32 taskId; afs_int32 code = 0; char *tname = 0; code = ConnectButc(config, port, &tconn); if (code) return (code); memset(&label, 0, sizeof(label)); code = TC_ReadLabel(tconn, &label, &taskId); if (code) { if (code == BUTM_NOLABEL) { printf("Tape read was unlabelled\n"); return 0; } afs_com_err(whoami, code, "; Failed to start readlabel"); return (code); } if (strcmp(label.pname, "")) tname = label.pname; else if (strcmp(label.afsname, "")) tname = label.afsname; if (!tname) { printf("Tape read was labelled : size : %u\n", label.size); } else if (!label.tapeId) { printf("Tape read was labelled : %s size : %lu Kbytes\n", tname, (long unsigned int) label.size); } else { printf("Tape read was labelled : %s (%lu) size : %lu Kbytes\n", tname, (long unsigned int) label.tapeId, (long unsigned int) label.size); } return 0; } int bc_ScanDumps(struct bc_config *config, afs_int32 dbAddFlag, afs_int32 port) { struct rx_connection *tconn; statusP statusPtr; afs_uint32 taskId; afs_int32 code = 0; code = ConnectButc(config, port, &tconn); if (code) return (code); code = TC_ScanDumps(tconn, dbAddFlag, &taskId); if (code) { afs_com_err(whoami, code, "; Failed to start scantape"); return (code); } /* create status monitor block */ statusPtr = createStatusNode(); lock_Status(); statusPtr->taskId = taskId; statusPtr->port = port; statusPtr->jobNumber = bc_jobNumber(); statusPtr->flags &= ~STARTING; /* ok to examine */ sprintf(statusPtr->taskName, "Scantape"); unlock_Status(); return (0); } /*************/ /* utilities */ /*************/ /* get a connection to the tape controller */ afs_int32 bc_GetConn(struct bc_config *aconfig, afs_int32 aport, struct rx_connection **tconn) { afs_uint32 host; unsigned short port; static struct rx_securityClass *rxsc; struct bc_hostEntry *te; *tconn = (struct rx_connection *)0; /* use non-secure connections to butc */ if (!rxsc) rxsc = rxnull_NewClientSecurityObject(); if (!rxsc || !aconfig) return (-1); for (te = aconfig->tapeHosts; te; te = te->next) { if (te->portOffset == aport) { /* found the right port */ host = te->addr.sin_addr.s_addr; if (!host) return (BC_NOHOSTENTRY); /* gethostbyname in bc_ParseHosts failed */ port = htons(BC_TAPEPORT + aport); /* servers is 1; sec index is 0 */ *tconn = rx_NewConnection(host, port, 1, rxsc, 0); return ((*tconn ? 0 : -1)); } } return (BC_NOHOSTENTRY); } /* CheckTCVersion * make sure we are talking to a compatible butc process. * exit: * 0 - ok * -1 - not compatible */ int CheckTCVersion(struct rx_connection *tconn) { struct tc_tcInfo tci; afs_int32 code; code = TC_TCInfo(tconn, &tci); if (code) return (code); if (tci.tcVersion != CUR_BUTC_VERSION) return (BC_VERSIONFAIL); return 0; } int ConnectButc(struct bc_config *config, afs_int32 port, struct rx_connection **tconn) { afs_int32 code; code = bc_GetConn(config, port, tconn); if (code) { afs_com_err(whoami, code, "; Can't connect to tape coordinator at port %d", port); return (code); } code = CheckTCVersion(*tconn); if (code) { rx_DestroyConnection(*tconn); if (code == BC_VERSIONFAIL) afs_com_err(whoami, code, "; Backup and butc are not the same version"); else afs_com_err(whoami, code, "; Can't access tape coordinator at port %d", port); return (code); } return (0); }