2 Bacula® - The Network Backup Solution
4 Copyright (C) 2003-2012 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Bacula Director -- Tape labeling commands
32 * Kern Sibbald, April MMIII
39 /* Slot list definition */
40 typedef struct s_vol_list {
41 struct s_vol_list *next;
47 /* Forward referenced functions */
48 static int do_label(UAContext *ua, const char *cmd, int relabel);
49 static void label_from_barcodes(UAContext *ua, int drive);
50 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
51 POOL_DBR *pr, int relabel, bool media_record_exits, int drive);
52 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan);
53 static void free_vol_list(vol_list_t *vol_list);
54 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
55 static BSOCK *open_sd_bsock(UAContext *ua);
56 static void close_sd_bsock(UAContext *ua);
57 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive);
58 static int get_num_slots_from_SD(UAContext *ua);
64 * label storage=xxx volume=vvv
66 int label_cmd(UAContext *ua, const char *cmd)
68 return do_label(ua, cmd, 0); /* standard label */
71 int relabel_cmd(UAContext *ua, const char *cmd)
73 return do_label(ua, cmd, 1); /* relabel tape */
76 static bool get_user_slot_list(UAContext *ua, char *slot_list, int num_slots)
81 /* slots are numbered 1 to num_slots */
82 for (int i=0; i <= num_slots; i++) {
85 i = find_arg_with_value(ua, "slots");
86 if (i == -1) { /* not found */
87 i = find_arg_with_value(ua, "slot");
90 /* scan slot list in ua->argv[i] */
94 strip_trailing_junk(ua->argv[i]);
95 for (p=ua->argv[i]; p && *p; p=e) {
101 /* Check for range */
102 h = strchr(p, '-'); /* range? */
104 msg = _("Negative numbers not permitted\n");
109 if (!is_an_integer(h)) {
110 msg = _("Range end is not integer.\n");
114 if (!is_an_integer(p)) {
115 msg = _("Range start is not an integer.\n");
121 msg = _("Range end not bigger than start.\n");
126 if (!is_an_integer(p)) {
127 msg = _("Input value is not an integer.\n");
132 if (beg <= 0 || end <= 0) {
133 msg = _("Values must be be greater than zero.\n");
136 if (end > num_slots) {
137 msg = _("Slot too large.\n");
140 for (i=beg; i<=end; i++) {
141 slot_list[i] = 1; /* Turn on specified range */
145 /* Turn everything on */
146 for (i=1; i <= num_slots; i++) {
150 Dmsg0(100, "Slots turned on:\n");
151 for (i=1; i <= num_slots; i++) {
153 Dmsg1(100, "%d\n", i);
159 Dmsg1(100, "Problem with user selection ERR=%s\n", msg);
164 * Update Slots corresponding to Volumes in autochanger
166 void update_slots(UAContext *ua)
169 vol_list_t *vl, *vol_list = NULL;
180 if (!open_client_db(ua)) {
183 store.store = get_storage_resource(ua, true/*arg is storage*/);
187 pm_strcpy(store.store_source, _("command line"));
188 set_wstorage(ua->jcr, &store);
189 drive = get_storage_drive(ua, store.store);
191 scan = find_arg(ua, NT_("scan")) >= 0;
192 if ((i=find_arg_with_value(ua, NT_("Enabled"))) >= 0) {
193 Enabled = get_enabled(ua, ua->argv[i]);
199 have_enabled = false;
202 max_slots = get_num_slots_from_SD(ua);
203 Dmsg1(100, "max_slots=%d\n", max_slots);
204 if (max_slots <= 0) {
205 ua->warning_msg(_("No slots in changer to scan.\n"));
208 slot_list = (char *)malloc(max_slots+1);
209 if (!get_user_slot_list(ua, slot_list, max_slots)) {
214 vol_list = get_vol_list_from_SD(ua, scan);
217 ua->warning_msg(_("No Volumes found to label, or no barcodes.\n"));
221 /* First zap out any InChanger with StorageId=0 */
222 db_sql_query(ua->db, "UPDATE Media SET InChanger=0 WHERE StorageId=0", NULL, NULL);
224 /* Walk through the list updating the media records */
225 for (vl=vol_list; vl; vl=vl->next) {
226 if (vl->Slot > max_slots) {
227 ua->warning_msg(_("Slot %d greater than max %d ignored.\n"),
228 vl->Slot, max_slots);
231 /* Check if user wants us to look at this slot */
232 if (!slot_list[vl->Slot]) {
233 Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
236 /* If scanning, we read the label rather than the barcode */
242 vl->VolName = get_volume_name_from_SD(ua, vl->Slot, drive);
243 Dmsg2(100, "Got Vol=%s from SD for Slot=%d\n", vl->VolName, vl->Slot);
245 slot_list[vl->Slot] = 0; /* clear Slot */
248 mr.MediaId = 0; /* Get by VolumeName */
250 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
252 mr.VolumeName[0] = 0;
254 set_storageid_in_mr(store.store, &mr);
255 /* Set InChanger to zero for this Slot */
256 Dmsg4(100, "Before make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
257 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
259 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
261 Dmsg4(100, "After make unique: Vol=%s slot=%d inchanger=%d sid=%d\n",
262 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
264 Dmsg1(100, "No VolName for Slot=%d setting InChanger to zero.\n", vl->Slot);
265 ua->info_msg(_("No VolName for Slot=%d InChanger set to zero.\n"), vl->Slot);
269 Dmsg4(100, "Before get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
270 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
271 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
272 Dmsg4(100, "After get MR: Vol=%s slot=%d inchanger=%d sid=%d\n",
273 mr.VolumeName, mr.Slot, mr.InChanger, mr.StorageId);
274 if (mr.Slot != vl->Slot || !mr.InChanger || mr.StorageId != store.store->StorageId) {
278 mr.Enabled = Enabled;
280 set_storageid_in_mr(store.store, &mr);
281 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
282 ua->error_msg("%s", db_strerror(ua->db));
285 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
286 mr.VolumeName, mr.Slot);
289 ua->info_msg(_("Catalog record for Volume \"%s\" is up to date.\n"),
295 ua->warning_msg(_("Volume \"%s\" not found in catalog. Slot=%d InChanger set to zero.\n"),
296 mr.VolumeName, vl->Slot);
302 set_storageid_in_mr(store.store, &mr);
304 for (int i=1; i <= max_slots; i++) {
307 /* Set InChanger to zero for this Slot */
308 db_make_inchanger_unique(ua->jcr, ua->db, &mr);
315 free_vol_list(vol_list);
324 * Common routine for both label and relabel
326 static int do_label(UAContext *ua, const char *cmd, int relabel)
330 char dev_name[MAX_NAME_LENGTH];
333 bool print_reminder = true;
334 bool label_barcodes = false;
338 bool media_record_exists = false;
339 static const char *barcode_keyword[] = {
345 memset(&pr, 0, sizeof(pr));
346 if (!open_client_db(ua)) {
350 /* Look for one of the barcode keywords */
351 if (!relabel && (i=find_arg_keyword(ua, barcode_keyword)) >= 0) {
352 /* Now find the keyword in the list */
353 if ((j = find_arg(ua, barcode_keyword[i])) > 0) {
354 *ua->argk[j] = 0; /* zap barcode keyword */
356 label_barcodes = true;
359 store.store = get_storage_resource(ua, true/*use default*/);
363 pm_strcpy(store.store_source, _("command line"));
364 set_wstorage(ua->jcr, &store);
365 drive = get_storage_drive(ua, store.store);
367 if (label_barcodes) {
368 label_from_barcodes(ua, drive);
372 /* If relabel get name of Volume to relabel */
374 /* Check for oldvolume=name */
375 i = find_arg_with_value(ua, "oldvolume");
377 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
378 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
381 ua->error_msg("%s", db_strerror(ua->db));
383 /* No keyword or Vol not found, ask user to select */
384 if (!select_media_dbr(ua, &omr)) {
388 /* Require Volume to be Purged or Recycled */
390 if (strcmp(omr.VolStatus, "Purged") != 0 && strcmp(omr.VolStatus, "Recycle") != 0) {
391 ua->error_msg(_("Volume \"%s\" has VolStatus %s. It must be Purged or Recycled before relabeling.\n"),
392 omr.VolumeName, omr.VolStatus);
397 /* Check for volume=NewVolume */
398 i = find_arg_with_value(ua, "volume");
400 pm_strcpy(ua->cmd, ua->argv[i]);
404 /* Get a new Volume name */
406 media_record_exists = false;
407 if (!get_cmd(ua, _("Enter new Volume name: "))) {
411 if (!is_volume_name_legal(ua, ua->cmd)) {
415 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
416 /* If VolBytes are zero the Volume is not labeled */
417 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
418 if (mr.VolBytes != 0) {
419 ua->error_msg(_("Media record for new Volume \"%s\" already exists.\n"),
423 media_record_exists = true;
428 /* If autochanger, request slot */
429 i = find_arg_with_value(ua, "slot");
431 mr.Slot = atoi(ua->argv[i]);
435 mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
436 } else if (store.store->autochanger) {
437 if (!get_pint(ua, _("Enter slot (0 or Enter for none): "))) {
440 mr.Slot = ua->pint32_val;
444 mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
446 set_storageid_in_mr(store.store, &mr);
448 bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));
450 /* Must select Pool if not already done */
451 if (pr.PoolId == 0) {
452 memset(&pr, 0, sizeof(pr));
453 if (!select_pool_dbr(ua, &pr)) {
458 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists, drive);
461 sd = ua->jcr->store_bsock;
463 /* Delete the old media record */
464 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
465 ua->error_msg(_("Delete of Volume \"%s\" failed. ERR=%s"),
466 omr.VolumeName, db_strerror(ua->db));
468 ua->info_msg(_("Old volume \"%s\" deleted from catalog.\n"),
470 /* Update the number of Volumes in the pool */
472 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
473 ua->error_msg("%s", db_strerror(ua->db));
478 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
479 ua->info_msg(_("Requesting to mount %s ...\n"), dev_name);
480 bash_spaces(dev_name);
481 bnet_fsend(sd, "mount %s drive=%d", dev_name, drive);
482 unbash_spaces(dev_name);
483 while (bnet_recv(sd) >= 0) {
484 ua->send_msg("%s", sd->msg);
486 * 3001 OK mount. Device=xxx or
487 * 3001 Mounted Volume vvvv
488 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
489 * 3906 is cannot mount non-tape
490 * So for those, no need to print a reminder
492 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
493 strncmp(sd->msg, "3002 ", 5) == 0 ||
494 strncmp(sd->msg, "3906 ", 5) == 0) {
495 print_reminder = false;
500 if (print_reminder) {
501 ua->info_msg(_("Do not forget to mount the drive!!!\n"));
509 * Request SD to send us the slot:barcodes, then wiffle
510 * through them all labeling them.
512 static void label_from_barcodes(UAContext *ua, int drive)
514 STORE *store = ua->jcr->wstore;
517 vol_list_t *vl, *vol_list = NULL;
518 bool media_record_exists;
523 max_slots = get_num_slots_from_SD(ua);
524 if (max_slots <= 0) {
525 ua->warning_msg(_("No slots in changer to scan.\n"));
528 slot_list = (char *)malloc(max_slots+1);
529 if (!get_user_slot_list(ua, slot_list, max_slots)) {
533 vol_list = get_vol_list_from_SD(ua, false /*no scan*/);
536 ua->warning_msg(_("No Volumes found to label, or no barcodes.\n"));
540 /* Display list of Volumes and ask if he really wants to proceed */
541 ua->send_msg(_("The following Volumes will be labeled:\n"
543 "==============\n"));
544 for (vl=vol_list; vl; vl=vl->next) {
545 if (!vl->VolName || !slot_list[vl->Slot]) {
548 ua->send_msg("%4d %s\n", vl->Slot, vl->VolName);
550 if (!get_yesno(ua, _("Do you want to label these Volumes? (yes|no): ")) ||
551 (ua->pint32_val == 0)) {
555 memset(&pr, 0, sizeof(pr));
556 if (!select_pool_dbr(ua, &pr)) {
560 /* Fire off the label requests */
561 for (vl=vol_list; vl; vl=vl->next) {
562 if (!vl->VolName || !slot_list[vl->Slot]) {
566 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
567 media_record_exists = false;
568 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
569 if (mr.VolBytes != 0) {
570 ua->warning_msg(_("Media record for Slot %d Volume \"%s\" already exists.\n"),
571 vl->Slot, mr.VolumeName);
573 mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
574 set_storageid_in_mr(store, &mr);
575 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
576 ua->error_msg(_("Error setting InChanger: ERR=%s"), db_strerror(ua->db));
580 media_record_exists = true;
582 mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
583 set_storageid_in_mr(store, &mr);
585 * Deal with creating cleaning tape here. Normal tapes created in
586 * send_label_request() below
588 if (is_cleaning_tape(ua, &mr, &pr)) {
589 if (media_record_exists) { /* we update it */
590 mr.VolBytes = 1; /* any bytes to indicate it exists */
591 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
593 set_storageid_in_mr(store, &mr);
594 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
595 ua->error_msg("%s", db_strerror(ua->db));
597 } else { /* create the media record */
598 if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
599 ua->error_msg(_("Maximum pool Volumes=%d reached.\n"), pr.MaxVols);
602 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
603 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
605 set_storageid_in_mr(store, &mr);
606 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
607 ua->send_msg(_("Catalog record for cleaning tape \"%s\" successfully created.\n"),
609 pr.NumVols++; /* this is a bit suspect */
610 if (!db_update_pool_record(ua->jcr, ua->db, &pr)) {
611 ua->error_msg("%s", db_strerror(ua->db));
614 ua->error_msg(_("Catalog error on cleaning tape: %s"), db_strerror(ua->db));
617 continue; /* done, go handle next volume */
619 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
622 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists, drive);
628 free_vol_list(vol_list);
635 * Check if the Volume name has legal characters
636 * If ua is non-NULL send the message
638 bool is_volume_name_legal(UAContext *ua, const char *name)
642 const char *accept = ":.-_";
644 /* Restrict the characters permitted in the Volume name */
645 for (p=name; *p; p++) {
646 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
650 ua->error_msg(_("Illegal character \"%c\" in a volume name.\n"), *p);
655 if (len >= MAX_NAME_LENGTH) {
657 ua->error_msg(_("Volume name too long.\n"));
663 ua->error_msg(_("Volume name must be at least one character long.\n"));
671 * NOTE! This routine opens the SD socket but leaves it open
673 static bool send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
674 POOL_DBR *pr, int relabel, bool media_record_exists,
678 char dev_name[MAX_NAME_LENGTH];
681 uint64_t VolBytes = 0;
683 if (!(sd=open_sd_bsock(ua))) {
686 bstrncpy(dev_name, ua->jcr->wstore->dev_name(), sizeof(dev_name));
687 bash_spaces(dev_name);
688 bash_spaces(mr->VolumeName);
689 bash_spaces(mr->MediaType);
690 bash_spaces(pr->Name);
692 bash_spaces(omr->VolumeName);
693 sd->fsend("relabel %s OldName=%s NewName=%s PoolName=%s "
694 "MediaType=%s Slot=%d drive=%d",
695 dev_name, omr->VolumeName, mr->VolumeName, pr->Name,
696 mr->MediaType, mr->Slot, drive);
697 ua->send_msg(_("Sending relabel command from \"%s\" to \"%s\" ...\n"),
698 omr->VolumeName, mr->VolumeName);
700 sd->fsend("label %s VolumeName=%s PoolName=%s MediaType=%s "
702 dev_name, mr->VolumeName, pr->Name, mr->MediaType,
704 ua->send_msg(_("Sending label command for Volume \"%s\" Slot %d ...\n"),
705 mr->VolumeName, mr->Slot);
706 Dmsg6(100, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d drive=%d\n",
707 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive);
710 while (sd->recv() >= 0) {
712 ua->send_msg("%s", sd->msg);
713 if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu DVD=%d ", &VolBytes,
719 unbash_spaces(mr->VolumeName);
720 unbash_spaces(mr->MediaType);
721 unbash_spaces(pr->Name);
722 mr->LabelDate = time(NULL);
723 mr->set_label_date = true;
725 /* We know that a freshly labelled DVD has 1 VolParts */
726 /* This does not apply to auto-labelled DVDs. */
730 if (media_record_exists) { /* we update it */
731 mr->VolBytes = VolBytes;
732 mr->InChanger = mr->Slot > 0; /* if slot give assume in changer */
733 set_storageid_in_mr(ua->jcr->wstore, mr);
734 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
735 ua->error_msg("%s", db_strerror(ua->db));
738 } else { /* create the media record */
739 set_pool_dbr_defaults_in_media_dbr(mr, pr);
740 mr->VolBytes = VolBytes;
741 mr->InChanger = mr->Slot > 0; /* if slot give assume in changer */
743 set_storageid_in_mr(ua->jcr->wstore, mr);
744 if (db_create_media_record(ua->jcr, ua->db, mr)) {
745 ua->info_msg(_("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
746 mr->VolumeName, mr->Slot);
747 /* Update number of volumes in pool */
749 if (!db_update_pool_record(ua->jcr, ua->db, pr)) {
750 ua->error_msg("%s", db_strerror(ua->db));
753 ua->error_msg("%s", db_strerror(ua->db));
758 ua->error_msg(_("Label command failed for Volume %s.\n"), mr->VolumeName);
763 static BSOCK *open_sd_bsock(UAContext *ua)
765 STORE *store = ua->jcr->wstore;
767 if (!ua->jcr->store_bsock) {
768 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d ...\n"),
769 store->name(), store->address, store->SDport);
770 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
771 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
775 return ua->jcr->store_bsock;
778 static void close_sd_bsock(UAContext *ua)
780 if (ua->jcr->store_bsock) {
781 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
782 bnet_close(ua->jcr->store_bsock);
783 ua->jcr->store_bsock = NULL;
787 static char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive)
789 STORE *store = ua->jcr->wstore;
791 char dev_name[MAX_NAME_LENGTH];
792 char *VolName = NULL;
795 if (!(sd=open_sd_bsock(ua))) {
796 ua->error_msg(_("Could not open SD socket.\n"));
799 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
800 bash_spaces(dev_name);
801 /* Ask for autochanger list of volumes */
802 sd->fsend(NT_("readlabel %s Slot=%d drive=%d\n"), dev_name, Slot, drive);
803 Dmsg1(100, "Sent: %s", sd->msg);
805 /* Get Volume name in this Slot */
806 while (sd->recv() >= 0) {
807 ua->send_msg("%s", sd->msg);
808 Dmsg1(100, "Got: %s", sd->msg);
809 if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) {
810 VolName = (char *)malloc(sd->msglen);
811 if (sscanf(sd->msg, NT_("3001 Volume=%s Slot=%d"), VolName, &rtn_slot) == 2) {
819 Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName));
824 * We get the slot list from the Storage daemon.
825 * If scan is set, we return all slots found,
826 * otherwise, we return only slots with valid barcodes (Volume names)
828 static vol_list_t *get_vol_list_from_SD(UAContext *ua, bool scan)
830 STORE *store = ua->jcr->wstore;
831 char dev_name[MAX_NAME_LENGTH];
834 vol_list_t *vol_list = NULL;
837 if (!(sd=open_sd_bsock(ua))) {
841 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
842 bash_spaces(dev_name);
843 /* Ask for autochanger list of volumes */
844 bnet_fsend(sd, NT_("autochanger list %s \n"), dev_name);
846 /* Read and organize list of Volumes */
847 while (bnet_recv(sd) >= 0) {
850 strip_trailing_junk(sd->msg);
852 /* Check for returned SD messages */
853 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
854 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
856 ua->send_msg("%s\n", sd->msg); /* pass them on to user */
860 /* Validate Slot: if scanning, otherwise Slot:Barcode */
861 p = strchr(sd->msg, ':');
863 /* Scanning -- require only valid slot */
864 Slot = atoi(sd->msg);
868 ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg);
873 if (p && strlen(p) > 1) {
875 if (!is_an_integer(sd->msg) || (Slot=atoi(sd->msg)) <= 0) {
878 ua->error_msg(_("Invalid Slot number: %s\n"), sd->msg);
884 if (!is_volume_name_legal(ua, p)) {
887 ua->error_msg(_("Invalid Volume name: %s\n"), sd->msg);
892 /* Add Slot and VolumeName to list */
893 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
897 p++; /* skip separator */
899 vl->VolName = bstrdup(p);
903 Dmsg2(100, "Add slot=%d Vol=%s to SD list.\n", vl->Slot, NPRT(vl->VolName));
908 vol_list_t *prev=vol_list;
909 /* Add new entry to the right place in the list */
910 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
911 if (tvl->Slot > vl->Slot) {
912 /* no previous item, update vol_list directly */
913 if (prev == vol_list) {
917 } else { /* replace the previous pointer */
923 /* we are at the end */
937 static void free_vol_list(vol_list_t *vol_list)
942 for (vl=vol_list; vl; ) {
954 * We get the number of slots in the changer from the SD
956 static int get_num_slots_from_SD(UAContext *ua)
958 STORE *store = ua->jcr->wstore;
959 char dev_name[MAX_NAME_LENGTH];
964 if (!(sd=open_sd_bsock(ua))) {
968 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
969 bash_spaces(dev_name);
970 /* Ask for autochanger number of slots */
971 sd->fsend(NT_("autochanger slots %s\n"), dev_name);
973 while (sd->recv() >= 0) {
974 if (sscanf(sd->msg, "slots=%d\n", &slots) == 1) {
977 ua->send_msg("%s", sd->msg);
981 ua->send_msg(_("Device \"%s\" has %d slots.\n"), store->dev_name(), slots);
986 * We get the number of drives in the changer from the SD
988 int get_num_drives_from_SD(UAContext *ua)
990 STORE *store = ua->jcr->wstore;
991 char dev_name[MAX_NAME_LENGTH];
996 if (!(sd=open_sd_bsock(ua))) {
1000 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
1001 bash_spaces(dev_name);
1002 /* Ask for autochanger number of slots */
1003 sd->fsend(NT_("autochanger drives %s\n"), dev_name);
1005 while (sd->recv() >= 0) {
1006 if (sscanf(sd->msg, NT_("drives=%d\n"), &drives) == 1) {
1009 ua->send_msg("%s", sd->msg);
1013 // bsendmsg(ua, _("Device \"%s\" has %d drives.\n"), store->dev_name(), drives);
1018 * Check if this is a cleaning tape by comparing the Volume name
1019 * with the Cleaning Prefix. If they match, this is a cleaning
1022 static bool is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
1024 /* Find Pool resource */
1025 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
1026 if (!ua->jcr->pool) {
1027 ua->error_msg(_("Pool \"%s\" resource not found for volume \"%s\"!\n"),
1028 pr->Name, mr->VolumeName);
1031 if (ua->jcr->pool->cleaning_prefix == NULL) {
1034 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
1035 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
1036 strlen(ua->jcr->pool->cleaning_prefix),
1037 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1038 strlen(ua->jcr->pool->cleaning_prefix)));
1039 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
1040 strlen(ua->jcr->pool->cleaning_prefix)) == 0;
1043 static void content_send_info(UAContext *ua, char type, int Slot, char *vol_name)
1045 char ed1[50], ed2[50], ed3[50];
1048 /* Type|Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire */
1049 const char *slot_api_full_format="%c|%i|%i|%s|%s|%s|%s|%s|%s|%s\n";
1050 const char *slot_api_empty_format="%c|%i||||||||\n";
1052 if (is_volume_name_legal(NULL, vol_name)) {
1053 bstrncpy(mr.VolumeName, vol_name, sizeof(mr.VolumeName));
1054 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
1055 memset(&pr, 0, sizeof(POOL_DBR));
1056 pr.PoolId = mr.PoolId;
1057 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1058 strcpy(pr.Name, "?");
1060 ua->send_msg(slot_api_full_format, type,
1061 Slot, mr.Slot, mr.VolumeName,
1062 edit_uint64(mr.VolBytes, ed1),
1063 mr.VolStatus, mr.MediaType, pr.Name,
1064 edit_uint64(mr.LastWritten, ed2),
1065 edit_uint64(mr.LastWritten+mr.VolRetention, ed3));
1067 } else { /* Media unknown */
1068 ua->send_msg(slot_api_full_format,
1069 type, Slot, 0, mr.VolumeName, "?", "?", "?", "?",
1074 ua->send_msg(slot_api_empty_format, type, Slot);
1079 * Input (output of mxt-changer listall):
1081 * Drive content: D:Drive num:F:Slot loaded:Volume Name
1082 * D:0:F:2:vol2 or D:Drive num:E
1087 * S:1:F:vol1 S:Slot num:F:Volume Name
1088 * S:2:E or S:Slot num:E
1091 * Import/Export tray slots:
1092 * I:10:F:vol10 I:Slot num:F:Volume Name
1093 * I:11:E or I:Slot num:E
1096 * If a drive is loaded, the slot *should* be empty
1100 * Drive list: D|Drive num|Slot loaded|Volume Name
1105 * Slot list: Type|Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire
1107 * S|1|1|vol1|31417344|Full|LTO1-ANSI|Inc|1250858902|1282394902
1109 * S|3|3|vol4|15869952|Append|LTO1-ANSI|Inc|1250858907|1282394907
1111 * TODO: need to merge with status_slots()
1113 void status_content(UAContext *ua, STORE *store)
1117 char dev_name[MAX_NAME_LENGTH];
1118 char vol_name[MAX_NAME_LENGTH];
1120 vol_list_t *vl=NULL, *vol_list = NULL;
1122 if (!(sd=open_sd_bsock(ua))) {
1126 if (!open_client_db(ua)) {
1130 bstrncpy(dev_name, store->dev_name(), sizeof(dev_name));
1131 bash_spaces(dev_name);
1132 /* Ask for autochanger list of volumes */
1133 bnet_fsend(sd, NT_("autochanger listall %s \n"), dev_name);
1135 /* Read and organize list of Drive, Slots and I/O Slots */
1136 while (bnet_recv(sd) >= 0) {
1137 strip_trailing_junk(sd->msg);
1139 /* Check for returned SD messages */
1140 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
1141 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
1142 sd->msg[4] == ' ') {
1143 ua->send_msg("%s\n", sd->msg); /* pass them on to user */
1150 if (sscanf(sd->msg, "D:%d:F:%d:%127s", &Drive, &Slot, vol_name) == 3) {
1151 ua->send_msg("D|%d|%d|%s\n", Drive, Slot, vol_name);
1153 /* we print information on the slot if we have a volume name */
1155 /* Add Slot and VolumeName to list */
1156 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
1158 vl->VolName = bstrdup(vol_name);
1159 vl->next = vol_list;
1163 } else if (sscanf(sd->msg, "D:%d:E", &Drive) == 1) {
1164 ua->send_msg("D|%d||\n", Drive);
1166 } else if (sscanf(sd->msg, "%c:%d:F:%127s", &type, &Slot, vol_name)== 3) {
1167 content_send_info(ua, type, Slot, vol_name);
1169 } else if (sscanf(sd->msg, "%c:%d:E", &type, &Slot) == 2) {
1170 /* type can be S (slot) or I (Import/Export slot) */
1171 vol_list_t *prev=NULL;
1172 for (vl = vol_list; vl; vl = vl->next) {
1173 if (vl->Slot == Slot) {
1174 bstrncpy(vol_name, vl->VolName, MAX_NAME_LENGTH);
1176 /* remove the node */
1178 prev->next = vl->next;
1180 vol_list = vl->next;
1188 content_send_info(ua, type, Slot, vol_name);
1191 Dmsg1(10, "Discarding msg=%s\n", sd->msg);
1198 * Print slots from AutoChanger
1200 void status_slots(UAContext *ua, STORE *store_r)
1204 vol_list_t *vl, *vol_list = NULL;
1209 /* Slot | Volume | Status | MediaType | Pool */
1210 const char *slot_hformat=" %4i%c| %16s | %9s | %20s | %18s |\n";
1213 status_content(ua, store_r);
1217 if (!open_client_db(ua)) {
1220 store.store = store_r;
1222 pm_strcpy(store.store_source, _("command line"));
1223 set_wstorage(ua->jcr, &store);
1224 get_storage_drive(ua, store.store);
1226 max_slots = get_num_slots_from_SD(ua);
1228 if (max_slots <= 0) {
1229 ua->warning_msg(_("No slots in changer to scan.\n"));
1232 slot_list = (char *)malloc(max_slots+1);
1233 if (!get_user_slot_list(ua, slot_list, max_slots)) {
1238 vol_list = get_vol_list_from_SD(ua, true /* want to see all slots */);
1241 ua->warning_msg(_("No Volumes found, or no barcodes.\n"));
1244 ua->send_msg(_(" Slot | Volume Name | Status | Media Type | Pool |\n"));
1245 ua->send_msg(_("------+------------------+-----------+----------------------+--------------------|\n"));
1247 /* Walk through the list getting the media records */
1248 for (vl=vol_list; vl; vl=vl->next) {
1249 if (vl->Slot > max_slots) {
1250 ua->warning_msg(_("Slot %d greater than max %d ignored.\n"),
1251 vl->Slot, max_slots);
1254 /* Check if user wants us to look at this slot */
1255 if (!slot_list[vl->Slot]) {
1256 Dmsg1(100, "Skipping slot=%d\n", vl->Slot);
1260 slot_list[vl->Slot] = 0; /* clear Slot */
1263 Dmsg1(100, "No VolName for Slot=%d.\n", vl->Slot);
1264 ua->send_msg(slot_hformat,
1266 "?", "?", "?", "?");
1270 /* Hope that slots are ordered */
1271 for (; i < vl->Slot; i++) {
1273 ua->send_msg(slot_hformat,
1274 i, ' ', "", "", "", "");
1279 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
1281 if (mr.VolumeName[0] && db_get_media_record(ua->jcr, ua->db, &mr)) {
1282 memset(&pr, 0, sizeof(POOL_DBR));
1283 pr.PoolId = mr.PoolId;
1284 if (!db_get_pool_record(ua->jcr, ua->db, &pr)) {
1285 strcpy(pr.Name, "?");
1289 /* Print information */
1290 ua->send_msg(slot_hformat,
1291 vl->Slot, ((vl->Slot==mr.Slot)?' ':'*'),
1292 mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name);
1294 } else { /* TODO: get information from catalog */
1295 ua->send_msg(slot_hformat,
1297 mr.VolumeName, "?", "?", "?");
1302 /* Display the rest of the autochanger
1304 for (; i <= max_slots; i++) {
1306 ua->send_msg(slot_hformat,
1307 i, ' ', "", "", "", "");
1314 free_vol_list(vol_list);