bool run_cmd(JCR *jcr) { struct timeval tv; struct timezone tz; struct timespec timeout; int errstat = 0; Dsm_check(200); Dmsg1(200, "Run_cmd: %s\n", jcr->dir_bsock->msg); /* If we do not need the FD, we are doing a virtual backup. */ if (jcr->no_client_used()) { do_vbackup(jcr); return false; } jcr->sendJobStatus(JS_WaitFD); /* wait for FD to connect */ Dmsg2(050, "sd_calls_client=%d sd_client=%d\n", jcr->sd_calls_client, jcr->sd_client); if (jcr->sd_calls_client) { if (!read_client_hello(jcr)) { return false; } /* * Authenticate the File daemon */ Dmsg0(050, "=== Authenticate FD\n"); if (jcr->authenticated || !authenticate_filed(jcr, jcr->file_bsock, jcr->FDVersion)) { Dmsg1(050, "Authentication failed Job %s\n", jcr->Job); Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n")); } else { jcr->authenticated = true; } } else if (!jcr->sd_client) { /* We wait to receive connection from Client */ gettimeofday(&tv, &tz); timeout.tv_nsec = tv.tv_usec * 1000; timeout.tv_sec = tv.tv_sec + me->client_wait; Dmsg3(050, "%s waiting %d sec for FD to contact SD key=%s\n", jcr->Job, (int)(timeout.tv_sec-time(NULL)), jcr->sd_auth_key); Dmsg3(800, "=== Block Job=%s jid=%d %p\n", jcr->Job, jcr->JobId, jcr); /* * Wait for the File daemon to contact us to start the Job, * when he does, we will be released, unless the 30 minutes * expires. */ P(mutex); while ( !jcr->authenticated && !job_canceled(jcr) ) { errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout); if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) { break; } Dmsg1(800, "=== Auth cond errstat=%d\n", errstat); } Dmsg4(050, "=== Auth=%d jid=%d canceled=%d errstat=%d\n", jcr->JobId, jcr->authenticated, job_canceled(jcr), errstat); V(mutex); Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr); } memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key)); if (jcr->authenticated && !job_canceled(jcr)) { Dmsg2(800, "Running jid=%d %p\n", jcr->JobId, jcr); run_job(jcr); /* Run the job */ } Dmsg2(800, "Done jid=%d %p\n", jcr->JobId, jcr); return false; }
/* * Do a backup of the specified FileSet * * Returns: false on failure * true on success */ bool do_backup(JCR *jcr) { int stat; int tls_need = BNET_TLS_NONE; BSOCK *fd; STORE *store; char ed1[100]; if (jcr->get_JobLevel() == L_VIRTUAL_FULL) { return do_vbackup(jcr); } /* Print Job Start message */ Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %s, Job=%s\n"), edit_uint64(jcr->JobId, ed1), jcr->Job); set_jcr_job_status(jcr, JS_Running); Dmsg2(100, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel); if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) { Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db)); return false; } /* * Open a message channel connection with the Storage * daemon. This is to let him know that our client * will be contacting him for a backup session. * */ Dmsg0(110, "Open connection with storage daemon\n"); set_jcr_job_status(jcr, JS_WaitSD); /* * Start conversation with Storage daemon */ if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) { return false; } /* * Now start a job with the Storage daemon */ if (!start_storage_daemon_job(jcr, NULL, jcr->wstorage)) { return false; } /* * Start the job prior to starting the message thread below * to avoid two threads from using the BSOCK structure at * the same time. */ if (!bnet_fsend(jcr->store_bsock, "run")) { return false; } /* * Now start a Storage daemon message thread. Note, * this thread is used to provide the catalog services * for the backup job, including inserting the attributes * into the catalog. See catalog_update() in catreq.c */ if (!start_storage_daemon_message_thread(jcr)) { return false; } Dmsg0(150, "Storage daemon connection OK\n"); set_jcr_job_status(jcr, JS_WaitFD); if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) { goto bail_out; } set_jcr_job_status(jcr, JS_Running); fd = jcr->file_bsock; if (!send_include_list(jcr)) { goto bail_out; } if (!send_exclude_list(jcr)) { goto bail_out; } if (!send_level_command(jcr)) { goto bail_out; } /* * send Storage daemon address to the File daemon */ store = jcr->wstore; if (store->SDDport == 0) { store->SDDport = store->SDport; } /* TLS Requirement */ if (store->tls_enable) { if (store->tls_require) { tls_need = BNET_TLS_REQUIRED; } else { tls_need = BNET_TLS_OK; } } fd->fsend(storaddr, store->address, store->SDDport, tls_need); if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) { goto bail_out; } if (!send_runscripts_commands(jcr)) { goto bail_out; } /* * 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)); } /* * If backup is in accurate mode, we send the list of * all files to FD. */ if (!send_accurate_current_files(jcr)) { goto bail_out; } /* Send backup command */ fd->fsend(backupcmd); if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) { goto bail_out; } /* Pickup Job termination data */ stat = wait_for_job_termination(jcr); db_write_batch_file_records(jcr); /* used by bulk batch file insert */ if (stat == JS_Terminated) { backup_cleanup(jcr, stat); return true; } return false; /* Come here only after starting SD thread */ bail_out: set_jcr_job_status(jcr, JS_ErrorTerminated); Dmsg1(400, "wait for sd. use=%d\n", jcr->use_count()); /* Cancel SD */ wait_for_job_termination(jcr, FDConnectTimeout); Dmsg1(400, "after wait for sd. use=%d\n", jcr->use_count()); return false; }
bool run_cmd(JCR *jcr) { struct timeval tv; struct timezone tz; struct timespec timeout; int errstat = 0; BSOCK *cl; int fd_version = 0; int sd_version = 0; char job_name[500]; int i; int stat; Dsm_check(200); Dmsg1(200, "Run_cmd: %s\n", jcr->dir_bsock->msg); /* If we do not need the FD, we are doing a virtual backup. */ if (jcr->no_client_used()) { do_vbackup(jcr); return false; } jcr->sendJobStatus(JS_WaitFD); /* wait for FD to connect */ Dmsg2(050, "sd_calls_client=%d sd_client=%d\n", jcr->sd_calls_client, jcr->sd_client); if (jcr->sd_calls_client) { /* We connected to Client, so finish work */ cl = jcr->file_bsock; if (!cl) { Jmsg0(jcr, M_FATAL, 0, _("Client socket not open. Could not connect to Client.\n")); Dmsg0(050, "Client socket not open. Could not connect to Client.\n"); return false; } /* Get response to Hello command sent earlier */ Dmsg0(050, "Read Hello command from Client\n"); for (i=0; i<60; i++) { stat = cl->recv(); if (stat <= 0) { bmicrosleep(1, 0); } else { break; } } if (stat <= 0) { berrno be; Jmsg1(jcr, M_FATAL, 0, _("Recv request to Client failed. ERR=%s\n"), be.bstrerror()); Dmsg1(050, _("Recv request to Client failed. ERR=%s\n"), be.bstrerror()); return false; } Dmsg1(050, "Got from FD: %s\n", cl->msg); if (sscanf(cl->msg, "Hello Bacula SD: Start Job %127s %d %d", job_name, &fd_version, &sd_version) != 3) { Jmsg1(jcr, M_FATAL, 0, _("Bad Hello from Client: %s.\n"), cl->msg); Dmsg1(050, _("Bad Hello from Client: %s.\n"), cl->msg); return false; } unbash_spaces(job_name); jcr->FDVersion = fd_version; jcr->SDVersion = sd_version; Dmsg1(050, "FDVersion=%d\n", fd_version); /* * Authenticate the File daemon */ Dmsg0(050, "=== Authenticate FD\n"); if (jcr->authenticated || !authenticate_filed(jcr)) { Dmsg1(050, "Authentication failed Job %s\n", jcr->Job); Jmsg(jcr, M_FATAL, 0, _("Unable to authenticate File daemon\n")); } else { jcr->authenticated = true; } } else if (!jcr->sd_client) { /* We wait to receive connection from Client */ gettimeofday(&tv, &tz); timeout.tv_nsec = tv.tv_usec * 1000; timeout.tv_sec = tv.tv_sec + me->client_wait; Dmsg3(050, "%s waiting %d sec for FD to contact SD key=%s\n", jcr->Job, (int)(timeout.tv_sec-time(NULL)), jcr->sd_auth_key); Dmsg3(800, "=== Block Job=%s jid=%d %p\n", jcr->Job, jcr->JobId, jcr); /* * Wait for the File daemon to contact us to start the Job, * when he does, we will be released, unless the 30 minutes * expires. */ P(mutex); while ( !jcr->authenticated && !job_canceled(jcr) ) { errstat = pthread_cond_timedwait(&jcr->job_start_wait, &mutex, &timeout); if (errstat == ETIMEDOUT || errstat == EINVAL || errstat == EPERM) { break; } Dmsg1(800, "=== Auth cond errstat=%d\n", errstat); } Dmsg4(050, "=== Auth=%d jid=%d canceled=%d errstat=%d\n", jcr->JobId, jcr->authenticated, job_canceled(jcr), errstat); V(mutex); Dmsg2(800, "Auth fail or cancel for jid=%d %p\n", jcr->JobId, jcr); } memset(jcr->sd_auth_key, 0, strlen(jcr->sd_auth_key)); if (jcr->authenticated && !job_canceled(jcr)) { Dmsg2(800, "Running jid=%d %p\n", jcr->JobId, jcr); run_job(jcr); /* Run the job */ } Dmsg2(800, "Done jid=%d %p\n", jcr->JobId, jcr); return false; }