]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_output.c
Make Recycle work -- kes25May02
[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, 2001, 2002 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 #include "ua.h"
34
35 /* Imported subroutines */
36 extern void run_job(JCR *jcr);
37
38 /* Imported variables */
39 extern int r_first;
40 extern int r_last;
41 extern struct s_res resources[];
42 extern int console_msg_pending;
43 extern FILE *con_fd;
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;
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
188  *
189  */
190 int listcmd(UAContext *ua, char *cmd) 
191 {
192    POOLMEM *VolumeName;
193    int jobid, n;
194    int i, j;
195    JOB_DBR jr;
196    POOL_DBR pr;
197    MEDIA_DBR mr;
198
199    if (!open_db(ua))
200       return 1;
201
202    memset(&jr, 0, sizeof(jr));
203    memset(&pr, 0, sizeof(pr));
204    memset(&mr, 0, sizeof(mr));
205
206    Dmsg1(20, "list: %s\n", cmd);
207
208    if (!ua->db) {
209       bsendmsg(ua, _("Hey! DB is NULL\n"));
210    }
211
212    /* Scan arguments looking for things to do */
213    for (i=1; i<ua->argc; i++) {
214       /* List JOBS */
215       if (strcasecmp(ua->argk[i], _("jobs")) == 0) {
216          db_list_job_records(ua->db, &jr, prtit, ua);
217
218          /* List JOBTOTALS */
219       } else if (strcasecmp(ua->argk[i], _("jobtotals")) == 0) {
220          db_list_job_totals(ua->db, &jr, prtit, ua);
221
222       /* List JOBID */
223       } else if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
224          if (ua->argv[i]) {
225             jobid = atoi(ua->argv[i]);
226             if (jobid > 0) {
227                jr.JobId = jobid;
228                db_list_job_records(ua->db, &jr, prtit, ua);
229             }
230          }
231
232       /* List JOB */
233       } else if (strcasecmp(ua->argk[i], _("job")) == 0 && ua->argv[i]) {
234          strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
235          jr.Job[MAX_NAME_LENGTH-1] = 0;
236          jr.JobId = 0;
237          db_list_job_records(ua->db, &jr, prtit, ua);
238
239       /* List FILES */
240       } else if (strcasecmp(ua->argk[i], _("files")) == 0) {
241
242          for (j=i+1; j<ua->argc; j++) {
243             if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
244                strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
245                jr.Job[MAX_NAME_LENGTH-1] = 0;
246                jr.JobId = 0;
247                db_get_job_record(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->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                strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
265                jr.Job[MAX_NAME_LENGTH-1] = 0;
266                jr.JobId = 0;
267                db_get_job_record(ua->db, &jr);
268                jobid = jr.JobId;
269             } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
270                jobid = atoi(ua->argv[j]);
271             } else {
272                continue;
273             }
274             db_list_jobmedia_records(ua->db, jobid, prtit, ua);
275             done = TRUE;
276          }
277          if (!done) {
278             /* List for all jobs (jobid=0) */
279             db_list_jobmedia_records(ua->db, 0, prtit, ua);
280          }
281
282       /* List POOLS */
283       } else if (strcasecmp(ua->argk[i], _("pools")) == 0) {
284          db_list_pool_records(ua->db, prtit, ua);
285
286       /* List MEDIA or VOLUMES */
287       } else if (strcasecmp(ua->argk[i], _("media")) == 0 ||
288                  strcasecmp(ua->argk[i], _("volumes")) == 0) {
289          int done = FALSE;
290          for (j=i+1; j<ua->argc; j++) {
291             if (strcasecmp(ua->argk[j], _("job")) == 0 && ua->argv[j]) {
292                strncpy(jr.Job, ua->argv[i], MAX_NAME_LENGTH);
293                jr.Job[MAX_NAME_LENGTH-1] = 0;
294                jr.JobId = 0;
295                db_get_job_record(ua->db, &jr);
296                jobid = jr.JobId;
297             } else if (strcasecmp(ua->argk[j], _("jobid")) == 0 && ua->argv[j]) {
298                jobid = atoi(ua->argv[j]);
299             } else {
300                continue;
301             }
302             VolumeName = get_pool_memory(PM_FNAME);
303             n = db_get_job_volume_names(ua->db, jobid, VolumeName);
304             bsendmsg(ua, _("Jobid %d used %d Volume(s): %s\n"), jobid, n, VolumeName);
305             free_memory(VolumeName);
306             done = TRUE;
307          }
308          /* if no job or jobid keyword found, then we list all media */
309          if (!done) {
310             if (!get_pool_dbr(ua, &pr)) {
311                return 1;
312             }
313             mr.PoolId = pr.PoolId;
314             db_list_media_records(ua->db, &mr, prtit, ua);
315          }
316       } else {
317          bsendmsg(ua, _("Unknown list keyword: %s\n"), ua->argk[i]);
318       }
319    }
320    return 1;
321 }
322
323 void do_messages(UAContext *ua, char *cmd)
324 {
325    char msg[2000];
326    int mlen; 
327
328    fcntl(fileno(con_fd), F_SETLKW);
329    rewind(con_fd);
330    while (fgets(msg, sizeof(msg), con_fd)) {
331       mlen = strlen(msg);
332       ua->UA_sock->msg = check_pool_memory_size(ua->UA_sock->msg, mlen+1);
333       strcpy(ua->UA_sock->msg, msg);
334       ua->UA_sock->msglen = mlen;
335       bnet_send(ua->UA_sock);
336    }
337    ftruncate(fileno(con_fd), 0L);
338    console_msg_pending = FALSE;
339    fcntl(fileno(con_fd), F_UNLCK);
340    ua->user_notified_msg_pending = FALSE;
341 }
342
343
344 int qmessagescmd(UAContext *ua, char *cmd)
345 {
346    if (console_msg_pending && ua->auto_display_messages) {
347       do_messages(ua, cmd);
348    }
349    return 1;
350 }
351
352 int messagescmd(UAContext *ua, char *cmd)
353 {
354    if (console_msg_pending) {
355       do_messages(ua, cmd);
356    } else {
357       bnet_fsend(ua->UA_sock, _("You have no messages.\n"));
358    }
359    return 1;
360 }
361
362 /*
363  * Callback routine for "printing" database file listing
364  */
365 void prtit(void *ctx, char *msg)
366 {
367    UAContext *ua = (UAContext *)ctx;
368  
369    bnet_fsend(ua->UA_sock, "%s", msg);
370 }
371
372 /* 
373  * Format message and send to other end.  
374
375  * If the UA_sock is NULL, it means that there is no user
376  * agent, so we are being called from Bacula core. In
377  * that case direct the messages to the Job.
378  */
379 void bsendmsg(void *ctx, char *fmt, ...)
380 {
381    va_list arg_ptr;
382    UAContext *ua = (UAContext *)ctx;
383    BSOCK *bs = ua->UA_sock;
384    int maxlen, len;
385    POOLMEM *msg;
386
387    if (bs) {
388       msg = bs->msg;
389    } else {
390       msg = get_pool_memory(PM_EMSG);
391    }
392
393 again:
394    maxlen = sizeof_pool_memory(msg) - 1;
395    va_start(arg_ptr, fmt);
396    len = bvsnprintf(msg, maxlen, fmt, arg_ptr);
397    va_end(arg_ptr);
398    if (len < 0 || len >= maxlen) {
399       msg = realloc_pool_memory(msg, maxlen + 200);
400       goto again;
401    }
402
403    if (bs) {
404       bs->msglen = len;
405       bnet_send(bs);
406    } else {                           /* No UA, send to Job */
407       Jmsg(ua->jcr, M_INFO, 0, msg);
408       free_pool_memory(msg);
409    }
410
411 }