3 * Bacula Director -- Tape labeling commands
5 * Kern Sibbald, April MMIII
11 Copyright (C) 2000-2003 Kern Sibbald and John Walker
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of
16 the License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public
24 License along with this program; if not, write to the Free
25 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
33 /* Slot list definition */
34 typedef struct s_vol_list {
35 struct s_vol_list *next;
41 /* Forward referenced functions */
42 static int do_label(UAContext *ua, char *cmd, int relabel);
43 static void label_from_barcodes(UAContext *ua);
44 static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
45 POOL_DBR *pr, int relabel, bool media_record_exits);
46 static vol_list_t *get_slot_list_from_SD(UAContext *ua);
47 static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
53 * label storage=xxx volume=vvv
55 int label_cmd(UAContext *ua, char *cmd)
57 return do_label(ua, cmd, 0); /* standard label */
60 int relabel_cmd(UAContext *ua, char *cmd)
62 return do_label(ua, cmd, 1); /* relabel tape */
67 * Update Slots corresponding to Volumes in autochanger
69 int update_slots(UAContext *ua)
72 vol_list_t *vl, *vol_list = NULL;
78 store = get_storage_resource(ua, 1);
82 ua->jcr->store = store;
84 vol_list = get_slot_list_from_SD(ua);
88 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
92 /* Walk through the list updating the media records */
93 for (vl=vol_list; vl; vl=vl->next) {
95 memset(&mr, 0, sizeof(mr));
96 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
98 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
99 if (mr.Slot != vl->Slot) {
101 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
102 bsendmsg(ua, _("%s\n"), db_strerror(ua->db));
105 "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
106 mr.VolumeName, mr.Slot);
109 bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
115 bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"),
124 for (vl=vol_list; vl; ) {
132 if (ua->jcr->store_bsock) {
133 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
134 bnet_close(ua->jcr->store_bsock);
135 ua->jcr->store_bsock = NULL;
141 * Common routine for both label and relabel
143 static int do_label(UAContext *ua, char *cmd, int relabel)
147 sd = ua->jcr->store_bsock;
148 char dev_name[MAX_NAME_LENGTH];
151 bool print_reminder = true;
154 bool media_record_exists = false;
155 static char *barcode_keyword[] = {
161 memset(&pr, 0, sizeof(pr));
165 store = get_storage_resource(ua, 1);
169 ua->jcr->store = store;
171 if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
172 label_from_barcodes(ua);
176 /* If relabel get name of Volume to relabel */
178 /* Check for oldvolume=name */
179 i = find_arg_with_value(ua, "oldvolume");
181 memset(&omr, 0, sizeof(omr));
182 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
183 if (db_get_media_record(ua->jcr, ua->db, &omr)) {
186 bsendmsg(ua, "%s", db_strerror(ua->db));
188 /* No keyword or Vol not found, ask user to select */
189 if (!select_media_dbr(ua, &omr)) {
193 /* Require Volume to be Purged */
195 if (strcmp(omr.VolStatus, "Purged") != 0) {
196 bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be purged before relabeling.\n"),
197 omr.VolumeName, omr.VolStatus);
202 /* Check for volume=NewVolume */
203 i = find_arg_with_value(ua, "volume");
205 pm_strcpy(&ua->cmd, ua->argv[i]);
209 /* Get a new Volume name */
211 media_record_exists = false;
212 if (!get_cmd(ua, _("Enter new Volume name: "))) {
216 if (!is_volume_name_legal(ua, ua->cmd)) {
220 memset(&mr, 0, sizeof(mr));
221 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
222 /* If VolBytes are zero the Volume is not labeled */
223 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
224 if (mr.VolBytes != 0) {
225 bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"),
229 media_record_exists = true;
234 /* If autochanger, request slot */
235 if (store->autochanger) {
236 i = find_arg_with_value(ua, "slot");
238 mr.Slot = atoi(ua->argv[i]);
239 } else if (!get_pint(ua, _("Enter slot (0 for none): "))) {
242 mr.Slot = ua->pint32_val;
246 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
248 /* Must select Pool if not already done */
249 if (pr.PoolId == 0) {
250 memset(&pr, 0, sizeof(pr));
251 if (!select_pool_dbr(ua, &pr)) {
256 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
257 store->hdr.name, store->address, store->SDport);
258 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
259 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
262 sd = ua->jcr->store_bsock;
264 ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists);
268 if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
269 bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
270 omr.VolumeName, db_strerror(ua->db));
272 bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"),
277 bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
278 bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
279 bash_spaces(dev_name);
280 bnet_fsend(sd, "mount %s", dev_name);
281 unbash_spaces(dev_name);
282 while (bnet_recv(sd) >= 0) {
283 bsendmsg(ua, "%s", sd->msg);
285 * 3001 OK mount. Device=xxx or
286 * 3001 Mounted Volume vvvv
287 * 3906 is cannot mount non-tape
288 * So for those, no need to print a reminder
290 if (strncmp(sd->msg, "3001 ", 5) == 0 ||
291 strncmp(sd->msg, "3906 ", 5) == 0) {
292 print_reminder = false;
297 if (print_reminder) {
298 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
300 bnet_sig(sd, BNET_TERMINATE);
302 ua->jcr->store_bsock = NULL;
308 * Request SD to send us the slot:barcodes, then wiffle
309 * through them all labeling them.
311 static void label_from_barcodes(UAContext *ua)
313 STORE *store = ua->jcr->store;
316 vol_list_t *vl, *vol_list = NULL;
317 bool media_record_exists;
319 vol_list = get_slot_list_from_SD(ua);
322 bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
326 /* Display list of Volumes and ask if he really wants to proceed */
327 bsendmsg(ua, _("The following Volumes will be labeled:\n"
329 "==============\n"));
330 for (vl=vol_list; vl; vl=vl->next) {
331 bsendmsg(ua, "%4d %s\n", vl->Slot, vl->VolName);
333 if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
334 (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
338 memset(&pr, 0, sizeof(pr));
339 if (!select_pool_dbr(ua, &pr)) {
342 memset(&omr, 0, sizeof(omr));
344 /* Fire off the label requests */
345 for (vl=vol_list; vl; vl=vl->next) {
347 memset(&mr, 0, sizeof(mr));
348 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
349 media_record_exists = false;
350 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
351 if (mr.VolBytes != 0) {
352 bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"),
353 vl->Slot, mr.VolumeName);
356 media_record_exists = true;
359 * Deal with creating cleaning tape here. Normal tapes created in
360 * send_label_request() below
362 if (is_cleaning_tape(ua, &mr, &pr)) {
363 if (media_record_exists) { /* we update it */
365 if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
366 bsendmsg(ua, "%s", db_strerror(ua->db));
368 } else { /* create the media record */
369 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
370 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
371 bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
374 bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
377 continue; /* done, go handle next volume */
379 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
380 if (ua->jcr->store_bsock) {
381 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
382 bnet_close(ua->jcr->store_bsock);
383 ua->jcr->store_bsock = NULL;
385 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
386 store->hdr.name, store->address, store->SDport);
387 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
388 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
393 send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists);
399 for (vl=vol_list; vl; ) {
407 if (ua->jcr->store_bsock) {
408 bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
409 bnet_close(ua->jcr->store_bsock);
410 ua->jcr->store_bsock = NULL;
417 * Check if the Volume name has legal characters
418 * If ua is non-NULL send the message
420 int is_volume_name_legal(UAContext *ua, char *name)
424 char *accept = ":.-_";
426 /* Restrict the characters permitted in the Volume name */
427 for (p=name; *p; p++) {
428 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
432 bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
437 if (len >= MAX_NAME_LENGTH) {
439 bsendmsg(ua, _("Volume name too long.\n"));
445 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
452 static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr,
453 POOL_DBR *pr, int relabel, bool media_record_exists)
456 char dev_name[MAX_NAME_LENGTH];
459 sd = ua->jcr->store_bsock;
460 bstrncpy(dev_name, ua->jcr->store->dev_name, sizeof(dev_name));
461 bash_spaces(dev_name);
462 bash_spaces(mr->VolumeName);
463 bash_spaces(mr->MediaType);
464 bash_spaces(pr->Name);
466 bash_spaces(omr->VolumeName);
467 bnet_fsend(sd, "relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d",
468 dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
469 bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
470 omr->VolumeName, mr->VolumeName);
472 bnet_fsend(sd, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d",
473 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
474 bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"),
475 mr->VolumeName, mr->Slot);
476 Dmsg5(200, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d\n",
477 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
480 while (bnet_recv(sd) >= 0) {
481 bsendmsg(ua, "%s", sd->msg);
482 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
486 unbash_spaces(mr->VolumeName);
487 unbash_spaces(mr->MediaType);
488 unbash_spaces(pr->Name);
489 mr->LabelDate = time(NULL);
491 if (media_record_exists) { /* we update it */
493 if (!db_update_media_record(ua->jcr, ua->db, mr)) {
494 bsendmsg(ua, "%s", db_strerror(ua->db));
497 } else { /* create the media record */
498 set_pool_dbr_defaults_in_media_dbr(mr, pr);
499 mr->VolBytes = 1; /* flag indicating Volume labeled */
500 if (db_create_media_record(ua->jcr, ua->db, mr)) {
501 bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d successfully created.\n"),
502 mr->VolumeName, mr->Slot);
504 bsendmsg(ua, "%s", db_strerror(ua->db));
509 bsendmsg(ua, _("Label command failed.\n"));
514 static vol_list_t *get_slot_list_from_SD(UAContext *ua)
516 STORE *store = ua->jcr->store;
517 char dev_name[MAX_NAME_LENGTH];
520 vol_list_t *vol_list = NULL;
523 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
524 store->hdr.name, store->address, store->SDport);
525 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
526 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
529 sd = ua->jcr->store_bsock;
531 bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
532 bash_spaces(dev_name);
533 /* Ask for autochanger list of volumes */
534 bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
536 /* Read and organize list of Volumes */
537 while (bnet_recv(sd) >= 0) {
540 strip_trailing_junk(sd->msg);
542 /* Check for returned SD messages */
543 if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) &&
544 B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
546 bsendmsg(ua, "%s\n", sd->msg); /* pass them on to user */
550 /* Validate Slot:Barcode */
551 p = strchr(sd->msg, ':');
552 if (p && strlen(p) > 1) {
554 if (!is_an_integer(sd->msg)) {
560 Slot = atoi(sd->msg);
561 if (Slot <= 0 || !is_volume_name_legal(ua, p)) {
565 /* Add Slot and VolumeName to list */
566 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
568 vl->VolName = bstrdup(p);
573 /* Add new entry to end of list */
574 for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
587 * Check if this is a cleaning tape by comparing the Volume name
588 * with the Cleaning Prefix. If they match, this is a cleaning
591 static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
593 if (!ua->jcr->pool) {
594 /* Find Pool resource */
595 ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
596 if (!ua->jcr->pool) {
597 bsendmsg(ua, _("Pool %s resource not found!\n"), pr->Name);
601 if (ua->jcr->pool->cleaning_prefix == NULL) {
604 Dmsg4(200, "CLNprefix=%s: Vol=%s: len=%d strncmp=%d\n",
605 ua->jcr->pool->cleaning_prefix, mr->VolumeName,
606 strlen(ua->jcr->pool->cleaning_prefix),
607 strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
608 strlen(ua->jcr->pool->cleaning_prefix)));
609 return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
610 strlen(ua->jcr->pool->cleaning_prefix)) == 0;