static void do_storage_cmd(UAContext *ua, STORERES *store, const char *cmd) { BSOCK *sd; JCR *jcr = ua->jcr; USTORERES lstore; lstore.store = store; pm_strcpy(lstore.store_source, _("unknown source")); set_wstorage(jcr, &lstore); if (!(sd = open_sd_bsock(ua))) { ua->error_msg(_("Could not open SD socket.\n")); return; } Dmsg0(120, _("Connected to storage daemon\n")); sd = jcr->store_bsock; sd->fsend("%s", cmd); if (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); } close_sd_bsock(ua); return; }
/* * resolve a host on a storage daemon */ bool do_storage_resolve(UAContext *ua, STORERES *store) { BSOCK *sd; USTORERES lstore; lstore.store = store; pm_strcpy(lstore.store_source, _("unknown source")); set_wstorage(ua->jcr, &lstore); if (!(sd = open_sd_bsock(ua))) { return false; } for (int i = 1; i < ua->argc; i++) { if (!*ua->argk[i]) { continue; } sd->fsend("resolve %s", ua->argk[i]); while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); } } sd->signal(BNET_TERMINATE); sd->close(); ua->jcr->store_bsock = NULL; return true; }
/* * Set storage override. * Releases any previous storage definition. */ void set_rwstorage(JCR *jcr, USTORERES *store) { if (!store) { Jmsg(jcr, M_FATAL, 0, _("No storage specified.\n")); return; } if (jcr->JobReads()) { set_rstorage(jcr, store); } set_wstorage(jcr, store); }
void cancel_storage_daemon_job(JCR *jcr) { if (jcr->sd_canceled) { return; /* cancel only once */ } UAContext *ua = new_ua_context(jcr); JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM); BSOCK *sd; ua->jcr = control_jcr; if (jcr->store_bsock) { if (!ua->jcr->wstorage) { if (jcr->rstorage) { copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource")); } else { copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource")); } } else { USTORE store; if (jcr->rstorage) { store.store = jcr->rstore; } else { store.store = jcr->wstore; } set_wstorage(ua->jcr, &store); } if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) { goto bail_out; } Dmsg0(200, "Connected to storage daemon\n"); sd = ua->jcr->store_bsock; sd->fsend("cancel Job=%s\n", jcr->Job); while (sd->recv() >= 0) { } sd->signal(BNET_TERMINATE); sd->close(); ua->jcr->store_bsock = NULL; jcr->sd_canceled = true; jcr->store_bsock->set_timed_out(); jcr->store_bsock->set_terminated(); sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL); jcr->my_thread_send_signal(TIMEOUT_SIGNAL); } bail_out: free_jcr(control_jcr); free_ua_context(ua); }
/* * Cancel a running job on a storage daemon. The silent flag sets * if we need to be silent or not e.g. when doing an interactive cancel * or a system invoked one. */ bool cancel_storage_daemon_job(UAContext *ua, JCR *jcr, bool silent) { BSOCK *sd; USTORERES store; if (!ua->jcr->wstorage) { if (jcr->rstorage) { copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource")); } else { copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource")); } } else { if (jcr->rstorage) { store.store = jcr->res.rstore; } else { store.store = jcr->res.wstore; } set_wstorage(ua->jcr, &store); } if (!connect_to_storage_daemon(ua->jcr, 10, me->SDConnectTimeout, true)) { if (!silent) { ua->error_msg(_("Failed to connect to Storage daemon.\n")); } return false; } Dmsg0(200, "Connected to storage daemon\n"); sd = ua->jcr->store_bsock; sd->fsend(canceljobcmd, jcr->Job); while (sd->recv() >= 0) { if (!silent) { ua->send_msg("%s", sd->msg); } } sd->signal(BNET_TERMINATE); sd->close(); delete ua->jcr->store_bsock; ua->jcr->store_bsock = NULL; if (silent) { jcr->sd_canceled = true; } jcr->store_bsock->set_timed_out(); jcr->store_bsock->set_terminated(); sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL); jcr->my_thread_send_signal(TIMEOUT_SIGNAL); return true; }
/* * Get the status of a remote storage daemon. */ void do_native_storage_status(UAContext *ua, STORERES *store, char *cmd) { BSOCK *sd; USTORERES lstore; lstore.store = store; pm_strcpy(lstore.store_source, _("unknown source")); set_wstorage(ua->jcr, &lstore); /* * Try connecting for up to 15 seconds */ if (!ua->api) { ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"), store->name(), store->address, store->SDport); } if (!connect_to_storage_daemon(ua->jcr, 10, me->SDConnectTimeout, false)) { ua->send_msg(_("\nFailed to connect to Storage daemon %s.\n====\n"), store->name()); if (ua->jcr->store_bsock) { ua->jcr->store_bsock->close(); delete ua->jcr->store_bsock; ua->jcr->store_bsock = NULL; } return; } Dmsg0(20, _("Connected to storage daemon\n")); sd = ua->jcr->store_bsock; if (cmd) { sd->fsend(dotstatuscmd, cmd); } else { sd->fsend(statuscmd); } while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); } sd->signal( BNET_TERMINATE); sd->close(); delete ua->jcr->store_bsock; ua->jcr->store_bsock = NULL; return; }
/* * Common routine for both label and relabel */ static int do_label(UAContext *ua, const char *cmd, bool relabel) { USTORERES store; BSOCK *sd; char dev_name[MAX_NAME_LENGTH]; MEDIA_DBR mr, omr; POOL_DBR pr; bool print_reminder = true; bool label_barcodes = false; bool label_encrypt = false; int ok = FALSE; int i, j; int drive; bool media_record_exists = false; static const char *barcode_keywords[] = { "barcode", "barcodes", NULL }; memset(&pr, 0, sizeof(pr)); if (!open_client_db(ua)) { return 1; } /* * Look for one of the barcode keywords */ if (!relabel && (i = find_arg_keyword(ua, barcode_keywords)) >= 0) { /* * Now find the keyword in the list */ if ((j = find_arg(ua, barcode_keywords[i])) > 0) { *ua->argk[j] = 0; /* zap barcode keyword */ } label_barcodes = true; } /* * Look for the encrypt keyword */ if ((i = find_arg(ua, "encrypt")) > 0) { *ua->argk[i] = 0; /* zap encrypt keyword */ label_encrypt = true; } store.store = get_storage_resource(ua, true, label_barcodes); if (!store.store) { return 1; } switch (store.store->Protocol) { case APT_NDMPV2: case APT_NDMPV3: case APT_NDMPV4: /* * See if the user selected a NDMP storage device but its * handled by a native Bareos storage daemon e.g. we have * a paired_storage pointer. */ if (store.store->paired_storage) { store.store = store.store->paired_storage; } else { ua->warning_msg(_("Storage has non-native protocol.\n")); return 1; } break; default: break; } pm_strcpy(store.store_source, _("command line")); set_wstorage(ua->jcr, &store); drive = get_storage_drive(ua, store.store); if (label_barcodes) { label_from_barcodes(ua, drive, label_encrypt); return 1; } /* * If relabel get name of Volume to relabel */ if (relabel) { /* * Check for oldvolume=name */ i = find_arg_with_value(ua, "oldvolume"); if (i >= 0) { bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName)); if (db_get_media_record(ua->jcr, ua->db, &omr)) { goto checkVol; } ua->error_msg("%s", db_strerror(ua->db)); } /* * No keyword or Vol not found, ask user to select */ if (!select_media_dbr(ua, &omr)) { return 1; } /* * Require Volume to be Purged or Recycled */ checkVol: if (!bstrcmp(omr.VolStatus, "Purged") && !bstrcmp(omr.VolStatus, "Recycle")) { ua->error_msg(_("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"), omr.VolumeName, omr.VolStatus); return 1; } } /* * Check for volume=NewVolume */ i = find_arg_with_value(ua, "volume"); if (i >= 0) { pm_strcpy(ua->cmd, ua->argv[i]); goto checkName; } /* * Get a new Volume name */ for ( ;; ) { media_record_exists = false; if (!get_cmd(ua, _("Enter new Volume name: "))) { return 1; } checkName: if (!is_volume_name_legal(ua, ua->cmd)) { continue; } /* * Search by Media name so set VolumeName and clear MediaId. */ mr.MediaId = 0; bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName)); /* * If VolBytes are zero the Volume is not labeled */ if (db_get_media_record(ua->jcr, ua->db, &mr)) { if (mr.VolBytes != 0) { ua->error_msg(_("Media record for new Volume \"%s\" already exists.\n"), mr.VolumeName); continue; } media_record_exists = true; } break; /* Got it */ } /* * If autochanger, request slot */ i = find_arg_with_value(ua, "slot"); if (i >= 0) { mr.Slot = atoi(ua->argv[i]); if (mr.Slot < 0) { mr.Slot = 0; } mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */ } else if (store.store->autochanger) { if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) { return 1; } mr.Slot = ua->pint32_val; if (mr.Slot < 0) { mr.Slot = 0; } mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */ } set_storageid_in_mr(store.store, &mr); bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType)); /* * Must select Pool if not already done */ if (pr.PoolId == 0) { memset(&pr, 0, sizeof(pr)); if (!select_pool_dbr(ua, &pr)) { return 1; } } /* * See if we need to generate a new passphrase for hardware encryption. */ if (label_encrypt) { ua->info_msg(_("Generating new hardware encryption key\n")); if (!generate_new_encryption_key(ua, &mr)) { return 1; } } ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive); if (ok) { sd = ua->jcr->store_bsock; if (relabel) { /* * Delete the old media record */ if (!db_delete_media_record(ua->jcr, ua->db, &omr)) { ua->error_msg(_("Delete of Volume \"%s\" failed. ERR=%s"), omr.VolumeName, db_strerror(ua->db)); } else { ua->info_msg(_("Old volume \"%s\" deleted from catalog.\n"), omr.VolumeName); /* * Update the number of Volumes in the pool */ pr.NumVols--; if (!db_update_pool_record(ua->jcr, ua->db, &pr)) { ua->error_msg("%s", db_strerror(ua->db)); } } } if (ua->automount) { bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name)); ua->info_msg(_("Requesting to mount %s ...\n"), dev_name); bash_spaces(dev_name); sd->fsend("mount %s drive=%d", dev_name, drive); unbash_spaces(dev_name); /* * We use bget_dirmsg here and not bnet_recv because as part of * the mount request the stored can request catalog information for * any plugin who listens to the bsdEventLabelVerified event. * As we don't want to loose any non protocol data e.g. errors * without a 3xxx prefix we set the allow_any_message of * bget_dirmsg to true and as such is behaves like a normal * bnet_recv for any non protocol messages. */ while (bget_dirmsg(sd, true) >= 0) { ua->send_msg("%s", sd->msg); /* * Here we can get * 3001 OK mount. Device=xxx or * 3001 Mounted Volume vvvv * 3002 Device "DVD-Writer" (/dev/hdc) is mounted. * 3906 is cannot mount non-tape * So for those, no need to print a reminder */ if (bstrncmp(sd->msg, "3001 ", 5) || bstrncmp(sd->msg, "3002 ", 5) || bstrncmp(sd->msg, "3906 ", 5)) { print_reminder = false; } } } } if (print_reminder) { ua->info_msg(_("Do not forget to mount the drive!!!\n")); } close_sd_bsock(ua); return 1; }
/* * Cancel a job -- typically called by the UA (Console program), but may also * be called by the job watchdog. * * Returns: true if cancel appears to be successful * false on failure. Message sent to ua->jcr. */ bool cancel_job(UAContext *ua, JCR *jcr) { BSOCK *sd, *fd; char ed1[50]; int32_t old_status = jcr->JobStatus; jcr->setJobStatus(JS_Canceled); switch (old_status) { case JS_Created: case JS_WaitJobRes: case JS_WaitClientRes: case JS_WaitStoreRes: case JS_WaitPriority: case JS_WaitMaxJobs: case JS_WaitStartTime: ua->info_msg(_("JobId %s, Job %s marked to be canceled.\n"), edit_uint64(jcr->JobId, ed1), jcr->Job); jobq_remove(&job_queue, jcr); /* attempt to remove it from queue */ break; default: /* Cancel File daemon */ if (jcr->file_bsock) { ua->jcr->client = jcr->client; if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) { ua->error_msg(_("Failed to connect to File daemon.\n")); return 0; } Dmsg0(200, "Connected to file daemon\n"); fd = ua->jcr->file_bsock; fd->fsend("cancel Job=%s\n", jcr->Job); while (fd->recv() >= 0) { ua->send_msg("%s", fd->msg); } fd->signal(BNET_TERMINATE); fd->close(); ua->jcr->file_bsock = NULL; jcr->file_bsock->set_terminated(); jcr->my_thread_send_signal(TIMEOUT_SIGNAL); } /* Cancel Storage daemon */ if (jcr->store_bsock) { if (!ua->jcr->wstorage) { if (jcr->rstorage) { copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource")); } else { copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource")); } } else { USTORE store; if (jcr->rstorage) { store.store = jcr->rstore; } else { store.store = jcr->wstore; } set_wstorage(ua->jcr, &store); } if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) { ua->error_msg(_("Failed to connect to Storage daemon.\n")); return false; } Dmsg0(200, "Connected to storage daemon\n"); sd = ua->jcr->store_bsock; sd->fsend("cancel Job=%s\n", jcr->Job); while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); } sd->signal(BNET_TERMINATE); sd->close(); ua->jcr->store_bsock = NULL; jcr->store_bsock->set_timed_out(); jcr->store_bsock->set_terminated(); sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL); jcr->my_thread_send_signal(TIMEOUT_SIGNAL); } break; } return true; }
/* * Common routine for both label and relabel */ static int do_label(UAContext *ua, const char *cmd, int relabel) { USTORE store; BSOCK *sd; char dev_name[MAX_NAME_LENGTH]; MEDIA_DBR mr, omr; POOL_DBR pr; bool print_reminder = true; bool label_barcodes = false; int ok = FALSE; int i, j; int drive; bool media_record_exists = false; static const char *barcode_keyword[] = { "barcode", "barcodes", NULL}; memset(&pr, 0, sizeof(pr)); if (!open_client_db(ua)) { return 1; } /* Look for one of the barcode keywords */ if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) { /* Now find the keyword in the list */ if ((j = find_arg(ua, barcode_keyword[i])) > 0) { *ua->argk[j] = 0; /* zap barcode keyword */ } label_barcodes = true; } store.store = get_storage_resource(ua, true/*use default*/); if (!store.store) { return 1; } pm_strcpy(store.store_source, _("command line")); set_wstorage(ua->jcr, &store); drive = get_storage_drive(ua, store.store); if (label_barcodes) { label_from_barcodes(ua, drive); return 1; } /* If relabel get name of Volume to relabel */ if (relabel) { /* Check for oldvolume=name */ i = find_arg_with_value(ua, "oldvolume"); if (i >= 0) { memset(&omr, 0, sizeof(omr)); bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName)); if (db_get_media_record(ua->jcr, ua->db, &omr)) { goto checkVol; } ua->error_msg("%s", db_strerror(ua->db)); } /* No keyword or Vol not found, ask user to select */ if (!select_media_dbr(ua, &omr)) { return 1; } /* Require Volume to be Purged or Recycled */ checkVol: if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) { ua->error_msg(_("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"), omr.VolumeName, omr.VolStatus); return 1; } } /* Check for volume=NewVolume */ i = find_arg_with_value(ua, "volume"); if (i >= 0) { pm_strcpy(ua->cmd, ua->argv[i]); goto checkName; } /* Get a new Volume name */ for ( ;; ) { media_record_exists = false; if (!get_cmd(ua, _("Enter new Volume name: "))) { return 1; } checkName: if (!is_volume_name_legal(ua, ua->cmd)) { continue; } memset(&mr, 0, sizeof(mr)); bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName)); /* If VolBytes are zero the Volume is not labeled */ if (db_get_media_record(ua->jcr, ua->db, &mr)) { if (mr.VolBytes != 0) { ua->error_msg(_("Media record for new Volume \"%s\" already exists.\n"), mr.VolumeName); continue; } media_record_exists = true; } break; /* Got it */ } /* If autochanger, request slot */ i = find_arg_with_value(ua, "slot"); if (i >= 0) { mr.Slot = atoi(ua->argv[i]); if (mr.Slot < 0) { mr.Slot = 0; } mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */ } else if (store.store->autochanger) { if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) { return 1; } mr.Slot = ua->pint32_val; if (mr.Slot < 0) { mr.Slot = 0; } mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */ } mr.StorageId = store.store->StorageId; bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType)); /* Must select Pool if not already done */ if (pr.PoolId == 0) { memset(&pr, 0, sizeof(pr)); if (!select_pool_dbr(ua, &pr)) { return 1; } } ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive); if (ok) { sd = ua->jcr->store_bsock; if (relabel) { /* Delete the old media record */ if (!db_delete_media_record(ua->jcr, ua->db, &omr)) { ua->error_msg(_("Delete of Volume \"%s\" failed. ERR=%s"), omr.VolumeName, db_strerror(ua->db)); } else { ua->info_msg(_("Old volume \"%s\" deleted from catalog.\n"), omr.VolumeName); /* Update the number of Volumes in the pool */ pr.NumVols--; if (!db_update_pool_record(ua->jcr, ua->db, &pr)) { ua->error_msg("%s", db_strerror(ua->db)); } } } if (ua->automount) { bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name)); ua->info_msg(_("Requesting to mount %s ...\n"), dev_name); bash_spaces(dev_name); bnet_fsend(sd, "mount %s drive=%d", dev_name, drive); unbash_spaces(dev_name); while (bnet_recv(sd) >= 0) { ua->send_msg("%s", sd->msg); /* Here we can get * 3001 OK mount. Device=xxx or * 3001 Mounted Volume vvvv * 3002 Device "DVD-Writer" (/dev/hdc) is mounted. * 3906 is cannot mount non-tape * So for those, no need to print a reminder */ if (strncmp(sd->msg, "3001 ", 5) == 0 || strncmp(sd->msg, "3002 ", 5) == 0 || strncmp(sd->msg, "3906 ", 5) == 0) { print_reminder = false; } } } } if (print_reminder) { ua->info_msg(_("Do not forget to mount the drive!!!\n")); } close_sd_bsock(ua); return 1; }
/* * Update Slots corresponding to Volumes in autochanger */ void update_slots(UAContext *ua) { USTORE store; vol_list_t *vl, *vol_list = NULL; MEDIA_DBR mr; char *slot_list; bool scan; int max_slots; int drive; int Enabled = 1; bool have_enabled; int i; if (!open_client_db(ua)) { return; } store.store = get_storage_resource(ua, true/*arg is storage*/); if (!store.store) { return; } pm_strcpy(store.store_source, _("command line")); set_wstorage(ua->jcr, &store); drive = get_storage_drive(ua, store.store); scan = find_arg(ua, NT_("scan")) >= 0; if ((i=find_arg_with_value(ua, NT_("Enabled"))) >= 0) { Enabled = get_enabled(ua, ua->argv[i]); if (Enabled < 0) { return; } have_enabled = true; } else { have_enabled = false; } max_slots = get_num_slots_from_SD(ua); Dmsg1(100, "max_slots=%d\n", max_slots); if (max_slots <= 0) { ua->warning_msg(_("No slots in changer to scan.\n")); return; } slot_list = (char *)malloc(max_slots+1); if (!get_user_slot_list(ua, slot_list, max_slots)) { free(slot_list); return; } vol_list = get_vol_list_from_SD(ua, scan); if (!vol_list) { ua->warning_msg(_("No Volumes found to label, or no barcodes.\n")); goto bail_out; } /* First zap out any InChanger with StorageId=0 */ db_sql_query(ua->db, "UPDATE Media SET InChanger=0 WHERE StorageId=0", NULL, NULL); /* Walk through the list updating the media records */ for (vl=vol_list; vl; vl=vl->next) { if (vl->Slot > max_slots) { ua->warning_msg(_("Slot %d greater than max %d ignored.\n"), vl->Slot, max_slots); continue; } /* Check if user wants us to look at this slot */ if (!slot_list[vl->Slot]) { Dmsg1(100, "Skipping slot=%d\n", vl->Slot); continue; } /* If scanning, we read the label rather than the barcode */ if (scan) { if (vl->VolName) { free(vl->VolName); vl->VolName = NULL; } vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive); Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot); } slot_list[vl->Slot] = 0; /* clear Slot */ memset(&mr, 0, sizeof(mr)); mr.Slot = vl->Slot; mr.InChanger = 1; mr.StorageId = store.store->StorageId; /* Set InChanger to zero for this Slot */ db_lock(ua->db); db_make_inchanger_unique(ua->jcr, ua->db, &mr); db_unlock(ua->db); if (!vl->VolName) { Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot); ua->info_msg(_("No VolName for Slot=%d InChanger set to zero.\n"), vl->Slot); continue; } memset(&mr, 0, sizeof(mr)); bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName)); db_lock(ua->db); if (db_get_media_record(ua->jcr, ua->db, &mr)) { if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store.store->StorageId) { mr.Slot = vl->Slot; mr.InChanger = 1; mr.StorageId = store.store->StorageId; if (have_enabled) { mr.Enabled = Enabled; } if (!db_update_media_record(ua->jcr, ua->db, &mr)) { ua->error_msg("%s", db_strerror(ua->db)); } else { ua->info_msg(_( "Catalog record for Volume \"%s\" updated to reference slot %d.\n"), mr.VolumeName, mr.Slot); } } else { ua->info_msg(_("Catalog record for Volume \"%s\" is up to date.\n"), mr.VolumeName); } db_unlock(ua->db); continue; } else { ua->warning_msg(_("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"), mr.VolumeName, vl->Slot); } db_unlock(ua->db); } memset(&mr, 0, sizeof(mr)); mr.InChanger = 1; mr.StorageId = store.store->StorageId; db_lock(ua->db); for (int i=1; i <= max_slots; i++) { if (slot_list[i]) { mr.Slot = i; /* Set InChanger to zero for this Slot */ db_make_inchanger_unique(ua->jcr, ua->db, &mr); } } db_unlock(ua->db); bail_out: free_vol_list(vol_list); free(slot_list); close_sd_bsock(ua); return; }
/* * Print slots from AutoChanger */ void status_slots(UAContext *ua, STORE *store_r) { USTORE store; POOL_DBR pr; vol_list_t *vl, *vol_list = NULL; MEDIA_DBR mr; char *slot_list; int max_slots; int drive; int i=1; /* output format */ const char *slot_api_empty_format="%i|||||\n"; const char *slot_api_full_format="%i|%i|%s|%s|%s|%s|\n"; const char *slot_hformat=" %4i%c| %16s | %9s | %20s | %18s |\n"; if (!open_client_db(ua)) { return; } store.store = store_r; pm_strcpy(store.store_source, _("command line")); set_wstorage(ua->jcr, &store); drive = get_storage_drive(ua, store.store); max_slots = get_num_slots_from_SD(ua); if (max_slots <= 0) { ua->warning_msg(_("No slots in changer to scan.\n")); return; } slot_list = (char *)malloc(max_slots+1); if (!get_user_slot_list(ua, slot_list, max_slots)) { free(slot_list); return; } vol_list = get_vol_list_from_SD(ua, true /* want to see all slots */); if (!vol_list) { ua->warning_msg(_("No Volumes found, or no barcodes.\n")); goto bail_out; } if (!ua->api) { ua->info_msg(_(" Slot | Volume Name | Status | Media Type | Pool |\n")); ua->info_msg(_("------+------------------+-----------+----------------------+--------------------|\n")); } /* Walk through the list getting the media records */ for (vl=vol_list; vl; vl=vl->next) { if (vl->Slot > max_slots) { ua->warning_msg(_("Slot %d greater than max %d ignored.\n"), vl->Slot, max_slots); continue; } /* Check if user wants us to look at this slot */ if (!slot_list[vl->Slot]) { Dmsg1(100, "Skipping slot=%d\n", vl->Slot); continue; } slot_list[vl->Slot] = 0; /* clear Slot */ if (!vl->VolName) { Dmsg1(100, "No VolName for Slot=%d.\n", vl->Slot); if (!ua->api) { ua->info_msg(slot_hformat, vl->Slot, '*', "?", "?", "?", "?"); } else { ua->info_msg(slot_api_empty_format, vl->Slot); } continue; } /* Hope that slots are ordered */ for (; i < vl->Slot; i++) { if (slot_list[i]) { if (!ua->api) { ua->info_msg(slot_hformat, i, ' ', "", "", "", ""); } else { ua->info_msg(slot_api_empty_format, i); } slot_list[i]=0; } } memset(&mr, 0, sizeof(mr)); bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName)); db_lock(ua->db); if (mr.VolumeName[0] && db_get_media_record(ua->jcr, ua->db, &mr)) { memset(&pr, 0, sizeof(POOL_DBR)); pr.PoolId = mr.PoolId; if (!db_get_pool_record(ua->jcr, ua->db, &pr)) { strcpy(pr.Name, "?"); } if (!ua->api) { /* Print information */ ua->info_msg(slot_hformat, vl->Slot, ((vl->Slot==mr.Slot)?' ':'*'), mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name); } else { ua->info_msg(slot_api_full_format, vl->Slot, mr.Slot, mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name); } db_unlock(ua->db); continue; } else { /* TODO: get information from catalog */ ua->info_msg(slot_hformat, vl->Slot, '*', mr.VolumeName, "?", "?", "?"); } db_unlock(ua->db); } /* Display the rest of the autochanger */ for (; i <= max_slots; i++) { if (slot_list[i]) { if (!ua->api) { ua->info_msg(slot_hformat, i, ' ', "", "", "", ""); } else { ua->info_msg(slot_api_empty_format, i); } slot_list[i]=0; } } bail_out: free_vol_list(vol_list); free(slot_list); close_sd_bsock(ua); return; }
/* * Update Slots corresponding to Volumes in autochanger */ static void update_slots(UAContext *ua) { USTORERES store; vol_list_t *vl; dlist *vol_list = NULL; MEDIA_DBR mr; char *slot_list; bool scan; int max_slots; int drive = -1; int Enabled = 1; bool have_enabled; int i; if (!open_client_db(ua)) { return; } store.store = get_storage_resource(ua, true, true); if (!store.store) { return; } pm_strcpy(store.store_source, _("command line")); set_wstorage(ua->jcr, &store); scan = find_arg(ua, NT_("scan")) >= 0; if (scan) { drive = get_storage_drive(ua, store.store); } if ((i=find_arg_with_value(ua, NT_("Enabled"))) >= 0) { Enabled = get_enabled(ua, ua->argv[i]); if (Enabled < 0) { return; } have_enabled = true; } else { have_enabled = false; } max_slots = get_num_slots_from_SD(ua); Dmsg1(100, "max_slots=%d\n", max_slots); if (max_slots <= 0) { ua->warning_msg(_("No slots in changer to scan.\n")); return; } slot_list = (char *)malloc(nbytes_for_bits(max_slots)); clear_all_bits(max_slots, slot_list); if (!get_user_slot_list(ua, slot_list, "slots", max_slots)) { free(slot_list); return; } vol_list = get_vol_list_from_SD(ua, store.store, false, scan); if (!vol_list) { ua->warning_msg(_("No Volumes found to update, or no barcodes.\n")); goto bail_out; } /* * First zap out any InChanger with StorageId=0 */ db_sql_query(ua->db, "UPDATE Media SET InChanger=0 WHERE StorageId=0"); /* * Walk through the list updating the media records */ memset(&mr, 0, sizeof(mr)); foreach_dlist(vl, vol_list) { if (vl->Slot > max_slots) { ua->warning_msg(_("Slot %d greater than max %d ignored.\n"), vl->Slot, max_slots); continue; } /* * Check if user wants us to look at this slot */ if (!bit_is_set(vl->Slot - 1, slot_list)) { Dmsg1(100, "Skipping slot=%d\n", vl->Slot); continue; } /* * If scanning, we read the label rather than the barcode */ if (scan) { if (vl->VolName) { free(vl->VolName); vl->VolName = NULL; } vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive); Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot); } clear_bit(vl->Slot - 1, slot_list); /* clear Slot */ set_storageid_in_mr(store.store, &mr); mr.Slot = vl->Slot; mr.InChanger = 1; mr.MediaId = 0; /* Get by VolumeName */ if (vl->VolName) { bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName)); } else { mr.VolumeName[0] = 0; } set_storageid_in_mr(store.store, &mr); Dmsg4(100, "Before make unique: Vol=%s slot=%d inchanger=%d sid=%d\n", mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId); db_lock(ua->db); /* * Set InChanger to zero for this Slot */ db_make_inchanger_unique(ua->jcr, ua->db, &mr); db_unlock(ua->db); Dmsg4(100, "After make unique: Vol=%s slot=%d inchanger=%d sid=%d\n", mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId); if (!vl->VolName) { Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot); ua->info_msg(_("No VolName for Slot=%d InChanger set to zero.\n"), vl->Slot); continue; } db_lock(ua->db); Dmsg4(100, "Before get MR: Vol=%s slot=%d inchanger=%d sid=%d\n", mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId); if (db_get_media_record(ua->jcr, ua->db, &mr)) { Dmsg4(100, "After get MR: Vol=%s slot=%d inchanger=%d sid=%d\n", mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId); /* * If Slot, Inchanger, and StorageId have changed, update the Media record */ if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store.store->StorageId) { mr.Slot = vl->Slot; mr.InChanger = 1; if (have_enabled) { mr.Enabled = Enabled; } set_storageid_in_mr(store.store, &mr); if (!db_update_media_record(ua->jcr, ua->db, &mr)) { ua->error_msg("%s", db_strerror(ua->db)); } else { ua->info_msg(_("Catalog record for Volume \"%s\" updated to reference slot %d.\n"), mr.VolumeName, mr.Slot); } } else { ua->info_msg(_("Catalog record for Volume \"%s\" is up to date.\n"), mr.VolumeName); } } else { ua->warning_msg(_("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"), mr.VolumeName, vl->Slot); } db_unlock(ua->db); } memset(&mr, 0, sizeof(mr)); mr.InChanger = 1; set_storageid_in_mr(store.store, &mr); /* * Any slot not visited gets it Inchanger flag reset. */ db_lock(ua->db); for (i = 1; i <= max_slots; i++) { if (bit_is_set(i - 1, slot_list)) { /* * Set InChanger to zero for this Slot */ mr.Slot = i; db_make_inchanger_unique(ua->jcr, ua->db, &mr); } } db_unlock(ua->db); bail_out: if (vol_list) { free_vol_list(vol_list); } free(slot_list); close_sd_bsock(ua); return; }