/* * 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; }
/** * After writing a Volume, create the JobMedia record. */ bool dir_create_jobmedia_record(DCR *dcr, bool zero) { JCR *jcr = dcr->jcr; BSOCK *dir = jcr->dir_bsock; char ed1[50]; /* If system job, do not update catalog */ if (jcr->is_JobType(JT_SYSTEM)) { return true; } /* Throw out records where FI is zero -- i.e. nothing done */ if (!zero && dcr->VolFirstIndex == 0 && (dcr->StartBlock != 0 || dcr->EndBlock != 0)) { Dmsg0(dbglvl, "JobMedia FI=0 StartBlock!=0 record suppressed\n"); return true; } if (!dcr->WroteVol) { return true; /* nothing written to tape */ } dcr->WroteVol = false; if (zero) { /* Send dummy place holder to avoid purging */ dir->fsend(Create_job_media, jcr->Job, 0 , 0, 0, 0, 0, 0, 0, 0, edit_uint64(dcr->VolMediaId, ed1)); } else { dir->fsend(Create_job_media, jcr->Job, dcr->VolFirstIndex, dcr->VolLastIndex, dcr->StartFile, dcr->EndFile, dcr->StartBlock, dcr->EndBlock, dcr->Copy, dcr->Stripe, edit_uint64(dcr->VolMediaId, ed1)); } Dmsg1(dbglvl, ">dird %s", dir->msg); if (dir->recv() <= 0) { Dmsg0(dbglvl, "create_jobmedia error bnet_recv\n"); Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"), dir->bstrerror()); return false; } Dmsg1(dbglvl, "<dird %s", dir->msg); if (!bstrcmp(dir->msg, OK_create)) { Dmsg1(dbglvl, "Bad response from Dir: %s\n", dir->msg); Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg); return false; } return true; }
/* * Read Data command * Open Data Channel, read the data from * the archive device and send to File * daemon. */ static bool read_data_cmd(JCR *jcr) { BSOCK *fd = jcr->file_bsock; Dmsg1(120, "Read data: %s", fd->msg); if (jcr->session_opened) { Dmsg1(120, "<bfiled: %s", fd->msg); return do_read_data(jcr); } else { pm_strcpy(jcr->errmsg, _("Attempt to read on non-open session.\n")); fd->fsend(NOT_opened); return false; } }
/* * Initiate the message channel with the Director. * It has made a connection to our server. * * Basic tasks done here: * - Assume the Hello message is already in the input buffer. * - Authenticate * - Get device * - Get media * - Get pool information * * This is the channel across which we will send error * messages and job status information. */ bool authenticate_director(JCR *jcr) { BSOCK *dir = jcr->dir_bsock; if (!two_way_authenticate(R_DIRECTOR, dir, jcr)) { dir->fsend("%s", Dir_sorry); Dmsg1(dbglvl, "Unable to authenticate Director at %s.\n", dir->who()); Jmsg1(jcr, M_ERROR, 0, _("Unable to authenticate Director at %s.\n"), dir->who()); bmicrosleep(5, 0); return false; } return dir->fsend("%s", OK_hello); }
void cancel_storage_daemon_job(JCR *jcr) { if (jcr->sd_canceled) { return; /* cancel only once */ } UAContext *ua = new_ua_context(jcr); JCR *control_jcr = new_control_jcr("*JobCancel*", JT_SYSTEM); BSOCK *sd; ua->jcr = control_jcr; if (jcr->store_bsock) { if (!ua->jcr->wstorage) { if (jcr->rstorage) { copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource")); } else { copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource")); } } else { USTORE store; if (jcr->rstorage) { store.store = jcr->rstore; } else { store.store = jcr->wstore; } set_wstorage(ua->jcr, &store); } if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) { goto bail_out; } Dmsg0(200, "Connected to storage daemon\n"); sd = ua->jcr->store_bsock; sd->fsend("cancel Job=%s\n", jcr->Job); while (sd->recv() >= 0) { } sd->signal(BNET_TERMINATE); sd->close(); ua->jcr->store_bsock = NULL; jcr->sd_canceled = true; jcr->store_bsock->set_timed_out(); jcr->store_bsock->set_terminated(); sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL); jcr->my_thread_send_signal(TIMEOUT_SIGNAL); } bail_out: free_jcr(control_jcr); free_ua_context(ua); }
/* * Cancel a running job on a storage daemon. The silent flag sets * if we need to be silent or not e.g. when doing an interactive cancel * or a system invoked one. */ bool cancel_storage_daemon_job(UAContext *ua, JCR *jcr, bool silent) { BSOCK *sd; USTORERES store; if (!ua->jcr->wstorage) { if (jcr->rstorage) { copy_wstorage(ua->jcr, jcr->rstorage, _("Job resource")); } else { copy_wstorage(ua->jcr, jcr->wstorage, _("Job resource")); } } else { if (jcr->rstorage) { store.store = jcr->res.rstore; } else { store.store = jcr->res.wstore; } set_wstorage(ua->jcr, &store); } if (!connect_to_storage_daemon(ua->jcr, 10, me->SDConnectTimeout, true)) { if (!silent) { ua->error_msg(_("Failed to connect to Storage daemon.\n")); } return false; } Dmsg0(200, "Connected to storage daemon\n"); sd = ua->jcr->store_bsock; sd->fsend(canceljobcmd, jcr->Job); while (sd->recv() >= 0) { if (!silent) { ua->send_msg("%s", sd->msg); } } sd->signal(BNET_TERMINATE); sd->close(); delete ua->jcr->store_bsock; ua->jcr->store_bsock = NULL; if (silent) { jcr->sd_canceled = true; } jcr->store_bsock->set_timed_out(); jcr->store_bsock->set_terminated(); sd_msg_thread_send_signal(jcr, TIMEOUT_SIGNAL); jcr->my_thread_send_signal(TIMEOUT_SIGNAL); return true; }
/* * Execute a command from the UA */ bool do_a_dot_command(UAContext *ua) { int i; int len; bool ok = false; bool found = false; BSOCK *user = ua->UA_sock; Dmsg1(1400, "Dot command: %s\n", user->msg); if (ua->argc == 0) { return false; } len = strlen(ua->argk[0]); if (len == 1) { if (ua->api) user->signal(BNET_CMD_BEGIN); if (ua->api) user->signal(BNET_CMD_OK); return true; /* no op */ } for (i=0; i<comsize; i++) { /* search for command */ if (bstrncasecmp(ua->argk[0], _(commands[i].key), len)) { /* Check if this command is authorized in RunScript */ if (ua->runscript && !commands[i].use_in_rs) { ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]); break; } bool gui = ua->gui; /* Check if command permitted, but "quit" is always OK */ if (!bstrcmp(ua->argk[0], NT_(".quit")) && !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) { break; } Dmsg1(100, "Cmd: %s\n", ua->cmd); ua->gui = true; if (ua->api) user->signal(BNET_CMD_BEGIN); ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */ if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED); ua->gui = gui; found = true; break; } } if (!found) { ua->error_msg("%s%s", ua->argk[0], _(": is an invalid command.\n")); ok = false; } return ok; }
/** * Get Volume info for a specific volume from the Director's Database * * Returns: true on success (Director guarantees that Pool and MediaType * are correct and VolStatus==Append or * VolStatus==Recycle) * false on failure * * Volume information returned in dcr->VolCatInfo */ bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw writing) { JCR *jcr = dcr->jcr; BSOCK *dir = jcr->dir_bsock; P(vol_info_mutex); dcr->setVolCatName(dcr->VolumeName); bash_spaces(dcr->getVolCatName()); dir->fsend(Get_Vol_Info, jcr->Job, dcr->getVolCatName(), writing==GET_VOL_INFO_FOR_WRITE?1:0); Dmsg1(dbglvl, ">dird %s", dir->msg); unbash_spaces(dcr->getVolCatName()); bool ok = do_get_volume_info(dcr); V(vol_info_mutex); return ok; }
/* * Now talk to the FD and do what he says */ void do_fd_commands(JCR *jcr) { int i; bool found, quit; BSOCK *fd = jcr->file_bsock; fd->set_jcr(jcr); for (quit=false; !quit;) { int stat; /* Read command coming from the File daemon */ stat = fd->recv(); if (is_bnet_stop(fd)) { /* hardeof or error */ break; /* connection terminated */ } if (stat <= 0) { continue; /* ignore signals and zero length msgs */ } Dmsg1(110, "<filed: %s", fd->msg); found = false; for (i=0; fd_cmds[i].cmd; i++) { if (strncmp(fd_cmds[i].cmd, fd->msg, strlen(fd_cmds[i].cmd)) == 0) { found = true; /* indicate command found */ jcr->errmsg[0] = 0; if (!fd_cmds[i].func(jcr) || job_canceled(jcr)) { /* do command */ /* Note fd->msg command may be destroyed by comm activity */ if (jcr->errmsg[0]) { Jmsg1(jcr, M_FATAL, 0, _("Command error with FD, hanging up. %s\n"), jcr->errmsg); } else { Jmsg0(jcr, M_FATAL, 0, _("Command error with FD, hanging up.\n")); } set_jcr_job_status(jcr, JS_ErrorTerminated); quit = true; } break; } } if (!found) { /* command not found */ Jmsg1(jcr, M_FATAL, 0, _("FD command not found: %s\n"), fd->msg); Dmsg1(110, "<filed: Command not found: %s\n", fd->msg); fd->fsend(ferrmsg); break; } } fd->signal(BNET_TERMINATE); /* signal to FD job is done */ }
/** * Get Volume info for a specific volume from the Director's Database * * Returns: true on success (Director guarantees that Pool and MediaType * are correct and VolStatus==Append or * VolStatus==Recycle) * false on failure * * Volume information returned in dcr->VolCatInfo */ bool SD_DCR::dir_get_volume_info(enum get_vol_info_rw writing) { bool ok; BSOCK *dir = jcr->dir_bsock; P(vol_info_mutex); setVolCatName(VolumeName); bash_spaces(getVolCatName()); dir->fsend(Get_Vol_Info, jcr->Job, getVolCatName(), (writing == GET_VOL_INFO_FOR_WRITE) ? 1 : 0); Dmsg1(dbglvl, ">dird %s", dir->msg); unbash_spaces(getVolCatName()); ok = do_get_volume_info(this); V(vol_info_mutex); return ok; }
bool finish_cmd(JCR *jcr) { BSOCK *dir = jcr->dir_bsock; char ec1[30]; /* * See if the Job has a certain protocol. Some protocols allow the * finish cmd some do not (Native backup for example does NOT) */ switch (jcr->getJobProtocol()) { case PT_NDMP: Dmsg1(200, "Finish_cmd: %s", jcr->dir_bsock->msg); jcr->end_time = time(NULL); dequeue_messages(jcr); /* send any queued messages */ jcr->setJobStatus(JS_Terminated); switch (jcr->getJobType()) { case JT_BACKUP: end_of_ndmp_backup(jcr); break; case JT_RESTORE: end_of_ndmp_restore(jcr); break; default: break; } generate_plugin_event(jcr, bsdEventJobEnd); dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, edit_uint64(jcr->JobBytes, ec1), jcr->JobErrors); dir->signal(BNET_EOD); /* send EOD to Director daemon */ free_plugins(jcr); /* release instantiated plugins */ Dmsg2(800, "Done jid=%d %p\n", jcr->JobId, jcr); return false; /* Continue DIR session ? */ default: Dmsg1(200, "Finish_cmd: %s", jcr->dir_bsock->msg); Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s tries to use finish cmd while not part of protocol.\n"), (uint32_t)jcr->JobId, jcr->Job); return false; /* Continue DIR session ? */ } }
/* * Authenticate Director */ static int authenticate_director(JCR *jcr) { const MONITORRES *monitor = MonitorItemThread::instance()->getMonitor(); BSOCK *dir = jcr->dir_bsock; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; bool compatible = true; char bashed_name[MAX_NAME_LENGTH]; char *password; bstrncpy(bashed_name, monitor->hdr.name, sizeof(bashed_name)); bash_spaces(bashed_name); password = monitor->password; /* Timeout Hello after 5 mins */ btimer_t *tid = start_bsock_timer(dir, 60 * 5); dir->fsend(DIRhello, bashed_name); if (!cram_md5_respond(dir, password, &tls_remote_need, &compatible) || !cram_md5_challenge(dir, password, tls_local_need, compatible)) { stop_bsock_timer(tid); Jmsg1(jcr, M_FATAL, 0, _("Director authorization problem.\n" "Most likely the passwords do not agree.\n" "Please see %s for help.\n"), MANUAL_AUTH_URL); return 0; } Dmsg1(6, ">dird: %s", dir->msg); if (dir->recv() <= 0) { stop_bsock_timer(tid); Jmsg1(jcr, M_FATAL, 0, _("Bad response to Hello command: ERR=%s\n"), dir->bstrerror()); return 0; } Dmsg1(10, "<dird: %s", dir->msg); stop_bsock_timer(tid); if (strncmp(dir->msg, DIROKhello, sizeof(DIROKhello)-1) != 0) { Jmsg0(jcr, M_FATAL, 0, _("Director rejected Hello command\n")); return 0; } else { Jmsg0(jcr, M_INFO, 0, dir->msg); } return 1; }
BSOCK *dup_bsock(BSOCK *osock) { BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK)); memcpy(bsock, osock, sizeof(BSOCK)); bsock->msg = get_pool_memory(PM_BSOCK); bsock->errmsg = get_pool_memory(PM_MESSAGE); if (osock->who()) { bsock->set_who(bstrdup(osock->who())); } if (osock->host()) { bsock->set_host(bstrdup(osock->host())); } if (osock->src_addr) { bsock->src_addr = New( IPADDR( *(osock->src_addr)) ); } bsock->set_duped(); return bsock; }
/* * Read Close session command * Close the read session */ static bool read_close_session(JCR *jcr) { BSOCK *fd = jcr->file_bsock; Dmsg1(120, "Read close session: %s\n", fd->msg); if (!jcr->session_opened) { fd->fsend(NOT_opened); return false; } /* Send final close msg to File daemon */ fd->fsend(OK_close, jcr->JobStatus); Dmsg1(160, ">filed: %s\n", fd->msg); fd->signal(BNET_EOD); /* send EOD to File daemon */ jcr->session_opened = false; return true; }
/* * Authenticate File daemon connection */ static int authenticate_file_daemon(JCR *jcr, CLIENTRES* client) { const MONITORRES *monitor = MonitorItemThread::instance()->getMonitor(); BSOCK *fd = jcr->file_bsock; char dirname[MAX_NAME_LENGTH]; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; bool compatible = true; /* * Send my name to the File daemon then do authentication */ bstrncpy(dirname, monitor->hdr.name, sizeof(dirname)); bash_spaces(dirname); /* Timeout Hello after 5 mins */ btimer_t *tid = start_bsock_timer(fd, 60 * 5); if (!fd->fsend(SDFDhello, dirname)) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to File daemon. ERR=%s\n"), bnet_strerror(fd)); return 0; } if (!cram_md5_respond(fd, client->password, &tls_remote_need, &compatible) || !cram_md5_challenge(fd, client->password, tls_local_need, compatible)) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Director and File daemon passwords or names not the same.\n" "Please see " MANUAL_AUTH_URL " for help.\n")); return 0; } Dmsg1(116, ">filed: %s", fd->msg); if (fd->recv() <= 0) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Bad response from File daemon to Hello command: ERR=%s\n"), fd->bstrerror()); return 0; } Dmsg1(110, "<stored: %s", fd->msg); stop_bsock_timer(tid); if (strncmp(fd->msg, FDOKhello, sizeof(FDOKhello)-1) != 0) { Jmsg(jcr, M_FATAL, 0, _("File daemon rejected Hello command\n")); return 0; } return 1; }
/* * Append Close session command * Close the append session and send back Statistics * (need to fix statistics) */ static bool append_close_session(JCR *jcr) { BSOCK *fd = jcr->file_bsock; Dmsg1(120, "<filed: %s", fd->msg); if (!jcr->session_opened) { pm_strcpy(jcr->errmsg, _("Attempt to close non-open session.\n")); fd->fsend(NOT_opened); return false; } /* Send final statistics to File daemon */ fd->fsend(OK_close, jcr->JobStatus); Dmsg1(120, ">filed: %s", fd->msg); fd->signal(BNET_EOD); /* send EOD to File daemon */ jcr->session_opened = false; return true; }
/* * Append Open session command * */ static bool append_open_session(JCR *jcr) { BSOCK *fd = jcr->file_bsock; Dmsg1(120, "Append open session: %s", fd->msg); if (jcr->session_opened) { pm_strcpy(jcr->errmsg, _("Attempt to open already open session.\n")); fd->fsend(NO_open); return false; } jcr->session_opened = true; /* Send "Ticket" to File Daemon */ fd->fsend(OK_open, jcr->VolSessionId); Dmsg1(110, ">filed: %s", fd->msg); return true; }
/* * We get the volume name from the SD */ char *get_volume_name_from_SD(UAContext *ua, int Slot, int drive) { BSOCK *sd; STORERES *store = ua->jcr->res.wstore; char dev_name[MAX_NAME_LENGTH]; char *VolName = NULL; int rtn_slot; if (!(sd = open_sd_bsock(ua))) { ua->error_msg(_("Could not open SD socket.\n")); return NULL; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* * Ask storage daemon to read the label of the volume in a * specific slot of the autochanger using the drive number given. * This could change the loaded volume in the drive. */ sd->fsend(readlabelcmd, dev_name, Slot, drive); Dmsg1(100, "Sent: %s", sd->msg); /* * Get Volume name in this Slot */ while (sd->recv() >= 0) { ua->send_msg("%s", sd->msg); Dmsg1(100, "Got: %s", sd->msg); if (strncmp(sd->msg, NT_("3001 Volume="), 12) == 0) { VolName = (char *)malloc(sd->msglen); if (sscanf(sd->msg, readlabelresponse, VolName, &rtn_slot) == 2) { break; } free(VolName); VolName = NULL; } } close_sd_bsock(ua); Dmsg1(100, "get_vol_name=%s\n", NPRT(VolName)); return VolName; }
/* * Ask the autochanger to move a volume from one slot to an other. * You have to update the database slots yourself afterwards. */ bool transfer_volume(UAContext *ua, STORERES *store, int src_slot, int dst_slot) { BSOCK *sd = NULL; bool retval = true; char dev_name[MAX_NAME_LENGTH]; if (!(sd = open_sd_bsock(ua))) { return false; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); /* * Ask for autochanger transfer of volumes */ sd->fsend(changertransfercmd, dev_name, src_slot, dst_slot); while (bnet_recv(sd) >= 0) { strip_trailing_junk(sd->msg); /* * Check for returned SD messages */ if (sd->msg[0] == '3' && B_ISDIGIT(sd->msg[1]) && B_ISDIGIT(sd->msg[2]) && B_ISDIGIT(sd->msg[3]) && sd->msg[4] == ' ') { /* * See if this is a failure msg. */ if (sd->msg[0] == '3' && sd->msg[0] == '9') retval = false; ua->send_msg("%s\n", sd->msg); /* pass them on to user */ continue; } ua->send_msg("%s\n", sd->msg); /* pass them on to user */ } close_sd_bsock(ua); return retval; }
/* * Authenticate Storage daemon connection */ int authenticate_storage_daemon(JCR *jcr, MONITOR *monitor, STORE* store) { BSOCK *sd = jcr->store_bsock; char dirname[MAX_NAME_LENGTH]; int tls_local_need = BNET_TLS_NONE; int tls_remote_need = BNET_TLS_NONE; int compatible = true; /* * Send my name to the Storage daemon then do authentication */ bstrncpy(dirname, monitor->hdr.name, sizeof(dirname)); bash_spaces(dirname); /* Timeout Hello after 5 mins */ btimer_t *tid = start_bsock_timer(sd, 60 * 5); if (!sd->fsend(SDFDhello, dirname)) { stop_bsock_timer(tid); Jmsg(jcr, M_FATAL, 0, _("Error sending Hello to Storage daemon. ERR=%s\n"), sd->bstrerror()); return 0; } if (!cram_md5_respond(sd, store->password, &tls_remote_need, &compatible) || !cram_md5_challenge(sd, store->password, tls_local_need, compatible)) { stop_bsock_timer(tid); Jmsg0(jcr, M_FATAL, 0, _("Director and Storage daemon passwords or names not the same.\n" "Please see " MANUAL_AUTH_URL " for help.\n")); return 0; } Dmsg1(116, ">stored: %s", sd->msg); if (sd->recv() <= 0) { stop_bsock_timer(tid); Jmsg1(jcr, M_FATAL, 0, _("bdird<stored: bad response to Hello command: ERR=%s\n"), sd->bstrerror()); return 0; } Dmsg1(110, "<stored: %s", sd->msg); stop_bsock_timer(tid); if (strncmp(sd->msg, SDOKhello, sizeof(SDOKhello)) != 0) { Jmsg0(jcr, M_FATAL, 0, _("Storage daemon rejected Hello command\n")); return 0; } return 1; }
/* * Replicate data. * Open Data Channel and receive Data for archiving * Write the Data to the archive device */ static bool replicate_data(JCR *jcr) { BSOCK *sd = jcr->store_bsock; Dmsg1(120, "Replicate data: %s", sd->msg); if (jcr->session_opened) { Dmsg1(110, "<stored: %s", sd->msg); if (do_append_data(jcr, sd, "SD")) { return true; } else { pm_strcpy(jcr->errmsg, _("Replicate data error.\n")); bnet_suppress_error_messages(sd, 1); /* ignore errors at this point */ sd->fsend(ERROR_replicate); } } else { pm_strcpy(jcr->errmsg, _("Attempt to replicate on non-open session.\n")); sd->fsend(NOT_opened); } return false; }
/* Initialize internal socket structure. * This probably should be done in net_open */ BSOCK *init_bsock(JCR * jcr, int sockfd, const char *who, const char *host, int port, struct sockaddr *client_addr) { Dmsg3(100, "who=%s host=%s port=%d\n", who, host, port); BSOCK *bsock = (BSOCK *)malloc(sizeof(BSOCK)); memset(bsock, 0, sizeof(BSOCK)); bsock->m_fd = sockfd; bsock->tls = NULL; bsock->errors = 0; bsock->m_blocking = 1; bsock->msg = get_pool_memory(PM_BSOCK); bsock->errmsg = get_pool_memory(PM_MESSAGE); bsock->set_who(bstrdup(who)); bsock->set_host(bstrdup(host)); bsock->set_port(port); memset(&bsock->peer_addr, 0, sizeof(bsock->peer_addr)); memcpy(&bsock->client_addr, client_addr, sizeof(bsock->client_addr)); bsock->timeout = BSOCK_TIMEOUT; bsock->set_jcr(jcr); return bsock; }
/* * Start of replication. */ static bool start_replication_session(JCR *jcr) { BSOCK *sd = jcr->store_bsock; Dmsg1(120, "Start replication session: %s", sd->msg); if (jcr->session_opened) { pm_strcpy(jcr->errmsg, _("Attempt to open already open session.\n")); sd->fsend(NO_open); return false; } jcr->session_opened = true; /* * Send "Ticket" to Storage Daemon */ sd->fsend(OK_start_replicate, jcr->VolSessionId); Dmsg1(110, ">stored: %s", sd->msg); return true; }
/* * Append Data command * Open Data Channel and receive Data for archiving * Write the Data to the archive device */ static bool append_data_cmd(JCR *jcr) { BSOCK *fd = jcr->file_bsock; Dmsg1(120, "Append data: %s", fd->msg); if (jcr->session_opened) { Dmsg1(110, "<bfiled: %s", fd->msg); jcr->set_JobType(JT_BACKUP); if (do_append_data(jcr)) { return true; } else { pm_strcpy(jcr->errmsg, _("Append data error.\n")); bnet_suppress_error_messages(fd, 1); /* ignore errors at this point */ fd->fsend(ERROR_append); } } else { pm_strcpy(jcr->errmsg, _("Attempt to append on non-open session.\n")); fd->fsend(NOT_opened); } return false; }
/* * Run a File daemon Job -- File daemon already authorized * Director sends us this command. * * Basic task here is: * - Read a command from the File daemon * - Execute it * */ void run_job(JCR *jcr) { BSOCK *dir = jcr->dir_bsock; char ec1[30]; dir->set_jcr(jcr); Dmsg1(120, "Start run Job=%s\n", jcr->Job); dir->fsend(Job_start, jcr->Job); jcr->start_time = time(NULL); jcr->run_time = jcr->start_time; set_jcr_job_status(jcr, JS_Running); dir_send_job_status(jcr); /* update director */ do_fd_commands(jcr); jcr->end_time = time(NULL); dequeue_messages(jcr); /* send any queued messages */ set_jcr_job_status(jcr, JS_Terminated); generate_daemon_event(jcr, "JobEnd"); dir->fsend(Job_end, jcr->Job, jcr->JobStatus, jcr->JobFiles, edit_uint64(jcr->JobBytes, ec1), jcr->JobErrors); dir->signal(BNET_EOD); /* send EOD to Director daemon */ return; }
/* * Terminate any digest and send it to Storage daemon */ static inline bool terminate_digest(b_save_ctx &bsctx) { uint32_t size; bool retval = false; BSOCK *sd = bsctx.jcr->store_bsock; sd->fsend("%ld %d 0", bsctx.jcr->JobFiles, bsctx.digest_stream); Dmsg1(300, "filed>stored:header %s", sd->msg); size = CRYPTO_DIGEST_MAX_SIZE; /* * Grow the bsock buffer to fit our message if necessary */ if (sizeof_pool_memory(sd->msg) < (int32_t)size) { sd->msg = realloc_pool_memory(sd->msg, size); } if (!crypto_digest_finalize(bsctx.digest, (uint8_t *)sd->msg, &size)) { Jmsg(bsctx.jcr, M_FATAL, 0, _("An error occurred finalizing signing the stream.\n")); goto bail_out; } /* * Keep the checksum if this file is a hardlink */ if (bsctx.ff_pkt->linked) { ff_pkt_set_link_digest(bsctx.ff_pkt, bsctx.digest_stream, sd->msg, size); } sd->msglen = size; sd->send(); sd->signal(BNET_EOD); /* end of checksum */ retval = true; bail_out: return retval; }
/* Send attributes and digest to Director for Catalog */ bool send_attrs_to_dir(JCR *jcr, DEV_RECORD *rec) { if (rec->maskedStream == STREAM_UNIX_ATTRIBUTES || rec->maskedStream == STREAM_UNIX_ATTRIBUTES_EX || rec->maskedStream == STREAM_RESTORE_OBJECT || crypto_digest_stream_type(rec->maskedStream) != CRYPTO_DIGEST_NONE) { if (!jcr->no_attributes) { BSOCK *dir = jcr->dir_bsock; if (are_attributes_spooled(jcr)) { dir->set_spooling(); } Dmsg0(850, "Send attributes to dir.\n"); if (!dir_update_file_attributes(jcr->dcr, rec)) { Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"), dir->bstrerror()); dir->clear_spooling(); return false; } dir->clear_spooling(); } } return true; }
/* * Ask the autochanger to perform a mount, umount or release operation. */ bool do_autochanger_volume_operation(UAContext *ua, STORERES *store, const char *operation, int drive, int slot) { BSOCK *sd = NULL; bool retval = true; char dev_name[MAX_NAME_LENGTH]; if (!(sd = open_sd_bsock(ua))) { return false; } bstrncpy(dev_name, store->dev_name(), sizeof(dev_name)); bash_spaces(dev_name); if (slot > 0) { sd->fsend(changervolopslotcmd, operation, dev_name, drive, slot); } else { sd->fsend(changervolopcmd, operation, dev_name, drive); } /* * We use bget_dirmsg here and not bnet_recv because as part of * the mount request the stored can request catalog information for * any plugin who listens to the bsdEventLabelVerified event. * As we don't want to loose any non protocol data e.g. errors * without a 3xxx prefix we set the allow_any_message of * bget_dirmsg to true and as such is behaves like a normal * bnet_recv for any non protocol messages. */ while (bget_dirmsg(sd, true) >= 0) { ua->send_msg("%s", sd->msg); } close_sd_bsock(ua); return retval; }
/* * Send update information about a device to Director */ bool SD_DCR::dir_update_device(JCR *jcr, DEVICE *dev) { BSOCK *dir = jcr->dir_bsock; POOL_MEM dev_name, VolumeName, MediaType, ChangerName; DEVRES *device = dev->device; bool ok; pm_strcpy(dev_name, device->hdr.name); bash_spaces(dev_name); if (dev->is_labeled()) { pm_strcpy(VolumeName, dev->VolHdr.VolumeName); } else { pm_strcpy(VolumeName, "*"); } bash_spaces(VolumeName); pm_strcpy(MediaType, device->media_type); bash_spaces(MediaType); if (device->changer_res) { pm_strcpy(ChangerName, device->changer_res->hdr.name); bash_spaces(ChangerName); } else { pm_strcpy(ChangerName, "*"); } ok = dir->fsend(Device_update, jcr->Job, dev_name.c_str(), dev->can_append() != 0, dev->can_read() != 0, dev->num_writers, dev->is_open() != 0, dev->is_labeled() != 0, dev->is_offline() != 0, dev->reserved_device, dev->is_tape() ? 100000 : 1, dev->autoselect, 0, ChangerName.c_str(), MediaType.c_str(), VolumeName.c_str()); Dmsg1(dbglvl, ">dird: %s", dir->msg); return ok; }
/* * Read Open session command * * We need to scan for the parameters of the job * to be restored. */ static bool read_open_session(JCR *jcr) { BSOCK *fd = jcr->file_bsock; Dmsg1(120, "%s\n", fd->msg); if (jcr->session_opened) { pm_strcpy(jcr->errmsg, _("Attempt to open read on non-open session.\n")); fd->fsend(NO_open); return false; } if (sscanf(fd->msg, read_open, jcr->read_dcr->VolumeName, &jcr->read_VolSessionId, &jcr->read_VolSessionTime, &jcr->read_StartFile, &jcr->read_EndFile, &jcr->read_StartBlock, &jcr->read_EndBlock) == 7) { if (jcr->session_opened) { pm_strcpy(jcr->errmsg, _("Attempt to open read on non-open session.\n")); fd->fsend(NOT_opened); return false; } Dmsg4(100, "read_open_session got: JobId=%d Vol=%s VolSessId=%ld VolSessT=%ld\n", jcr->JobId, jcr->read_dcr->VolumeName, jcr->read_VolSessionId, jcr->read_VolSessionTime); Dmsg4(100, " StartF=%ld EndF=%ld StartB=%ld EndB=%ld\n", jcr->read_StartFile, jcr->read_EndFile, jcr->read_StartBlock, jcr->read_EndBlock); } jcr->session_opened = true; jcr->set_JobType(JT_RESTORE); /* Send "Ticket" to File Daemon */ fd->fsend(OK_open, jcr->VolSessionId); Dmsg1(110, ">filed: %s", fd->msg); return true; }