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];
176 /* Dump a single resource with specified name */
178 len = strlen(res_name);
179 for (j=0; reses[j].res_name; j++) {
180 if (strncasecmp(res_name, reses[j].res_name, len) == 0) {
181 type = reses[j].type;
182 res = (RES *)GetResWithName(type, ua->argv[i]);
194 for (j=r_first; j<=r_last; j++) {
195 /* Skip R_DEVICE since it is really not used or updated */
197 dump_resource(j, res_head[j-r_first], bsendmsg, ua);
203 ua->send_msg(_("Keywords for the show command are:\n"));
204 for (j=0; reses[j].res_name; j++) {
205 ua->error_msg("%s\n", reses[j].res_name);
208 /* Resource not found */
210 ua->error_msg(_("%s resource %s not found.\n"), res_name, ua->argv[i]);
212 /* Resource not found */
214 ua->error_msg(_("Resource %s not found\n"), res_name);
216 /* Dump a specific type */
218 dump_resource(recurse?type:-type, res, bsendmsg, ua);
228 * Check if the access is permitted for a list of jobids
230 * Not in ua_acl.c because it's using db access, and tools such
231 * as bdirjson are not linked with cats.
233 bool acl_access_jobid_ok(UAContext *ua, const char *jobids)
244 if (!is_a_number_list(jobids)) {
248 /* If no console resource => default console and all is permitted */
249 if (!ua || !ua->cons) {
250 Dmsg0(1400, "Root cons access OK.\n");
251 return true; /* No cons resource -> root console OK for everything */
254 alist *list = ua->cons->ACL_lists[Job_ACL];
255 if (!list) { /* empty list */
256 return false; /* List empty, reject everything */
259 /* Special case *all* gives full access */
260 if (list->size() == 1 && strcasecmp("*all*", (char *)list->get(0)) == 0) {
264 /* If we can't open the database, just say no */
265 if (!open_new_client_db(ua)) {
269 p = tmp = bstrdup(jobids);
271 while (get_next_jobid_from_list(&p, &jid) > 0) {
272 memset(&jr, 0, sizeof(jr));
275 if (db_get_job_record(ua->jcr, ua->db, &jr)) {
276 for (int i=0; i<list->size(); i++) {
277 if (strcasecmp(jr.Name, (char *)list->get(i)) == 0) {
278 Dmsg3(1400, "ACL found %s in %d %s\n", jr.Name,
279 Job_ACL, (char *)list->get(i));
295 * List contents of database
297 * list jobs - lists all jobs run
298 * list jobid=nnn - list job data for jobid
299 * list ujobid=uname - list job data for unique jobid
300 * list job=name - list all jobs with "name"
301 * list jobname=name - same as above
302 * list jobmedia jobid=<nn>
303 * list jobmedia job=name
304 * list joblog jobid=<nn>
305 * list joblog job=name
306 * list files jobid=<nn> - list files saved for job nn
307 * list files job=name
308 * list pools - list pool records
309 * list jobtotals - list totals for all jobs
310 * list media - list media for given pool (deprecated)
311 * list volumes - list Volumes
312 * list clients - list clients
313 * list nextvol job=xx - list the next vol to be used by job
314 * list nextvolume job=xx - same as above.
315 * list copies jobid=x,y,z
319 /* Do long or full listing */
320 int llist_cmd(UAContext *ua, const char *cmd)
322 return do_list_cmd(ua, cmd, VERT_LIST);
325 /* Do short or summary listing */
326 int list_cmd(UAContext *ua, const char *cmd)
328 return do_list_cmd(ua, cmd, HORZ_LIST);
331 static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
340 if (!open_new_client_db(ua))
343 memset(&jr, 0, sizeof(jr));
344 memset(&pr, 0, sizeof(pr));
346 Dmsg1(20, "list: %s\n", cmd);
349 ua->error_msg(_("Hey! DB is NULL\n"));
351 /* Apply any limit */
352 for (j = 1; j < ua->argc ; j++) {
353 if (strcasecmp(ua->argk[j], NT_("joberrors")) == 0) {
355 } else if (!ua->argv[j]) {
357 } else if (strcasecmp(ua->argk[j], NT_("order")) == 0) {
358 if (strcasecmp(ua->argv[j], NT_("desc")) == 0 ||
359 strcasecmp(ua->argv[j], NT_("descending")) == 0) {
361 } else if (strcasecmp(ua->argv[j], NT_("asc")) == 0 ||
362 strcasecmp(ua->argv[j], NT_("ascending")) == 0) {
365 ua->error_msg(_("Unknown order type %s\n"), ua->argv[j]);
368 } else if (strcasecmp(ua->argk[j], NT_("limit")) == 0) {
369 jr.limit = atoi(ua->argv[j]);
371 } else if (strcasecmp(ua->argk[j], NT_("jobstatus")) == 0) {
372 if (B_ISALPHA(ua->argv[j][0])) {
373 jr.JobStatus = ua->argv[j][0];
375 } else if (strcasecmp(ua->argk[j], NT_("client")) == 0) {
376 if (is_name_valid(ua->argv[j], NULL)) {
378 memset(&cr, 0, sizeof(cr));
379 if(get_client_dbr(ua, &cr)) {
380 jr.ClientId = cr.ClientId;
386 /* Scan arguments looking for things to do */
387 for (i=1; i<ua->argc; i++) {
389 if (strcasecmp(ua->argk[i], NT_("jobs")) == 0) {
390 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
393 } else if (strcasecmp(ua->argk[i], NT_("jobtotals")) == 0) {
394 db_list_job_totals(ua->jcr, ua->db, &jr, prtit, ua);
397 } else if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
399 jobid = str_to_int64(ua->argv[i]);
402 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
407 } else if ((strcasecmp(ua->argk[i], NT_("job")) == 0 ||
408 strcasecmp(ua->argk[i], NT_("jobname")) == 0) && ua->argv[i]) {
409 bstrncpy(jr.Name, ua->argv[i], MAX_NAME_LENGTH);
411 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
413 /* List UJOBID=xxx */
414 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0 && ua->argv[i]) {
415 bstrncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
417 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
419 /* List Base files */
420 } else if (strcasecmp(ua->argk[i], NT_("basefiles")) == 0) {
421 /* TODO: cleanup this block */
422 for (j=i+1; j<ua->argc; j++) {
423 if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
424 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
426 db_get_job_record(ua->jcr, ua->db, &jr);
428 } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
429 jobid = str_to_int64(ua->argv[j]);
434 db_list_base_files_for_job(ua->jcr, ua->db, jobid, prtit, ua);
439 } else if (strcasecmp(ua->argk[i], NT_("files")) == 0) {
441 for (j=i+1; j<ua->argc; j++) {
442 if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
443 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
445 db_get_job_record(ua->jcr, ua->db, &jr);
447 } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
448 jobid = str_to_int64(ua->argv[j]);
453 db_list_files_for_job(ua->jcr, ua->db, jobid, prtit, ua);
458 } else if (strcasecmp(ua->argk[i], NT_("jobmedia")) == 0) {
460 for (j=i+1; j<ua->argc; j++) {
461 if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
462 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
464 db_get_job_record(ua->jcr, ua->db, &jr);
466 } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
467 jobid = str_to_int64(ua->argv[j]);
471 db_list_jobmedia_records(ua->jcr, ua->db, jobid, prtit, ua, llist);
475 /* List for all jobs (jobid=0) */
476 db_list_jobmedia_records(ua->jcr, ua->db, 0, prtit, ua, llist);
480 } else if (strcasecmp(ua->argk[i], NT_("joblog")) == 0) {
482 for (j=i+1; j<ua->argc; j++) {
483 if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
484 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
486 db_get_job_record(ua->jcr, ua->db, &jr);
488 } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
489 jobid = str_to_int64(ua->argv[j]);
493 db_list_joblog_records(ua->jcr, ua->db, jobid, prtit, ua, llist);
497 /* List for all jobs (jobid=0) */
498 db_list_joblog_records(ua->jcr, ua->db, 0, prtit, ua, llist);
503 } else if (strcasecmp(ua->argk[i], NT_("pool")) == 0 ||
504 strcasecmp(ua->argk[i], NT_("pools")) == 0) {
506 memset(&pr, 0, sizeof(pr));
508 bstrncpy(pr.Name, ua->argv[i], sizeof(pr.Name));
510 db_list_pool_records(ua->jcr, ua->db, &pr, prtit, ua, llist);
512 } else if (strcasecmp(ua->argk[i], NT_("clients")) == 0) {
513 db_list_client_records(ua->jcr, ua->db, prtit, ua, llist);
515 /* List MEDIA or VOLUMES */
516 } else if (strcasecmp(ua->argk[i], NT_("media")) == 0 ||
517 strcasecmp(ua->argk[i], NT_("volume")) == 0 ||
518 strcasecmp(ua->argk[i], NT_("volumes")) == 0) {
520 for (j=i+1; j<ua->argc; j++) {
521 if (strcasecmp(ua->argk[j], NT_("ujobid")) == 0 && ua->argv[j]) {
522 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
524 db_get_job_record(ua->jcr, ua->db, &jr);
526 } else if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
527 jobid = str_to_int64(ua->argv[j]);
531 VolumeName = get_pool_memory(PM_FNAME);
532 n = db_get_job_volume_names(ua->jcr, ua->db, jobid, &VolumeName);
533 ua->send_msg(_("Jobid %d used %d Volume(s): %s\n"), jobid, n, VolumeName);
534 free_pool_memory(VolumeName);
538 /* if no job or jobid keyword found, then we list all media */
542 /* List a specific volume? */
543 if (ua->argv[i] && *ua->argv[i]) {
544 bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName));
545 db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
548 /* Is a specific pool wanted? */
549 for (i=1; i<ua->argc; i++) {
550 if (strcasecmp(ua->argk[i], NT_("pool")) == 0) {
551 if (!get_pool_dbr(ua, &pr)) {
552 ua->error_msg(_("No Pool specified.\n"));
555 mr.PoolId = pr.PoolId;
556 db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
561 /* List Volumes in all pools */
562 if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
563 ua->error_msg(_("Error obtaining pool ids. ERR=%s\n"),
564 db_strerror(ua->db));
567 if (num_pools <= 0) {
570 for (i=0; i < num_pools; i++) {
572 if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
573 ua->send_msg(_("Pool: %s\n"), pr.Name);
576 db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
581 /* List next volume */
582 } else if (strcasecmp(ua->argk[i], NT_("nextvol")) == 0 ||
583 strcasecmp(ua->argk[i], NT_("nextvolume")) == 0) {
585 j = find_arg_with_value(ua, NT_("days"));
587 n = atoi(ua->argv[j]);
588 if ((n < 0) || (n > 50)) {
589 ua->warning_msg(_("Ignoring invalid value for days. Max is 50.\n"));
594 } else if (strcasecmp(ua->argk[i], NT_("copies")) == 0) {
597 for (j=i+1; j<ua->argc; j++) {
598 if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
599 if (is_a_number_list(ua->argv[j])) {
600 jobids = ua->argv[j];
602 } else if (strcasecmp(ua->argk[j], NT_("limit")) == 0 && ua->argv[j]) {
603 limit = atoi(ua->argv[j]);
606 db_list_copies_records(ua->jcr,ua->db,limit,jobids,prtit,ua,llist);
607 } else if (strcasecmp(ua->argk[i], NT_("limit")) == 0
608 || strcasecmp(ua->argk[i], NT_("days")) == 0
609 || strcasecmp(ua->argk[i], NT_("joberrors")) == 0
610 || strcasecmp(ua->argk[i], NT_("order")) == 0
611 || strcasecmp(ua->argk[i], NT_("jobstatus")) == 0
612 || strcasecmp(ua->argk[i], NT_("client")) == 0
615 } else if (strcasecmp(ua->argk[i], NT_("snapshot")) == 0 ||
616 strcasecmp(ua->argk[i], NT_("snapshots")) == 0)
618 snapshot_list(ua, i, prtit, llist);
622 ua->error_msg(_("Unknown list keyword: %s\n"), NPRT(ua->argk[i]));
628 static bool list_nextvol(UAContext *ua, int ndays)
639 int i = find_arg_with_value(ua, "job");
641 if ((job = select_job_resource(ua)) == NULL) {
645 job = (JOB *)GetResWithName(R_JOB, ua->argv[i]);
647 Jmsg(ua->jcr, M_ERROR, 0, _("%s is not a job name.\n"), ua->argv[i]);
648 if ((job = select_job_resource(ua)) == NULL) {
654 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
655 for (run=NULL; (run = find_next_run(run, job, runtime, ndays)); ) {
656 if (!complete_jcr_for_job(jcr, job, run->pool)) {
660 if (!jcr->jr.PoolId) {
661 ua->error_msg(_("Could not find Pool for Job %s\n"), job->name());
664 memset(&pr, 0, sizeof(pr));
665 pr.PoolId = jcr->jr.PoolId;
666 if (!db_get_pool_record(jcr, jcr->db, &pr)) {
667 bstrncpy(pr.Name, "*UnknownPool*", sizeof(pr.Name));
669 mr.PoolId = jcr->jr.PoolId;
670 get_job_storage(&store, job, run);
671 set_storageid_in_mr(store.store, &mr);
672 /* no need to set ScratchPoolId, since we use fnv_no_create_vol */
673 if (!find_next_volume_for_append(jcr, &mr, 1, fnv_no_create_vol, fnv_prune)) {
674 ua->error_msg(_("Could not find next Volume for Job %s (Pool=%s, Level=%s).\n"),
675 job->name(), pr.Name, level_to_str(run->level));
678 _("The next Volume to be used by Job \"%s\" (Pool=%s, Level=%s) will be %s\n"),
679 job->name(), pr.Name, level_to_str(run->level), mr.VolumeName);
685 if (jcr->db) db_close_database(jcr, jcr->db);
689 ua->error_msg(_("Could not find next Volume for Job %s.\n"),
698 * For a given job, we examine all his run records
699 * to see if it is scheduled today or tomorrow.
701 RUN *find_next_run(RUN *run, JOB *job, utime_t &runtime, int ndays)
703 time_t now, future, endtime;
706 int mday, wday, month, wom, i;
711 sched = job->schedule;
712 if (!sched || !job->enabled || (sched && !sched->enabled) ||
713 (job->client && !job->client->enabled)) {
714 return NULL; /* no nothing to report */
717 /* Break down the time into components */
719 endtime = now + (ndays * 60 * 60 * 24);
726 for ( ; run; run=run->next) {
728 * Find runs in next 24 hours. Day 0 is today, so if
729 * ndays=1, look at today and tomorrow.
731 for (day = 0; day <= ndays; day++) {
732 future = now + (day * 60 * 60 * 24);
734 /* Break down the time into components */
735 (void)localtime_r(&future, &tm);
736 mday = tm.tm_mday - 1;
740 woy = tm_woy(future);
741 ldom = tm_ldom(month, tm.tm_year + 1900);
743 is_scheduled = (bit_is_set(mday, run->mday) &&
744 bit_is_set(wday, run->wday) &&
745 bit_is_set(month, run->month) &&
746 bit_is_set(wom, run->wom) &&
747 bit_is_set(woy, run->woy)) ||
748 (bit_is_set(month, run->month) &&
749 bit_is_set(31, run->mday) && mday == ldom);
752 Pmsg2(000, "day=%d is_scheduled=%d\n", day, is_scheduled);
753 Pmsg1(000, "bit_set_mday=%d\n", bit_is_set(mday, run->mday));
754 Pmsg1(000, "bit_set_wday=%d\n", bit_is_set(wday, run->wday));
755 Pmsg1(000, "bit_set_month=%d\n", bit_is_set(month, run->month));
756 Pmsg1(000, "bit_set_wom=%d\n", bit_is_set(wom, run->wom));
757 Pmsg1(000, "bit_set_woy=%d\n", bit_is_set(woy, run->woy));
760 if (is_scheduled) { /* Jobs scheduled on that day */
762 char buf[300], num[10];
763 bsnprintf(buf, sizeof(buf), "tm.hour=%d hour=", tm.tm_hour);
764 for (i=0; i<24; i++) {
765 if (bit_is_set(i, run->hour)) {
766 bsnprintf(num, sizeof(num), "%d ", i);
767 bstrncat(buf, num, sizeof(buf));
770 bstrncat(buf, "\n", sizeof(buf));
771 Pmsg1(000, "%s", buf);
773 /* find time (time_t) job is to be run */
774 (void)localtime_r(&future, &runtm);
775 for (i= 0; i < 24; i++) {
776 if (bit_is_set(i, run->hour)) {
778 runtm.tm_min = run->minute;
780 runtime = mktime(&runtm);
781 Dmsg2(200, "now=%d runtime=%lld\n", now, runtime);
782 if ((runtime > now) && (runtime < endtime)) {
783 Dmsg2(200, "Found it level=%d %c\n", run->level, run->level);
784 return run; /* found it, return run resource */
790 } /* end for loop over runs */
796 * Fill in the remaining fields of the jcr as if it
797 * is going to run the job.
799 bool complete_jcr_for_job(JCR *jcr, JOB *job, POOL *pool)
803 memset(&pr, 0, sizeof(POOL_DBR));
804 set_jcr_defaults(jcr, job);
806 jcr->pool = pool; /* override */
809 Dmsg0(100, "complete_jcr close db\n");
810 db_close_database(jcr, jcr->db);
814 Dmsg0(100, "complete_jcr open db\n");
815 jcr->db = db_init_database(jcr, jcr->catalog->db_driver, jcr->catalog->db_name,
816 jcr->catalog->db_user,
817 jcr->catalog->db_password, jcr->catalog->db_address,
818 jcr->catalog->db_port, jcr->catalog->db_socket,
819 jcr->catalog->db_ssl_key, jcr->catalog->db_ssl_cert, jcr->catalog->db_ssl_ca,
820 jcr->catalog->db_ssl_capath, jcr->catalog->db_ssl_cipher,
821 jcr->catalog->mult_db_connections,
822 jcr->catalog->disable_batch_insert);
823 if (!jcr->db || !db_open_database(jcr, jcr->db)) {
824 Jmsg(jcr, M_FATAL, 0, _("Could not open database \"%s\".\n"),
825 jcr->catalog->db_name);
827 Jmsg(jcr, M_FATAL, 0, "%s", db_strerror(jcr->db));
828 db_close_database(jcr, jcr->db);
833 bstrncpy(pr.Name, jcr->pool->name(), sizeof(pr.Name));
834 while (!db_get_pool_record(jcr, jcr->db, &pr)) { /* get by Name */
835 /* Try to create the pool */
836 if (create_pool(jcr, jcr->db, jcr->pool, POOL_OP_CREATE) < 0) {
837 Jmsg(jcr, M_FATAL, 0, _("Pool %s not in database. %s"), pr.Name,
838 db_strerror(jcr->db));
840 db_close_database(jcr, jcr->db);
845 Jmsg(jcr, M_INFO, 0, _("Pool %s created in database.\n"), pr.Name);
848 jcr->jr.PoolId = pr.PoolId;
853 static void con_lock_release(void *arg)
858 void do_messages(UAContext *ua, const char *cmd)
862 bool do_truncate = false;
865 dequeue_messages(ua->jcr);
868 pthread_cleanup_push(con_lock_release, (void *)NULL);
870 while (fgets(msg, sizeof(msg), con_fd)) {
872 ua->UA_sock->msg = check_pool_memory_size(ua->UA_sock->msg, mlen+1);
873 strcpy(ua->UA_sock->msg, msg);
874 ua->UA_sock->msglen = mlen;
879 (void)ftruncate(fileno(con_fd), 0L);
881 console_msg_pending = FALSE;
882 ua->user_notified_msg_pending = FALSE;
883 pthread_cleanup_pop(0);
888 int qmessagescmd(UAContext *ua, const char *cmd)
890 if (console_msg_pending && ua->auto_display_messages) {
891 do_messages(ua, cmd);
896 int messagescmd(UAContext *ua, const char *cmd)
898 if (console_msg_pending) {
899 do_messages(ua, cmd);
901 ua->UA_sock->fsend(_("You have no messages.\n"));
907 * Callback routine for "printing" database file listing
909 void prtit(void *ctx, const char *msg)
911 UAContext *ua = (UAContext *)ctx;
913 if (ua) ua->send_msg("%s", msg);
917 * Format message and send to other end.
919 * If the UA_sock is NULL, it means that there is no user
920 * agent, so we are being called from Bacula core. In
921 * that case direct the messages to the Job.
924 void bmsg(UAContext *ua, const char *fmt, va_list arg_ptr)
926 BSOCK *bs = ua->UA_sock;
935 msg = get_pool_memory(PM_EMSG);
939 maxlen = sizeof_pool_memory(msg) - 1;
940 va_copy(ap, arg_ptr);
941 len = bvsnprintf(msg, maxlen, fmt, ap);
943 if (len < 0 || len >= maxlen) {
944 msg = realloc_pool_memory(msg, maxlen + maxlen/2);
952 } else { /* No UA, send to Job */
953 Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
954 free_pool_memory(msg);
959 #else /* no va_copy() -- brain damaged version of variable arguments */
961 void bmsg(UAContext *ua, const char *fmt, va_list arg_ptr)
963 BSOCK *bs = ua->UA_sock;
971 msg = get_memory(5000);
974 maxlen = sizeof_pool_memory(msg) - 1;
976 msg = realloc_pool_memory(msg, 5000);
979 len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
980 if (len < 0 || len >= maxlen) {
981 pm_strcpy(msg, _("Message too long to display.\n"));
989 } else { /* No UA, send to Job */
990 Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
991 free_pool_memory(msg);
997 void bsendmsg(void *ctx, const char *fmt, ...)
1000 va_start(arg_ptr, fmt);
1001 bmsg((UAContext *)ctx, fmt, arg_ptr);
1006 * The following UA methods are mainly intended for GUI
1010 * This is a message that should be displayed on the user's
1013 void UAContext::send_msg(const char *fmt, ...)
1016 va_start(arg_ptr, fmt);
1017 bmsg(this, fmt, arg_ptr);
1023 * This is an error condition with a command. The gui should put
1024 * up an error or critical dialog box. The command is aborted.
1026 void UAContext::error_msg(const char *fmt, ...)
1028 BSOCK *bs = UA_sock;
1031 if (bs && api) bs->signal(BNET_ERROR_MSG);
1032 va_start(arg_ptr, fmt);
1033 bmsg(this, fmt, arg_ptr);
1038 * This is a warning message, that should bring up a warning
1039 * dialog box on the GUI. The command is not aborted, but something
1042 void UAContext::warning_msg(const char *fmt, ...)
1044 BSOCK *bs = UA_sock;
1047 if (bs && api) bs->signal(BNET_WARNING_MSG);
1048 va_start(arg_ptr, fmt);
1049 bmsg(this, fmt, arg_ptr);
1054 * This is an information message that should probably be put
1055 * into the status line of a GUI program.
1057 void UAContext::info_msg(const char *fmt, ...)
1059 BSOCK *bs = UA_sock;
1062 if (bs && api) bs->signal(BNET_INFO_MSG);
1063 va_start(arg_ptr, fmt);
1064 bmsg(this, fmt, arg_ptr);