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