X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=bacula%2Fsrc%2Fdird%2Fua_label.c;h=df9578fd55a04c31961e767cb15e6292dc0e9184;hb=c79c1f5ae10408debf2f3f26361df38100bc025e;hp=20ed2bd493e0f87efe1a418ad9599ea4f59b3c02;hpb=bca74a7343c597a0a687721e732916377972c3d6;p=bacula%2Fbacula diff --git a/bacula/src/dird/ua_label.c b/bacula/src/dird/ua_label.c index 20ed2bd493..df9578fd55 100644 --- a/bacula/src/dird/ua_label.c +++ b/bacula/src/dird/ua_label.c @@ -1,26 +1,26 @@ /* Bacula® - The Network Backup Solution - Copyright (C) 2003-2007 Free Software Foundation Europe e.V. + Copyright (C) 2003-2008 Free Software Foundation Europe e.V. The main author of Bacula is Kern Sibbald, with contributions from many others, a complete list can be found in the file AUTHORS. This program is Free Software; you can redistribute it and/or - modify it under the terms of version two of the GNU General Public - License as published by the Free Software Foundation plus additions - that are listed in the file LICENSE. + modify it under the terms of version three of the GNU Affero General Public + License as published by the Free Software Foundation and included + in the file LICENSE. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU General Public License + You should have received a copy of the GNU Affero General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - Bacula® is a registered trademark of John Walker. + Bacula® is a registered trademark of Kern Sibbald. The licensor of Bacula is the Free Software Foundation Europe (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich, Switzerland, email:ftf@fsfeurope.org. @@ -84,6 +84,9 @@ static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots) slot_list[i] = 0; } i = find_arg_with_value(ua, "slots"); + if (i == -1) { /* not found */ + i = find_arg_with_value(ua, "slot"); + } if (i > 0) { /* scan slot list in ua->argv[i] */ char *p, *e, *h; @@ -154,6 +157,7 @@ static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots) return true; bail_out: + Dmsg1(100, "Problem with user selection ERR=%s\n", msg); return false; } @@ -535,7 +539,7 @@ static void label_from_barcodes(UAContext *ua, int drive) } ua->send_msg("%4d %s\n", vl->Slot, vl->VolName); } - if (!get_yesno(ua, _("Do you want to continue? (yes|no): ")) || + if (!get_yesno(ua, _("Do you want to label these Volumes? (yes|no): ")) || (ua->pint32_val == 0)) { goto bail_out; } @@ -678,14 +682,14 @@ static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, bash_spaces(pr->Name); if (relabel) { bash_spaces(omr->VolumeName); - bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s " + sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s " "MediaType=%s Slot=%d drive=%d", dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive); ua->send_msg(_("Sending relabel command from \"%s\" to \"%s\" ...\n"), omr->VolumeName, mr->VolumeName); } else { - bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s " + sd->fsend("label %s VolumeName=%s PoolName=%s MediaType=%s " "Slot=%d drive=%d", dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive); @@ -695,7 +699,7 @@ static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive); } - while (bnet_recv(sd) >= 0) { + while (sd->recv() >= 0) { int dvd; ua->send_msg("%s", sd->msg); if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes, @@ -787,11 +791,11 @@ static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive) bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* Ask for autochanger list of volumes */ - bnet_fsend(sd, NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive); + 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 (bnet_recv(sd) >= 0) { + 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) { @@ -893,13 +897,28 @@ static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan) vl->next = vol_list; vol_list = vl; } else { - /* Add new entry to end of list */ + vol_list_t *prev=vol_list; + /* Add new entry to the right place in the list */ for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) { + if (tvl->Slot > vl->Slot) { + /* no previous item, update vol_list directly */ + if (prev == vol_list) { + vl->next = vol_list; + vol_list = vl; + + } else { /* replace the previous pointer */ + prev->next = vl; + vl->next = tvl; + } + break; + } + /* we are at the end */ if (!tvl->next) { tvl->next = vl; vl->next = NULL; break; } + prev = tvl; } } } @@ -941,9 +960,9 @@ static int get_num_slots_from_SD(UAContext *ua) bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* Ask for autochanger number of slots */ - bnet_fsend(sd, NT_("autochanger slots %s\n"), dev_name); + sd->fsend(NT_("autochanger slots %s\n"), dev_name); - while (bnet_recv(sd) >= 0) { + while (sd->recv() >= 0) { if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) { break; } else { @@ -973,9 +992,9 @@ int get_num_drives_from_SD(UAContext *ua) bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* Ask for autochanger number of slots */ - bnet_fsend(sd, NT_("autochanger drives %s\n"), dev_name); + sd->fsend(NT_("autochanger drives %s\n"), dev_name); - while (bnet_recv(sd) >= 0) { + while (sd->recv() >= 0) { if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) { break; } else { @@ -987,9 +1006,6 @@ int get_num_drives_from_SD(UAContext *ua) return drives; } - - - /* * Check if this is a cleaning tape by comparing the Volume name * with the Cleaning Prefix. If they match, this is a cleaning @@ -1015,3 +1031,284 @@ static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr) return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix, strlen(ua->jcr->pool->cleaning_prefix)) == 0; } + +static void content_send_info(UAContext *ua, char type, int Slot, char *vol_name) +{ + char ed1[50], ed2[50], ed3[50]; + POOL_DBR pr; + MEDIA_DBR mr; + /* Type|Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire */ + const char *slot_api_full_format="%c|%i|%i|%s|%s|%s|%s|%s|%s|%s\n"; + const char *slot_api_empty_format="%c|%i||||||||\n"; + + if (is_volume_name_legal(NULL, vol_name)) { + memset(&mr, 0, sizeof(mr)); + bstrncpy(mr.VolumeName, vol_name, sizeof(mr.VolumeName)); + if (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, "?"); + } + ua->send_msg(slot_api_full_format, type, + Slot, mr.Slot, mr.VolumeName, + edit_uint64(mr.VolBytes, ed1), + mr.VolStatus, mr.MediaType, pr.Name, + edit_uint64(mr.LastWritten, ed2), + edit_uint64(mr.LastWritten+mr.VolRetention, ed3)); + + } else { /* Media unknown */ + ua->send_msg(slot_api_full_format, + type, Slot, 0, mr.VolumeName, "?", "?", "?", "?", + "0", "0"); + + } + } else { + ua->send_msg(slot_api_empty_format, type, Slot); + } +} + +/* + * 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 + * + * Output: + * + * Drive list: D|Drive num|Slot loaded|Volume Name + * D|0|45|vol45 + * D|1|42|vol42 + * D|3|| + * + * Slot list: Type|Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire + * + * S|1|1|vol1|31417344|Full|LTO1-ANSI|Inc|1250858902|1282394902 + * S|2|||||||| + * S|3|3|vol4|15869952|Append|LTO1-ANSI|Inc|1250858907|1282394907 + * + * TODO: need to merge with status_slots() + */ +void status_content(UAContext *ua, STORE *store) +{ + int Slot, Drive; + char type; + char dev_name[MAX_NAME_LENGTH]; + char vol_name[MAX_NAME_LENGTH]; + BSOCK *sd; + vol_list_t *vl=NULL, *vol_list = NULL; + + if (!(sd=open_sd_bsock(ua))) { + return; + } + + if (!open_client_db(ua)) { + return; + } + + bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); + bash_spaces(dev_name); + /* Ask for autochanger list of volumes */ + bnet_fsend(sd, NT_("autochanger listall %s \n"), dev_name); + + /* Read and organize list of Drive, Slots and I/O Slots */ + 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; + } + + Drive = Slot = -1; + *vol_name = 0; + + if (sscanf(sd->msg, "D:%d:F:%d:%127s", &Drive, &Slot, vol_name) == 3) { + ua->send_msg("D|%d|%d|%s\n", Drive, Slot, vol_name); + + /* we print information on the slot if we have a volume name */ + if (*vol_name) { + /* Add Slot and VolumeName to list */ + vl = (vol_list_t *)malloc(sizeof(vol_list_t)); + vl->Slot = Slot; + vl->VolName = bstrdup(vol_name); + vl->next = vol_list; + vol_list = vl; + } + + } else if (sscanf(sd->msg, "D:%d:E", &Drive) == 1) { + ua->send_msg("D|%d||\n", Drive); + + } else if (sscanf(sd->msg, "%c:%d:F:%127s", &type, &Slot, vol_name)== 3) { + content_send_info(ua, type, Slot, vol_name); + + } else if (sscanf(sd->msg, "%c:%d:E", &type, &Slot) == 2) { + /* type can be S (slot) or I (Import/Export slot) */ + vol_list_t *prev=NULL; + for (vl = vol_list; vl; vl = vl->next) { + if (vl->Slot == Slot) { + bstrncpy(vol_name, vl->VolName, MAX_NAME_LENGTH); + + /* remove the node */ + if (prev) { + prev->next = vl->next; + } else { + vol_list = vl->next; + } + free(vl->VolName); + free(vl); + break; + } + prev = vl; + } + content_send_info(ua, type, Slot, vol_name); + + } else { + Dmsg1(10, "Discarding msg=%s\n", sd->msg); + } + } + close_sd_bsock(ua); +} + +/* + * 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; + /* Slot | Volume | Status | MediaType | Pool */ + const char *slot_hformat=" %4i%c| %16s | %9s | %20s | %18s |\n"; + + if (ua->api) { + status_content(ua, store_r); + return; + } + + 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; + } + ua->send_msg(_(" Slot | Volume Name | Status | Media Type | Pool |\n")); + ua->send_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); + ua->send_msg(slot_hformat, + vl->Slot, '*', + "?", "?", "?", "?"); + continue; + } + + /* Hope that slots are ordered */ + for (; i < vl->Slot; i++) { + if (slot_list[i]) { + ua->send_msg(slot_hformat, + 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, "?"); + } + db_unlock(ua->db); + + /* Print information */ + ua->send_msg(slot_hformat, + vl->Slot, ((vl->Slot==mr.Slot)?' ':'*'), + mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name); + continue; + } else { /* TODO: get information from catalog */ + ua->send_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]) { + ua->send_msg(slot_hformat, + i, ' ', "", "", "", ""); + slot_list[i]=0; + } + } + +bail_out: + + free_vol_list(vol_list); + free(slot_list); + close_sd_bsock(ua); + + return; +}