2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Bacula Director -- backup.c -- responsible for doing backup jobs
32 * Kern Sibbald, March MM
34 * Basic tasks done here:
35 * Open DB and create records for this job.
36 * Open Message Channel with Storage daemon to tell him a job will be starting.
37 * Open connection with File daemon and pass him commands
39 * When the File daemon finishes the job, update the DB.
48 /* Commands sent to File daemon */
49 static char backupcmd[] = "backup\n";
50 static char storaddr[] = "storage address=%s port=%d ssl=%d\n";
52 /* Responses received from File daemon */
53 static char OKbackup[] = "2000 OK backup\n";
54 static char OKstore[] = "2000 OK storage\n";
55 static char EndJob[] = "2800 End Job TermCode=%d JobFiles=%u "
56 "ReadBytes=%llu JobBytes=%llu Errors=%u "
57 "VSS=%d Encrypt=%d\n";
58 /* Pre 1.39.29 (04Dec06) EndJob */
59 static char OldEndJob[] = "2800 End Job TermCode=%d JobFiles=%u "
60 "ReadBytes=%llu JobBytes=%llu Errors=%u\n";
62 * Called here before the job is run to do the job
65 bool do_backup_init(JCR *jcr)
68 if (jcr->get_JobLevel() == L_VIRTUAL_FULL) {
69 return do_vbackup_init(jcr);
71 free_rstorage(jcr); /* we don't read so release */
73 if (!get_or_create_fileset_record(jcr)) {
78 * Get definitive Job level and since time
80 get_level_since_time(jcr, jcr->since, sizeof(jcr->since));
82 apply_pool_overrides(jcr);
84 if (!allow_duplicate_job(jcr)) {
88 jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
89 if (jcr->jr.PoolId == 0) {
93 /* If pool storage specified, use it instead of job storage */
94 copy_wstorage(jcr, jcr->pool->storage, _("Pool resource"));
97 Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Job or Pool.\n"));
101 create_clones(jcr); /* run any clone jobs */
107 * Foreach files in currrent list, send "/path/fname\0LStat" to FD
109 static int accurate_list_handler(void *ctx, int num_fields, char **row)
111 JCR *jcr = (JCR *)ctx;
113 if (job_canceled(jcr)) {
117 if (row[2] > 0) { /* discard when file_index == 0 */
118 jcr->file_bsock->fsend("%s%s%c%s", row[0], row[1], 0, row[4]);
124 * Send current file list to FD
125 * DIR -> FD : accurate files=xxxx
126 * DIR -> FD : /path/to/file\0Lstat
127 * DIR -> FD : /path/to/dir/\0Lstat
131 bool send_accurate_current_files(JCR *jcr)
137 if (!jcr->accurate || job_canceled(jcr) || jcr->get_JobLevel()==L_FULL) {
140 jobids = get_pool_memory(PM_FNAME);
142 db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids);
145 free_pool_memory(jobids);
146 Jmsg(jcr, M_FATAL, 0, _("Cannot find previous jobids.\n"));
149 if (jcr->JobId) { /* display the message only for real jobs */
150 Jmsg(jcr, M_INFO, 0, _("Sending Accurate information.\n"));
152 /* to be able to allocate the right size for htable */
153 nb = get_pool_memory(PM_FNAME);
154 *nb = 0; /* clear buffer */
155 Mmsg(buf, "SELECT sum(JobFiles) FROM Job WHERE JobId IN (%s)",jobids);
156 db_sql_query(jcr->db, buf.c_str(), db_get_int_handler, nb);
157 Dmsg2(200, "jobids=%s nb=%s\n", jobids, nb);
158 jcr->file_bsock->fsend("accurate files=%s\n", nb);
160 if (!db_open_batch_connexion(jcr, jcr->db)) {
161 free_pool_memory(jobids);
162 free_pool_memory(nb);
163 Jmsg0(jcr, M_FATAL, 0, "Can't get batch sql connexion");
167 db_get_file_list(jcr, jcr->db_batch, jobids, accurate_list_handler, (void *)jcr);
169 /* TODO: close the batch connexion ? (can be used very soon) */
171 free_pool_memory(jobids);
172 free_pool_memory(nb);
174 jcr->file_bsock->signal(BNET_EOD);
180 * Do a backup of the specified FileSet
182 * Returns: false on failure
185 bool do_backup(JCR *jcr)
188 int tls_need = BNET_TLS_NONE;
193 if (jcr->get_JobLevel() == L_VIRTUAL_FULL) {
194 return do_vbackup(jcr);
197 /* Print Job Start message */
198 Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %s, Job=%s\n"),
199 edit_uint64(jcr->JobId, ed1), jcr->Job);
201 set_jcr_job_status(jcr, JS_Running);
202 Dmsg2(100, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel);
203 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
204 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
209 * Open a message channel connection with the Storage
210 * daemon. This is to let him know that our client
211 * will be contacting him for a backup session.
214 Dmsg0(110, "Open connection with storage daemon\n");
215 set_jcr_job_status(jcr, JS_WaitSD);
217 * Start conversation with Storage daemon
219 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
223 * Now start a job with the Storage daemon
225 if (!start_storage_daemon_job(jcr, NULL, jcr->wstorage)) {
230 * Start the job prior to starting the message thread below
231 * to avoid two threads from using the BSOCK structure at
234 if (!bnet_fsend(jcr->store_bsock, "run")) {
239 * Now start a Storage daemon message thread. Note,
240 * this thread is used to provide the catalog services
241 * for the backup job, including inserting the attributes
242 * into the catalog. See catalog_update() in catreq.c
244 if (!start_storage_daemon_message_thread(jcr)) {
247 Dmsg0(150, "Storage daemon connection OK\n");
249 set_jcr_job_status(jcr, JS_WaitFD);
250 if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
254 set_jcr_job_status(jcr, JS_Running);
255 fd = jcr->file_bsock;
257 if (!send_include_list(jcr)) {
261 if (!send_exclude_list(jcr)) {
265 if (!send_level_command(jcr)) {
270 * send Storage daemon address to the File daemon
273 if (store->SDDport == 0) {
274 store->SDDport = store->SDport;
277 /* TLS Requirement */
278 if (store->tls_enable) {
279 if (store->tls_require) {
280 tls_need = BNET_TLS_REQUIRED;
282 tls_need = BNET_TLS_OK;
286 fd->fsend(storaddr, store->address, store->SDDport, tls_need);
287 if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
291 if (!send_runscripts_commands(jcr)) {
296 * We re-update the job start record so that the start
297 * time is set after the run before job. This avoids
298 * that any files created by the run before job will
299 * be saved twice. They will be backed up in the current
300 * job, but not in the next one unless they are changed.
301 * Without this, they will be backed up in this job and
302 * in the next job run because in that case, their date
303 * is after the start of this run.
305 jcr->start_time = time(NULL);
306 jcr->jr.StartTime = jcr->start_time;
307 if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
308 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
312 * If backup is in accurate mode, we send the list of
315 if (!send_accurate_current_files(jcr)) {
319 /* Send backup command */
320 fd->fsend(backupcmd);
321 if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) {
325 /* Pickup Job termination data */
326 stat = wait_for_job_termination(jcr);
327 db_write_batch_file_records(jcr); /* used by bulk batch file insert */
328 if (stat == JS_Terminated) {
329 backup_cleanup(jcr, stat);
334 /* Come here only after starting SD thread */
336 set_jcr_job_status(jcr, JS_ErrorTerminated);
337 Dmsg1(400, "wait for sd. use=%d\n", jcr->use_count());
339 wait_for_job_termination(jcr, FDConnectTimeout);
340 Dmsg1(400, "after wait for sd. use=%d\n", jcr->use_count());
346 * Here we wait for the File daemon to signal termination,
347 * then we wait for the Storage daemon. When both
348 * are done, we return the job status.
349 * Also used by restore.c
351 int wait_for_job_termination(JCR *jcr, int timeout)
354 BSOCK *fd = jcr->file_bsock;
356 uint32_t JobFiles, JobErrors;
357 uint32_t JobWarnings = 0;
358 uint64_t ReadBytes = 0;
359 uint64_t JobBytes = 0;
364 set_jcr_job_status(jcr, JS_Running);
368 tid = start_bsock_timer(fd, timeout); /* TODO: New timeout directive??? */
370 /* Wait for Client to terminate */
371 while ((n = bget_dirmsg(fd)) >= 0) {
373 (sscanf(fd->msg, EndJob, &jcr->FDJobStatus, &JobFiles,
374 &ReadBytes, &JobBytes, &JobErrors, &VSS, &Encrypt) == 7 ||
375 sscanf(fd->msg, OldEndJob, &jcr->FDJobStatus, &JobFiles,
376 &ReadBytes, &JobBytes, &JobErrors) == 5)) {
378 set_jcr_job_status(jcr, jcr->FDJobStatus);
379 Dmsg1(100, "FDStatus=%c\n", (char)jcr->JobStatus);
381 Jmsg(jcr, M_WARNING, 0, _("Unexpected Client Job message: %s\n"),
384 if (job_canceled(jcr)) {
389 stop_bsock_timer(tid);
392 if (is_bnet_error(fd)) {
393 Jmsg(jcr, M_FATAL, 0, _("Network error with FD during %s: ERR=%s\n"),
394 job_type_to_str(jcr->get_JobType()), fd->bstrerror());
396 fd->signal(BNET_TERMINATE); /* tell Client we are terminating */
399 /* Force cancel in SD if failing */
400 if (job_canceled(jcr) || !fd_ok) {
401 cancel_storage_daemon_job(jcr);
404 /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */
405 wait_for_storage_daemon_termination(jcr);
407 /* Return values from FD */
409 jcr->JobFiles = JobFiles;
410 jcr->JobErrors += JobErrors; /* Keep total errors */
411 jcr->ReadBytes = ReadBytes;
412 jcr->JobBytes = JobBytes;
413 jcr->JobWarnings = JobWarnings;
415 jcr->Encrypt = Encrypt;
417 Jmsg(jcr, M_FATAL, 0, _("No Job status returned from FD.\n"));
420 // Dmsg4(100, "fd_ok=%d FDJS=%d JS=%d SDJS=%d\n", fd_ok, jcr->FDJobStatus,
421 // jcr->JobStatus, jcr->SDJobStatus);
423 /* Return the first error status we find Dir, FD, or SD */
424 if (!fd_ok || is_bnet_error(fd)) { /* if fd not set, that use !fd_ok */
425 jcr->FDJobStatus = JS_ErrorTerminated;
427 if (jcr->JobStatus != JS_Terminated) {
428 return jcr->JobStatus;
430 if (jcr->FDJobStatus != JS_Terminated) {
431 return jcr->FDJobStatus;
433 return jcr->SDJobStatus;
437 * Release resources allocated during backup.
439 void backup_cleanup(JCR *jcr, int TermCode)
441 char sdt[50], edt[50], schedt[50];
442 char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], compress[50];
443 char ec6[30], ec7[30], ec8[30], elapsed[50];
444 char term_code[100], fd_term_msg[100], sd_term_msg[100];
445 const char *term_msg;
446 int msg_type = M_INFO;
449 double kbps, compression;
452 if (jcr->get_JobLevel() == L_VIRTUAL_FULL) {
453 vbackup_cleanup(jcr, TermCode);
457 Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode);
458 memset(&mr, 0, sizeof(mr));
459 memset(&cr, 0, sizeof(cr));
461 update_job_end(jcr, TermCode);
463 if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
464 Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
465 db_strerror(jcr->db));
466 set_jcr_job_status(jcr, JS_ErrorTerminated);
469 bstrncpy(cr.Name, jcr->client->name(), sizeof(cr.Name));
470 if (!db_get_client_record(jcr, jcr->db, &cr)) {
471 Jmsg(jcr, M_WARNING, 0, _("Error getting Client record for Job report: ERR=%s"),
472 db_strerror(jcr->db));
475 bstrncpy(mr.VolumeName, jcr->VolumeName, sizeof(mr.VolumeName));
476 if (!db_get_media_record(jcr, jcr->db, &mr)) {
477 Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
478 mr.VolumeName, db_strerror(jcr->db));
479 set_jcr_job_status(jcr, JS_ErrorTerminated);
482 update_bootstrap_file(jcr);
484 switch (jcr->JobStatus) {
486 if (jcr->JobErrors || jcr->SDErrors) {
487 term_msg = _("Backup OK -- with warnings");
489 term_msg = _("Backup OK");
493 term_msg = _("Backup OK -- with warnings");
496 case JS_ErrorTerminated:
497 term_msg = _("*** Backup Error ***");
498 msg_type = M_ERROR; /* Generate error message */
499 if (jcr->store_bsock) {
500 jcr->store_bsock->signal(BNET_TERMINATE);
501 if (jcr->SD_msg_chan) {
502 pthread_cancel(jcr->SD_msg_chan);
507 term_msg = _("Backup Canceled");
508 if (jcr->store_bsock) {
509 jcr->store_bsock->signal(BNET_TERMINATE);
510 if (jcr->SD_msg_chan) {
511 pthread_cancel(jcr->SD_msg_chan);
516 term_msg = term_code;
517 sprintf(term_code, _("Inappropriate term code: %c\n"), jcr->JobStatus);
520 bstrftimes(schedt, sizeof(schedt), jcr->jr.SchedTime);
521 bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
522 bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
523 RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
527 kbps = ((double)jcr->jr.JobBytes) / (1000.0 * (double)RunTime);
529 if (!db_get_job_volume_names(jcr, jcr->db, jcr->jr.JobId, &jcr->VolumeName)) {
531 * Note, if the job has erred, most likely it did not write any
532 * tape, so suppress this "error" message since in that case
533 * it is normal. Or look at it the other way, only for a
534 * normal exit should we complain about this error.
536 if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
537 Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
539 jcr->VolumeName[0] = 0; /* none */
542 if (jcr->ReadBytes == 0) {
543 bstrncpy(compress, "None", sizeof(compress));
545 compression = (double)100 - 100.0 * ((double)jcr->JobBytes / (double)jcr->ReadBytes);
546 if (compression < 0.5) {
547 bstrncpy(compress, "None", sizeof(compress));
549 bsnprintf(compress, sizeof(compress), "%.1f %%", compression);
552 jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
553 jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
555 // bmicrosleep(15, 0); /* for debugging SIGHUP */
557 Jmsg(jcr, msg_type, 0, _("%s %s %s (%s): %s\n"
558 " Build OS: %s %s %s\n"
561 " Backup Level: %s%s\n"
562 " Client: \"%s\" %s\n"
563 " FileSet: \"%s\" %s\n"
564 " Pool: \"%s\" (From %s)\n"
565 " Catalog: \"%s\" (From %s)\n"
566 " Storage: \"%s\" (From %s)\n"
567 " Scheduled time: %s\n"
570 " Elapsed time: %s\n"
572 " FD Files Written: %s\n"
573 " SD Files Written: %s\n"
574 " FD Bytes Written: %s (%sB)\n"
575 " SD Bytes Written: %s (%sB)\n"
577 " Software Compression: %s\n"
581 " Volume name(s): %s\n"
582 " Volume Session Id: %d\n"
583 " Volume Session Time: %d\n"
584 " Last Volume Bytes: %s (%sB)\n"
585 " Non-fatal FD errors: %d\n"
587 " FD termination status: %s\n"
588 " SD termination status: %s\n"
589 " Termination: %s\n\n"),
590 BACULA, my_name, VERSION, LSMDATE, edt,
591 HOST_OS, DISTNAME, DISTVER,
594 level_to_str(jcr->get_JobLevel()), jcr->since,
595 jcr->client->name(), cr.Uname,
596 jcr->fileset->name(), jcr->FSCreateTime,
597 jcr->pool->name(), jcr->pool_source,
598 jcr->catalog->name(), jcr->catalog_source,
599 jcr->wstore->name(), jcr->wstore_source,
603 edit_utime(RunTime, elapsed, sizeof(elapsed)),
605 edit_uint64_with_commas(jcr->jr.JobFiles, ec1),
606 edit_uint64_with_commas(jcr->SDJobFiles, ec2),
607 edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
608 edit_uint64_with_suffix(jcr->jr.JobBytes, ec4),
609 edit_uint64_with_commas(jcr->SDJobBytes, ec5),
610 edit_uint64_with_suffix(jcr->SDJobBytes, ec6),
613 jcr->VSS?_("yes"):_("no"),
614 jcr->Encrypt?_("yes"):_("no"),
615 jcr->accurate?_("yes"):_("no"),
619 edit_uint64_with_commas(mr.VolBytes, ec7),
620 edit_uint64_with_suffix(mr.VolBytes, ec8),
627 Dmsg0(100, "Leave backup_cleanup()\n");
630 void update_bootstrap_file(JCR *jcr)
632 /* Now update the bootstrap file if any */
633 if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes &&
634 jcr->job->WriteBootstrap) {
638 POOLMEM *fname = get_pool_memory(PM_FNAME);
639 fname = edit_job_codes(jcr, fname, jcr->job->WriteBootstrap, "");
641 VOL_PARAMS *VolParams = NULL;
643 char edt[50], ed1[50], ed2[50];
647 bpipe = open_bpipe(fname+1, 0, "w"); /* skip first char "|" */
648 fd = bpipe ? bpipe->wfd : NULL;
650 /* ***FIXME*** handle BASE */
651 fd = fopen(fname, jcr->get_JobLevel()==L_FULL?"w+b":"a+b");
654 VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId,
657 Jmsg(jcr, M_ERROR, 0, _("Could not get Job Volume Parameters to "
658 "update Bootstrap file. ERR=%s\n"), db_strerror(jcr->db));
659 if (jcr->SDJobFiles != 0) {
660 set_jcr_job_status(jcr, JS_ErrorTerminated);
664 /* Start output with when and who wrote it */
665 bstrftimes(edt, sizeof(edt), time(NULL));
666 fprintf(fd, "# %s - %s - %s%s\n", edt, jcr->jr.Job,
667 level_to_str(jcr->get_JobLevel()), jcr->since);
668 for (int i=0; i < VolCount; i++) {
669 /* Write the record */
670 fprintf(fd, "Volume=\"%s\"\n", VolParams[i].VolumeName);
671 fprintf(fd, "MediaType=\"%s\"\n", VolParams[i].MediaType);
672 if (VolParams[i].Slot > 0) {
673 fprintf(fd, "Slot=%d\n", VolParams[i].Slot);
675 fprintf(fd, "VolSessionId=%u\n", jcr->VolSessionId);
676 fprintf(fd, "VolSessionTime=%u\n", jcr->VolSessionTime);
677 fprintf(fd, "VolAddr=%s-%s\n",
678 edit_uint64(VolParams[i].StartAddr, ed1),
679 edit_uint64(VolParams[i].EndAddr, ed2));
680 fprintf(fd, "FileIndex=%d-%d\n", VolParams[i].FirstIndex,
681 VolParams[i].LastIndex);
693 Jmsg(jcr, M_ERROR, 0, _("Could not open WriteBootstrap file:\n"
694 "%s: ERR=%s\n"), fname, be.bstrerror());
695 set_jcr_job_status(jcr, JS_ErrorTerminated);
697 free_pool_memory(fname);