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