3 * Bacula Director -- User Agent Output Commands
4 * I.e. messages, listing database, showing resources, ...
6 * Kern Sibbald, September MM
12 Copyright (C) 2000-2003 Kern Sibbald and John Walker
14 This program is free software; you can redistribute it and/or
15 modify it under the terms of the GNU General Public License as
16 published by the Free Software Foundation; either version 2 of
17 the License, or (at your option) any later version.
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 General Public License for more details.
24 You should have received a copy of the GNU General Public
25 License along with this program; if not, write to the Free
26 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
34 /* Imported subroutines */
35 extern void run_job(JCR *jcr);
37 /* Imported variables */
40 extern struct s_res resources[];
41 extern int console_msg_pending;
43 extern brwlock_t con_lock;
46 /* Imported functions */
48 /* Forward referenced functions */
49 static int do_listcmd(UAContext *ua, char *cmd, int llist);
53 * Turn auto display of console messages on/off
55 int autodisplaycmd(UAContext *ua, char *cmd)
62 switch (find_arg_keyword(ua, kw)) {
64 ua->auto_display_messages = 1;
67 ua->auto_display_messages = 0;
70 bsendmsg(ua, _("ON or OFF keyword missing.\n"));
77 struct showstruct {char *res_name; int type;};
78 static struct showstruct reses[] = {
79 {N_("directors"), R_DIRECTOR},
80 {N_("clients"), R_CLIENT},
82 {N_("storages"), R_STORAGE},
83 {N_("catalogs"), R_CATALOG},
84 {N_("schedules"), R_SCHEDULE},
85 {N_("filesets"), R_FILESET},
86 {N_("groups"), R_GROUP},
87 {N_("pools"), R_POOL},
88 {N_("messages"), R_MSGS},
99 * show <resource-keyword-name> e.g. show directors
100 * show <resource-keyword-name>=<name> e.g. show director=HeadMan
103 int showcmd(UAContext *ua, char *cmd)
110 Dmsg1(20, "show: %s\n", ua->UA_sock->msg);
113 for (i=1; i<ua->argc; i++) {
115 res_name = ua->argk[i];
116 if (!ua->argv[i]) { /* was a name given? */
117 /* No name, dump all resources of specified type */
119 len = strlen(res_name);
120 for (j=0; reses[j].res_name; j++) {
121 if (strncasecmp(res_name, _(reses[j].res_name), len) == 0) {
122 type = reses[j].type;
124 res = resources[type-r_first].res_head;
132 /* Dump a single resource with specified name */
134 len = strlen(res_name);
135 for (j=0; reses[j].res_name; j++) {
136 if (strncasecmp(res_name, _(reses[j].res_name), len) == 0) {
137 type = reses[j].type;
138 res = (RES *)GetResWithName(type, ua->argv[i]);
149 for (j=r_first; j<=r_last; j++) {
150 dump_resource(j, resources[j-r_first].res_head, bsendmsg, ua);
154 bsendmsg(ua, _("Keywords for the show command are:\n"));
155 for (j=0; reses[j].res_name; j++) {
156 bsendmsg(ua, "%s\n", _(reses[j].res_name));
160 bsendmsg(ua, _("%s resource %s not found.\n"), res_name, ua->argv[i]);
163 bsendmsg(ua, _("Resource %s not found\n"), res_name);
166 dump_resource(recurse?type:-type, res, bsendmsg, ua);
177 * List contents of database
179 * list jobs - lists all jobs run
180 * list jobid=nnn - list job data for jobid
181 * list job=name - list job data for job
182 * list jobmedia jobid=<nn>
183 * list jobmedia job=name
184 * list files jobid=<nn> - list files saved for job nn
185 * list files job=name
186 * list pools - list pool records
187 * list jobtotals - list totals for all jobs
188 * list media - list media for given pool (deprecated)
189 * list volumes - list Volumes
190 * list clients - list clients
194 /* Do long or full listing */
195 int llistcmd(UAContext *ua, char *cmd)
197 return do_listcmd(ua, cmd, 1);
200 /* Do short or summary listing */
201 int listcmd(UAContext *ua, char *cmd)
203 return do_listcmd(ua, cmd, 0);
206 static int do_listcmd(UAContext *ua, char *cmd, int llist)
218 memset(&jr, 0, sizeof(jr));
219 memset(&pr, 0, sizeof(pr));
220 memset(&mr, 0, sizeof(mr));
222 Dmsg1(20, "list: %s\n", cmd);
225 bsendmsg(ua, _("Hey! DB is NULL\n"));
228 /* Scan arguments looking for things to do */
229 for (i=1; i<ua->argc; i++) {
231 if (strcasecmp(ua->argk[i], _("jobs")) == 0) {
232 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua);
235 } else if (strcasecmp(ua->argk[i], _("jobtotals")) == 0) {
236 db_list_job_totals(ua->jcr, ua->db, &jr, prtit, ua);
239 } else if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
241 jobid = atoi(ua->argv[i]);
244 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua);
249 } else if (strcasecmp(ua->argk[i], _("job")) == 0 && ua->argv[i]) {
250 bstrncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
252 db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua);
255 } else if (strcasecmp(ua->argk[i], _("files")) == 0) {
257 for (j=i+1; j<ua->argc; j++) {
258 if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
259 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
261 db_get_job_record(ua->jcr, ua->db, &jr);
263 } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
264 jobid = atoi(ua->argv[j]);
269 db_list_files_for_job(ua->jcr, ua->db, jobid, prtit, ua);
274 } else if (strcasecmp(ua->argk[i], _("jobmedia")) == 0) {
276 for (j=i+1; j<ua->argc; j++) {
277 if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
278 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
280 db_get_job_record(ua->jcr, ua->db, &jr);
282 } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
283 jobid = atoi(ua->argv[j]);
287 db_list_jobmedia_records(ua->jcr, ua->db, jobid, prtit, ua);
291 /* List for all jobs (jobid=0) */
292 db_list_jobmedia_records(ua->jcr, ua->db, 0, prtit, ua);
296 } else if (strcasecmp(ua->argk[i], _("pools")) == 0) {
297 db_list_pool_records(ua->jcr, ua->db, prtit, ua);
299 } else if (strcasecmp(ua->argk[i], _("clients")) == 0) {
300 db_list_client_records(ua->jcr, ua->db, prtit, ua);
303 /* List MEDIA or VOLUMES */
304 } else if (strcasecmp(ua->argk[i], _("media")) == 0 ||
305 strcasecmp(ua->argk[i], _("volumes")) == 0) {
307 for (j=i+1; j<ua->argc; j++) {
308 if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
309 bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
311 db_get_job_record(ua->jcr, ua->db, &jr);
313 } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
314 jobid = atoi(ua->argv[j]);
318 VolumeName = get_pool_memory(PM_FNAME);
319 n = db_get_job_volume_names(ua->jcr, ua->db, jobid, &VolumeName);
320 bsendmsg(ua, _("Jobid %d used %d Volume(s): %s\n"), jobid, n, VolumeName);
321 free_pool_memory(VolumeName);
324 /* if no job or jobid keyword found, then we list all media */
328 /* Is a specific pool wanted? */
329 for (i=1; i<ua->argc; i++) {
330 if (strcasecmp(ua->argk[i], _("pool")) == 0) {
331 if (!get_pool_dbr(ua, &pr)) {
334 mr.PoolId = pr.PoolId;
335 db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua);
339 /* List Volumes in all pools */
340 if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
341 bsendmsg(ua, _("Error obtaining pool ids. ERR=%s\n"),
342 db_strerror(ua->db));
345 if (num_pools <= 0) {
348 for (i=0; i < num_pools; i++) {
350 if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
351 bsendmsg(ua, _("Pool: %s\n"), pr.Name);
354 db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua);
360 bsendmsg(ua, _("Unknown list keyword: %s\n"), NPRT(ua->argk[i]));
366 static void con_lock_release(void *arg)
371 void do_messages(UAContext *ua, char *cmd)
375 int do_truncate = FALSE;
378 pthread_cleanup_push(con_lock_release, (void *)NULL);
380 while (fgets(msg, sizeof(msg), con_fd)) {
382 ua->UA_sock->msg = check_pool_memory_size(ua->UA_sock->msg, mlen+1);
383 strcpy(ua->UA_sock->msg, msg);
384 ua->UA_sock->msglen = mlen;
385 bnet_send(ua->UA_sock);
389 ftruncate(fileno(con_fd), 0L);
391 console_msg_pending = FALSE;
392 ua->user_notified_msg_pending = FALSE;
393 pthread_cleanup_pop(0);
398 int qmessagescmd(UAContext *ua, char *cmd)
400 if (console_msg_pending && ua->auto_display_messages) {
401 do_messages(ua, cmd);
406 int messagescmd(UAContext *ua, char *cmd)
408 if (console_msg_pending) {
409 do_messages(ua, cmd);
411 bnet_fsend(ua->UA_sock, _("You have no messages.\n"));
417 * Callback routine for "printing" database file listing
419 void prtit(void *ctx, char *msg)
421 UAContext *ua = (UAContext *)ctx;
423 bnet_fsend(ua->UA_sock, "%s", msg);
427 * Format message and send to other end.
429 * If the UA_sock is NULL, it means that there is no user
430 * agent, so we are being called from Bacula core. In
431 * that case direct the messages to the Job.
433 void bsendmsg(void *ctx, char *fmt, ...)
436 UAContext *ua = (UAContext *)ctx;
437 BSOCK *bs = ua->UA_sock;
444 msg = get_pool_memory(PM_EMSG);
448 maxlen = sizeof_pool_memory(msg) - 1;
449 va_start(arg_ptr, fmt);
450 len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
452 if (len < 0 || len >= maxlen) {
453 msg = realloc_pool_memory(msg, maxlen + 200);
460 } else { /* No UA, send to Job */
461 Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
462 free_pool_memory(msg);