]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
Misc see kes-1.30a
[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 is_legal_volume_name(UAContext *ua, char *name);
45 static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
46                POOL_DBR *pr, int relabel);
47 static vol_list_t *get_slot_list_from_SD(UAContext *ua);
48 static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr);
49
50
51 /*
52  * Label a tape 
53  *  
54  *   label storage=xxx volume=vvv
55  */
56 int labelcmd(UAContext *ua, char *cmd)
57 {
58    return do_label(ua, cmd, 0);       /* standard label */
59 }
60
61 int relabelcmd(UAContext *ua, char *cmd)
62 {
63    return do_label(ua, cmd, 1);      /* relabel tape */
64 }
65
66
67 /*
68  * Update Slots corresponding to Volumes in autochanger 
69  */
70 int update_slots(UAContext *ua)
71 {
72    STORE *store;
73    vol_list_t *vl, *vol_list = NULL;
74    MEDIA_DBR mr;
75
76    if (!open_db(ua)) {
77       return 1;
78    }
79    store = get_storage_resource(ua, 1);
80    if (!store) {
81       return 1;
82    }
83    ua->jcr->store = store;
84
85    vol_list = get_slot_list_from_SD(ua);
86
87
88    if (!vol_list) {
89       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
90       goto bail_out;
91    }
92
93    /* Walk through the list updating the media records */
94    for (vl=vol_list; vl; vl=vl->next) {
95
96       memset(&mr, 0, sizeof(mr));
97       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) {
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           continue;
113       } else {
114           bsendmsg(ua, _("Record for Volume \"%s\" not found in catalog.\n"), 
115              mr.VolumeName);
116       }
117    }
118
119
120 bail_out:
121    /* Free list */
122    for (vl=vol_list; vl; ) {
123       vol_list_t *ovl;
124       free(vl->VolName);
125       ovl = vl;
126       vl = vl->next;
127       free(ovl);
128    }
129
130    if (ua->jcr->store_bsock) {
131       bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
132       bnet_close(ua->jcr->store_bsock);
133       ua->jcr->store_bsock = NULL;
134    }
135    return 1;
136 }
137
138 /*
139  * Common routine for both label and relabel
140  */
141 static int do_label(UAContext *ua, char *cmd, int relabel)
142 {
143    STORE *store;
144    BSOCK *sd;
145    sd = ua->jcr->store_bsock;
146    char dev_name[MAX_NAME_LENGTH];
147    MEDIA_DBR mr, omr;
148    POOL_DBR pr;
149    int ok = FALSE;
150    int mounted = FALSE;
151    int i;
152    static char *barcode_keyword[] = {
153       "barcode",
154       "barcodes",
155       NULL};
156
157
158    memset(&pr, 0, sizeof(pr));
159    if (!open_db(ua)) {
160       return 1;
161    }
162    store = get_storage_resource(ua, 1);
163    if (!store) {
164       return 1;
165    }
166    ua->jcr->store = store;
167
168    if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
169       label_from_barcodes(ua);
170       return 1;
171    }
172
173    /* If relabel get name of Volume to relabel */
174    if (relabel) {
175       /* Check for volume=OldVolume */
176       i = find_arg(ua, "volume"); 
177       if (i >= 0 && ua->argv[i]) {
178          memset(&omr, 0, sizeof(omr));
179          bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
180          if (db_get_media_record(ua->jcr, ua->db, &omr)) {
181             goto checkVol;
182          } 
183          bsendmsg(ua, "%s", db_strerror(ua->db));
184       }
185       /* No keyword or Vol not found, ask user to select */
186       if (!select_media_dbr(ua, &omr)) {
187          return 1;
188       }
189
190       /* Require Volume to be Purged */
191 checkVol:
192       if (strcmp(omr.VolStatus, "Purged") != 0) {
193          bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be purged before relabeling.\n"),
194             omr.VolumeName, omr.VolStatus);
195          return 1;
196       }
197    }
198
199    /* Check for name=NewVolume */
200    i = find_arg(ua, "name");
201    if (i >= 0 && ua->argv[i]) {
202       pm_strcpy(&ua->cmd, ua->argv[i]);
203       goto checkName;
204    }
205
206    /* Get a new Volume name */
207    for ( ;; ) {
208       if (!get_cmd(ua, _("Enter new Volume name: ")) || ua->cmd[0] == '.') {
209          return 1;
210       }
211 checkName:
212       if (!is_legal_volume_name(ua, ua->cmd)) {
213          continue;
214       }
215
216       memset(&mr, 0, sizeof(mr));
217       bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
218       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
219           bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), 
220              mr.VolumeName);
221           continue;
222       }
223       break;                          /* Got it */
224    }
225
226    /* If autochanger, request slot */
227    if (store->autochanger) {
228       int first = 1;
229       for ( ;; ) {
230          if (first) {
231             i = find_arg(ua, "slot"); 
232             if (i >= 0 && ua->argv[i]) {
233                mr.Slot = atoi(ua->argv[i]);
234             }
235             first = 0;
236          } else {
237             if (!get_cmd(ua, _("Enter slot (0 for none): ")) || ua->cmd[0] == '.') {
238                return 1;
239             }
240             mr.Slot = atoi(ua->cmd);
241          }
242          if (mr.Slot >= 0) {          /* OK */
243             break;
244          }
245          bsendmsg(ua, _("Slot numbers must be positive.\n"));
246       }
247    }
248
249    bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
250
251    /* Must select Pool if not already done */
252    if (pr.PoolId == 0) {
253       memset(&pr, 0, sizeof(pr));
254       if (!select_pool_dbr(ua, &pr)) {
255          return 1;
256       }
257    }
258
259    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
260       store->hdr.name, store->address, store->SDport);
261    if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
262       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
263       return 1;   
264    }
265    sd = ua->jcr->store_bsock;
266
267    ok = send_label_request(ua, &mr, &omr, &pr, relabel);
268
269    if (ok) {
270       if (relabel) {
271          if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
272             bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
273                omr.VolumeName, db_strerror(ua->db));
274          } else {
275             bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"), 
276                omr.VolumeName);
277          }
278       }
279       if (ua->automount) {
280          strcpy(dev_name, store->dev_name);
281          bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
282          bash_spaces(dev_name);
283          bnet_fsend(sd, "mount %s", dev_name);
284          unbash_spaces(dev_name);
285          while (bnet_recv(sd) >= 0) {
286             bsendmsg(ua, "%s", sd->msg);
287             /* Here we can get
288              *  3001 OK mount. Device=xxx      or
289              *  3001 Mounted Volume vvvv
290              */
291             mounted = strncmp(sd->msg, "3001 ", 5) == 0;
292          }
293       }
294    }
295    if (!mounted) {
296       bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
297    }
298    bnet_sig(sd, BNET_TERMINATE);
299    bnet_close(sd);
300    ua->jcr->store_bsock = NULL;
301
302    return 1;
303 }
304
305 /*
306  * Request SD to send us the slot:barcodes, then wiffle
307  *  through them all labeling them.
308  */
309 static void label_from_barcodes(UAContext *ua)
310 {
311    STORE *store = ua->jcr->store;
312    POOL_DBR pr;
313    MEDIA_DBR mr, omr;
314    vol_list_t *vl, *vol_list = NULL;
315
316    vol_list = get_slot_list_from_SD(ua);
317
318    if (!vol_list) {
319       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
320       goto bail_out;
321    }
322
323    /* Display list of Volumes and ask if he really wants to proceed */
324    bsendmsg(ua, _("The following Volumes will be labeled:\n"
325                   "Slot  Volume\n"
326                   "==============\n"));
327    for (vl=vol_list; vl; vl=vl->next) {
328       bsendmsg(ua, "%4d  %s\n", vl->Slot, vl->VolName);
329    }
330    if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
331        (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
332       goto bail_out;
333    }
334    /* Select a pool */
335    memset(&pr, 0, sizeof(pr));
336    if (!select_pool_dbr(ua, &pr)) {
337       goto bail_out;
338    }
339    memset(&omr, 0, sizeof(omr));
340
341    /* Fire off the label requests */
342    for (vl=vol_list; vl; vl=vl->next) {
343
344       memset(&mr, 0, sizeof(mr));
345       bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
346       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
347           bsendmsg(ua, _("Media record for Slot %d Volume \"%s\" already exists.\n"), 
348              vl->Slot, mr.VolumeName);
349           continue;
350       }
351       if (is_cleaning_tape(ua, &mr, &pr)) {
352          set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
353          if (db_create_media_record(ua->jcr, ua->db, &mr)) {
354             bsendmsg(ua, _("Catalog record for cleaning tape \"%s\" successfully created.\n"),
355                mr.VolumeName);
356          } else {
357             bsendmsg(ua, "Catalog error on cleaning tape: %s", db_strerror(ua->db));
358          }
359          continue;
360       }
361       bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
362       if (ua->jcr->store_bsock) {
363          bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
364          bnet_close(ua->jcr->store_bsock);
365          ua->jcr->store_bsock = NULL;
366       }
367       bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
368          store->hdr.name, store->address, store->SDport);
369       if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
370          bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
371          goto bail_out;
372       }
373
374       mr.Slot = vl->Slot;
375       send_label_request(ua, &mr, &omr, &pr, 0);
376    }
377
378
379 bail_out:
380    /* Free list */
381    for (vl=vol_list; vl; ) {
382       vol_list_t *ovl;
383       free(vl->VolName);
384       ovl = vl;
385       vl = vl->next;
386       free(ovl);
387    }
388
389    if (ua->jcr->store_bsock) {
390       bnet_sig(ua->jcr->store_bsock, BNET_TERMINATE);
391       bnet_close(ua->jcr->store_bsock);
392       ua->jcr->store_bsock = NULL;
393    }
394
395    return;
396 }
397
398 static int is_legal_volume_name(UAContext *ua, char *name)
399 {
400    int len;
401    /* Restrict the characters permitted in the Volume name */
402    if (strpbrk(name, "`~!@#$%^&*()[]{}|\\;'\"<>?,/")) {
403       bsendmsg(ua, _("Illegal character | in a volume name.\n"));
404       return 0;
405    }
406    len = strlen(name);
407    if (len >= MAX_NAME_LENGTH) {
408       bsendmsg(ua, _("Volume name too long.\n"));
409       return 0;
410    }
411    if (len == 0) {
412       bsendmsg(ua, _("Volume name must be at least one character long.\n"));
413       return 0;
414    }
415    return 1;
416 }
417
418 static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
419                               POOL_DBR *pr, int relabel)
420 {
421    BSOCK *sd;
422    char dev_name[MAX_NAME_LENGTH];
423    int ok = FALSE;
424
425    sd = ua->jcr->store_bsock;
426    bstrncpy(dev_name, ua->jcr->store->dev_name, sizeof(dev_name));
427    bash_spaces(dev_name);
428    bash_spaces(mr->VolumeName);
429    bash_spaces(mr->MediaType);
430    bash_spaces(pr->Name);
431    if (relabel) {
432       bash_spaces(omr->VolumeName);
433       bnet_fsend(sd, _("relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d"), 
434          dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
435       bsendmsg(ua, _("Sending relabel command from \"%s\" to \"%s\" ...\n"),
436          omr->VolumeName, mr->VolumeName);
437    } else {
438       bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d"), 
439          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
440       bsendmsg(ua, _("Sending label command for Volume \"%s\" Slot %d ...\n"), 
441          mr->VolumeName, mr->Slot);
442       Dmsg5(200, "label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d\n", 
443          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
444    }
445
446    while (bget_msg(sd, 0) >= 0) {
447       bsendmsg(ua, "%s", sd->msg);
448       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
449          ok = TRUE;
450       } 
451    }
452    unbash_spaces(mr->VolumeName);
453    unbash_spaces(mr->MediaType);
454    unbash_spaces(pr->Name);
455    mr->LabelDate = time(NULL);
456    if (ok) {
457       set_pool_dbr_defaults_in_media_dbr(mr, pr);
458       if (db_create_media_record(ua->jcr, ua->db, mr)) {
459          bsendmsg(ua, _("Catalog record for Volume \"%s\", Slot %d  successfully created.\n"),
460             mr->VolumeName, mr->Slot);
461       } else {
462          bsendmsg(ua, "%s", db_strerror(ua->db));
463          ok = FALSE;
464       }
465    } else {
466       bsendmsg(ua, _("Label command failed.\n"));
467    }
468    return ok;
469 }
470
471 static vol_list_t *get_slot_list_from_SD(UAContext *ua)
472 {
473    STORE *store = ua->jcr->store;
474    char dev_name[MAX_NAME_LENGTH];
475    BSOCK *sd;
476    vol_list_t *vl;
477    vol_list_t *vol_list = NULL;
478
479
480    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
481       store->hdr.name, store->address, store->SDport);
482    if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
483       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
484       return NULL;
485    }
486    sd  = ua->jcr->store_bsock;
487
488    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
489    bash_spaces(dev_name);
490    /* Ask for autochanger list of volumes */
491    bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
492
493    /* Read and organize list of Volumes */
494    while (bget_msg(sd, 0) >= 0) {
495       char *p;
496       int Slot;
497       strip_trailing_junk(sd->msg);
498
499       /* Check for returned SD messages */
500       if (sd->msg[0] == '3'     && B_ISDIGIT(sd->msg[1]) &&
501           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
502           sd->msg[4] == ' ') {
503          bsendmsg(ua, "%s\n", sd->msg);   /* pass them on to user */
504          continue;
505       }
506
507       /* Validate Slot:Barcode */
508       p = strchr(sd->msg, ':');
509       if (p && strlen(p) > 1) {
510          *p++ = 0;
511          if (!is_an_integer(sd->msg)) {
512             continue;
513          }
514       } else {
515          continue;
516       }
517       Slot = atoi(sd->msg);
518       if (Slot <= 0 || !is_legal_volume_name(ua, p)) {
519          continue;
520       }
521
522       /* Add Slot and VolumeName to list */
523       vl = (vol_list_t *)malloc(sizeof(vol_list_t));
524       vl->Slot = Slot;
525       vl->VolName = bstrdup(p);
526       if (!vol_list) {
527          vl->next = vol_list;
528          vol_list = vl;
529       } else {
530          /* Add new entry to end of list */
531          for (vol_list_t *tvl=vol_list; tvl; tvl=tvl->next) {
532             if (!tvl->next) {
533                tvl->next = vl;
534                vl->next = NULL;
535                break;
536             }
537          }
538       }
539    }
540    return vol_list;
541 }
542
543 /*
544  * Check if this is a cleaning tape by comparing the Volume name
545  *  with the Cleaning Prefix. If they match, this is a cleaning 
546  *  tape.
547  */
548 static int is_cleaning_tape(UAContext *ua, MEDIA_DBR *mr, POOL_DBR *pr)
549 {
550    if (!ua->jcr->pool) {
551       /* Find Pool resource */
552       ua->jcr->pool = (POOL *)GetResWithName(R_POOL, pr->Name);
553       if (!ua->jcr->pool) {
554          bsendmsg(ua, _("Pool %s resource not found!\n"), pr->Name);
555          return 1;
556       }
557    }
558    if (ua->jcr->pool->cleaning_prefix == NULL) {
559       return 0;
560    }
561    return strncmp(mr->VolumeName, ua->jcr->pool->cleaning_prefix,
562                   strlen(ua->jcr->pool->cleaning_prefix)) == 0;
563 }