]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/backup.c
Fix #2940 Allow specific Director job code in WriteBootstrap directive
[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
360    /* TLS Requirement for the client */
361    if (jcr->client->tls_enable) {
362       if (jcr->client->tls_require) {
363          tls_need = BNET_TLS_REQUIRED;
364       } else {
365          tls_need = BNET_TLS_OK;
366       }
367    }
368    /*
369     * Send Client address to the SD
370     */
371    sd->fsend(clientaddr, jcr->client->address(), jcr->client->FDport, tls_need);
372    if (!response(jcr, sd, OKclient, "Client", DISPLAY_ERROR)) {
373       return false;
374    }
375    return true;
376 }
377
378 /*
379  * Allow to specify the address used by the Client to
380  * connect to the storage daemon in the Client resource
381  * or in the Storage resource.
382  */
383 char *get_storage_address(CLIENT *client, STORE *store)
384 {
385    char *store_address;
386
387    if (client && client->fd_storage_address) {
388       Dmsg0(10, "Using Client resource FD Storage Address to contact the Storage\n");
389       store_address = client->fd_storage_address;
390
391    } else if (store->fd_storage_address) {
392       Dmsg0(10, "Using Storage resource FD Storage Address to contact the Storage\n");
393       store_address = store->fd_storage_address;
394
395    } else {
396       Dmsg0(10, "Using default Storage address\n");
397       store_address = store->address;
398    }
399    return store_address;
400 }
401
402 bool run_storage_and_start_message_thread(JCR *jcr, BSOCK *sd)
403 {
404    /*
405     * Start the job prior to starting the message thread below
406     * to avoid two threads from using the BSOCK structure at
407     * the same time.
408     */
409    if (!sd->fsend("run")) {
410       return false;
411    }
412
413    /*
414     * Now start a Storage daemon message thread.  Note,
415     *   this thread is used to provide the catalog services
416     *   for the backup job, including inserting the attributes
417     *   into the catalog.  See catalog_update() in catreq.c
418     */
419    if (!start_storage_daemon_message_thread(jcr)) {
420       return false;
421    }
422    Dmsg0(150, "Storage daemon connection OK\n");
423    return true;
424 }
425
426 /*
427  * Do a backup of the specified FileSet
428  *
429  *  Returns:  false on failure
430  *            true  on success
431  */
432 bool do_backup(JCR *jcr)
433 {
434    int stat;
435    BSOCK   *fd, *sd;
436    STORE *store;
437    char *store_address;
438    uint32_t store_port;
439    char ed1[100];
440    db_int64_ctx job;
441    POOL_MEM buf;
442
443    if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
444       return do_vbackup(jcr);
445    }
446
447    /* Print Job Start message */
448    if (jcr->rerunning) {
449       Jmsg(jcr, M_INFO, 0, _("Restart Incomplete Backup JobId %s, Job=%s\n"),
450            edit_uint64(jcr->JobId, ed1), jcr->Job);
451    } else {
452       Jmsg(jcr, M_INFO, 0, _("Start Backup JobId %s, Job=%s\n"),
453            edit_uint64(jcr->JobId, ed1), jcr->Job);
454    }
455
456    jcr->setJobStatus(JS_Running);
457    Dmsg2(100, "JobId=%d JobLevel=%c\n", jcr->jr.JobId, jcr->jr.JobLevel);
458    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
459       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
460       return false;
461    }
462
463    /* For incomplete Jobs, we add our own id */
464    if (jcr->rerunning) {
465       edit_int64(jcr->JobId, ed1);
466       Mmsg(buf, "SELECT max(FileIndex) FROM File WHERE JobId=%s", ed1);
467       if (db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
468          Jmsg(jcr, M_INFO, 0, _("Found %ld files from prior incomplete Job.\n"),
469             (int32_t)job.value);
470       } else {
471          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
472          return false;
473       }
474       jcr->JobFiles = job.value;
475       Dmsg1(100, "==== FI=%ld\n", jcr->JobFiles);
476       Mmsg(buf, "SELECT VolSessionId FROM Job WHERE JobId=%s", ed1);
477       if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
478          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
479          return false;
480       }
481       jcr->VolSessionId = job.value;
482       Mmsg(buf, "SELECT VolSessionTime FROM Job WHERE JobId=%s", ed1);
483       if (!db_sql_query(jcr->db, buf.c_str(), db_int64_handler, &job)) {
484          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
485          return false;
486       }
487       jcr->VolSessionTime = job.value;
488       Dmsg4(100, "JobId=%s JobFiles=%ld VolSessionId=%ld VolSessionTime=%ld\n", ed1,
489             jcr->JobFiles, jcr->VolSessionId, jcr->VolSessionTime);
490    }
491
492    /*
493     * Open a message channel connection with the Storage
494     * daemon. This is to let him know that our client
495     * will be contacting him for a backup  session.
496     *
497     */
498    Dmsg0(110, "Open connection with storage daemon\n");
499    jcr->setJobStatus(JS_WaitSD);
500    /*
501     * Start conversation with Storage daemon
502     */
503    if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
504       return false;
505    }
506    /*
507     * Now start a job with the Storage daemon
508     */
509    if (!start_storage_daemon_job(jcr, NULL, jcr->wstorage)) {
510       return false;
511    }
512    sd = jcr->store_bsock;
513    if (jcr->client) {
514       jcr->sd_calls_client = jcr->client->sd_calls_client;
515    }
516    /*
517     * Note startup sequence of SD/FD is different depending on
518     *  whether the SD listens (normal) or the SD calls the FD.
519     */
520    if (!jcr->sd_calls_client) {
521       if (!run_storage_and_start_message_thread(jcr, sd)) {
522          goto bail_out;
523       }
524    }
525    jcr->setJobStatus(JS_WaitFD);
526    if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
527       goto bail_out;
528    }
529
530    jcr->setJobStatus(JS_Running);
531    fd = jcr->file_bsock;
532
533    if (!send_level_command(jcr)) {
534       goto bail_out;
535    }
536
537    if (!send_include_list(jcr)) {
538       goto bail_out;
539    }
540
541    if (!send_exclude_list(jcr)) {
542       goto bail_out;
543    }
544
545    /* TODO: See priority with bandwidth parameter */
546    if (jcr->job->max_bandwidth > 0) {
547       jcr->max_bandwidth = jcr->job->max_bandwidth;
548    } else if (jcr->client->max_bandwidth > 0) {
549       jcr->max_bandwidth = jcr->client->max_bandwidth;
550    }
551
552    if (jcr->max_bandwidth > 0) {
553       send_bwlimit(jcr, jcr->Job); /* Old clients don't have this command */
554    }
555
556    send_snapshot_retention(jcr, jcr->snapshot_retention);
557
558    store = jcr->wstore;
559
560    if (jcr->sd_calls_client) {
561       if (jcr->FDVersion < 10) {
562          Jmsg(jcr, M_FATAL, 0, _("The File daemon does not support SDCallsClient.\n"));
563          goto bail_out;
564       }
565       if (!send_client_addr_to_sd(jcr)) {
566          goto bail_out;
567       }
568
569       if (!run_storage_and_start_message_thread(jcr, sd)) {
570          goto bail_out;
571       }
572
573       store_address = jcr->wstore->address;  /* dummy */
574       store_port = 0;           /* flag that SD calls FD */
575    } else {
576       /*
577        * send Storage daemon address to the File daemon
578        */
579       if (store->SDDport == 0) {
580          store->SDDport = store->SDport;
581       }
582
583       store_address = get_storage_address(jcr->client, store);
584       store_port = store->SDDport;
585    }
586
587    if (!send_store_addr_to_fd(jcr, store, store_address, store_port)) {
588       goto bail_out;
589    }
590
591    /* Declare the job started to start the MaxRunTime check */
592    jcr->setJobStarted();
593
594    /* Send and run the RunBefore */
595    if (!send_runscripts_commands(jcr)) {
596       goto bail_out;
597    }
598
599    /*
600     * We re-update the job start record so that the start
601     *  time is set after the run before job.  This avoids
602     *  that any files created by the run before job will
603     *  be saved twice.  They will be backed up in the current
604     *  job, but not in the next one unless they are changed.
605     *  Without this, they will be backed up in this job and
606     *  in the next job run because in that case, their date
607     *   is after the start of this run.
608     */
609    jcr->start_time = time(NULL);
610    jcr->jr.StartTime = jcr->start_time;
611    if (!db_update_job_start_record(jcr, jcr->db, &jcr->jr)) {
612       Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
613    }
614
615    /*
616     * If backup is in accurate mode, we send the list of
617     * all files to FD.
618     */
619    if (!send_accurate_current_files(jcr)) {
620       goto bail_out;     /* error */
621    }
622
623    /* Send backup command */
624    fd->fsend(backupcmd, jcr->JobFiles);
625    Dmsg1(100, ">filed: %s", fd->msg);
626    if (!response(jcr, fd, OKbackup, "backup", DISPLAY_ERROR)) {
627       goto bail_out;
628    }
629
630    /* Pickup Job termination data */
631    stat = wait_for_job_termination(jcr);
632    db_write_batch_file_records(jcr);    /* used by bulk batch file insert */
633
634    if (jcr->HasBase) {
635       db_commit_base_file_attributes_record(jcr, jcr->db);
636       /* Any error already printed */
637    }
638
639    if (!jcr->is_canceled() && stat == JS_Terminated) {
640       backup_cleanup(jcr, stat);
641       return true;
642    }
643    return false;
644
645 /* Come here only after starting SD thread */
646 bail_out:
647    jcr->setJobStatus(JS_ErrorTerminated);
648    Dmsg1(400, "wait for sd. use=%d\n", jcr->use_count());
649    /* Cancel SD */
650    wait_for_job_termination(jcr, FDConnectTimeout);
651    Dmsg1(400, "after wait for sd. use=%d\n", jcr->use_count());
652    return false;
653 }
654
655
656 /*
657  * Here we wait for the File daemon to signal termination,
658  *   then we wait for the Storage daemon.  When both
659  *   are done, we return the job status.
660  * Also used by restore.c
661  */
662 int wait_for_job_termination(JCR *jcr, int timeout)
663 {
664    int32_t n = 0;
665    BSOCK *fd = jcr->file_bsock;
666    bool fd_ok = false;
667    uint32_t JobFiles, JobErrors;
668    uint32_t JobWarnings = 0;
669    uint64_t ReadBytes = 0;
670    uint64_t JobBytes = 0;
671    uint64_t CommBytes = 0;
672    uint64_t CommCompressedBytes = 0;
673    int VSS = 0;                 /* or Snapshot on Unix */
674    int Encrypt = 0;
675    btimer_t *tid=NULL;
676
677    if (fd) {
678       if (timeout) {
679          tid = start_bsock_timer(fd, timeout); /* TODO: New timeout directive??? */
680       }
681       /* Wait for Client to terminate */
682       while ((n = bget_dirmsg(fd)) >= 0) {
683          if (!fd_ok &&
684              (sscanf(fd->msg, newEndJob, &jcr->FDJobStatus, &JobFiles,
685                      &ReadBytes, &JobBytes, &JobErrors, &VSS, &Encrypt,
686                      &CommBytes, &CommCompressedBytes) == 9 ||
687               sscanf(fd->msg, EndJob, &jcr->FDJobStatus, &JobFiles,
688                      &ReadBytes, &JobBytes, &JobErrors, &VSS, &Encrypt) == 7 ||
689               sscanf(fd->msg, OldEndJob, &jcr->FDJobStatus, &JobFiles,
690                      &ReadBytes, &JobBytes, &JobErrors) == 5)) {
691             fd_ok = true;
692             jcr->setJobStatus(jcr->FDJobStatus);
693             Dmsg1(100, "FDStatus=%c\n", (char)jcr->JobStatus);
694          } else {
695             Jmsg(jcr, M_WARNING, 0, _("Unexpected Client Job message: %s\n"),
696                  fd->msg);
697          }
698          if (job_canceled(jcr)) {
699             break;
700          }
701       }
702       if (tid) {
703          stop_bsock_timer(tid);
704       }
705
706       if (fd->is_error() && jcr->getJobStatus() != JS_Canceled) {
707          int i = 0;
708          Jmsg(jcr, M_FATAL, 0, _("Network error with FD during %s: ERR=%s\n"),
709               job_type_to_str(jcr->getJobType()), fd->bstrerror());
710          while (i++ < 20 && jcr->job->RescheduleIncompleteJobs && jcr->is_canceled()) {
711             bmicrosleep(3, 0);
712          }
713       }
714       fd->signal(BNET_TERMINATE);   /* tell Client we are terminating */
715    }
716
717    /*
718     * Force cancel in SD if failing, but not for Incomplete jobs
719     *  so that we let the SD despool.
720     */
721    Dmsg5(100, "cancel=%d fd_ok=%d FDJS=%d JS=%d SDJS=%d\n", jcr->is_canceled(), fd_ok, jcr->FDJobStatus,
722         jcr->JobStatus, jcr->SDJobStatus);
723    if (jcr->is_canceled() || (!jcr->job->RescheduleIncompleteJobs && !fd_ok)) {
724       Dmsg4(100, "fd_ok=%d FDJS=%d JS=%d SDJS=%d\n", fd_ok, jcr->FDJobStatus,
725            jcr->JobStatus, jcr->SDJobStatus);
726       cancel_storage_daemon_job(jcr);
727    }
728
729    /* Note, the SD stores in jcr->JobFiles/ReadBytes/JobBytes/JobErrors */
730    wait_for_storage_daemon_termination(jcr);
731
732    /* Return values from FD */
733    if (fd_ok) {
734       jcr->JobFiles = JobFiles;
735       jcr->JobErrors += JobErrors;       /* Keep total errors */
736       jcr->ReadBytes = ReadBytes;
737       jcr->JobBytes = JobBytes;
738       jcr->JobWarnings = JobWarnings;
739       jcr->CommBytes = CommBytes;
740       jcr->CommCompressedBytes = CommCompressedBytes;
741       jcr->Snapshot = VSS;
742       jcr->Encrypt = Encrypt;
743    } else if (jcr->getJobStatus() != JS_Canceled) {
744       Jmsg(jcr, M_FATAL, 0, _("No Job status returned from FD.\n"));
745    }
746
747    /* Return the first error status we find Dir, FD, or SD */
748    if (!fd_ok || fd->is_error()) { /* if fd not set, that use !fd_ok */
749       if (jcr->getJobStatus() == JS_Canceled) {
750          jcr->FDJobStatus = JS_Canceled;
751       } else {
752          jcr->FDJobStatus = JS_ErrorTerminated;
753       }
754    }
755    if (jcr->JobStatus != JS_Terminated) {
756       return jcr->JobStatus;
757    }
758    if (jcr->FDJobStatus != JS_Terminated) {
759       return jcr->FDJobStatus;
760    }
761    return jcr->SDJobStatus;
762 }
763
764 /*
765  * Release resources allocated during backup.
766  */
767 void backup_cleanup(JCR *jcr, int TermCode)
768 {
769    char sdt[50], edt[50], schedt[50];
770    char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30];
771    char ec6[30], ec7[30], ec8[30], ec9[30], ec10[30], elapsed[50];
772    char data_compress[200], comm_compress[200];
773    char fd_term_msg[100], sd_term_msg[100];
774    POOL_MEM term_msg;
775    int msg_type = M_INFO;
776    MEDIA_DBR mr;
777    CLIENT_DBR cr;
778    double kbps, compression, ratio;
779    utime_t RunTime;
780    POOL_MEM base_info;
781    POOL_MEM vol_info;
782
783    remove_dummy_jobmedia_records(jcr);
784
785    if (jcr->is_JobLevel(L_VIRTUAL_FULL)) {
786       vbackup_cleanup(jcr, TermCode);
787       return;
788    }
789
790    Dmsg2(100, "Enter backup_cleanup %d %c\n", TermCode, TermCode);
791    memset(&cr, 0, sizeof(cr));
792
793 #ifdef xxxx
794    /* The current implementation of the JS_Warning status is not
795     * completed. SQL part looks to be ok, but the code is using
796     * JS_Terminated almost everywhere instead of (JS_Terminated || JS_Warning)
797     * as we do with is_canceled()
798     */
799    if (jcr->getJobStatus() == JS_Terminated &&
800         (jcr->JobErrors || jcr->SDErrors || jcr->JobWarnings)) {
801       TermCode = JS_Warnings;
802    }
803 #endif
804
805    update_job_end(jcr, TermCode);
806
807    if (!db_get_job_record(jcr, jcr->db, &jcr->jr)) {
808       Jmsg(jcr, M_WARNING, 0, _("Error getting Job record for Job report: ERR=%s"),
809          db_strerror(jcr->db));
810       jcr->setJobStatus(JS_ErrorTerminated);
811    }
812
813    bstrncpy(cr.Name, jcr->client->name(), sizeof(cr.Name));
814    if (!db_get_client_record(jcr, jcr->db, &cr)) {
815       Jmsg(jcr, M_WARNING, 0, _("Error getting Client record for Job report: ERR=%s"),
816          db_strerror(jcr->db));
817    }
818
819    bstrncpy(mr.VolumeName, jcr->VolumeName, sizeof(mr.VolumeName));
820    if (!db_get_media_record(jcr, jcr->db, &mr)) {
821       Jmsg(jcr, M_WARNING, 0, _("Error getting Media record for Volume \"%s\": ERR=%s"),
822          mr.VolumeName, db_strerror(jcr->db));
823       jcr->setJobStatus(JS_ErrorTerminated);
824    }
825
826    update_bootstrap_file(jcr);
827
828    switch (jcr->JobStatus) {
829       case JS_Terminated:
830          if (jcr->JobErrors || jcr->SDErrors) {
831             Mmsg(term_msg, _("Backup OK -- %s"), jcr->StatusErrMsg[0] ? jcr->StatusErrMsg : _("with warnings"));
832
833          } else {
834             Mmsg(term_msg, _("Backup OK"));
835          }
836          break;
837       case JS_Incomplete:
838          Mmsg(term_msg, _("Backup failed -- incomplete"));
839          break;
840       case JS_Warnings:
841          Mmsg(term_msg, _("Backup OK -- %s"), jcr->StatusErrMsg[0] ? jcr->StatusErrMsg : _("with warnings"));
842          break;
843       case JS_FatalError:
844       case JS_ErrorTerminated:
845          Mmsg(term_msg, _("*** Backup Error ***"));
846          msg_type = M_ERROR;          /* Generate error message */
847          if (jcr->store_bsock) {
848             jcr->store_bsock->signal(BNET_TERMINATE);
849             if (jcr->SD_msg_chan_started) {
850                pthread_cancel(jcr->SD_msg_chan);
851             }
852          }
853          break;
854       case JS_Canceled:
855          Mmsg(term_msg, _("Backup Canceled"));
856          if (jcr->store_bsock) {
857             jcr->store_bsock->signal(BNET_TERMINATE);
858             if (jcr->SD_msg_chan_started) {
859                pthread_cancel(jcr->SD_msg_chan);
860             }
861          }
862          break;
863       default:
864          Mmsg(term_msg, _("Inappropriate term code: %c\n"), jcr->JobStatus);
865          break;
866    }
867    bstrftimes(schedt, sizeof(schedt), jcr->jr.SchedTime);
868    bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
869    bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
870    RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
871    if (RunTime <= 0) {
872       RunTime = 1;
873    }
874    kbps = ((double)jcr->jr.JobBytes) / (1000.0 * (double)RunTime);
875    if (!db_get_job_volume_names(jcr, jcr->db, jcr->jr.JobId, &jcr->VolumeName)) {
876       /*
877        * Note, if the job has erred, most likely it did not write any
878        *  tape, so suppress this "error" message since in that case
879        *  it is normal.  Or look at it the other way, only for a
880        *  normal exit should we complain about this error.
881        */
882       if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes) {
883          Jmsg(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db));
884       }
885       jcr->VolumeName[0] = 0;         /* none */
886    }
887
888    if (jcr->ReadBytes == 0) {
889       bstrncpy(data_compress, "None", sizeof(data_compress));
890    } else {
891       compression = (double)100 - 100.0 * ((double)jcr->SDJobBytes / (double)jcr->ReadBytes);
892       if (compression < 0.5) {
893          bstrncpy(data_compress, "None", sizeof(data_compress));
894       } else {
895          if (jcr->SDJobBytes > 0) {
896             ratio = (double)jcr->ReadBytes / (double)jcr->SDJobBytes;
897          } else {
898             ratio = 1.0;
899          }
900          bsnprintf(data_compress, sizeof(data_compress), "%.1f%% %.1f:1",
901             compression, ratio);
902       }
903    }
904    if (jcr->CommBytes == 0 || jcr->CommCompressedBytes == 0) {
905       bstrncpy(comm_compress, "None", sizeof(comm_compress));
906    } else {
907       compression = (double)100 - 100.0 * ((double)jcr->CommCompressedBytes / (double)jcr->CommBytes);
908       if (compression < 0.5) {
909          bstrncpy(comm_compress, "None", sizeof(comm_compress));
910       } else {
911          ratio = (double)jcr->CommBytes / (double)jcr->CommCompressedBytes;
912          bsnprintf(comm_compress, sizeof(comm_compress), "%.1f%% %.1f:1",
913             compression, ratio);
914       }
915       Dmsg2(200, "=== CommCompressed=%lld CommBytes=%lld\n",
916          jcr->CommCompressedBytes, jcr->CommBytes);
917    }
918    jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
919    jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
920
921    if (jcr->HasBase) {
922       Mmsg(base_info, _("  Base files/Used files:  %lld/%lld (%.2f%%)\n"),
923            jcr->nb_base_files,
924            jcr->nb_base_files_used,
925            jcr->nb_base_files_used*100.0/jcr->nb_base_files);
926    }
927    /* Edit string for last volume size */
928    if (mr.VolABytes != 0) {
929       Mmsg(vol_info, _("meta: %s (%sB) aligned: %s (%sB)"),
930         edit_uint64_with_commas(mr.VolBytes, ec7),
931         edit_uint64_with_suffix(mr.VolBytes, ec8),
932         edit_uint64_with_commas(mr.VolABytes, ec9),
933         edit_uint64_with_suffix(mr.VolABytes, ec10));
934    } else {
935      Mmsg(vol_info, _("%s (%sB)"),
936         edit_uint64_with_commas(mr.VolBytes, ec7),
937         edit_uint64_with_suffix(mr.VolBytes, ec8));
938    }
939
940 // bmicrosleep(15, 0);                /* for debugging SIGHUP */
941
942    Jmsg(jcr, msg_type, 0, _("%s %s %s (%s):\n"
943 "  Build OS:               %s %s %s\n"
944 "  JobId:                  %d\n"
945 "  Job:                    %s\n"
946 "  Backup Level:           %s%s\n"
947 "  Client:                 \"%s\" %s\n"
948 "  FileSet:                \"%s\" %s\n"
949 "  Pool:                   \"%s\" (From %s)\n"
950 "  Catalog:                \"%s\" (From %s)\n"
951 "  Storage:                \"%s\" (From %s)\n"
952 "  Scheduled time:         %s\n"
953 "  Start time:             %s\n"
954 "  End time:               %s\n"
955 "  Elapsed time:           %s\n"
956 "  Priority:               %d\n"
957 "  FD Files Written:       %s\n"
958 "  SD Files Written:       %s\n"
959 "  FD Bytes Written:       %s (%sB)\n"
960 "  SD Bytes Written:       %s (%sB)\n"
961 "  Rate:                   %.1f KB/s\n"
962 "  Software Compression:   %s\n"
963 "  Comm Line Compression:  %s\n"
964 "%s"                                         /* Basefile info */
965 "  Snapshot/VSS:           %s\n"
966 "  Encryption:             %s\n"
967 "  Accurate:               %s\n"
968 "  Volume name(s):         %s\n"
969 "  Volume Session Id:      %d\n"
970 "  Volume Session Time:    %d\n"
971 "  Last Volume Bytes:      %s\n"
972 "  Non-fatal FD errors:    %d\n"
973 "  SD Errors:              %d\n"
974 "  FD termination status:  %s\n"
975 "  SD termination status:  %s\n"
976 "  Termination:            %s\n\n"),
977         BACULA, my_name, VERSION, LSMDATE,
978         HOST_OS, DISTNAME, DISTVER,
979         jcr->jr.JobId,
980         jcr->jr.Job,
981         level_to_str(jcr->getJobLevel()), jcr->since,
982         jcr->client->name(), cr.Uname,
983         jcr->fileset->name(), jcr->FSCreateTime,
984         jcr->pool->name(), jcr->pool_source,
985         jcr->catalog->name(), jcr->catalog_source,
986         jcr->wstore->name(), jcr->wstore_source,
987         schedt,
988         sdt,
989         edt,
990         edit_utime(RunTime, elapsed, sizeof(elapsed)),
991         jcr->JobPriority,
992         edit_uint64_with_commas(jcr->jr.JobFiles, ec1),
993         edit_uint64_with_commas(jcr->SDJobFiles, ec2),
994         edit_uint64_with_commas(jcr->jr.JobBytes, ec3),
995         edit_uint64_with_suffix(jcr->jr.JobBytes, ec4),
996         edit_uint64_with_commas(jcr->SDJobBytes, ec5),
997         edit_uint64_with_suffix(jcr->SDJobBytes, ec6),
998         kbps,
999         data_compress,
1000         comm_compress,
1001         base_info.c_str(),
1002         jcr->Snapshot?_("yes"):_("no"),
1003         jcr->Encrypt?_("yes"):_("no"),
1004         jcr->accurate?_("yes"):_("no"),
1005         jcr->VolumeName,
1006         jcr->VolSessionId,
1007         jcr->VolSessionTime,
1008         vol_info.c_str(),
1009         jcr->JobErrors,
1010         jcr->SDErrors,
1011         fd_term_msg,
1012         sd_term_msg,
1013         term_msg.c_str());
1014
1015    Dmsg0(100, "Leave backup_cleanup()\n");
1016 }
1017
1018 void update_bootstrap_file(JCR *jcr)
1019 {
1020    /* Now update the bootstrap file if any */
1021    if (jcr->JobStatus == JS_Terminated && jcr->jr.JobBytes &&
1022        jcr->job->WriteBootstrap) {
1023       FILE *fd;
1024       BPIPE *bpipe = NULL;
1025       int got_pipe = 0;
1026       POOLMEM *fname = get_pool_memory(PM_FNAME);
1027       fname = edit_job_codes(jcr, fname, jcr->job->WriteBootstrap, "",
1028                              job_code_callback_director);
1029
1030       VOL_PARAMS *VolParams = NULL;
1031       int VolCount;
1032       char edt[50], ed1[50], ed2[50];
1033
1034       if (*fname == '|') {
1035          got_pipe = 1;
1036          bpipe = open_bpipe(fname+1, 0, "w"); /* skip first char "|" */
1037          fd = bpipe ? bpipe->wfd : NULL;
1038       } else {
1039          /* ***FIXME*** handle BASE */
1040          fd = bfopen(fname, jcr->is_JobLevel(L_FULL)?"w+b":"a+b");
1041       }
1042       if (fd) {
1043          VolCount = db_get_job_volume_parameters(jcr, jcr->db, jcr->JobId,
1044                     &VolParams);
1045          if (VolCount == 0) {
1046             Jmsg(jcr, M_ERROR, 0, _("Could not get Job Volume Parameters to "
1047                  "update Bootstrap file. ERR=%s\n"), db_strerror(jcr->db));
1048              if (jcr->SDJobFiles != 0) {
1049                 jcr->setJobStatus(JS_ErrorTerminated);
1050              }
1051
1052          }
1053          /* Start output with when and who wrote it */
1054          bstrftimes(edt, sizeof(edt), time(NULL));
1055          fprintf(fd, "# %s - %s - %s%s\n", edt, jcr->jr.Job,
1056                  level_to_str(jcr->getJobLevel()), jcr->since);
1057          for (int i=0; i < VolCount; i++) {
1058             /* Write the record */
1059             fprintf(fd, "Volume=\"%s\"\n", VolParams[i].VolumeName);
1060             fprintf(fd, "MediaType=\"%s\"\n", VolParams[i].MediaType);
1061             if (VolParams[i].Slot > 0) {
1062                fprintf(fd, "Slot=%d\n", VolParams[i].Slot);
1063             }
1064             fprintf(fd, "VolSessionId=%u\n", jcr->VolSessionId);
1065             fprintf(fd, "VolSessionTime=%u\n", jcr->VolSessionTime);
1066             fprintf(fd, "VolAddr=%s-%s\n",
1067                     edit_uint64(VolParams[i].StartAddr, ed1),
1068                     edit_uint64(VolParams[i].EndAddr, ed2));
1069             fprintf(fd, "FileIndex=%d-%d\n", VolParams[i].FirstIndex,
1070                          VolParams[i].LastIndex);
1071          }
1072          if (VolParams) {
1073             free(VolParams);
1074          }
1075          if (got_pipe) {
1076             close_bpipe(bpipe);
1077          } else {
1078             fclose(fd);
1079          }
1080       } else {
1081          berrno be;
1082          Jmsg(jcr, M_ERROR, 0, _("Could not open WriteBootstrap file:\n"
1083               "%s: ERR=%s\n"), fname, be.bstrerror());
1084          jcr->setJobStatus(JS_ErrorTerminated);
1085       }
1086       free_pool_memory(fname);
1087    }
1088 }