1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2003-2012 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2016 Planets Communications B.V.
6 Copyright (C) 2013-2019 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23 /*
24 * Kern Sibbald, April MMIII
25 */
26 /**
27 * @file
28 * BAREOS Director -- Tape labeling commands
29 */
30
31 #include "include/bareos.h"
32 #include "dird.h"
33 #include "dird/dird_globals.h"
34 #include "dird/msgchan.h"
35 #include "dird/next_vol.h"
36
37 #if HAVE_NDMP
38 #include "ndmp/ndmagents.h"
39 #endif
40
41 #include "dird/ndmp_dma_storage.h"
42 #include "dird/jcr_private.h"
43 #include "dird/sd_cmds.h"
44 #include "dird/storage.h"
45 #include "dird/ua_db.h"
46 #include "dird/ua_input.h"
47 #include "dird/ua_label.h"
48 #include "dird/ua_select.h"
49 #include "include/auth_protocol_types.h"
50 #include "lib/crypto_wrap.h"
51 #include "lib/passphrase.h"
52 #include "lib/util.h"
53
54 namespace directordaemon {
55
56 /* Forward referenced functions */
57
58 /* External functions */
59
update_database(UaContext * ua,MediaDbRecord * mr,PoolDbRecord * pr,bool media_record_exists)60 static inline bool update_database(UaContext* ua,
61 MediaDbRecord* mr,
62 PoolDbRecord* pr,
63 bool media_record_exists)
64 {
65 bool retval = true;
66
67 if (media_record_exists) {
68 /*
69 * Update existing media record.
70 */
71 mr->InChanger = mr->Slot > 0; /* If slot give assume in changer */
72 SetStorageidInMr(ua->jcr->impl->res.write_storage, mr);
73 if (!ua->db->UpdateMediaRecord(ua->jcr, mr)) {
74 ua->ErrorMsg("%s", ua->db->strerror());
75 retval = false;
76 }
77 } else {
78 /*
79 * Create the media record
80 */
81 SetPoolDbrDefaultsInMediaDbr(mr, pr);
82 mr->InChanger = mr->Slot > 0; /* If slot give assume in changer */
83 mr->Enabled = 1;
84 SetStorageidInMr(ua->jcr->impl->res.write_storage, mr);
85
86 if (ua->db->CreateMediaRecord(ua->jcr, mr)) {
87 ua->InfoMsg(_("Catalog record for Volume \"%s\", Slot %hd successfully "
88 "created.\n"),
89 mr->VolumeName, mr->Slot);
90
91 /*
92 * Update number of volumes in pool
93 */
94 pr->NumVols++;
95 if (!ua->db->UpdatePoolRecord(ua->jcr, pr)) {
96 ua->ErrorMsg("%s", ua->db->strerror());
97 }
98 } else {
99 ua->ErrorMsg("%s", ua->db->strerror());
100 retval = false;
101 }
102 }
103
104 return retval;
105 }
106
107 /*
108 * NOTE! This routine opens the SD socket but leaves it open
109 */
native_send_label_request(UaContext * ua,MediaDbRecord * mr,MediaDbRecord * omr,PoolDbRecord * pr,bool relabel,drive_number_t drive)110 static inline bool native_send_label_request(UaContext* ua,
111 MediaDbRecord* mr,
112 MediaDbRecord* omr,
113 PoolDbRecord* pr,
114 bool relabel,
115 drive_number_t drive)
116 {
117 BareosSocket* sd;
118 char dev_name[MAX_NAME_LENGTH];
119 bool retval = false;
120 uint64_t VolBytes = 0;
121
122 if (!(sd = open_sd_bsock(ua))) { return false; }
123
124 bstrncpy(dev_name, ua->jcr->impl->res.write_storage->dev_name(),
125 sizeof(dev_name));
126 BashSpaces(dev_name);
127 BashSpaces(mr->VolumeName);
128 BashSpaces(mr->MediaType);
129 BashSpaces(pr->Name);
130
131 if (relabel) {
132 BashSpaces(omr->VolumeName);
133 sd->fsend(
134 "relabel %s OldName=%s NewName=%s PoolName=%s "
135 "MediaType=%s Slot=%hd drive=%hd MinBlocksize=%d MaxBlocksize=%d",
136 dev_name, omr->VolumeName, mr->VolumeName, pr->Name, mr->MediaType,
137 mr->Slot, drive,
138 /*
139 * if relabeling, keep blocksize settings
140 */
141 omr->MinBlocksize, omr->MaxBlocksize);
142 ua->SendMsg(_("Sending relabel command from \"%s\" to \"%s\" ...\n"),
143 omr->VolumeName, mr->VolumeName);
144 } else {
145 sd->fsend(
146 "label %s VolumeName=%s PoolName=%s MediaType=%s "
147 "Slot=%hd drive=%hd MinBlocksize=%d MaxBlocksize=%d",
148 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive,
149 /*
150 * If labeling, use blocksize defined in pool
151 */
152 pr->MinBlocksize, pr->MaxBlocksize);
153 ua->SendMsg(_("Sending label command for Volume \"%s\" Slot %hd ...\n"),
154 mr->VolumeName, mr->Slot);
155 Dmsg8(100,
156 "label %s VolumeName=%s PoolName=%s MediaType=%s "
157 "Slot=%hd drive=%hd MinBlocksize=%d MaxBlocksize=%d\n",
158 dev_name, mr->VolumeName, pr->Name, mr->MediaType, mr->Slot, drive,
159 pr->MinBlocksize, pr->MaxBlocksize);
160 }
161
162 /*
163 * We use BgetDirmsg here and not BnetRecv because as part of
164 * the label request the stored can request catalog information for
165 * any plugin who listens to the bsdEventLabelVerified event.
166 * As we don't want to loose any non protocol data e.g. errors
167 * without a 3xxx prefix we set the allow_any_message of
168 * BgetDirmsg to true and as such is behaves like a normal
169 * BnetRecv for any non protocol messages.
170 */
171 while (BgetDirmsg(sd, true) >= 0) {
172 ua->SendMsg("%s", sd->msg);
173 if (sscanf(sd->msg, "3000 OK label. VolBytes=%llu ", &VolBytes) == 1) {
174 retval = true;
175 }
176 }
177
178 UnbashSpaces(mr->VolumeName);
179 UnbashSpaces(mr->MediaType);
180 UnbashSpaces(pr->Name);
181 mr->LabelDate = time(NULL);
182 mr->set_label_date = true;
183 mr->VolBytes = VolBytes;
184
185 return retval;
186 }
187
188 /*
189 * Generate a new encryption key for use in volume encryption.
190 * We don't ask the user for a encryption key but generate a semi
191 * random passphrase of the wanted length which is way stronger.
192 * When the config has a wrap key we use that to wrap the newly
193 * created passphrase using RFC3394 aes wrap and always convert
194 * the passphrase into a base64 encoded string. This key is
195 * stored in the database and is passed to the storage daemon
196 * when needed. The storage daemon has the same wrap key per
197 * director so it can unwrap the passphrase for use.
198 *
199 * Changing the wrap key will render any previously created
200 * crypto keys useless so only change the wrap key after initial
201 * setting when you know what you are doing and always store
202 * the old key somewhere save so you can use bscrypto to
203 * convert them for the new wrap key.
204 */
GenerateNewEncryptionKey(UaContext * ua,MediaDbRecord * mr)205 static bool GenerateNewEncryptionKey(UaContext* ua, MediaDbRecord* mr)
206 {
207 int length;
208 char* passphrase;
209
210 passphrase = generate_crypto_passphrase(DEFAULT_PASSPHRASE_LENGTH);
211 if (!passphrase) {
212 ua->ErrorMsg(
213 _("Failed to generate new encryption passphrase for Volume %s.\n"),
214 mr->VolumeName);
215 return false;
216 }
217
218 /*
219 * See if we need to wrap the passphrase.
220 */
221 if (me->keyencrkey.value) {
222 char* wrapped_passphrase;
223
224 length = DEFAULT_PASSPHRASE_LENGTH + 8;
225 wrapped_passphrase = (char*)malloc(length);
226 memset(wrapped_passphrase, 0, length);
227 AesWrap((unsigned char*)me->keyencrkey.value, DEFAULT_PASSPHRASE_LENGTH / 8,
228 (unsigned char*)passphrase, (unsigned char*)wrapped_passphrase);
229
230 free(passphrase);
231 passphrase = wrapped_passphrase;
232 } else {
233 length = DEFAULT_PASSPHRASE_LENGTH;
234 }
235
236 /*
237 * The passphrase is always base64 encoded.
238 */
239 BinToBase64(mr->EncrKey, sizeof(mr->EncrKey), passphrase, length, true);
240
241 free(passphrase);
242 return true;
243 }
244
SendLabelRequest(UaContext * ua,StorageResource * store,MediaDbRecord * mr,MediaDbRecord * omr,PoolDbRecord * pr,bool media_record_exists,bool relabel,drive_number_t drive,slot_number_t slot)245 bool SendLabelRequest(UaContext* ua,
246 StorageResource* store,
247 MediaDbRecord* mr,
248 MediaDbRecord* omr,
249 PoolDbRecord* pr,
250 bool media_record_exists,
251 bool relabel,
252 drive_number_t drive,
253 slot_number_t slot)
254 {
255 bool retval;
256
257 switch (store->Protocol) {
258 case APT_NATIVE:
259 retval = native_send_label_request(ua, mr, omr, pr, relabel, drive);
260 break;
261 case APT_NDMPV2:
262 case APT_NDMPV3:
263 case APT_NDMPV4:
264 retval =
265 NdmpSendLabelRequest(ua, store, mr, omr, pr, relabel, drive, slot);
266 break;
267 default:
268 retval = false;
269 break;
270 }
271
272 if (retval) {
273 retval = update_database(ua, mr, pr, media_record_exists);
274 } else {
275 ua->ErrorMsg(_("Label command failed for Volume %s.\n"), mr->VolumeName);
276 }
277
278 return retval;
279 }
280
281 /*
282 * Check if this is a cleaning tape by comparing the Volume name
283 * with the Cleaning Prefix. If they match, this is a cleaning tape.
284 */
IsCleaningTape(UaContext * ua,MediaDbRecord * mr,PoolDbRecord * pr)285 static inline bool IsCleaningTape(UaContext* ua,
286 MediaDbRecord* mr,
287 PoolDbRecord* pr)
288 {
289 bool retval;
290
291 /*
292 * Find Pool resource
293 */
294 ua->jcr->impl->res.pool = ua->GetPoolResWithName(pr->Name, false);
295 if (!ua->jcr->impl->res.pool) {
296 ua->ErrorMsg(_("Pool \"%s\" resource not found for volume \"%s\"!\n"),
297 pr->Name, mr->VolumeName);
298 return false;
299 }
300
301 retval = bstrncmp(mr->VolumeName, ua->jcr->impl->res.pool->cleaning_prefix,
302 strlen(ua->jcr->impl->res.pool->cleaning_prefix));
303
304 Dmsg4(100, "CLNprefix=%s: Vol=%s: len=%d bstrncmp=%s\n",
305 ua->jcr->impl->res.pool->cleaning_prefix, mr->VolumeName,
306 strlen(ua->jcr->impl->res.pool->cleaning_prefix),
307 retval ? "true" : "false");
308
309 return retval;
310 }
311
312
313 /*
314 * Request Storage to send us the slot:barcodes, then wiffle through them all
315 * labeling them.
316 */
label_from_barcodes(UaContext * ua,drive_number_t drive,bool label_encrypt,bool yes)317 static void label_from_barcodes(UaContext* ua,
318 drive_number_t drive,
319 bool label_encrypt,
320 bool yes)
321 {
322 StorageResource* store = ua->jcr->impl->res.write_storage;
323 PoolDbRecord pr;
324 MediaDbRecord mr;
325 vol_list_t* vl;
326 changer_vol_list_t* vol_list = NULL;
327 bool media_record_exists;
328 char* slot_list;
329 int max_slots;
330
331
332 max_slots = GetNumSlots(ua, ua->jcr->impl->res.write_storage);
333 if (max_slots <= 0) {
334 ua->WarningMsg(_("No slots in changer to scan.\n"));
335 return;
336 }
337
338 slot_list = (char*)malloc(NbytesForBits(max_slots));
339 ClearAllBits(max_slots, slot_list);
340 if (!GetUserSlotList(ua, slot_list, "slots", max_slots)) { goto bail_out; }
341
342 vol_list = get_vol_list_from_storage(ua, store, false /* no listall */,
343 false /* no scan */);
344 if (!vol_list) {
345 ua->WarningMsg(_("No Volumes found to label, or no barcodes.\n"));
346 goto bail_out;
347 }
348
349 /*
350 * Display list of Volumes and ask if he really wants to proceed
351 */
352 ua->SendMsg(
353 _("The following Volumes will be labeled:\n"
354 "Slot Volume\n"
355 "==============\n"));
356 foreach_dlist (vl, vol_list->contents) {
357 if (!vl->VolName || !BitIsSet(vl->bareos_slot_number - 1, slot_list)) {
358 continue;
359 }
360 ua->SendMsg("%4d %s\n", vl->bareos_slot_number, vl->VolName);
361 }
362
363 if (!yes &&
364 (!GetYesno(ua, _("Do you want to label these Volumes? (yes|no): ")) ||
365 !ua->pint32_val)) {
366 goto bail_out;
367 }
368
369 /*
370 * Select a pool
371 */
372 if (!SelectPoolDbr(ua, &pr)) { goto bail_out; }
373
374 /*
375 * Fire off the label requests
376 */
377 foreach_dlist (vl, vol_list->contents) {
378 if (!vl->VolName || !BitIsSet(vl->bareos_slot_number - 1, slot_list)) {
379 continue;
380 }
381 mr = MediaDbRecord{};
382 bstrncpy(mr.VolumeName, vl->VolName, sizeof(mr.VolumeName));
383 media_record_exists = false;
384 if (ua->db->GetMediaRecord(ua->jcr, &mr)) {
385 if (mr.VolBytes != 0) {
386 ua->WarningMsg(
387 _("Media record for Slot %hd Volume \"%s\" already exists.\n"),
388 vl->bareos_slot_number, mr.VolumeName);
389 mr.Slot = vl->bareos_slot_number;
390 mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
391 SetStorageidInMr(store, &mr);
392 if (!ua->db->UpdateMediaRecord(ua->jcr, &mr)) {
393 ua->ErrorMsg(_("Error setting InChanger: ERR=%s"),
394 ua->db->strerror());
395 }
396 continue;
397 }
398 media_record_exists = true;
399 }
400 mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
401 SetStorageidInMr(store, &mr);
402
403 /*
404 * Deal with creating cleaning tape here.
405 * Normal tapes created in SendLabelRequest() below
406 */
407 if (IsCleaningTape(ua, &mr, &pr)) {
408 if (media_record_exists) { /* we update it */
409 mr.VolBytes = 1; /* any bytes to indicate it exists */
410 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
411 mr.MediaType[0] = 0;
412 SetStorageidInMr(store, &mr);
413 if (!ua->db->UpdateMediaRecord(ua->jcr, &mr)) {
414 ua->ErrorMsg("%s", ua->db->strerror());
415 }
416 } else { /* create the media record */
417 if (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
418 ua->ErrorMsg(_("Maximum pool Volumes=%d reached.\n"), pr.MaxVols);
419 goto bail_out;
420 }
421 SetPoolDbrDefaultsInMediaDbr(&mr, &pr);
422 bstrncpy(mr.VolStatus, "Cleaning", sizeof(mr.VolStatus));
423 mr.MediaType[0] = 0;
424 SetStorageidInMr(store, &mr);
425 if (ua->db->CreateMediaRecord(ua->jcr, &mr)) {
426 ua->SendMsg(_("Catalog record for cleaning tape \"%s\" successfully "
427 "created.\n"),
428 mr.VolumeName);
429 pr.NumVols++; /* this is a bit suspect */
430 if (!ua->db->UpdatePoolRecord(ua->jcr, &pr)) {
431 ua->ErrorMsg("%s", ua->db->strerror());
432 }
433 } else {
434 ua->ErrorMsg(_("Catalog error on cleaning tape: %s"),
435 ua->db->strerror());
436 }
437 }
438 continue; /* done, go handle next volume */
439 }
440 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
441
442 /*
443 * See if we need to generate a new passphrase for hardware encryption.
444 */
445 if (label_encrypt) {
446 if (!GenerateNewEncryptionKey(ua, &mr)) { continue; }
447 }
448
449 mr.Slot = vl->bareos_slot_number;
450 SendLabelRequest(ua, store, &mr, NULL, &pr, media_record_exists, false,
451 drive, vl->bareos_slot_number);
452 }
453
454 bail_out:
455 free(slot_list);
456 if (vol_list) { StorageReleaseVolList(store, vol_list); }
457 CloseSdBsock(ua);
458
459 return;
460 }
461
462 /*
463 * Common routine for both label and relabel
464 */
do_label(UaContext * ua,const char * cmd,bool relabel)465 static int do_label(UaContext* ua, const char* cmd, bool relabel)
466 {
467 int i, j;
468 BareosSocket* sd;
469 MediaDbRecord mr, omr;
470 PoolDbRecord pr;
471 UnifiedStorageResource store;
472 bool ok = false;
473 bool yes = false; /* Was "yes" given on cmdline */
474 drive_number_t drive;
475 bool print_reminder = true;
476 bool label_barcodes = false;
477 bool label_encrypt = false;
478 bool media_record_exists = false;
479 char dev_name[MAX_NAME_LENGTH];
480 static const char* barcode_keywords[] = {"barcode", "barcodes", NULL};
481
482 if (!OpenClientDb(ua)) { return 1; }
483
484 if (ua->batch || FindArg(ua, NT_("yes")) > 0) { yes = true; }
485
486 /*
487 * Look for one of the barcode keywords
488 */
489 if (!relabel && (i = FindArgKeyword(ua, barcode_keywords)) >= 0) {
490 /*
491 * Now find the keyword in the list
492 */
493 if ((j = FindArg(ua, barcode_keywords[i])) > 0) {
494 *ua->argk[j] = 0; /* zap barcode keyword */
495 }
496 label_barcodes = true;
497 }
498
499 /*
500 * Look for the encrypt keyword
501 */
502 if ((i = FindArg(ua, "encrypt")) > 0) {
503 *ua->argk[i] = 0; /* zap encrypt keyword */
504 label_encrypt = true;
505 }
506
507 store.store = get_storage_resource(ua, true, label_barcodes);
508 if (!store.store) { return 1; }
509
510 switch (store.store->Protocol) {
511 case APT_NDMPV2:
512 case APT_NDMPV3:
513 case APT_NDMPV4:
514 /*
515 * See if the user selected a NDMP storage device but its
516 * handled by a native Bareos storage daemon e.g. we have
517 * a paired_storage pointer.
518 */
519 if (store.store->paired_storage) {
520 store.store = store.store->paired_storage;
521 }
522 break;
523 default:
524 break;
525 }
526
527 PmStrcpy(store.store_source, _("command line"));
528 SetWstorage(ua->jcr, &store);
529 drive = GetStorageDrive(ua, store.store);
530
531 if (label_barcodes) {
532 label_from_barcodes(ua, drive, label_encrypt, yes);
533 return 1;
534 }
535
536 /*
537 * If relabel get name of Volume to relabel
538 */
539 if (relabel) {
540 /*
541 * Check for oldvolume=name
542 */
543 i = FindArgWithValue(ua, "oldvolume");
544 if (i >= 0) {
545 bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName));
546 if (ua->db->GetMediaRecord(ua->jcr, &omr)) { goto checkVol; }
547 ua->ErrorMsg("%s", ua->db->strerror());
548 }
549 /*
550 * No keyword or Vol not found, ask user to select
551 */
552 if (!SelectMediaDbr(ua, &omr)) { return 1; }
553
554 /*
555 * Require Volume to be Purged or Recycled
556 */
557 checkVol:
558 if (!bstrcmp(omr.VolStatus, "Purged") &&
559 !bstrcmp(omr.VolStatus, "Recycle")) {
560 ua->ErrorMsg(_("Volume \"%s\" has VolStatus %s. It must be Purged or "
561 "Recycled before relabeling.\n"),
562 omr.VolumeName, omr.VolStatus);
563 return 1;
564 }
565 }
566
567 /*
568 * Check for volume=NewVolume
569 */
570 i = FindArgWithValue(ua, "volume");
571 if (i >= 0) {
572 PmStrcpy(ua->cmd, ua->argv[i]);
573 goto checkName;
574 }
575
576 /*
577 * Get a new Volume name
578 */
579 for (;;) {
580 media_record_exists = false;
581 if (!GetCmd(ua, _("Enter new Volume name: "))) { return 1; }
582 checkName:
583 if (!IsVolumeNameLegal(ua, ua->cmd)) { continue; }
584
585 /*
586 * Search by Media name so set VolumeName and clear MediaId.
587 */
588 mr.MediaId = 0;
589 bstrncpy(mr.VolumeName, ua->cmd, sizeof(mr.VolumeName));
590
591 /*
592 * If VolBytes are zero the Volume is not labeled
593 */
594 if (ua->db->GetMediaRecord(ua->jcr, &mr)) {
595 if (mr.VolBytes != 0) {
596 ua->ErrorMsg(_("Media record for new Volume \"%s\" already exists.\n"),
597 mr.VolumeName);
598 continue;
599 }
600 media_record_exists = true;
601 }
602 break; /* Got it */
603 }
604
605 /*
606 * If autochanger, request slot
607 */
608 i = FindArgWithValue(ua, "slot");
609 if (i >= 0) {
610 mr.Slot = atoi(ua->argv[i]);
611 if (mr.Slot < 0) { mr.Slot = 0; }
612 mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
613 } else if (store.store->autochanger) {
614 if (!GetPint(ua, _("Enter slot (0 or Enter for none): "))) { return 1; }
615 mr.Slot = (slot_number_t)ua->pint32_val;
616 if (mr.Slot < 0) { mr.Slot = 0; }
617 mr.InChanger = mr.Slot > 0; /* if slot give assume in changer */
618 }
619 SetStorageidInMr(store.store, &mr);
620
621 bstrncpy(mr.MediaType, store.store->media_type, sizeof(mr.MediaType));
622
623 /*
624 * Must select Pool if not already done
625 */
626 if (pr.PoolId == 0) {
627 pr = PoolDbRecord{};
628 if (!SelectPoolDbr(ua, &pr)) { return 1; }
629 }
630
631 /*
632 * See if we need to generate a new passphrase for hardware encryption.
633 */
634 if (label_encrypt) {
635 ua->InfoMsg(_("Generating new hardware encryption key\n"));
636 if (!GenerateNewEncryptionKey(ua, &mr)) { return 1; }
637 }
638
639 ok = SendLabelRequest(ua, store.store, &mr, &omr, &pr, media_record_exists,
640 relabel, drive, mr.Slot);
641 if (ok) {
642 sd = ua->jcr->store_bsock;
643 if (relabel) {
644 /*
645 * Delete the old media record
646 */
647 if (!ua->db->DeleteMediaRecord(ua->jcr, &omr)) {
648 ua->ErrorMsg(_("Delete of Volume \"%s\" failed. ERR=%s"),
649 omr.VolumeName, ua->db->strerror());
650 } else {
651 ua->InfoMsg(_("Old volume \"%s\" deleted from catalog.\n"),
652 omr.VolumeName);
653 /*
654 * Update the number of Volumes in the pool
655 */
656 pr.NumVols--;
657 if (!ua->db->UpdatePoolRecord(ua->jcr, &pr)) {
658 ua->ErrorMsg("%s", ua->db->strerror());
659 }
660 }
661 }
662 if (ua->automount) {
663 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
664 ua->InfoMsg(_("Requesting to mount %s ...\n"), dev_name);
665 BashSpaces(dev_name);
666 sd->fsend("mount %s drive=%hd", dev_name, drive);
667 UnbashSpaces(dev_name);
668
669 /*
670 * We use BgetDirmsg here and not BnetRecv because as part of
671 * the mount request the stored can request catalog information for
672 * any plugin who listens to the bsdEventLabelVerified event.
673 * As we don't want to loose any non protocol data e.g. errors
674 * without a 3xxx prefix we set the allow_any_message of
675 * BgetDirmsg to true and as such is behaves like a normal
676 * BnetRecv for any non protocol messages.
677 */
678 while (BgetDirmsg(sd, true) >= 0) {
679 ua->SendMsg("%s", sd->msg);
680
681 /*
682 * Here we can get
683 * 3001 OK mount. Device=xxx or
684 * 3001 Mounted Volume vvvv
685 * 3002 Device "DVD-Writer" (/dev/hdc) is mounted.
686 * 3906 is cannot mount non-tape
687 * So for those, no need to print a reminder
688 */
689 if (bstrncmp(sd->msg, "3001 ", 5) || bstrncmp(sd->msg, "3002 ", 5) ||
690 bstrncmp(sd->msg, "3906 ", 5)) {
691 print_reminder = false;
692 }
693 }
694 }
695 }
696
697 if (print_reminder) {
698 ua->InfoMsg(_("Do not forget to mount the drive!!!\n"));
699 }
700
701 /*
702 * close socket opened by native_send_label_request()
703 */
704 CloseSdBsock(ua);
705
706 return 1;
707 }
708
709 /*
710 * Label a tape
711 *
712 * label storage=xxx volume=vvv
713 */
LabelCmd(UaContext * ua,const char * cmd)714 bool LabelCmd(UaContext* ua, const char* cmd)
715 {
716 return do_label(ua, cmd, false); /* standard label */
717 }
718
RelabelCmd(UaContext * ua,const char * cmd)719 bool RelabelCmd(UaContext* ua, const char* cmd)
720 {
721 return do_label(ua, cmd, true); /* relabel tape */
722 }
723
724 /*
725 * Check if the Volume name has legal characters
726 * If ua is non-NULL send the message
727 */
IsVolumeNameLegal(UaContext * ua,const char * name)728 bool IsVolumeNameLegal(UaContext* ua, const char* name)
729 {
730 int len;
731 const char* p;
732 const char* accept = ":.-_/";
733
734 if (name[0] == '/') {
735 if (ua) { ua->ErrorMsg(_("Volume name can not start with \"/\".\n")); }
736 return 0;
737 }
738
739 /*
740 * Restrict the characters permitted in the Volume name
741 */
742 for (p = name; *p; p++) {
743 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
744 continue;
745 }
746 if (ua) {
747 ua->ErrorMsg(_("Illegal character \"%c\" in a volume name.\n"), *p);
748 }
749 return 0;
750 }
751 len = strlen(name);
752 if (len >= MAX_NAME_LENGTH) {
753 if (ua) { ua->ErrorMsg(_("Volume name too long.\n")); }
754 return 0;
755 }
756 if (len == 0) {
757 if (ua) {
758 ua->ErrorMsg(_("Volume name must be at least one character long.\n"));
759 }
760 return 0;
761 }
762 return 1;
763 }
764 } /* namespace directordaemon */
765