]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
This commit was manufactured by cvs2svn to create tag
[bacula/bacula] / bacula / src / dird / ua_label.c
1 /*
2  *
3  *   Bacula Director -- Tape labeling commands
4  *
5  *     Kern Sibbald, April MMIII
6  *
7  *   Version $Id$
8  */
9
10 /*
11    Copyright (C) 2000-2003 Kern Sibbald and John Walker
12
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.
17
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.
22
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,
26    MA 02111-1307, USA.
27
28  */
29
30 #include "bacula.h"
31 #include "dird.h"
32
33 /* Slot list definition */
34 typedef struct s_vol_list {
35    struct s_vol_list *next;
36    char *VolName;
37    int Slot;
38 } vol_list_t;
39
40
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);
48
49
50 /*
51  * Label a tape 
52  *  
53  *   label storage=xxx volume=vvv
54  */
55 int label_cmd(UAContext *ua, char *cmd)
56 {
57    return do_label(ua, cmd, 0);       /* standard label */
58 }
59
60 int relabel_cmd(UAContext *ua, char *cmd)
61 {
62    return do_label(ua, cmd, 1);      /* relabel tape */
63 }
64
65
66 /*
67  * Update Slots corresponding to Volumes in autochanger 
68  */
69 int update_slots(UAContext *ua)
70 {
71    STORE *store;
72    vol_list_t *vl, *vol_list = NULL;
73    MEDIA_DBR mr;
74
75    if (!open_db(ua)) {
76       return 1;
77    }
78    store = get_storage_resource(ua, 1);
79    if (!store) {
80       return 1;
81    }
82    ua->jcr->store = store;
83
84    vol_list = get_slot_list_from_SD(ua);
85
86
87    if (!vol_list) {
88       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
89       goto bail_out;
90    }
91
92    /* Walk through the list updating the media records */
93    for (vl=vol_list; vl; vl=vl->next) {
94
95       memset(&mr, 0, sizeof(mr));
96       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
97       db_lock(ua->db);
98       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
99           if (mr.Slot != vl->Slot) {
100              mr.Slot = vl->Slot;
101              if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
102                 bsendmsg(ua, _("%s\n"), db_strerror(ua->db));
103              } else {
104                 bsendmsg(ua, _(
105                   "Catalog record for Volume \"%s\" updated to reference slot %d.\n"),
106                   mr.VolumeName, mr.Slot);
107              }
108           } else {
109              bsendmsg(ua, _("Catalog record for Volume \"%s\" is up to date.\n"),
110                 mr.VolumeName);
111           }   
112           db_unlock(ua->db);
113           continue;
114       } else {
115           bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"), 
116              mr.VolumeName);
117       }
118       db_unlock(ua->db);
119    }
120
121
122 bail_out:
123    /* Free list */
124    for (vl=vol_list; vl; ) {
125       vol_list_t *ovl;
126       free(vl->VolName);
127       ovl = vl;
128       vl = vl->next;
129       free(ovl);
130    }
131
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;
136    }
137    return 1;
138 }
139
140 /*
141  * Common routine for both label and relabel
142  */
143 static int do_label(UAContext *ua, char *cmd, int relabel)
144 {
145    STORE *store;
146    BSOCK *sd;
147    sd = ua->jcr->store_bsock;
148    char dev_name[MAX_NAME_LENGTH];
149    MEDIA_DBR mr, omr;
150    POOL_DBR pr;
151    bool print_reminder = true;
152    int ok = FALSE;
153    int i;
154    bool media_record_exists = false;
155    static char *barcode_keyword[] = {
156       "barcode",
157       "barcodes",
158       NULL};
159
160
161    memset(&pr, 0, sizeof(pr));
162    if (!open_db(ua)) {
163       return 1;
164    }
165    store = get_storage_resource(ua, 1);
166    if (!store) {
167       return 1;
168    }
169    ua->jcr->store = store;
170
171    if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
172       label_from_barcodes(ua);
173       return 1;
174    }
175
176    /* If relabel get name of Volume to relabel */
177    if (relabel) {
178       /* Check for oldvolume=name */
179       i = find_arg_with_value(ua, "oldvolume"); 
180       if (i >= 0) {
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)) {
184             goto checkVol;
185          } 
186          bsendmsg(ua, "%s", db_strerror(ua->db));
187       }
188       /* No keyword or Vol not found, ask user to select */
189       if (!select_media_dbr(ua, &omr)) {
190          return 1;
191       }
192
193       /* Require Volume to be Purged */
194 checkVol:
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);
198          return 1;
199       }
200    }
201
202    /* Check for volume=NewVolume */
203    i = find_arg_with_value(ua, "volume");
204    if (i >= 0) {
205       pm_strcpy(&ua->cmd, ua->argv[i]);
206       goto checkName;
207    }
208
209    /* Get a new Volume name */
210    for ( ;; ) {
211       media_record_exists = false;
212       if (!get_cmd(ua, _("Enter new Volume name: "))) {
213          return 1;
214       }
215 checkName:
216       if (!is_volume_name_legal(ua, ua->cmd)) {
217          continue;
218       }
219
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"), 
226                 mr.VolumeName);
227              continue;
228           }
229           media_record_exists = true;
230       }
231       break;                          /* Got it */
232    }
233
234    /* If autochanger, request slot */
235    if (store->autochanger) {
236       i = find_arg_with_value(ua, "slot"); 
237       if (i >= 0) {
238          mr.Slot = atoi(ua->argv[i]);
239       } else if (!get_pint(ua, _("Enter slot (0 for none): "))) {
240          return 1;
241       } else {
242          mr.Slot = ua->pint32_val;
243       }
244    }
245
246    bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
247
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)) {
252          return 1;
253       }
254    }
255
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"));
260       return 1;   
261    }
262    sd = ua->jcr->store_bsock;
263
264    ok = send_label_request(ua, &mr, &omr, &pr, relabel, media_record_exists);
265
266    if (ok) {
267       if (relabel) {
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));
271          } else {
272             bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"), 
273                omr.VolumeName);
274          }
275       }
276       if (ua->automount) {
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);
284             /* Here we can get
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
289              */
290             if (strncmp(sd->msg, "3001 ", 5) == 0 ||
291                 strncmp(sd->msg, "3906 ", 5) == 0) {
292                print_reminder = false;
293          }
294       }
295    }
296    }
297    if (!print_reminder) {
298       bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
299    }
300    bnet_sig(sd, BNET_TERMINATE);
301    bnet_close(sd);
302    ua->jcr->store_bsock = NULL;
303
304    return 1;
305 }
306
307 /*
308  * Request SD to send us the slot:barcodes, then wiffle
309  *  through them all labeling them.
310  */
311 static void label_from_barcodes(UAContext *ua)
312 {
313    STORE *store = ua->jcr->store;
314    POOL_DBR pr;
315    MEDIA_DBR mr, omr;
316    vol_list_t *vl, *vol_list = NULL;
317    bool media_record_exists;
318
319    vol_list = get_slot_list_from_SD(ua);
320
321    if (!vol_list) {
322       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
323       goto bail_out;
324    }
325
326    /* Display list of Volumes and ask if he really wants to proceed */
327    bsendmsg(ua, _("The following Volumes will be labeled:\n"
328                   "Slot  Volume\n"
329                   "==============\n"));
330    for (vl=vol_list; vl; vl=vl->next) {
331       bsendmsg(ua, "%4d  %s\n", vl->Slot, vl->VolName);
332    }
333    if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
334        (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
335       goto bail_out;
336    }
337    /* Select a pool */
338    memset(&pr, 0, sizeof(pr));
339    if (!select_pool_dbr(ua, &pr)) {
340       goto bail_out;
341    }
342    memset(&omr, 0, sizeof(omr));
343
344    /* Fire off the label requests */
345    for (vl=vol_list; vl; vl=vl->next) {
346
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);
354              continue;
355           } 
356           media_record_exists = true;
357       }
358       /*
359        * Deal with creating cleaning tape here. Normal tapes created in
360        *  send_label_request() below
361        */
362       if (is_cleaning_tape(ua, &mr, &pr)) {
363          if (media_record_exists) {      /* we update it */
364             mr.VolBytes = 1;
365             if (!db_update_media_record(ua->jcr, ua->db, &mr)) {
366                 bsendmsg(ua, "%s", db_strerror(ua->db));
367             }
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"),
372                   mr.VolumeName);
373             } else {
374                bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
375             }
376          }
377          continue;                    /* done, go handle next volume */
378       }
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;
384       }
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"));
389          goto bail_out;
390       }
391
392       mr.Slot = vl->Slot;
393       send_label_request(ua, &mr, &omr, &pr, 0, media_record_exists);
394    }
395
396
397 bail_out:
398    /* Free list */
399    for (vl=vol_list; vl; ) {
400       vol_list_t *ovl;
401       free(vl->VolName);
402       ovl = vl;
403       vl = vl->next;
404       free(ovl);
405    }
406
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;
411    }
412
413    return;
414 }
415
416 /* 
417  * Check if the Volume name has legal characters
418  * If ua is non-NULL send the message
419  */
420 int is_volume_name_legal(UAContext *ua, char *name)
421 {
422    int len;
423    char *p;
424    char *accept = ":.-_";
425
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))) {
429          continue;
430       }
431       if (ua) {
432          bsendmsg(ua, _("Illegal character \"%c\" in a volume name.\n"), *p);
433       }
434       return 0;
435    }
436    len = strlen(name);
437    if (len >= MAX_NAME_LENGTH) {
438       if (ua) {
439          bsendmsg(ua, _("Volume name too long.\n"));
440       }
441       return 0;
442    }
443    if (len == 0) {
444       if (ua) {
445          bsendmsg(ua, _("Volume name must be at least one character long.\n"));
446       }
447       return 0;
448    }
449    return 1;
450 }
451
452 static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
453                               POOL_DBR *pr, int relabel, bool media_record_exists)
454 {
455    BSOCK *sd;
456    char dev_name[MAX_NAME_LENGTH];
457    int ok = FALSE;
458
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);
465    if (relabel) {
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);
471    } else {
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);
478    }
479
480    while (bnet_recv(sd) >= 0) {
481       bsendmsg(ua, "%s", sd->msg);
482       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
483          ok = TRUE;
484       } 
485    }
486    unbash_spaces(mr->VolumeName);
487    unbash_spaces(mr->MediaType);
488    unbash_spaces(pr->Name);
489    mr->LabelDate = time(NULL);
490    if (ok) {
491       if (media_record_exists) {      /* we update it */
492          mr->VolBytes = 1;
493          if (!db_update_media_record(ua->jcr, ua->db, mr)) {
494              bsendmsg(ua, "%s", db_strerror(ua->db));
495              ok = FALSE;
496          }
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);
503          } else {
504             bsendmsg(ua, "%s", db_strerror(ua->db));
505             ok = FALSE;
506          }
507       }
508    } else {
509       bsendmsg(ua, _("Label command failed.\n"));
510    }
511    return ok;
512 }
513
514 static vol_list_t *get_slot_list_from_SD(UAContext *ua)
515 {
516    STORE *store = ua->jcr->store;
517    char dev_name[MAX_NAME_LENGTH];
518    BSOCK *sd;
519    vol_list_t *vl;
520    vol_list_t *vol_list = NULL;
521
522
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"));
527       return NULL;
528    }
529    sd  = ua->jcr->store_bsock;
530
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);
535
536    /* Read and organize list of Volumes */
537    while (bnet_recv(sd) >= 0) {
538       char *p;
539       int Slot;
540       strip_trailing_junk(sd->msg);
541
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]) &&
545           sd->msg[4] == ' ') {
546          bsendmsg(ua, "%s\n", sd->msg);   /* pass them on to user */
547          continue;
548       }
549
550       /* Validate Slot:Barcode */
551       p = strchr(sd->msg, ':');
552       if (p && strlen(p) > 1) {
553          *p++ = 0;
554          if (!is_an_integer(sd->msg)) {
555             continue;
556          }
557       } else {
558          continue;
559       }
560       Slot = atoi(sd->msg);
561       if (Slot <= 0 || !is_volume_name_legal(ua, p)) {
562          continue;
563       }
564
565       /* Add Slot and VolumeName to list */
566       vl = (vol_list_t *)malloc(sizeof(vol_list_t));
567       vl->Slot = Slot;
568       vl->VolName = bstrdup(p);
569       if (!vol_list) {
570          vl->next = vol_list;
571          vol_list = vl;
572       } else {
573          /* Add new entry to end of list */
574          for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
575             if (!tvl->next) {
576                tvl->next = vl;
577                vl->next = NULL;
578                break;
579             }
580          }
581       }
582    }
583    return vol_list;
584 }
585
586 /*
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 
589  *  tape.
590  */
591 static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
592 {
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);
598          return 1;
599       }
600    }
601    if (ua->jcr->pool->cleaning_prefix == NULL) {
602       return 0;
603    }
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;
611 }