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