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