1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2002-2010 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2016 Planets Communications B.V.
6 Copyright (C) 2013-2016 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, July 2002
25 */
26 /**
27 * @file
28 * Bootstrap routines.
29 */
30
31 #include "include/bareos.h"
32 #include "dird.h"
33 #include "dird/dird_globals.h"
34 #include "dird/jcr_private.h"
35 #include "dird/ua_input.h"
36 #include "dird/ua_restore.h"
37 #include "dird/ua_server.h"
38 #include "dird/ua_select.h"
39 #include "lib/berrno.h"
40 #include "lib/edit.h"
41 #include "lib/parse_conf.h"
42 #include "include/make_unique.h"
43
44 #include <algorithm>
45
46 namespace directordaemon {
47
48 #define UA_CMD_SIZE 1000
49
RestoreBootstrapRecord()50 RestoreBootstrapRecord::RestoreBootstrapRecord()
51 {
52 fi = std::make_unique<RestoreBootstrapRecordFileIndex>();
53 }
54
RestoreBootstrapRecord(JobId_t t_JobId)55 RestoreBootstrapRecord::RestoreBootstrapRecord(JobId_t t_JobId)
56 : RestoreBootstrapRecord::RestoreBootstrapRecord()
57 {
58 JobId = t_JobId;
59 }
60
~RestoreBootstrapRecord()61 RestoreBootstrapRecord::~RestoreBootstrapRecord()
62 {
63 if (VolParams) { free(VolParams); }
64 if (fileregex) { free(fileregex); }
65 }
66
Add(int32_t findex)67 void RestoreBootstrapRecordFileIndex::Add(int32_t findex)
68 {
69 if (findex == 0) { return; /* probably a dummy directory */ }
70 fileIds_.push_back(findex);
71 sorted_ = false;
72 }
73
AddAll()74 void RestoreBootstrapRecordFileIndex::AddAll() { allFiles_ = true; }
Sort()75 void RestoreBootstrapRecordFileIndex::Sort()
76 {
77 if (sorted_) return;
78
79 if (!std::is_sorted(fileIds_.begin(), fileIds_.end())) {
80 std::sort(fileIds_.begin(), fileIds_.end());
81 }
82 sorted_ = true;
83 }
84
85 std::vector<std::pair<int32_t, int32_t>>
GetRanges()86 RestoreBootstrapRecordFileIndex::GetRanges()
87 {
88 if (allFiles_) {
89 return std::vector<std::pair<int32_t, int32_t>>{
90 std::make_pair(1, INT32_MAX)};
91 } else {
92 Sort();
93
94 auto ranges = std::vector<std::pair<int32_t, int32_t>>{};
95 auto begin = int32_t{0};
96 auto end = int32_t{0};
97
98 for (auto fileId : fileIds_) {
99 if (begin == 0) {
100 begin = end = fileId;
101 } else if (fileId > end + 1) {
102 ranges.push_back(std::make_pair(begin, end));
103 begin = end = fileId;
104 } else {
105 end = fileId;
106 }
107 }
108 ranges.push_back(std::make_pair(begin, end));
109 return ranges;
110 }
111 }
112
113 /**
114 * Get storage device name from Storage resource
115 */
GetStorageDevice(char * device,char * storage)116 static bool GetStorageDevice(char* device, char* storage)
117 {
118 StorageResource* store;
119 if (storage[0] == 0) { return false; }
120 store = (StorageResource*)my_config->GetResWithName(R_STORAGE, storage);
121 if (!store) { return false; }
122 DeviceResource* dev = (DeviceResource*)(store->device->first());
123 if (!dev) { return false; }
124 bstrncpy(device, dev->resource_name_, MAX_NAME_LENGTH);
125 return true;
126 }
127
128 /**
129 * Print a BootStrapRecord entry into a memory buffer.
130 */
PrintBsrItem(std::string & buffer,const char * fmt,...)131 static void PrintBsrItem(std::string& buffer, const char* fmt, ...)
132 {
133 va_list arg_ptr;
134 int len, maxlen;
135 PoolMem item(PM_MESSAGE);
136
137 while (1) {
138 maxlen = item.MaxSize() - 1;
139 va_start(arg_ptr, fmt);
140 len = Bvsnprintf(item.c_str(), maxlen, fmt, arg_ptr);
141 va_end(arg_ptr);
142 if (len < 0 || len >= (maxlen - 5)) {
143 item.ReallocPm(maxlen + maxlen / 2);
144 continue;
145 }
146 break;
147 }
148
149 buffer += item.c_str();
150 }
151
152 /**
153 * Our data structures were not designed completely
154 * correctly, so the file indexes cover the full
155 * range regardless of volume. The FirstIndex and LastIndex
156 * passed in here are for the current volume, so when
157 * writing out the fi, constrain them to those values.
158 *
159 * We are called here once for each JobMedia record
160 * for each Volume.
161 */
write_findex(RestoreBootstrapRecordFileIndex * fi,int32_t FirstIndex,int32_t LastIndex,std::string & buffer)162 uint32_t write_findex(RestoreBootstrapRecordFileIndex* fi,
163 int32_t FirstIndex,
164 int32_t LastIndex,
165 std::string& buffer)
166 {
167 auto count = uint32_t{0};
168 auto bsrItems = std::string{};
169
170 for (auto& range : fi->GetRanges()) {
171 auto first = range.first;
172 auto last = range.second;
173 if ((first >= FirstIndex && first <= LastIndex) ||
174 (last >= FirstIndex && last <= LastIndex) ||
175 (first < FirstIndex && last > LastIndex)) {
176 first = std::max(first, FirstIndex);
177 last = std::min(last, LastIndex);
178
179 if (first == last) {
180 bsrItems += "FileIndex=" + std::to_string(first) + "\n";
181 count++;
182 } else {
183 bsrItems += "FileIndex=" + std::to_string(first) + "-" +
184 std::to_string(last) + "\n";
185 count += last - first + 1;
186 }
187 }
188 }
189 buffer += bsrItems.c_str();
190 return count;
191 }
192
193 /**
194 * Find out if Volume defined with FirstIndex and LastIndex
195 * falls within the range of selected files in the bsr.
196 */
is_volume_selected(RestoreBootstrapRecordFileIndex * fi,int32_t FirstIndex,int32_t LastIndex)197 static inline bool is_volume_selected(RestoreBootstrapRecordFileIndex* fi,
198 int32_t FirstIndex,
199 int32_t LastIndex)
200 {
201 for (auto range : fi->GetRanges()) {
202 auto first = range.first;
203 auto last = range.second;
204 if ((first >= FirstIndex && first <= LastIndex) ||
205 (last >= FirstIndex && last <= LastIndex) ||
206 (first < FirstIndex && last > LastIndex)) {
207 return true;
208 }
209 }
210 return false;
211 }
212
213
214 /**
215 * Complete the BootStrapRecord by filling in the VolumeName and
216 * VolSessionId and VolSessionTime using the JobId
217 */
AddVolumeInformationToBsr(UaContext * ua,RestoreBootstrapRecord * bsr)218 bool AddVolumeInformationToBsr(UaContext* ua, RestoreBootstrapRecord* bsr)
219 {
220 for (; bsr; bsr = bsr->next.get()) {
221 JobDbRecord jr;
222 jr.JobId = bsr->JobId;
223 if (!ua->db->GetJobRecord(ua->jcr, &jr)) {
224 ua->ErrorMsg(_("Unable to get Job record. ERR=%s\n"), ua->db->strerror());
225 return false;
226 }
227 bsr->VolSessionId = jr.VolSessionId;
228 bsr->VolSessionTime = jr.VolSessionTime;
229 if (jr.JobFiles == 0) { /* zero files is OK, not an error, but */
230 bsr->VolCount = 0; /* there are no volumes */
231 continue;
232 }
233 if ((bsr->VolCount = ua->db->GetJobVolumeParameters(
234 ua->jcr, bsr->JobId, &(bsr->VolParams))) == 0) {
235 ua->ErrorMsg(_("Unable to get Job Volume Parameters. ERR=%s\n"),
236 ua->db->strerror());
237 if (bsr->VolParams) {
238 free(bsr->VolParams);
239 bsr->VolParams = NULL;
240 }
241 return false;
242 }
243 }
244 return true;
245 }
246
247 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
248 static uint32_t uniq = 0;
249
MakeUniqueRestoreFilename(UaContext * ua,PoolMem & fname)250 static void MakeUniqueRestoreFilename(UaContext* ua, PoolMem& fname)
251 {
252 JobControlRecord* jcr = ua->jcr;
253 int i = FindArgWithValue(ua, "bootstrap");
254 if (i >= 0) {
255 Mmsg(fname, "%s", ua->argv[i]);
256 jcr->impl->unlink_bsr = false;
257 } else {
258 P(mutex);
259 uniq++;
260 V(mutex);
261 Mmsg(fname, "%s/%s.restore.%u.bsr", working_directory, my_name, uniq);
262 jcr->impl->unlink_bsr = true;
263 }
264 if (jcr->RestoreBootstrap) { free(jcr->RestoreBootstrap); }
265 jcr->RestoreBootstrap = strdup(fname.c_str());
266 }
267
268 /**
269 * Write the bootstrap records to file
270 */
WriteBsrFile(UaContext * ua,RestoreContext & rx)271 uint32_t WriteBsrFile(UaContext* ua, RestoreContext& rx)
272 {
273 FILE* fd;
274 bool err;
275 uint32_t count = 0;
276 PoolMem fname(PM_MESSAGE);
277 std::string buffer;
278
279 MakeUniqueRestoreFilename(ua, fname);
280 fd = fopen(fname.c_str(), "w+b");
281 if (!fd) {
282 BErrNo be;
283 ua->ErrorMsg(_("Unable to create bootstrap file %s. ERR=%s\n"),
284 fname.c_str(), be.bstrerror());
285 goto bail_out;
286 }
287
288 /*
289 * Write them to a buffer.
290 */
291 count = WriteBsr(ua, rx, buffer);
292
293 /*
294 * Write the buffer to file
295 */
296 fprintf(fd, "%s", buffer.c_str());
297
298 err = ferror(fd);
299 fclose(fd);
300 if (count == 0) {
301 ua->InfoMsg(_("No files found to read. No bootstrap file written.\n"));
302 goto bail_out;
303 }
304 if (err) {
305 ua->ErrorMsg(_("Error writing bsr file.\n"));
306 count = 0;
307 goto bail_out;
308 }
309
310 ua->SendMsg(_("Bootstrap records written to %s\n"), fname.c_str());
311
312 if (debug_level >= 10) { PrintBsr(ua, rx); }
313
314 bail_out:
315 return count;
316 }
317
DisplayVolInfo(UaContext * ua,RestoreContext & rx,JobId_t JobId)318 static void DisplayVolInfo(UaContext* ua, RestoreContext& rx, JobId_t JobId)
319 {
320 int i;
321 RestoreBootstrapRecord* bsr;
322 char online;
323 PoolMem volmsg(PM_MESSAGE);
324 char Device[MAX_NAME_LENGTH];
325
326 for (bsr = rx.bsr.get(); bsr; bsr = bsr->next.get()) {
327 if (JobId && JobId != bsr->JobId) { continue; }
328
329 for (i = 0; i < bsr->VolCount; i++) {
330 if (bsr->VolParams[i].VolumeName[0]) {
331 if (!GetStorageDevice(Device, bsr->VolParams[i].Storage)) {
332 Device[0] = 0;
333 }
334 if (bsr->VolParams[i].InChanger && bsr->VolParams[i].Slot) {
335 online = '*';
336 } else {
337 online = ' ';
338 }
339 Mmsg(volmsg, "%c%-25s %-25s %-25s", online,
340 bsr->VolParams[i].VolumeName, bsr->VolParams[i].Storage, Device);
341 AddPrompt(ua, volmsg.c_str());
342 }
343 }
344 }
345 }
346
DisplayBsrInfo(UaContext * ua,RestoreContext & rx)347 void DisplayBsrInfo(UaContext* ua, RestoreContext& rx)
348 {
349 int i;
350 char* p;
351 JobId_t JobId;
352
353 /*
354 * Tell the user what he will need to mount
355 */
356 ua->SendMsg("\n");
357 ua->SendMsg(
358 _("The job will require the following\n"
359 " Volume(s) Storage(s) SD Device(s)\n"
360 "======================================================================"
361 "=====\n"));
362
363 /*
364 * Create Unique list of Volumes using prompt list
365 */
366 StartPrompt(ua, "");
367 if (*rx.JobIds == 0) {
368 /*
369 * Print Volumes in any order
370 */
371 DisplayVolInfo(ua, rx, 0);
372 } else {
373 /*
374 * Ensure that the volumes are printed in JobId order
375 */
376 for (p = rx.JobIds; GetNextJobidFromList(&p, &JobId) > 0;) {
377 DisplayVolInfo(ua, rx, JobId);
378 }
379 }
380
381 for (i = 0; i < ua->num_prompts; i++) {
382 ua->SendMsg(" %s\n", ua->prompt[i]);
383 free(ua->prompt[i]);
384 }
385
386 if (ua->num_prompts == 0) {
387 ua->SendMsg(_("No Volumes found to restore.\n"));
388 } else {
389 ua->SendMsg(_("\nVolumes marked with \"*\" are online.\n"));
390 }
391
392 ua->num_prompts = 0;
393 ua->SendMsg("\n");
394
395 return;
396 }
397
398 /**
399 * Write bsr data for a single bsr record
400 */
write_bsr_item(RestoreBootstrapRecord * bsr,UaContext * ua,RestoreContext & rx,std::string & buffer,bool & first,uint32_t & LastIndex)401 static uint32_t write_bsr_item(RestoreBootstrapRecord* bsr,
402 UaContext* ua,
403 RestoreContext& rx,
404 std::string& buffer,
405 bool& first,
406 uint32_t& LastIndex)
407 {
408 int i;
409 char ed1[50], ed2[50];
410 uint32_t count = 0;
411 uint32_t total_count = 0;
412 char device[MAX_NAME_LENGTH];
413
414 /*
415 * For a given volume, loop over all the JobMedia records.
416 * VolCount is the number of JobMedia records.
417 */
418 for (i = 0; i < bsr->VolCount; i++) {
419 if (!is_volume_selected(bsr->fi.get(), bsr->VolParams[i].FirstIndex,
420 bsr->VolParams[i].LastIndex)) {
421 bsr->VolParams[i].VolumeName[0] = 0; /* zap VolumeName */
422 continue;
423 }
424
425 if (!rx.store) {
426 FindStorageResource(ua, rx, bsr->VolParams[i].Storage,
427 bsr->VolParams[i].MediaType);
428 }
429
430 PrintBsrItem(buffer, "Storage=\"%s\"\n", bsr->VolParams[i].Storage);
431 PrintBsrItem(buffer, "Volume=\"%s\"\n", bsr->VolParams[i].VolumeName);
432 PrintBsrItem(buffer, "MediaType=\"%s\"\n", bsr->VolParams[i].MediaType);
433
434 if (bsr->fileregex) {
435 PrintBsrItem(buffer, "FileRegex=%s\n", bsr->fileregex);
436 }
437
438 if (GetStorageDevice(device, bsr->VolParams[i].Storage)) {
439 PrintBsrItem(buffer, "Device=\"%s\"\n", device);
440 }
441
442 if (bsr->VolParams[i].Slot > 0) {
443 PrintBsrItem(buffer, "Slot=%d\n", bsr->VolParams[i].Slot);
444 }
445
446 PrintBsrItem(buffer, "VolSessionId=%u\n", bsr->VolSessionId);
447 PrintBsrItem(buffer, "VolSessionTime=%u\n", bsr->VolSessionTime);
448 PrintBsrItem(buffer, "VolAddr=%s-%s\n",
449 edit_uint64(bsr->VolParams[i].StartAddr, ed1),
450 edit_uint64(bsr->VolParams[i].EndAddr, ed2));
451
452 count = write_findex(bsr->fi.get(), bsr->VolParams[i].FirstIndex,
453 bsr->VolParams[i].LastIndex, buffer);
454 if (count) { PrintBsrItem(buffer, "Count=%u\n", count); }
455
456 total_count += count;
457
458 /*
459 * If the same file is present on two tapes or in two files
460 * on a tape, it is a continuation, and should not be treated
461 * twice in the totals.
462 */
463 if (!first && LastIndex == bsr->VolParams[i].FirstIndex) { total_count--; }
464 first = false;
465 LastIndex = bsr->VolParams[i].LastIndex;
466 }
467
468 return total_count;
469 }
470
471 /**
472 * Here we actually write out the details of the bsr file.
473 * Note, there is one bsr for each JobId, but the bsr may
474 * have multiple volumes, which have been entered in the
475 * order they were written.
476 *
477 * The bsrs must be written out in the order the JobIds
478 * are found in the jobid list.
479 */
WriteBsr(UaContext * ua,RestoreContext & rx,std::string & buffer)480 uint32_t WriteBsr(UaContext* ua, RestoreContext& rx, std::string& buffer)
481 {
482 bool first = true;
483 uint32_t LastIndex = 0;
484 uint32_t total_count = 0;
485 char* p;
486 JobId_t JobId;
487 RestoreBootstrapRecord* bsr;
488
489 if (*rx.JobIds == 0) {
490 for (bsr = rx.bsr.get(); bsr; bsr = bsr->next.get()) {
491 total_count += write_bsr_item(bsr, ua, rx, buffer, first, LastIndex);
492 }
493 return total_count;
494 }
495
496 for (p = rx.JobIds; GetNextJobidFromList(&p, &JobId) > 0;) {
497 for (bsr = rx.bsr.get(); bsr; bsr = bsr->next.get()) {
498 if (JobId == bsr->JobId) {
499 total_count += write_bsr_item(bsr, ua, rx, buffer, first, LastIndex);
500 }
501 }
502 }
503
504 return total_count;
505 }
506
PrintBsr(UaContext * ua,RestoreContext & rx)507 void PrintBsr(UaContext* ua, RestoreContext& rx)
508 {
509 std::string buffer;
510
511 WriteBsr(ua, rx, buffer);
512 fprintf(stdout, "%s", buffer.c_str());
513 }
514
515 /**
516 * Add a FileIndex to the list of BootStrap records.
517 * Here we are only dealing with JobId's and the FileIndexes
518 * associated with those JobIds.
519 */
AddFindex(RestoreBootstrapRecord * bsr,uint32_t JobId,int32_t findex)520 void AddFindex(RestoreBootstrapRecord* bsr, uint32_t JobId, int32_t findex)
521 {
522 RestoreBootstrapRecord* nbsr;
523
524 if (findex == 0) { return; /* probably a dummy directory */ }
525
526 if (bsr->fi->Empty()) { /* if no FI yet, jobid is not yet set */
527 bsr->JobId = JobId;
528 }
529
530 /*
531 * Walk down list of bsrs until we find the JobId
532 */
533 if (bsr->JobId != JobId) {
534 for (nbsr = bsr->next.get(); nbsr; nbsr = nbsr->next.get()) {
535 if (nbsr->JobId == JobId) {
536 bsr = nbsr;
537 break;
538 }
539 }
540
541 if (!nbsr) { /* Must add new JobId */
542 /*
543 * Add new JobId at end of chain
544 */
545 for (nbsr = bsr; nbsr->next.get(); nbsr = nbsr->next.get()) {}
546 nbsr->next = std::make_unique<RestoreBootstrapRecord>(JobId);
547 bsr = nbsr->next.get();
548 }
549 }
550
551 bsr->fi->Add(findex);
552 }
553
554 /**
555 * Add all possible FileIndexes to the list of BootStrap records.
556 * Here we are only dealing with JobId's and the FileIndexes
557 * associated with those JobIds.
558 */
AddFindexAll(RestoreBootstrapRecord * bsr,uint32_t JobId)559 void AddFindexAll(RestoreBootstrapRecord* bsr, uint32_t JobId)
560 {
561 RestoreBootstrapRecord* nbsr;
562
563 if (bsr->fi->Empty()) { /* if no FI add one */
564 bsr->JobId = JobId;
565 }
566
567 /*
568 * Walk down list of bsrs until we find the JobId
569 */
570 if (bsr->JobId != JobId) {
571 for (nbsr = bsr->next.get(); nbsr; nbsr = nbsr->next.get()) {
572 if (nbsr->JobId == JobId) {
573 bsr = nbsr;
574 break;
575 }
576 }
577
578 if (!nbsr) { /* Must add new JobId */
579 for (nbsr = bsr; nbsr->next.get(); nbsr = nbsr->next.get()) {}
580 nbsr->next = std::make_unique<RestoreBootstrapRecord>(JobId);
581 if (bsr->fileregex) { nbsr->next->fileregex = strdup(bsr->fileregex); }
582 bsr = nbsr->next.get();
583 }
584 }
585
586 bsr->fi->AddAll();
587 }
588
589 /**
590 * Open the bootstrap file and find the first Storage=
591 * Returns ok if able to open
592 *
593 * It fills the storage name (should be the first line)
594 * and the file descriptor to the bootstrap file,
595 * it should be used for next operations, and need to be
596 * closed at the end.
597 */
OpenBootstrapFile(JobControlRecord * jcr,bootstrap_info & info)598 bool OpenBootstrapFile(JobControlRecord* jcr, bootstrap_info& info)
599 {
600 FILE* bs;
601 UaContext* ua;
602 info.bs = NULL;
603 info.ua = NULL;
604
605 if (!jcr->RestoreBootstrap) { return false; }
606 bstrncpy(info.storage, jcr->impl->res.read_storage->resource_name_,
607 MAX_NAME_LENGTH);
608
609 bs = fopen(jcr->RestoreBootstrap, "rb");
610 if (!bs) {
611 BErrNo be;
612 Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
613 jcr->RestoreBootstrap, be.bstrerror());
614 jcr->setJobStatus(JS_ErrorTerminated);
615 return false;
616 }
617
618 ua = new_ua_context(jcr);
619 ua->cmd = CheckPoolMemorySize(ua->cmd, UA_CMD_SIZE + 1);
620 while (!fgets(ua->cmd, UA_CMD_SIZE, bs)) {
621 ParseUaArgs(ua);
622 if (ua->argc != 1) { continue; }
623 if (Bstrcasecmp(ua->argk[0], "Storage")) {
624 bstrncpy(info.storage, ua->argv[0], MAX_NAME_LENGTH);
625 break;
626 }
627 }
628 info.bs = bs;
629 info.ua = ua;
630 fseek(bs, 0, SEEK_SET); /* return to the top of the file */
631 return true;
632 }
633
634 /**
635 * This function compare the given storage name with the
636 * the current one. We compare the name and the address:port.
637 * Returns true if we use the same storage.
638 */
IsOnSameStorage(JobControlRecord * jcr,char * new_one)639 static inline bool IsOnSameStorage(JobControlRecord* jcr, char* new_one)
640 {
641 StorageResource* new_store;
642
643 /*
644 * With old FD, we send the whole bootstrap to the storage
645 */
646 if (jcr->impl->FDVersion < FD_VERSION_2) { return true; }
647
648 /*
649 * We are in init loop ? shoudn't fail here
650 */
651 if (!*new_one) { return true; }
652
653 /*
654 * Same name
655 */
656 if (bstrcmp(new_one, jcr->impl->res.read_storage->resource_name_)) {
657 return true;
658 }
659
660 new_store = (StorageResource*)my_config->GetResWithName(R_STORAGE, new_one);
661 if (!new_store) {
662 Jmsg(jcr, M_WARNING, 0, _("Could not get storage resource '%s'.\n"),
663 new_one);
664 return true;
665 }
666
667 /*
668 * If Port and Hostname/IP are same, we are talking to the same
669 * Storage Daemon
670 */
671 if (jcr->impl->res.read_storage->SDport != new_store->SDport ||
672 !bstrcmp(jcr->impl->res.read_storage->address, new_store->address)) {
673 return false;
674 }
675
676 return true;
677 }
678
679 /**
680 * Check if the current line contains Storage="xxx", and compare the
681 * result to the current storage. We use UaContext to analyse the bsr
682 * string.
683 *
684 * Returns true if we need to change the storage, and it set the new
685 * Storage resource name in "storage" arg.
686 */
CheckForNewStorage(JobControlRecord * jcr,bootstrap_info & info)687 static inline bool CheckForNewStorage(JobControlRecord* jcr,
688 bootstrap_info& info)
689 {
690 UaContext* ua = info.ua;
691
692 ParseUaArgs(ua);
693 if (ua->argc != 1) { return false; }
694
695 if (Bstrcasecmp(ua->argk[0], "Storage")) {
696 /*
697 * Continue if this is a volume from the same storage.
698 */
699 if (IsOnSameStorage(jcr, ua->argv[0])) { return false; }
700
701 /*
702 * Note the next storage name
703 */
704 bstrncpy(info.storage, ua->argv[0], MAX_NAME_LENGTH);
705 Dmsg1(5, "Change storage to %s\n", info.storage);
706 return true;
707 }
708
709 return false;
710 }
711
712 /**
713 * Send bootstrap file to Storage daemon section by section.
714 */
SendBootstrapFile(JobControlRecord * jcr,BareosSocket * sock,bootstrap_info & info)715 bool SendBootstrapFile(JobControlRecord* jcr,
716 BareosSocket* sock,
717 bootstrap_info& info)
718 {
719 boffset_t pos;
720 const char* bootstrap = "bootstrap\n";
721 UaContext* ua = info.ua;
722 FILE* bs = info.bs;
723
724 Dmsg1(400, "SendBootstrapFile: %s\n", jcr->RestoreBootstrap);
725 if (!jcr->RestoreBootstrap) { return false; }
726
727 sock->fsend(bootstrap);
728 pos = ftello(bs);
729
730 while (fgets(ua->cmd, UA_CMD_SIZE, bs)) {
731 if (CheckForNewStorage(jcr, info)) {
732 /*
733 * Otherwise, we need to contact another storage daemon.
734 * Reset bs to the beginning of the current segment.
735 */
736 fseeko(bs, pos, SEEK_SET);
737 break;
738 }
739 sock->fsend("%s", ua->cmd);
740 pos = ftello(bs);
741 }
742
743 sock->signal(BNET_EOD);
744
745 return true;
746 }
747
748 /**
749 * Clean the bootstrap_info struct
750 */
CloseBootstrapFile(bootstrap_info & info)751 void CloseBootstrapFile(bootstrap_info& info)
752 {
753 if (info.bs) { fclose(info.bs); }
754 if (info.ua) { FreeUaContext(info.ua); }
755 }
756 } /* namespace directordaemon */
757