2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Bacula Director -- User Agent Output Commands
22 * I.e. messages, listing database, showing resources, ...
24 * Kern Sibbald, September MM
30 /* Imported subroutines */
32 /* Imported variables */
34 /* Imported functions */
36 /* Forward referenced functions */
37 static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist);
38 static bool list_nextvol(UAContext *ua, int ndays);
41 * Turn auto display of console messages on/off
43 int autodisplay_cmd(UAContext *ua, const char *cmd)
45 static const char *kw[] = {
50 switch (find_arg_keyword(ua, kw)) {
52 ua->auto_display_messages = true;
55 ua->auto_display_messages = false;
58 ua->error_msg(_("ON or OFF keyword missing.\n"));
65 * Turn GUI mode on/off
67 int gui_cmd(UAContext *ua, const char *cmd)
69 static const char *kw[] = {
74 switch (find_arg_keyword(ua, kw)) {
76 ua->jcr->gui = ua->gui = true;
79 ua->jcr->gui = ua->gui = false;
82 ua->error_msg(_("ON or OFF keyword missing.\n"));
89 * Enter with Resources locked
91 static void show_disabled_jobs(UAContext *ua)
95 foreach_res(job, R_JOB) {
96 if (!acl_access_ok(ua, Job_ACL, job->name())) {
102 ua->send_msg(_("Disabled Jobs:\n"));
104 ua->send_msg(" %s\n", job->name());
108 ua->send_msg(_("No disabled Jobs.\n"));
112 struct showstruct {const char *res_name; int type;};
113 static struct showstruct reses[] = {
114 {NT_("directors"), R_DIRECTOR},
115 {NT_("clients"), R_CLIENT},
116 {NT_("counters"), R_COUNTER},
117 {NT_("devices"), R_DEVICE},
118 {NT_("jobs"), R_JOB},
119 {NT_("storages"), R_STORAGE},
120 {NT_("catalogs"), R_CATALOG},
121 {NT_("schedules"), R_SCHEDULE},
122 {NT_("filesets"), R_FILESET},
123 {NT_("pools"), R_POOL},
124 {NT_("messages"), R_MSGS},
135 * show <resource-keyword-name> e.g. show directors
136 * show <resource-keyword-name>=<name> e.g. show director=HeadMan
137 * show disabled shows disabled jobs
140 int show_cmd(UAContext *ua, const char *cmd)
147 Dmsg1(20, "show: %s\n", ua->UA_sock->msg);
151 for (i=1; i<ua->argc; i++) {
152 if (strcasecmp(ua->argk[i], NT_("disabled")) == 0) {
153 show_disabled_jobs(ua);
159 res_name = ua->argk[i];
160 if (!ua->argv[i]) { /* was a name given? */
161 /* No name, dump all resources of specified type */
163 len = strlen(res_name);
164 for (j=0; reses[j].res_name; j++) {
165 if (strncasecmp(res_name, reses[j].res_name, len) == 0) {
166 type = reses[j].type;
168 res = res_head[type-r_first];
177 /* Dump a single resource with specified name */
179 len = strlen(res_name);
180 for (j=0; reses[j].res_name; j++) {
181 if (strncasecmp(res_name, reses[j].res_name, len) == 0) {
182 type = reses[j].type;
183 res = (RES *)GetResWithName(type, ua->argv[i]);
195 for (j=r_first; j<=r_last; j++) {
196 /* Skip R_DEVICE since it is really not used or updated */
198 dump_resource(j, res_head[j-r_first], bsendmsg, ua);
204 ua->send_msg(_("Keywords for the show command are:\n"));
205 for (j=0; reses[j].res_name; j++) {
206 ua->error_msg("%s\n", reses[j].res_name);
209 /* Resource not found */
211 ua->error_msg(_("%s resource %s not found.\n"), res_name, ua->argv[i]);
213 /* Resource not found */
215 ua->error_msg(_("Resource %s not found\n"), res_name);
217 /* Dump a specific type */
219 dump_resource(recurse?type:-type, res, bsendmsg, ua);
229 * Check if the access is permitted for a list of jobids
231 * Not in ua_acl.c because it's using db access, and tools such
232 * as bdirjson are not linked with cats.
234 bool acl_access_jobid_ok(UAContext *ua, const char *jobids)
245 if (!is_a_number_list(jobids)) {
249 /* If no console resource => default console and all is permitted */
250 if (!ua || !ua->cons) {
251 Dmsg0(1400, "Root cons access OK.\n");
252 return true; /* No cons resource -> root console OK for everything */
255 alist *list = ua->cons->ACL_lists[Job_ACL];
256 if (!list) { /* empty list */
257 return false; /* List empty, reject everything */
260 /* Special case *all* gives full access */
261 if (list->size() == 1 && strcasecmp("*all*", (char *)list->get(0)) == 0) {
265 /* If we can't open the database, just say no */
266 if (!open_new_client_db(ua)) {
270 p = tmp = bstrdup(jobids);
272 while (get_next_jobid_from_list(&p, &jid) > 0) {
273 memset(&jr, 0, sizeof(jr));
276 if (db_get_job_record(ua->jcr, ua->db, &jr)) {
277 for (int i=0; i<list->size(); i++) {
278 if (strcasecmp(jr.Name, (char *)list->get(i)) == 0) {
279 Dmsg3(1400, "ACL found %s in %d %s\n", jr.Name,
280 Job_ACL, (char *)list->get(i));
296 * List contents of database
298 * list jobs - lists all jobs run
299 * list jobid=nnn - list job data for jobid
300 * list ujobid=uname - list job data for unique jobid
301 * list job=name - list all jobs with "name"
302 * list jobname=name - same as above
303 * list jobmedia jobid=<nn>
304 * list jobmedia job=name
305 * list joblog jobid=<nn>
306 * list joblog job=name
307 * list files jobid=<nn> - list files saved for job nn
308 * list files job=name
309 * list pools - list pool records
310 * list jobtotals - list totals for all jobs
311 * list media - list media for given pool (deprecated)
312 * list volumes - list Volumes
313 * list clients - list clients
314 * list nextvol job=xx - list the next vol to be used by job
315 * list nextvolume job=xx - same as above.
316 * list copies jobid=x,y,z
320 /* Do long or full listing */
321 int llist_cmd(UAContext *ua, const char *cmd)
323 return do_list_cmd(ua, cmd, VERT_LIST);
326 /* Do short or summary listing */
327 int list_cmd(UAContext *ua, const char *cmd)
329 return do_list_cmd(ua, cmd, HORZ_LIST);
332 static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
341 if (!open_new_client_db(ua))
344 memset(&jr, 0, sizeof(jr));
345 memset(&pr, 0, sizeof(pr));
347 Dmsg1(20, "list: %s\n", cmd);
350 ua->error_msg(_("Hey! DB is NULL\n"));
352 /* Apply any limit */
353 for (j = 1; j < ua->argc ; j++) {
354 if (strcasecmp(ua->argk[j], NT_("joberrors")) == 0) {
356 } else if (!ua->argv[j]) {
358 } else if (strcasecmp(ua->argk[j], NT_("order")) == 0) {
359 if (strcasecmp(ua->argv[j], NT_("desc")) == 0) {
361 } else if (strcasecmp(ua->argv[j], NT_("asc")) == 0) {
364 ua->error_msg(_("Unknown order type %s\n"), ua->argv[j]);
367 } else if (strcasecmp(ua->argk[j], NT_("limit")) == 0) {
368 jr.limit = atoi(ua->argv[j]);
370 } else if (strcasecmp(ua->argk[j], NT_("jobstatus")) == 0) {
371 if (B_ISALPHA(ua->argv[j][0])) {
372 jr.JobStatus = ua->argv[j][0];
374 } else if (strcasecmp(ua->argk[j], NT_("client")) == 0) {
375 if (is_name_valid(ua->argv[j], NULL)) {
377 memset(&cr, 0, sizeof(cr));
378 if(get_client_dbr(ua, &cr)) {
379 jr.ClientId = cr.ClientId;
385 /* Scan arguments looking for things to do */
386 for (i=1; i<ua->argc; i++) {
388 if (strcasecmp(ua->argk[i], NT_("jobs")) == 0) {
389 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
392 } else if (strcasecmp(ua->argk[i], NT_("jobtotals")) == 0) {
393 db_list_job_totals(ua->jcr, ua->db, &jr, prtit, ua);
396 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
398 jobid = str_to_int64(ua->argv[i]);
401 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
406 } else if ((strcasecmp(ua->argk[i], NT_("job")) == 0 ||
407 strcasecmp(ua->argk[i], NT_("jobname")) == 0) && ua->argv[i]) {
408 bstrncpy(jr.Name, ua->argv[i], MAX_NAME_LENGTH);
410 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
412 /* List UJOBID=xxx */
413 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
414 bstrncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
416 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
418 /* List Base files */
419 } else if (strcasecmp(ua->argk[i], NT_("basefiles")) == 0) {
420 /* TODO: cleanup this block */
421 for (j=i+1; j<ua->argc; j++) {
422 if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
423 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
425 db_get_job_record(ua->jcr, ua->db, &jr);
427 } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
428 jobid = str_to_int64(ua->argv[j]);
433 db_list_base_files_for_job(ua->jcr, ua->db, jobid, prtit, ua);
438 } else if (strcasecmp(ua->argk[i], NT_("files")) == 0) {
440 for (j=i+1; j<ua->argc; j++) {
441 if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
442 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
444 db_get_job_record(ua->jcr, ua->db, &jr);
446 } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
447 jobid = str_to_int64(ua->argv[j]);
452 db_list_files_for_job(ua->jcr, ua->db, jobid, prtit, ua);
457 } else if (strcasecmp(ua->argk[i], NT_("jobmedia")) == 0) {
459 for (j=i+1; j<ua->argc; j++) {
460 if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
461 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
463 db_get_job_record(ua->jcr, ua->db, &jr);
465 } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
466 jobid = str_to_int64(ua->argv[j]);
470 db_list_jobmedia_records(ua->jcr, ua->db, jobid, prtit, ua, llist);
474 /* List for all jobs (jobid=0) */
475 db_list_jobmedia_records(ua->jcr, ua->db, 0, prtit, ua, llist);
479 } else if (strcasecmp(ua->argk[i], NT_("joblog")) == 0) {
481 for (j=i+1; j<ua->argc; j++) {
482 if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
483 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
485 db_get_job_record(ua->jcr, ua->db, &jr);
487 } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
488 jobid = str_to_int64(ua->argv[j]);
492 db_list_joblog_records(ua->jcr, ua->db, jobid, prtit, ua, llist);
496 /* List for all jobs (jobid=0) */
497 db_list_joblog_records(ua->jcr, ua->db, 0, prtit, ua, llist);
502 } else if (strcasecmp(ua->argk[i], NT_("pool")) == 0 ||
503 strcasecmp(ua->argk[i], NT_("pools")) == 0) {
505 memset(&pr, 0, sizeof(pr));
507 bstrncpy(pr.Name, ua->argv[i], sizeof(pr.Name));
509 db_list_pool_records(ua->jcr, ua->db, &pr, prtit, ua, llist);
511 } else if (strcasecmp(ua->argk[i], NT_("clients")) == 0) {
512 db_list_client_records(ua->jcr, ua->db, prtit, ua, llist);
514 /* List MEDIA or VOLUMES */
515 } else if (strcasecmp(ua->argk[i], NT_("media")) == 0 ||
516 strcasecmp(ua->argk[i], NT_("volume")) == 0 ||
517 strcasecmp(ua->argk[i], NT_("volumes")) == 0) {
519 for (j=i+1; j<ua->argc; j++) {
520 if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
521 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
523 db_get_job_record(ua->jcr, ua->db, &jr);
525 } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
526 jobid = str_to_int64(ua->argv[j]);
530 VolumeName = get_pool_memory(PM_FNAME);
531 n = db_get_job_volume_names(ua->jcr, ua->db, jobid, &VolumeName);
532 ua->send_msg(_("Jobid %d used %d Volume(s): %s\n"), jobid, n, VolumeName);
533 free_pool_memory(VolumeName);
537 /* if no job or jobid keyword found, then we list all media */
541 /* List a specific volume? */
542 if (ua->argv[i] && *ua->argv[i]) {
543 bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName));
544 db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
547 /* Is a specific pool wanted? */
548 for (i=1; i<ua->argc; i++) {
549 if (strcasecmp(ua->argk[i], NT_("pool")) == 0) {
550 if (!get_pool_dbr(ua, &pr)) {
551 ua->error_msg(_("No Pool specified.\n"));
554 mr.PoolId = pr.PoolId;
555 db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
560 /* List Volumes in all pools */
561 if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
562 ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"),
563 db_strerror(ua->db));
566 if (num_pools <= 0) {
569 for (i=0; i < num_pools; i++) {
571 if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
572 ua->send_msg(_("Pool: %s\n"), pr.Name);
575 db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
580 /* List next volume */
581 } else if (strcasecmp(ua->argk[i], NT_("nextvol")) == 0 ||
582 strcasecmp(ua->argk[i], NT_("nextvolume")) == 0) {
584 j = find_arg_with_value(ua, NT_("days"));
586 n = atoi(ua->argv[j]);
587 if ((n < 0) || (n > 50)) {
588 ua->warning_msg(_("Ignoring invalid value for days. Max is 50.\n"));
593 } else if (strcasecmp(ua->argk[i], NT_("copies")) == 0) {
596 for (j=i+1; j<ua->argc; j++) {
597 if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
598 if (is_a_number_list(ua->argv[j])) {
599 jobids = ua->argv[j];
601 } else if (strcasecmp(ua->argk[j], NT_("limit")) == 0 && ua->argv[j]) {
602 limit = atoi(ua->argv[j]);
605 db_list_copies_records(ua->jcr,ua->db,limit,jobids,prtit,ua,llist);
606 } else if (strcasecmp(ua->argk[i], NT_("limit")) == 0
607 || strcasecmp(ua->argk[i], NT_("days")) == 0
608 || strcasecmp(ua->argk[i], NT_("joberrors")) == 0
609 || strcasecmp(ua->argk[i], NT_("order")) == 0
610 || strcasecmp(ua->argk[i], NT_("jobstatus")) == 0
611 || strcasecmp(ua->argk[i], NT_("client")) == 0
614 } else if (strcasecmp(ua->argk[i], NT_("snapshot")) == 0 ||
615 strcasecmp(ua->argk[i], NT_("snapshots")) == 0)
617 snapshot_list(ua, i, prtit, llist);
621 ua->error_msg(_("Unknown list keyword: %s\n"), NPRT(ua->argk[i]));
627 static bool list_nextvol(UAContext *ua, int ndays)
638 int i = find_arg_with_value(ua, "job");
640 if ((job = select_job_resource(ua)) == NULL) {
644 job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
646 Jmsg(ua->jcr, M_ERROR, 0, _("%s is not a job name.\n"), ua->argv[i]);
647 if ((job = select_job_resource(ua)) == NULL) {
653 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
654 for (run=NULL; (run = find_next_run(run, job, runtime, ndays)); ) {
655 if (!complete_jcr_for_job(jcr, job, run->pool)) {
659 if (!jcr->jr.PoolId) {
660 ua->error_msg(_("Could not find Pool for Job %s\n"), job->name());
663 memset(&pr, 0, sizeof(pr));
664 pr.PoolId = jcr->jr.PoolId;
665 if (!db_get_pool_record(jcr, jcr->db, &pr)) {
666 bstrncpy(pr.Name, "*UnknownPool*", sizeof(pr.Name));
668 mr.PoolId = jcr->jr.PoolId;
669 get_job_storage(&store, job, run);
670 set_storageid_in_mr(store.store, &mr);
671 /* no need to set ScratchPoolId, since we use fnv_no_create_vol */
672 if (!find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_prune)) {
673 ua->error_msg(_("Could not find next Volume for Job %s (Pool=%s, Level=%s).\n"),
674 job->name(), pr.Name, level_to_str(run->level));
677 _("The next Volume to be used by Job \"%s\" (Pool=%s, Level=%s) will be %s\n"),
678 job->name(), pr.Name, level_to_str(run->level), mr.VolumeName);
684 if (jcr->db) db_close_database(jcr, jcr->db);
688 ua->error_msg(_("Could not find next Volume for Job %s.\n"),
697 * For a given job, we examine all his run records
698 * to see if it is scheduled today or tomorrow.
700 RUN *find_next_run(RUN *run, JOB *job, utime_t &runtime, int ndays)
702 time_t now, future, endtime;
705 int mday, wday, month, wom, i;
710 sched = job->schedule;
711 if (!sched || !job->enabled || (sched && !sched->enabled) ||
712 (job->client && !job->client->enabled)) {
713 return NULL; /* no nothing to report */
716 /* Break down the time into components */
718 endtime = now + (ndays * 60 * 60 * 24);
725 for ( ; run; run=run->next) {
727 * Find runs in next 24 hours. Day 0 is today, so if
728 * ndays=1, look at today and tomorrow.
730 for (day = 0; day <= ndays; day++) {
731 future = now + (day * 60 * 60 * 24);
733 /* Break down the time into components */
734 (void)localtime_r(&future, &tm);
735 mday = tm.tm_mday - 1;
739 woy = tm_woy(future);
740 ldom = tm_ldom(month, tm.tm_year + 1900);
742 is_scheduled = (bit_is_set(mday, run->mday) &&
743 bit_is_set(wday, run->wday) &&
744 bit_is_set(month, run->month) &&
745 bit_is_set(wom, run->wom) &&
746 bit_is_set(woy, run->woy)) ||
747 (bit_is_set(month, run->month) &&
748 bit_is_set(31, run->mday) && mday == ldom);
751 Pmsg2(000, "day=%d is_scheduled=%d\n", day, is_scheduled);
752 Pmsg1(000, "bit_set_mday=%d\n", bit_is_set(mday, run->mday));
753 Pmsg1(000, "bit_set_wday=%d\n", bit_is_set(wday, run->wday));
754 Pmsg1(000, "bit_set_month=%d\n", bit_is_set(month, run->month));
755 Pmsg1(000, "bit_set_wom=%d\n", bit_is_set(wom, run->wom));
756 Pmsg1(000, "bit_set_woy=%d\n", bit_is_set(woy, run->woy));
759 if (is_scheduled) { /* Jobs scheduled on that day */
761 char buf[300], num[10];
762 bsnprintf(buf, sizeof(buf), "tm.hour=%d hour=", tm.tm_hour);
763 for (i=0; i<24; i++) {
764 if (bit_is_set(i, run->hour)) {
765 bsnprintf(num, sizeof(num), "%d ", i);
766 bstrncat(buf, num, sizeof(buf));
769 bstrncat(buf, "\n", sizeof(buf));
770 Pmsg1(000, "%s", buf);
772 /* find time (time_t) job is to be run */
773 (void)localtime_r(&future, &runtm);
774 for (i= 0; i < 24; i++) {
775 if (bit_is_set(i, run->hour)) {
777 runtm.tm_min = run->minute;
779 runtime = mktime(&runtm);
780 Dmsg2(200, "now=%d runtime=%lld\n", now, runtime);
781 if ((runtime > now) && (runtime < endtime)) {
782 Dmsg2(200, "Found it level=%d %c\n", run->level, run->level);
783 return run; /* found it, return run resource */
789 } /* end for loop over runs */
795 * Fill in the remaining fields of the jcr as if it
796 * is going to run the job.
798 bool complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool)
802 memset(&pr, 0, sizeof(POOL_DBR));
803 set_jcr_defaults(jcr, job);
805 jcr->pool = pool; /* override */
808 Dmsg0(100, "complete_jcr close db\n");
809 db_close_database(jcr, jcr->db);
813 Dmsg0(100, "complete_jcr open db\n");
814 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
815 jcr->catalog->db_user,
816 jcr->catalog->db_password, jcr->catalog->db_address,
817 jcr->catalog->db_port, jcr->catalog->db_socket,
818 jcr->catalog->db_ssl_key, jcr->catalog->db_ssl_cert, jcr->catalog->db_ssl_ca,
819 jcr->catalog->db_ssl_capath, jcr->catalog->db_ssl_cipher,
820 jcr->catalog->mult_db_connections,
821 jcr->catalog->disable_batch_insert);
822 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
823 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
824 jcr->catalog->db_name);
826 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
827 db_close_database(jcr, jcr->db);
832 bstrncpy(pr.Name, jcr->pool->name(), sizeof(pr.Name));
833 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
834 /* Try to create the pool */
835 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
836 Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
837 db_strerror(jcr->db));
839 db_close_database(jcr, jcr->db);
844 Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
847 jcr->jr.PoolId = pr.PoolId;
852 static void con_lock_release(void *arg)
857 void do_messages(UAContext *ua, const char *cmd)
861 bool do_truncate = false;
864 dequeue_messages(ua->jcr);
867 pthread_cleanup_push(con_lock_release, (void *)NULL);
869 while (fgets(msg, sizeof(msg), con_fd)) {
871 ua->UA_sock->msg = check_pool_memory_size(ua->UA_sock->msg, mlen+1);
872 strcpy(ua->UA_sock->msg, msg);
873 ua->UA_sock->msglen = mlen;
878 (void)ftruncate(fileno(con_fd), 0L);
880 console_msg_pending = FALSE;
881 ua->user_notified_msg_pending = FALSE;
882 pthread_cleanup_pop(0);
887 int qmessagescmd(UAContext *ua, const char *cmd)
889 if (console_msg_pending && ua->auto_display_messages) {
890 do_messages(ua, cmd);
895 int messagescmd(UAContext *ua, const char *cmd)
897 if (console_msg_pending) {
898 do_messages(ua, cmd);
900 ua->UA_sock->fsend(_("You have no messages.\n"));
906 * Callback routine for "printing" database file listing
908 void prtit(void *ctx, const char *msg)
910 UAContext *ua = (UAContext *)ctx;
912 if (ua) ua->send_msg("%s", msg);
916 * Format message and send to other end.
918 * If the UA_sock is NULL, it means that there is no user
919 * agent, so we are being called from Bacula core. In
920 * that case direct the messages to the Job.
923 void bmsg(UAContext *ua, const char *fmt, va_list arg_ptr)
925 BSOCK *bs = ua->UA_sock;
934 msg = get_pool_memory(PM_EMSG);
938 maxlen = sizeof_pool_memory(msg) - 1;
939 va_copy(ap, arg_ptr);
940 len = bvsnprintf(msg, maxlen, fmt, ap);
942 if (len < 0 || len >= maxlen) {
943 msg = realloc_pool_memory(msg, maxlen + maxlen/2);
951 } else { /* No UA, send to Job */
952 Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
953 free_pool_memory(msg);
958 #else /* no va_copy() -- brain damaged version of variable arguments */
960 void bmsg(UAContext *ua, const char *fmt, va_list arg_ptr)
962 BSOCK *bs = ua->UA_sock;
970 msg = get_memory(5000);
973 maxlen = sizeof_pool_memory(msg) - 1;
975 msg = realloc_pool_memory(msg, 5000);
978 len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
979 if (len < 0 || len >= maxlen) {
980 pm_strcpy(msg, _("Message too long to display.\n"));
988 } else { /* No UA, send to Job */
989 Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
990 free_pool_memory(msg);
996 void bsendmsg(void *ctx, const char *fmt, ...)
999 va_start(arg_ptr, fmt);
1000 bmsg((UAContext *)ctx, fmt, arg_ptr);
1005 * The following UA methods are mainly intended for GUI
1009 * This is a message that should be displayed on the user's
1012 void UAContext::send_msg(const char *fmt, ...)
1015 va_start(arg_ptr, fmt);
1016 bmsg(this, fmt, arg_ptr);
1022 * This is an error condition with a command. The gui should put
1023 * up an error or critical dialog box. The command is aborted.
1025 void UAContext::error_msg(const char *fmt, ...)
1027 BSOCK *bs = UA_sock;
1030 if (bs && api) bs->signal(BNET_ERROR_MSG);
1031 va_start(arg_ptr, fmt);
1032 bmsg(this, fmt, arg_ptr);
1037 * This is a warning message, that should bring up a warning
1038 * dialog box on the GUI. The command is not aborted, but something
1041 void UAContext::warning_msg(const char *fmt, ...)
1043 BSOCK *bs = UA_sock;
1046 if (bs && api) bs->signal(BNET_WARNING_MSG);
1047 va_start(arg_ptr, fmt);
1048 bmsg(this, fmt, arg_ptr);
1053 * This is an information message that should probably be put
1054 * into the status line of a GUI program.
1056 void UAContext::info_msg(const char *fmt, ...)
1058 BSOCK *bs = UA_sock;
1061 if (bs && api) bs->signal(BNET_INFO_MSG);
1062 va_start(arg_ptr, fmt);
1063 bmsg(this, fmt, arg_ptr);