/* * Scan all slots that are not empty for the exact volumename * by reading the label of the volume replacing the scanned * barcode when available. When a valid source slot list * is given we only check the slots enabled in that slot list. * We return an updated dlist with the new content of the * autochanger after the scan as that may move some volumes * around. We free the old list and return the new. */ static inline dlist *scan_slots_for_volnames(UAContext *ua, STORERES *store, int drive, dlist *vol_list, char *src_slot_list) { dlist *new_vol_list; vol_list_t vls; vol_list_t *vl1, *vl2; /* * Walk the list of drives and slots available. */ foreach_dlist(vl1, vol_list) { switch (vl1->Type) { case slot_type_drive: continue; default: /* * See if a slot list selection was done and * if so only get the content for this slot when * it is selected in the slot list. */ if (src_slot_list && !bit_is_set(vl1->Slot - 1, src_slot_list)) { continue; } switch (vl1->Content) { case slot_content_full: if (vl1->VolName) { free(vl1->VolName); vl1->VolName = NULL; } vl1->VolName = get_volume_name_from_SD(ua, vl1->Slot, drive); Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl1->VolName, vl1->Slot); break; case slot_content_empty: /* * See if the slot is empty because the volume is * loaded in a drive. */ if (vl1->Type == slot_type_normal && (vl2 = is_loaded_in_drive(vol_list, vl1->Slot)) != NULL) { if (vl2->VolName) { free(vl2->VolName); vl2->VolName = NULL; } vl2->VolName = get_volume_name_from_SD(ua, vl1->Slot, drive); Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl2->VolName, vl1->Slot); } break; default: continue; } break; } } /* * As the scan for volumes can alter the location of * the volumes in the autochanger e.g. volumes in drives * being put back into slots etc we rescan the changer. */ new_vol_list = get_vol_list_from_storage(ua, store, true /* listall */, true /* want to see all slots */); if (!new_vol_list) { /* * Free the old vol_list and return a NULL vol_list. */ storage_free_vol_list(vol_list); return NULL; } /* * Walk the list of drives and slots available. * And copy the new scanned volume names from the old list * to the new list. * * This is optimized for the case the slots are still * filled with the same volume. */ foreach_dlist(vl1, new_vol_list) { switch (vl1->Type) { case slot_type_drive: switch (vl1->Content) { case slot_content_full: /* * Lookup the drive in the old list. */ vls.Index = vl1->Index; vl2 = (vol_list_t *)vol_list->binary_search((void *)&vls, compare_vol_list_entry); if (vl2 && vl2->Content == slot_content_full && vl2->Loaded == vl1->Loaded) { /* * Volume in drive is the same copy the volume name. */ if (vl2->VolName) { free(vl2->VolName); } vl2->VolName = vl1->VolName; vl1->VolName = NULL; } else { /* * Drive is loaded with a volume which was previously * loaded somewhere else. Lookup the currently loaded * volume in the old list. */ vl2 = find_slot_in_list(vol_list, vl1->Loaded); if (vl2) { if (vl2->VolName) { free(vl2->VolName); } vl2->VolName = vl1->VolName; vl1->VolName = NULL; } } break; default: continue; } break; case slot_type_normal: case slot_type_import: /* * See if a slot list selection was done and * if so only get the content for this slot when * it is selected in the slot list. */ if (src_slot_list && !bit_is_set(vl1->Slot - 1, src_slot_list)) { continue; } switch (vl1->Content) { case slot_content_full: /* * Lookup the slot in the old list. */ vls.Index = vl1->Index; vl2 = (vol_list_t *)vol_list->binary_search((void *)&vls, compare_vol_list_entry); if (vl2 && vl2->Content == slot_content_full && vl2->Slot == vl1->Slot) { /* * Volume in slot is the same copy the volume name. */ if (vl2->VolName) { free(vl2->VolName); } vl2->VolName = vl1->VolName; vl1->VolName = NULL; } else { /* * This should never happen as a volume is always put back * into the same slot it was taken from. But as we have the * code to lookup the old place we take a shot at it. */ vl2 = find_slot_in_list(vol_list, vl1->Slot); if (vl2) { if (vl2->VolName) { free(vl2->VolName); } vl2->VolName = vl1->VolName; vl1->VolName = NULL; } } break; default: continue; } break; default: break; } } /* * Free the old vol_list and return the new data. */ storage_free_vol_list(vol_list); return new_vol_list; }
/* * 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; }
/* * 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; }