]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/backup.c
Implement MaxVirtualFullInterval
[bacula/bacula] / bacula / src / dird / backup.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2015 Kern Sibbald
5
6    The original author of Bacula is Kern Sibbald, with contributions
7    from many others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    This notice must be preserved when any source code is 
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   Bacula Director -- backup.c -- responsible for doing backup jobs
22  *
23  *     Kern Sibbald, March MM
24  *
25  *  Basic tasks done here:
26  *     Open DB and create records for this job.
27  *     Open Message Channel with Storage daemon to tell him a job will be starting.
28  *     Open connection with File daemon and pass him commands
29  *       to do the backup.
30  *     When the File daemon finishes the job, update the DB.
31  *
32  */
33
34 #include "bacula.h"
35 #include "dird.h"
36 #include "ua.h"
37
38 /* Commands sent to File daemon */
39 static char backupcmd[] = "backup FileIndex=%ld\n";
40 static char storaddr[]  = "storage address=%s port=%d ssl=%d\n";
41
42 /* Responses received from File daemon */
43 static char OKbackup[]   = "2000 OK backup\n";
44 static char OKstore[]    = "2000 OK storage\n";
45 static char EndJob[]     = "2800 End Job TermCode=%d JobFiles=%u "
46                            "ReadBytes=%llu JobBytes=%llu Errors=%u "
47                            "VSS=%d Encrypt=%d\n";
48 /* Pre 1.39.29 (04Dec06) EndJob */
49 static char OldEndJob[]  = "2800 End Job TermCode=%d JobFiles=%u "
50                            "ReadBytes=%llu JobBytes=%llu Errors=%u\n";
51
52 /* Commands sent to Storage daemon */
53 static char clientaddr[] = "client address=%s port=%d ssl=%d\n";
54
55 /* Commands received from Storage daemon */
56 static char OKclient[]   = "3000 OK client command\n";
57
58 /*
59  * Called here before the job is run to do the job
60  *   specific setup.
61  */
62 bool do_backup_init(JCR *jcr)
63 {
64    /* Make local copy */
65    jcr->RescheduleIncompleteJobs = jcr->job->RescheduleIncompleteJobs;
66
67    if (!get_or_create_fileset_record(jcr)) {
68       Dmsg1(100, "JobId=%d no FileSet\n", (int)jcr->JobId);
69       return false;
70    }
71
72    /*
73     * Get definitive Job level and since time
74     * unless it's a virtual full.  In that case
75     * it is not needed.
76     */
77    if (!jcr->is_JobLevel(L_VIRTUAL_FULL)) {
78       get_level_since_time(jcr, jcr->since, sizeof(jcr->since));
79    }
80
81    apply_pool_overrides(jcr);
82
83    if (!allow_duplicate_job(jcr)) {
84       return false;
85    }
86
87    jcr->jr.PoolId = get_or_create_pool_record(jcr, jcr->pool->name());
88    if (jcr->jr.PoolId == 0) {
89       Dmsg1(100, "JobId=%d no PoolId\n", (int)jcr->JobId);
90       Jmsg(jcr, M_FATAL, 0, _("Could not get or create a Pool record.\n"));
91       return false;
92    }
93
94    /*
95     * If we are a virtual full job or got upgraded to one
96     * then we divert at this point and call the virtual full 
97     * backup init method
98     */ 
99    if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
100      return do_vbackup_init(jcr);
101    }
102
103    free_rstorage(jcr);                   /* we don't read so release */
104
105    /* If pool storage specified, use it instead of job storage */
106    copy_wstorage(jcr, jcr->pool->storage, _("Pool resource"));
107
108    if (!jcr->wstorage) {
109       Jmsg(jcr, M_FATAL, 0, _("No Storage specification found in Job or Pool.\n"));
110       return false;
111    }
112
113    create_clones(jcr);                /* run any clone jobs */
114
115    return true;
116 }
117
118 /* Take all base jobs from job resource and find the
119  * last L_BASE jobid.
120  */
121 static bool get_base_jobids(JCR *jcr, db_list_ctx *jobids)
122 {
123    JOB_DBR jr;
124    JOB *job;
125    JobId_t id;
126    char str_jobid[50];
127
128    if (!jcr->job->base) {
129       return false;             /* no base job, stop accurate */
130    }
131
132    memset(&jr, 0, sizeof(JOB_DBR));
133    jr.StartTime = jcr->jr.StartTime;
134
135    foreach_alist(job, jcr->job->base) {
136       bstrncpy(jr.Name, job->name(), sizeof(jr.Name));
137       db_get_base_jobid(jcr, jcr->db, &jr, &id);
138
139       if (id) {
140          if (jobids->count) {
141             pm_strcat(jobids->list, ",");
142          }
143          pm_strcat(jobids->list, edit_uint64(id, str_jobid));
144          jobids->count++;
145       }
146    }
147
148    return jobids->count > 0;
149 }
150
151 /*
152  * Foreach files in currrent list, send "/path/fname\0LStat\0MD5\0Delta" to FD
153  *      row[0]=Path, row[1]=Filename, row[2]=FileIndex
154  *      row[3]=JobId row[4]=LStat row[5]=DeltaSeq row[6]=MD5
155  */
156 static int accurate_list_handler(void *ctx, int num_fields, char **row)
157 {
158    JCR *jcr = (JCR *)ctx;
159
160    if (job_canceled(jcr)) {
161       return 1;
162    }
163
164    if (row[2][0] == '0') {           /* discard when file_index == 0 */
165       return 0;
166    }
167
168    /* sending with checksum */
169    if (jcr->use_accurate_chksum
170        && num_fields == 7
171        && row[6][0] /* skip checksum = '0' */
172        && row[6][1])
173    {
174       jcr->file_bsock->fsend("%s%s%c%s%c%s%c%s",
175                              row[0], row[1], 0, row[4], 0, row[6], 0, row[5]);
176    } else {
177       jcr->file_bsock->fsend("%s%s%c%s%c%c%s",
178                              row[0], row[1], 0, row[4], 0, 0, row[5]);
179    }
180    return 0;
181 }
182
183 /* In this procedure, we check if the current fileset is using checksum
184  * FileSet-> Include-> Options-> Accurate/Verify/BaseJob=checksum
185  * This procedure uses jcr->HasBase, so it must be call after the initialization
186  */
187 static bool is_checksum_needed_by_fileset(JCR *jcr)
188 {
189    FILESET *f;
190    INCEXE *inc;
191    FOPTS *fopts;
192    bool in_block=false;
193    bool have_basejob_option=false;
194    if (!jcr->job || !jcr->job->fileset) {
195       return false;
196    }
197
198    f = jcr->job->fileset;
199
200    for (int i=0; i < f->num_includes; i++) { /* Parse all Include {} */
201       inc = f->include_items[i];
202
203       for (int j=0; j < inc->num_opts; j++) { /* Parse all Options {} */
204          fopts = inc->opts_list[j];
205
206          for (char *k=fopts->opts; *k ; k++) { /* Try to find one request */
207             switch (*k) {
208             case 'V':           /* verify */
209                in_block = (jcr->getJobType() == JT_VERIFY); /* not used now */
210                break;
211             case 'J':           /* Basejob keyword */
212                have_basejob_option = in_block = jcr->HasBase;
213                break;
214             case 'C':           /* Accurate keyword */
215                in_block = !jcr->is_JobLevel(L_FULL);
216                break;
217             case ':':           /* End of keyword */
218                in_block = false;
219                break;
220             case '5':           /* MD5  */
221             case '1':           /* SHA1 */
222                if (in_block) {
223                   Dmsg0(50, "Checksum will be sent to FD\n");
224                   return true;
225                }
226                break;
227             default:
228                break;
229             }
230          }
231       }
232    }
233
234    /* By default for BaseJobs, we send the checksum */
235    if (!have_basejob_option && jcr->HasBase) {
236       return true;
237    }
238
239    Dmsg0(50, "Checksum will be sent to FD\n");
240    return false;
241 }
242
243 /*
244  * Send current file list to FD
245  *    DIR -> FD : accurate files=xxxx
246  *    DIR -> FD : /path/to/file\0Lstat\0MD5\0Delta
247  *    DIR -> FD : /path/to/dir/\0Lstat\0MD5\0Delta
248  *    ...
249  *    DIR -> FD : EOD
250  */
251 bool send_accurate_current_files(JCR *jcr)
252 {
253    POOL_MEM buf;
254    db_list_ctx jobids;
255    db_list_ctx nb;
256    char ed1[50];
257
258    /* In base level, no previous job is used and no restart incomplete jobs */
259    if (jcr->is_canceled() || jcr->is_JobLevel(L_BASE)) {
260       return true;
261    }
262    if (!jcr->accurate && !jcr->rerunning) {
263       return true;
264    }
265
266    if (jcr->is_JobLevel(L_FULL)) {
267       /* On Full mode, if no previous base job, no accurate things */
268       if (get_base_jobids(jcr, &jobids)) {
269          jcr->HasBase = true;
270          Jmsg(jcr, M_INFO, 0, _("Using Base JobId(s): %s\n"), jobids.list);
271       } else if (!jcr->rerunning) {
272          return true;
273       }
274    } else {
275       /* For Incr/Diff level, we search for older jobs */
276       db_get_accurate_jobids(jcr, jcr->db, &jcr->jr, &jobids);
277
278       /* We are in Incr/Diff, but no Full to build the accurate list... */
279       if (jobids.count == 0) {
280          Jmsg(jcr, M_FATAL, 0, _("Cannot find previous jobids.\n"));
281          return false;  /* fail */
282       }
283    }
284
285    /* For incomplete Jobs, we add our own id */
286    if (jcr->rerunning) {
287       edit_int64(jcr->JobId, ed1);
288       jobids.add(ed1);
289    }
290
291    /* Don't send and store the checksum if fileset doesn't require it */
292    jcr->use_accurate_chksum = is_checksum_needed_by_fileset(jcr);
293
294    if (jcr->JobId) {            /* display the message only for real jobs */
295       Jmsg(jcr, M_INFO, 0, _("Sending Accurate information to the FD.\n"));
296    }
297
298    /* to be able to allocate the right size for htable */
299    Mmsg(buf, "SELECT sum(JobFiles) FROM Job WHERE JobId IN (%s)", jobids.list);
300    db_sql_query(jcr->db, buf.c_str(), db_list_handler, &nb);
301    Dmsg2(200, "jobids=%s nb=%s\n", jobids.list, nb.list);
302    jcr->file_bsock->fsend("accurate files=%s\n", nb.list);
303
304    if (!db_open_batch_connexion(jcr, jcr->db)) {
305       Jmsg0(jcr, M_FATAL, 0, "Can't get batch sql connexion");
306       return false;  /* Fail */
307    }
308
309    if (jcr->HasBase) {
310       jcr->nb_base_files = str_to_int64(nb.list);
311       if (!db_create_base_file_list(jcr, jcr->db, jobids.list)) {
312          Jmsg1(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
313          return false;
314       }
315       if (!db_get_base_file_list(jcr, jcr->db, jcr->use_accurate_chksum,
316                             accurate_list_handler, (void *)jcr)) {
317          Jmsg1(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
318          return false;
319       }
320
321    } else {
322       if (!db_get_file_list(jcr, jcr->db_batch,
323                        jobids.list, jcr->use_accurate_chksum, false /* no delta */,
324                        accurate_list_handler, (void *)jcr)) {
325          Jmsg1(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db_batch));
326          return false;
327       }
328    }
329
330    /* TODO: close the batch connection ? (can be used very soon) */
331    jcr->file_bsock->signal(BNET_EOD);
332    return true;
333 }
334
335 bool send_store_addr_to_fd(JCR *jcr, STORE *store,
336                            char *store_address, uint32_t store_port)
337 {
338    int tls_need = BNET_TLS_NONE;
339
340    /* TLS Requirement */
341    if (store->tls_enable) {
342       if (store->tls_require) {
343          tls_need = BNET_TLS_REQUIRED;
344       } else {
345          tls_need = BNET_TLS_OK;
346       }
347    }
348
349    /*
350     * Send Storage address to the FD
351     */
352    jcr->file_bsock->fsend(storaddr, store_address, store_port, tls_need);
353    if (!response(jcr, jcr->file_bsock, OKstore, "Storage", DISPLAY_ERROR)) {
354       return false;
355    }
356    return true;
357 }
358
359 bool send_client_addr_to_sd(JCR *jcr)
360 {
361    int tls_need = BNET_TLS_NONE;
362    BSOCK *sd = jcr->store_bsock;
363
364    /* TLS Requirement for the client */
365    if (jcr->client->tls_enable) {
366       if (jcr->client->tls_require) {
367          tls_need = BNET_TLS_REQUIRED;
368       } else {
369          tls_need = BNET_TLS_OK;
370       }
371    }
372    /*
373     * Send Client address to the SD
374     */
375    sd->fsend(clientaddr, jcr->client->address, jcr->client->FDport, tls_need);
376    if (!response(jcr, sd, OKclient, "Client", DISPLAY_ERROR)) {
377       return false;
378    }
379    return true;
380 }
381
382 /*
383  * Allow to specify the address used by the Client to
384  * connect to the storage daemon in the Client resource
385  * or in the Storage resource.
386  */
387 char *get_storage_address(CLIENT *client, STORE *store)
388 {
389    char *store_address;
390
391    if (client && client->fd_storage_address) {
392       Dmsg0(10, "Using Client resource FD Storage Address to contact the Storage\n");
393       store_address = client->fd_storage_address;
394
395    } else if (store->fd_storage_address) {
396       Dmsg0(10, "Using Storage resource FD Storage Address to contact the Storage\n");
397       store_address = store->fd_storage_address;
398
399    } else {
400       Dmsg0(10, "Using default Storage address\n");
401       store_address = store->address;
402    }
403    return store_address;
404 }
405
406 bool run_storage_and_start_message_thread(JCR *jcr, BSOCK *sd)
407 {
408    /*
409     * Start the job prior to starting the message thread below
410     * to avoid two threads from using the BSOCK structure at
411     * the same time.
412     */
413    if (!sd->fsend("run")) {
414       return false;
415    }
416
417    /*
418     * Now start a Storage daemon message thread.  Note,
419     *   this thread is used to provide the catalog services
420     *   for the backup job, including inserting the attributes
421     *   into the catalog.  See catalog_update() in catreq.c
422     */
423    if (!start_storage_daemon_message_thread(jcr)) {
424       return false;
425    }
426    Dmsg0(150, "Storage daemon connection OK\n");
427    return true;
428 }
429
430 /*
431  * Do a backup of the specified FileSet
432  *
433  *  Returns:  false on failure
434  *            true  on success
435  */
436 bool do_backup(JCR *jcr)
437 {
438    int stat;
439    BSOCK   *fd, *sd;
440    STORE *store;
441    char *store_address;
442    uint32_t store_port;
443    char ed1[100];
444    db_int64_ctx job;
445    POOL_MEM buf;
446
447    if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
448       return do_vbackup(jcr);
449    }
450
451    /* Print Job Start message */
452    if (jcr->rerunning) {
453       Jmsg(jcr, M_INFO, 0, _("Restart Incomplete Backup JobId %s, Job=%s\n"),
454            edit_uint64(jcr->JobId, ed1), jcr->Job);
455    } else {
456       Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %s, Job=%s\n"),
457            edit_uint64(jcr->JobId, ed1), jcr->Job);
458    }
459
460    jcr->setJobStatus(JS_Running);
461    Dmsg2(100, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel);
462    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
463       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
464       return false;
465    }
466
467    /* For incomplete Jobs, we add our own id */
468    if (jcr->rerunning) {
469       edit_int64(jcr->JobId, ed1);
470       Mmsg(buf, "SELECT max(FileIndex) FROM File WHERE JobId=%s", ed1);
471       if (db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
472          Jmsg(jcr, M_INFO, 0, _("Found %ld files from prior incomplete Job.\n"),
473             (int32_t)job.value);
474       } else {
475          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
476          return false;
477       }
478       jcr->JobFiles = job.value;
479       Dmsg1(100, "==== FI=%ld\n", jcr->JobFiles);
480       Mmsg(buf, "SELECT VolSessionId FROM Job WHERE JobId=%s", ed1);
481       if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
482          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
483          return false;
484       }
485       jcr->VolSessionId = job.value;
486       Mmsg(buf, "SELECT VolSessionTime FROM Job WHERE JobId=%s", ed1);
487       if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
488          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
489          return false;
490       }
491       jcr->VolSessionTime = job.value;
492       Dmsg4(100, "JobId=%s JobFiles=%ld VolSessionId=%ld VolSessionTime=%ld\n", ed1,
493             jcr->JobFiles, jcr->VolSessionId, jcr->VolSessionTime);
494    }
495
496    /*
497     * Open a message channel connection with the Storage
498     * daemon. This is to let him know that our client
499     * will be contacting him for a backup  session.
500     *
501     */
502    Dmsg0(110, "Open connection with storage daemon\n");
503    jcr->setJobStatus(JS_WaitSD);
504    /*
505     * Start conversation with Storage daemon
506     */
507    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
508       return false;
509    }
510    /*
511     * Now start a job with the Storage daemon
512     */
513    if (!start_storage_daemon_job(jcr, NULL, jcr->wstorage)) {
514       return false;
515    }
516    sd = jcr->store_bsock;
517    if (jcr->client) {
518       jcr->sd_calls_client = jcr->client->sd_calls_client;
519    }
520    /*
521     * Note startup sequence of SD/FD is different depending on
522     *  whether the SD listens (normal) or the SD calls the FD.
523     */
524    if (!jcr->sd_calls_client) {
525       if (!run_storage_and_start_message_thread(jcr, sd)) {
526          goto bail_out;
527       }
528    }
529    jcr->setJobStatus(JS_WaitFD);
530    if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
531       goto bail_out;
532    }
533
534    jcr->setJobStatus(JS_Running);
535    fd = jcr->file_bsock;
536
537    if (!send_level_command(jcr)) {
538       goto bail_out;
539    }
540
541    if (!send_include_list(jcr)) {
542       goto bail_out;
543    }
544
545    if (!send_exclude_list(jcr)) {
546       goto bail_out;
547    }
548
549    /* TODO: See priority with bandwidth parameter */
550    if (jcr->job->max_bandwidth > 0) {
551       jcr->max_bandwidth = jcr->job->max_bandwidth;
552    } else if (jcr->client->max_bandwidth > 0) {
553       jcr->max_bandwidth = jcr->client->max_bandwidth;
554    }
555
556    if (jcr->max_bandwidth > 0) {
557       send_bwlimit(jcr, jcr->Job); /* Old clients don't have this command */
558    }
559
560    send_snapshot_retention(jcr, jcr->snapshot_retention);
561
562    store = jcr->wstore;
563
564    if (jcr->sd_calls_client) {
565       if (jcr->FDVersion < 10) {
566          Jmsg(jcr, M_FATAL, 0, _("The File daemon does not support SDCallsClient.\n"));
567          goto bail_out;
568       }
569       if (!send_client_addr_to_sd(jcr)) {
570          goto bail_out;
571       }
572
573       if (!run_storage_and_start_message_thread(jcr, sd)) {
574          goto bail_out;
575       }
576
577       store_address = jcr->wstore->address;  /* dummy */
578       store_port = 0;           /* flag that SD calls FD */
579    } else {
580       /*
581        * send Storage daemon address to the File daemon
582        */
583       if (store->SDDport == 0) {
584          store->SDDport = store->SDport;
585       }
586
587       store_address = get_storage_address(jcr->client, store);
588       store_port = store->SDDport;
589    }
590
591    if (!send_store_addr_to_fd(jcr, store, store_address, store_port)) {
592       goto bail_out;
593    }
594
595    /* Declare the job started to start the MaxRunTime check */
596    jcr->setJobStarted();
597
598    /* Send and run the RunBefore */
599    if (!send_runscripts_commands(jcr)) {
600       goto bail_out;
601    }
602
603    /*
604     * We re-update the job start record so that the start
605     *  time is set after the run before job.  This avoids
606     *  that any files created by the run before job will
607     *  be saved twice.  They will be backed up in the current
608     *  job, but not in the next one unless they are changed.
609     *  Without this, they will be backed up in this job and
610     *  in the next job run because in that case, their date
611     *   is after the start of this run.
612     */
613    jcr->start_time = time(NULL);
614    jcr->jr.StartTime = jcr->start_time;
615    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
616       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
617    }
618
619    /*
620     * If backup is in accurate mode, we send the list of
621     * all files to FD.
622     */
623    if (!send_accurate_current_files(jcr)) {
624       goto bail_out;     /* error */
625    }
626
627    /* Send backup command */
628    fd->fsend(backupcmd, jcr->JobFiles);
629    Dmsg1(100, ">filed: %s", fd->msg);
630    if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) {
631       goto bail_out;
632    }
633
634    /* Pickup Job termination data */
635    stat = wait_for_job_termination(jcr);
636    db_write_batch_file_records(jcr);    /* used by bulk batch file insert */
637
638    if (jcr->HasBase) {
639       db_commit_base_file_attributes_record(jcr, jcr->db);
640       /* Any error already printed */
641    }
642
643    if (!jcr->is_canceled() && stat == JS_Terminated) {
644       backup_cleanup(jcr, stat);
645       return true;
646    }
647    return false;
648
649 /* Come here only after starting SD thread */
650 bail_out:
651    jcr->setJobStatus(JS_ErrorTerminated);
652    Dmsg1(400, "wait for sd. use=%d\n", jcr->use_count());
653    /* Cancel SD */
654    wait_for_job_termination(jcr, FDConnectTimeout);
655    Dmsg1(400, "after wait for sd. use=%d\n", jcr->use_count());
656    return false;
657 }
658
659
660 /*
661  * Here we wait for the File daemon to signal termination,
662  *   then we wait for the Storage daemon.  When both
663  *   are done, we return the job status.
664  * Also used by restore.c
665  */
666 int wait_for_job_termination(JCR *jcr, int timeout)
667 {
668    int32_t n = 0;
669    BSOCK *fd = jcr->file_bsock;
670    bool fd_ok = false;
671    uint32_t JobFiles, JobErrors;
672    uint32_t JobWarnings = 0;
673    uint64_t ReadBytes = 0;
674    uint64_t JobBytes = 0;
675    int VSS = 0;                 /* or Snapshot on Unix */
676    int Encrypt = 0;
677    btimer_t *tid=NULL;
678
679    if (fd) {
680       if (timeout) {
681          tid = start_bsock_timer(fd, timeout); /* TODO: New timeout directive??? */
682       }
683       /* Wait for Client to terminate */
684       while ((n = bget_dirmsg(fd)) >= 0) {
685          if (!fd_ok && 
686               (sscanf(fd->msg, EndJob, &jcr->FDJobStatus, &JobFiles,
687                      &ReadBytes, &JobBytes, &JobErrors, &VSS, &Encrypt) == 7 ||
688                sscanf(fd->msg, OldEndJob, &jcr->FDJobStatus, &JobFiles,
689                      &ReadBytes, &JobBytes, &JobErrors) == 5)) {
690             fd_ok = true;
691             jcr->setJobStatus(jcr->FDJobStatus);
692             Dmsg1(100, "FDStatus=%c\n", (char)jcr->JobStatus);
693          } else {
694             Jmsg(jcr, M_WARNING, 0, _("Unexpected Client Job message: %s\n"),
695                  fd->msg);
696          }
697          if (job_canceled(jcr)) {
698             break;
699          }
700       }
701       if (tid) {
702          stop_bsock_timer(tid);
703       }
704
705       if (fd->is_error() && jcr->getJobStatus() != JS_Canceled) {
706          int i = 0;
707          Jmsg(jcr, M_FATAL, 0, _("Network error with FD during %s: ERR=%s\n"),
708               job_type_to_str(jcr->getJobType()), fd->bstrerror());
709          while (i++ < 20 && jcr->job->RescheduleIncompleteJobs && jcr->is_canceled()) {
710             bmicrosleep(3, 0);
711          }
712       }
713       fd->signal(BNET_TERMINATE);   /* tell Client we are terminating */
714    }
715
716    /*
717     * Force cancel in SD if failing, but not for Incomplete jobs
718     *  so that we let the SD despool.
719     */
720    Dmsg5(100, "cancel=%d fd_ok=%d FDJS=%d JS=%d SDJS=%d\n", jcr->is_canceled(), fd_ok, jcr->FDJobStatus,
721         jcr->JobStatus, jcr->SDJobStatus);
722    if (jcr->is_canceled() || (!jcr->job->RescheduleIncompleteJobs && !fd_ok)) {
723       Dmsg4(100, "fd_ok=%d FDJS=%d JS=%d SDJS=%d\n", fd_ok, jcr->FDJobStatus,
724            jcr->JobStatus, jcr->SDJobStatus);
725       cancel_storage_daemon_job(jcr);
726    }
727
728    /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */
729    wait_for_storage_daemon_termination(jcr);
730
731    /* Return values from FD */
732    if (fd_ok) {
733       jcr->JobFiles = JobFiles;
734       jcr->JobErrors += JobErrors;       /* Keep total errors */
735       jcr->ReadBytes = ReadBytes;
736       jcr->JobBytes = JobBytes;
737       jcr->JobWarnings = JobWarnings;
738       jcr->Snapshot = VSS;
739       jcr->Encrypt = Encrypt;
740    } else if (jcr->getJobStatus() != JS_Canceled) {
741       Jmsg(jcr, M_FATAL, 0, _("No Job status returned from FD.\n"));
742    }
743
744    /* Return the first error status we find Dir, FD, or SD */
745    if (!fd_ok || fd->is_error()) { /* if fd not set, that use !fd_ok */
746       if (jcr->getJobStatus() == JS_Canceled) {
747          jcr->FDJobStatus = JS_Canceled;
748       } else {
749          jcr->FDJobStatus = JS_ErrorTerminated;
750       }
751    }
752    if (jcr->JobStatus != JS_Terminated) {
753       return jcr->JobStatus;
754    }
755    if (jcr->FDJobStatus != JS_Terminated) {
756       return jcr->FDJobStatus;
757    }
758    return jcr->SDJobStatus;
759 }
760
761 /*
762  * Release resources allocated during backup.
763  */
764 void backup_cleanup(JCR *jcr, int TermCode)
765 {
766    char sdt[50], edt[50], schedt[50];
767    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30];
768    char ec6[30], ec7[30], ec8[30], ec9[30], ec10[30], elapsed[50];
769    char data_compress[200];
770    char term_code[100], fd_term_msg[100], sd_term_msg[100];
771    const char *term_msg;
772    int msg_type = M_INFO;
773    MEDIA_DBR mr;
774    CLIENT_DBR cr;
775    double kbps, compression, ratio;
776    utime_t RunTime;
777    POOL_MEM base_info;
778    POOL_MEM vol_info;
779
780    if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
781       vbackup_cleanup(jcr, TermCode);
782       return;
783    }
784
785    Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode);
786    memset(&cr, 0, sizeof(cr));
787
788    update_job_end(jcr, TermCode);
789
790    if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
791       Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
792          db_strerror(jcr->db));
793       jcr->setJobStatus(JS_ErrorTerminated);
794    }
795
796    bstrncpy(cr.Name, jcr->client->name(), sizeof(cr.Name));
797    if (!db_get_client_record(jcr, jcr->db, &cr)) {
798       Jmsg(jcr, M_WARNING, 0, _("Error getting Client record for Job report: ERR=%s"),
799          db_strerror(jcr->db));
800    }
801
802    bstrncpy(mr.VolumeName, jcr->VolumeName, sizeof(mr.VolumeName));
803    if (!db_get_media_record(jcr, jcr->db, &mr)) {
804       Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
805          mr.VolumeName, db_strerror(jcr->db));
806       jcr->setJobStatus(JS_ErrorTerminated);
807    }
808
809    update_bootstrap_file(jcr);
810
811    switch (jcr->JobStatus) {
812       case JS_Terminated:
813          if (jcr->JobErrors || jcr->SDErrors) {
814             term_msg = _("Backup OK -- with warnings");
815          } else {
816             term_msg = _("Backup OK");
817          }
818          break;
819       case JS_Incomplete:
820          term_msg = _("Backup failed -- incomplete");
821          break;
822       case JS_Warnings:
823          term_msg = _("Backup OK -- with warnings");
824          break;
825       case JS_FatalError:
826       case JS_ErrorTerminated:
827          term_msg = _("*** Backup Error ***");
828          msg_type = M_ERROR;          /* Generate error message */
829          if (jcr->store_bsock) {
830             jcr->store_bsock->signal(BNET_TERMINATE);
831             if (jcr->SD_msg_chan_started) {
832                pthread_cancel(jcr->SD_msg_chan);
833             }
834          }
835          break;
836       case JS_Canceled:
837          term_msg = _("Backup Canceled");
838          if (jcr->store_bsock) {
839             jcr->store_bsock->signal(BNET_TERMINATE);
840             if (jcr->SD_msg_chan_started) {
841                pthread_cancel(jcr->SD_msg_chan);
842             }
843          }
844          break;
845       default:
846          term_msg = term_code;
847          sprintf(term_code, _("Inappropriate term code: %c\n"), jcr->JobStatus);
848          break;
849    }
850    bstrftimes(schedt, sizeof(schedt), jcr->jr.SchedTime);
851    bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
852    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
853    RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
854    if (RunTime <= 0) {
855       kbps = 0;
856    } else {
857       kbps = ((double)jcr->jr.JobBytes) / (1000.0 * (double)RunTime);
858    }
859    if (!db_get_job_volume_names(jcr, jcr->db, jcr->jr.JobId, &jcr->VolumeName)) {
860       /*
861        * Note, if the job has erred, most likely it did not write any
862        *  tape, so suppress this "error" message since in that case
863        *  it is normal.  Or look at it the other way, only for a
864        *  normal exit should we complain about this error.
865        */
866       if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
867          Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
868       }
869       jcr->VolumeName[0] = 0;         /* none */
870    }
871
872    if (jcr->ReadBytes == 0) {
873       bstrncpy(data_compress, "None", sizeof(data_compress));
874    } else {
875       compression = (double)100 - 100.0 * ((double)jcr->SDJobBytes / (double)jcr->ReadBytes);
876       if (compression < 0.5) {
877          bstrncpy(data_compress, "None", sizeof(data_compress));
878       } else {
879          if (jcr->SDJobBytes > 0) {
880             ratio = (double)jcr->ReadBytes / (double)jcr->SDJobBytes;
881          } else {
882             ratio = 1.0;
883          }
884          bsnprintf(data_compress, sizeof(data_compress), "%.1f%% %.1f:1",
885             compression, ratio);
886       }
887    }
888    jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
889    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
890
891    if (jcr->HasBase) {
892       Mmsg(base_info, _("  Base files/Used files:  %lld/%lld (%.2f%%)\n"),
893            jcr->nb_base_files,
894            jcr->nb_base_files_used,
895            jcr->nb_base_files_used*100.0/jcr->nb_base_files);
896    }
897    /* Edit string for last volume size */
898    if (mr.VolABytes != 0) {
899       Mmsg(vol_info, _("meta: %s (%sB) aligned: %s (%sB)"),
900         edit_uint64_with_commas(mr.VolBytes, ec7),
901         edit_uint64_with_suffix(mr.VolBytes, ec8),
902         edit_uint64_with_commas(mr.VolABytes, ec9),
903         edit_uint64_with_suffix(mr.VolABytes, ec10));
904    } else {
905      Mmsg(vol_info, _("%s (%sB)"),
906         edit_uint64_with_commas(mr.VolBytes, ec7),
907         edit_uint64_with_suffix(mr.VolBytes, ec8));
908    }
909
910 // bmicrosleep(15, 0);                /* for debugging SIGHUP */
911
912    Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
913 "  Build OS:               %s %s %s\n"
914 "  JobId:                  %d\n"
915 "  Job:                    %s\n"
916 "  Backup Level:           %s%s\n"
917 "  Client:                 \"%s\" %s\n"
918 "  FileSet:                \"%s\" %s\n"
919 "  Pool:                   \"%s\" (From %s)\n"
920 "  Catalog:                \"%s\" (From %s)\n"
921 "  Storage:                \"%s\" (From %s)\n"
922 "  Scheduled time:         %s\n"
923 "  Start time:             %s\n"
924 "  End time:               %s\n"
925 "  Elapsed time:           %s\n"
926 "  Priority:               %d\n"
927 "  FD Files Written:       %s\n"
928 "  SD Files Written:       %s\n"
929 "  FD Bytes Written:       %s (%sB)\n"
930 "  SD Bytes Written:       %s (%sB)\n"
931 "  Rate:                   %.1f KB/s\n"
932 "  Software Compression:   %s\n"
933 "%s"                                         /* Basefile info */
934 "  Snapshot/VSS:           %s\n"
935 "  Encryption:             %s\n"
936 "  Accurate:               %s\n"
937 "  Volume name(s):         %s\n"
938 "  Volume Session Id:      %d\n"
939 "  Volume Session Time:    %d\n"
940 "  Last Volume Bytes:      %s\n"
941 "  Non-fatal FD errors:    %d\n"
942 "  SD Errors:              %d\n"
943 "  FD termination status:  %s\n"
944 "  SD termination status:  %s\n"
945 "  Termination:            %s\n\n"),
946         BACULA, my_name, VERSION, LSMDATE,
947         HOST_OS, DISTNAME, DISTVER,
948         jcr->jr.JobId,
949         jcr->jr.Job,
950         level_to_str(jcr->getJobLevel()), jcr->since,
951         jcr->client->name(), cr.Uname,
952         jcr->fileset->name(), jcr->FSCreateTime,
953         jcr->pool->name(), jcr->pool_source,
954         jcr->catalog->name(), jcr->catalog_source,
955         jcr->wstore->name(), jcr->wstore_source,
956         schedt,
957         sdt,
958         edt,
959         edit_utime(RunTime, elapsed, sizeof(elapsed)),
960         jcr->JobPriority,
961         edit_uint64_with_commas(jcr->jr.JobFiles, ec1),
962         edit_uint64_with_commas(jcr->SDJobFiles, ec2),
963         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
964         edit_uint64_with_suffix(jcr->jr.JobBytes, ec4),
965         edit_uint64_with_commas(jcr->SDJobBytes, ec5),
966         edit_uint64_with_suffix(jcr->SDJobBytes, ec6),
967         kbps,
968         data_compress,
969         base_info.c_str(),
970         jcr->Snapshot?_("yes"):_("no"),
971         jcr->Encrypt?_("yes"):_("no"),
972         jcr->accurate?_("yes"):_("no"),
973         jcr->VolumeName,
974         jcr->VolSessionId,
975         jcr->VolSessionTime,
976         vol_info.c_str(),
977         jcr->JobErrors,
978         jcr->SDErrors,
979         fd_term_msg,
980         sd_term_msg,
981         term_msg);
982
983    Dmsg0(100, "Leave backup_cleanup()\n");
984 }
985
986 void update_bootstrap_file(JCR *jcr)
987 {
988    /* Now update the bootstrap file if any */
989    if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes &&
990        jcr->job->WriteBootstrap) {
991       FILE *fd;
992       BPIPE *bpipe = NULL;
993       int got_pipe = 0;
994       POOLMEM *fname = get_pool_memory(PM_FNAME);
995       fname = edit_job_codes(jcr, fname, jcr->job->WriteBootstrap, "");
996
997       VOL_PARAMS *VolParams = NULL;
998       int VolCount;
999       char edt[50], ed1[50], ed2[50];
1000
1001       if (*fname == '|') {
1002          got_pipe = 1;
1003          bpipe = open_bpipe(fname+1, 0, "w"); /* skip first char "|" */
1004          fd = bpipe ? bpipe->wfd : NULL;
1005       } else {
1006          /* ***FIXME*** handle BASE */
1007          fd = fopen(fname, jcr->is_JobLevel(L_FULL)?"w+b":"a+b");
1008       }
1009       if (fd) {
1010          VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId,
1011                     &VolParams);
1012          if (VolCount == 0) {
1013             Jmsg(jcr, M_ERROR, 0, _("Could not get Job Volume Parameters to "
1014                  "update Bootstrap file. ERR=%s\n"), db_strerror(jcr->db));
1015              if (jcr->SDJobFiles != 0) {
1016                 jcr->setJobStatus(JS_ErrorTerminated);
1017              }
1018
1019          }
1020          /* Start output with when and who wrote it */
1021          bstrftimes(edt, sizeof(edt), time(NULL));
1022          fprintf(fd, "# %s - %s - %s%s\n", edt, jcr->jr.Job,
1023                  level_to_str(jcr->getJobLevel()), jcr->since);
1024          for (int i=0; i < VolCount; i++) {
1025             /* Write the record */
1026             fprintf(fd, "Volume=\"%s\"\n", VolParams[i].VolumeName);
1027             fprintf(fd, "MediaType=\"%s\"\n", VolParams[i].MediaType);
1028             if (VolParams[i].Slot > 0) {
1029                fprintf(fd, "Slot=%d\n", VolParams[i].Slot);
1030             }
1031             fprintf(fd, "VolSessionId=%u\n", jcr->VolSessionId);
1032             fprintf(fd, "VolSessionTime=%u\n", jcr->VolSessionTime);
1033             fprintf(fd, "VolAddr=%s-%s\n",
1034                     edit_uint64(VolParams[i].StartAddr, ed1),
1035                     edit_uint64(VolParams[i].EndAddr, ed2));
1036             fprintf(fd, "FileIndex=%d-%d\n", VolParams[i].FirstIndex,
1037                          VolParams[i].LastIndex);
1038          }
1039          if (VolParams) {
1040             free(VolParams);
1041          }
1042          if (got_pipe) {
1043             close_bpipe(bpipe);
1044          } else {
1045             fclose(fd);
1046          }
1047       } else {
1048          berrno be;
1049          Jmsg(jcr, M_ERROR, 0, _("Could not open WriteBootstrap file:\n"
1050               "%s: ERR=%s\n"), fname, be.bstrerror());
1051          jcr->setJobStatus(JS_ErrorTerminated);
1052       }
1053       free_pool_memory(fname);
1054    }
1055 }