]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_output.c
ebl Work on copy jobs
[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  *  list copies jobid=x,y,z
227  *
228  */
229
230 /* Do long or full listing */
231 int llist_cmd(UAContext *ua, const char *cmd)
232 {
233    return do_list_cmd(ua, cmd, VERT_LIST);
234 }
235
236 /* Do short or summary listing */
237 int list_cmd(UAContext *ua, const char *cmd)
238 {
239    return do_list_cmd(ua, cmd, HORZ_LIST);
240 }
241
242 static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
243 {
244    POOLMEM *VolumeName;
245    int jobid, n;
246    int i, j;
247    JOB_DBR jr;
248    POOL_DBR pr;
249    MEDIA_DBR mr;
250
251    if (!open_client_db(ua))
252       return 1;
253
254    memset(&jr, 0, sizeof(jr));
255    memset(&pr, 0, sizeof(pr));
256    memset(&mr, 0, sizeof(mr));
257
258    Dmsg1(20, "list: %s\n", cmd);
259
260    if (!ua->db) {
261       ua->error_msg(_("Hey! DB is NULL\n"));
262    }
263
264    /* Scan arguments looking for things to do */
265    for (i=1; i<ua->argc; i++) {
266       /* List JOBS */
267       if (strcasecmp(ua->argk[i], NT_("jobs")) == 0) {
268          /* Apply any limit */
269          j = find_arg_with_value(ua, NT_("limit"));
270          if (j >= 0) {
271             jr.limit = atoi(ua->argv[j]);
272          }
273          db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
274
275          /* List JOBTOTALS */
276       } else if (strcasecmp(ua->argk[i], NT_("jobtotals")) == 0) {
277          db_list_job_totals(ua->jcr, ua->db, &jr, prtit, ua);
278
279       /* List JOBID=nn */
280       } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
281          if (ua->argv[i]) {
282             jobid = str_to_int64(ua->argv[i]);
283             if (jobid > 0) {
284                jr.JobId = jobid;
285                db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
286             }
287          }
288
289       /* List JOB=xxx */
290       } else if ((strcasecmp(ua->argk[i], NT_("job")) == 0 ||
291                   strcasecmp(ua->argk[i], NT_("jobname")) == 0) && ua->argv[i]) {
292          bstrncpy(jr.Name, ua->argv[i], MAX_NAME_LENGTH);
293          jr.JobId = 0;
294          db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
295
296       /* List UJOBID=xxx */
297       } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
298          bstrncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
299          jr.JobId = 0;
300          db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
301
302       /* List FILES */
303       } else if (strcasecmp(ua->argk[i], NT_("files")) == 0) {
304
305          for (j=i+1; j<ua->argc; j++) {
306             if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
307                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
308                jr.JobId = 0;
309                db_get_job_record(ua->jcr, ua->db, &jr);
310                jobid = jr.JobId;
311             } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
312                jobid = str_to_int64(ua->argv[j]);
313             } else {
314                continue;
315             }
316             if (jobid > 0) {
317                db_list_files_for_job(ua->jcr, ua->db, jobid, prtit, ua);
318             }
319          }
320
321       /* List JOBMEDIA */
322       } else if (strcasecmp(ua->argk[i], NT_("jobmedia")) == 0) {
323          int done = FALSE;
324          for (j=i+1; j<ua->argc; j++) {
325             if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
326                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
327                jr.JobId = 0;
328                db_get_job_record(ua->jcr, ua->db, &jr);
329                jobid = jr.JobId;
330             } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
331                jobid = str_to_int64(ua->argv[j]);
332             } else {
333                continue;
334             }
335             db_list_jobmedia_records(ua->jcr, ua->db, jobid, prtit, ua, llist);
336             done = TRUE;
337          }
338          if (!done) {
339             /* List for all jobs (jobid=0) */
340             db_list_jobmedia_records(ua->jcr, ua->db, 0, prtit, ua, llist);
341          }
342
343       /* List JOBLOG */
344       } else if (strcasecmp(ua->argk[i], NT_("joblog")) == 0) {
345          int done = FALSE;
346          for (j=i+1; j<ua->argc; j++) {
347             if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
348                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
349                jr.JobId = 0;
350                db_get_job_record(ua->jcr, ua->db, &jr);
351                jobid = jr.JobId;
352             } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
353                jobid = str_to_int64(ua->argv[j]);
354             } else {
355                continue;
356             }
357             db_list_joblog_records(ua->jcr, ua->db, jobid, prtit, ua, llist);
358             done = TRUE;
359          }
360          if (!done) {
361             /* List for all jobs (jobid=0) */
362             db_list_joblog_records(ua->jcr, ua->db, 0, prtit, ua, llist);
363          }
364
365
366       /* List POOLS */
367       } else if (strcasecmp(ua->argk[i], NT_("pool")) == 0 ||
368                  strcasecmp(ua->argk[i], NT_("pools")) == 0) {
369          POOL_DBR pr;
370          memset(&pr, 0, sizeof(pr));
371          if (ua->argv[i]) {
372             bstrncpy(pr.Name, ua->argv[i], sizeof(pr.Name));
373          }
374          db_list_pool_records(ua->jcr, ua->db, &pr, prtit, ua, llist);
375
376       } else if (strcasecmp(ua->argk[i], NT_("clients")) == 0) {
377          db_list_client_records(ua->jcr, ua->db, prtit, ua, llist);
378
379
380       /* List MEDIA or VOLUMES */
381       } else if (strcasecmp(ua->argk[i], NT_("media")) == 0 ||
382                  strcasecmp(ua->argk[i], NT_("volume")) == 0 ||
383                  strcasecmp(ua->argk[i], NT_("volumes")) == 0) {
384          bool done = false;
385          for (j=i+1; j<ua->argc; j++) {
386             if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
387                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
388                jr.JobId = 0;
389                db_get_job_record(ua->jcr, ua->db, &jr);
390                jobid = jr.JobId;
391             } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
392                jobid = str_to_int64(ua->argv[j]);
393             } else {
394                continue;
395             }
396             VolumeName = get_pool_memory(PM_FNAME);
397             n = db_get_job_volume_names(ua->jcr, ua->db, jobid, &VolumeName);
398             ua->send_msg(_("Jobid %d used %d Volume(s): %s\n"), jobid, n, VolumeName);
399             free_pool_memory(VolumeName);
400             done = true;
401          }
402          /* if no job or jobid keyword found, then we list all media */
403          if (!done) {
404             int num_pools;
405             uint32_t *ids;
406             /* List a specific volume? */
407             if (ua->argv[i]) {
408                bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName));
409                db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
410                return 1;
411             }
412             /* Is a specific pool wanted? */
413             for (i=1; i<ua->argc; i++) {
414                if (strcasecmp(ua->argk[i], NT_("pool")) == 0) {
415                   if (!get_pool_dbr(ua, &pr)) {
416                      ua->error_msg(_("No Pool specified.\n"));
417                      return 1;
418                   }
419                   mr.PoolId = pr.PoolId;
420                   db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
421                   return 1;
422                }
423             }
424
425             /* List Volumes in all pools */
426             if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
427                ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"),
428                         db_strerror(ua->db));
429                return 1;
430             }
431             if (num_pools <= 0) {
432                return 1;
433             }
434             for (i=0; i < num_pools; i++) {
435                pr.PoolId = ids[i];
436                if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
437                   ua->send_msg(_("Pool: %s\n"), pr.Name);
438                }
439                mr.PoolId = ids[i];
440                db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
441             }
442             free(ids);
443             return 1;
444          }
445       /* List next volume */
446       } else if (strcasecmp(ua->argk[i], NT_("nextvol")) == 0 ||
447                  strcasecmp(ua->argk[i], NT_("nextvolume")) == 0) {
448          n = 1;
449          j = find_arg_with_value(ua, NT_("days"));
450          if (j >= 0) {
451             n = atoi(ua->argv[j]);
452             if ((n < 0) || (n > 50)) {
453               ua->warning_msg(_("Ignoring invalid value for days. Max is 50.\n"));
454               n = 1;
455             }
456          }
457          list_nextvol(ua, n);
458       } else if (strcasecmp(ua->argk[i], NT_("copies")) == 0) {
459          char *jobids=NULL;
460          uint32_t limit=0;
461          for (j=i+1; j<ua->argc; j++) {
462             if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
463                if (is_a_number_list(ua->argv[j])) {
464                   jobids = ua->argv[j];
465                }
466             } else if (strcasecmp(ua->argk[j], NT_("limit")) == 0 && ua->argv[j]) {
467                limit = atoi(ua->argv[j]);
468             } 
469          }
470          db_list_copies_records(ua->jcr,ua->db,limit,jobids,prtit,ua,llist);
471       } else if (strcasecmp(ua->argk[i], NT_("limit")) == 0
472                  || strcasecmp(ua->argk[i], NT_("days")) == 0) {
473          /* Ignore it */
474       } else {
475          ua->error_msg(_("Unknown list keyword: %s\n"), NPRT(ua->argk[i]));
476       }
477    }
478    return 1;
479 }
480
481 static bool list_nextvol(UAContext *ua, int ndays)
482 {
483    JOB *job;
484    JCR *jcr;          
485    USTORE store;
486    RUN *run;
487    utime_t runtime;
488    bool found = false;
489    MEDIA_DBR mr;
490    POOL_DBR pr;
491
492    memset(&mr, 0, sizeof(mr));
493    int i = find_arg_with_value(ua, "job");
494    if (i <= 0) {
495       if ((job = select_job_resource(ua)) == NULL) {
496          return false;
497       }
498    } else {
499       job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
500       if (!job) {
501          Jmsg(ua->jcr, M_ERROR, 0, _("%s is not a job name.\n"), ua->argv[i]);
502          if ((job = select_job_resource(ua)) == NULL) {
503             return false;
504          }
505       }
506    }
507
508    jcr = new_jcr(sizeof(JCR), dird_free_jcr);
509    for (run=NULL; (run = find_next_run(run, job, runtime, ndays)); ) {
510       if (!complete_jcr_for_job(jcr, job, run->pool)) {
511          found = false;
512          goto get_out;
513       }
514       if (!jcr->jr.PoolId) {
515          ua->error_msg(_("Could not find Pool for Job %s\n"), job->name());
516          continue;
517       }
518       memset(&pr, 0, sizeof(pr));
519       pr.PoolId = jcr->jr.PoolId;
520       if (!db_get_pool_record(jcr, jcr->db, &pr)) {
521          bstrncpy(pr.Name, "*UnknownPool*", sizeof(pr.Name));
522       }
523       mr.PoolId = jcr->jr.PoolId;
524       get_job_storage(&store, job, run);
525       mr.StorageId = store.store->StorageId;
526       if (!find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_prune)) {
527          ua->error_msg(_("Could not find next Volume for Job %s (Pool=%s, Level=%s).\n"),
528             job->name(), pr.Name, level_to_str(run->level));
529       } else {
530          ua->send_msg(
531             _("The next Volume to be used by Job \"%s\" (Pool=%s, Level=%s) will be %s\n"),
532             job->name(), pr.Name, level_to_str(run->level), mr.VolumeName);
533          found = true;
534       }
535    }
536
537 get_out:
538    db_close_database(jcr, jcr->db);
539    jcr->db = NULL;
540    free_jcr(jcr);
541    if (!found) {
542       ua->error_msg(_("Could not find next Volume for Job %s.\n"),
543          job->hdr.name);
544       return false;
545    }
546    return true;
547 }
548
549
550 /*
551  * For a given job, we examine all his run records
552  *  to see if it is scheduled today or tomorrow.
553  */
554 RUN *find_next_run(RUN *run, JOB *job, utime_t &runtime, int ndays)
555 {
556    time_t now, future, endtime;
557    SCHED *sched;
558    struct tm tm, runtm;
559    int mday, wday, month, wom, i;
560    int woy;
561    int day;
562    int is_scheduled;
563
564    sched = job->schedule;
565    if (sched == NULL) {            /* scheduled? */
566       return NULL;                 /* no nothing to report */
567    }
568
569    /* Break down the time into components */
570    now = time(NULL);
571    endtime = now + (ndays * 60 * 60 * 24);
572
573    if (run == NULL) {
574       run = sched->run;
575    } else {
576       run = run->next;
577    }
578    for ( ; run; run=run->next) {
579       /*
580        * Find runs in next 24 hours.  Day 0 is today, so if
581        *   ndays=1, look at today and tomorrow.
582        */
583       for (day = 0; day <= ndays; day++) {
584          future = now + (day * 60 * 60 * 24);
585
586          /* Break down the time into components */
587          (void)localtime_r(&future, &tm);
588          mday = tm.tm_mday - 1;
589          wday = tm.tm_wday;
590          month = tm.tm_mon;
591          wom = mday / 7;
592          woy = tm_woy(future);
593
594          is_scheduled = bit_is_set(mday, run->mday) && bit_is_set(wday, run->wday) &&
595             bit_is_set(month, run->month) && bit_is_set(wom, run->wom) &&
596             bit_is_set(woy, run->woy);
597  
598 #ifdef xxx
599          Pmsg2(000, "day=%d is_scheduled=%d\n", day, is_scheduled);
600          Pmsg1(000, "bit_set_mday=%d\n", bit_is_set(mday, run->mday));
601          Pmsg1(000, "bit_set_wday=%d\n", bit_is_set(wday, run->wday));
602          Pmsg1(000, "bit_set_month=%d\n", bit_is_set(month, run->month));
603          Pmsg1(000, "bit_set_wom=%d\n", bit_is_set(wom, run->wom));
604          Pmsg1(000, "bit_set_woy=%d\n", bit_is_set(woy, run->woy));
605 #endif
606
607          if (is_scheduled) { /* Jobs scheduled on that day */
608 #ifdef xxx
609             char buf[300], num[10];
610             bsnprintf(buf, sizeof(buf), "tm.hour=%d hour=", tm.tm_hour);
611             for (i=0; i<24; i++) {
612                if (bit_is_set(i, run->hour)) {
613                   bsnprintf(num, sizeof(num), "%d ", i);
614                   bstrncat(buf, num, sizeof(buf));
615                }
616             }
617             bstrncat(buf, "\n", sizeof(buf));
618             Pmsg1(000, "%s", buf);
619 #endif
620             /* find time (time_t) job is to be run */
621             (void)localtime_r(&future, &runtm);
622             for (i= 0; i < 24; i++) {
623                if (bit_is_set(i, run->hour)) {
624                   runtm.tm_hour = i;
625                   runtm.tm_min = run->minute;
626                   runtm.tm_sec = 0;
627                   runtime = mktime(&runtm);
628                   Dmsg2(200, "now=%d runtime=%lld\n", now, runtime);
629                   if ((runtime > now) && (runtime < endtime)) {
630                      Dmsg2(200, "Found it level=%d %c\n", run->level, run->level);
631                      return run;         /* found it, return run resource */
632                   }
633                }
634             }
635          }
636       }
637    } /* end for loop over runs */
638    /* Nothing found */
639    return NULL;
640 }
641
642 /*
643  * Fill in the remaining fields of the jcr as if it
644  *  is going to run the job.
645  */
646 bool complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool)
647 {
648    POOL_DBR pr;
649
650    memset(&pr, 0, sizeof(POOL_DBR));
651    set_jcr_defaults(jcr, job);
652    if (pool) {
653       jcr->pool = pool;               /* override */
654    }
655    if (jcr->db) {
656       Dmsg0(100, "complete_jcr close db\n");
657       db_close_database(jcr, jcr->db);
658       jcr->db = NULL;
659    }
660
661    Dmsg0(100, "complete_jcr open db\n");
662    jcr->db = jcr->db=db_init(jcr, jcr->catalog->db_driver, jcr->catalog->db_name, 
663                       jcr->catalog->db_user,
664                       jcr->catalog->db_password, jcr->catalog->db_address,
665                       jcr->catalog->db_port, jcr->catalog->db_socket,
666                       jcr->catalog->mult_db_connections);
667    if (!jcr->db || !db_open_database(jcr, jcr->db)) {
668       Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
669                  jcr->catalog->db_name);
670       if (jcr->db) {
671          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
672          db_close_database(jcr, jcr->db);
673          jcr->db = NULL;
674       }
675       return false;
676    }
677    bstrncpy(pr.Name, jcr->pool->name(), sizeof(pr.Name));
678    while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
679       /* Try to create the pool */
680       if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
681          Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
682             db_strerror(jcr->db));
683          if (jcr->db) {
684             db_close_database(jcr, jcr->db);
685             jcr->db = NULL;
686          }
687          return false;
688       } else {
689          Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
690       }
691    }
692    jcr->jr.PoolId = pr.PoolId;
693    return true;
694 }
695
696
697 static void con_lock_release(void *arg)
698 {
699    Vw(con_lock);
700 }
701
702 void do_messages(UAContext *ua, const char *cmd)
703 {
704    char msg[2000];
705    int mlen;
706    bool do_truncate = false;
707
708    Pw(con_lock);
709    pthread_cleanup_push(con_lock_release, (void *)NULL);
710    rewind(con_fd);
711    while (fgets(msg, sizeof(msg), con_fd)) {
712       mlen = strlen(msg);
713       ua->UA_sock->msg = check_pool_memory_size(ua->UA_sock->msg, mlen+1);
714       strcpy(ua->UA_sock->msg, msg);
715       ua->UA_sock->msglen = mlen;
716       ua->UA_sock->send();
717       do_truncate = true;
718    }
719    if (do_truncate) {
720       (void)ftruncate(fileno(con_fd), 0L);
721    }
722    console_msg_pending = FALSE;
723    ua->user_notified_msg_pending = FALSE;
724    pthread_cleanup_pop(0);
725    Vw(con_lock);
726 }
727
728
729 int qmessagescmd(UAContext *ua, const char *cmd)
730 {
731    if (console_msg_pending && ua->auto_display_messages) {
732       do_messages(ua, cmd);
733    }
734    return 1;
735 }
736
737 int messagescmd(UAContext *ua, const char *cmd)
738 {
739    if (console_msg_pending) {
740       do_messages(ua, cmd);
741    } else {
742       ua->UA_sock->fsend(_("You have no messages.\n"));
743    }
744    return 1;
745 }
746
747 /*
748  * Callback routine for "printing" database file listing
749  */
750 void prtit(void *ctx, const char *msg)
751 {
752    UAContext *ua = (UAContext *)ctx;
753
754    ua->UA_sock->fsend("%s", msg);
755 }
756
757 /*
758  * Format message and send to other end.
759
760  * If the UA_sock is NULL, it means that there is no user
761  * agent, so we are being called from Bacula core. In
762  * that case direct the messages to the Job.
763  */
764 #ifdef HAVE_VA_COPY
765 void bmsg(UAContext *ua, const char *fmt, va_list arg_ptr)
766 {
767    BSOCK *bs = ua->UA_sock;
768    int maxlen, len;
769    POOLMEM *msg = NULL;
770    va_list ap;
771
772    if (bs) {
773       msg = bs->msg;
774    }
775    if (!msg) {
776       msg = get_pool_memory(PM_EMSG);
777    }
778
779 again:
780    maxlen = sizeof_pool_memory(msg) - 1;
781    va_copy(ap, arg_ptr);
782    len = bvsnprintf(msg, maxlen, fmt, ap);
783    va_end(ap);
784    if (len < 0 || len >= maxlen) {
785       msg = realloc_pool_memory(msg, maxlen + maxlen/2);
786       goto again;
787    }
788
789    if (bs) {
790       bs->msg = msg;
791       bs->msglen = len;
792       bs->send();
793    } else {                           /* No UA, send to Job */
794       Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
795       free_pool_memory(msg);
796    }
797
798 }
799
800 #else /* no va_copy() -- brain damaged version of variable arguments */
801
802 void bmsg(UAContext *ua, const char *fmt, va_list arg_ptr)
803 {
804    BSOCK *bs = ua->UA_sock;
805    int maxlen, len;
806    POOLMEM *msg = NULL;
807
808    if (bs) {
809       msg = bs->msg;
810    }
811    if (!msg) {
812       msg = get_memory(5000);
813    }
814
815    maxlen = sizeof_pool_memory(msg) - 1;
816    if (maxlen < 4999) {
817       msg = realloc_pool_memory(msg, 5000);
818       maxlen = 4999;
819    }
820    len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
821    if (len < 0 || len >= maxlen) {
822       pm_strcpy(msg, _("Message too long to display.\n"));
823       len = strlen(msg);
824    }
825
826    if (bs) {
827       bs->msg = msg;
828       bs->msglen = len;
829       bs->send();
830    } else {                           /* No UA, send to Job */
831       Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
832       free_pool_memory(msg);
833    }
834
835 }
836 #endif
837  
838 void bsendmsg(void *ctx, const char *fmt, ...)
839 {
840    va_list arg_ptr;
841    va_start(arg_ptr, fmt);
842    bmsg((UAContext *)ctx, fmt, arg_ptr);
843    va_end(arg_ptr);
844 }
845
846 /*
847  * The following UA methods are mainly intended for GUI
848  * programs
849  */
850 /*
851  * This is a message that should be displayed on the user's 
852  *  console.
853  */
854 void UAContext::send_msg(const char *fmt, ...)
855 {
856    va_list arg_ptr;
857    va_start(arg_ptr, fmt);
858    bmsg(this, fmt, arg_ptr);
859    va_end(arg_ptr);
860 }
861
862
863 /*
864  * This is an error condition with a command. The gui should put
865  *  up an error or critical dialog box.  The command is aborted.
866  */
867 void UAContext::error_msg(const char *fmt, ...)
868 {
869    BSOCK *bs = UA_sock;
870    va_list arg_ptr;
871
872    if (bs && api) bs->signal(BNET_ERROR_MSG);
873    va_start(arg_ptr, fmt);
874    bmsg(this, fmt, arg_ptr);
875    va_end(arg_ptr);
876 }
877
878 /*  
879  * This is a warning message, that should bring up a warning
880  *  dialog box on the GUI. The command is not aborted, but something
881  *  went wrong.
882  */
883 void UAContext::warning_msg(const char *fmt, ...)
884 {
885    BSOCK *bs = UA_sock;
886    va_list arg_ptr;
887
888    if (bs && api) bs->signal(BNET_WARNING_MSG);
889    va_start(arg_ptr, fmt);
890    bmsg(this, fmt, arg_ptr);
891    va_end(arg_ptr);
892 }
893
894 /* 
895  * This is an information message that should probably be put
896  *  into the status line of a GUI program.
897  */
898 void UAContext::info_msg(const char *fmt, ...)
899 {
900    BSOCK *bs = UA_sock;
901    va_list arg_ptr;
902
903    if (bs && api) bs->signal(BNET_INFO_MSG);
904    va_start(arg_ptr, fmt);
905    bmsg(this, fmt, arg_ptr);
906    va_end(arg_ptr);
907 }