]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_label.c
More on barcodes
[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 /* Forward referenced functions */
34 static int do_label(UAContext *ua, char *cmd, int relabel);
35 static void label_from_barcodes(UAContext *ua);
36 static int is_legal_volume_name(UAContext *ua, char *name);
37 static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
38                POOL_DBR *pr, int relabel);
39
40
41 /*
42  * Label a tape 
43  *  
44  *   label storage=xxx volume=vvv
45  */
46 int labelcmd(UAContext *ua, char *cmd)
47 {
48    return do_label(ua, cmd, 0);       /* standard label */
49 }
50
51 int relabelcmd(UAContext *ua, char *cmd)
52 {
53    return do_label(ua, cmd, 1);      /* relabel tape */
54 }
55
56
57 /*
58  * Common routine for both label and relabel
59  */
60 static int do_label(UAContext *ua, char *cmd, int relabel)
61 {
62    STORE *store;
63    BSOCK *sd;
64    sd = ua->jcr->store_bsock;
65    char dev_name[MAX_NAME_LENGTH];
66    MEDIA_DBR mr, omr;
67    POOL_DBR pr;
68    int ok = FALSE;
69    int mounted = FALSE;
70    int i;
71    static char *name_keyword[] = {
72       "name",
73       NULL};
74    static char *vol_keyword[] = {
75       "volume",
76       NULL};
77    static char *barcode_keyword[] = {
78       "barcode",
79       "barcodes",
80       NULL};
81
82
83    memset(&pr, 0, sizeof(pr));
84    if (!open_db(ua)) {
85       return 1;
86    }
87    store = get_storage_resource(ua, cmd);
88    if (!store) {
89       return 1;
90    }
91    ua->jcr->store = store;
92
93    if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) {
94       label_from_barcodes(ua);
95       return 1;
96    }
97
98    /* If relabel get name of Volume to relabel */
99    if (relabel) {
100       /* Check for volume=OldVolume */
101       i = find_arg_keyword(ua, vol_keyword); 
102       if (i >= 0 && ua->argv[i]) {
103          memset(&omr, 0, sizeof(omr));
104          bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
105          if (db_get_media_record(ua->jcr, ua->db, &omr)) {
106             goto checkVol;
107          } 
108          bsendmsg(ua, "%s", db_strerror(ua->db));
109       }
110       /* No keyword or Vol not found, ask user to select */
111       if (!select_pool_and_media_dbr(ua, &pr, &omr)) {
112          return 1;
113       }
114
115       /* Require Volume to be Purged */
116 checkVol:
117       if (strcmp(omr.VolStatus, "Purged") != 0) {
118          bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be purged before relabeling.\n"),
119             omr.VolumeName, omr.VolStatus);
120          return 1;
121       }
122    }
123
124    /* Check for name=NewVolume */
125    i = find_arg_keyword(ua, name_keyword);
126    if (i >=0 && ua->argv[i]) {
127       strcpy(ua->cmd, ua->argv[i]);
128       goto checkName;
129    }
130
131    /* Get a new Volume name */
132    for ( ;; ) {
133       if (!get_cmd(ua, _("Enter new Volume name: "))) {
134          return 1;
135       }
136 checkName:
137       if (!is_legal_volume_name(ua, ua->cmd)) {
138          continue;
139       }
140
141       memset(&mr, 0, sizeof(mr));
142       strcpy(mr.VolumeName, ua->cmd);
143       if (db_get_media_record(ua->jcr, ua->db, &mr)) {
144           bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), 
145              mr.VolumeName);
146           continue;
147       }
148       break;                          /* Got it */
149    }
150
151    /* If autochanger, request slot */
152    if (store->autochanger) {
153       for ( ;; ) {
154          if (!get_cmd(ua, _("Enter slot (0 for none): "))) {
155             return 1;
156          }
157          mr.Slot = atoi(ua->cmd);
158          if (mr.Slot >= 0) {          /* OK */
159             break;
160          }
161          bsendmsg(ua, _("Slot numbers must be positive.\n"));
162       }
163    }
164    strcpy(mr.MediaType, store->media_type);
165
166    /* Must select Pool if not already done */
167    if (pr.PoolId == 0) {
168       memset(&pr, 0, sizeof(pr));
169       if (!select_pool_dbr(ua, &pr)) {
170          return 1;
171       }
172    }
173
174    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
175       store->hdr.name, store->address, store->SDport);
176    if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
177       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
178       return 1;   
179    }
180    sd = ua->jcr->store_bsock;
181
182    ok = send_label_request(ua, &mr, &omr, &pr, relabel);
183
184    if (ok) {
185       if (relabel) {
186          if (!db_delete_media_record(ua->jcr, ua->db, &omr)) {
187             bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"),
188                omr.VolumeName, db_strerror(ua->db));
189          } else {
190             bsendmsg(ua, _("Old volume \"%s\" deleted from catalog.\n"), 
191                omr.VolumeName);
192          }
193       }
194       if (ua->automount) {
195          strcpy(dev_name, store->dev_name);
196          bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
197          bash_spaces(dev_name);
198          bnet_fsend(sd, "mount %s", dev_name);
199          unbash_spaces(dev_name);
200          while (bnet_recv(sd) >= 0) {
201             bsendmsg(ua, "%s", sd->msg);
202             /* Here we can get
203              *  3001 OK mount. Device=xxx      or
204              *  3001 Mounted Volume vvvv
205              */
206             mounted = strncmp(sd->msg, "3001 ", 5) == 0;
207          }
208       }
209    }
210    if (!mounted) {
211       bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
212    }
213    bnet_sig(sd, BNET_TERMINATE);
214    bnet_close(sd);
215    ua->jcr->store_bsock = NULL;
216
217    return 1;
218 }
219
220 /*
221  * Request SD to send us the slot:barcodes, then wiffle
222  *  through them all labeling them.
223  */
224 static void label_from_barcodes(UAContext *ua)
225 {
226    STORE *store = ua->jcr->store;
227    BSOCK *sd;
228    POOL_DBR pr;
229    char dev_name[MAX_NAME_LENGTH];
230 //   MEDIA_DBR mr, omr;
231    typedef struct s_vol_list {
232       struct s_vol_list *next;
233       char *VolName;
234       int Slot;
235    } vol_list_t;
236    vol_list_t *vol_list = NULL;
237    vol_list_t *vl;
238
239    bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), 
240       store->hdr.name, store->address, store->SDport);
241    if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
242       bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
243       return;
244    }
245    sd  = ua->jcr->store_bsock;
246
247    bstrncpy(dev_name, store->dev_name, sizeof(dev_name));
248    bash_spaces(dev_name);
249    bnet_fsend(sd, _("autochanger list %s \n"), dev_name);
250    while (bget_msg(sd, 0) >= 0) {
251       char *p;
252       strip_trailing_junk(sd->msg);
253       /* Check for returned SD messages */
254       if (sd->msg[0] == '3'     && sd->msg[1] == '9' &&         
255           B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) &&
256           sd->msg[4] == ' ') {
257          bsendmsg(ua, "%s\n", sd->msg);   /* pass them on to user */
258          continue;
259       }
260       p = strchr(sd->msg, ':');
261       if (p && strlen(p) > 1) {
262          *p++ = 0;
263          if (!is_an_integer(sd->msg)) {
264             continue;
265          }
266       } else {
267          continue;
268       }
269       vl = (vol_list_t *)malloc(sizeof(vol_list_t));
270       vl->Slot = atoi(sd->msg);
271       vl->VolName = bstrdup(p);
272       vl->next = vol_list;
273       vol_list = vl;
274    }
275
276    if (!vol_list) {
277       bsendmsg(ua, _("No Volumes found to label, or no barcodes.\n"));
278       goto bail_out;
279    }
280    bsendmsg(ua, _("The following Volumes will be labeled:\n"
281                   "Slot  Volume\n"
282                   "==============\n"));
283    for (vl=vol_list; vl; vl=vl->next) {
284       bsendmsg(ua, "%4d  %s\n", vl->Slot, vl->VolName);
285    }
286    if (!get_cmd(ua, _("Do you want to continue? (y/n): ")) ||
287        (ua->cmd[0] != 'y' && ua->cmd[0] != 'Y')) {
288       goto bail_out;
289    }
290
291
292
293 #ifdef xxxx
294    memset(&mr, 0, sizeof(mr));
295    strcpy(mr.VolumeName, ua->cmd);
296    if (db_get_media_record(ua->jcr, ua->db, &mr)) {
297        bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), 
298           mr.VolumeName);
299        continue;
300    }
301 #endif
302
303 bail_out:
304    /* Free list */
305    for (vl=vol_list; vl; ) {
306       vol_list_t *ovl;
307       free(vl->VolName);
308       ovl = vl;
309       vl = vl->next;
310       free(ovl);
311    }
312
313    bnet_sig(sd, BNET_TERMINATE);
314    bnet_close(sd);
315    ua->jcr->store_bsock = NULL;
316
317    return;
318
319    memset(&pr, 0, sizeof(pr));
320    if (!select_pool_dbr(ua, &pr)) {
321       return;
322    }
323
324    return;
325 }
326
327 static int is_legal_volume_name(UAContext *ua, char *name)
328 {
329    int len;
330    /* Restrict the characters permitted in the Volume name */
331    if (strpbrk(name, "`~!@#$%^&*()[]{}|\\;'\"<>?,/")) {
332       bsendmsg(ua, _("Illegal character | in a volume name.\n"));
333       return 0;
334    }
335    len = strlen(name);
336    if (len >= MAX_NAME_LENGTH) {
337       bsendmsg(ua, _("Volume name too long.\n"));
338       return 0;
339    }
340    if (len == 0) {
341       bsendmsg(ua, _("Volume name must be at least one character long.\n"));
342       return 0;
343    }
344    return 1;
345 }
346
347 static int send_label_request(UAContext *ua, MEDIA_DBR *mr, MEDIA_DBR *omr, 
348                               POOL_DBR *pr, int relabel)
349 {
350    BSOCK *sd;
351    char dev_name[MAX_NAME_LENGTH];
352    int ok = FALSE;
353
354    sd = ua->jcr->store_bsock;
355    strcpy(dev_name, ua->jcr->store->dev_name);
356    bash_spaces(dev_name);
357    bash_spaces(mr->VolumeName);
358    bash_spaces(mr->MediaType);
359    bash_spaces(pr->Name);
360    if (relabel) {
361       bash_spaces(omr->VolumeName);
362       bnet_fsend(sd, _("relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d"), 
363          dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
364       bsendmsg(ua, _("Sending relabel command ...\n"));
365    } else {
366       bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d"), 
367          dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot);
368       bsendmsg(ua, _("Sending label command ...\n"));
369    }
370    while (bget_msg(sd, 0) >= 0) {
371       bsendmsg(ua, "%s", sd->msg);
372       if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
373          ok = TRUE;
374       } else {
375          bsendmsg(ua, _("Label command failed.\n"));
376       }
377    }
378    ua->jcr->store_bsock = NULL;
379    unbash_spaces(dev_name);
380    unbash_spaces(mr->VolumeName);
381    unbash_spaces(mr->MediaType);
382    unbash_spaces(pr->Name);
383    mr->LabelDate = time(NULL);
384    if (ok) {
385       set_pool_dbr_defaults_in_media_dbr(mr, pr);
386       if (db_create_media_record(ua->jcr, ua->db, mr)) {
387          bsendmsg(ua, _("Media record for Volume \"%s\" successfully created.\n"),
388             mr->VolumeName);
389       } else {
390          bsendmsg(ua, "%s", db_strerror(ua->db));
391          ok = FALSE;
392       }
393    }
394    return ok;
395 }