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