]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_output.c
1afe0484f1ef3a056572d98571e7701beace28ce
[bacula/bacula] / bacula / src / dird / ua_output.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *   Bacula Director -- User Agent Output Commands
31  *     I.e. messages, listing database, showing resources, ...
32  *
33  *     Kern Sibbald, September MM
34  *
35  *   Version $Id$
36  */
37
38 #include "bacula.h"
39 #include "dird.h"
40
41 /* Imported subroutines */
42
43 /* Imported variables */
44
45 /* Imported functions */
46
47 /* Forward referenced functions */
48 static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist);
49 static bool list_nextvol(UAContext *ua, int ndays);
50
51 /*
52  * Turn auto display of console messages on/off
53  */
54 int autodisplay_cmd(UAContext *ua, const char *cmd)
55 {
56    static const char *kw[] = {
57       NT_("on"),
58       NT_("off"),
59       NULL};
60
61    switch (find_arg_keyword(ua, kw)) {
62    case 0:
63       ua->auto_display_messages = true;
64       break;
65    case 1:
66       ua->auto_display_messages = false;
67       break;
68    default:
69       ua->error_msg(_("ON or OFF keyword missing.\n"));
70       break;
71    }
72    return 1;
73 }
74
75 /*
76  * Turn GUI mode on/off
77  */
78 int gui_cmd(UAContext *ua, const char *cmd)
79 {
80    static const char *kw[] = {
81       NT_("on"),
82       NT_("off"),
83       NULL};
84
85    switch (find_arg_keyword(ua, kw)) {
86    case 0:
87       ua->jcr->gui = ua->gui = true;
88       break;
89    case 1:
90       ua->jcr->gui = ua->gui = false;
91       break;
92    default:
93       ua->error_msg(_("ON or OFF keyword missing.\n"));
94       break;
95    }
96    return 1;
97 }
98
99
100
101 struct showstruct {const char *res_name; int type;};
102 static struct showstruct reses[] = {
103    {NT_("directors"),  R_DIRECTOR},
104    {NT_("clients"),    R_CLIENT},
105    {NT_("counters"),   R_COUNTER},
106    {NT_("devices"),    R_DEVICE},
107    {NT_("jobs"),       R_JOB},
108    {NT_("storages"),   R_STORAGE},
109    {NT_("catalogs"),   R_CATALOG},
110    {NT_("schedules"),  R_SCHEDULE},
111    {NT_("filesets"),   R_FILESET},
112    {NT_("pools"),      R_POOL},
113    {NT_("messages"),   R_MSGS},
114    {NT_("all"),        -1},
115    {NT_("help"),       -2},
116    {NULL,           0}
117 };
118
119
120 /*
121  *  Displays Resources
122  *
123  *  show all
124  *  show <resource-keyword-name>  e.g. show directors
125  *  show <resource-keyword-name>=<name> e.g. show director=HeadMan
126  *
127  */
128 int show_cmd(UAContext *ua, const char *cmd)
129 {
130    int i, j, type, len;
131    int recurse;
132    char *res_name;
133    RES *res = NULL;
134
135    Dmsg1(20, "show: %s\n", ua->UA_sock->msg);
136
137
138    LockRes();
139    for (i=1; i<ua->argc; i++) {
140       type = 0;
141       res_name = ua->argk[i];
142       if (!ua->argv[i]) {             /* was a name given? */
143          /* No name, dump all resources of specified type */
144          recurse = 1;
145          len = strlen(res_name);
146          for (j=0; reses[j].res_name; j++) {
147             if (strncasecmp(res_name, _(reses[j].res_name), len) == 0) {
148                type = reses[j].type;
149                if (type > 0) {
150                   res = res_head[type-r_first];
151                } else {
152                   res = NULL;
153                }
154                break;
155             }
156          }
157
158       } else {
159          /* Dump a single resource with specified name */
160          recurse = 0;
161          len = strlen(res_name);
162          for (j=0; reses[j].res_name; j++) {
163             if (strncasecmp(res_name, _(reses[j].res_name), len) == 0) {
164                type = reses[j].type;
165                res = (RES *)GetResWithName(type, ua->argv[i]);
166                if (!res) {
167                   type = -3;
168                }
169                break;
170             }
171          }
172       }
173
174       switch (type) {
175       case -1:                           /* all */
176          for (j=r_first; j<=r_last; j++) {
177             dump_resource(j, res_head[j-r_first], bsendmsg, ua);
178          }
179          break;
180       case -2:
181          ua->send_msg(_("Keywords for the show command are:\n"));
182          for (j=0; reses[j].res_name; j++) {
183             ua->error_msg("%s\n", _(reses[j].res_name));
184          }
185          goto bail_out;
186       case -3:
187          ua->error_msg(_("%s resource %s not found.\n"), res_name, ua->argv[i]);
188          goto bail_out;
189       case 0:
190          ua->error_msg(_("Resource %s not found\n"), res_name);
191          goto bail_out;
192       default:
193          dump_resource(recurse?type:-type, res, bsendmsg, ua);
194          break;
195       }
196    }
197 bail_out:
198    UnlockRes();
199    return 1;
200 }
201
202
203
204
205 /*
206  *  List contents of database
207  *
208  *  list jobs           - lists all jobs run
209  *  list jobid=nnn      - list job data for jobid
210  *  list ujobid=uname   - list job data for unique jobid
211  *  list job=name       - list all jobs with "name"   
212  *  list jobname=name   - same as above 
213  *  list jobmedia jobid=<nn>
214  *  list jobmedia job=name
215  *  list joblog jobid=<nn>
216  *  list joblog job=name
217  *  list files jobid=<nn> - list files saved for job nn
218  *  list files job=name
219  *  list pools          - list pool records
220  *  list jobtotals      - list totals for all jobs
221  *  list media          - list media for given pool (deprecated)
222  *  list volumes        - list Volumes
223  *  list clients        - list clients
224  *  list nextvol job=xx  - list the next vol to be used by job
225  *  list nextvolume job=xx - same as above.
226  *
227  */
228
229 /* Do long or full listing */
230 int llist_cmd(UAContext *ua, const char *cmd)
231 {
232    return do_list_cmd(ua, cmd, VERT_LIST);
233 }
234
235 /* Do short or summary listing */
236 int list_cmd(UAContext *ua, const char *cmd)
237 {
238    return do_list_cmd(ua, cmd, HORZ_LIST);
239 }
240
241 static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
242 {
243    POOLMEM *VolumeName;
244    int jobid, n;
245    int i, j;
246    JOB_DBR jr;
247    POOL_DBR pr;
248    MEDIA_DBR mr;
249
250    if (!open_client_db(ua))
251       return 1;
252
253    memset(&jr, 0, sizeof(jr));
254    memset(&pr, 0, sizeof(pr));
255    memset(&mr, 0, sizeof(mr));
256
257    Dmsg1(20, "list: %s\n", cmd);
258
259    if (!ua->db) {
260       ua->error_msg(_("Hey! DB is NULL\n"));
261    }
262
263    /* Scan arguments looking for things to do */
264    for (i=1; i<ua->argc; i++) {
265       /* List JOBS */
266       if (strcasecmp(ua->argk[i], NT_("jobs")) == 0) {
267          /* Apply any limit */
268          j = find_arg_with_value(ua, NT_("limit"));
269          if (j >= 0) {
270             jr.limit = atoi(ua->argv[j]);
271          }
272          db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
273
274          /* List JOBTOTALS */
275       } else if (strcasecmp(ua->argk[i], NT_("jobtotals")) == 0) {
276          db_list_job_totals(ua->jcr, ua->db, &jr, prtit, ua);
277
278       /* List JOBID=nn */
279       } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
280          if (ua->argv[i]) {
281             jobid = str_to_int64(ua->argv[i]);
282             if (jobid > 0) {
283                jr.JobId = jobid;
284                db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
285             }
286          }
287
288       /* List JOB=xxx */
289       } else if ((strcasecmp(ua->argk[i], NT_("job")) == 0 ||
290                   strcasecmp(ua->argk[i], NT_("jobname")) == 0) && ua->argv[i]) {
291          bstrncpy(jr.Name, ua->argv[i], MAX_NAME_LENGTH);
292          jr.JobId = 0;
293          db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
294
295       /* List UJOBID=xxx */
296       } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
297          bstrncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
298          jr.JobId = 0;
299          db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
300
301       /* List FILES */
302       } else if (strcasecmp(ua->argk[i], NT_("files")) == 0) {
303
304          for (j=i+1; j<ua->argc; j++) {
305             if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
306                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
307                jr.JobId = 0;
308                db_get_job_record(ua->jcr, ua->db, &jr);
309                jobid = jr.JobId;
310             } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
311                jobid = str_to_int64(ua->argv[j]);
312             } else {
313                continue;
314             }
315             if (jobid > 0) {
316                db_list_files_for_job(ua->jcr, ua->db, jobid, prtit, ua);
317             }
318          }
319
320       /* List JOBMEDIA */
321       } else if (strcasecmp(ua->argk[i], NT_("jobmedia")) == 0) {
322          int done = FALSE;
323          for (j=i+1; j<ua->argc; j++) {
324             if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
325                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
326                jr.JobId = 0;
327                db_get_job_record(ua->jcr, ua->db, &jr);
328                jobid = jr.JobId;
329             } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
330                jobid = str_to_int64(ua->argv[j]);
331             } else {
332                continue;
333             }
334             db_list_jobmedia_records(ua->jcr, ua->db, jobid, prtit, ua, llist);
335             done = TRUE;
336          }
337          if (!done) {
338             /* List for all jobs (jobid=0) */
339             db_list_jobmedia_records(ua->jcr, ua->db, 0, prtit, ua, llist);
340          }
341
342       /* List JOBLOG */
343       } else if (strcasecmp(ua->argk[i], NT_("joblog")) == 0) {
344          int done = FALSE;
345          for (j=i+1; j<ua->argc; j++) {
346             if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
347                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
348                jr.JobId = 0;
349                db_get_job_record(ua->jcr, ua->db, &jr);
350                jobid = jr.JobId;
351             } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
352                jobid = str_to_int64(ua->argv[j]);
353             } else {
354                continue;
355             }
356             db_list_joblog_records(ua->jcr, ua->db, jobid, prtit, ua, llist);
357             done = TRUE;
358          }
359          if (!done) {
360             /* List for all jobs (jobid=0) */
361             db_list_joblog_records(ua->jcr, ua->db, 0, prtit, ua, llist);
362          }
363
364
365       /* List POOLS */
366       } else if (strcasecmp(ua->argk[i], NT_("pool")) == 0 ||
367                  strcasecmp(ua->argk[i], NT_("pools")) == 0) {
368          POOL_DBR pr;
369          memset(&pr, 0, sizeof(pr));
370          if (ua->argv[i]) {
371             bstrncpy(pr.Name, ua->argv[i], sizeof(pr.Name));
372          }
373          db_list_pool_records(ua->jcr, ua->db, &pr, prtit, ua, llist);
374
375       } else if (strcasecmp(ua->argk[i], NT_("clients")) == 0) {
376          db_list_client_records(ua->jcr, ua->db, prtit, ua, llist);
377
378
379       /* List MEDIA or VOLUMES */
380       } else if (strcasecmp(ua->argk[i], NT_("media")) == 0 ||
381                  strcasecmp(ua->argk[i], NT_("volume")) == 0 ||
382                  strcasecmp(ua->argk[i], NT_("volumes")) == 0) {
383          bool done = false;
384          for (j=i+1; j<ua->argc; j++) {
385             if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
386                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
387                jr.JobId = 0;
388                db_get_job_record(ua->jcr, ua->db, &jr);
389                jobid = jr.JobId;
390             } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
391                jobid = str_to_int64(ua->argv[j]);
392             } else {
393                continue;
394             }
395             VolumeName = get_pool_memory(PM_FNAME);
396             n = db_get_job_volume_names(ua->jcr, ua->db, jobid, &VolumeName);
397             ua->send_msg(_("Jobid %d used %d Volume(s): %s\n"), jobid, n, VolumeName);
398             free_pool_memory(VolumeName);
399             done = true;
400          }
401          /* if no job or jobid keyword found, then we list all media */
402          if (!done) {
403             int num_pools;
404             uint32_t *ids;
405             /* List a specific volume? */
406             if (ua->argv[i]) {
407                bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName));
408                db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
409                return 1;
410             }
411             /* Is a specific pool wanted? */
412             for (i=1; i<ua->argc; i++) {
413                if (strcasecmp(ua->argk[i], NT_("pool")) == 0) {
414                   if (!get_pool_dbr(ua, &pr)) {
415                      ua->error_msg(_("No Pool specified.\n"));
416                      return 1;
417                   }
418                   mr.PoolId = pr.PoolId;
419                   db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
420                   return 1;
421                }
422             }
423
424             /* List Volumes in all pools */
425             if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
426                ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"),
427                         db_strerror(ua->db));
428                return 1;
429             }
430             if (num_pools <= 0) {
431                return 1;
432             }
433             for (i=0; i < num_pools; i++) {
434                pr.PoolId = ids[i];
435                if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
436                   ua->send_msg(_("Pool: %s\n"), pr.Name);
437                }
438                mr.PoolId = ids[i];
439                db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
440             }
441             free(ids);
442             return 1;
443          }
444       /* List next volume */
445       } else if (strcasecmp(ua->argk[i], NT_("nextvol")) == 0 ||
446                  strcasecmp(ua->argk[i], NT_("nextvolume")) == 0) {
447          n = 1;
448          j = find_arg_with_value(ua, NT_("days"));
449          if (j >= 0) {
450             n = atoi(ua->argv[j]);
451             if ((n < 0) || (n > 50)) {
452               ua->warning_msg(_("Ignoring invalid value for days. Max is 50.\n"));
453               n = 1;
454             }
455          }
456          list_nextvol(ua, n);
457       } else if (strcasecmp(ua->argk[i], NT_("limit")) == 0
458                  || strcasecmp(ua->argk[i], NT_("days")) == 0) {
459          /* Ignore it */
460       } else {
461          ua->error_msg(_("Unknown list keyword: %s\n"), NPRT(ua->argk[i]));
462       }
463    }
464    return 1;
465 }
466
467 static bool list_nextvol(UAContext *ua, int ndays)
468 {
469    JOB *job;
470    JCR *jcr;          
471    USTORE store;
472    RUN *run;
473    utime_t runtime;
474    bool found = false;
475    MEDIA_DBR mr;
476    POOL_DBR pr;
477
478    memset(&mr, 0, sizeof(mr));
479    int i = find_arg_with_value(ua, "job");
480    if (i <= 0) {
481       if ((job = select_job_resource(ua)) == NULL) {
482          return false;
483       }
484    } else {
485       job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
486       if (!job) {
487          Jmsg(ua->jcr, M_ERROR, 0, _("%s is not a job name.\n"), ua->argv[i]);
488          if ((job = select_job_resource(ua)) == NULL) {
489             return false;
490          }
491       }
492    }
493
494    jcr = new_jcr(sizeof(JCR), dird_free_jcr);
495    for (run=NULL; (run = find_next_run(run, job, runtime, ndays)); ) {
496       if (!complete_jcr_for_job(jcr, job, run->pool)) {
497          found = false;
498          goto get_out;
499       }
500       if (!jcr->jr.PoolId) {
501          ua->error_msg(_("Could not find Pool for Job %s\n"), job->name());
502          continue;
503       }
504       memset(&pr, 0, sizeof(pr));
505       pr.PoolId = jcr->jr.PoolId;
506       if (!db_get_pool_record(jcr, jcr->db, &pr)) {
507          bstrncpy(pr.Name, "*UnknownPool*", sizeof(pr.Name));
508       }
509       mr.PoolId = jcr->jr.PoolId;
510       get_job_storage(&store, job, run);
511       mr.StorageId = store.store->StorageId;
512       if (!find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_prune)) {
513          ua->error_msg(_("Could not find next Volume for Job %s (Pool=%s, Level=%s).\n"),
514             job->name(), pr.Name, level_to_str(run->level));
515       } else {
516          ua->send_msg(
517             _("The next Volume to be used by Job \"%s\" (Pool=%s, Level=%s) will be %s\n"),
518             job->name(), pr.Name, level_to_str(run->level), mr.VolumeName);
519          found = true;
520       }
521    }
522
523 get_out:
524    db_close_database(jcr, jcr->db);
525    jcr->db = NULL;
526    free_jcr(jcr);
527    if (!found) {
528       ua->error_msg(_("Could not find next Volume for Job %s.\n"),
529          job->hdr.name);
530       return false;
531    }
532    return true;
533 }
534
535
536 /*
537  * For a given job, we examine all his run records
538  *  to see if it is scheduled today or tomorrow.
539  */
540 RUN *find_next_run(RUN *run, JOB *job, utime_t &runtime, int ndays)
541 {
542    time_t now, future, endtime;
543    SCHED *sched;
544    struct tm tm, runtm;
545    int mday, wday, month, wom, i;
546    int woy;
547    int day;
548    int is_scheduled;
549
550    sched = job->schedule;
551    if (sched == NULL) {            /* scheduled? */
552       return NULL;                 /* no nothing to report */
553    }
554
555    /* Break down the time into components */
556    now = time(NULL);
557    endtime = now + (ndays * 60 * 60 * 24);
558
559    if (run == NULL) {
560       run = sched->run;
561    } else {
562       run = run->next;
563    }
564    for ( ; run; run=run->next) {
565       /*
566        * Find runs in next 24 hours.  Day 0 is today, so if
567        *   ndays=1, look at today and tomorrow.
568        */
569       for (day = 0; day <= ndays; day++) {
570          future = now + (day * 60 * 60 * 24);
571
572          /* Break down the time into components */
573          (void)localtime_r(&future, &tm);
574          mday = tm.tm_mday - 1;
575          wday = tm.tm_wday;
576          month = tm.tm_mon;
577          wom = mday / 7;
578          woy = tm_woy(future);
579
580          is_scheduled = bit_is_set(mday, run->mday) && bit_is_set(wday, run->wday) &&
581             bit_is_set(month, run->month) && bit_is_set(wom, run->wom) &&
582             bit_is_set(woy, run->woy);
583  
584 #ifdef xxx
585          Pmsg2(000, "day=%d is_scheduled=%d\n", day, is_scheduled);
586          Pmsg1(000, "bit_set_mday=%d\n", bit_is_set(mday, run->mday));
587          Pmsg1(000, "bit_set_wday=%d\n", bit_is_set(wday, run->wday));
588          Pmsg1(000, "bit_set_month=%d\n", bit_is_set(month, run->month));
589          Pmsg1(000, "bit_set_wom=%d\n", bit_is_set(wom, run->wom));
590          Pmsg1(000, "bit_set_woy=%d\n", bit_is_set(woy, run->woy));
591 #endif
592
593          if (is_scheduled) { /* Jobs scheduled on that day */
594 #ifdef xxx
595             char buf[300], num[10];
596             bsnprintf(buf, sizeof(buf), "tm.hour=%d hour=", tm.tm_hour);
597             for (i=0; i<24; i++) {
598                if (bit_is_set(i, run->hour)) {
599                   bsnprintf(num, sizeof(num), "%d ", i);
600                   bstrncat(buf, num, sizeof(buf));
601                }
602             }
603             bstrncat(buf, "\n", sizeof(buf));
604             Pmsg1(000, "%s", buf);
605 #endif
606             /* find time (time_t) job is to be run */
607             (void)localtime_r(&future, &runtm);
608             for (i= 0; i < 24; i++) {
609                if (bit_is_set(i, run->hour)) {
610                   runtm.tm_hour = i;
611                   runtm.tm_min = run->minute;
612                   runtm.tm_sec = 0;
613                   runtime = mktime(&runtm);
614                   Dmsg2(200, "now=%d runtime=%lld\n", now, runtime);
615                   if ((runtime > now) && (runtime < endtime)) {
616                      Dmsg2(200, "Found it level=%d %c\n", run->level, run->level);
617                      return run;         /* found it, return run resource */
618                   }
619                }
620             }
621          }
622       }
623    } /* end for loop over runs */
624    /* Nothing found */
625    return NULL;
626 }
627
628 /*
629  * Fill in the remaining fields of the jcr as if it
630  *  is going to run the job.
631  */
632 bool complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool)
633 {
634    POOL_DBR pr;
635
636    memset(&pr, 0, sizeof(POOL_DBR));
637    set_jcr_defaults(jcr, job);
638    if (pool) {
639       jcr->pool = pool;               /* override */
640    }
641    if (jcr->db) {
642       Dmsg0(100, "complete_jcr close db\n");
643       db_close_database(jcr, jcr->db);
644       jcr->db = NULL;
645    }
646
647    Dmsg0(100, "complete_jcr open db\n");
648    jcr->db = jcr->db=db_init(jcr, jcr->catalog->db_driver, jcr->catalog->db_name, 
649                       jcr->catalog->db_user,
650                       jcr->catalog->db_password, jcr->catalog->db_address,
651                       jcr->catalog->db_port, jcr->catalog->db_socket,
652                       jcr->catalog->mult_db_connections);
653    if (!jcr->db || !db_open_database(jcr, jcr->db)) {
654       Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
655                  jcr->catalog->db_name);
656       if (jcr->db) {
657          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
658          db_close_database(jcr, jcr->db);
659          jcr->db = NULL;
660       }
661       return false;
662    }
663    bstrncpy(pr.Name, jcr->pool->name(), sizeof(pr.Name));
664    while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
665       /* Try to create the pool */
666       if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
667          Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
668             db_strerror(jcr->db));
669          if (jcr->db) {
670             db_close_database(jcr, jcr->db);
671             jcr->db = NULL;
672          }
673          return false;
674       } else {
675          Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
676       }
677    }
678    jcr->jr.PoolId = pr.PoolId;
679    return true;
680 }
681
682
683 static void con_lock_release(void *arg)
684 {
685    Vw(con_lock);
686 }
687
688 void do_messages(UAContext *ua, const char *cmd)
689 {
690    char msg[2000];
691    int mlen;
692    bool do_truncate = false;
693
694    Pw(con_lock);
695    pthread_cleanup_push(con_lock_release, (void *)NULL);
696    rewind(con_fd);
697    while (fgets(msg, sizeof(msg), con_fd)) {
698       mlen = strlen(msg);
699       ua->UA_sock->msg = check_pool_memory_size(ua->UA_sock->msg, mlen+1);
700       strcpy(ua->UA_sock->msg, msg);
701       ua->UA_sock->msglen = mlen;
702       ua->UA_sock->send();
703       do_truncate = true;
704    }
705    if (do_truncate) {
706       (void)ftruncate(fileno(con_fd), 0L);
707    }
708    console_msg_pending = FALSE;
709    ua->user_notified_msg_pending = FALSE;
710    pthread_cleanup_pop(0);
711    Vw(con_lock);
712 }
713
714
715 int qmessagescmd(UAContext *ua, const char *cmd)
716 {
717    if (console_msg_pending && ua->auto_display_messages) {
718       do_messages(ua, cmd);
719    }
720    return 1;
721 }
722
723 int messagescmd(UAContext *ua, const char *cmd)
724 {
725    if (console_msg_pending) {
726       do_messages(ua, cmd);
727    } else {
728       ua->UA_sock->fsend(_("You have no messages.\n"));
729    }
730    return 1;
731 }
732
733 /*
734  * Callback routine for "printing" database file listing
735  */
736 void prtit(void *ctx, const char *msg)
737 {
738    UAContext *ua = (UAContext *)ctx;
739
740    ua->UA_sock->fsend("%s", msg);
741 }
742
743 /*
744  * Format message and send to other end.
745
746  * If the UA_sock is NULL, it means that there is no user
747  * agent, so we are being called from Bacula core. In
748  * that case direct the messages to the Job.
749  */
750 #ifdef HAVE_VA_COPY
751 void bmsg(UAContext *ua, const char *fmt, va_list arg_ptr)
752 {
753    BSOCK *bs = ua->UA_sock;
754    int maxlen, len;
755    POOLMEM *msg = NULL;
756    va_list ap;
757
758    if (bs) {
759       msg = bs->msg;
760    }
761    if (!msg) {
762       msg = get_pool_memory(PM_EMSG);
763    }
764
765 again:
766    maxlen = sizeof_pool_memory(msg) - 1;
767    va_copy(ap, arg_ptr);
768    len = bvsnprintf(msg, maxlen, fmt, ap);
769    va_end(ap);
770    if (len < 0 || len >= maxlen) {
771       msg = realloc_pool_memory(msg, maxlen + maxlen/2);
772       goto again;
773    }
774
775    if (bs) {
776       bs->msg = msg;
777       bs->msglen = len;
778       bs->send();
779    } else {                           /* No UA, send to Job */
780       Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
781       free_pool_memory(msg);
782    }
783
784 }
785
786 #else /* no va_copy() -- brain damaged version of variable arguments */
787
788 void bmsg(UAContext *ua, const char *fmt, va_list arg_ptr)
789 {
790    BSOCK *bs = ua->UA_sock;
791    int maxlen, len;
792    POOLMEM *msg = NULL;
793
794    if (bs) {
795       msg = bs->msg;
796    }
797    if (!msg) {
798       msg = get_memory(5000);
799    }
800
801    maxlen = sizeof_pool_memory(msg) - 1;
802    if (maxlen < 4999) {
803       msg = realloc_pool_memory(msg, 5000);
804       maxlen = 4999;
805    }
806    len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
807    if (len < 0 || len >= maxlen) {
808       pm_strcpy(msg, _("Message too long to display.\n"));
809       len = strlen(msg);
810    }
811
812    if (bs) {
813       bs->msg = msg;
814       bs->msglen = len;
815       bs->send();
816    } else {                           /* No UA, send to Job */
817       Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
818       free_pool_memory(msg);
819    }
820
821 }
822 #endif
823  
824 void bsendmsg(void *ctx, const char *fmt, ...)
825 {
826    va_list arg_ptr;
827    va_start(arg_ptr, fmt);
828    bmsg((UAContext *)ctx, fmt, arg_ptr);
829    va_end(arg_ptr);
830 }
831
832 /*
833  * The following UA methods are mainly intended for GUI
834  * programs
835  */
836 /*
837  * This is a message that should be displayed on the user's 
838  *  console.
839  */
840 void UAContext::send_msg(const char *fmt, ...)
841 {
842    va_list arg_ptr;
843    va_start(arg_ptr, fmt);
844    bmsg(this, fmt, arg_ptr);
845    va_end(arg_ptr);
846 }
847
848
849 /*
850  * This is an error condition with a command. The gui should put
851  *  up an error or critical dialog box.  The command is aborted.
852  */
853 void UAContext::error_msg(const char *fmt, ...)
854 {
855    BSOCK *bs = UA_sock;
856    va_list arg_ptr;
857
858    if (bs && api) bs->signal(BNET_ERROR_MSG);
859    va_start(arg_ptr, fmt);
860    bmsg(this, fmt, arg_ptr);
861    va_end(arg_ptr);
862 }
863
864 /*  
865  * This is a warning message, that should bring up a warning
866  *  dialog box on the GUI. The command is not aborted, but something
867  *  went wrong.
868  */
869 void UAContext::warning_msg(const char *fmt, ...)
870 {
871    BSOCK *bs = UA_sock;
872    va_list arg_ptr;
873
874    if (bs && api) bs->signal(BNET_WARNING_MSG);
875    va_start(arg_ptr, fmt);
876    bmsg(this, fmt, arg_ptr);
877    va_end(arg_ptr);
878 }
879
880 /* 
881  * This is an information message that should probably be put
882  *  into the status line of a GUI program.
883  */
884 void UAContext::info_msg(const char *fmt, ...)
885 {
886    BSOCK *bs = UA_sock;
887    va_list arg_ptr;
888
889    if (bs && api) bs->signal(BNET_INFO_MSG);
890    va_start(arg_ptr, fmt);
891    bmsg(this, fmt, arg_ptr);
892    va_end(arg_ptr);
893 }