]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_output.c
ebl Add new ScratchPool directive to Pool. Thanks to Graham
[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       /* no need to set ScratchPoolId, since we use fnv_no_create_vol */
527       if (!find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_prune)) {
528          ua->error_msg(_("Could not find next Volume for Job %s (Pool=%s, Level=%s).\n"),
529             job->name(), pr.Name, level_to_str(run->level));
530       } else {
531          ua->send_msg(
532             _("The next Volume to be used by Job \"%s\" (Pool=%s, Level=%s) will be %s\n"),
533             job->name(), pr.Name, level_to_str(run->level), mr.VolumeName);
534          found = true;
535       }
536    }
537
538 get_out:
539    db_close_database(jcr, jcr->db);
540    jcr->db = NULL;
541    free_jcr(jcr);
542    if (!found) {
543       ua->error_msg(_("Could not find next Volume for Job %s.\n"),
544          job->hdr.name);
545       return false;
546    }
547    return true;
548 }
549
550
551 /*
552  * For a given job, we examine all his run records
553  *  to see if it is scheduled today or tomorrow.
554  */
555 RUN *find_next_run(RUN *run, JOB *job, utime_t &runtime, int ndays)
556 {
557    time_t now, future, endtime;
558    SCHED *sched;
559    struct tm tm, runtm;
560    int mday, wday, month, wom, i;
561    int woy;
562    int day;
563    int is_scheduled;
564
565    sched = job->schedule;
566    if (sched == NULL) {            /* scheduled? */
567       return NULL;                 /* no nothing to report */
568    }
569
570    /* Break down the time into components */
571    now = time(NULL);
572    endtime = now + (ndays * 60 * 60 * 24);
573
574    if (run == NULL) {
575       run = sched->run;
576    } else {
577       run = run->next;
578    }
579    for ( ; run; run=run->next) {
580       /*
581        * Find runs in next 24 hours.  Day 0 is today, so if
582        *   ndays=1, look at today and tomorrow.
583        */
584       for (day = 0; day <= ndays; day++) {
585          future = now + (day * 60 * 60 * 24);
586
587          /* Break down the time into components */
588          (void)localtime_r(&future, &tm);
589          mday = tm.tm_mday - 1;
590          wday = tm.tm_wday;
591          month = tm.tm_mon;
592          wom = mday / 7;
593          woy = tm_woy(future);
594
595          is_scheduled = bit_is_set(mday, run->mday) && bit_is_set(wday, run->wday) &&
596             bit_is_set(month, run->month) && bit_is_set(wom, run->wom) &&
597             bit_is_set(woy, run->woy);
598  
599 #ifdef xxx
600          Pmsg2(000, "day=%d is_scheduled=%d\n", day, is_scheduled);
601          Pmsg1(000, "bit_set_mday=%d\n", bit_is_set(mday, run->mday));
602          Pmsg1(000, "bit_set_wday=%d\n", bit_is_set(wday, run->wday));
603          Pmsg1(000, "bit_set_month=%d\n", bit_is_set(month, run->month));
604          Pmsg1(000, "bit_set_wom=%d\n", bit_is_set(wom, run->wom));
605          Pmsg1(000, "bit_set_woy=%d\n", bit_is_set(woy, run->woy));
606 #endif
607
608          if (is_scheduled) { /* Jobs scheduled on that day */
609 #ifdef xxx
610             char buf[300], num[10];
611             bsnprintf(buf, sizeof(buf), "tm.hour=%d hour=", tm.tm_hour);
612             for (i=0; i<24; i++) {
613                if (bit_is_set(i, run->hour)) {
614                   bsnprintf(num, sizeof(num), "%d ", i);
615                   bstrncat(buf, num, sizeof(buf));
616                }
617             }
618             bstrncat(buf, "\n", sizeof(buf));
619             Pmsg1(000, "%s", buf);
620 #endif
621             /* find time (time_t) job is to be run */
622             (void)localtime_r(&future, &runtm);
623             for (i= 0; i < 24; i++) {
624                if (bit_is_set(i, run->hour)) {
625                   runtm.tm_hour = i;
626                   runtm.tm_min = run->minute;
627                   runtm.tm_sec = 0;
628                   runtime = mktime(&runtm);
629                   Dmsg2(200, "now=%d runtime=%lld\n", now, runtime);
630                   if ((runtime > now) && (runtime < endtime)) {
631                      Dmsg2(200, "Found it level=%d %c\n", run->level, run->level);
632                      return run;         /* found it, return run resource */
633                   }
634                }
635             }
636          }
637       }
638    } /* end for loop over runs */
639    /* Nothing found */
640    return NULL;
641 }
642
643 /*
644  * Fill in the remaining fields of the jcr as if it
645  *  is going to run the job.
646  */
647 bool complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool)
648 {
649    POOL_DBR pr;
650
651    memset(&pr, 0, sizeof(POOL_DBR));
652    set_jcr_defaults(jcr, job);
653    if (pool) {
654       jcr->pool = pool;               /* override */
655    }
656    if (jcr->db) {
657       Dmsg0(100, "complete_jcr close db\n");
658       db_close_database(jcr, jcr->db);
659       jcr->db = NULL;
660    }
661
662    Dmsg0(100, "complete_jcr open db\n");
663    jcr->db = jcr->db=db_init(jcr, jcr->catalog->db_driver, jcr->catalog->db_name, 
664                       jcr->catalog->db_user,
665                       jcr->catalog->db_password, jcr->catalog->db_address,
666                       jcr->catalog->db_port, jcr->catalog->db_socket,
667                       jcr->catalog->mult_db_connections);
668    if (!jcr->db || !db_open_database(jcr, jcr->db)) {
669       Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
670                  jcr->catalog->db_name);
671       if (jcr->db) {
672          Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
673          db_close_database(jcr, jcr->db);
674          jcr->db = NULL;
675       }
676       return false;
677    }
678    bstrncpy(pr.Name, jcr->pool->name(), sizeof(pr.Name));
679    while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
680       /* Try to create the pool */
681       if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
682          Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
683             db_strerror(jcr->db));
684          if (jcr->db) {
685             db_close_database(jcr, jcr->db);
686             jcr->db = NULL;
687          }
688          return false;
689       } else {
690          Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
691       }
692    }
693    jcr->jr.PoolId = pr.PoolId;
694    return true;
695 }
696
697
698 static void con_lock_release(void *arg)
699 {
700    Vw(con_lock);
701 }
702
703 void do_messages(UAContext *ua, const char *cmd)
704 {
705    char msg[2000];
706    int mlen;
707    bool do_truncate = false;
708
709    Pw(con_lock);
710    pthread_cleanup_push(con_lock_release, (void *)NULL);
711    rewind(con_fd);
712    while (fgets(msg, sizeof(msg), con_fd)) {
713       mlen = strlen(msg);
714       ua->UA_sock->msg = check_pool_memory_size(ua->UA_sock->msg, mlen+1);
715       strcpy(ua->UA_sock->msg, msg);
716       ua->UA_sock->msglen = mlen;
717       ua->UA_sock->send();
718       do_truncate = true;
719    }
720    if (do_truncate) {
721       (void)ftruncate(fileno(con_fd), 0L);
722    }
723    console_msg_pending = FALSE;
724    ua->user_notified_msg_pending = FALSE;
725    pthread_cleanup_pop(0);
726    Vw(con_lock);
727 }
728
729
730 int qmessagescmd(UAContext *ua, const char *cmd)
731 {
732    if (console_msg_pending && ua->auto_display_messages) {
733       do_messages(ua, cmd);
734    }
735    return 1;
736 }
737
738 int messagescmd(UAContext *ua, const char *cmd)
739 {
740    if (console_msg_pending) {
741       do_messages(ua, cmd);
742    } else {
743       ua->UA_sock->fsend(_("You have no messages.\n"));
744    }
745    return 1;
746 }
747
748 /*
749  * Callback routine for "printing" database file listing
750  */
751 void prtit(void *ctx, const char *msg)
752 {
753    UAContext *ua = (UAContext *)ctx;
754
755    ua->UA_sock->fsend("%s", msg);
756 }
757
758 /*
759  * Format message and send to other end.
760
761  * If the UA_sock is NULL, it means that there is no user
762  * agent, so we are being called from Bacula core. In
763  * that case direct the messages to the Job.
764  */
765 #ifdef HAVE_VA_COPY
766 void bmsg(UAContext *ua, const char *fmt, va_list arg_ptr)
767 {
768    BSOCK *bs = ua->UA_sock;
769    int maxlen, len;
770    POOLMEM *msg = NULL;
771    va_list ap;
772
773    if (bs) {
774       msg = bs->msg;
775    }
776    if (!msg) {
777       msg = get_pool_memory(PM_EMSG);
778    }
779
780 again:
781    maxlen = sizeof_pool_memory(msg) - 1;
782    va_copy(ap, arg_ptr);
783    len = bvsnprintf(msg, maxlen, fmt, ap);
784    va_end(ap);
785    if (len < 0 || len >= maxlen) {
786       msg = realloc_pool_memory(msg, maxlen + maxlen/2);
787       goto again;
788    }
789
790    if (bs) {
791       bs->msg = msg;
792       bs->msglen = len;
793       bs->send();
794    } else {                           /* No UA, send to Job */
795       Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
796       free_pool_memory(msg);
797    }
798
799 }
800
801 #else /* no va_copy() -- brain damaged version of variable arguments */
802
803 void bmsg(UAContext *ua, const char *fmt, va_list arg_ptr)
804 {
805    BSOCK *bs = ua->UA_sock;
806    int maxlen, len;
807    POOLMEM *msg = NULL;
808
809    if (bs) {
810       msg = bs->msg;
811    }
812    if (!msg) {
813       msg = get_memory(5000);
814    }
815
816    maxlen = sizeof_pool_memory(msg) - 1;
817    if (maxlen < 4999) {
818       msg = realloc_pool_memory(msg, 5000);
819       maxlen = 4999;
820    }
821    len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
822    if (len < 0 || len >= maxlen) {
823       pm_strcpy(msg, _("Message too long to display.\n"));
824       len = strlen(msg);
825    }
826
827    if (bs) {
828       bs->msg = msg;
829       bs->msglen = len;
830       bs->send();
831    } else {                           /* No UA, send to Job */
832       Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
833       free_pool_memory(msg);
834    }
835
836 }
837 #endif
838  
839 void bsendmsg(void *ctx, const char *fmt, ...)
840 {
841    va_list arg_ptr;
842    va_start(arg_ptr, fmt);
843    bmsg((UAContext *)ctx, fmt, arg_ptr);
844    va_end(arg_ptr);
845 }
846
847 /*
848  * The following UA methods are mainly intended for GUI
849  * programs
850  */
851 /*
852  * This is a message that should be displayed on the user's 
853  *  console.
854  */
855 void UAContext::send_msg(const char *fmt, ...)
856 {
857    va_list arg_ptr;
858    va_start(arg_ptr, fmt);
859    bmsg(this, fmt, arg_ptr);
860    va_end(arg_ptr);
861 }
862
863
864 /*
865  * This is an error condition with a command. The gui should put
866  *  up an error or critical dialog box.  The command is aborted.
867  */
868 void UAContext::error_msg(const char *fmt, ...)
869 {
870    BSOCK *bs = UA_sock;
871    va_list arg_ptr;
872
873    if (bs && api) bs->signal(BNET_ERROR_MSG);
874    va_start(arg_ptr, fmt);
875    bmsg(this, fmt, arg_ptr);
876    va_end(arg_ptr);
877 }
878
879 /*  
880  * This is a warning message, that should bring up a warning
881  *  dialog box on the GUI. The command is not aborted, but something
882  *  went wrong.
883  */
884 void UAContext::warning_msg(const char *fmt, ...)
885 {
886    BSOCK *bs = UA_sock;
887    va_list arg_ptr;
888
889    if (bs && api) bs->signal(BNET_WARNING_MSG);
890    va_start(arg_ptr, fmt);
891    bmsg(this, fmt, arg_ptr);
892    va_end(arg_ptr);
893 }
894
895 /* 
896  * This is an information message that should probably be put
897  *  into the status line of a GUI program.
898  */
899 void UAContext::info_msg(const char *fmt, ...)
900 {
901    BSOCK *bs = UA_sock;
902    va_list arg_ptr;
903
904    if (bs && api) bs->signal(BNET_INFO_MSG);
905    va_start(arg_ptr, fmt);
906    bmsg(this, fmt, arg_ptr);
907    va_end(arg_ptr);
908 }