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