/* * After receiving a connection (in dircmd.c) if it is * from the Storage daemon, this routine is called. */ void *handle_stored_connection(BSOCK *sd, char *job_name) { JCR *jcr; /* * With the following bmicrosleep on, running the * SD under the debugger fails. */ // bmicrosleep(0, 50000); /* wait 50 millisecs */ if (!(jcr = get_jcr_by_full_name(job_name))) { Jmsg1(NULL, M_FATAL, 0, _("SD connect failed: Job name not found: %s\n"), job_name); Dmsg1(3, "**** Job \"%s\" not found.\n", job_name); sd->close(); delete sd; return NULL; } Dmsg1(50, "Found Job %s\n", job_name); if (jcr->authenticated) { Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"), (uint32_t)jcr->JobId, jcr->Job); Dmsg2(50, "Hey!!!! JobId %u Job %s already authenticated.\n", (uint32_t)jcr->JobId, jcr->Job); sd->close(); delete sd; free_jcr(jcr); return NULL; } jcr->store_bsock = sd; jcr->store_bsock->set_jcr(jcr); /* * Authenticate the Storage daemon */ if (jcr->authenticated || !authenticate_storagedaemon(jcr)) { Dmsg1(50, "Authentication failed Job %s\n", jcr->Job); Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate Storage daemon\n")); } else { jcr->authenticated = true; Dmsg2(50, "OK Authentication jid=%u Job %s\n", (uint32_t)jcr->JobId, jcr->Job); } if (!jcr->authenticated) { jcr->setJobStatus(JS_ErrorTerminated); } pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */ free_jcr(jcr); return NULL; }
/* * After receiving a connection (in dircmd.c) if it is * from the File daemon, this routine is called. */ void handle_filed_connection(BSOCK *fd, char *job_name, int fd_version, int sd_version) { JCR *jcr; if (!(jcr=get_jcr_by_full_name(job_name))) { Jmsg1(NULL, M_FATAL, 0, _("FD connect failed: Job name not found: %s\n"), job_name); Dmsg1(3, "**** Job \"%s\" not found.\n", job_name); fd->destroy(); return; } Dmsg1(100, "Found Filed Job %s\n", job_name); if (jcr->authenticated) { Jmsg2(jcr, M_FATAL, 0, _("Hey!!!! JobId %u Job %s already authenticated.\n"), (uint32_t)jcr->JobId, jcr->Job); Dmsg2(050, "Hey!!!! JobId %u Job %s already authenticated.\n", (uint32_t)jcr->JobId, jcr->Job); fd->destroy(); free_jcr(jcr); return; } jcr->file_bsock = fd; jcr->file_bsock->set_jcr(jcr); jcr->FDVersion = fd_version; jcr->SDVersion = sd_version; Dmsg2(050, "fd_version=%d sd_version=%d\n", fd_version, sd_version); /* * Authenticate the File daemon */ if (jcr->authenticated || !authenticate_filed(jcr)) { Dmsg1(50, "Authentication failed Job %s\n", jcr->Job); Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n")); } else { jcr->authenticated = true; Dmsg2(050, "OK Authentication jid=%u Job %s\n", (uint32_t)jcr->JobId, jcr->Job); } if (!jcr->authenticated) { jcr->setJobStatus(JS_ErrorTerminated); } Dmsg3(050, "=== Auth OK, unblock Job %s jid=%d sd_ver=%d\n", job_name, jcr->JobId, sd_version); if (sd_version > 0) { jcr->sd_client = true; } pthread_cond_signal(&jcr->job_start_wait); /* wake waiting job */ free_jcr(jcr); return; }
/* * Create a Job Control Record for a control "job", * filling in all the appropriate fields. */ JCR *new_control_jcr(const char *base_name, int job_type) { JCR *jcr; jcr = new_jcr(sizeof(JCR), dird_free_jcr); /* * The job and defaults are not really used, but * we set them up to ensure that everything is correctly * initialized. */ LockRes(); jcr->job = (JOB *)GetNextRes(R_JOB, NULL); set_jcr_defaults(jcr, jcr->job); UnlockRes(); jcr->sd_auth_key = bstrdup("dummy"); /* dummy Storage daemon key */ create_unique_job_name(jcr, base_name); jcr->sched_time = jcr->start_time; jcr->setJobType(job_type); jcr->setJobLevel(L_NONE); jcr->setJobStatus(JS_Running); jcr->JobId = 0; return jcr; }
/* * NB! This routine locks the device, but if committing will * not unlock it. If not committing, it will be unlocked. */ static bool despool_data(DCR *dcr, bool commit) { DEVICE *rdev; DCR *rdcr; bool ok = true; DEV_BLOCK *block; JCR *jcr = dcr->jcr; int status; char ec1[50]; BSOCK *dir = jcr->dir_bsock; Dmsg0(100, "Despooling data\n"); if (jcr->dcr->job_spool_size == 0) { Jmsg(jcr, M_WARNING, 0, _("Despooling zero bytes. Your disk is probably FULL!\n")); } /* * Commit means that the job is done, so we commit, otherwise, we * are despooling because of user spool size max or some error * (e.g. filesystem full). */ if (commit) { Jmsg(jcr, M_INFO, 0, _("Committing spooled data to Volume \"%s\". Despooling %s bytes ...\n"), jcr->dcr->VolumeName, edit_uint64_with_commas(jcr->dcr->job_spool_size, ec1)); jcr->setJobStatus(JS_DataCommitting); } else { Jmsg(jcr, M_INFO, 0, _("Writing spooled data to Volume. Despooling %s bytes ...\n"), edit_uint64_with_commas(jcr->dcr->job_spool_size, ec1)); jcr->setJobStatus(JS_DataDespooling); } jcr->sendJobStatus(JS_DataDespooling); dcr->despool_wait = true; dcr->spooling = false; /* * We work with device blocked, but not locked so that other threads * e.g. reservations can lock the device structure. */ dcr->dblock(BST_DESPOOLING); dcr->despool_wait = false; dcr->despooling = true; /* * This is really quite kludgy and should be fixed some time. * We create a dev structure to read from the spool file * in rdev and rdcr. */ rdev = (DEVICE *)malloc(sizeof(DEVICE)); memset(rdev, 0, sizeof(DEVICE)); rdev->dev_name = get_memory(strlen(spool_name)+1); bstrncpy(rdev->dev_name, spool_name, sizeof_pool_memory(rdev->dev_name)); rdev->errmsg = get_pool_memory(PM_EMSG); *rdev->errmsg = 0; rdev->max_block_size = dcr->dev->max_block_size; rdev->min_block_size = dcr->dev->min_block_size; rdev->device = dcr->dev->device; rdcr = dcr->get_new_spooling_dcr(); setup_new_dcr_device(jcr, rdcr, rdev, NULL); rdcr->spool_fd = dcr->spool_fd; block = dcr->block; /* save block */ dcr->block = rdcr->block; /* make read and write block the same */ Dmsg1(800, "read/write block size = %d\n", block->buf_len); lseek(rdcr->spool_fd, 0, SEEK_SET); /* rewind */ #if defined(HAVE_POSIX_FADVISE) && defined(POSIX_FADV_WILLNEED) posix_fadvise(rdcr->spool_fd, 0, 0, POSIX_FADV_WILLNEED); #endif /* Add run time, to get current wait time */ int32_t despool_start = time(NULL) - jcr->run_time; set_new_file_parameters(dcr); while (ok) { if (job_canceled(jcr)) { ok = false; break; } status = read_block_from_spool_file(rdcr); if (status == RB_EOT) { break; } else if (status == RB_ERROR) { ok = false; break; } ok = dcr->write_block_to_device(); if (!ok) { Jmsg2(jcr, M_FATAL, 0, _("Fatal append error on device %s: ERR=%s\n"), dcr->dev->print_name(), dcr->dev->bstrerror()); Dmsg2(000, "Fatal append error on device %s: ERR=%s\n", dcr->dev->print_name(), dcr->dev->bstrerror()); /* Force in case Incomplete set */ jcr->forceJobStatus(JS_FatalError); } Dmsg3(800, "Write block ok=%d FI=%d LI=%d\n", ok, block->FirstIndex, block->LastIndex); } /* * If this Job is incomplete, we need to backup the FileIndex * to the last correctly saved file so that the JobMedia * LastIndex is correct. */ if (jcr->is_JobStatus(JS_Incomplete)) { dcr->VolLastIndex = dir->get_FileIndex(); Dmsg1(100, "======= Set FI=%ld\n", dir->get_FileIndex()); } if (!dcr->dir_create_jobmedia_record(false)) { Jmsg2(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), dcr->getVolCatName(), jcr->Job); jcr->forceJobStatus(JS_FatalError); /* override any Incomplete */ } /* Set new file/block parameters for current dcr */ set_new_file_parameters(dcr); /* * Subtracting run_time give us elapsed time - wait_time since * we started despooling. Note, don't use time_t as it is 32 or 64 * bits depending on the OS and doesn't edit with %d */ int32_t despool_elapsed = time(NULL) - despool_start - jcr->run_time; if (despool_elapsed <= 0) { despool_elapsed = 1; } Jmsg(jcr, M_INFO, 0, _("Despooling elapsed time = %02d:%02d:%02d, Transfer rate = %s Bytes/second\n"), despool_elapsed / 3600, despool_elapsed % 3600 / 60, despool_elapsed % 60, edit_uint64_with_suffix(jcr->dcr->job_spool_size / despool_elapsed, ec1)); dcr->block = block; /* reset block */ lseek(rdcr->spool_fd, 0, SEEK_SET); /* rewind */ if (ftruncate(rdcr->spool_fd, 0) != 0) { berrno be; Jmsg(jcr, M_ERROR, 0, _("Ftruncate spool file failed: ERR=%s\n"), be.bstrerror()); /* Note, try continuing despite ftruncate problem */ } P(mutex); if (spool_stats.data_size < dcr->job_spool_size) { spool_stats.data_size = 0; } else { spool_stats.data_size -= dcr->job_spool_size; } V(mutex); P(dcr->dev->spool_mutex); dcr->dev->spool_size -= dcr->job_spool_size; dcr->job_spool_size = 0; /* zap size in input dcr */ V(dcr->dev->spool_mutex); free_memory(rdev->dev_name); free_pool_memory(rdev->errmsg); /* Be careful to NULL the jcr and free rdev after free_dcr() */ rdcr->jcr = NULL; rdcr->set_dev(NULL); free_dcr(rdcr); free(rdev); dcr->spooling = true; /* turn on spooling again */ dcr->despooling = false; /* * Note, if committing we leave the device blocked. It will be removed in * release_device(); */ if (!commit) { dcr->dev->dunblock(); } jcr->sendJobStatus(JS_Running); return ok; }
/* * Create a Job Control Record and link it into JCR chain * Returns newly allocated JCR * * Note, since each daemon has a different JCR, he passes * us the size. */ JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr) { JCR *jcr; MQUEUE_ITEM *item = NULL; struct sigaction sigtimer; int status; Dmsg0(dbglvl, "Enter new_jcr\n"); setup_tsd_key(); jcr = (JCR *)malloc(size); memset(jcr, 0, size); jcr->msg_queue = New(dlist(item, &item->link)); if ((status = pthread_mutex_init(&jcr->msg_queue_mutex, NULL)) != 0) { berrno be; Jmsg(NULL, M_ABORT, 0, _("Could not init msg_queue mutex. ERR=%s\n"), be.bstrerror(status)); } jcr->job_end_push.init(1, false); jcr->sched_time = time(NULL); jcr->initial_sched_time = jcr->sched_time; jcr->daemon_free_jcr = daemon_free_jcr; /* plug daemon free routine */ jcr->init_mutex(); jcr->inc_use_count(); jcr->VolumeName = get_pool_memory(PM_FNAME); jcr->VolumeName[0] = 0; jcr->errmsg = get_pool_memory(PM_MESSAGE); jcr->errmsg[0] = 0; jcr->comment = get_pool_memory(PM_FNAME); jcr->comment[0] = 0; /* * Setup some dummy values */ bstrncpy(jcr->Job, "*System*", sizeof(jcr->Job)); jcr->JobId = 0; jcr->setJobType(JT_SYSTEM); /* internal job until defined */ jcr->setJobLevel(L_NONE); jcr->setJobStatus(JS_Created); /* ready to run */ sigtimer.sa_flags = 0; sigtimer.sa_handler = timeout_handler; sigfillset(&sigtimer.sa_mask); sigaction(TIMEOUT_SIGNAL, &sigtimer, NULL); /* * Locking jobs is a global lock that is needed * so that the Director can stop new jobs from being * added to the jcr chain while it processes a new * conf file and does the job_end_push(). */ lock_jobs(); lock_jcr_chain(); if (!jcrs) { jcrs = New(dlist(jcr, &jcr->link)); } jcrs->append(jcr); unlock_jcr_chain(); unlock_jobs(); return jcr; }
/* * Check for duplicate jobs. * Returns: true if current job should continue * false if current job should terminate */ bool allow_duplicate_job(JCR *jcr) { JCR *djcr; /* possible duplicate job */ JOBRES *job = jcr->res.job; bool cancel_dup = false; bool cancel_me = false; /* * See if AllowDuplicateJobs is set or * if duplicate checking is disabled for this job. */ if (job->AllowDuplicateJobs || jcr->IgnoreDuplicateJobChecking) { return true; } Dmsg0(800, "Enter allow_duplicate_job\n"); /* * After this point, we do not want to allow any duplicate * job to run. */ foreach_jcr(djcr) { if (jcr == djcr || djcr->JobId == 0) { continue; /* do not cancel this job or consoles */ } /* * See if this Job has the IgnoreDuplicateJobChecking flag set, ignore it * for any checking against other jobs. */ if (djcr->IgnoreDuplicateJobChecking) { continue; } if (bstrcmp(job->name(), djcr->res.job->name())) { if (job->DuplicateJobProximity > 0) { utime_t now = (utime_t)time(NULL); if ((now - djcr->start_time) > job->DuplicateJobProximity) { continue; /* not really a duplicate */ } } if (job->CancelLowerLevelDuplicates && djcr->getJobType() == 'B' && jcr->getJobType() == 'B') { switch (jcr->getJobLevel()) { case L_FULL: if (djcr->getJobLevel() == L_DIFFERENTIAL || djcr->getJobLevel() == L_INCREMENTAL) { cancel_dup = true; } break; case L_DIFFERENTIAL: if (djcr->getJobLevel() == L_INCREMENTAL) { cancel_dup = true; } if (djcr->getJobLevel() == L_FULL) { cancel_me = true; } break; case L_INCREMENTAL: if (djcr->getJobLevel() == L_FULL || djcr->getJobLevel() == L_DIFFERENTIAL) { cancel_me = true; } } /* * cancel_dup will be done below */ if (cancel_me) { /* Zap current job */ jcr->setJobStatus(JS_Canceled); Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"), djcr->JobId); break; /* get out of foreach_jcr */ } } /* * Cancel one of the two jobs (me or dup) * If CancelQueuedDuplicates is set do so only if job is queued. */ if (job->CancelQueuedDuplicates) { switch (djcr->JobStatus) { case JS_Created: case JS_WaitJobRes: case JS_WaitClientRes: case JS_WaitStoreRes: case JS_WaitPriority: case JS_WaitMaxJobs: case JS_WaitStartTime: cancel_dup = true; /* cancel queued duplicate */ break; default: break; } } if (cancel_dup || job->CancelRunningDuplicates) { /* * Zap the duplicated job djcr */ UAContext *ua = new_ua_context(jcr); Jmsg(jcr, M_INFO, 0, _("Cancelling duplicate JobId=%d.\n"), djcr->JobId); cancel_job(ua, djcr); bmicrosleep(0, 500000); djcr->setJobStatus(JS_Canceled); cancel_job(ua, djcr); free_ua_context(ua); Dmsg2(800, "Cancel dup %p JobId=%d\n", djcr, djcr->JobId); } else { /* * Zap current job */ jcr->setJobStatus(JS_Canceled); Jmsg(jcr, M_FATAL, 0, _("JobId %d already running. Duplicate job not allowed.\n"), djcr->JobId); Dmsg2(800, "Cancel me %p JobId=%d\n", jcr, jcr->JobId); } Dmsg4(800, "curJobId=%d use_cnt=%d dupJobId=%d use_cnt=%d\n", jcr->JobId, jcr->use_count(), djcr->JobId, djcr->use_count()); break; /* did our work, get out of foreach loop */ } } endeach_jcr(djcr); return true; }
/* * This is the engine called by jobq.c:jobq_add() when we were pulled * from the work queue. * At this point, we are running in our own thread and all * necessary resources are allocated -- see jobq.c */ static void *job_thread(void *arg) { JCR *jcr = (JCR *)arg; pthread_detach(pthread_self()); Dsm_check(100); Dmsg0(200, "=====Start Job=========\n"); jcr->setJobStatus(JS_Running); /* this will be set only if no error */ jcr->start_time = time(NULL); /* set the real start time */ jcr->jr.StartTime = jcr->start_time; if (jcr->res.job->MaxStartDelay != 0 && jcr->res.job->MaxStartDelay < (utime_t)(jcr->start_time - jcr->sched_time)) { jcr->setJobStatus(JS_Canceled); Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n")); } if (job_check_maxrunschedtime(jcr)) { jcr->setJobStatus(JS_Canceled); Jmsg(jcr, M_FATAL, 0, _("Job canceled because max run sched time exceeded.\n")); } /* TODO : check if it is used somewhere */ if (jcr->res.job->RunScripts == NULL) { Dmsg0(200, "Warning, job->RunScripts is empty\n"); jcr->res.job->RunScripts = New(alist(10, not_owned_by_alist)); } if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); } /* Run any script BeforeJob on dird */ run_scripts(jcr, jcr->res.job->RunScripts, "BeforeJob"); /* * We re-update the job start record so that the start * time is set after the run before job. This avoids * that any files created by the run before job will * be saved twice. They will be backed up in the current * job, but not in the next one unless they are changed. * Without this, they will be backed up in this job and * in the next job run because in that case, their date * is after the start of this run. */ jcr->start_time = time(NULL); jcr->jr.StartTime = jcr->start_time; if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); } generate_plugin_event(jcr, bDirEventJobRun); switch (jcr->getJobType()) { case JT_BACKUP: switch (jcr->getJobProtocol()) { case PT_NDMP: if (!job_canceled(jcr)) { if (do_ndmp_backup(jcr)) { do_autoprune(jcr); } else { ndmp_backup_cleanup(jcr, JS_ErrorTerminated); } } else { ndmp_backup_cleanup(jcr, JS_Canceled); } break; default: if (!job_canceled(jcr)) { if (jcr->is_JobLevel(L_VIRTUAL_FULL)) { if (do_native_vbackup(jcr)) { do_autoprune(jcr); } else { native_vbackup_cleanup(jcr, JS_ErrorTerminated); } } else { if (do_native_backup(jcr)) { do_autoprune(jcr); } else { native_backup_cleanup(jcr, JS_ErrorTerminated); } } } else { if (jcr->is_JobLevel(L_VIRTUAL_FULL)) { native_vbackup_cleanup(jcr, JS_Canceled); } else { native_backup_cleanup(jcr, JS_Canceled); } } break; } break; case JT_VERIFY: if (!job_canceled(jcr)) { if (do_verify(jcr)) { do_autoprune(jcr); } else { verify_cleanup(jcr, JS_ErrorTerminated); } } else { verify_cleanup(jcr, JS_Canceled); } break; case JT_RESTORE: switch (jcr->getJobProtocol()) { case PT_NDMP: if (!job_canceled(jcr)) { if (do_ndmp_restore(jcr)) { do_autoprune(jcr); } else { ndmp_restore_cleanup(jcr, JS_ErrorTerminated); } } else { ndmp_restore_cleanup(jcr, JS_Canceled); } break; default: if (!job_canceled(jcr)) { if (do_native_restore(jcr)) { do_autoprune(jcr); } else { native_restore_cleanup(jcr, JS_ErrorTerminated); } } else { native_restore_cleanup(jcr, JS_Canceled); } break; } break; case JT_ADMIN: if (!job_canceled(jcr)) { if (do_admin(jcr)) { do_autoprune(jcr); } else { admin_cleanup(jcr, JS_ErrorTerminated); } } else { admin_cleanup(jcr, JS_Canceled); } break; case JT_COPY: case JT_MIGRATE: if (!job_canceled(jcr)) { if (do_migration(jcr)) { do_autoprune(jcr); } else { migration_cleanup(jcr, JS_ErrorTerminated); } } else { migration_cleanup(jcr, JS_Canceled); } break; default: Pmsg1(0, _("Unimplemented job type: %d\n"), jcr->getJobType()); break; } run_scripts(jcr, jcr->res.job->RunScripts, "AfterJob"); /* Send off any queued messages */ if (jcr->msg_queue && jcr->msg_queue->size() > 0) { dequeue_messages(jcr); } generate_plugin_event(jcr, bDirEventJobEnd); Dmsg1(50, "======== End Job stat=%c ==========\n", jcr->JobStatus); Dsm_check(100); return NULL; }
/* * Setup deflate for auto deflate of data streams. */ static bool setup_auto_deflation(DCR *dcr) { JCR *jcr = dcr->jcr; bool retval = false; uint32_t compress_buf_size = 0; if (jcr->buf_size == 0) { jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE; } if (!setup_compression_buffers(jcr, sd_enabled_compatible, dcr->device->autodeflate_algorithm, &compress_buf_size)) { goto bail_out; } /* * See if we need to create a new compression buffer or make sure the existing is big enough. */ if (!jcr->compress.deflate_buffer) { jcr->compress.deflate_buffer = get_memory(compress_buf_size); jcr->compress.deflate_buffer_size = compress_buf_size; } else { if (compress_buf_size > jcr->compress.deflate_buffer_size) { jcr->compress.deflate_buffer = realloc_pool_memory(jcr->compress.deflate_buffer, compress_buf_size); jcr->compress.deflate_buffer_size = compress_buf_size; } } switch (dcr->device->autodeflate_algorithm) { #if defined(HAVE_LIBZ) case COMPRESS_GZIP: { int zstat; z_stream *pZlibStream; pZlibStream = (z_stream *)jcr->compress.workset.pZLIB; if ((zstat = deflateParams(pZlibStream, dcr->device->autodeflate_level, Z_DEFAULT_STRATEGY)) != Z_OK) { Jmsg(jcr, M_FATAL, 0, _("Compression deflateParams error: %d\n"), zstat); jcr->setJobStatus(JS_ErrorTerminated); goto bail_out; } break; } #endif #if defined(HAVE_LZO) case COMPRESS_LZO1X: break; #endif #if defined(HAVE_FASTLZ) case COMPRESS_FZFZ: case COMPRESS_FZ4L: case COMPRESS_FZ4H: { int zstat; zfast_stream *pZfastStream; zfast_stream_compressor compressor = COMPRESSOR_FASTLZ; switch (dcr->device->autodeflate_algorithm) { case COMPRESS_FZ4L: case COMPRESS_FZ4H: compressor = COMPRESSOR_LZ4; break; } pZfastStream = (zfast_stream *)jcr->compress.workset.pZFAST; if ((zstat = fastlzlibSetCompressor(pZfastStream, compressor)) != Z_OK) { Jmsg(jcr, M_FATAL, 0, _("Compression fastlzlibSetCompressor error: %d\n"), zstat); jcr->setJobStatus(JS_ErrorTerminated); goto bail_out; } break; } #endif default: break; } retval = true; bail_out: return retval; }
void *handle_stored_connection(BSOCK *sd) { JCR *jcr; char job_name[MAX_NAME_LENGTH]; /* * Do a sanity check on the message received */ if (sd->msglen < 25 || sd->msglen > 256) { Dmsg1(000, "<filed: %s", sd->msg); Emsg2(M_ERROR, 0, _("Invalid connection from %s. Len=%d\n"), sd->who(), sd->msglen); bmicrosleep(5, 0); /* make user wait 5 seconds */ sd->close(); return NULL; } if (sscanf(sd->msg, "Hello Storage calling Start Job %127s", job_name) != 1) { char addr[64]; char *who = bnet_get_peer(sd, addr, sizeof(addr)) ? sd->who() : addr; sd->msg[100] = 0; Dmsg2(dbglvl, "Bad Hello command from Director at %s: %s\n", sd->who(), sd->msg); Jmsg2(NULL, M_FATAL, 0, _("Bad Hello command from Director at %s: %s\n"), who, sd->msg); sd->close(); return NULL; } if (!(jcr = get_jcr_by_full_name(job_name))) { Jmsg1(NULL, M_FATAL, 0, _("SD connect failed: Job name not found: %s\n"), job_name); Dmsg1(3, "**** Job \"%s\" not found.\n", job_name); sd->close(); return NULL; } Dmsg1(50, "Found Job %s\n", job_name); jcr->store_bsock = sd; jcr->store_bsock->set_jcr(jcr); /* * Authenticate the Storage Daemon. */ if (!authenticate_storagedaemon(jcr)) { Dmsg1(50, "Authentication failed Job %s\n", jcr->Job); Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n")); jcr->setJobStatus(JS_ErrorTerminated); } else { Dmsg2(50, "OK Authentication jid=%u Job %s\n", (uint32_t)jcr->JobId, jcr->Job); } if (!jcr->max_bandwidth) { if (jcr->director->max_bandwidth_per_job) { jcr->max_bandwidth = jcr->director->max_bandwidth_per_job; } else if (me->max_bandwidth_per_job) { jcr->max_bandwidth = me->max_bandwidth_per_job; } } sd->set_bwlimit(jcr->max_bandwidth); if (me->allow_bw_bursting) { sd->set_bwlimit_bursting(); } free_jcr(jcr); return NULL; }