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