]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_output.c
Update doc
[bacula/bacula] / bacula / src / dird / ua_output.c
1 /*
2  *
3  *   Bacula Director -- User Agent Output Commands
4  *     I.e. messages, listing database, showing resources, ...
5  *
6  *     Kern Sibbald, September MM
7  *
8  *   Version $Id$
9  */
10
11 /*
12    Copyright (C) 2000-2003 Kern Sibbald and John Walker
13
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.
18
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.
23
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,
27    MA 02111-1307, USA.
28
29  */
30
31 #include "bacula.h"
32 #include "dird.h"
33
34 /* Imported subroutines */
35 extern void run_job(JCR *jcr);
36
37 /* Imported variables */
38 extern int r_first;
39 extern int r_last;
40 extern struct s_res resources[];
41 extern int console_msg_pending;
42 extern FILE *con_fd;
43 extern brwlock_t con_lock;
44
45
46 /* Imported functions */
47
48 /* Forward referenced functions */
49 static int do_listcmd(UAContext *ua, char *cmd, int llist);
50
51
52 /*
53  * Turn auto display of console messages on/off
54  */
55 int autodisplaycmd(UAContext *ua, char *cmd)
56 {
57    static char *kw[] = {
58       N_("on"), 
59       N_("off"),
60       NULL};
61
62    switch (find_arg_keyword(ua, kw)) {
63       case 0:
64          ua->auto_display_messages = 1;
65          break;
66       case 1:
67          ua->auto_display_messages = 0;
68          break;
69       default:
70          bsendmsg(ua, _("ON or OFF keyword missing.\n"));
71          break;
72    }
73    return 1; 
74 }
75
76
77 struct showstruct {char *res_name; int type;};
78 static struct showstruct reses[] = {
79    {N_("directors"),  R_DIRECTOR},
80    {N_("clients"),    R_CLIENT},
81    {N_("jobs"),       R_JOB},
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},
89    {N_("all"),        -1},
90    {N_("help"),       -2},
91    {NULL,           0}
92 };
93
94
95 /*
96  *  Displays Resources
97  *
98  *  show all
99  *  show <resource-keyword-name>  e.g. show directors
100  *  show <resource-keyword-name>=<name> e.g. show director=HeadMan
101  *
102  */
103 int showcmd(UAContext *ua, char *cmd)
104 {
105    int i, j, type, len; 
106    int recurse;
107    char *res_name;
108    RES *res = NULL;
109
110    Dmsg1(20, "show: %s\n", ua->UA_sock->msg);
111
112
113    for (i=1; i<ua->argc; i++) {
114       type = 0;
115       res_name = ua->argk[i]; 
116       if (!ua->argv[i]) {             /* was a name given? */
117          /* No name, dump all resources of specified type */
118          recurse = 1;
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;
123                if (type > 0) {
124                   res = resources[type-r_first].res_head;
125                } else {
126                   res = NULL;
127                }
128                break;
129             }
130          }
131       } else {
132          /* Dump a single resource with specified name */
133          recurse = 0;
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]);
139                if (!res) {
140                   type = -3;
141                }
142                break;
143             }
144          }
145       }
146
147       switch (type) {
148       case -1:                           /* all */
149          for (j=r_first; j<=r_last; j++) {
150             dump_resource(j, resources[j-r_first].res_head, bsendmsg, ua);     
151          }
152          break;
153       case -2:
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));
157          }
158          return 1;
159       case -3:
160          bsendmsg(ua, _("%s resource %s not found.\n"), res_name, ua->argv[i]);
161          return 1;
162       case 0:
163          bsendmsg(ua, _("Resource %s not found\n"), res_name);
164          return 1;
165       default:
166          dump_resource(recurse?type:-type, res, bsendmsg, ua);
167          break;
168       }
169    }
170    return 1;
171 }
172
173
174
175
176 /*
177  *  List contents of database
178  *
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
191  *
192  */
193
194 /* Do long or full listing */
195 int llistcmd(UAContext *ua, char *cmd)
196 {
197    return do_listcmd(ua, cmd, 1);
198 }
199
200 /* Do short or summary listing */
201 int listcmd(UAContext *ua, char *cmd)
202 {
203    return do_listcmd(ua, cmd, 0);
204 }
205
206 static int do_listcmd(UAContext *ua, char *cmd, int llist) 
207 {
208    POOLMEM *VolumeName;
209    int jobid, n;
210    int i, j;
211    JOB_DBR jr;
212    POOL_DBR pr;
213    MEDIA_DBR mr;
214
215    if (!open_db(ua))
216       return 1;
217
218    memset(&jr, 0, sizeof(jr));
219    memset(&pr, 0, sizeof(pr));
220    memset(&mr, 0, sizeof(mr));
221
222    Dmsg1(20, "list: %s\n", cmd);
223
224    if (!ua->db) {
225       bsendmsg(ua, _("Hey! DB is NULL\n"));
226    }
227
228    /* Scan arguments looking for things to do */
229    for (i=1; i<ua->argc; i++) {
230       /* List JOBS */
231       if (strcasecmp(ua->argk[i], _("jobs")) == 0) {
232          db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
233
234          /* List JOBTOTALS */
235       } else if (strcasecmp(ua->argk[i], _("jobtotals")) == 0) {
236          db_list_job_totals(ua->jcr, ua->db, &jr, prtit, ua);
237
238       /* List JOBID */
239       } else if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
240          if (ua->argv[i]) {
241             jobid = atoi(ua->argv[i]);
242             if (jobid > 0) {
243                jr.JobId = jobid;
244                db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
245             }
246          }
247
248       /* List JOB */
249       } else if (strcasecmp(ua->argk[i], _("job")) == 0 && ua->argv[i]) {
250          bstrncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
251          jr.JobId = 0;
252          db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua, llist);
253
254       /* List FILES */
255       } else if (strcasecmp(ua->argk[i], _("files")) == 0) {
256
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);
260                jr.JobId = 0;
261                db_get_job_record(ua->jcr, ua->db, &jr);
262                jobid = jr.JobId;
263             } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
264                jobid = atoi(ua->argv[j]);
265             } else {
266                continue;
267             }
268             if (jobid > 0) {
269                db_list_files_for_job(ua->jcr, ua->db, jobid, prtit, ua);
270             }
271          }
272       
273       /* List JOBMEDIA */
274       } else if (strcasecmp(ua->argk[i], _("jobmedia")) == 0) {
275          int done = FALSE;
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);
279                jr.JobId = 0;
280                db_get_job_record(ua->jcr, ua->db, &jr);
281                jobid = jr.JobId;
282             } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
283                jobid = atoi(ua->argv[j]);
284             } else {
285                continue;
286             }
287             db_list_jobmedia_records(ua->jcr, ua->db, jobid, prtit, ua, llist);
288             done = TRUE;
289          }
290          if (!done) {
291             /* List for all jobs (jobid=0) */
292             db_list_jobmedia_records(ua->jcr, ua->db, 0, prtit, ua, llist);
293          }
294
295       /* List POOLS */
296       } else if (strcasecmp(ua->argk[i], _("pools")) == 0) {
297          db_list_pool_records(ua->jcr, ua->db, prtit, ua, llist);
298
299       } else if (strcasecmp(ua->argk[i], _("clients")) == 0) {
300          db_list_client_records(ua->jcr, ua->db, prtit, ua, llist);
301
302
303       /* List MEDIA or VOLUMES */
304       } else if (strcasecmp(ua->argk[i], _("media")) == 0 ||
305                  strcasecmp(ua->argk[i], _("volumes")) == 0) {
306          int done = FALSE;
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);
310                jr.JobId = 0;
311                db_get_job_record(ua->jcr, ua->db, &jr);
312                jobid = jr.JobId;
313             } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
314                jobid = atoi(ua->argv[j]);
315             } else {
316                continue;
317             }
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);
322             done = TRUE;
323          }
324          /* if no job or jobid keyword found, then we list all media */
325          if (!done) {
326             int num_pools;
327             uint32_t *ids;
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)) {
332                      bsendmsg(ua, _("No Pool specified.\n"));
333                      return 1;
334                   }
335                   mr.PoolId = pr.PoolId;
336                   db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
337                   return 1;
338                }
339             }
340             /* List Volumes in all pools */
341             if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
342                bsendmsg(ua, _("Error obtaining pool ids. ERR=%s\n"), 
343                         db_strerror(ua->db));
344                return 1;
345             }
346             if (num_pools <= 0) {
347                return 1;
348             }
349             for (i=0; i < num_pools; i++) {
350                pr.PoolId = ids[i];
351                if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
352                   bsendmsg(ua, _("Pool: %s\n"), pr.Name);
353                }
354                mr.PoolId = ids[i];
355                db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
356             }
357             free(ids);
358             return 1;
359          }
360       /* List a specific volume */
361       } else if (strcasecmp(ua->argk[i], _("volume")) == 0) {
362          if (!ua->argv[i]) {
363             bsendmsg(ua, _("No Volume Name specified.\n"));
364             return 1;
365          }
366          bstrncpy(mr.VolumeName, ua->argv[i], sizeof(mr.VolumeName));
367          db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua, llist);
368          return 1;
369       } else {
370          bsendmsg(ua, _("Unknown list keyword: %s\n"), NPRT(ua->argk[i]));
371       }
372    }
373    return 1;
374 }
375
376 static void con_lock_release(void *arg)
377 {
378    Vw(con_lock);
379 }
380
381 void do_messages(UAContext *ua, char *cmd)
382 {
383    char msg[2000];
384    int mlen; 
385    int do_truncate = FALSE;
386
387    Pw(con_lock);
388    pthread_cleanup_push(con_lock_release, (void *)NULL);
389    rewind(con_fd);
390    while (fgets(msg, sizeof(msg), con_fd)) {
391       mlen = strlen(msg);
392       ua->UA_sock->msg = check_pool_memory_size(ua->UA_sock->msg, mlen+1);
393       strcpy(ua->UA_sock->msg, msg);
394       ua->UA_sock->msglen = mlen;
395       bnet_send(ua->UA_sock);
396       do_truncate = TRUE;
397    }
398    if (do_truncate) {
399       ftruncate(fileno(con_fd), 0L);
400    }
401    console_msg_pending = FALSE;
402    ua->user_notified_msg_pending = FALSE;
403    pthread_cleanup_pop(0);
404    Vw(con_lock);
405 }
406
407
408 int qmessagescmd(UAContext *ua, char *cmd)
409 {
410    if (console_msg_pending && ua->auto_display_messages) {
411       do_messages(ua, cmd);
412    }
413    return 1;
414 }
415
416 int messagescmd(UAContext *ua, char *cmd)
417 {
418    if (console_msg_pending) {
419       do_messages(ua, cmd);
420    } else {
421       bnet_fsend(ua->UA_sock, _("You have no messages.\n"));
422    }
423    return 1;
424 }
425
426 /*
427  * Callback routine for "printing" database file listing
428  */
429 void prtit(void *ctx, char *msg)
430 {
431    UAContext *ua = (UAContext *)ctx;
432  
433    bnet_fsend(ua->UA_sock, "%s", msg);
434 }
435
436 /* 
437  * Format message and send to other end.  
438
439  * If the UA_sock is NULL, it means that there is no user
440  * agent, so we are being called from Bacula core. In
441  * that case direct the messages to the Job.
442  */
443 void bsendmsg(void *ctx, char *fmt, ...)
444 {
445    va_list arg_ptr;
446    UAContext *ua = (UAContext *)ctx;
447    BSOCK *bs = ua->UA_sock;
448    int maxlen, len;
449    POOLMEM *msg;
450
451    if (bs) {
452       msg = bs->msg;
453    } else {
454       msg = get_pool_memory(PM_EMSG);
455    }
456
457 again:
458    maxlen = sizeof_pool_memory(msg) - 1;
459    va_start(arg_ptr, fmt);
460    len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
461    va_end(arg_ptr);
462    if (len < 0 || len >= maxlen) {
463       msg = realloc_pool_memory(msg, maxlen + 200);
464       goto again;
465    }
466
467    if (bs) {
468       bs->msglen = len;
469       bnet_send(bs);
470    } else {                           /* No UA, send to Job */
471       Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
472       free_pool_memory(msg);
473    }
474
475 }