1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2011-2015 Planets Communications B.V.
5 Copyright (C) 2013-2020 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 * Marco van Wieringen, May 2015
24 */
25 /**
26 * @file
27 * Storage specific NDMP Data Management Application (DMA) routines
28 */
29
30 #include "include/bareos.h"
31 #include "dird.h"
32 #include "dird/dird_globals.h"
33 #include "dird/sd_cmds.h"
34 #include "dird/storage.h"
35 #include "dird/ndmp_slot2elemaddr.h"
36
37 #if HAVE_NDMP
38 #include "ndmp/ndmagents.h"
39 #include "ndmp_dma_priv.h"
40 #endif
41
42 namespace directordaemon {
43
44 #if HAVE_NDMP
45 /* Imported variables */
46
47 /* Forward referenced functions */
48
49 /**
50 * ndmp query callback
51 */
get_tape_info_cb(struct ndm_session * sess,ndmp9_device_info * info,unsigned n_info)52 int get_tape_info_cb(struct ndm_session *sess, ndmp9_device_info *info, unsigned n_info)
53 {
54 Dmsg0(100, "Get tape info called\n");
55 unsigned int i, j, k;
56 const char *what = "tape";
57 JobControlRecord *jcr = NULL;
58 StorageResource *store = NULL;
59 NIS *nis = (NIS *)sess->param->log.ctx;
60
61 if (nis->jcr) {
62 jcr = nis->jcr;
63 } else if (nis->ua && nis->ua->jcr) {
64 jcr = nis->ua->jcr;
65 } else {
66 return -1;
67 }
68
69 if (jcr->is_JobType(JT_BACKUP)) {
70 store = jcr->res.write_storage;
71
72 } else if (jcr->is_JobType(JT_RESTORE)) {
73 store = jcr->res.read_storage;
74
75 } else {
76 return -1;
77 }
78
79 /* if (store->rss->ndmp_deviceinfo) { */
80 /* delete(store->rss->ndmp_deviceinfo); */
81 /* store->rss->ndmp_deviceinfo = NULL; */
82 /* } */
83 if (!store->rss->ndmp_deviceinfo) {
84 store->rss->ndmp_deviceinfo = new(std::list<ndmp_deviceinfo_t>);
85
86 for (i = 0; i < n_info; i++) {
87 Dmsg2(100, " %s %s\n", what, info[i].model);
88
89 ndmp_deviceinfo_t *devinfo = new(ndmp_deviceinfo_t);
90 devinfo->JobIdUsingDevice = 0;
91
92 ndmp9_device_capability *info_dc;
93 info_dc = info[i].caplist.caplist_val;
94 devinfo->model = info[i].model;
95 devinfo->device = info_dc->device;
96 store->rss->ndmp_deviceinfo->push_back(*devinfo);
97
98 for (j = 0; j < info[i].caplist.caplist_len; j++) {
99 ndmp9_device_capability *dc;
100 uint32_t attr;
101 dc = &info[i].caplist.caplist_val[j];
102 Dmsg1(100, " device %s\n", dc->device);
103
104
105
106 if (!strcmp(what, "tape\n")) {
107 #ifndef NDMOS_OPTION_NO_NDMP3
108 if (sess->plumb.tape->protocol_version == 3) {
109 attr = dc->v3attr.value;
110 Dmsg1(100, " attr 0x%lx\n",
111 attr);
112 if (attr & NDMP3_TAPE_ATTR_REWIND)
113 Dmsg0(100, " REWIND\n");
114 if (attr & NDMP3_TAPE_ATTR_UNLOAD)
115 Dmsg0(100, " UNLOAD\n");
116 }
117 #endif /* !NDMOS_OPTION_NO_NDMP3 */
118 #ifndef NDMOS_OPTION_NO_NDMP4
119 if (sess->plumb.tape->protocol_version == 4) {
120 attr = dc->v4attr.value;
121 Dmsg1(100, " attr 0x%lx\n",
122 attr);
123 if (attr & NDMP4_TAPE_ATTR_REWIND)
124 Dmsg0(100, " REWIND\n");
125 if (attr & NDMP4_TAPE_ATTR_UNLOAD)
126 Dmsg0(100, " UNLOAD\n");
127 }
128 #endif /* !NDMOS_OPTION_NO_NDMP4 */
129 }
130 for (k = 0; k < dc->capability.capability_len; k++) {
131 Dmsg2(100, " set %s=%s\n",
132 dc->capability.capability_val[k].name,
133 dc->capability.capability_val[k].value);
134 }
135 if (k == 0)
136 Dmsg0(100, " empty capabilities\n");
137 }
138 if (j == 0)
139 Dmsg0(100, " empty caplist\n");
140 Dmsg0(100, "\n");
141 }
142 }
143 if (i == 0)
144 Dmsg1(100, " Empty %s info\n", what);
145 return 0;
146 }
147
148 /**
149 * execute NDMP_QUERY_AGENTS on Tape and Robot
150 */
do_ndmp_native_query_tape_and_robot_agents(JobControlRecord * jcr,StorageResource * store)151 bool do_ndmp_native_query_tape_and_robot_agents(JobControlRecord *jcr, StorageResource *store) {
152
153 struct ndm_job_param ndmp_job;
154
155 if (!NdmpBuildStorageJob(jcr,
156 store,
157 true, /* Query Tape Agent */
158 true, /* Query Robot Agent */
159 NDM_JOB_OP_QUERY_AGENTS,
160 &ndmp_job)) {
161
162 Dmsg0(100, "error in NdmpBuildStorageJob");
163 return false;
164 }
165
166 struct ndmca_query_callbacks query_callbacks;
167 query_callbacks.get_tape_info = get_tape_info_cb;
168 ndmca_query_callbacks *query_cbs = &query_callbacks;
169
170 NdmpDoQuery(NULL, jcr, &ndmp_job, me->ndmp_loglevel, query_cbs);
171
172 /*
173 * Debug output
174 */
175
176 if (store->rss->ndmp_deviceinfo) {
177 Jmsg(jcr, M_INFO, 0, "NDMP Devices for storage %s:(%s)\n", store->name(), store->rss->smc_ident);
178 } else {
179 Jmsg(jcr, M_INFO, 0, "No NDMP Devices for storage %s:(%s)\n", store->name(), store->rss->smc_ident);
180 return false;
181 }
182 for (auto devinfo = store->rss->ndmp_deviceinfo->begin();
183 devinfo != store->rss->ndmp_deviceinfo->end();
184 devinfo++) {
185 Jmsg(jcr, M_INFO, 0, " %s\n",
186 devinfo->device.c_str(), devinfo->model.c_str() );
187 }
188 return true;
189 }
190
191 /**
192 * get status of a NDMP Native storage and store the information
193 * coming in via the NDMP protocol
194 */
DoNdmpNativeStorageStatus(UaContext * ua,StorageResource * store,char * cmd)195 void DoNdmpNativeStorageStatus(UaContext *ua, StorageResource *store, char *cmd)
196 {
197 struct ndm_job_param ndmp_job;
198
199 ua->jcr->res.write_storage = store;
200
201 if (!NdmpBuildStorageJob(ua->jcr,
202 store,
203 true, /* Query Tape Agent */
204 true, /* Query Robot Agent */
205 NDM_JOB_OP_QUERY_AGENTS,
206 &ndmp_job)) {
207
208 ua->InfoMsg("build_storage_job failed\n");
209 }
210
211 struct ndmca_query_callbacks query_callbacks;
212 query_callbacks.get_tape_info = get_tape_info_cb;
213 ndmca_query_callbacks *query_cbs = &query_callbacks;
214
215 NdmpDoQuery(ua, NULL, &ndmp_job, me->ndmp_loglevel, query_cbs);
216
217 ndmp_deviceinfo_t *deviceinfo = NULL;
218 int i = 0;
219 if (store->rss->ndmp_deviceinfo) {
220 ua->InfoMsg("NDMP Devices for storage %s:(%s)\n", store->name(), store->rss->smc_ident);
221 ua->InfoMsg(" element_address Device Model (JobId) \n");
222 for (auto devinfo = store->rss->ndmp_deviceinfo->begin();
223 devinfo != store->rss->ndmp_deviceinfo->end();
224 devinfo++) {
225 ua->InfoMsg(" %d %s %s (%d)\n",
226 i++, devinfo->device.c_str(), devinfo->model.c_str(),
227 devinfo->JobIdUsingDevice);
228 }
229 }
230 }
231
232 /**
233 * Output the status of a storage daemon when its a normal storage
234 * daemon accessed via the NDMP protocol or query the TAPE and ROBOT
235 * agent of a native NDMP server.
236 */
DoNdmpStorageStatus(UaContext * ua,StorageResource * store,char * cmd)237 void DoNdmpStorageStatus(UaContext *ua, StorageResource *store, char *cmd)
238 {
239 /*
240 * See if the storage is just a NDMP instance of a normal storage daemon.
241 */
242 if (store->paired_storage) {
243 DoNativeStorageStatus(ua, store->paired_storage, cmd);
244 } else {
245 DoNdmpNativeStorageStatus(ua, store, cmd);
246 }
247 }
248
249 /**
250 * Interface function which glues the logging infra of the NDMP lib for debugging.
251 */
NdmpRobotStatusHandler(struct ndmlog * log,char * tag,int lev,char * msg)252 extern "C" void NdmpRobotStatusHandler(struct ndmlog *log, char *tag, int lev, char *msg)
253 {
254 NIS *nis;
255
256 /*
257 * Make sure if the logging system was setup properly.
258 */
259 nis = (NIS *)log->ctx;
260 if (!nis) {
261 return;
262 }
263
264 Dmsg1(100, "%s\n", msg);
265 }
266
267 /**
268 * Generic cleanup function that can be used after a successful or failed NDMP Job ran.
269 */
CleanupNdmpSession(struct ndm_session * ndmp_sess)270 static void CleanupNdmpSession(struct ndm_session *ndmp_sess)
271 {
272 Dmsg0(200, "Start to clean up ndmp session.\n");
273
274 /*
275 * Destroy the session.
276 */
277 ndma_session_destroy(ndmp_sess);
278
279 /*
280 * Free the param block.
281 */
282 free(ndmp_sess->param->log_tag);
283 free(ndmp_sess->param->log.ctx);
284 free(ndmp_sess->param);
285 free(ndmp_sess);
286 }
287
288 /**
289 * Generic function to run a storage Job on a remote NDMP server.
290 */
NdmpRunStorageJob(JobControlRecord * jcr,StorageResource * store,struct ndm_session * ndmp_sess,struct ndm_job_param * ndmp_job)291 static bool NdmpRunStorageJob(JobControlRecord *jcr, StorageResource *store, struct ndm_session *ndmp_sess, struct ndm_job_param *ndmp_job)
292 {
293 NIS *nis;
294
295 ndmp_sess->conn_snooping = (me->ndmp_snooping) ? 1 : 0;
296 ndmp_sess->control_agent_enabled = 1;
297
298 ndmp_sess->param = (struct ndm_session_param *)malloc(sizeof(struct ndm_session_param));
299 memset(ndmp_sess->param, 0, sizeof(struct ndm_session_param));
300 ndmp_sess->param->log.deliver = NdmpRobotStatusHandler;
301 nis = (NIS *)malloc(sizeof(NIS));
302 memset(nis, 0, sizeof(NIS));
303 ndmp_sess->param->log_level = NativeToNdmpLoglevel(me->ndmp_loglevel, debug_level, nis);
304 ndmp_sess->param->log.ctx = nis;
305 ndmp_sess->param->log_tag = bstrdup("DIR-NDMP");
306 nis->jcr = jcr;
307
308 /*
309 * Initialize the session structure.
310 */
311 if (ndma_session_initialize(ndmp_sess)) {
312 Dmsg0(200, "Could not initialize ndma session.\n");
313 return false;
314 }
315
316 /*
317 * Copy the actual job to perform.
318 */
319 memcpy(&ndmp_sess->control_acb->job, ndmp_job, sizeof(struct ndm_job_param));
320 if (!NdmpValidateJob(jcr, &ndmp_sess->control_acb->job)) {
321 Dmsg0(200, "Could not validate ndma job.\n");
322 return false;
323 }
324
325 /*
326 * Commission the session for a run.
327 */
328 if (ndma_session_commission(ndmp_sess)) {
329 Dmsg0(200, "Could not commission the ndma session.\n");
330 return false;
331 }
332
333 /*
334 * Setup the DMA.
335 */
336 if (ndmca_connect_control_agent(ndmp_sess)) {
337 Dmsg0(200, "Could not connect to control agent.\n");
338 return false;
339 }
340
341 ndmp_sess->conn_open = 1;
342 ndmp_sess->conn_authorized = 1;
343
344 char ndm_job_type = ndmp_sess->control_acb->job.operation & 0xff;
345 Dmsg2(200, "ndma job.operation - job_type: %#x - %c\n",
346 ndmp_sess->control_acb->job.operation, ndm_job_type);
347
348 /*
349 * Let the DMA perform its magic.
350 */
351 int err{};
352 if ((err = ndmca_control_agent(ndmp_sess)) != 0) {
353 Dmsg1(200, "Ndma control agent error: %d\n", err);
354 return false;
355 }
356
357 return true;
358 }
359
360 /**
361 * Generic function to get the current element status of a NDMP robot.
362 */
GetRobotElementStatus(JobControlRecord * jcr,StorageResource * store,struct ndm_session ** ndmp_sess)363 static bool GetRobotElementStatus(JobControlRecord *jcr, StorageResource *store, struct ndm_session **ndmp_sess)
364 {
365 struct ndm_job_param ndmp_job;
366
367 /*
368 * See if this is an autochanger.
369 */
370 if (!store->autochanger || !store->ndmp_changer_device) {
371 Dmsg2(200, "Autochanger: %s - NDMP Changer device: %s\n",
372 store->autochanger ? "true" : "false",
373 store->ndmp_changer_device ? store->ndmp_changer_device : "(NULL)");
374 return false;
375 }
376
377 if (!NdmpBuildStorageJob(jcr,
378 store,
379 false, /* Setup Tape Agent */
380 true, /* Setup Robot Agent */
381 NDM_JOB_OP_INIT_ELEM_STATUS,
382 &ndmp_job)) {
383 Dmsg0(200, "Could not build NDMP storage job\n");
384 return false;
385 }
386
387 /*
388 * Set the remote robotics name to use.
389 * We use the ndmscsi_target_from_str() function which parses the NDMJOB format of a
390 * device in the form NAME[,[CNUM,]SID[,LUN]
391 */
392 ndmp_job.robot_target = (struct ndmscsi_target *)actuallymalloc(sizeof(struct ndmscsi_target));
393 int error_number = ndmscsi_target_from_str(ndmp_job.robot_target, store->ndmp_changer_device);
394 if (error_number != 0) {
395 Actuallyfree(ndmp_job.robot_target);
396 Dmsg1(200, "Could not create NDMP target name from string: %d\n", error_number);
397 return false;
398 }
399 ndmp_job.have_robot = 1;
400 ndmp_job.auto_remedy = 1;
401
402 /*
403 * Initialize a new NDMP session
404 */
405 *ndmp_sess = (struct ndm_session *)malloc(sizeof(struct ndm_session));
406 memset(*ndmp_sess, 0, sizeof(struct ndm_session));
407
408 if (!NdmpRunStorageJob(jcr, store, *ndmp_sess, &ndmp_job)) {
409 CleanupNdmpSession(*ndmp_sess);
410 Dmsg0(200, "NdmpRunStorageJob failed.\n");
411 return false;
412 }
413
414 return true;
415 }
416
417 /**
418 * Get the volume names from a smc_element_descriptor.
419 */
FillVolumeName(vol_list_t * vl,struct smc_element_descriptor * edp)420 static void FillVolumeName(vol_list_t *vl, struct smc_element_descriptor *edp)
421 {
422 if (edp->PVolTag) {
423 vl->VolName = bstrdup((char *)edp->primary_vol_tag->volume_id);
424 StripTrailingJunk(vl->VolName);
425 } else if (edp->AVolTag) {
426 vl->VolName = bstrdup((char *)edp->alternate_vol_tag->volume_id);
427 StripTrailingJunk(vl->VolName);
428 }
429 }
430
431 /**
432 * Get the information to map logical addresses (index) to
433 * physical address (scsi element address)
434 *
435 * Everything that is needed for that is stored in the
436 * smc smc_element_address_assignment.
437 *
438 * For each type of element a start address and the
439 * number of entries (count) is stored there.
440 */
NdmpFillStorageMappings(StorageResource * store,struct ndm_session * ndmp_sess)441 static void NdmpFillStorageMappings(StorageResource *store, struct ndm_session *ndmp_sess)
442 {
443 drive_number_t drive;
444 slot_number_t slot,
445 picker;
446 struct smc_ctrl_block *smc;
447
448 smc = ndmp_sess->control_acb->smc_cb;
449 memcpy(store->rss->smc_ident, smc->ident, sizeof(store->rss->smc_ident));
450
451 if (smc->valid_elem_aa) {
452 memcpy(&store->rss->storage_mapping, &smc->elem_aa, sizeof(store->rss->storage_mapping));
453
454 } else {
455 Dmsg0(0,"Warning, smc does not have valid elem_aa info\n");
456 }
457 }
458
459 /**
460 * Get the current content of the autochanger as a generic vol_list dlist.
461 */
ndmp_get_vol_list(UaContext * ua,StorageResource * store,bool listall,bool scan)462 dlist *ndmp_get_vol_list(UaContext *ua, StorageResource *store, bool listall, bool scan)
463 {
464 struct ndm_session *ndmp_sess;
465 struct smc_ctrl_block *smc;
466 struct smc_element_descriptor *edp;
467 vol_list_t *vl = NULL;
468 dlist *vol_list = NULL;
469
470 ua->WarningMsg(_("get ndmp_vol_list...\n"));
471 if (!GetRobotElementStatus(ua->jcr, store, &ndmp_sess)) {
472 return (dlist *)NULL;
473 }
474
475 /*
476 * If we have no storage mappings create them now from the data we just retrieved.
477 */
478 NdmpFillStorageMappings(store, ndmp_sess);
479
480 /*
481 * Start with an empty dlist().
482 */
483 vol_list = New(dlist(vl, &vl->link));
484
485 /*
486 * Process the robot element status retrieved.
487 */
488 smc = ndmp_sess->control_acb->smc_cb;
489 for (edp = smc->elem_desc; edp; edp = edp->next) {
490 vl = (vol_list_t *)malloc(sizeof(vol_list_t));
491 memset(vl, 0, sizeof(vol_list_t));
492
493 if (scan && !listall) {
494 /*
495 * Scanning -- require only valid slot
496 */
497 switch (edp->element_type_code) {
498 case SMC_ELEM_TYPE_SE:
499 /*
500 * Normal slot
501 */
502 vl->slot_type = slot_type_storage;
503 if (edp->Full) {
504 vl->slot_status = slot_status_full;
505 FillVolumeName(vl, edp);
506 } else {
507 vl->slot_status = slot_status_empty;
508 }
509 vl->element_address = edp->element_address;
510 break;
511 default:
512 free(vl);
513 continue;
514 }
515 } else if (!listall) {
516 /*
517 * Not scanning and not listall.
518 */
519 switch (edp->element_type_code) {
520 case SMC_ELEM_TYPE_SE:
521 /*
522 * Normal slot
523 */
524 vl->slot_type = slot_type_storage;
525 vl->element_address = edp->element_address;
526 if (!edp->Full) {
527 free(vl);
528 continue;
529 } else {
530 vl->slot_status = slot_status_full;
531 FillVolumeName(vl, edp);
532 }
533 break;
534 default:
535 free(vl);
536 continue;
537 }
538 } else {
539 /*
540 * Listall.
541 */
542 switch (edp->element_type_code) {
543 case SMC_ELEM_TYPE_MTE:
544 /*
545 * Transport
546 */
547 free(vl);
548 continue;
549 case SMC_ELEM_TYPE_SE:
550 /*
551 * Normal slot
552 */
553 vl->slot_type = slot_type_storage;
554 vl->element_address = edp->element_address;
555 if (edp->Full) {
556 vl->slot_status = slot_status_full;
557 FillVolumeName(vl, edp);
558 } else {
559 vl->slot_status = slot_status_empty;
560 }
561 break;
562 case SMC_ELEM_TYPE_IEE:
563 /*
564 * Import/Export bareos_slot_number
565 */
566 vl->slot_type = slot_type_import;
567 vl->element_address = edp->element_address;
568 if (edp->Full) {
569 vl->slot_status = slot_status_full;
570 FillVolumeName(vl, edp);
571 } else {
572 vl->slot_status = slot_status_empty;
573 }
574 if (edp->InEnab) {
575 vl->flags |= can_import;
576 }
577 if (edp->ExEnab) {
578 vl->flags |= can_export;
579 }
580 if (edp->ImpExp) {
581 vl->flags |= by_oper;
582 } else {
583 vl->flags |= by_mte;
584 }
585 break;
586 case SMC_ELEM_TYPE_DTE:
587 /*
588 * Drive
589 */
590 vl->slot_type = slot_type_drive;
591 vl->element_address = edp->element_address;
592 if (edp->Full) {
593 slot_number_t slot_mapping;
594 vl->slot_status = slot_status_full;
595 slot_mapping = GetBareosSlotNumberByElementAddress(&store->rss->storage_mapping, slot_type_storage, edp->src_se_addr);
596 vl->currently_loaded_slot_number = slot_mapping;
597 FillVolumeName(vl, edp);
598 } else {
599 vl->slot_status = slot_status_empty;
600 }
601 break;
602 default:
603 vl->slot_type = slot_type_unknown;
604 vl->element_address = edp->element_address;
605 break;
606 }
607 }
608
609
610 /*
611 * Map physical storage address to logical one using the storage mappings.
612 */
613 vl->bareos_slot_number = GetBareosSlotNumberByElementAddress(&store->rss->storage_mapping, vl->slot_type, edp->element_address);
614 if (vl->VolName) {
615 Dmsg6(100, "Add phys_slot = %hd logi_slot=%hd loaded=%hd type=%hd status=%hd Vol=%s to SD list.\n",
616 vl->element_address, vl->bareos_slot_number, vl->currently_loaded_slot_number, vl->slot_type, vl->slot_status, NPRT(vl->VolName));
617 } else {
618 Dmsg5(100, "Add phys_slot = %hd logi_slot=%hd loaded=%hd type=%hd status=%hd Vol=NULL to SD list.\n",
619 vl->element_address, vl->bareos_slot_number, vl->currently_loaded_slot_number, vl->slot_type, vl->slot_status);
620 }
621
622 vol_list->binary_insert(vl, StorageCompareVolListEntry);
623 }/* for */
624
625 if (vol_list->size() == 0) {
626 delete vol_list;
627 vol_list = NULL;
628 }
629
630 CleanupNdmpSession(ndmp_sess);
631
632 return vol_list;
633 }
634
635 /**
636 * Update the mapping table from logical to physical storage addresses.
637 */
NdmpUpdateStorageMappings(JobControlRecord * jcr,StorageResource * store)638 bool NdmpUpdateStorageMappings(JobControlRecord* jcr, StorageResource *store)
639 {
640 struct ndm_session *ndmp_sess;
641
642 if (!GetRobotElementStatus(jcr, store, &ndmp_sess)) {
643 Dmsg0(200, "Could not get robot element status.\n");
644 return false;
645 }
646
647 NdmpFillStorageMappings(store, ndmp_sess);
648
649 CleanupNdmpSession(ndmp_sess);
650
651 return true;
652
653 }
654
655 /**
656 * Update the mapping table from logical to physical storage addresses.
657 */
NdmpUpdateStorageMappings(UaContext * ua,StorageResource * store)658 bool NdmpUpdateStorageMappings(UaContext *ua, StorageResource *store)
659 {
660 struct ndm_session *ndmp_sess;
661
662 if (!GetRobotElementStatus(ua->jcr, store, &ndmp_sess)) {
663 Dmsg0(200, "Could not get robot element status.\n");
664 return false;
665 }
666
667 NdmpFillStorageMappings(store, ndmp_sess);
668
669 CleanupNdmpSession(ndmp_sess);
670
671 return true;
672 }
673
674 /**
675 * Number of slots in a NDMP autochanger.
676 */
NdmpGetNumSlots(UaContext * ua,StorageResource * store)677 slot_number_t NdmpGetNumSlots(UaContext *ua, StorageResource *store)
678 {
679 slot_number_t slots = 0;
680
681 /*
682 * See if the mappings are already determined.
683 */
684 if (!NdmpUpdateStorageMappings(ua, store)) {
685 Dmsg0(200,"NdmpUpdateStorageMappings failed\n");
686 return slots;
687 }
688
689 return store->rss->storage_mapping.se_count
690 + store->rss->storage_mapping.iee_count;
691 }
692
693 /**
694 * Number of drives in a NDMP autochanger.
695 */
NdmpGetNumDrives(UaContext * ua,StorageResource * store)696 drive_number_t NdmpGetNumDrives(UaContext *ua, StorageResource *store)
697 {
698 drive_number_t drives = 0;
699
700 /*
701 * See if the mappings are already determined.
702 */
703 if (!NdmpUpdateStorageMappings(ua, store)) {
704 Dmsg0(200,"NdmpUpdateStorageMappings failed\n");
705 return drives;
706 }
707
708 return store->rss->storage_mapping.dte_count;
709 }
710
711 /**
712 * Move a volume from one slot to an other in a NDMP autochanger.
713 */
NdmpTransferVolume(UaContext * ua,StorageResource * store,slot_number_t src_slot,slot_number_t dst_slot)714 bool NdmpTransferVolume(UaContext *ua, StorageResource *store,
715 slot_number_t src_slot, slot_number_t dst_slot)
716 {
717 bool retval = false;
718 slot_number_t from_addr;
719 slot_number_t to_addr;
720 struct ndm_job_param ndmp_job;
721 struct ndm_session *ndmp_sess;
722
723 /*
724 * See if this is an autochanger.
725 */
726 if (!store->autochanger || !store->ndmp_changer_device) {
727 return retval;
728 }
729
730 if (!NdmpBuildStorageJob(ua->jcr,
731 store,
732 false, /* Setup Tape Agent */
733 true, /* Setup Robot Agent */
734 NDM_JOB_OP_MOVE_TAPE,
735 &ndmp_job)) {
736 return retval;
737 }
738
739 /*
740 * Fill in the from and to address.
741 *
742 * As the upper level functions work with logical slot numbers convert them
743 * to physical slot numbers for the actual NDMP operation.
744 */
745 from_addr = GetBareosSlotNumberByElementAddress(&store->rss->storage_mapping, slot_type_storage, src_slot);
746 if (from_addr == -1) {
747 ua->ErrorMsg("No slot mapping for slot %hd\n", src_slot);
748 return retval;
749 }
750 ndmp_job.from_addr = from_addr;
751 ndmp_job.from_addr_given = 1;
752
753 to_addr = GetElementAddressByBareosSlotNumber(&store->rss->storage_mapping, slot_type_storage, dst_slot);
754 if (to_addr == -1) {
755 ua->ErrorMsg("No slot mapping for slot %hd\n", dst_slot);
756 return retval;
757 }
758 ndmp_job.to_addr = to_addr;
759 ndmp_job.to_addr_given = 1;
760
761 ua->WarningMsg(_ ("transferring form slot %hd to slot %hd...\n"), src_slot, dst_slot );
762
763 /*
764 * Set the remote robotics name to use.
765 * We use the ndmscsi_target_from_str() function which parses the NDMJOB format of a
766 * device in the form NAME[,[CNUM,]SID[,LUN]
767 */
768 ndmp_job.robot_target = (struct ndmscsi_target *)actuallymalloc(sizeof(struct ndmscsi_target));
769 if (ndmscsi_target_from_str(ndmp_job.robot_target, store->ndmp_changer_device) != 0) {
770 Actuallyfree(ndmp_job.robot_target);
771 return retval;
772 }
773 ndmp_job.have_robot = 1;
774 ndmp_job.auto_remedy = 1;
775
776 /*
777 * Initialize a new NDMP session
778 */
779 ndmp_sess = (struct ndm_session *)malloc(sizeof(struct ndm_session));
780 memset(ndmp_sess, 0, sizeof(struct ndm_session));
781
782 if (!NdmpRunStorageJob(ua->jcr, store, ndmp_sess, &ndmp_job)) {
783 CleanupNdmpSession(ndmp_sess);
784 return retval;
785 }
786
787 retval = true;
788
789 CleanupNdmpSession(ndmp_sess);
790
791 return retval;
792 }
793
794 /**
795 * reserve a NDMP Tape drive for a certain job
796 * lock the devinfo list
797 * check if any of the devices is available (deviceinfo.JobUsingDevice == 0)
798 * set the JobId into deviceinfo.JobUsingDevice
799 * unlock devinfo
800 * return name of device that was reserved
801 */
reserve_ndmp_tapedevice_for_job(StorageResource * store,JobControlRecord * jcr)802 std::string reserve_ndmp_tapedevice_for_job(StorageResource *store, JobControlRecord *jcr) {
803 JobId_t jobid = jcr->JobId;
804 std::string returnvalue;
805 P(store->rss->ndmp_deviceinfo_lock);
806
807 if (store->rss->ndmp_deviceinfo) {
808 for (auto devinfo = store->rss->ndmp_deviceinfo->begin();
809 devinfo != store->rss->ndmp_deviceinfo->end(); devinfo++) {
810 if (devinfo->JobIdUsingDevice == 0) {
811 devinfo->JobIdUsingDevice = jobid;
812 returnvalue = devinfo->device;
813 Jmsg(jcr, M_INFO, 0, _("successfully reserved NDMP Tape Device %s for job %d\n"),
814 returnvalue.c_str(), jobid);
815 break;
816 } else{
817 Jmsg(jcr, M_INFO, 0, _("NDMP Tape Device %s is already reserved for for job %d\n"),
818 devinfo->device.c_str(), devinfo->JobIdUsingDevice);
819 }
820 }
821 }
822 V(store->rss->ndmp_deviceinfo_lock);
823 return returnvalue;
824 }
825
826 /*
827 * remove job from tapedevice
828 */
unreserve_ndmp_tapedevice_for_job(StorageResource * store,JobControlRecord * jcr)829 bool unreserve_ndmp_tapedevice_for_job(StorageResource *store, JobControlRecord *jcr)
830 {
831 JobId_t jobid = jcr->JobId;
832 bool retval = false;
833 P(store->rss->ndmp_deviceinfo_lock);
834
835 if (store->rss->ndmp_deviceinfo) {
836 for (auto devinfo = store->rss->ndmp_deviceinfo->begin();
837 devinfo != store->rss->ndmp_deviceinfo->end(); devinfo++) {
838 if (devinfo->JobIdUsingDevice == jobid) {
839 devinfo->JobIdUsingDevice = 0;
840 retval = true;
841 Jmsg(jcr, M_INFO, 0, _("removed reservation of NDMP Tape Device %s for job %d\n"),
842 devinfo->device.c_str(), jobid);
843 break;
844 }
845 }
846 }
847 V(store->rss->ndmp_deviceinfo_lock);
848 return retval;
849 }
850
851 /**
852 * Lookup the name of a drive in a NDMP autochanger.
853 */
lookup_ndmp_drive(StorageResource * store,drive_number_t drivenumber)854 char *lookup_ndmp_drive(StorageResource *store, drive_number_t drivenumber)
855 {
856 int cnt = 0;
857 char *tapedevice;
858 CommonResourceHeader *tapedeviceres = nullptr;
859
860 if (store->device) {
861 foreach_alist(tapedeviceres, store->device) {
862 if (cnt == drivenumber) {
863 tapedevice = tapedeviceres->name;
864 return tapedevice;
865 }
866 cnt++;
867 }
868 }
869
870 return NULL;
871 }
872
873 /**
874 * Lookup the drive index by device name in a NDMP autochanger.
875 */
lookup_ndmp_driveindex_by_name(StorageResource * store,char * drivename)876 int lookup_ndmp_driveindex_by_name(StorageResource *store, char *drivename)
877 {
878 int cnt = 0;
879
880 if (!drivename) {
881 return -1;
882 }
883
884 if (store->rss->ndmp_deviceinfo) {
885 for (auto devinfo = store->rss->ndmp_deviceinfo->begin();
886 devinfo != store->rss->ndmp_deviceinfo->end();
887 devinfo++) {
888 if ((drivename == devinfo->device)) {
889 return cnt;
890 }
891 cnt++;
892 }
893 }
894 return -1;
895 }
896
897 /**
898 * Perform an autochanger operation in a NDMP autochanger.
899 */
NdmpAutochangerVolumeOperation(UaContext * ua,StorageResource * store,const char * operation,drive_number_t drive,slot_number_t slot)900 bool NdmpAutochangerVolumeOperation(UaContext *ua, StorageResource *store, const char *operation,
901 drive_number_t drive, slot_number_t slot)
902 {
903 drive_number_t drive_mapping;
904 int ndmp_operation;
905 bool retval = false;
906 struct ndm_job_param ndmp_job;
907 struct ndm_session *ndmp_sess;
908
909 Dmsg3(100, "NdmpAutochangerVolumeOperation: operation %s, drive %hd, slot %hd\n", operation, drive, slot);
910 ua->WarningMsg(_("NdmpAutochangerVolumeOperation: operation %s, drive %hd, slot %hd\n"), operation, drive, slot);
911 /*
912 * See if this is an autochanger.
913 */
914 if (!store->autochanger || !store->ndmp_changer_device) {
915 return retval;
916 }
917
918 if (bstrcmp(operation, "unmount") || bstrcmp(operation, "release")) {
919 ndmp_operation = NDM_JOB_OP_UNLOAD_TAPE;
920 } else if (bstrcmp(operation, "mount")) {
921 ndmp_operation = NDM_JOB_OP_LOAD_TAPE;
922 } else {
923 ua->ErrorMsg("Illegal autochanger operation %s\n", operation);
924 return retval;
925 }
926
927 if (!NdmpBuildStorageJob(ua->jcr,
928 store,
929 false, /* Setup Tape Agent */
930 true, /* Setup Robot Agent */
931 ndmp_operation,
932 &ndmp_job)) {
933 return retval;
934 }
935
936 /*
937 * See if the mappings are already determined.
938 */
939 if (!NdmpUpdateStorageMappings(ua, store)) {
940 return false;
941 }
942
943 if (slot >= 0) {
944 slot_number_t slot_mapping;
945
946 /*
947 * Map the logical address to a physical one.
948 */
949 slot_mapping = GetElementAddressByBareosSlotNumber(&store->rss->storage_mapping, slot_type_storage, slot);
950 if (slot_mapping == -1) {
951 ua->ErrorMsg("No slot mapping for slot %hd\n", slot);
952 return retval;
953 }
954 ndmp_job.from_addr = slot_mapping;
955 ndmp_job.from_addr_given = 1;
956 }
957
958 /*
959 * Map the logical address to a physical one.
960 */
961 drive_mapping = GetElementAddressByBareosSlotNumber(&store->rss->storage_mapping, slot_type_drive, slot);
962 if (drive_mapping == -1) {
963 ua->ErrorMsg("No slot mapping for drive %hd\n", drive);
964 return retval;
965 }
966 ndmp_job.drive_addr = drive_mapping;
967 ndmp_job.drive_addr_given = 1;
968
969 /*
970 * Set the remote robotics name to use.
971 * We use the ndmscsi_target_from_str() function which parses the NDMJOB format of a
972 * device in the form NAME[,[CNUM,]SID[,LUN]
973 */
974 ndmp_job.robot_target = (struct ndmscsi_target *)actuallymalloc(sizeof(struct ndmscsi_target));
975 if (ndmscsi_target_from_str(ndmp_job.robot_target, store->ndmp_changer_device) != 0) {
976 Actuallyfree(ndmp_job.robot_target);
977 return retval;
978 }
979 ndmp_job.have_robot = 1;
980 ndmp_job.auto_remedy = 1;
981
982 /*
983 * Initialize a new NDMP session
984 */
985 ndmp_sess = (struct ndm_session *)malloc(sizeof(struct ndm_session));
986 memset(ndmp_sess, 0, sizeof(struct ndm_session));
987
988 if (!NdmpRunStorageJob(ua->jcr, store, ndmp_sess, &ndmp_job)) {
989 CleanupNdmpSession(ndmp_sess);
990 return retval;
991 }
992
993 retval = true;
994
995 CleanupNdmpSession(ndmp_sess);
996
997 return retval;
998 }
999
1000 /**
1001 * Label a volume in a NDMP autochanger.
1002 */
NdmpSendLabelRequest(UaContext * ua,StorageResource * store,MediaDbRecord * mr,MediaDbRecord * omr,PoolDbRecord * pr,bool relabel,drive_number_t drive,slot_number_t slot)1003 bool NdmpSendLabelRequest(UaContext *ua, StorageResource *store, MediaDbRecord *mr,
1004 MediaDbRecord *omr, PoolDbRecord *pr, bool relabel,
1005 drive_number_t drive, slot_number_t slot)
1006 {
1007 bool retval = false;
1008 struct ndm_job_param ndmp_job;
1009 struct ndm_session *ndmp_sess;
1010 struct ndmmedia *media;
1011
1012 Dmsg4(100,"ndmp_send_label_request: VolumeName=%s MediaType=%s PoolName=%s drive=%hd\n", mr->VolumeName, mr->MediaType, pr->Name, drive);
1013
1014 /*
1015 * See if this is an autochanger.
1016 */
1017 if (!store->autochanger || !store->ndmp_changer_device) {
1018 return retval;
1019 }
1020
1021 if (!NdmpBuildStorageJob(ua->jcr,
1022 store,
1023 true, /* Setup Tape Agent */
1024 true, /* Setup Robot Agent */
1025 NDM_JOB_OP_INIT_LABELS,
1026 &ndmp_job)) {
1027 return retval;
1028 }
1029
1030 /*
1031 * Set the remote robotics name to use.
1032 * We use the ndmscsi_target_from_str() function which parses the NDMJOB format of a
1033 * device in the form NAME[,[CNUM,]SID[,LUN]
1034 */
1035 ndmp_job.robot_target = (struct ndmscsi_target *)actuallymalloc(sizeof(struct ndmscsi_target));
1036 if (ndmscsi_target_from_str(ndmp_job.robot_target, store->ndmp_changer_device) != 0) {
1037 Actuallyfree(ndmp_job.robot_target);
1038 Dmsg0(100,"NdmpSendLabelRequest: no robot to use\n");
1039 return retval;
1040 }
1041 ndmp_job.have_robot = 1;
1042 ndmp_job.auto_remedy = 1;
1043
1044 /*
1045 * Set the remote tape drive to use.
1046 */
1047 ndmp_job.tape_device = bstrdup(((DeviceResource*)(store->device->first()))->name());
1048 if (!ndmp_job.tape_device) {
1049 Actuallyfree(ndmp_job.robot_target);
1050 }
1051
1052 /*
1053 * Insert a media entry of the slot to label.
1054 */
1055 if (slot > 0) {
1056 slot_number_t slot_mapping;
1057
1058 slot_mapping = GetElementAddressByBareosSlotNumber(&store->rss->storage_mapping, slot_type_storage, slot);
1059 if (slot_mapping == -1) {
1060 ua->ErrorMsg("No slot mapping for slot %hd\n", slot);
1061 return retval;
1062 }
1063 media = ndma_store_media(&ndmp_job.media_tab, slot_mapping);
1064 } else {
1065 media = ndma_store_media(&ndmp_job.media_tab, 0);
1066 }
1067 bstrncpy(media->label, mr->VolumeName, NDMMEDIA_LABEL_MAX - 1);
1068 media->valid_label = NDMP9_VALIDITY_VALID;
1069
1070
1071 /*
1072 * Initialize a new NDMP session
1073 */
1074 ndmp_sess = (struct ndm_session *)malloc(sizeof(struct ndm_session));
1075 memset(ndmp_sess, 0, sizeof(struct ndm_session));
1076
1077 if (!NdmpRunStorageJob(ua->jcr, store, ndmp_sess, &ndmp_job)) {
1078 CleanupNdmpSession(ndmp_sess);
1079 return retval;
1080 }
1081
1082 retval = true;
1083
1084 CleanupNdmpSession(ndmp_sess);
1085
1086 return retval;
1087 }
1088
1089
ndmp_native_update_runtime_storage_status(JobControlRecord * jcr,StorageResource * store)1090 static bool ndmp_native_update_runtime_storage_status(JobControlRecord *jcr, StorageResource *store)
1091 {
1092
1093 bool retval = true;
1094
1095 P(store->rss->changer_lock);
1096 if ( !do_ndmp_native_query_tape_and_robot_agents(jcr, store) ) {
1097 retval = false;
1098 }
1099 V(store->rss->changer_lock);
1100
1101 P(store->rss->changer_lock);
1102 if( !NdmpUpdateStorageMappings(jcr, store) ) {
1103 retval = false;
1104 }
1105 V(store->rss->changer_lock);
1106
1107 return retval;
1108 }
1109
ndmp_native_setup_robot_and_tape_for_native_backup_job(JobControlRecord * jcr,StorageResource * store,ndm_job_param & ndmp_job)1110 bool ndmp_native_setup_robot_and_tape_for_native_backup_job(JobControlRecord* jcr, StorageResource* store,
1111 ndm_job_param& ndmp_job)
1112 {
1113 int driveaddress, driveindex;
1114 std::string tapedevice;
1115 bool retval = false;
1116 if ( !ndmp_native_update_runtime_storage_status(jcr, store) ) {
1117 Jmsg(jcr, M_ERROR, 0, _("Failed getting updating runtime storage status\n"));
1118 return retval;
1119 }
1120
1121 ndmp_job.robot_target = (struct ndmscsi_target *)actuallymalloc(sizeof(struct ndmscsi_target));
1122 if (ndmscsi_target_from_str(ndmp_job.robot_target, store->ndmp_changer_device) != 0) {
1123 Actuallyfree(ndmp_job.robot_target);
1124 Dmsg0(100,"no robot to use\n");
1125 return retval;
1126 }
1127
1128 tapedevice = reserve_ndmp_tapedevice_for_job(store, jcr);
1129 ndmp_job.tape_device = (char*)tapedevice.c_str();
1130
1131 driveindex = lookup_ndmp_driveindex_by_name(store, ndmp_job.tape_device);
1132
1133 if (driveindex == -1) {
1134 Jmsg(jcr, M_ERROR, 0, _("Could not find driveindex of drive %s\n"),
1135 ndmp_job.tape_device);
1136 return retval;
1137 }
1138
1139 driveaddress = GetElementAddressByBareosSlotNumber(&store->rss->storage_mapping, slot_type_drive, driveindex);
1140 if (driveaddress == -1) {
1141 Jmsg(jcr, M_ERROR, 0, _("Could not lookup driveaddress for driveindex %d\n"),
1142 driveaddress);
1143 return retval;
1144 }
1145 ndmp_job.drive_addr = driveaddress;
1146 ndmp_job.drive_addr_given = 1;
1147
1148 ndmp_job.have_robot = 1;
1149 /*
1150 * unload tape if tape is in drive
1151 */
1152 ndmp_job.auto_remedy = 1;
1153 ndmp_job.record_size = jcr->res.client->ndmp_blocksize;
1154
1155 Jmsg(jcr, M_INFO, 0, _("Using Data host %s\n"), ndmp_job.data_agent.host);
1156 Jmsg(jcr, M_INFO, 0, _("Using Tape host:device:address %s:%s:@%d\n"),
1157 ndmp_job.tape_agent.host, ndmp_job.tape_device, ndmp_job.drive_addr);
1158 Jmsg(jcr, M_INFO, 0, _("Using Robot host:device(ident) %s:%s(%s)\n"),
1159 ndmp_job.robot_agent.host, ndmp_job.robot_target, store->rss->smc_ident);
1160 Jmsg(jcr, M_INFO, 0, _("Using Tape record size %d\n"), ndmp_job.record_size);
1161
1162 return true;
1163 }
1164
1165
1166
1167
1168 #else
1169 /**
1170 * Dummy entry points when NDMP not enabled.
1171 */
1172 void DoNdmpStorageStatus(UaContext *ua, StorageResource *store, char *cmd)
1173 {
1174 Jmsg(ua->jcr, M_FATAL, 0, _("NDMP protocol not supported\n"));
1175 }
1176
1177 dlist *ndmp_get_vol_list(UaContext *ua, StorageResource *store, bool listall, bool scan)
1178 {
1179 Jmsg(ua->jcr, M_FATAL, 0, _("NDMP protocol not supported\n"));
1180 return (dlist *)NULL;
1181 }
1182
1183 slot_number_t NdmpGetNumSlots(UaContext *ua, StorageResource *store)
1184 {
1185 Jmsg(ua->jcr, M_FATAL, 0, _("NDMP protocol not supported\n"));
1186 return 0;
1187 }
1188
1189 drive_number_t NdmpGetNumDrives(UaContext *ua, StorageResource *store)
1190 {
1191 Jmsg(ua->jcr, M_FATAL, 0, _("NDMP protocol not supported\n"));
1192 return 0;
1193 }
1194
1195 bool NdmpTransferVolume(UaContext *ua, StorageResource *store,
1196 slot_number_t src_slot, slot_number_t dst_slot)
1197 {
1198 Jmsg(ua->jcr, M_FATAL, 0, _("NDMP protocol not supported\n"));
1199 return false;
1200 }
1201
1202 bool NdmpAutochangerVolumeOperation(UaContext *ua, StorageResource *store,
1203 const char *operation, drive_number_t drive, slot_number_t slot)
1204 {
1205 Jmsg(ua->jcr, M_FATAL, 0, _("NDMP protocol not supported\n"));
1206 return false;
1207 }
1208
1209 bool NdmpSendLabelRequest(UaContext *ua, StorageResource *store, MediaDbRecord *mr,
1210 MediaDbRecord *omr, PoolDbRecord *pr, bool relabel,
1211 drive_number_t drive, slot_number_t slot)
1212 {
1213 Jmsg(ua->jcr, M_FATAL, 0, _("NDMP protocol not supported\n"));
1214 return false;
1215 }
1216
1217 #endif /* HAVE_NDMP */
1218 } /* namespace directordaemon */
1219