/* * Read Data and send to File Daemon * * Returns: false on failure * true on success */ bool do_read_data(JCR *jcr) { BSOCK *fd = jcr->file_bsock; DCR *dcr = jcr->read_dcr; bool ok = true; Dmsg0(20, "Start read data.\n"); if (!bnet_set_buffer_size(fd, dcr->device->max_network_buffer_size, BNET_SETBUF_WRITE)) { return false; } if (jcr->NumReadVolumes == 0) { Jmsg(jcr, M_FATAL, 0, _("No Volume names found for restore.\n")); fd->fsend(FD_error); return false; } Dmsg2(200, "Found %d volumes names to restore. First=%s\n", jcr->NumReadVolumes, jcr->VolList->VolumeName); /* * Ready device for reading */ if (!acquire_device_for_read(dcr)) { fd->fsend(FD_error); return false; } /* * Let any SD plugin know now its time to setup the record translation infra. */ if (generate_plugin_event(jcr, bsdEventSetupRecordTranslation, dcr) != bRC_OK) { jcr->setJobStatus(JS_ErrorTerminated); return false; } /* * Tell File daemon we will send data */ fd->fsend(OK_data); jcr->sendJobStatus(JS_Running); ok = read_records(dcr, record_cb, mount_next_read_volume); /* * Send end of data to FD */ fd->signal(BNET_EOD); if (!release_device(jcr->read_dcr)) { ok = false; } Dmsg0(30, "Done reading.\n"); return ok; }
/* * Read Data and send to File Daemon * Returns: false on failure * true on success */ bool do_read_data(JCR *jcr) { BSOCK *fd = jcr->file_bsock; bool ok = true; DCR *dcr = jcr->read_dcr; Dmsg0(20, "Start read data.\n"); if (!bnet_set_buffer_size(fd, dcr->device->max_network_buffer_size, BNET_SETBUF_WRITE)) { return false; } if (jcr->NumReadVolumes == 0) { Jmsg(jcr, M_FATAL, 0, _("No Volume names found for restore.\n")); fd->fsend(FD_error); return false; } Dmsg2(200, "Found %d volumes names to restore. First=%s\n", jcr->NumReadVolumes, jcr->VolList->VolumeName); /* Ready device for reading */ if (!acquire_device_for_read(dcr)) { fd->fsend(FD_error); return false; } /* Tell File daemon we will send data */ fd->fsend(OK_data); jcr->sendJobStatus(JS_Running); ok = read_records(dcr, record_cb, mount_next_read_volume); /* Send end of data to FD */ fd->signal(BNET_EOD); if (!release_device(jcr->read_dcr)) { ok = false; } Dmsg0(30, "Done reading.\n"); return ok; }
/* * If we are reading, we come here at the end of the tape * and see if there are more volumes to be mounted. */ bool mount_next_read_volume(DCR *dcr) { DEVICE *dev = dcr->dev; JCR *jcr = dcr->jcr; Dmsg2(90, "NumReadVolumes=%d CurReadVolume=%d\n", jcr->NumReadVolumes, jcr->CurReadVolume); volume_unused(dcr); /* release current volume */ /* * End Of Tape -- mount next Volume (if another specified) */ if (jcr->NumReadVolumes > 1 && jcr->CurReadVolume < jcr->NumReadVolumes) { dev->close(); if (!acquire_device_for_read(dcr)) { Jmsg2(jcr, M_FATAL, 0, _("Cannot open Dev=%s, Vol=%s\n"), dev->print_name(), dcr->VolumeName); return false; } return true; /* next volume mounted */ } Dmsg0(90, "End of Device reached.\n"); return false; }
/* * Setup device, jcr, and prepare to access device. * If the caller wants read access, acquire the device, otherwise, * the caller will do it. */ static DCR *setup_to_access_device(JCR *jcr, char *dev_name, const char *VolumeName, int mode) { DEVICE *dev; char *p; DEVRES *device; DCR *dcr; char VolName[MAX_NAME_LENGTH]; init_reservations_lock(); /* * If no volume name already given and no bsr, and it is a file, * try getting name from Filename */ if (VolumeName) { bstrncpy(VolName, VolumeName, sizeof(VolName)); if (strlen(VolumeName) >= MAX_NAME_LENGTH) { Jmsg0(jcr, M_ERROR, 0, _("Volume name or names is too long. Please use a .bsr file.\n")); } } else { VolName[0] = 0; } if (!jcr->bsr && VolName[0] == 0) { if (!bstrncmp(dev_name, "/dev/", 5)) { /* Try stripping file part */ p = dev_name + strlen(dev_name); while (p >= dev_name && !IsPathSeparator(*p)) p--; if (IsPathSeparator(*p)) { bstrncpy(VolName, p+1, sizeof(VolName)); *p = 0; } } } if ((device=find_device_res(dev_name, mode)) == NULL) { Jmsg2(jcr, M_FATAL, 0, _("Cannot find device \"%s\" in config file %s.\n"), dev_name, configfile); return NULL; } dev = init_dev(jcr, device); if (!dev) { Jmsg1(jcr, M_FATAL, 0, _("Cannot init device %s\n"), dev_name); return NULL; } device->dev = dev; jcr->dcr = dcr = new_dcr(jcr, NULL, dev); if (VolName[0]) { bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName)); } bstrncpy(dcr->dev_name, device->device_name, sizeof(dcr->dev_name)); create_restore_volume_list(jcr); if (mode) { /* read only access? */ Dmsg0(100, "Acquire device for read\n"); if (!acquire_device_for_read(dcr)) { return NULL; } jcr->read_dcr = dcr; } else { if (!first_open_device(dcr)) { Jmsg1(jcr, M_FATAL, 0, _("Cannot open %s\n"), dev->print_name()); return NULL; } jcr->dcr = dcr; /* write dcr */ } return dcr; }
/* * Read Data and commit to new job. */ bool do_mac_run(JCR *jcr) { DEVICE *dev; char ec1[50]; const char *Type; bool ok = true; BSOCK *dir = jcr->dir_bsock; switch(jcr->getJobType()) { case JT_MIGRATE: Type = "Migration"; break; case JT_ARCHIVE: Type = "Archive"; break; case JT_COPY: Type = "Copy"; break; case JT_BACKUP: Type = "Virtual Backup"; break; default: Type = "Unknown"; break; } Dmsg0(20, "Start read data.\n"); if (jcr->NumReadVolumes == 0) { Jmsg(jcr, M_FATAL, 0, _("No Volume names found for %s.\n"), Type); goto bail_out; } /* * Check autoinflation/autodeflation settings. */ check_auto_xflation(jcr); /* * See if we perform both read and write or read only. */ if (jcr->remote_replicate) { BSOCK *sd; if (!jcr->read_dcr) { Jmsg(jcr, M_FATAL, 0, _("Read device not properly initialized.\n")); goto bail_out; } Dmsg1(100, "read_dcr=%p\n", jcr->read_dcr); Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumReadVolumes, Type, jcr->VolList->VolumeName); /* * Ready devices for reading. */ if (!acquire_device_for_read(jcr->read_dcr)) { ok = false; goto bail_out; } Dmsg2(200, "===== After acquire pos %u:%u\n", jcr->read_dcr->dev->file, jcr->read_dcr->dev->block_num); jcr->sendJobStatus(JS_Running); /* * Set network buffering. */ sd = jcr->store_bsock; if (!sd->set_buffer_size(me->max_network_buffer_size, BNET_SETBUF_WRITE)) { Jmsg(jcr, M_FATAL, 0, _("Cannot set buffer size SD->SD.\n")); ok = false; goto bail_out; } /* * Let the remote SD know we are about to start the replication. */ sd->fsend(start_replicate); Dmsg1(110, ">stored: %s", sd->msg); /* * Expect to receive back the Ticket number. */ if (bget_msg(sd) >= 0) { Dmsg1(110, "<stored: %s", sd->msg); if (sscanf(sd->msg, OK_start_replicate, &jcr->Ticket) != 1) { Jmsg(jcr, M_FATAL, 0, _("Bad response to start replicate: %s\n"), sd->msg); goto bail_out; } Dmsg1(110, "Got Ticket=%d\n", jcr->Ticket); } else { Jmsg(jcr, M_FATAL, 0, _("Bad response from stored to start replicate command\n")); goto bail_out; } /* * Let the remote SD know we are now really going to send the data. */ sd->fsend(replicate_data, jcr->Ticket); Dmsg1(110, ">stored: %s", sd->msg); /* * Expect to get response to the replicate data cmd from Storage daemon */ if (!response(jcr, sd, OK_data, "replicate data")) { ok = false; goto bail_out; } /* * Read all data and send it to remote SD. */ ok = read_records(jcr->read_dcr, clone_record_to_remote_sd, mount_next_read_volume); /* * Send the last EOD to close the last data transfer and a next EOD to * signal the remote we are done. */ if (!sd->signal(BNET_EOD) || !sd->signal(BNET_EOD)) { if (!jcr->is_job_canceled()) { Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror()); } goto bail_out; } /* * Expect to get response that the replicate data succeeded. */ if (!response(jcr, sd, OK_replicate, "replicate data")) { ok = false; goto bail_out; } /* * End replicate session. */ sd->fsend(end_replicate); Dmsg1(110, ">stored: %s", sd->msg); /* * Expect to get response to the end replicate cmd from Storage daemon */ if (!response(jcr, sd, OK_end_replicate, "end replicate")) { ok = false; goto bail_out; } /* Inform Storage daemon that we are done */ sd->signal(BNET_TERMINATE); } else { if (!jcr->read_dcr || !jcr->dcr) { Jmsg(jcr, M_FATAL, 0, _("Read and write devices not properly initialized.\n")); goto bail_out; } Dmsg2(100, "read_dcr=%p write_dcr=%p\n", jcr->read_dcr, jcr->dcr); Dmsg3(200, "Found %d volumes names for %s. First=%s\n", jcr->NumReadVolumes, Type, jcr->VolList->VolumeName); /* * Ready devices for reading and writing. */ if (!acquire_device_for_read(jcr->read_dcr) || !acquire_device_for_append(jcr->dcr)) { ok = false; goto bail_out; } Dmsg2(200, "===== After acquire pos %u:%u\n", jcr->dcr->dev->file, jcr->dcr->dev->block_num); jcr->sendJobStatus(JS_Running); if (!begin_data_spool(jcr->dcr) ) { ok = false; goto bail_out; } if (!begin_attribute_spool(jcr)) { ok = false; goto bail_out; } jcr->dcr->VolFirstIndex = jcr->dcr->VolLastIndex = 0; jcr->run_time = time(NULL); set_start_vol_position(jcr->dcr); jcr->JobFiles = 0; /* * Read all data and make a local clone of it. */ ok = read_records(jcr->read_dcr, clone_record_internally, mount_next_read_volume); } bail_out: if (!ok) { jcr->setJobStatus(JS_ErrorTerminated); } if (!jcr->remote_replicate && jcr->dcr) { /* * Don't use time_t for job_elapsed as time_t can be 32 or 64 bits, * and the subsequent Jmsg() editing will break */ int32_t job_elapsed; dev = jcr->dcr->dev; Dmsg1(100, "ok=%d\n", ok); if (ok || dev->can_write()) { /* * Flush out final partial block of this session */ if (!jcr->dcr->write_block_to_device()) { Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), dev->print_name(), dev->bstrerror()); Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n")); ok = false; } Dmsg2(200, "Flush block to device pos %u:%u\n", dev->file, dev->block_num); } if (!ok) { discard_data_spool(jcr->dcr); } else { /* * Note: if commit is OK, the device will remain blocked */ commit_data_spool(jcr->dcr); } job_elapsed = time(NULL) - jcr->run_time; if (job_elapsed <= 0) { job_elapsed = 1; } Jmsg(jcr, M_INFO, 0, _("Elapsed time=%02d:%02d:%02d, Transfer rate=%s Bytes/second\n"), job_elapsed / 3600, job_elapsed % 3600 / 60, job_elapsed % 60, edit_uint64_with_suffix(jcr->JobBytes / job_elapsed, ec1)); /* * Release the device -- and send final Vol info to DIR */ release_device(jcr->dcr); if (!ok || job_canceled(jcr)) { discard_attribute_spool(jcr); } else { commit_attribute_spool(jcr); } } if (jcr->read_dcr) { if (!release_device(jcr->read_dcr)) { ok = false; } } jcr->sendJobStatus(); /* update director */ Dmsg0(30, "Done reading.\n"); jcr->end_time = time(NULL); dequeue_messages(jcr); /* send any queued messages */ if (ok) { jcr->setJobStatus(JS_Terminated); } generate_plugin_event(jcr, bsdEventJobEnd); dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, edit_uint64(jcr->JobBytes, ec1), jcr->JobErrors); Dmsg4(100, Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, ec1); dir->signal(BNET_EOD); /* send EOD to Director daemon */ free_plugins(jcr); /* release instantiated plugins */ return false; /* Continue DIR session ? */ }