/* * Called by Bareos when there are certain events that the * plugin might want to know. The value depends on the * event. */ static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value) { char *name; switch (event->eventType) { case bEventJobStart: printf("plugin: JobStart=%s\n", NPRT((char *)value)); break; case bEventJobEnd: printf("plugin: JobEnd\n"); break; case bEventStartBackupJob: printf("plugin: BackupStart\n"); break; case bEventEndBackupJob: printf("plugin: BackupEnd\n"); break; case bEventLevel: printf("plugin: JobLevel=%c %d\n", (int64_t)value, (int64_t)value); break; case bEventSince: printf("plugin: since=%d\n", (int64_t)value); break; case bEventStartRestoreJob: printf("plugin: StartRestoreJob\n"); break; case bEventEndRestoreJob: printf("plugin: EndRestoreJob\n"); break; case bEventRestoreCommand: /* * Plugin command e.g. plugin = <plugin-name>:<name-space>:command */ printf("plugin: backup command=%s\n", NPRT((char *)value)); break; case bEventBackupCommand: /* * Plugin command e.g. plugin = <plugin-name>:<name-space>:command */ printf("plugin: backup command=%s\n", NPRT((char *)value)); break; case bEventComponentInfo: printf("plugin: Component=%s\n", NPRT((char *)value)); break; default: printf("plugin: unknown event=%d\n", event->eventType); } bfuncs->getBareosValue(ctx, bVarFDName, (void *)&name); return bRC_OK; }
/* * Dump contents of resource */ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock) { URES *res = (URES *)reshdr; bool recurse = true; if (res == NULL) { printf(_("No record for %d %s\n"), type, res_to_str(type)); return; } if (type < 0) { /* no recursion */ type = - type; recurse = false; } switch (type) { case R_DIRECTOR: printf(_("Director: name=%s address=%s DIRport=%d\n"), reshdr->name, res->dir_res.address, res->dir_res.DIRport); break; case R_CONSOLE: printf(_("Console: name=%s\n"), reshdr->name); break; case R_CONSOLE_FONT: printf(_("ConsoleFont: name=%s font face=%s\n"), reshdr->name, NPRT(res->con_font.fontface)); break; default: printf(_("Unknown resource type %d\n"), type); } if (recurse && res->dir_res.hdr.next) { dump_resource(type, res->dir_res.hdr.next, sendit, sock); } }
static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive) { STORE *store = ua->jcr->wstore; BSOCK *sd; char dev_name[MAX_NAME_LENGTH]; char *VolName = NULL; int rtn_slot; if (!(sd=open_sd_bsock(ua))) { ua->error_msg(_("Could not open SD socket.\n")); return NULL; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* Ask for autochanger list of volumes */ sd->fsend(NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive); Dmsg1(100, "Sent: %s", sd->msg); /* Get Volume name in this Slot */ while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); Dmsg1(100, "Got: %s", sd->msg); if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) { VolName = (char *)malloc(sd->msglen); if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) { break; } free(VolName); VolName = NULL; } } close_sd_bsock(ua); Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName)); return VolName; }
/* set this->target to client_name */ void RUNSCRIPT::set_target(const char *client_name) { Dmsg1(500, "runscript: setting target = %s\n", NPRT(client_name)); if (!client_name) { return; } if (!target) { target = get_pool_memory(PM_FNAME); } pm_strcpy(target, client_name); }
/* set this->command to cmd */ void RUNSCRIPT::set_command(const char *cmd, int acmd_type) { Dmsg1(500, "runscript: setting command = %s\n", NPRT(cmd)); if (!cmd) { return; } if (!command) { command = get_pool_memory(PM_FNAME); } pm_strcpy(command, cmd); cmd_type = acmd_type; }
/* * Dump contents of resource */ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fmt, ...), void *sock) { URES *res = (URES *)reshdr; bool recurse = true; char ed1[100], ed2[100]; if (res == NULL) { sendit(sock, _("No %s resource defined\n"), res_to_str(type)); return; } if (type < 0) { /* no recursion */ type = - type; recurse = false; } switch (type) { case R_MONITOR: sendit(sock, _("Monitor: name=%s FDtimeout=%s SDtimeout=%s\n"), reshdr->name, edit_uint64(res->res_monitor.FDConnectTimeout, ed1), edit_uint64(res->res_monitor.SDConnectTimeout, ed2)); break; case R_DIRECTOR: sendit(sock, _("Director: name=%s address=%s FDport=%d\n"), res->res_dir.hdr.name, res->res_dir.address, res->res_dir.DIRport); break; case R_CLIENT: sendit(sock, _("Client: name=%s address=%s FDport=%d\n"), res->res_client.hdr.name, res->res_client.address, res->res_client.FDport); break; case R_STORAGE: sendit(sock, _("Storage: name=%s address=%s SDport=%d\n"), res->res_store.hdr.name, res->res_store.address, res->res_store.SDport); break; case R_CONSOLE_FONT: sendit(sock, _("ConsoleFont: name=%s font face=%s\n"), reshdr->name, NPRT(res->con_font.fontface)); break; default: sendit(sock, _("Unknown resource type %d in dump_resource.\n"), type); break; } if (recurse && res->res_monitor.hdr.next) { dump_resource(type, res->res_monitor.hdr.next, sendit, sock); } }
/* * We get the volume name from the SD */ char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive) { BSOCK *sd; STORERES *store = ua->jcr->res.wstore; char dev_name[MAX_NAME_LENGTH]; char *VolName = NULL; int rtn_slot; if (!(sd = open_sd_bsock(ua))) { ua->error_msg(_("Could not open SD socket.\n")); return NULL; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* * Ask storage daemon to read the label of the volume in a * specific slot of the autochanger using the drive number given. * This could change the loaded volume in the drive. */ sd->fsend(readlabelcmd, dev_name, Slot, drive); Dmsg1(100, "Sent: %s", sd->msg); /* * Get Volume name in this Slot */ while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); Dmsg1(100, "Got: %s", sd->msg); if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) { VolName = (char *)malloc(sd->msglen); if (sscanf(sd->msg, readlabelresponse, VolName, &rtn_slot) == 2) { break; } free(VolName); VolName = NULL; } } close_sd_bsock(ua); Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName)); return VolName; }
/* * Edit codes into ChangerCommand * %% = % * %a = Archive device name * %c = Changer device name * %D = Diagnostic device name * %d = Changer drive index * %f = Client's name * %j = Job name * %o = Command * %s = Slot base 0 * %S = Slot base 1 * %v = Volume name * * * omsg = edited output message * imsg = input string containing edit codes (%x) * cmd = command string (load, unload, ...) */ char *edit_device_codes(DCR *dcr, POOLMEM *&omsg, const char *imsg, const char *cmd) { const char *p; const char *str; char ed1[50]; *omsg = 0; Dmsg1(1800, "edit_device_codes: %s\n", imsg); for (p=imsg; *p; p++) { if (*p == '%') { switch (*++p) { case '%': str = "%"; break; case 'a': str = dcr->dev->archive_name(); break; case 'c': str = NPRT(dcr->device->changer_name); break; case 'D': str = NPRT(dcr->device->diag_device_name); break; case 'd': str = edit_int64(dcr->dev->drive_index, ed1); break; case 'o': str = NPRT(cmd); break; case 's': str = edit_int64(dcr->VolCatInfo.Slot - 1, ed1); break; case 'S': str = edit_int64(dcr->VolCatInfo.Slot, ed1); break; case 'j': /* Job name */ str = dcr->jcr->Job; break; case 'v': if (dcr->VolCatInfo.VolCatName[0]) { str = dcr->VolCatInfo.VolCatName; } else if (dcr->VolumeName[0]) { str = dcr->VolumeName; } else if (dcr->dev->vol && dcr->dev->vol->vol_name) { str = dcr->dev->vol->vol_name; } else { str = dcr->dev->VolHdr.VolumeName; } break; case 'f': str = NPRT(dcr->jcr->client_name); break; default: ed1[0] = '%'; ed1[1] = *p; ed1[2] = 0; str = ed1; break; } } else { ed1[0] = *p; ed1[1] = 0; str = ed1; } Dmsg1(1900, "add_str %s\n", str); pm_strcat(omsg, (char *)str); Dmsg1(1800, "omsg=%s\n", omsg); } Dmsg1(800, "omsg=%s\n", omsg); return omsg; }
/* Store Messages Destination information */ void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass) { int token; char *cmd; POOLMEM *dest; int dest_len; Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code); if (pass == 1) { switch (item->code) { case MD_STDOUT: case MD_STDERR: case MD_SYSLOG: /* syslog */ case MD_CONSOLE: case MD_CATALOG: scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL); break; case MD_OPERATOR: /* send to operator */ case MD_DIRECTOR: /* send to Director */ case MD_MAIL: /* mail */ case MD_MAIL_ON_ERROR: /* mail if Job errors */ case MD_MAIL_ON_SUCCESS: /* mail if Job succeeds */ if (item->code == MD_OPERATOR) { cmd = res_all.res_msgs.operator_cmd; } else { cmd = res_all.res_msgs.mail_cmd; } dest = get_pool_memory(PM_MESSAGE); dest[0] = 0; dest_len = 0; /* Pick up comma separated list of destinations */ for ( ;; ) { token = lex_get_token(lc, T_NAME); /* scan destination */ dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2); if (dest[0] != 0) { pm_strcat(dest, " "); /* separate multiple destinations with space */ dest_len++; } pm_strcat(dest, lc->str); dest_len += lc->str_len; Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest)); token = lex_get_token(lc, T_SKIP_EOL); if (token == T_COMMA) { continue; /* get another destination */ } if (token != T_EQUALS) { scan_err1(lc, _("expected an =, got: %s"), lc->str); return; } break; } Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd)); scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd); free_pool_memory(dest); Dmsg0(900, "done with dest codes\n"); break; case MD_FILE: /* file */ case MD_APPEND: /* append */ dest = get_pool_memory(PM_MESSAGE); /* Pick up a single destination */ token = lex_get_token(lc, T_NAME); /* scan destination */ pm_strcpy(dest, lc->str); dest_len = lc->str_len; token = lex_get_token(lc, T_SKIP_EOL); Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest)); if (token != T_EQUALS) { scan_err1(lc, _("expected an =, got: %s"), lc->str); return; } scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL); free_pool_memory(dest); Dmsg0(900, "done with dest codes\n"); break; default: scan_err1(lc, _("Unknown item code: %d\n"), item->code); return; } } scan_to_eol(lc); set_bit(index, res_all.hdr.item_present); Dmsg0(900, "Done store_msgs\n"); }
/* * We get the slot list from the Storage daemon. * If listall is set we run an 'autochanger listall' cmd * otherwise an 'autochanger list' cmd * If scan is set and listall is not, we return all slots found, * otherwise, we return only slots with valid barcodes (Volume names) * * Input (output of mxt-changer list): * * 0:vol2 Slot num:Volume Name * * Input (output of mxt-changer listall): * * Drive content: D:Drive num:F:Slot loaded:Volume Name * D:0:F:2:vol2 or D:Drive num:E * D:1:F:42:vol42 * D:3:E * * Slot content: * S:1:F:vol1 S:Slot num:F:Volume Name * S:2:E or S:Slot num:E * S:3:F:vol4 * * Import/Export tray slots: * I:10:F:vol10 I:Slot num:F:Volume Name * I:11:E or I:Slot num:E * I:12:F:vol40 * * If a drive is loaded, the slot *should* be empty */ dlist *get_vol_list_from_SD(UAContext *ua, STORERES *store, bool listall, bool scan) { int nr_fields; char *bp; char dev_name[MAX_NAME_LENGTH]; char *field1, *field2, *field3, *field4, *field5; vol_list_t *vl = NULL; dlist *vol_list; BSOCK *sd = NULL; if (!(sd = open_sd_bsock(ua))) { return NULL; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* * Ask for autochanger list of volumes */ if (listall) { sd->fsend(changerlistallcmd , dev_name); } else { sd->fsend(changerlistcmd, dev_name); } vol_list = New(dlist(vl, &vl->link)); /* * Read and organize list of Volumes */ while (bnet_recv(sd) >= 0) { strip_trailing_junk(sd->msg); /* * Check for returned SD messages */ if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) && B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) && sd->msg[4] == ' ') { ua->send_msg("%s\n", sd->msg); /* pass them on to user */ continue; } /* * Parse the message. list gives max 2 fields listall max 5. * We always make sure all fields are initialized to either * a value or NULL. * * For autochanger list the following mapping is used: * - field1 == slotnr * - field2 == volumename * * For autochanger listall the following mapping is used: * - field1 == type * - field2 == slotnr * - field3 == content (E for Empty, F for Full) * - field4 == loaded (loaded slot if type == D) * - field4 == volumename (if type == S or I) * - field5 == volumename (if type == D) */ field1 = sd->msg; field2 = strchr(sd->msg, ':'); if (field2) { *field2++ = '\0'; if (listall) { field3 = strchr(field2, ':'); if (field3) { *field3++ = '\0'; field4 = strchr(field3, ':'); if (field4) { *field4++ = '\0'; field5 = strchr(field4, ':'); if (field5) { *field5++ = '\0'; nr_fields = 5; } else { nr_fields = 4; } } else { nr_fields = 3; field5 = NULL; } } else { nr_fields = 2; field4 = NULL; field5 = NULL; } } else { nr_fields = 2; field3 = NULL; field4 = NULL; field5 = NULL; } } else { nr_fields = 1; field3 = NULL; field4 = NULL; field5 = NULL; } /* * See if this is a parsable string from either list or listall * e.g. at least f1:f2 */ if (!field1 && !field2) { goto parse_error; } vl = (vol_list_t *)malloc(sizeof(vol_list_t)); memset(vl, 0, sizeof(vol_list_t)); if (scan && !listall) { /* * Scanning -- require only valid slot */ vl->Slot = atoi(field1); if (vl->Slot <= 0) { ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg); free(vl); continue; } vl->Type = slot_type_normal; if (strlen(field2) > 0) { vl->Content = slot_content_full; vl->VolName = bstrdup(field2); } else { vl->Content = slot_content_empty; } vl->Index = INDEX_SLOT_OFFSET + vl->Slot; } else if (!listall) { /* * Not scanning and not listall. */ if (strlen(field2) == 0) { free(vl); continue; } if (!is_an_integer(field1) || (vl->Slot = atoi(field1)) <= 0) { ua->error_msg(_("Invalid Slot number: %s\n"), field1); free(vl); continue; } if (!is_volume_name_legal(ua, field2)) { ua->error_msg(_("Invalid Volume name: %s\n"), field2); free(vl); continue; } vl->Type = slot_type_normal; vl->Content = slot_content_full; vl->VolName = bstrdup(field2); vl->Index = INDEX_SLOT_OFFSET + vl->Slot; } else { /* * Listall. */ if (!field3) { goto parse_error; } switch (*field1) { case 'D': vl->Type = slot_type_drive; break; case 'S': vl->Type = slot_type_normal; break; case 'I': vl->Type = slot_type_import; break; default: vl->Type = slot_type_unknown; break; } /* * For drives the Slot is the actual drive number. * For any other type its the actual slot number. */ switch (vl->Type) { case slot_type_drive: if (!is_an_integer(field2) || (vl->Slot = atoi(field2)) < 0) { ua->error_msg(_("Invalid Drive number: %s\n"), field2); free(vl); continue; } vl->Index = INDEX_DRIVE_OFFSET + vl->Slot; if (vl->Index >= INDEX_MAX_DRIVES) { ua->error_msg(_("Drive number %d greater then INDEX_MAX_DRIVES(%d) please increase define\n"), vl->Slot, INDEX_MAX_DRIVES); free(vl); continue; } break; default: if (!is_an_integer(field2) || (vl->Slot = atoi(field2)) <= 0) { ua->error_msg(_("Invalid Slot number: %s\n"), field2); free(vl); continue; } vl->Index = INDEX_SLOT_OFFSET + vl->Slot; break; } switch (*field3) { case 'E': vl->Content = slot_content_empty; break; case 'F': vl->Content = slot_content_full; switch (vl->Type) { case slot_type_normal: case slot_type_import: if (field4) { vl->VolName = bstrdup(field4); } break; case slot_type_drive: if (field4) { vl->Loaded = atoi(field4); } if (field5) { vl->VolName = bstrdup(field5); } break; default: break; } break; default: vl->Content = slot_content_unknown; break; } } if (vl->VolName) { Dmsg6(100, "Add index = %d slot=%d loaded=%d type=%d content=%d Vol=%s to SD list.\n", vl->Index, vl->Slot, vl->Loaded, vl->Type, vl->Content, NPRT(vl->VolName)); } else { Dmsg5(100, "Add index = %d slot=%d loaded=%d type=%d content=%d Vol=NULL to SD list.\n", vl->Index, vl->Slot, vl->Loaded, vl->Type, vl->Content); } vol_list->binary_insert(vl, compare_vol_list_entry); continue; parse_error: /* * We encountered a parse error, see how many replacements * we done of ':' with '\0' by looking at the nr_fields * variable and undo those. Number of undo's are nr_fields - 1 */ while (nr_fields > 1 && (bp = strchr(sd->msg, '\0')) != NULL) { *bp = ':'; nr_fields--; } ua->error_msg(_("Illegal output from autochanger %s: %s\n"), (listall) ? _("listall") : _("list"), sd->msg); free(vl); continue; } close_sd_bsock(ua); if (vol_list->size() == 0) { delete vol_list; vol_list = NULL; } return vol_list; }
/* * Do a verification of the specified files against the Catlaog * * Returns: false on failure * true on success */ bool do_verify(JCR *jcr) { const char *level; BSOCK *fd, *sd; int stat; char ed1[100]; JOB_DBR jr; JobId_t verify_jobid = 0; char *store_address; uint32_t store_port; const char *Name; free_wstorage(jcr); /* we don't write */ memset(&jcr->previous_jr, 0, sizeof(jcr->previous_jr)); /* * Find JobId of last job that ran. Note, we do this when * the job actually starts running, not at schedule time, * so that we find the last job that terminated before * this job runs rather than before it is scheduled. This * permits scheduling a Backup and Verify at the same time, * but with the Verify at a lower priority. * * For VERIFY_CATALOG we want the JobId of the last INIT. * For VERIFY_VOLUME_TO_CATALOG, we want the JobId of the * last backup Job. */ if (jcr->getJobLevel() == L_VERIFY_CATALOG || jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG || jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG || jcr->getJobLevel() == L_VERIFY_DATA) { memcpy(&jr, &jcr->jr, sizeof(jr)); if (jcr->verify_job && (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG || jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG || jcr->getJobLevel() == L_VERIFY_DATA)) { Name = jcr->verify_job->name(); } else { Name = NULL; } Dmsg1(100, "find last jobid for: %s\n", NPRT(Name)); /* see if user supplied a jobid= as run argument or from menu */ if (jcr->RestoreJobId) { verify_jobid = jcr->RestoreJobId; Dmsg1(100, "Supplied jobid=%d\n", verify_jobid); } else { if (!db_find_last_jobid(jcr, jcr->db, Name, &jr)) { if (jcr->getJobLevel() == L_VERIFY_CATALOG) { Jmsg(jcr, M_FATAL, 0, _( "Unable to find JobId of previous InitCatalog Job.\n" "Please run a Verify with Level=InitCatalog before\n" "running the current Job.\n")); } else { Jmsg(jcr, M_FATAL, 0, _( "Unable to find JobId of previous Job for this client.\n")); } return false; } verify_jobid = jr.JobId; } Dmsg1(100, "Last full jobid=%d\n", verify_jobid); } /* * Now get the job record for the previous backup that interests * us. We use the verify_jobid that we found above. */ if (jcr->getJobLevel() == L_VERIFY_CATALOG || jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG || jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG || jcr->getJobLevel() == L_VERIFY_DATA) { jcr->previous_jr.JobId = verify_jobid; if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) { Jmsg(jcr, M_FATAL, 0, _("Could not get job record for previous Job. ERR=%s"), db_strerror(jcr->db)); return false; } if (!(jcr->previous_jr.JobStatus == JS_Terminated || jcr->previous_jr.JobStatus == JS_Warnings)) { Jmsg(jcr, M_FATAL, 0, _("Last Job %d did not terminate normally. JobStatus=%c\n"), verify_jobid, jcr->previous_jr.JobStatus); return false; } Jmsg(jcr, M_INFO, 0, _("Verifying against JobId=%d Job=%s\n"), jcr->previous_jr.JobId, jcr->previous_jr.Job); } /* * If we are verifying a Volume, we need the Storage * daemon, so open a connection, otherwise, just * create a dummy authorization key (passed to * File daemon but not used). */ if (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG || jcr->getJobLevel() == L_VERIFY_DATA) { int stat; /* * Note: negative status is an error, zero status, means * no files were backed up, so skip calling SD and * client. */ stat = create_restore_bootstrap_file(jcr); if (stat < 0) { /* error */ return false; } else if (stat == 0) { /* No files, nothing to do */ verify_cleanup(jcr, JS_Terminated); /* clean up */ return true; /* get out */ } } else { jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */ } /* Pass the original fileset to the client */ if (jcr->getJobLevel() == L_VERIFY_DATA) { FILESET_DBR fdbr; memset(&fdbr, 0, sizeof(fdbr)); fdbr.FileSetId = jcr->previous_jr.FileSetId; if (!db_get_fileset_record(jcr, jcr->db, &fdbr)) { Jmsg(jcr, M_FATAL, 0, _("Could not get fileset record from previous Job. ERR=%s"), db_strerror(jcr->db)); return false; } jcr->fileset = (FILESET *)GetResWithName(R_FILESET, fdbr.FileSet); if (!jcr->fileset) { if (jcr->verify_job) { jcr->fileset = jcr->verify_job->fileset; Jmsg(jcr, M_WARNING, 0, _("Could not find FileSet resource \"%s\" from previous Job\n"), fdbr.FileSet); Jmsg(jcr, M_INFO, 0, _("Using FileSet \"%\"\n"), jcr->fileset->name()); } else { Jmsg(jcr, M_FATAL, 0, _("Could not get FileSet resource for verify Job.")); return false; } } Dmsg1(50, "FileSet = %s\n", jcr->fileset->name()); } /* Pass the current fileset to the client */ if (jcr->getJobLevel() == L_VERIFY_DISK_TO_CATALOG && jcr->verify_job) { jcr->fileset = jcr->verify_job->fileset; } Dmsg2(100, "ClientId=%u JobLevel=%c\n", jcr->previous_jr.ClientId, jcr->getJobLevel()); if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); return false; } /* Print Job Start message */ Jmsg(jcr, M_INFO, 0, _("Start Verify JobId=%s Level=%s Job=%s\n"), edit_uint64(jcr->JobId, ed1), level_to_str(jcr->getJobLevel()), jcr->Job); if (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG || jcr->getJobLevel() == L_VERIFY_DATA) { /* * Start conversation with Storage daemon */ jcr->setJobStatus(JS_Blocked); if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) { return false; } /* * Now start a job with the Storage daemon */ if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) { return false; } sd = jcr->store_bsock; jcr->sd_calls_client = jcr->client->sd_calls_client; /* * Send the bootstrap file -- what Volumes/files to restore */ if (!send_bootstrap_file(jcr, sd) || !response(jcr, sd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) { goto bail_out; } if (!jcr->sd_calls_client) { if (!run_storage_and_start_message_thread(jcr, sd)) { return false; } } } /* * OK, now connect to the File daemon * and ask him for the files. */ jcr->setJobStatus(JS_Blocked); if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) { goto bail_out; } jcr->setJobStatus(JS_Running); fd = jcr->file_bsock; Dmsg0(30, ">filed: Send include list\n"); if (!send_include_list(jcr)) { goto bail_out; } Dmsg0(30, ">filed: Send exclude list\n"); if (!send_exclude_list(jcr)) { goto bail_out; } /* * Send Level command to File daemon, as well * as the Storage address if appropriate. */ switch (jcr->getJobLevel()) { case L_VERIFY_INIT: level = "init"; break; case L_VERIFY_CATALOG: level = "catalog"; break; case L_VERIFY_DATA: case L_VERIFY_VOLUME_TO_CATALOG: if (jcr->sd_calls_client) { if (jcr->FDVersion < 10) { Jmsg(jcr, M_FATAL, 0, _("The File daemon does not support SDCallsClient.\n")); goto bail_out; } if (!send_client_addr_to_sd(jcr)) { goto bail_out; } if (!run_storage_and_start_message_thread(jcr, jcr->store_bsock)) { return false; } store_address = jcr->rstore->address; /* dummy */ store_port = 0; /* flag that SD calls FD */ } else { /* * send Storage daemon address to the File daemon */ if (jcr->rstore->SDDport == 0) { jcr->rstore->SDDport = jcr->rstore->SDport; } store_address = get_storage_address(jcr->client, jcr->rstore); store_port = jcr->rstore->SDDport; } if (!send_store_addr_to_fd(jcr, jcr->rstore, store_address, store_port)) { goto bail_out; } if (!jcr->RestoreBootstrap) { Jmsg0(jcr, M_FATAL, 0, _("Deprecated feature ... use bootstrap.\n")); goto bail_out; } if (jcr->getJobLevel() == L_VERIFY_VOLUME_TO_CATALOG) { level = "volume"; } else { level = "data"; } break; case L_VERIFY_DISK_TO_CATALOG: level="disk_to_catalog"; break; default: Jmsg2(jcr, M_FATAL, 0, _("Unimplemented Verify level %d(%c)\n"), jcr->getJobLevel(), jcr->getJobLevel()); goto bail_out; } if (!send_runscripts_commands(jcr)) { goto bail_out; } /* * Send verify command/level to File daemon */ fd->fsend(verifycmd, level); if (!response(jcr, fd, OKverify, "Verify", DISPLAY_ERROR)) { goto bail_out; } /* * Now get data back from File daemon and * compare it to the catalog or store it in the * catalog depending on the run type. */ /* Compare to catalog */ switch (jcr->getJobLevel()) { case L_VERIFY_CATALOG: Dmsg0(10, "Verify level=catalog\n"); jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ jcr->SDJobStatus = JS_Terminated; get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId); break; case L_VERIFY_VOLUME_TO_CATALOG: Dmsg0(10, "Verify level=volume\n"); get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId); break; case L_VERIFY_DISK_TO_CATALOG: Dmsg0(10, "Verify level=disk_to_catalog\n"); jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ jcr->SDJobStatus = JS_Terminated; get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId); break; case L_VERIFY_INIT: /* Build catalog */ Dmsg0(10, "Verify level=init\n"); jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ jcr->SDJobStatus = JS_Terminated; get_attributes_and_put_in_catalog(jcr); db_end_transaction(jcr, jcr->db); /* terminate any open transaction */ db_write_batch_file_records(jcr); break; case L_VERIFY_DATA: /* Nothing special to do */ bget_dirmsg(fd); /* eat EOD */ break; default: Jmsg1(jcr, M_FATAL, 0, _("Unimplemented verify level %d\n"), jcr->getJobLevel()); goto bail_out; } stat = wait_for_job_termination(jcr); verify_cleanup(jcr, stat); return true; bail_out: return false; }
/* * Load a specific plugin and check if the plugin had the correct * entry points, the license is compatible and the initialize the plugin. */ static bool load_a_plugin(void *binfo, void *bfuncs, const char *plugin_pathname, const char *plugin_name, const char *type, alist *plugin_list, bool is_plugin_compatible(Plugin *plugin)) { t_loadPlugin loadPlugin; Plugin *plugin = NULL; plugin = new_plugin(); plugin->file = bstrdup(plugin_name); plugin->file_len = strstr(plugin->file, type) - plugin->file; plugin->pHandle = dlopen(plugin_pathname, LT_LAZY_OR_NOW | LT_GLOBAL); if (!plugin->pHandle) { const char *error = dlerror(); Jmsg(NULL, M_ERROR, 0, _("dlopen plugin %s failed: ERR=%s\n"), plugin_pathname, NPRT(error)); Dmsg2(dbglvl, "dlopen plugin %s failed: ERR=%s\n", plugin_pathname, NPRT(error)); close_plugin(plugin); return false; } /* * Get two global entry points */ loadPlugin = (t_loadPlugin)dlsym(plugin->pHandle, "loadPlugin"); if (!loadPlugin) { Jmsg(NULL, M_ERROR, 0, _("Lookup of loadPlugin in plugin %s failed: ERR=%s\n"), plugin_pathname, NPRT(dlerror())); Dmsg2(dbglvl, "Lookup of loadPlugin in plugin %s failed: ERR=%s\n", plugin_pathname, NPRT(dlerror())); close_plugin(plugin); return false; } plugin->unloadPlugin = (t_unloadPlugin)dlsym(plugin->pHandle, "unloadPlugin"); if (!plugin->unloadPlugin) { Jmsg(NULL, M_ERROR, 0, _("Lookup of unloadPlugin in plugin %s failed: ERR=%s\n"), plugin_pathname, NPRT(dlerror())); Dmsg2(dbglvl, "Lookup of unloadPlugin in plugin %s failed: ERR=%s\n", plugin_pathname, NPRT(dlerror())); close_plugin(plugin); return false; } /* * Initialize the plugin */ if (loadPlugin(binfo, bfuncs, &plugin->pinfo, &plugin->pfuncs) != bRC_OK) { close_plugin(plugin); return false; } if (!is_plugin_compatible) { Dmsg0(50, "Plugin compatibility pointer not set.\n"); } else if (!is_plugin_compatible(plugin)) { close_plugin(plugin); return false; } plugin_list->append(plugin); return true; }
B_DB *db_init_database(JCR *jcr, const char *db_driver, const char *db_name, const char *db_user, const char *db_password, const char *db_address, int db_port, const char *db_socket, bool mult_db_connections, bool disable_batch_insert, bool need_private) { void *dl_handle; char shared_library_name[1024]; backend_interface_mapping_t *backend_interface_mapping; backend_shared_library_t *backend_shared_library; t_backend_instantiate backend_instantiate; t_flush_backend flush_backend; /* * A db_driver is mandatory for dynamic loading of backends to work. */ if (!db_driver) { Jmsg(jcr, M_ABORT, 0, _("Driver type not specified in Catalog resource.\n")); } /* * If we didn't find a mapping its fatal because we don't know what database backend to use. */ backend_interface_mapping = lookup_backend_interface_mapping(db_driver); if (backend_interface_mapping == NULL) { Jmsg(jcr, M_ABORT, 0, _("Unknown database type: %s\n"), db_driver); return (B_DB *)NULL; } /* * See if the backend is already loaded. */ if (loaded_backends) { foreach_alist(backend_shared_library, loaded_backends) { if (backend_shared_library->interface_type_id == backend_interface_mapping->interface_type_id) { return backend_shared_library->backend_instantiate(jcr, db_driver, db_name, db_user, db_password, db_address, db_port, db_socket, mult_db_connections, disable_batch_insert, need_private); } } } /* * This is a new backend try to use dynamic loading to load the backend library. */ #if defined(HAVE_WIN32) bsnprintf(shared_library_name, sizeof(shared_library_name), "libbareoscats-%s%s", backend_interface_mapping->interface_name, DYN_LIB_EXTENSION); #else bsnprintf(shared_library_name, sizeof(shared_library_name), "%s/libbareoscats-%s%s", LIBDIR, backend_interface_mapping->interface_name, DYN_LIB_EXTENSION); #endif dl_handle = dlopen(shared_library_name, RTLD_NOW); if (!dl_handle) { Jmsg(jcr, M_ABORT, 0, _("Unable to load shared library: %s ERR=%s\n"), shared_library_name, NPRT(dlerror())); return (B_DB *)NULL; } /* * Lookup the backend_instantiate function. */ backend_instantiate = (t_backend_instantiate)dlsym(dl_handle, "backend_instantiate"); if (backend_instantiate == NULL) { Jmsg(jcr, M_ABORT, 0, _("Lookup of backend_instantiate in shared library %s failed: ERR=%s\n"), shared_library_name, NPRT(dlerror())); dlclose(dl_handle); return (B_DB *)NULL; } /* * Lookup the flush_backend function. */ flush_backend = (t_flush_backend)dlsym(dl_handle, "flush_backend"); if (flush_backend == NULL) { Jmsg(jcr, M_ABORT, 0, _("Lookup of flush_backend in shared library %s failed: ERR=%s\n"), shared_library_name, NPRT(dlerror())); dlclose(dl_handle); return (B_DB *)NULL; } /* * Create a new loaded shared library entry and tack it onto the list of loaded backend shared libs. */ backend_shared_library = (backend_shared_library_t *)malloc(sizeof(backend_shared_library_t)); backend_shared_library->interface_type_id = backend_interface_mapping->interface_type_id; backend_shared_library->handle = dl_handle; backend_shared_library->backend_instantiate = backend_instantiate; backend_shared_library->flush_backend = flush_backend; if (loaded_backends == NULL) { loaded_backends = New(alist(10, not_owned_by_alist)); } loaded_backends->append(backend_shared_library); return backend_shared_library->backend_instantiate(jcr, db_driver, db_name, db_user, db_password, db_address, db_port, db_socket, mult_db_connections, disable_batch_insert, need_private); }
/* * Read the volume label * * If dcr->VolumeName == NULL, we accept any Bareos Volume * If dcr->VolumeName[0] == 0, we accept any Bareos Volume * otherwise dcr->VolumeName must match the Volume. * * If VolName given, ensure that it matches * * Returns VOL_ code as defined in record.h * VOL_NOT_READ * VOL_OK good label found * VOL_NO_LABEL volume not labeled * VOL_IO_ERROR I/O error reading tape * VOL_NAME_ERROR label has wrong name * VOL_CREATE_ERROR Error creating label * VOL_VERSION_ERROR label has wrong version * VOL_LABEL_ERROR bad label type * VOL_NO_MEDIA no media in drive * * The dcr block is emptied on return, and the Volume is * rewound. */ int read_dev_volume_label(DCR *dcr) { JCR *jcr = dcr->jcr; DEVICE * volatile dev = dcr->dev; char *VolName = dcr->VolumeName; DEV_RECORD *record; bool ok = false; DEV_BLOCK *block = dcr->block; int status; bool want_ansi_label; bool have_ansi_label = false; Dmsg4(100, "Enter read_volume_label res=%d device=%s vol=%s dev_Vol=%s\n", dev->num_reserved(), dev->print_name(), VolName, dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*"); if (!dev->is_open()) { if (!dev->open(dcr, OPEN_READ_ONLY)) { return VOL_IO_ERROR; } } dev->clear_labeled(); dev->clear_append(); dev->clear_read(); dev->label_type = B_BAREOS_LABEL; if (!dev->rewind(dcr)) { Mmsg(jcr->errmsg, _("Couldn't rewind device %s: ERR=%s\n"), dev->print_name(), dev->print_errmsg()); Dmsg1(130, "return VOL_NO_MEDIA: %s", jcr->errmsg); return VOL_NO_MEDIA; } bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id)); /* * The stored plugin handling the bsdEventLabelRead event can abort * the reading of the label by returning a non bRC_OK. */ if (generate_plugin_event(jcr, bsdEventLabelRead, dcr) != bRC_OK) { Dmsg0(200, "Error from bsdEventLabelRead plugin event.\n"); return VOL_NO_MEDIA; } /* * Read ANSI/IBM label if so requested */ want_ansi_label = dcr->VolCatInfo.LabelType != B_BAREOS_LABEL || dcr->device->label_type != B_BAREOS_LABEL; if (want_ansi_label || dev->has_cap(CAP_CHECKLABELS)) { status = read_ansi_ibm_label(dcr); /* * If we want a label and didn't find it, return error */ if (want_ansi_label && status != VOL_OK) { goto bail_out; } if (status == VOL_NAME_ERROR || status == VOL_LABEL_ERROR) { Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"), dev->print_name(), VolName, dev->VolHdr.VolumeName); if (!dev->poll && jcr->label_errors++ > 100) { Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg); } goto bail_out; } if (status != VOL_OK) { /* Not an ANSI/IBM label, so re-read */ dev->rewind(dcr); } else { have_ansi_label = true; } } /* * Read the Bareos Volume label block */ record = new_record(); empty_block(block); Dmsg0(130, "Big if statement in read_volume_label\n"); if (!dcr->read_block_from_dev(NO_BLOCK_NUMBER_CHECK)) { Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bareos " "labeled Volume, because: ERR=%s"), NPRT(VolName), dev->print_name(), dev->print_errmsg()); Dmsg1(130, "%s", jcr->errmsg); } else if (!read_record_from_block(dcr, record)) { Mmsg(jcr->errmsg, _("Could not read Volume label from block.\n")); Dmsg1(130, "%s", jcr->errmsg); } else if (!unser_volume_label(dev, record)) { Mmsg(jcr->errmsg, _("Could not unserialize Volume label: ERR=%s\n"), dev->print_errmsg()); Dmsg1(130, "%s", jcr->errmsg); } else if (!bstrcmp(dev->VolHdr.Id, BareosId) && !bstrcmp(dev->VolHdr.Id, OldBaculaId) && !bstrcmp(dev->VolHdr.Id, OlderBaculaId)) { Mmsg(jcr->errmsg, _("Volume Header Id bad: %s\n"), dev->VolHdr.Id); Dmsg1(130, "%s", jcr->errmsg); } else { ok = true; } free_record(record); /* finished reading Volume record */ if (!dev->is_volume_to_unload()) { dev->clear_unload(); } if (!ok) { if (forge_on || jcr->ignore_label_errors) { dev->set_labeled(); /* set has Bareos label */ Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg); goto ok_out; } Dmsg0(100, "No volume label - bailing out\n"); status = VOL_NO_LABEL; goto bail_out; } /* * At this point, we have read the first Bareos block, and * then read the Bareos Volume label. Now we need to * make sure we have the right Volume. */ if (dev->VolHdr.VerNum != BareosTapeVersion && dev->VolHdr.VerNum != OldCompatibleBareosTapeVersion1 && dev->VolHdr.VerNum != OldCompatibleBareosTapeVersion2 && dev->VolHdr.VerNum != OldCompatibleBareosTapeVersion3) { Mmsg(jcr->errmsg, _("Volume on %s has wrong Bareos version. Wanted %d got %d\n"), dev->print_name(), BareosTapeVersion, dev->VolHdr.VerNum); Dmsg1(130, "VOL_VERSION_ERROR: %s", jcr->errmsg); status = VOL_VERSION_ERROR; goto bail_out; } /* * We are looking for either an unused Bareos tape (PRE_LABEL) or * a Bareos volume label (VOL_LABEL) */ if (dev->VolHdr.LabelType != PRE_LABEL && dev->VolHdr.LabelType != VOL_LABEL) { Mmsg(jcr->errmsg, _("Volume on %s has bad Bareos label type: %x\n"), dev->print_name(), dev->VolHdr.LabelType); Dmsg1(130, "%s", jcr->errmsg); if (!dev->poll && jcr->label_errors++ > 100) { Jmsg(jcr, M_FATAL, 0, _("Too many tries: %s"), jcr->errmsg); } Dmsg0(150, "return VOL_LABEL_ERROR\n"); status = VOL_LABEL_ERROR; goto bail_out; } dev->set_labeled(); /* set has Bareos label */ /* Compare Volume Names */ Dmsg2(130, "Compare Vol names: VolName=%s hdr=%s\n", VolName?VolName:"*", dev->VolHdr.VolumeName); if (VolName && *VolName && *VolName != '*' && !bstrcmp(dev->VolHdr.VolumeName, VolName)) { Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"), dev->print_name(), VolName, dev->VolHdr.VolumeName); Dmsg1(130, "%s", jcr->errmsg); /* * Cancel Job if too many label errors * => we are in a loop */ if (!dev->poll && jcr->label_errors++ > 100) { Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg); } Dmsg0(150, "return VOL_NAME_ERROR\n"); status = VOL_NAME_ERROR; goto bail_out; } if (debug_level >= 200) { dump_volume_label(dev); } Dmsg0(130, "Leave read_volume_label() VOL_OK\n"); /* * If we are a streaming device, we only get one chance to read */ if (!dev->has_cap(CAP_STREAM)) { dev->rewind(dcr); if (have_ansi_label) { status = read_ansi_ibm_label(dcr); /* * If we want a label and didn't find it, return error */ if (status != VOL_OK) { goto bail_out; } } } Dmsg1(100, "Call reserve_volume=%s\n", dev->VolHdr.VolumeName); if (reserve_volume(dcr, dev->VolHdr.VolumeName) == NULL) { Mmsg2(jcr->errmsg, _("Could not reserve volume %s on %s\n"), dev->VolHdr.VolumeName, dev->print_name()); Dmsg2(150, "Could not reserve volume %s on %s\n", dev->VolHdr.VolumeName, dev->print_name()); status = VOL_NAME_ERROR; goto bail_out; } ok_out: /* * The stored plugin handling the bsdEventLabelVerified event can override * the return value e.g. although we think the volume label is ok the plugin * has reasons to override that. So when the plugin returns something else * then bRC_OK it want to tell us the volume is not OK to use and as * such we return VOL_NAME_ERROR as error although it might not be te * best error it should be sufficient. */ if (generate_plugin_event(jcr, bsdEventLabelVerified, dcr) != bRC_OK) { Dmsg0(200, "Error from bsdEventLabelVerified plugin event.\n"); status = VOL_NAME_ERROR; goto bail_out; } empty_block(block); return VOL_OK; bail_out: empty_block(block); dev->rewind(dcr); Dmsg1(150, "return %d\n", status); return status; }
static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist) { POOLMEM *VolumeName; int jobid, n; int i, j; JOB_DBR jr; POOL_DBR pr; MEDIA_DBR mr; if (!open_client_db(ua)) return 1; memset(&jr, 0, sizeof(jr)); memset(&pr, 0, sizeof(pr)); Dmsg1(20, "list: %s\n", cmd); if (!ua->db) { ua->error_msg(_("Hey! DB is NULL\n")); } /* Apply any limit */ j = find_arg_with_value(ua, NT_("limit")); if (j >= 0) { jr.limit = atoi(ua->argv[j]); } /* Scan arguments looking for things to do */ for (i=1; i<ua->argc; i++) { /* List JOBS */ if (bstrcasecmp(ua->argk[i], NT_("jobs"))) { db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist); /* List JOBTOTALS */ } else if (bstrcasecmp(ua->argk[i], NT_("jobtotals"))) { db_list_job_totals(ua->jcr, ua->db, &jr, prtit, ua); /* List JOBID=nn */ } else if (bstrcasecmp(ua->argk[i], NT_("jobid"))) { if (ua->argv[i]) { jobid = str_to_int64(ua->argv[i]); if (jobid > 0) { jr.JobId = jobid; db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist); } } /* List JOB=xxx */ } else if ((bstrcasecmp(ua->argk[i], NT_("job")) || bstrcasecmp(ua->argk[i], NT_("jobname"))) && ua->argv[i]) { bstrncpy(jr.Name, ua->argv[i], MAX_NAME_LENGTH); jr.JobId = 0; db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist); /* List UJOBID=xxx */ } else if (bstrcasecmp(ua->argk[i], NT_("ujobid")) && ua->argv[i]) { bstrncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH); jr.JobId = 0; db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist); /* List Base files */ } else if (bstrcasecmp(ua->argk[i], NT_("basefiles"))) { /* TODO: cleanup this block */ for (j=i+1; j<ua->argc; j++) { if (bstrcasecmp(ua->argk[j], NT_("ujobid")) && ua->argv[j]) { bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH); jr.JobId = 0; db_get_job_record(ua->jcr, ua->db, &jr); jobid = jr.JobId; } else if (bstrcasecmp(ua->argk[j], NT_("jobid")) && ua->argv[j]) { jobid = str_to_int64(ua->argv[j]); } else { continue; } if (jobid > 0) { db_list_base_files_for_job(ua->jcr, ua->db, jobid, prtit, ua); } } /* List FILES */ } else if (bstrcasecmp(ua->argk[i], NT_("files"))) { for (j=i+1; j<ua->argc; j++) { if (bstrcasecmp(ua->argk[j], NT_("ujobid")) && ua->argv[j]) { bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH); jr.JobId = 0; db_get_job_record(ua->jcr, ua->db, &jr); jobid = jr.JobId; } else if (bstrcasecmp(ua->argk[j], NT_("jobid")) && ua->argv[j]) { jobid = str_to_int64(ua->argv[j]); } else { continue; } if (jobid > 0) { db_list_files_for_job(ua->jcr, ua->db, jobid, prtit, ua); } } /* List JOBMEDIA */ } else if (bstrcasecmp(ua->argk[i], NT_("jobmedia"))) { bool done = false; for (j=i+1; j<ua->argc; j++) { if (bstrcasecmp(ua->argk[j], NT_("ujobid")) && ua->argv[j]) { bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH); jr.JobId = 0; db_get_job_record(ua->jcr, ua->db, &jr); jobid = jr.JobId; } else if (bstrcasecmp(ua->argk[j], NT_("jobid")) && ua->argv[j]) { jobid = str_to_int64(ua->argv[j]); } else { continue; } db_list_jobmedia_records(ua->jcr, ua->db, jobid, prtit, ua, llist); done = true; } if (!done) { /* List for all jobs (jobid=0) */ db_list_jobmedia_records(ua->jcr, ua->db, 0, prtit, ua, llist); } /* List JOBLOG */ } else if (bstrcasecmp(ua->argk[i], NT_("joblog"))) { bool done = false; for (j=i+1; j<ua->argc; j++) { if (bstrcasecmp(ua->argk[j], NT_("ujobid")) && ua->argv[j]) { bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH); jr.JobId = 0; db_get_job_record(ua->jcr, ua->db, &jr); jobid = jr.JobId; } else if (bstrcasecmp(ua->argk[j], NT_("jobid")) && ua->argv[j]) { jobid = str_to_int64(ua->argv[j]); } else { continue; } db_list_joblog_records(ua->jcr, ua->db, jobid, prtit, ua, llist); done = true; } if (!done) { /* List for all jobs (jobid=0) */ db_list_joblog_records(ua->jcr, ua->db, 0, prtit, ua, llist); } /* List POOLS */ } else if (bstrcasecmp(ua->argk[i], NT_("pool")) || bstrcasecmp(ua->argk[i], NT_("pools"))) { POOL_DBR pr; memset(&pr, 0, sizeof(pr)); if (ua->argv[i]) { bstrncpy(pr.Name, ua->argv[i], sizeof(pr.Name)); } db_list_pool_records(ua->jcr, ua->db, &pr, prtit, ua, llist); } else if (bstrcasecmp(ua->argk[i], NT_("clients"))) { db_list_client_records(ua->jcr, ua->db, prtit, ua, llist); /* List MEDIA or VOLUMES */ } else if (bstrcasecmp(ua->argk[i], NT_("media")) || bstrcasecmp(ua->argk[i], NT_("volume")) || bstrcasecmp(ua->argk[i], NT_("volumes"))) { bool done = false; for (j=i+1; j<ua->argc; j++) { if (bstrcasecmp(ua->argk[j], NT_("ujobid")) && ua->argv[j]) { bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH); jr.JobId = 0; db_get_job_record(ua->jcr, ua->db, &jr); jobid = jr.JobId; } else if (bstrcasecmp(ua->argk[j], NT_("jobid")) && ua->argv[j]) { jobid = str_to_int64(ua->argv[j]); } else { continue; } VolumeName = get_pool_memory(PM_FNAME); n = db_get_job_volume_names(ua->jcr, ua->db, jobid, &VolumeName); ua->send_msg(_("Jobid %d used %d Volume(s): %s\n"), jobid, n, VolumeName); free_pool_memory(VolumeName); done = true; } /* if no job or jobid keyword found, then we list all media */ if (!done) { int num_pools; uint32_t *ids; /* List a specific volume? */ if (ua->argv[i]) { bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName)); db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist); return 1; } /* Is a specific pool wanted? */ for (i=1; i<ua->argc; i++) { if (bstrcasecmp(ua->argk[i], NT_("pool"))) { if (!get_pool_dbr(ua, &pr)) { ua->error_msg(_("No Pool specified.\n")); return 1; } mr.PoolId = pr.PoolId; db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist); return 1; } } /* List Volumes in all pools */ if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) { ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"), db_strerror(ua->db)); return 1; } if (num_pools <= 0) { return 1; } for (i=0; i < num_pools; i++) { pr.PoolId = ids[i]; if (db_get_pool_record(ua->jcr, ua->db, &pr)) { ua->send_msg(_("Pool: %s\n"), pr.Name); } mr.PoolId = ids[i]; db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist); } free(ids); return 1; } /* List next volume */ } else if (bstrcasecmp(ua->argk[i], NT_("nextvol")) || bstrcasecmp(ua->argk[i], NT_("nextvolume"))) { n = 1; j = find_arg_with_value(ua, NT_("days")); if (j >= 0) { n = atoi(ua->argv[j]); if ((n < 0) || (n > 50)) { ua->warning_msg(_("Ignoring invalid value for days. Max is 50.\n")); n = 1; } } list_nextvol(ua, n); } else if (bstrcasecmp(ua->argk[i], NT_("copies"))) { char *jobids = NULL; uint32_t limit=0; for (j=i+1; j<ua->argc; j++) { if (bstrcasecmp(ua->argk[j], NT_("jobid")) && ua->argv[j]) { if (is_a_number_list(ua->argv[j])) { jobids = ua->argv[j]; } } else if (bstrcasecmp(ua->argk[j], NT_("limit")) && ua->argv[j]) { limit = atoi(ua->argv[j]); } } db_list_copies_records(ua->jcr,ua->db,limit,jobids,prtit,ua,llist); } else if (bstrcasecmp(ua->argk[i], NT_("limit")) || bstrcasecmp(ua->argk[i], NT_("days"))) { /* Ignore it */ } else { ua->error_msg(_("Unknown list keyword: %s\n"), NPRT(ua->argk[i])); } } return 1; }
/* * We get the slot list from the Storage daemon. * If scan is set, we return all slots found, * otherwise, we return only slots with valid barcodes (Volume names) */ static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan) { STORE *store = ua->jcr->wstore; char dev_name[MAX_NAME_LENGTH]; BSOCK *sd; vol_list_t *vl; vol_list_t *vol_list = NULL; if (!(sd=open_sd_bsock(ua))) { return NULL; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* Ask for autochanger list of volumes */ bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name); /* Read and organize list of Volumes */ while (bnet_recv(sd) >= 0) { char *p; int Slot; strip_trailing_junk(sd->msg); /* Check for returned SD messages */ if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) && B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) && sd->msg[4] == ' ') { ua->send_msg("%s\n", sd->msg); /* pass them on to user */ continue; } /* Validate Slot: if scanning, otherwise Slot:Barcode */ p = strchr(sd->msg, ':'); if (scan && p) { /* Scanning -- require only valid slot */ Slot = atoi(sd->msg); if (Slot <= 0) { p--; *p = ':'; ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg); continue; } } else { /* Not scanning */ if (p && strlen(p) > 1) { *p++ = 0; if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) { p--; *p = ':'; ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg); continue; } } else { continue; } if (!is_volume_name_legal(ua, p)) { p--; *p = ':'; ua->error_msg(_("Invalid Volume name: %s\n"), sd->msg); continue; } } /* Add Slot and VolumeName to list */ vl = (vol_list_t *)malloc(sizeof(vol_list_t)); vl->Slot = Slot; if (p) { if (*p == ':') { p++; /* skip separator */ } vl->VolName = bstrdup(p); } else { vl->VolName = NULL; } Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName)); if (!vol_list) { vl->next = vol_list; vol_list = vl; } else { /* Add new entry to end of list */ for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) { if (!tvl->next) { tvl->next = vl; vl->next = NULL; break; } } } } close_sd_bsock(ua); return vol_list; }
int run_scripts(JCR *jcr, alist *runscripts, const char *label, alist *allowed_script_dirs) { RUNSCRIPT *script; bool runit; int when; Dmsg2(200, "runscript: running all RUNSCRIPT object (%s) JobStatus=%c\n", label, jcr->JobStatus); if (strstr(label, NT_("Before"))) { when = SCRIPT_Before; } else if (bstrcmp(label, NT_("ClientAfterVSS"))) { when = SCRIPT_AfterVSS; } else { when = SCRIPT_After; } if (runscripts == NULL) { Dmsg0(100, "runscript: WARNING RUNSCRIPTS list is NULL\n"); return 0; } foreach_alist(script, runscripts) { Dmsg2(200, "runscript: try to run %s:%s\n", NPRT(script->target), NPRT(script->command)); runit = false; if ((script->when & SCRIPT_Before) && (when & SCRIPT_Before)) { if ((script->on_success && (jcr->JobStatus == JS_Running || jcr->JobStatus == JS_Created)) || (script->on_failure && (job_canceled(jcr) || jcr->JobStatus == JS_Differences))) { Dmsg4(200, "runscript: Run it because SCRIPT_Before (%s,%i,%i,%c)\n", script->command, script->on_success, script->on_failure, jcr->JobStatus ); runit = true; } } if ((script->when & SCRIPT_AfterVSS) && (when & SCRIPT_AfterVSS)) { if ((script->on_success && (jcr->JobStatus == JS_Blocked)) || (script->on_failure && job_canceled(jcr))) { Dmsg4(200, "runscript: Run it because SCRIPT_AfterVSS (%s,%i,%i,%c)\n", script->command, script->on_success, script->on_failure, jcr->JobStatus ); runit = true; } } if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) { if ((script->on_success && (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) || (script->on_failure && (job_canceled(jcr) || jcr->JobStatus == JS_Differences))) { Dmsg4(200, "runscript: Run it because SCRIPT_After (%s,%i,%i,%c)\n", script->command, script->on_success, script->on_failure, jcr->JobStatus ); runit = true; } } if (!script->is_local()) { runit = false; } /* * We execute it */ if (runit) { if (!script_dir_allowed(jcr, script, allowed_script_dirs)) { Dmsg1(200, "runscript: Not running script %s because its not in one of the allowed scripts dirs\n", script->command); Jmsg(jcr, M_ERROR, 0, _("Runscript: run %s \"%s\" could not execute, " "not in one of the allowed scripts dirs\n"), label, script->command); jcr->setJobStatus(JS_ErrorTerminated); goto bail_out; } script->run(jcr, label); } }
DEVICE *init_backend_dev(JCR *jcr, int device_type) { struct stat st; char *backend_dir; void *dl_handle = NULL; POOL_MEM shared_library_name(PM_FNAME); backend_interface_mapping_t *backend_interface_mapping; backend_shared_library_t *backend_shared_library; t_backend_instantiate backend_instantiate; t_flush_backend flush_backend; /* * For dynamic loading storage backends there must be a list of backend dirs set. */ if (!backend_dirs) { Jmsg(jcr, M_ERROR_TERM, 0, _("Catalog Backends Dir not configured.\n")); } backend_interface_mapping = lookup_backend_interface_mapping(device_type); if (backend_interface_mapping == NULL) { return (DEVICE *)NULL; } /* * See if the backend is already loaded. */ if (loaded_backends) { foreach_alist(backend_shared_library, loaded_backends) { if (backend_shared_library->interface_type_id == backend_interface_mapping->interface_type_id) { return backend_shared_library->backend_instantiate(jcr, device_type); } } } /* * This is a new backend try to use dynamic loading to load the backend library. */ foreach_alist(backend_dir, backend_dirs) { Mmsg(shared_library_name, "%s/libbareossd-%s%s", backend_dir, backend_interface_mapping->interface_name, DYN_LIB_EXTENSION); Dmsg3(100, "init_backend_dev: testing backend %s/libbareossd-%s%s\n", backend_dir, backend_interface_mapping->interface_name, DYN_LIB_EXTENSION); /* * Make sure the shared library with this name exists. */ if (stat(shared_library_name.c_str(), &st) == 0) { dl_handle = dlopen(shared_library_name.c_str(), RTLD_NOW); if (!dl_handle) { Jmsg(jcr, M_ERROR, 0, _("Unable to load shared library: %s ERR=%s\n"), shared_library_name.c_str(), NPRT(dlerror())); continue; } /* * Lookup the backend_instantiate function. */ backend_instantiate = (t_backend_instantiate)dlsym(dl_handle, "backend_instantiate"); if (backend_instantiate == NULL) { Jmsg(jcr, M_ERROR, 0, _("Lookup of backend_instantiate in shared library %s failed: ERR=%s\n"), shared_library_name.c_str(), NPRT(dlerror())); dlclose(dl_handle); dl_handle = NULL; continue; } /* * Lookup the flush_backend function. */ flush_backend = (t_flush_backend)dlsym(dl_handle, "flush_backend"); if (flush_backend == NULL) { Jmsg(jcr, M_ERROR, 0, _("Lookup of flush_backend in shared library %s failed: ERR=%s\n"), shared_library_name.c_str(), NPRT(dlerror())); dlclose(dl_handle); dl_handle = NULL; continue; } /* * We found the shared library and it has the right entry points. */ break; } }
/* * Do a verification of the specified files against the Catlaog * * Returns: false on failure * true on success */ bool do_verify(JCR *jcr) { int JobLevel; const char *level; BSOCK *fd = NULL; BSOCK *sd = NULL; int status; char ed1[100]; JOB_DBR jr; JobId_t verify_jobid = 0; const char *Name; free_wstorage(jcr); /* we don't write */ memset(&jcr->previous_jr, 0, sizeof(jcr->previous_jr)); /* * Find JobId of last job that ran. Note, we do this when * the job actually starts running, not at schedule time, * so that we find the last job that terminated before * this job runs rather than before it is scheduled. This * permits scheduling a Backup and Verify at the same time, * but with the Verify at a lower priority. * * For VERIFY_CATALOG we want the JobId of the last INIT. * For VERIFY_VOLUME_TO_CATALOG, we want the JobId of the * last backup Job. */ JobLevel = jcr->getJobLevel(); switch (JobLevel) { case L_VERIFY_CATALOG: case L_VERIFY_VOLUME_TO_CATALOG: case L_VERIFY_DISK_TO_CATALOG: memcpy(&jr, &jcr->jr, sizeof(jr)); if (jcr->res.verify_job && (JobLevel == L_VERIFY_VOLUME_TO_CATALOG || JobLevel == L_VERIFY_DISK_TO_CATALOG)) { Name = jcr->res.verify_job->name(); } else { Name = NULL; } Dmsg1(100, "find last jobid for: %s\n", NPRT(Name)); /* * See if user supplied a jobid= as run argument or from menu */ if (jcr->VerifyJobId) { verify_jobid = jcr->VerifyJobId; Dmsg1(100, "Supplied jobid=%d\n", verify_jobid); } else { if (!db_find_last_jobid(jcr, jcr->db, Name, &jr)) { if (JobLevel == L_VERIFY_CATALOG) { Jmsg(jcr, M_FATAL, 0, _( "Unable to find JobId of previous InitCatalog Job.\n" "Please run a Verify with Level=InitCatalog before\n" "running the current Job.\n")); } else { Jmsg(jcr, M_FATAL, 0, _( "Unable to find JobId of previous Job for this client.\n")); } return false; } verify_jobid = jr.JobId; } Dmsg1(100, "Last full jobid=%d\n", verify_jobid); /* * Now get the job record for the previous backup that interests * us. We use the verify_jobid that we found above. */ jcr->previous_jr.JobId = verify_jobid; if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) { Jmsg(jcr, M_FATAL, 0, _("Could not get job record for previous Job. ERR=%s"), db_strerror(jcr->db)); return false; } if (!(jcr->previous_jr.JobStatus == JS_Terminated || jcr->previous_jr.JobStatus == JS_Warnings)) { Jmsg(jcr, M_FATAL, 0, _("Last Job %d did not terminate normally. JobStatus=%c\n"), verify_jobid, jcr->previous_jr.JobStatus); return false; } Jmsg(jcr, M_INFO, 0, _("Verifying against JobId=%d Job=%s\n"), jcr->previous_jr.JobId, jcr->previous_jr.Job); } /* * If we are verifying a Volume, we need the Storage * daemon, so open a connection, otherwise, just * create a dummy authorization key (passed to * File daemon but not used). */ switch (JobLevel) { case L_VERIFY_VOLUME_TO_CATALOG: /* * Note: negative status is an error, zero status, means * no files were backed up, so skip calling SD and * client. */ status = create_restore_bootstrap_file(jcr); if (status < 0) { /* error */ return false; } else if (status == 0) { /* No files, nothing to do */ verify_cleanup(jcr, JS_Terminated); /* clean up */ return true; /* get out */ } if (jcr->res.verify_job) { jcr->res.fileset = jcr->res.verify_job->fileset; } break; default: jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */ break; } Dmsg2(100, "ClientId=%u JobLevel=%c\n", jcr->previous_jr.ClientId, JobLevel); if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); return false; } /* * Print Job Start message */ Jmsg(jcr, M_INFO, 0, _("Start Verify JobId=%s Level=%s Job=%s\n"), edit_uint64(jcr->JobId, ed1), level_to_str(JobLevel), jcr->Job); switch (JobLevel) { case L_VERIFY_VOLUME_TO_CATALOG: /* * Start conversation with Storage daemon */ jcr->setJobStatus(JS_Blocked); if (!connect_to_storage_daemon(jcr, 10, me->SDConnectTimeout, true)) { return false; } sd = jcr->store_bsock; /* * Now start a job with the Storage daemon */ if (!start_storage_daemon_job(jcr, jcr->res.rstorage, NULL, /* send_bsr */ true)) { return false; } jcr->passive_client = jcr->res.client->passive; if (!jcr->passive_client) { /* * Start the Job in the SD. */ if (!sd->fsend("run")) { return false; } /* * Now start a Storage daemon message thread */ if (!start_storage_daemon_message_thread(jcr)) { return false; } Dmsg0(50, "Storage daemon connection OK\n"); } /* * OK, now connect to the File daemon and ask him for the files. */ jcr->setJobStatus(JS_Blocked); if (!connect_to_file_daemon(jcr, 10, me->FDConnectTimeout, true)) { goto bail_out; } send_job_info(jcr); fd = jcr->file_bsock; /* * Check if the file daemon supports passive client mode. */ if (jcr->passive_client && jcr->FDVersion < FD_VERSION_51) { Jmsg(jcr, M_FATAL, 0, _("Client \"%s\" doesn't support passive client mode. " "Please upgrade your client or disable compat mode.\n"), jcr->res.client->name()); goto bail_out; } break; default: /* * OK, now connect to the File daemon and ask him for the files. */ jcr->setJobStatus(JS_Blocked); if (!connect_to_file_daemon(jcr, 10, me->FDConnectTimeout, true)) { goto bail_out; } send_job_info(jcr); fd = jcr->file_bsock; break; } jcr->setJobStatus(JS_Running); Dmsg0(30, ">filed: Send include list\n"); if (!send_include_list(jcr)) { goto bail_out; } Dmsg0(30, ">filed: Send exclude list\n"); if (!send_exclude_list(jcr)) { goto bail_out; } /* * Send Level command to File daemon, as well as the Storage address if appropriate. */ switch (JobLevel) { case L_VERIFY_INIT: level = "init"; break; case L_VERIFY_CATALOG: level = "catalog"; break; case L_VERIFY_VOLUME_TO_CATALOG: if (!jcr->RestoreBootstrap) { Jmsg0(jcr, M_FATAL, 0, _("Deprecated feature ... use bootstrap.\n")); goto bail_out; } if (!jcr->passive_client) { int tls_need = BNET_TLS_NONE; STORERES *store = jcr->res.rstore; /* * Send Storage daemon address to the File daemon */ if (store->SDDport == 0) { store->SDDport = store->SDport; } /* * TLS Requirement */ if (store->tls.enable) { if (store->tls.require) { tls_need = BNET_TLS_REQUIRED; } else { tls_need = BNET_TLS_OK; } } fd->fsend(storaddrcmd, store->address, store->SDDport, tls_need, jcr->sd_auth_key); if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) { goto bail_out; } } else { int tls_need = BNET_TLS_NONE; CLIENTRES *client = jcr->res.client; /* * TLS Requirement */ if (client->tls.enable) { if (client->tls.require) { tls_need = BNET_TLS_REQUIRED; } else { tls_need = BNET_TLS_OK; } } /* * Tell the SD to connect to the FD. */ sd->fsend(passiveclientcmd, client->address, client->FDport, tls_need); if (!response(jcr, sd, OKpassiveclient, "Passive client", DISPLAY_ERROR)) { goto bail_out; } /* * Start the Job in the SD. */ if (!sd->fsend("run")) { goto bail_out; } /* * Now start a Storage daemon message thread */ if (!start_storage_daemon_message_thread(jcr)) { goto bail_out; } Dmsg0(50, "Storage daemon connection OK\n"); } level = "volume"; break; case L_VERIFY_DATA: level = "data"; break; case L_VERIFY_DISK_TO_CATALOG: level="disk_to_catalog"; break; default: Jmsg2(jcr, M_FATAL, 0, _("Unimplemented Verify level %d(%c)\n"), JobLevel, JobLevel); goto bail_out; } if (!send_runscripts_commands(jcr)) { goto bail_out; } /* * Send verify command/level to File daemon */ fd->fsend(verifycmd, level); if (!response(jcr, fd, OKverify, "Verify", DISPLAY_ERROR)) { goto bail_out; } /* * Now get data back from File daemon and * compare it to the catalog or store it in the * catalog depending on the run type. */ switch (JobLevel) { case L_VERIFY_CATALOG: /* * Verify from catalog */ Dmsg0(10, "Verify level=catalog\n"); jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ jcr->SDJobStatus = JS_Terminated; get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId); break; case L_VERIFY_VOLUME_TO_CATALOG: /* * Verify Volume to catalog entries */ Dmsg0(10, "Verify level=volume\n"); get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId); break; case L_VERIFY_DISK_TO_CATALOG: /* * Verify Disk attributes to catalog */ Dmsg0(10, "Verify level=disk_to_catalog\n"); jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ jcr->SDJobStatus = JS_Terminated; get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId); break; case L_VERIFY_INIT: /* * Build catalog */ Dmsg0(10, "Verify level=init\n"); jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ jcr->SDJobStatus = JS_Terminated; get_attributes_and_put_in_catalog(jcr); db_end_transaction(jcr, jcr->db); /* terminate any open transaction */ db_write_batch_file_records(jcr); break; default: Jmsg1(jcr, M_FATAL, 0, _("Unimplemented verify level %d\n"), JobLevel); goto bail_out; } status = wait_for_job_termination(jcr); verify_cleanup(jcr, status); return true; bail_out: if (jcr->file_bsock) { jcr->file_bsock->signal(BNET_TERMINATE); jcr->file_bsock->close(); delete jcr->file_bsock; jcr->file_bsock = NULL; } return false; }
B_DB *db_init_database(JCR *jcr, const char *db_driver, const char *db_name, const char *db_user, const char *db_password, const char *db_address, int db_port, const char *db_socket, bool mult_db_connections, bool disable_batch_insert, bool need_private) { struct stat st; char *backend_dir; void *dl_handle = NULL; POOL_MEM shared_library_name(PM_FNAME); backend_interface_mapping_t *backend_interface_mapping; backend_shared_library_t *backend_shared_library; t_backend_instantiate backend_instantiate; t_flush_backend flush_backend; /* * For dynamic loading catalog backends there must be a list of backend dirs set. */ if (!backend_dirs) { Jmsg(jcr, M_ABORT, 0, _("Catalog Backends Dir not configured.\n")); } /* * A db_driver is mandatory for dynamic loading of backends to work. */ if (!db_driver) { Jmsg(jcr, M_ABORT, 0, _("Driver type not specified in Catalog resource.\n")); } /* * If we didn't find a mapping its fatal because we don't know what database backend to use. */ backend_interface_mapping = lookup_backend_interface_mapping(db_driver); if (backend_interface_mapping == NULL) { Jmsg(jcr, M_ABORT, 0, _("Unknown database type: %s\n"), db_driver); return (B_DB *)NULL; } /* * See if the backend is already loaded. */ if (loaded_backends) { foreach_alist(backend_shared_library, loaded_backends) { if (backend_shared_library->interface_type_id == backend_interface_mapping->interface_type_id) { return backend_shared_library->backend_instantiate(jcr, db_driver, db_name, db_user, db_password, db_address, db_port, db_socket, mult_db_connections, disable_batch_insert, need_private); } } } /* * This is a new backend try to use dynamic loading to load the backend library. */ foreach_alist(backend_dir, backend_dirs) { Mmsg(shared_library_name, "%s/libbareoscats-%s%s", backend_dir, backend_interface_mapping->interface_name, DYN_LIB_EXTENSION); Dmsg3(100, "db_init_database: testing backend %s/libbareoscats-%s%s\n", backend_dir, backend_interface_mapping->interface_name, DYN_LIB_EXTENSION); /* * Make sure the shared library with this name exists. */ if (stat(shared_library_name.c_str(), &st) == 0) { dl_handle = dlopen(shared_library_name.c_str(), RTLD_NOW); if (!dl_handle) { Jmsg(jcr, M_ERROR, 0, _("Unable to load shared library: %s ERR=%s\n"), shared_library_name.c_str(), NPRT(dlerror())); continue; } /* * Lookup the backend_instantiate function. */ backend_instantiate = (t_backend_instantiate)dlsym(dl_handle, "backend_instantiate"); if (backend_instantiate == NULL) { Jmsg(jcr, M_ERROR, 0, _("Lookup of backend_instantiate in shared library %s failed: ERR=%s\n"), shared_library_name.c_str(), NPRT(dlerror())); dlclose(dl_handle); dl_handle = NULL; continue; } /* * Lookup the flush_backend function. */ flush_backend = (t_flush_backend)dlsym(dl_handle, "flush_backend"); if (flush_backend == NULL) { Jmsg(jcr, M_ERROR, 0, _("Lookup of flush_backend in shared library %s failed: ERR=%s\n"), shared_library_name.c_str(), NPRT(dlerror())); dlclose(dl_handle); dl_handle = NULL; continue; } /* * We found the shared library and it has the right entry points. */ break; } }
/* * Handle an event that was generated in Bareos */ static bRC handlePluginEvent(bpContext *ctx, bEvent *event, void *value) { struct plugin_ctx *p_ctx = (struct plugin_ctx *)ctx->pContext; restore_object_pkt *rop; if (!p_ctx) { return bRC_Error; } // char *name; switch (event->eventType) { case bEventJobStart: Dmsg(ctx, dbglvl, "test-plugin-fd: JobStart=%s\n", (char *)value); break; case bEventEndFileSet: /* * End of Dir FileSet commands, now we can add excludes */ bfuncs->NewOptions(ctx); bfuncs->AddWild(ctx, "*.c", ' '); bfuncs->AddWild(ctx, "*.cpp", ' '); bfuncs->AddOptions(ctx, "ei"); /* exclude, ignore case */ bfuncs->AddExclude(ctx, "/home/user/bareos/regress/README"); break; case bEventRestoreObject: { FILE *fp; POOLMEM *q; char *working; static int _nb = 0; printf("Plugin RestoreObject\n"); if (!value) { Dmsg(ctx, dbglvl, "test-plugin-fd: End restore objects\n"); break; } rop = (restore_object_pkt *)value; Dmsg(ctx, dbglvl, "Get RestoreObject len=%d JobId=%d oname=%s type=%d data=%.127s\n", rop->object_len, rop->JobId, rop->object_name, rop->object_type, rop->object); q = get_pool_memory(PM_FNAME); bfuncs->getBareosValue(ctx, bVarWorkingDir, &working); Mmsg(q, "%s/restore.%d", working, _nb++); if ((fp = fopen(q, "w")) != NULL) { fwrite(rop->object, rop->object_len, 1, fp); fclose(fp); } free_pool_memory(q); if (!strcmp(rop->object_name, INI_RESTORE_OBJECT_NAME)) { ConfigFile ini; if (!ini.dump_string(rop->object, rop->object_len)) { break; } ini.register_items(test_items, sizeof(struct ini_items)); if (ini.parse(ini.out_fname)) { Jmsg(ctx, M_INFO, "string1 = %s\n", ini.items[0].val.strval); } else { Jmsg(ctx, M_ERROR, "Can't parse config\n"); } } break; } case bEventEstimateCommand: /* Fall-through wanted */ case bEventBackupCommand: { /* * Plugin command e.g. plugin = <plugin-name>:<name-space>:read command:write command */ char *p; Dmsg(ctx, dbglvl, "test-plugin-fd: pluginEvent cmd=%s\n", (char *)value); p_ctx->cmd = bstrdup((char *)value); p = strchr(p_ctx->cmd, ':'); if (!p) { Jmsg(ctx, M_FATAL, "Plugin terminator not found: %s\n", (char *)value); Dmsg(ctx, dbglvl, "Plugin terminator not found: %s\n", (char *)value); return bRC_Error; } *p++ = 0; /* terminate plugin */ p_ctx->fname = p; p = strchr(p, ':'); if (!p) { Jmsg(ctx, M_FATAL, "File terminator not found: %s\n", (char *)value); Dmsg(ctx, dbglvl, "File terminator not found: %s\n", (char *)value); return bRC_Error; } *p++ = 0; /* terminate file */ p_ctx->reader = p; p = strchr(p, ':'); if (!p) { Jmsg(ctx, M_FATAL, "Reader terminator not found: %s\n", (char *)value); Dmsg(ctx, dbglvl, "Reader terminator not found: %s\n", (char *)value); return bRC_Error; } *p++ = 0; /* terminate reader string */ p_ctx->writer = p; Dmsg(ctx, dbglvl, "test-plugin-fd: plugin=%s fname=%s reader=%s writer=%s\n", p_ctx->cmd, p_ctx->fname, p_ctx->reader, p_ctx->writer); break; } case bEventComponentInfo: Dmsg(ctx, dbglvl, "plugin: Component=%s\n", NPRT((char *)value)); break; default: Dmsg(ctx, dbglvl, "test-plugin-fd: unknown event=%d\n", event->eventType); break; } return bRC_OK; }
int run_scripts(JCR *jcr, alist *runscripts, const char *label) { Dmsg2(200, "runscript: running all RUNSCRIPT object (%s) JobStatus=%c\n", label, jcr->JobStatus); RUNSCRIPT *script; bool runit; int when; if (strstr(label, NT_("Before"))) { when = SCRIPT_Before; } else if (bstrcmp(label, NT_("ClientAfterVSS"))) { when = SCRIPT_AfterVSS; } else { when = SCRIPT_After; } if (runscripts == NULL) { Dmsg0(100, "runscript: WARNING RUNSCRIPTS list is NULL\n"); return 0; } foreach_alist(script, runscripts) { Dmsg2(200, "runscript: try to run %s:%s\n", NPRT(script->target), NPRT(script->command)); runit = false; if ((script->when & SCRIPT_Before) && (when & SCRIPT_Before)) { if ((script->on_success && (jcr->JobStatus == JS_Running || jcr->JobStatus == JS_Created)) || (script->on_failure && (job_canceled(jcr) || jcr->JobStatus == JS_Differences)) ) { Dmsg4(200, "runscript: Run it because SCRIPT_Before (%s,%i,%i,%c)\n", script->command, script->on_success, script->on_failure, jcr->JobStatus ); runit = true; } } if ((script->when & SCRIPT_AfterVSS) && (when & SCRIPT_AfterVSS)) { if ((script->on_success && (jcr->JobStatus == JS_Blocked)) || (script->on_failure && job_canceled(jcr)) ) { Dmsg4(200, "runscript: Run it because SCRIPT_AfterVSS (%s,%i,%i,%c)\n", script->command, script->on_success, script->on_failure, jcr->JobStatus ); runit = true; } } if ((script->when & SCRIPT_After) && (when & SCRIPT_After)) { if ((script->on_success && (jcr->JobStatus == JS_Terminated || jcr->JobStatus == JS_Warnings)) || (script->on_failure && (job_canceled(jcr) || jcr->JobStatus == JS_Differences)) ) { Dmsg4(200, "runscript: Run it because SCRIPT_After (%s,%i,%i,%c)\n", script->command, script->on_success, script->on_failure, jcr->JobStatus ); runit = true; } } if (!script->is_local()) { runit = false; } /* we execute it */ if (runit) { script->run(jcr, label); } }
/* * Do a verification of the specified files against the Catlaog * * Returns: false on failure * true on success */ bool do_verify(JCR *jcr) { const char *level; BSOCK *fd; int stat; char ed1[100]; JOB_DBR jr; JobId_t verify_jobid = 0; const char *Name; free_wstorage(jcr); /* we don't write */ memset(&jcr->previous_jr, 0, sizeof(jcr->previous_jr)); /* * Find JobId of last job that ran. Note, we do this when * the job actually starts running, not at schedule time, * so that we find the last job that terminated before * this job runs rather than before it is scheduled. This * permits scheduling a Backup and Verify at the same time, * but with the Verify at a lower priority. * * For VERIFY_CATALOG we want the JobId of the last INIT. * For VERIFY_VOLUME_TO_CATALOG, we want the JobId of the * last backup Job. */ if (jcr->get_JobLevel() == L_VERIFY_CATALOG || jcr->get_JobLevel() == L_VERIFY_VOLUME_TO_CATALOG || jcr->get_JobLevel() == L_VERIFY_DISK_TO_CATALOG) { memcpy(&jr, &jcr->jr, sizeof(jr)); if (jcr->verify_job && (jcr->get_JobLevel() == L_VERIFY_VOLUME_TO_CATALOG || jcr->get_JobLevel() == L_VERIFY_DISK_TO_CATALOG)) { Name = jcr->verify_job->name(); } else { Name = NULL; } Dmsg1(100, "find last jobid for: %s\n", NPRT(Name)); if (!db_find_last_jobid(jcr, jcr->db, Name, &jr)) { if (jcr->get_JobLevel() == L_VERIFY_CATALOG) { Jmsg(jcr, M_FATAL, 0, _( "Unable to find JobId of previous InitCatalog Job.\n" "Please run a Verify with Level=InitCatalog before\n" "running the current Job.\n")); } else { Jmsg(jcr, M_FATAL, 0, _( "Unable to find JobId of previous Job for this client.\n")); } return false; } verify_jobid = jr.JobId; Dmsg1(100, "Last full jobid=%d\n", verify_jobid); } /* * Now get the job record for the previous backup that interests * us. We use the verify_jobid that we found above. */ if (jcr->get_JobLevel() == L_VERIFY_CATALOG || jcr->get_JobLevel() == L_VERIFY_VOLUME_TO_CATALOG || jcr->get_JobLevel() == L_VERIFY_DISK_TO_CATALOG) { jcr->previous_jr.JobId = verify_jobid; if (!db_get_job_record(jcr, jcr->db, &jcr->previous_jr)) { Jmsg(jcr, M_FATAL, 0, _("Could not get job record for previous Job. ERR=%s"), db_strerror(jcr->db)); return false; } if (!(jcr->previous_jr.JobStatus == JS_Terminated || jcr->previous_jr.JobStatus == JS_Warnings)) { Jmsg(jcr, M_FATAL, 0, _("Last Job %d did not terminate normally. JobStatus=%c\n"), verify_jobid, jcr->previous_jr.JobStatus); return false; } Jmsg(jcr, M_INFO, 0, _("Verifying against JobId=%d Job=%s\n"), jcr->previous_jr.JobId, jcr->previous_jr.Job); } /* * If we are verifying a Volume, we need the Storage * daemon, so open a connection, otherwise, just * create a dummy authorization key (passed to * File daemon but not used). */ if (jcr->get_JobLevel() == L_VERIFY_VOLUME_TO_CATALOG) { if (!create_restore_bootstrap_file(jcr)) { return false; } } else { jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */ } if (jcr->get_JobLevel() == L_VERIFY_DISK_TO_CATALOG && jcr->verify_job) { jcr->fileset = jcr->verify_job->fileset; } Dmsg2(100, "ClientId=%u JobLevel=%c\n", jcr->previous_jr.ClientId, jcr->get_JobLevel()); if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); return false; } /* Print Job Start message */ Jmsg(jcr, M_INFO, 0, _("Start Verify JobId=%s Level=%s Job=%s\n"), edit_uint64(jcr->JobId, ed1), level_to_str(jcr->get_JobLevel()), jcr->Job); if (jcr->get_JobLevel() == L_VERIFY_VOLUME_TO_CATALOG) { /* * Start conversation with Storage daemon */ set_jcr_job_status(jcr, JS_Blocked); if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) { return false; } /* * Now start a job with the Storage daemon */ if (!start_storage_daemon_job(jcr, jcr->rstorage, NULL)) { return false; } if (!jcr->store_bsock->fsend("run")) { return false; } /* * Now start a Storage daemon message thread */ if (!start_storage_daemon_message_thread(jcr)) { return false; } Dmsg0(50, "Storage daemon connection OK\n"); } /* * OK, now connect to the File daemon * and ask him for the files. */ set_jcr_job_status(jcr, JS_Blocked); if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) { goto bail_out; } set_jcr_job_status(jcr, JS_Running); fd = jcr->file_bsock; Dmsg0(30, ">filed: Send include list\n"); if (!send_include_list(jcr)) { goto bail_out; } Dmsg0(30, ">filed: Send exclude list\n"); if (!send_exclude_list(jcr)) { goto bail_out; } /* * Send Level command to File daemon, as well * as the Storage address if appropriate. */ switch (jcr->get_JobLevel()) { case L_VERIFY_INIT: level = "init"; break; case L_VERIFY_CATALOG: level = "catalog"; break; case L_VERIFY_VOLUME_TO_CATALOG: /* * send Storage daemon address to the File daemon */ if (jcr->rstore->SDDport == 0) { jcr->rstore->SDDport = jcr->rstore->SDport; } bnet_fsend(fd, storaddr, jcr->rstore->address, jcr->rstore->SDDport); if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) { goto bail_out; } /* * Send the bootstrap file -- what Volumes/files to restore */ if (!send_bootstrap_file(jcr, fd) || !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) { goto bail_out; } if (!jcr->RestoreBootstrap) { Jmsg0(jcr, M_FATAL, 0, _("Deprecated feature ... use bootstrap.\n")); goto bail_out; } level = "volume"; break; case L_VERIFY_DATA: level = "data"; break; case L_VERIFY_DISK_TO_CATALOG: level="disk_to_catalog"; break; default: Jmsg2(jcr, M_FATAL, 0, _("Unimplemented Verify level %d(%c)\n"), jcr->get_JobLevel(), jcr->get_JobLevel()); goto bail_out; } if (!send_runscripts_commands(jcr)) { goto bail_out; } /* * Send verify command/level to File daemon */ fd->fsend(verifycmd, level); if (!response(jcr, fd, OKverify, "Verify", DISPLAY_ERROR)) { goto bail_out; } /* * Now get data back from File daemon and * compare it to the catalog or store it in the * catalog depending on the run type. */ /* Compare to catalog */ switch (jcr->get_JobLevel()) { case L_VERIFY_CATALOG: Dmsg0(10, "Verify level=catalog\n"); jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ jcr->SDJobStatus = JS_Terminated; get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId); break; case L_VERIFY_VOLUME_TO_CATALOG: Dmsg0(10, "Verify level=volume\n"); get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId); break; case L_VERIFY_DISK_TO_CATALOG: Dmsg0(10, "Verify level=disk_to_catalog\n"); jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ jcr->SDJobStatus = JS_Terminated; get_attributes_and_compare_to_catalog(jcr, jcr->previous_jr.JobId); break; case L_VERIFY_INIT: /* Build catalog */ Dmsg0(10, "Verify level=init\n"); jcr->sd_msg_thread_done = true; /* no SD msg thread, so it is done */ jcr->SDJobStatus = JS_Terminated; get_attributes_and_put_in_catalog(jcr); db_end_transaction(jcr, jcr->db); /* terminate any open transaction */ db_write_batch_file_records(jcr); break; default: Jmsg1(jcr, M_FATAL, 0, _("Unimplemented verify level %d\n"), jcr->get_JobLevel()); goto bail_out; } stat = wait_for_job_termination(jcr); verify_cleanup(jcr, stat); return true; bail_out: return false; }