]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_output.c
c60873c2756822cc999358dfc11cf34437bcf728
[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
50
51 /*
52  * Turn auto display of console messages on/off
53  */
54 int autodisplaycmd(UAContext *ua, char *cmd)
55 {
56    static char *kw[] = {
57       N_("on"), 
58       N_("off"),
59       NULL};
60
61    switch (find_arg_keyword(ua, kw)) {
62       case 0:
63          ua->auto_display_messages = 1;
64          break;
65       case 1:
66          ua->auto_display_messages = 0;
67          break;
68       default:
69          bsendmsg(ua, _("ON or OFF keyword missing.\n"));
70          break;
71    }
72    return 1; 
73 }
74
75
76 struct showstruct {char *res_name; int type;};
77 static struct showstruct reses[] = {
78    {N_("directors"),  R_DIRECTOR},
79    {N_("clients"),    R_CLIENT},
80    {N_("jobs"),       R_JOB},
81    {N_("storages"),   R_STORAGE},
82    {N_("catalogs"),   R_CATALOG},
83    {N_("schedules"),  R_SCHEDULE},
84    {N_("filesets"),   R_FILESET},
85    {N_("groups"),     R_GROUP},
86    {N_("pools"),      R_POOL},
87    {N_("messages"),   R_MSGS},
88    {N_("all"),        -1},
89    {N_("help"),       -2},
90    {NULL,           0}
91 };
92
93
94 /*
95  *  Displays Resources
96  *
97  *  show all
98  *  show <resource-keyword-name>  e.g. show directors
99  *  show <resource-keyword-name>=<name> e.g. show director=HeadMan
100  *
101  */
102 int showcmd(UAContext *ua, char *cmd)
103 {
104    int i, j, type, len; 
105    int recurse;
106    char *res_name;
107    RES *res = NULL;
108
109    Dmsg1(20, "show: %s\n", ua->UA_sock->msg);
110
111
112    for (i=1; i<ua->argc; i++) {
113       type = 0;
114       res_name = ua->argk[i]; 
115       if (!ua->argv[i]) {             /* was a name given? */
116          /* No name, dump all resources of specified type */
117          recurse = 1;
118          len = strlen(res_name);
119          for (j=0; reses[j].res_name; j++) {
120             if (strncasecmp(res_name, _(reses[j].res_name), len) == 0) {
121                type = reses[j].type;
122                if (type > 0) {
123                   res = resources[type-r_first].res_head;
124                } else {
125                   res = NULL;
126                }
127                break;
128             }
129          }
130       } else {
131          /* Dump a single resource with specified name */
132          recurse = 0;
133          len = strlen(res_name);
134          for (j=0; reses[j].res_name; j++) {
135             if (strncasecmp(res_name, _(reses[j].res_name), len) == 0) {
136                type = reses[j].type;
137                res = (RES *)GetResWithName(type, ua->argv[i]);
138                if (!res) {
139                   type = -3;
140                }
141                break;
142             }
143          }
144       }
145
146       switch (type) {
147       case -1:                           /* all */
148          for (j=r_first; j<=r_last; j++) {
149             dump_resource(j, resources[j-r_first].res_head, bsendmsg, ua);     
150          }
151          break;
152       case -2:
153          bsendmsg(ua, _("Keywords for the show command are:\n"));
154          for (j=0; reses[j].res_name; j++) {
155             bsendmsg(ua, "%s\n", _(reses[j].res_name));
156          }
157          return 1;
158       case -3:
159          bsendmsg(ua, _("%s resource %s not found.\n"), res_name, ua->argv[i]);
160          return 1;
161       case 0:
162          bsendmsg(ua, _("Resource %s not found\n"), res_name);
163          return 1;
164       default:
165          dump_resource(recurse?type:-type, res, bsendmsg, ua);
166          break;
167       }
168    }
169    return 1;
170 }
171
172
173
174
175 /*
176  *  List contents of database
177  *
178  *  list jobs           - lists all jobs run
179  *  list jobid=nnn      - list job data for jobid
180  *  list job=name       - list job data for job
181  *  list jobmedia jobid=<nn>
182  *  list jobmedia job=name
183  *  list files jobid=<nn> - list files saved for job nn
184  *  list files job=name
185  *  list pools          - list pool records
186  *  list jobtotals      - list totals for all jobs
187  *  list media          - list media for given pool (deprecated)
188  *  list volumes        - list Volumes
189  *  list clients        - list clients
190  *
191  */
192 int listcmd(UAContext *ua, char *cmd) 
193 {
194    POOLMEM *VolumeName;
195    int jobid, n;
196    int i, j;
197    JOB_DBR jr;
198    POOL_DBR pr;
199    MEDIA_DBR mr;
200
201    if (!open_db(ua))
202       return 1;
203
204    memset(&jr, 0, sizeof(jr));
205    memset(&pr, 0, sizeof(pr));
206    memset(&mr, 0, sizeof(mr));
207
208    Dmsg1(20, "list: %s\n", cmd);
209
210    if (!ua->db) {
211       bsendmsg(ua, _("Hey! DB is NULL\n"));
212    }
213
214    /* Scan arguments looking for things to do */
215    for (i=1; i<ua->argc; i++) {
216       /* List JOBS */
217       if (strcasecmp(ua->argk[i], _("jobs")) == 0) {
218          db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua);
219
220          /* List JOBTOTALS */
221       } else if (strcasecmp(ua->argk[i], _("jobtotals")) == 0) {
222          db_list_job_totals(ua->jcr, ua->db, &jr, prtit, ua);
223
224       /* List JOBID */
225       } else if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
226          if (ua->argv[i]) {
227             jobid = atoi(ua->argv[i]);
228             if (jobid > 0) {
229                jr.JobId = jobid;
230                db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua);
231             }
232          }
233
234       /* List JOB */
235       } else if (strcasecmp(ua->argk[i], _("job")) == 0 && ua->argv[i]) {
236          bstrncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
237          jr.JobId = 0;
238          db_list_job_records(ua->jcr, ua->db, &jr, prtit, ua);
239
240       /* List FILES */
241       } else if (strcasecmp(ua->argk[i], _("files")) == 0) {
242
243          for (j=i+1; j<ua->argc; j++) {
244             if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
245                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
246                jr.JobId = 0;
247                db_get_job_record(ua->jcr, ua->db, &jr);
248                jobid = jr.JobId;
249             } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
250                jobid = atoi(ua->argv[j]);
251             } else {
252                continue;
253             }
254             if (jobid > 0) {
255                db_list_files_for_job(ua->jcr, ua->db, jobid, prtit, ua);
256             }
257          }
258       
259       /* List JOBMEDIA */
260       } else if (strcasecmp(ua->argk[i], _("jobmedia")) == 0) {
261          int done = FALSE;
262          for (j=i+1; j<ua->argc; j++) {
263             if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
264                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
265                jr.JobId = 0;
266                db_get_job_record(ua->jcr, ua->db, &jr);
267                jobid = jr.JobId;
268             } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
269                jobid = atoi(ua->argv[j]);
270             } else {
271                continue;
272             }
273             db_list_jobmedia_records(ua->jcr, ua->db, jobid, prtit, ua);
274             done = TRUE;
275          }
276          if (!done) {
277             /* List for all jobs (jobid=0) */
278             db_list_jobmedia_records(ua->jcr, ua->db, 0, prtit, ua);
279          }
280
281       /* List POOLS */
282       } else if (strcasecmp(ua->argk[i], _("pools")) == 0) {
283          db_list_pool_records(ua->jcr, ua->db, prtit, ua);
284
285       } else if (strcasecmp(ua->argk[i], _("clients")) == 0) {
286          db_list_client_records(ua->jcr, ua->db, prtit, ua);
287
288
289       /* List MEDIA or VOLUMES */
290       } else if (strcasecmp(ua->argk[i], _("media")) == 0 ||
291                  strcasecmp(ua->argk[i], _("volumes")) == 0) {
292          int done = FALSE;
293          for (j=i+1; j<ua->argc; j++) {
294             if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
295                bstrncpy(jr.Job, ua->argv[j], MAX_NAME_LENGTH);
296                jr.JobId = 0;
297                db_get_job_record(ua->jcr, ua->db, &jr);
298                jobid = jr.JobId;
299             } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
300                jobid = atoi(ua->argv[j]);
301             } else {
302                continue;
303             }
304             VolumeName = get_pool_memory(PM_FNAME);
305             n = db_get_job_volume_names(ua->jcr, ua->db, jobid, &VolumeName);
306             bsendmsg(ua, _("Jobid %d used %d Volume(s): %s\n"), jobid, n, VolumeName);
307             free_pool_memory(VolumeName);
308             done = TRUE;
309          }
310          /* if no job or jobid keyword found, then we list all media */
311          if (!done) {
312             int num_pools;
313             uint32_t *ids;
314             /* Is a specific pool wanted? */
315             for (i=1; i<ua->argc; i++) {
316                if (strcasecmp(ua->argk[i], _("pool")) == 0) {
317                   if (!get_pool_dbr(ua, &pr)) {
318                      return 1;
319                   }
320                   mr.PoolId = pr.PoolId;
321                   db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua);
322                   return 1;
323                }
324             }
325             /* List Volumes in all pools */
326             if (!db_get_pool_ids(ua->jcr, ua->db, &num_pools, &ids)) {
327                bsendmsg(ua, _("Error obtaining pool ids. ERR=%s\n"), 
328                         db_strerror(ua->db));
329                return 1;
330             }
331             if (num_pools <= 0) {
332                return 1;
333             }
334             for (i=0; i < num_pools; i++) {
335                pr.PoolId = ids[i];
336                if (db_get_pool_record(ua->jcr, ua->db, &pr)) {
337                   bsendmsg(ua, _("Pool: %s\n"), pr.Name);
338                }
339                mr.PoolId = ids[i];
340                db_list_media_records(ua->jcr, ua->db, &mr, prtit, ua);
341             }
342             free(ids);
343             return 1;
344          }
345       } else {
346          bsendmsg(ua, _("Unknown list keyword: %s\n"), NPRT(ua->argk[i]));
347       }
348    }
349    return 1;
350 }
351
352 static void con_lock_release(void *arg)
353 {
354    Vw(con_lock);
355 }
356
357 void do_messages(UAContext *ua, char *cmd)
358 {
359    char msg[2000];
360    int mlen; 
361    int do_truncate = FALSE;
362
363    Pw(con_lock);
364    pthread_cleanup_push(con_lock_release, (void *)NULL);
365    rewind(con_fd);
366    while (fgets(msg, sizeof(msg), con_fd)) {
367       mlen = strlen(msg);
368       ua->UA_sock->msg = check_pool_memory_size(ua->UA_sock->msg, mlen+1);
369       strcpy(ua->UA_sock->msg, msg);
370       ua->UA_sock->msglen = mlen;
371       bnet_send(ua->UA_sock);
372       do_truncate = TRUE;
373    }
374    if (do_truncate) {
375       ftruncate(fileno(con_fd), 0L);
376    }
377    console_msg_pending = FALSE;
378    ua->user_notified_msg_pending = FALSE;
379    pthread_cleanup_pop(0);
380    Vw(con_lock);
381 }
382
383
384 int qmessagescmd(UAContext *ua, char *cmd)
385 {
386    if (console_msg_pending && ua->auto_display_messages) {
387       do_messages(ua, cmd);
388    }
389    return 1;
390 }
391
392 int messagescmd(UAContext *ua, char *cmd)
393 {
394    if (console_msg_pending) {
395       do_messages(ua, cmd);
396    } else {
397       bnet_fsend(ua->UA_sock, _("You have no messages.\n"));
398    }
399    return 1;
400 }
401
402 /*
403  * Callback routine for "printing" database file listing
404  */
405 void prtit(void *ctx, char *msg)
406 {
407    UAContext *ua = (UAContext *)ctx;
408  
409    bnet_fsend(ua->UA_sock, "%s", msg);
410 }
411
412 /* 
413  * Format message and send to other end.  
414
415  * If the UA_sock is NULL, it means that there is no user
416  * agent, so we are being called from Bacula core. In
417  * that case direct the messages to the Job.
418  */
419 void bsendmsg(void *ctx, char *fmt, ...)
420 {
421    va_list arg_ptr;
422    UAContext *ua = (UAContext *)ctx;
423    BSOCK *bs = ua->UA_sock;
424    int maxlen, len;
425    POOLMEM *msg;
426
427    if (bs) {
428       msg = bs->msg;
429    } else {
430       msg = get_pool_memory(PM_EMSG);
431    }
432
433 again:
434    maxlen = sizeof_pool_memory(msg) - 1;
435    va_start(arg_ptr, fmt);
436    len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
437    va_end(arg_ptr);
438    if (len < 0 || len >= maxlen) {
439       msg = realloc_pool_memory(msg, maxlen + 200);
440       goto again;
441    }
442
443    if (bs) {
444       bs->msglen = len;
445       bnet_send(bs);
446    } else {                           /* No UA, send to Job */
447       Jmsg(ua->jcr, M_INFO, 0, "%s", msg);
448       free_pool_memory(msg);
449    }
450
451 }