/* * Update a media record -- allows you to change the * Volume status. E.g. if you want Bacula to stop * writing on the volume, set it to anything other * than Append. */ static int update_volume(UAContext *ua) { MEDIA_DBR mr; POOL *pool; POOL_DBR pr; POOLMEM *query; POOL_MEM ret; char buf[1000]; char ed1[130]; bool done = false; int i; const char *kw[] = { NT_("VolStatus"), /* 0 */ NT_("VolRetention"), /* 1 */ NT_("VolUse"), /* 2 */ NT_("MaxVolJobs"), /* 3 */ NT_("MaxVolFiles"), /* 4 */ NT_("MaxVolBytes"), /* 5 */ NT_("Recycle"), /* 6 */ NT_("InChanger"), /* 7 */ NT_("Slot"), /* 8 */ NT_("Pool"), /* 9 */ NT_("FromPool"), /* 10 */ NT_("AllFromPool"), /* 11 !!! see below !!! */ NT_("Enabled"), /* 12 */ NT_("RecyclePool"), /* 13 */ NT_("ActionOnPurge"), /* 14 */ NULL }; #define AllFromPool 11 /* keep this updated with above */ for (i=0; kw[i]; i++) { int j; POOL_DBR pr; if ((j=find_arg_with_value(ua, kw[i])) > 0) { /* If all from pool don't select a media record */ if (i != AllFromPool && !select_media_dbr(ua, &mr)) { return 0; } switch (i) { case 0: update_volstatus(ua, ua->argv[j], &mr); break; case 1: update_volretention(ua, ua->argv[j], &mr); break; case 2: update_voluseduration(ua, ua->argv[j], &mr); break; case 3: update_volmaxjobs(ua, ua->argv[j], &mr); break; case 4: update_volmaxfiles(ua, ua->argv[j], &mr); break; case 5: update_volmaxbytes(ua, ua->argv[j], &mr); break; case 6: update_volrecycle(ua, ua->argv[j], &mr); break; case 7: update_volinchanger(ua, ua->argv[j], &mr); break; case 8: update_volslot(ua, ua->argv[j], &mr); break; case 9: memset(&pr, 0, sizeof(POOL_DBR)); pr.PoolId = mr.PoolId; if (!db_get_pool_record(ua->jcr, ua->db, &pr)) { ua->error_msg("%s", db_strerror(ua->db)); break; } update_vol_pool(ua, ua->argv[j], &mr, &pr); break; case 10: update_vol_from_pool(ua, &mr); return 1; case 11: update_all_vols_from_pool(ua, ua->argv[j]); return 1; case 12: update_volenabled(ua, ua->argv[j], &mr); break; case 13: update_vol_recyclepool(ua, ua->argv[j], &mr); break; case 14: update_vol_actiononpurge(ua, ua->argv[j], &mr); break; } done = true; } } /* Allow user to simply update all volumes */ if (find_arg(ua, NT_("fromallpools")) > 0) { update_all_vols(ua); return 1; } for ( ; !done; ) { start_prompt(ua, _("Parameters to modify:\n")); add_prompt(ua, _("Volume Status")); /* 0 */ add_prompt(ua, _("Volume Retention Period")); /* 1 */ add_prompt(ua, _("Volume Use Duration")); /* 2 */ add_prompt(ua, _("Maximum Volume Jobs")); /* 3 */ add_prompt(ua, _("Maximum Volume Files")); /* 4 */ add_prompt(ua, _("Maximum Volume Bytes")); /* 5 */ add_prompt(ua, _("Recycle Flag")); /* 6 */ add_prompt(ua, _("Slot")); /* 7 */ add_prompt(ua, _("InChanger Flag")); /* 8 */ add_prompt(ua, _("Volume Files")); /* 9 */ add_prompt(ua, _("Pool")); /* 10 */ add_prompt(ua, _("Volume from Pool")); /* 11 */ add_prompt(ua, _("All Volumes from Pool")); /* 12 */ add_prompt(ua, _("All Volumes from all Pools")); /* 13 */ add_prompt(ua, _("Enabled")), /* 14 */ add_prompt(ua, _("RecyclePool")), /* 15 */ add_prompt(ua, _("Action On Purge")), /* 16 */ add_prompt(ua, _("Done")); /* 17 */ i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0); /* For All Volumes, All Volumes from Pool, and Done, we don't need * a Volume record */ if ( i != 12 && i != 13 && i != 17) { if (!select_media_dbr(ua, &mr)) { /* Get Volume record */ return 0; } ua->info_msg(_("Updating Volume \"%s\"\n"), mr.VolumeName); } switch (i) { case 0: /* Volume Status */ /* Modify Volume Status */ ua->info_msg(_("Current Volume status is: %s\n"), mr.VolStatus); start_prompt(ua, _("Possible Values are:\n")); add_prompt(ua, NT_("Append")); add_prompt(ua, NT_("Archive")); add_prompt(ua, NT_("Disabled")); add_prompt(ua, NT_("Full")); add_prompt(ua, NT_("Used")); add_prompt(ua, NT_("Cleaning")); if (strcmp(mr.VolStatus, NT_("Purged")) == 0) { add_prompt(ua, NT_("Recycle")); } add_prompt(ua, NT_("Read-Only")); if (do_prompt(ua, "", _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) { return 1; } update_volstatus(ua, ua->cmd, &mr); break; case 1: /* Retention */ ua->info_msg(_("Current retention period is: %s\n"), edit_utime(mr.VolRetention, ed1, sizeof(ed1))); if (!get_cmd(ua, _("Enter Volume Retention period: "))) { return 0; } update_volretention(ua, ua->cmd, &mr); break; case 2: /* Use Duration */ ua->info_msg(_("Current use duration is: %s\n"), edit_utime(mr.VolUseDuration, ed1, sizeof(ed1))); if (!get_cmd(ua, _("Enter Volume Use Duration: "))) { return 0; } update_voluseduration(ua, ua->cmd, &mr); break; case 3: /* Max Jobs */ ua->info_msg(_("Current max jobs is: %u\n"), mr.MaxVolJobs); if (!get_pint(ua, _("Enter new Maximum Jobs: "))) { return 0; } update_volmaxjobs(ua, ua->cmd, &mr); break; case 4: /* Max Files */ ua->info_msg(_("Current max files is: %u\n"), mr.MaxVolFiles); if (!get_pint(ua, _("Enter new Maximum Files: "))) { return 0; } update_volmaxfiles(ua, ua->cmd, &mr); break; case 5: /* Max Bytes */ ua->info_msg(_("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1)); if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) { return 0; } update_volmaxbytes(ua, ua->cmd, &mr); break; case 6: /* Recycle */ ua->info_msg(_("Current recycle flag is: %s\n"), mr.Recycle==1?_("yes"):_("no")); if (!get_yesno(ua, _("Enter new Recycle status: "))) { return 0; } update_volrecycle(ua, ua->cmd, &mr); break; case 7: /* Slot */ ua->info_msg(_("Current Slot is: %d\n"), mr.Slot); if (!get_pint(ua, _("Enter new Slot: "))) { return 0; } update_volslot(ua, ua->cmd, &mr); break; case 8: /* InChanger */ ua->info_msg(_("Current InChanger flag is: %d\n"), mr.InChanger); bsnprintf(buf, sizeof(buf), _("Set InChanger flag for Volume \"%s\": yes/no: "), mr.VolumeName); if (!get_yesno(ua, buf)) { return 0; } mr.InChanger = ua->pint32_val; /* * Make sure to use db_update... rather than doing this directly, * so that any Slot is handled correctly. */ if (!db_update_media_record(ua->jcr, ua->db, &mr)) { ua->error_msg(_("Error updating media record Slot: ERR=%s"), db_strerror(ua->db)); } else { ua->info_msg(_("New InChanger flag is: %d\n"), mr.InChanger); } break; case 9: /* Volume Files */ int32_t VolFiles; ua->warning_msg(_("Warning changing Volume Files can result\n" "in loss of data on your Volume\n\n")); ua->info_msg(_("Current Volume Files is: %u\n"), mr.VolFiles); if (!get_pint(ua, _("Enter new number of Files for Volume: "))) { return 0; } VolFiles = ua->pint32_val; if (VolFiles != (int)(mr.VolFiles + 1)) { ua->warning_msg(_("Normally, you should only increase Volume Files by one!\n")); if (!get_yesno(ua, _("Increase Volume Files? (yes/no): ")) || ua->pint32_val == 0) { break; } } query = get_pool_memory(PM_MESSAGE); Mmsg(query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%s", VolFiles, edit_int64(mr.MediaId, ed1)); if (!db_sql_query(ua->db, query, NULL, NULL)) { ua->error_msg("%s", db_strerror(ua->db)); } else { ua->info_msg(_("New Volume Files is: %u\n"), VolFiles); } free_pool_memory(query); break; case 10: /* Volume's Pool */ memset(&pr, 0, sizeof(POOL_DBR)); pr.PoolId = mr.PoolId; if (!db_get_pool_record(ua->jcr, ua->db, &pr)) { ua->error_msg("%s", db_strerror(ua->db)); return 0; } ua->info_msg(_("Current Pool is: %s\n"), pr.Name); if (!get_cmd(ua, _("Enter new Pool name: "))) { return 0; } update_vol_pool(ua, ua->cmd, &mr, &pr); return 1; case 11: update_vol_from_pool(ua, &mr); return 1; case 12: pool = select_pool_resource(ua); if (pool) { update_all_vols_from_pool(ua, pool->name()); } return 1; case 13: update_all_vols(ua); return 1; case 14: ua->info_msg(_("Current Enabled is: %d\n"), mr.Enabled); if (!get_cmd(ua, _("Enter new Enabled: "))) { return 0; } if (strcasecmp(ua->cmd, "yes") == 0 || strcasecmp(ua->cmd, "true") == 0) { mr.Enabled = 1; } else if (strcasecmp(ua->cmd, "no") == 0 || strcasecmp(ua->cmd, "false") == 0) { mr.Enabled = 0; } else if (strcasecmp(ua->cmd, "archived") == 0) { mr.Enabled = 2; } else { mr.Enabled = atoi(ua->cmd); } update_volenabled(ua, ua->cmd, &mr); break; case 15: memset(&pr, 0, sizeof(POOL_DBR)); pr.PoolId = mr.RecyclePoolId; if (db_get_pool_record(ua->jcr, ua->db, &pr)) { ua->info_msg(_("Current RecyclePool is: %s\n"), pr.Name); } else { ua->info_msg(_("No current RecyclePool\n")); } if (!select_pool_dbr(ua, &pr, NT_("recyclepool"))) { return 0; } update_vol_recyclepool(ua, pr.Name, &mr); return 1; case 16: pm_strcpy(ret, ""); ua->info_msg(_("Current ActionOnPurge is: %s\n"), action_on_purge_to_string(mr.ActionOnPurge, ret)); if (!get_cmd(ua, _("Enter new ActionOnPurge (one of: Truncate, None): "))) { return 0; } update_vol_actiononpurge(ua, ua->cmd, &mr); break; default: /* Done or error */ ua->info_msg(_("Selection terminated.\n")); return 1; } } return 1; }
/* * Request SD to send us the slot:barcodes, then wiffle * through them all labeling them. */ static void label_from_barcodes(UAContext *ua, int drive, bool label_encrypt) { STORERES *store = ua->jcr->res.wstore; POOL_DBR pr; MEDIA_DBR mr, omr; vol_list_t *vl; dlist *vol_list = NULL; bool media_record_exists; char *slot_list; int max_slots; 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(nbytes_for_bits(max_slots)); clear_all_bits(max_slots, slot_list); if (!get_user_slot_list(ua, slot_list, "slots", max_slots)) { goto bail_out; } vol_list = get_vol_list_from_SD(ua, store, false /* no listall */ , false /*no scan*/); if (!vol_list) { ua->warning_msg(_("No Volumes found to label, or no barcodes.\n")); goto bail_out; } /* * Display list of Volumes and ask if he really wants to proceed */ ua->send_msg(_("The following Volumes will be labeled:\n" "Slot Volume\n" "==============\n")); foreach_dlist(vl, vol_list) { if (!vl->VolName || !bit_is_set(vl->Slot - 1, slot_list)) { continue; } ua->send_msg("%4d %s\n", vl->Slot, vl->VolName); } if (!get_yesno(ua, _("Do you want to label these Volumes? (yes|no): ")) || (ua->pint32_val == 0)) { goto bail_out; } /* * Select a pool */ memset(&pr, 0, sizeof(pr)); if (!select_pool_dbr(ua, &pr)) { goto bail_out; } /* * Fire off the label requests */ foreach_dlist(vl, vol_list) { if (!vl->VolName || !bit_is_set(vl->Slot - 1, slot_list)) { continue; } mr.clear(); bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName)); media_record_exists = false; if (db_get_media_record(ua->jcr, ua->db, &mr)) { if (mr.VolBytes != 0) { ua->warning_msg(_("Media record for Slot %d Volume \"%s\" already exists.\n"), vl->Slot, mr.VolumeName); mr.Slot = vl->Slot; mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */ set_storageid_in_mr(store, &mr); if (!db_update_media_record(ua->jcr, ua->db, &mr)) { ua->error_msg(_("Error setting InChanger: ERR=%s"), db_strerror(ua->db)); } continue; } media_record_exists = true; } mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */ set_storageid_in_mr(store, &mr); /* * Deal with creating cleaning tape here. Normal tapes created in send_label_request() below */ if (is_cleaning_tape(ua, &mr, &pr)) { if (media_record_exists) { /* we update it */ mr.VolBytes = 1; /* any bytes to indicate it exists */ bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus)); mr.MediaType[0] = 0; set_storageid_in_mr(store, &mr); if (!db_update_media_record(ua->jcr, ua->db, &mr)) { ua->error_msg("%s", db_strerror(ua->db)); } } else { /* create the media record */ if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) { ua->error_msg(_("Maximum pool Volumes=%d reached.\n"), pr.MaxVols); goto bail_out; } set_pool_dbr_defaults_in_media_dbr(&mr, &pr); bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus)); mr.MediaType[0] = 0; set_storageid_in_mr(store, &mr); if (db_create_media_record(ua->jcr, ua->db, &mr)) { ua->send_msg(_("Catalog record for cleaning tape \"%s\" successfully created.\n"), mr.VolumeName); pr.NumVols++; /* this is a bit suspect */ if (!db_update_pool_record(ua->jcr, ua->db, &pr)) { ua->error_msg("%s", db_strerror(ua->db)); } } else { ua->error_msg(_("Catalog error on cleaning tape: %s"), db_strerror(ua->db)); } } continue; /* done, go handle next volume */ } bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType)); /* * See if we need to generate a new passphrase for hardware encryption. */ if (label_encrypt) { if (!generate_new_encryption_key(ua, &mr)) { continue; } } mr.Slot = vl->Slot; send_label_request(ua, &mr, &omr, &pr, false, media_record_exists, drive); } bail_out: free(slot_list); if (vol_list) { free_vol_list(vol_list); } close_sd_bsock(ua); 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; }
/* * 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; }