1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2011-2012 Planets Communications B.V.
5 Copyright (C) 2013-2018 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation and included
10 in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * Written by Marco van Wieringen, December 2011
24 */
25 /**
26 * @file
27 * BAREOS Director -- Import/Export and Move functions.
28 */
29
30 #include "include/bareos.h"
31 #include "dird.h"
32 #include "dird/sd_cmds.h"
33 #include "dird/storage.h"
34 #include "dird/ua_label.h"
35 #include "dird/ua_impexp.h"
36 #include "dird/ua_update.h"
37 #include "dird/ua_select.h"
38 #include "lib/edit.h"
39
40 namespace directordaemon {
41
42 /* Forward referenced functions */
43
44 /**
45 * Import/Export and Move volumes in an autochanger.
46 *
47 * The following things apply here:
48 * - the source and destination slot list is walked in order
49 * So when you give a selection of 1-3,7,5 it will visit the
50 * slots 1,2,3,5,7 in that order.
51 * - moving volumes from a source slot specification to a
52 * destination slot specification also is performed in order.
53 * So when you specify the source slots as 1-3,7,5 and
54 * the destination slots as 22-24,25,27 the following moves
55 * will take place:
56 * 1 --> 22
57 * 2 --> 23
58 * 3 --> 24
59 * 5 --> 25
60 * 7 --> 27
61 *
62 * When you want to be sure the moves are performed in the
63 * way you expect them to happen make sure the selection
64 * cannot be wrongly interpreted by the code e.g. use
65 * unambigious ranges. Or ranges of only one slot for
66 * both the source and destination.
67 */
68
69 /**
70 * Walk the slot list and count the number of slots enabled in
71 * the list.
72 */
count_enabled_slots(char * slot_list,slot_number_t max_slots)73 static inline slot_number_t count_enabled_slots(char* slot_list,
74 slot_number_t max_slots)
75 {
76 slot_number_t i;
77 slot_number_t cnt = 0;
78
79 for (i = 0; i < max_slots; i++) {
80 if (BitIsSet(i, slot_list)) { cnt++; }
81 }
82 return cnt;
83 }
84
85 /**
86 * See if a selected slot list has the wanted status and
87 * deselect any slot which has not.
88 */
validate_slot_list(UaContext * ua,StorageResource * store,changer_vol_list_t * vol_list,char * slot_list,slot_status_t status)89 static inline void validate_slot_list(UaContext* ua,
90 StorageResource* store,
91 changer_vol_list_t* vol_list,
92 char* slot_list,
93 slot_status_t status)
94 {
95 vol_list_t* vl;
96
97 /*
98 * Walk the list of drives and slots available.
99 */
100 foreach_dlist (vl, vol_list->contents) {
101 switch (vl->slot_type) {
102 case slot_type_t::kSlotTypeStorage:
103 case slot_type_t::kSlotTypeImport:
104 if (BitIsSet(vl->bareos_slot_number - 1, slot_list)) {
105 switch (status) {
106 case slot_status_t::kSlotStatusFull:
107 /*
108 * If it has the correct status we are done.
109 */
110 if (vl->slot_status == status) { continue; }
111 /*
112 * If the request is for a slot with status
113 * we check the actual status. When its empty
114 * but loaded in the drive we just pretend
115 * that it has status. We just unload the drive
116 * on the export move operation.
117 */
118 if (vl->slot_type == slot_type_t::kSlotTypeStorage &&
119 vl->slot_status == slot_status_t::kSlotStatusEmpty &&
120 vol_is_loaded_in_drive(store, vol_list,
121 vl->bareos_slot_number) != NULL) {
122 continue;
123 }
124 Dmsg1(100, "Deselecting slot %hd doesn't have wanted status.\n",
125 vl->bareos_slot_number);
126 ua->WarningMsg(
127 _("Deselecting slot %hd doesn't have wanted status.\n"),
128 vl->bareos_slot_number);
129 ClearBit(vl->bareos_slot_number - 1, slot_list);
130 break;
131 case slot_status_t::kSlotStatusEmpty:
132 /*
133 * If it has the correct status we are done.
134 */
135 if (vl->slot_status == status) { continue; }
136 /*
137 * If the slot is empty and this is normal slot
138 * make sure its not loaded in a drive because
139 * then the slot is not really empty.
140 */
141 if (vl->slot_type == slot_type_t::kSlotTypeStorage &&
142 vl->slot_status == slot_status_t::kSlotStatusEmpty &&
143 vol_is_loaded_in_drive(store, vol_list,
144 vl->bareos_slot_number) == NULL) {
145 continue;
146 }
147 Dmsg1(100, "Deselecting slot %hd doesn't have wanted status.\n",
148 vl->bareos_slot_number);
149 ua->WarningMsg(
150 _("Deselecting slot %hd doesn't have wanted status.\n"),
151 vl->bareos_slot_number);
152 ClearBit(vl->bareos_slot_number - 1, slot_list);
153 break;
154 default:
155 break;
156 }
157 }
158 break;
159 default:
160 break;
161 }
162 }
163 }
164
165 /**
166 * See where a certain slot is referenced.
167 * For a drive slot we check the loaded variable
168 * and for all other slots the exact slotnr.
169 * We only check slots which have content.
170 */
find_slot_in_list(changer_vol_list_t * vol_list,slot_number_t slotnr)171 static inline vol_list_t* find_slot_in_list(changer_vol_list_t* vol_list,
172 slot_number_t slotnr)
173 {
174 vol_list_t* vl;
175
176 foreach_dlist (vl, vol_list->contents) {
177 switch (vl->slot_status) {
178 case slot_status_t::kSlotStatusFull:
179 switch (vl->slot_type) {
180 case slot_type_t::kSlotTypeDrive:
181 if (vl->currently_loaded_slot_number == slotnr) { return vl; }
182 break;
183 default:
184 if (vl->bareos_slot_number == slotnr) { return vl; }
185 break;
186 }
187 break;
188 default:
189 continue;
190 }
191 }
192 return NULL;
193 }
194
195 /**
196 * Check if a source and destination slot list overlap.
197 * An overlap is solved when there is a slot enabled
198 * in either the source or destination slot list before
199 * the overlap is detected. e.g. then on a move the volume
200 * is first moved somewhere else before either the source
201 * or destination slot is referenced by the next operation.
202 * Then again it wise not to perform to crazy operations
203 * as we will cancel any crazy-ness as soon as we encounter
204 * it.
205 */
slot_lists_overlap(char * src_slot_list,char * dst_slot_list,slot_number_t max_slots)206 static inline bool slot_lists_overlap(char* src_slot_list,
207 char* dst_slot_list,
208 slot_number_t max_slots)
209 {
210 slot_number_t i;
211 bool other_slot_enabled = false;
212
213 for (i = 0; i < max_slots; i++) {
214 /*
215 * See if both the source and destination slot are selected
216 * and there has not been a source or destination slot
217 * which has been selected before.
218 */
219 if (BitIsSet(i, src_slot_list) && BitIsSet(i, dst_slot_list) &&
220 !other_slot_enabled) {
221 Dmsg0(100,
222 "Found slot enabled in either source or destination selection "
223 "which overlap\n");
224 return true;
225 } else {
226 if (BitIsSet(i, src_slot_list) || BitIsSet(i, dst_slot_list)) {
227 Dmsg0(100,
228 "Found slot enabled in either source or destination selection\n");
229 other_slot_enabled = true;
230 }
231 }
232 }
233 Dmsg0(100,
234 "Found no slot enabled in either source or destination selection which "
235 "overlap\n");
236 return false;
237 }
238
239 /**
240 * Scan all slots that are not empty for the exact volumename
241 * by reading the label of the volume replacing the scanned
242 * barcode when available. When a valid source slot list
243 * is given we only check the slots enabled in that slot list.
244 * We return an updated changer_vol_list_t with the new content
245 * of the autochanger after the scan as that may move some
246 * volumes around. We free the old list and return the new.
247 */
scan_slots_for_volnames(UaContext * ua,StorageResource * store,drive_number_t drive,changer_vol_list_t * vol_list,char * src_slot_list)248 static inline changer_vol_list_t* scan_slots_for_volnames(
249 UaContext* ua,
250 StorageResource* store,
251 drive_number_t drive,
252 changer_vol_list_t* vol_list,
253 char* src_slot_list)
254 {
255 changer_vol_list_t* new_vol_list;
256 vol_list_t vls;
257 vol_list_t *vl1, *vl2;
258
259 /*
260 * Walk the list of drives and slots available.
261 */
262 foreach_dlist (vl1, vol_list->contents) {
263 switch (vl1->slot_type) {
264 case slot_type_t::kSlotTypeDrive:
265 continue;
266 default:
267 /*
268 * See if a slot list selection was done and
269 * if so only get the content for this slot when
270 * it is selected in the slot list.
271 */
272 if (src_slot_list &&
273 !BitIsSet(vl1->bareos_slot_number - 1, src_slot_list)) {
274 continue;
275 }
276
277 switch (vl1->slot_status) {
278 case slot_status_t::kSlotStatusFull:
279 if (vl1->VolName) {
280 free(vl1->VolName);
281 vl1->VolName = NULL;
282 }
283 vl1->VolName =
284 get_volume_name_from_SD(ua, vl1->bareos_slot_number, drive);
285 Dmsg2(100, "Got Vol=%s from SD for Slot=%hd\n", vl1->VolName,
286 vl1->bareos_slot_number);
287 break;
288 case slot_status_t::kSlotStatusEmpty:
289 /*
290 * See if the slot is empty because the volume is
291 * loaded in a drive.
292 */
293 if (vl1->slot_type == slot_type_t::kSlotTypeStorage &&
294 (vl2 = vol_is_loaded_in_drive(
295 store, vol_list, vl1->bareos_slot_number)) != NULL) {
296 if (vl2->VolName) {
297 free(vl2->VolName);
298 vl2->VolName = NULL;
299 }
300 vl2->VolName =
301 get_volume_name_from_SD(ua, vl1->bareos_slot_number, drive);
302 Dmsg2(100, "Got Vol=%s from SD for Slot=%hd\n", vl2->VolName,
303 vl1->bareos_slot_number);
304 }
305 break;
306 default:
307 continue;
308 }
309 break;
310 }
311 }
312
313 /*
314 * As the scan for volumes can alter the location of
315 * the volumes in the autochanger e.g. volumes in drives
316 * being put back into slots etc we rescan the changer.
317 */
318 new_vol_list = get_vol_list_from_storage(ua, store, true /* listall */,
319 true /* want to see all slots */,
320 false /* non cached list */);
321 if (!new_vol_list) {
322 /*
323 * Free the old vol_list and return a NULL vol_list.
324 */
325 StorageFreeVolList(store, vol_list);
326 return NULL;
327 }
328
329 /*
330 * Walk the list of drives and slots available.
331 * And copy the new scanned volume names from the old list
332 * to the new list.
333 *
334 * This is optimized for the case the slots are still
335 * filled with the same volume.
336 */
337 foreach_dlist (vl1, new_vol_list->contents) {
338 switch (vl1->slot_type) {
339 case slot_type_t::kSlotTypeDrive:
340 switch (vl1->slot_status) {
341 case slot_status_t::kSlotStatusFull:
342 /*
343 * Lookup the drive in the old list.
344 */
345 vls.element_address = vl1->element_address;
346 vl2 = (vol_list_t*)vol_list->contents->binary_search(
347 (void*)&vls, StorageCompareVolListEntry);
348 if (vl2 && vl2->slot_status == slot_status_t::kSlotStatusFull &&
349 vl2->currently_loaded_slot_number ==
350 vl1->currently_loaded_slot_number) {
351 /*
352 * Volume in drive is the same copy the volume name.
353 */
354 if (vl2->VolName) { free(vl2->VolName); }
355 vl2->VolName = vl1->VolName;
356 vl1->VolName = NULL;
357 } else {
358 /*
359 * Drive is loaded with a volume which was previously
360 * loaded somewhere else. Lookup the currently loaded
361 * volume in the old list.
362 */
363 vl2 = find_slot_in_list(vol_list,
364 vl1->currently_loaded_slot_number);
365 if (vl2) {
366 if (vl2->VolName) { free(vl2->VolName); }
367 vl2->VolName = vl1->VolName;
368 vl1->VolName = NULL;
369 }
370 }
371 break;
372 default:
373 continue;
374 }
375 break;
376 case slot_type_t::kSlotTypeStorage:
377 case slot_type_t::kSlotTypeImport:
378 /*
379 * See if a slot list selection was done and
380 * if so only get the content for this slot when
381 * it is selected in the slot list.
382 */
383 if (src_slot_list &&
384 !BitIsSet(vl1->bareos_slot_number - 1, src_slot_list)) {
385 continue;
386 }
387 switch (vl1->slot_status) {
388 case slot_status_t::kSlotStatusFull:
389 /*
390 * Lookup the slot in the old list.
391 */
392 vls.element_address = vl1->element_address;
393 vl2 = (vol_list_t*)vol_list->contents->binary_search(
394 (void*)&vls, StorageCompareVolListEntry);
395 if (vl2 && vl2->slot_status == slot_status_t::kSlotStatusFull &&
396 vl2->bareos_slot_number == vl1->bareos_slot_number) {
397 /*
398 * Volume in slot is the same copy the volume name.
399 */
400 if (vl2->VolName) { free(vl2->VolName); }
401 vl2->VolName = vl1->VolName;
402 vl1->VolName = NULL;
403 } else {
404 /*
405 * This should never happen as a volume is always put back
406 * into the same slot it was taken from. But as we have the
407 * code to lookup the old place we take a shot at it.
408 */
409 vl2 = find_slot_in_list(vol_list, vl1->bareos_slot_number);
410 if (vl2) {
411 if (vl2->VolName) { free(vl2->VolName); }
412 vl2->VolName = vl1->VolName;
413 vl1->VolName = NULL;
414 }
415 }
416 break;
417 default:
418 continue;
419 }
420 break;
421 default:
422 break;
423 }
424 }
425
426 /*
427 * Free the old vol_list and return the new data.
428 */
429 StorageFreeVolList(store, vol_list);
430 return new_vol_list;
431 }
432
433 /**
434 * Convert a volume name into a slot selection.
435 */
get_slot_list_using_volname(UaContext * ua,StorageResource * store,const char * volumename,changer_vol_list_t * vol_list,char * wanted_slot_list,char * selected_slot_list,slot_number_t max_slots)436 static inline bool get_slot_list_using_volname(UaContext* ua,
437 StorageResource* store,
438 const char* volumename,
439 changer_vol_list_t* vol_list,
440 char* wanted_slot_list,
441 char* selected_slot_list,
442 slot_number_t max_slots)
443 {
444 vol_list_t *vl1, *vl2;
445 bool found = false;
446
447 if (IsNameValid(volumename)) {
448 foreach_dlist (vl1, vol_list->contents) {
449 /*
450 * We only select normal and import/export slots.
451 */
452 switch (vl1->slot_type) {
453 case slot_type_t::kSlotTypeStorage:
454 case slot_type_t::kSlotTypeImport:
455 /*
456 * When the source slot list is limited we check to
457 * see if this slot should be taken into consideration.
458 */
459 if (wanted_slot_list &&
460 !BitIsSet(vl1->bareos_slot_number - 1, wanted_slot_list)) {
461 continue;
462 }
463
464 switch (vl1->slot_status) {
465 case slot_status_t::kSlotStatusFull:
466 /*
467 * See if the wanted volume is loaded in this slot.
468 */
469 Dmsg3(
470 100,
471 "Checking for volume name in slot %hd, wanted %s, found %s\n",
472 vl1->bareos_slot_number, volumename,
473 (vl1->VolName) ? vl1->VolName : "NULL");
474 if (vl1->VolName && bstrcmp(vl1->VolName, volumename)) {
475 found = true;
476 }
477 break;
478 case slot_status_t::kSlotStatusEmpty:
479 /*
480 * See if this slot is loaded in drive and drive contains wanted
481 * volume
482 */
483 vl2 = vol_is_loaded_in_drive(store, vol_list,
484 vl1->bareos_slot_number);
485 if (vl2 != NULL) {
486 Dmsg3(100,
487 "Checking for volume name in drive %hd, wanted %s, found "
488 "%s\n",
489 vl2->bareos_slot_number, volumename,
490 (vl2->VolName) ? vl2->VolName : "NULL");
491 if (vl2->VolName && bstrcmp(vl2->VolName, volumename)) {
492 found = true;
493 }
494 } else {
495 Dmsg1(100, "Skipping empty slot %hd\n",
496 vl1->bareos_slot_number);
497 }
498 break;
499 default:
500 break;
501 }
502 break;
503 default:
504 break;
505 }
506
507 /*
508 * If we found a match break the loop.
509 */
510 if (found) { break; }
511 }
512
513 /*
514 * See if we found the wanted volumename in the list
515 * of available slots in the autochanger and mark the
516 * slot in the slot_list or give a warning when the
517 * volumename was not found.
518 */
519 if (found) {
520 SetBit(vl1->bareos_slot_number - 1, selected_slot_list);
521 } else {
522 Dmsg1(100, "No volume named %s in changer or in selected source slots.\n",
523 volumename);
524 ua->WarningMsg(
525 _("No volume named %s in changer or in selected source slots.\n"),
526 volumename);
527 }
528 } else {
529 Dmsg1(100, "Skipping illegal volumename %s.\n", volumename);
530 ua->WarningMsg(_("Skipping illegal volumename %s.\n"), volumename);
531 }
532
533 return found;
534 }
535
536 /**
537 * Convert a number of volume names into a slot selection.
538 */
get_slot_list_using_volnames(UaContext * ua,StorageResource * store,int arg,changer_vol_list_t * vol_list,char * wanted_slot_list,char * selected_slot_list,slot_number_t max_slots)539 static inline slot_number_t get_slot_list_using_volnames(
540 UaContext* ua,
541 StorageResource* store,
542 int arg,
543 changer_vol_list_t* vol_list,
544 char* wanted_slot_list,
545 char* selected_slot_list,
546 slot_number_t max_slots)
547 {
548 slot_number_t i;
549 slot_number_t cnt = 0;
550 char *s, *token, *sep;
551
552 /*
553 * The arg argument contains the index of the first occurence
554 * of the volume keyword. We scan the whole cmdline for one
555 * or more volume= cmdline parameters.
556 */
557 for (i = arg; i < ua->argc; i++) {
558 if (Bstrcasecmp(ua->argk[i], "volume")) {
559 /*
560 * Parse a volumelist e.g. vol1|vol2 and a single volume e.g. vol1
561 */
562 s = strdup(ua->argv[i]);
563 token = s;
564
565 /*
566 * We could use strtok() here. But we're not going to, because:
567 * (a) strtok() is deprecated, having been replaced by strsep();
568 * (b) strtok() is broken in significant ways.
569 * we could use strsep() instead, but it's not universally available.
570 * so we grow our own using strchr().
571 */
572 sep = strchr(token, '|');
573 while (sep != NULL) {
574 *sep = '\0';
575 if (get_slot_list_using_volname(ua, store, token, vol_list,
576 wanted_slot_list, selected_slot_list,
577 max_slots)) {
578 cnt++;
579 }
580 token = ++sep;
581 sep = strchr(token, '|');
582 }
583
584 /*
585 * Pick up the last token.
586 */
587 if (*token) {
588 if (get_slot_list_using_volname(ua, store, token, vol_list,
589 wanted_slot_list, selected_slot_list,
590 max_slots)) {
591 cnt++;
592 }
593 }
594
595 free(s);
596 }
597 }
598 return cnt;
599 }
600
601 /**
602 * Create a slot list selection based on the slot type
603 * and slot content. All slots which have the wanted
604 * slot type and wanted slot content are selected.
605 */
auto_fill_slot_selection(StorageResource * store,changer_vol_list_t * vol_list,char * slot_list,slot_type_t type,slot_status_t content)606 static inline slot_number_t auto_fill_slot_selection(
607 StorageResource* store,
608 changer_vol_list_t* vol_list,
609 char* slot_list,
610 slot_type_t type,
611 slot_status_t content)
612 {
613 slot_number_t cnt = 0;
614 vol_list_t* vl;
615
616 /*
617 * Walk the list of drives and slots available.
618 */
619 foreach_dlist (vl, vol_list->contents) {
620 /*
621 * Make sure slot_type and slot_status match.
622 */
623 if (vl->slot_type != type || vl->slot_status != content) {
624 Dmsg3(100, "Skipping slot %hd, Type %hd, Content %hd\n",
625 vl->bareos_slot_number, vl->slot_type, vl->slot_status);
626 continue;
627 }
628
629 /*
630 * If the slot is empty and this is normal slot
631 * make sure its not loaded in a drive because
632 * then the slot is not really empty.
633 */
634 if (type == slot_type_t::kSlotTypeStorage &&
635 content == slot_status_t::kSlotStatusEmpty &&
636 vol_is_loaded_in_drive(store, vol_list, vl->bareos_slot_number) !=
637 NULL) {
638 Dmsg3(100,
639 "Skipping slot %hd, Type %hd, Content %hd is empty but loaded in "
640 "drive\n",
641 vl->bareos_slot_number, vl->slot_type, vl->slot_status);
642 continue;
643 }
644
645 /*
646 * Mark the slot as selected in the slot list.
647 * And increase the number of slots selected.
648 */
649 Dmsg3(100,
650 "Selected slot %hd which has slot_type %hd and content_type %hd\n",
651 vl->bareos_slot_number, vl->slot_type, vl->slot_status);
652 SetBit(vl->bareos_slot_number - 1, slot_list);
653 cnt++;
654 }
655 return cnt;
656 }
657
658 /**
659 * Verify if all slots in the given slot list are of a certain
660 * type and have a given content.
661 */
verify_slot_list(StorageResource * store,changer_vol_list_t * vol_list,char * slot_list,slot_type_t type,slot_status_t content)662 static inline bool verify_slot_list(StorageResource* store,
663 changer_vol_list_t* vol_list,
664 char* slot_list,
665 slot_type_t type,
666 slot_status_t content)
667 {
668 vol_list_t* vl;
669
670 /*
671 * Walk the list of drives and slots available.
672 */
673 foreach_dlist (vl, vol_list->contents) {
674 /*
675 * Move operations are only allowed between
676 * normal slots and import/export slots so
677 * don't consider any other slot type.
678 */
679 switch (vl->slot_type) {
680 case slot_type_t::kSlotTypeStorage:
681 case slot_type_t::kSlotTypeImport:
682 if (BitIsSet(vl->bareos_slot_number - 1, slot_list)) {
683 /*
684 * If the type and content is ok we can continue with the next one.
685 */
686 if (vl->slot_type == type && vl->slot_status == content) { continue; }
687
688 /*
689 * When the content is not the wanted and this is a normal
690 * slot take into consideration if its loaded into the drive.
691 * When we are asked for an empty slot it should NOT be loaded
692 * in the drive but when we are asked for a full slot it being
693 * loaded in the drive also makes that the slot is filled as
694 * we can just release the drive so that its put back into
695 * the slot and then moved.
696 */
697 if (vl->slot_type == slot_type_t::kSlotTypeStorage) {
698 switch (content) {
699 case slot_status_t::kSlotStatusEmpty:
700 if (vol_is_loaded_in_drive(store, vol_list,
701 vl->bareos_slot_number) != NULL) {
702 Dmsg3(100,
703 "Skipping slot %hd, Type %hd, Content %hd is empty but "
704 "loaded in drive\n",
705 vl->bareos_slot_number, vl->slot_type, vl->slot_status);
706 return false;
707 }
708 break;
709 case slot_status_t::kSlotStatusFull:
710 if (vol_is_loaded_in_drive(store, vol_list,
711 vl->bareos_slot_number) != NULL) {
712 continue;
713 }
714 break;
715 default:
716 break;
717 }
718 }
719
720 /*
721 * Not the wanted type or content and not a special case.
722 */
723 Dmsg3(100, "Skipping slot %hd, Type %hd, Content %hd\n",
724 vl->bareos_slot_number, vl->slot_type, vl->slot_status);
725 return false;
726 }
727 break;
728 default:
729 break;
730 }
731 }
732 return true;
733 }
734
735 /**
736 * Perform an internal update of our view of the autochanger on a move
737 * instruction without requesting the new status from the SD again.
738 */
update_internal_slot_list(changer_vol_list_t * vol_list,slot_number_t source,slot_number_t destination)739 static inline bool update_internal_slot_list(changer_vol_list_t* vol_list,
740 slot_number_t source,
741 slot_number_t destination)
742 {
743 bool found;
744 vol_list_t *vl1, *vl2;
745
746 /*
747 * First lookup the source and destination slots in the vol_list.
748 */
749 found = false;
750 foreach_dlist (vl1, vol_list->contents) {
751 switch (vl1->slot_type) {
752 case slot_type_t::kSlotTypeDrive:
753 continue;
754 default:
755 if (vl1->bareos_slot_number == source) { found = true; }
756 break;
757 }
758 if (found) { break; }
759 }
760
761 found = false;
762 foreach_dlist (vl2, vol_list->contents) {
763 switch (vl2->slot_type) {
764 case slot_type_t::kSlotTypeDrive:
765 continue;
766 default:
767 if (vl2->bareos_slot_number == destination) { found = true; }
768 break;
769 }
770 if (found) { break; }
771 }
772
773 if (vl1 && vl2) {
774 /*
775 * Swap the data.
776 */
777 vl2->VolName = vl1->VolName;
778 vl2->slot_status = slot_status_t::kSlotStatusFull;
779 vl1->VolName = NULL;
780 vl1->slot_status = slot_status_t::kSlotStatusEmpty;
781 Dmsg5(100,
782 "Update internal slotlist slot %hd with volname %s, content %hd and "
783 "slot %hd with content %hd and volname NULL\n",
784 vl2->bareos_slot_number, (vl2->VolName) ? vl2->VolName : "NULL",
785 vl2->slot_status, vl1->bareos_slot_number, vl1->slot_status);
786 return true;
787 }
788 return false;
789 }
790
791 /**
792 * Unload a volume currently loaded in a drive.
793 */
release_loaded_volume(UaContext * ua,StorageResource * store,drive_number_t drive,changer_vol_list_t * vol_list)794 static bool release_loaded_volume(UaContext* ua,
795 StorageResource* store,
796 drive_number_t drive,
797 changer_vol_list_t* vol_list)
798 {
799 bool found;
800 vol_list_t *vl1, *vl2;
801
802 if (!DoAutochangerVolumeOperation(ua, store, "release", drive, -1)) {
803 return false;
804 }
805
806 /*
807 * Lookup the drive in the vol_list.
808 */
809 found = false;
810 foreach_dlist (vl1, vol_list->contents) {
811 switch (vl1->slot_type) {
812 case slot_type_t::kSlotTypeDrive:
813 if (vl1->bareos_slot_number == drive) { found = true; }
814 break;
815 default:
816 break;
817 }
818 /*
819 * As drives are at the front of the list
820 * when we see the first non drive we are done.
821 */
822 if (found || vl1->slot_type != slot_type_t::kSlotTypeDrive) { break; }
823 }
824
825 /*
826 * Lookup the slot in the slotlist referenced by the loaded value in the drive
827 * slot.
828 */
829 found = false;
830 foreach_dlist (vl2, vol_list->contents) {
831 switch (vl2->slot_type) {
832 case slot_type_t::kSlotTypeDrive:
833 continue;
834 default:
835 if (vl2->bareos_slot_number == vl1->currently_loaded_slot_number) {
836 found = true;
837 }
838 break;
839 }
840 if (found) { break; }
841 }
842
843 if (vl1 && vl2) {
844 /*
845 * Swap the data.
846 */
847 vl2->VolName = vl1->VolName;
848 vl2->slot_status = slot_status_t::kSlotStatusFull;
849 vl1->VolName = NULL;
850 vl1->slot_status = slot_status_t::kSlotStatusEmpty;
851 vl1->currently_loaded_slot_number = 0;
852 Dmsg5(100,
853 "Update internal slotlist slot %hd with volname %s, content %hd and "
854 "slot %hd with content %hd and volname NULL\n",
855 vl2->bareos_slot_number, (vl2->VolName) ? vl2->VolName : "NULL",
856 vl2->slot_status, vl1->bareos_slot_number, vl1->slot_status);
857 return true;
858 }
859 return false;
860 }
861
862 /**
863 * Ask the autochanger to move volume from a source slot
864 * to a destination slot by walking the two filled
865 * slot lists and marking every visited slot.
866 */
move_volumes_in_autochanger(UaContext * ua,enum e_move_op operation,StorageResource * store,changer_vol_list_t * vol_list,char * src_slot_list,char * dst_slot_list,slot_number_t max_slots)867 static char* move_volumes_in_autochanger(UaContext* ua,
868 enum e_move_op operation,
869 StorageResource* store,
870 changer_vol_list_t* vol_list,
871 char* src_slot_list,
872 char* dst_slot_list,
873 slot_number_t max_slots)
874 {
875 vol_list_t* vl;
876 slot_number_t transfer_from, transfer_to;
877 char* visited_slot_list;
878 slot_number_t nr_enabled_src_slots, nr_enabled_dst_slots;
879
880 /*
881 * Sanity check.
882 */
883 nr_enabled_src_slots = count_enabled_slots(src_slot_list, max_slots);
884 nr_enabled_dst_slots = count_enabled_slots(dst_slot_list, max_slots);
885 if (nr_enabled_src_slots == 0 || nr_enabled_dst_slots == 0) {
886 ua->WarningMsg(_("Nothing to do\n"));
887 return NULL;
888 }
889
890 /*
891 * When doing an export we first set all slots in the database
892 * to inchanger = 0 so we cannot get surprises that a running
893 * backup can grab such a volume.
894 */
895 switch (operation) {
896 case VOLUME_EXPORT:
897 UpdateInchangerForExport(ua, store, vol_list, src_slot_list);
898 break;
899 default:
900 break;
901 }
902
903 /*
904 * Create an empty slot list in which we keep track of the slots
905 * we visited during this move operation so we can return that data
906 * to the caller which can use it to update only the slots updated
907 * by the move operation.
908 */
909 visited_slot_list = (char*)malloc(NbytesForBits(max_slots));
910 ClearAllBits(max_slots, visited_slot_list);
911
912 transfer_to = 1;
913 for (transfer_from = 1; transfer_from <= max_slots; transfer_from++) {
914 /*
915 * See if the slot is marked in the source slot list.
916 */
917 if (BitIsSet(transfer_from - 1, src_slot_list)) {
918 /*
919 * Search for the first marked slot in the destination selection.
920 */
921 while (transfer_to <= max_slots) {
922 if (BitIsSet(transfer_to - 1, dst_slot_list)) { break; }
923 transfer_to++;
924 }
925
926 /*
927 * This should never happen but a sanity check just in case.
928 */
929 if (transfer_to > max_slots) {
930 Dmsg0(100, "Failed to find suitable destination slot in slot range.\n");
931 ua->WarningMsg(
932 _("Failed to find suitable destination slot in slot range.\n"));
933 break;
934 }
935
936 /*
937 * Based on the operation see if we need to unload the drive.
938 */
939 switch (operation) {
940 case VOLUME_EXPORT:
941 /*
942 * Sanity check to see if the volume being exported is in the drive.
943 * If so we release the drive and then perform the actual move.
944 */
945 vl = vol_is_loaded_in_drive(store, vol_list, transfer_from);
946 if (vl != NULL) {
947 if (!release_loaded_volume(ua, store, vl->bareos_slot_number,
948 vol_list)) {
949 Dmsg1(100, "Failed to release volume in drive %hd\n",
950 vl->bareos_slot_number);
951 ua->WarningMsg(_("Failed to release volume in drive %hd\n"),
952 vl->bareos_slot_number);
953 continue;
954 }
955 }
956 break;
957 default:
958 break;
959 }
960
961 /*
962 * If we found a source and destination slot perform the move.
963 */
964 if (transfer_volume(ua, store, transfer_from, transfer_to)) {
965 Dmsg2(100,
966 "Successfully moved volume from source slot %hd to destination "
967 "slot %hd\n",
968 transfer_from, transfer_to);
969 update_internal_slot_list(vol_list, transfer_from, transfer_to);
970 SetBit(transfer_from - 1, visited_slot_list);
971 SetBit(transfer_to - 1, visited_slot_list);
972 } else {
973 Dmsg2(100,
974 "Failed to move volume from source slot %hd to destination slot "
975 "%hd\n",
976 transfer_from, transfer_to);
977 ua->WarningMsg(_("Failed to move volume from source slot %hd to "
978 "destination slot %hd\n"),
979 transfer_from, transfer_to);
980 switch (operation) {
981 case VOLUME_EXPORT:
982 /*
983 * For an export we always set the source slot as visited so when
984 * the move operation fails we update the inchanger flag in the
985 * database back to 1 so we know it still is in the changer.
986 */
987 SetBit(transfer_from - 1, visited_slot_list);
988 break;
989 default:
990 break;
991 }
992 }
993 transfer_to++;
994 }
995 }
996
997 return visited_slot_list;
998 }
999
1000 /**
1001 * Perform the actual move operation which is either a:
1002 * - import of import slots into normal slots
1003 * - export of normal slots into export slots
1004 * - move from one normal slot to another normal slot
1005 */
PerformMoveOperation(UaContext * ua,enum e_move_op operation)1006 static bool PerformMoveOperation(UaContext* ua, enum e_move_op operation)
1007 {
1008 bool scan;
1009 UnifiedStorageResource store;
1010 changer_vol_list_t* vol_list;
1011 char *src_slot_list = NULL, *dst_slot_list = NULL, *tmp_slot_list = NULL,
1012 *visited_slot_list = NULL;
1013 slot_number_t nr_enabled_src_slots = 0, nr_enabled_dst_slots = 0;
1014 drive_number_t drive = kInvalidDriveNumber;
1015 slot_number_t max_slots;
1016 int list_index;
1017 bool retval = false;
1018
1019 store.store = get_storage_resource(ua, false, true);
1020 if (!store.store) { return retval; }
1021
1022 PmStrcpy(store.store_source, _("command line"));
1023 SetWstorage(ua->jcr, &store);
1024
1025 /*
1026 * See if the scan option was given.
1027 * We need a drive for the scanning so ask if
1028 * the scan option was specified.
1029 */
1030 scan = FindArg(ua, NT_("scan")) >= 0;
1031 if (scan) { drive = GetStorageDrive(ua, store.store); }
1032
1033 /*
1034 * Get the number of slots in the autochanger for
1035 * sizing the slot lists.
1036 */
1037 max_slots = GetNumSlots(ua, store.store);
1038 if (max_slots <= 0) {
1039 ua->WarningMsg(_("No slots in changer.\n"));
1040 return retval;
1041 }
1042
1043 /*
1044 * Get the current content of the autochanger for
1045 * validation and selection purposes.
1046 */
1047 vol_list = get_vol_list_from_storage(ua, store.store, true /* listall */,
1048 true /* want to see all slots */);
1049 if (!vol_list) {
1050 ua->WarningMsg(_("No Volumes found, or no barcodes.\n"));
1051 goto bail_out;
1052 }
1053
1054 /*
1055 * See if there are any source slot selections.
1056 */
1057 list_index = FindArgWithValue(ua, "srcslots");
1058 if (list_index < 0) { list_index = FindArgWithValue(ua, "srcslot"); }
1059 if (list_index >= 0) {
1060 src_slot_list = (char*)malloc(NbytesForBits(max_slots));
1061 ClearAllBits(max_slots, src_slot_list);
1062 if (!GetUserSlotList(ua, src_slot_list, "srcslots", max_slots)) {
1063 goto bail_out;
1064 } else {
1065 /*
1066 * See if we should scan slots for the correct
1067 * volume name or that we can use the barcodes.
1068 * If a set of src slots was given we only scan
1069 * the content of those slots.
1070 */
1071 if (scan) {
1072 vol_list = scan_slots_for_volnames(ua, store.store, drive, vol_list,
1073 src_slot_list);
1074 if (!vol_list) { goto bail_out; }
1075 }
1076
1077 /*
1078 * Clear any slot that has no content in the source selection.
1079 */
1080 validate_slot_list(ua, store.store, vol_list, src_slot_list,
1081 slot_status_t::kSlotStatusFull);
1082 nr_enabled_src_slots = count_enabled_slots(src_slot_list, max_slots);
1083 }
1084 } else {
1085 /*
1086 * See if we should scan slots for the correct
1087 * volume name or that we can use the barcodes.
1088 */
1089 if (scan) {
1090 vol_list = scan_slots_for_volnames(ua, store.store, drive, vol_list,
1091 src_slot_list);
1092 if (!vol_list) { goto bail_out; }
1093 }
1094 }
1095
1096 /*
1097 * See if there are any destination slot selections.
1098 */
1099 list_index = FindArgWithValue(ua, "dstslots");
1100 if (list_index < 0) { list_index = FindArgWithValue(ua, "dstslot"); }
1101 if (list_index >= 0) {
1102 dst_slot_list = (char*)malloc(NbytesForBits(max_slots));
1103 ClearAllBits(max_slots, dst_slot_list);
1104 if (!GetUserSlotList(ua, dst_slot_list, "dstslots", max_slots)) {
1105 goto bail_out;
1106 } else {
1107 /*
1108 * Clear any slot in the destination slot list which has not the wanted
1109 * content.
1110 */
1111 switch (operation) {
1112 case VOLUME_IMPORT:
1113 case VOLUME_EXPORT:
1114 validate_slot_list(ua, store.store, vol_list, dst_slot_list,
1115 slot_status_t::kSlotStatusEmpty);
1116 break;
1117 default:
1118 break;
1119 }
1120 nr_enabled_dst_slots = count_enabled_slots(dst_slot_list, max_slots);
1121 }
1122 }
1123
1124 /*
1125 * For Import and Export operations we can also use a list
1126 * of volume names for which we lookup the slot they are
1127 * loaded in.
1128 */
1129 switch (operation) {
1130 case VOLUME_IMPORT:
1131 case VOLUME_EXPORT:
1132 list_index = FindArgWithValue(ua, "volume");
1133 if (list_index > 0) {
1134 /*
1135 * Create a new temporary slot list with gets filled
1136 * by the selection criteria on the cmdline. We provide
1137 * the current src_slot_list as an extra selection criteria.
1138 */
1139 tmp_slot_list = (char*)malloc(NbytesForBits(max_slots));
1140 ClearAllBits(max_slots, tmp_slot_list);
1141 nr_enabled_src_slots = get_slot_list_using_volnames(
1142 ua, store.store, list_index, vol_list, src_slot_list, tmp_slot_list,
1143 max_slots);
1144 if (src_slot_list) { free(src_slot_list); }
1145 src_slot_list = tmp_slot_list;
1146 }
1147 break;
1148 default:
1149 break;
1150 }
1151
1152 Dmsg2(100, "src_slots = %hd, dst_slots = %hd\n", nr_enabled_src_slots,
1153 nr_enabled_dst_slots);
1154
1155 /*
1156 * First generic sanity check if there is a source selection the number
1157 * of selected slots in the source must be less or equal to the
1158 * number of slots in the destination
1159 */
1160 if (nr_enabled_src_slots && nr_enabled_dst_slots &&
1161 nr_enabled_src_slots > nr_enabled_dst_slots) {
1162 ua->WarningMsg(
1163 _("Source slot selection doesn't fit into destination slot "
1164 "selection.\n"));
1165 goto bail_out;
1166 }
1167
1168 /*
1169 * Detect any conflicting overlaps in source and destination selection.
1170 */
1171 if (nr_enabled_src_slots && nr_enabled_dst_slots &&
1172 slot_lists_overlap(src_slot_list, dst_slot_list, max_slots)) {
1173 ua->WarningMsg(
1174 _("Source slot selection and destination slot selection overlap.\n"));
1175 goto bail_out;
1176 }
1177
1178 /*
1179 * Operation specific checks.
1180 */
1181 switch (operation) {
1182 case VOLUME_EXPORT:
1183 if (nr_enabled_src_slots == 0) {
1184 ua->WarningMsg(
1185 _("Cannot perform an export operation without source slot "
1186 "selection\n"));
1187 goto bail_out;
1188 }
1189 break;
1190 case VOLUME_MOVE:
1191 if (nr_enabled_src_slots == 0 || nr_enabled_dst_slots == 0) {
1192 ua->WarningMsg(
1193 _("Cannot perform a move operation without source and/or "
1194 "destination selection\n"));
1195 goto bail_out;
1196 }
1197 break;
1198 default:
1199 break;
1200 }
1201
1202 switch (operation) {
1203 case VOLUME_IMPORT:
1204 /*
1205 * Perform an autofill of the source slots when none are selected.
1206 */
1207 if (nr_enabled_src_slots == 0) {
1208 src_slot_list = (char*)malloc(NbytesForBits(max_slots));
1209 ClearAllBits(max_slots, src_slot_list);
1210 nr_enabled_src_slots = auto_fill_slot_selection(
1211 store.store, vol_list, src_slot_list, slot_type_t::kSlotTypeImport,
1212 slot_status_t::kSlotStatusFull);
1213 } else {
1214 /*
1215 * All slots in the source selection need to be import/export slots and
1216 * filled.
1217 */
1218 if (!verify_slot_list(store.store, vol_list, src_slot_list,
1219 slot_type_t::kSlotTypeImport,
1220 slot_status_t::kSlotStatusFull)) {
1221 ua->WarningMsg(
1222 _("Not all slots in source selection are import slots and "
1223 "filled.\n"));
1224 goto bail_out;
1225 }
1226 }
1227 /*
1228 * Perform an autofill of the destination slots when none are selected.
1229 */
1230 if (nr_enabled_dst_slots == 0) {
1231 dst_slot_list = (char*)malloc(NbytesForBits(max_slots));
1232 ClearAllBits(max_slots, dst_slot_list);
1233 nr_enabled_dst_slots = auto_fill_slot_selection(
1234 store.store, vol_list, dst_slot_list, slot_type_t::kSlotTypeStorage,
1235 slot_status_t::kSlotStatusEmpty);
1236 if (nr_enabled_src_slots > nr_enabled_dst_slots) {
1237 ua->WarningMsg(
1238 _("Not enough free slots available to import %hd volumes\n"),
1239 nr_enabled_src_slots);
1240 goto bail_out;
1241 }
1242 } else {
1243 /*
1244 * All slots in the destination selection need to be normal slots and
1245 * empty.
1246 */
1247 if (!verify_slot_list(store.store, vol_list, dst_slot_list,
1248 slot_type_t::kSlotTypeStorage,
1249 slot_status_t::kSlotStatusEmpty)) {
1250 ua->WarningMsg(
1251 _("Not all slots in destination selection are normal slots and "
1252 "empty.\n"));
1253 goto bail_out;
1254 }
1255 }
1256 visited_slot_list =
1257 move_volumes_in_autochanger(ua, operation, store.store, vol_list,
1258 src_slot_list, dst_slot_list, max_slots);
1259 break;
1260 case VOLUME_EXPORT:
1261 /*
1262 * All slots in the source selection need to be normal slots.
1263 */
1264 if (!verify_slot_list(store.store, vol_list, src_slot_list,
1265 slot_type_t::kSlotTypeStorage,
1266 slot_status_t::kSlotStatusFull)) {
1267 ua->WarningMsg(
1268 _("Not all slots in source selection are normal slots and "
1269 "filled.\n"));
1270 goto bail_out;
1271 }
1272 /*
1273 * Perform an autofill of the destination slots when none are selected.
1274 */
1275 if (nr_enabled_dst_slots == 0) {
1276 dst_slot_list = (char*)malloc(NbytesForBits(max_slots));
1277 ClearAllBits(max_slots, dst_slot_list);
1278 nr_enabled_dst_slots = auto_fill_slot_selection(
1279 store.store, vol_list, dst_slot_list, slot_type_t::kSlotTypeImport,
1280 slot_status_t::kSlotStatusEmpty);
1281 if (nr_enabled_src_slots > nr_enabled_dst_slots) {
1282 ua->WarningMsg(_("Not enough free export slots available to export "
1283 "%hd volume%s\n"),
1284 nr_enabled_src_slots,
1285 nr_enabled_src_slots > 1 ? "s" : "");
1286 goto bail_out;
1287 }
1288 } else {
1289 /*
1290 * All slots in the destination selection need to be import/export slots
1291 * and empty.
1292 */
1293 if (!verify_slot_list(store.store, vol_list, dst_slot_list,
1294 slot_type_t::kSlotTypeImport,
1295 slot_status_t::kSlotStatusEmpty)) {
1296 ua->WarningMsg(
1297 _("Not all slots in destination selection are export slots and "
1298 "empty.\n"));
1299 goto bail_out;
1300 }
1301 }
1302 visited_slot_list =
1303 move_volumes_in_autochanger(ua, operation, store.store, vol_list,
1304 src_slot_list, dst_slot_list, max_slots);
1305 break;
1306 case VOLUME_MOVE:
1307 visited_slot_list =
1308 move_volumes_in_autochanger(ua, operation, store.store, vol_list,
1309 src_slot_list, dst_slot_list, max_slots);
1310 break;
1311 default:
1312 break;
1313 }
1314
1315 /*
1316 * If we actually moved some volumes update the database with the
1317 * new info for those slots.
1318 */
1319 if (visited_slot_list &&
1320 count_enabled_slots(visited_slot_list, max_slots) > 0) {
1321 Dmsg0(100, "Updating database with new info for visited slots\n");
1322 UpdateSlotsFromVolList(ua, store.store, vol_list, visited_slot_list);
1323 }
1324
1325 retval = true;
1326
1327 bail_out:
1328 CloseSdBsock(ua);
1329
1330 if (vol_list) { StorageReleaseVolList(store.store, vol_list); }
1331 if (src_slot_list) { free(src_slot_list); }
1332 if (dst_slot_list) { free(dst_slot_list); }
1333 if (visited_slot_list) { free(visited_slot_list); }
1334
1335 return retval;
1336 }
1337
1338 /**
1339 * Import volumes from Import/Export Slots into normal Slots.
1340 */
ImportCmd(UaContext * ua,const char * cmd)1341 bool ImportCmd(UaContext* ua, const char* cmd)
1342 {
1343 return PerformMoveOperation(ua, VOLUME_IMPORT);
1344 }
1345
1346 /**
1347 * Export volumes from normal slots to Import/Export Slots.
1348 */
ExportCmd(UaContext * ua,const char * cmd)1349 bool ExportCmd(UaContext* ua, const char* cmd)
1350 {
1351 return PerformMoveOperation(ua, VOLUME_EXPORT);
1352 }
1353
1354 /**
1355 * Move volume from one slot to another.
1356 */
move_cmd(UaContext * ua,const char * cmd)1357 bool move_cmd(UaContext* ua, const char* cmd)
1358 {
1359 return PerformMoveOperation(ua, VOLUME_MOVE);
1360 }
1361 } /* namespace directordaemon */
1362