]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/dird/ua_dotcmds.c
Kludge joblist to include all jobs
[bacula/bacula] / bacula / src / dird / ua_dotcmds.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2002-2007 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation plus additions
11    that are listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *   Bacula Director -- User Agent Commands
31  *     These are "dot" commands, i.e. commands preceded
32  *        by a period. These commands are meant to be used
33  *        by a program, so there is no prompting, and the
34  *        returned results are (supposed to be) predictable.
35  *
36  *     Kern Sibbald, April MMII
37  *
38  *   Version $Id$
39  */
40
41 #include "bacula.h"
42 #include "dird.h"
43
44 /* Imported variables */
45 extern int r_first;
46 extern int r_last;
47 extern struct s_res resources[];
48
49 /* Imported functions */
50 extern void do_messages(UAContext *ua, const char *cmd);
51 extern int quit_cmd(UAContext *ua, const char *cmd);
52 extern int qhelp_cmd(UAContext *ua, const char *cmd);
53 extern bool dot_status_cmd(UAContext *ua, const char *cmd);
54
55
56 /* Forward referenced functions */
57 static bool diecmd(UAContext *ua, const char *cmd);
58 static bool jobscmd(UAContext *ua, const char *cmd);
59 static bool filesetscmd(UAContext *ua, const char *cmd);
60 static bool clientscmd(UAContext *ua, const char *cmd);
61 static bool msgscmd(UAContext *ua, const char *cmd);
62 static bool poolscmd(UAContext *ua, const char *cmd);
63 static bool storagecmd(UAContext *ua, const char *cmd);
64 static bool defaultscmd(UAContext *ua, const char *cmd);
65 static bool typescmd(UAContext *ua, const char *cmd);
66 static bool backupscmd(UAContext *ua, const char *cmd);
67 static bool levelscmd(UAContext *ua, const char *cmd);
68 static bool getmsgscmd(UAContext *ua, const char *cmd);
69
70 static bool api_cmd(UAContext *ua, const char *cmd);
71 static bool sql_cmd(UAContext *ua, const char *cmd);
72 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
73 static bool dot_help_cmd(UAContext *ua, const char *cmd);
74
75 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help; };
76 static struct cmdstruct commands[] = {
77  { NT_(".api"),        api_cmd,        NULL},
78  { NT_(".backups"),    backupscmd,     NULL},
79  { NT_(".clients"),    clientscmd,     NULL},
80  { NT_(".defaults"),   defaultscmd,    NULL},
81  { NT_(".die"),        diecmd,         NULL},
82  { NT_(".exit"),       dot_quit_cmd,   NULL},
83  { NT_(".filesets"),   filesetscmd,    NULL},
84  { NT_(".help"),       dot_help_cmd,   NULL},
85  { NT_(".jobs"),       jobscmd,        NULL},
86  { NT_(".levels"),     levelscmd,      NULL},
87  { NT_(".messages"),   getmsgscmd,     NULL},
88  { NT_(".msgs"),       msgscmd,        NULL},
89  { NT_(".pools"),      poolscmd,       NULL},
90  { NT_(".quit"),       dot_quit_cmd,   NULL},
91  { NT_(".sql"),        sql_cmd,        NULL},
92  { NT_(".status"),     dot_status_cmd, NULL},
93  { NT_(".storage"),    storagecmd,     NULL},
94  { NT_(".types"),      typescmd,       NULL} 
95              };
96 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
97
98 /*
99  * Execute a command from the UA
100  */
101 int do_a_dot_command(UAContext *ua, const char *cmd)
102 {
103    int i;
104    int len;
105    bool ok = false;
106    bool found = false;
107    BSOCK *user = ua->UA_sock;
108
109    Dmsg1(1400, "Dot command: %s\n", user->msg);
110    if (ua->argc == 0) {
111       return 1;
112    }
113
114    len = strlen(ua->argk[0]);
115    if (len == 1) {
116       if (ua->api) user->signal(BNET_CMD_BEGIN);
117       if (ua->api) user->signal(BNET_CMD_OK);
118       return 1;                       /* no op */
119    }
120    for (i=0; i<comsize; i++) {     /* search for command */
121       if (strncasecmp(ua->argk[0],  _(commands[i].key), len) == 0) {
122          bool gui = ua->gui;
123          /* Check if command permitted, but "quit" is always OK */
124          if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
125              !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
126             break;
127          }
128          ua->gui = true;
129          if (ua->api) user->signal(BNET_CMD_BEGIN);
130          ok = (*commands[i].func)(ua, cmd);   /* go execute command */
131          ua->gui = gui;
132          found = true;
133          break;
134       }
135    }
136    if (!found) {
137       pm_strcat(user->msg, _(": is an invalid command.\n"));
138       user->msglen = strlen(user->msg);
139       user->send();
140    }
141    if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
142    return 1;
143 }
144
145 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
146 {
147    quit_cmd(ua, cmd);
148    return true;
149 }
150
151 static bool dot_help_cmd(UAContext *ua, const char *cmd)
152 {
153    qhelp_cmd(ua, cmd);
154    return true;
155 }
156
157 static bool getmsgscmd(UAContext *ua, const char *cmd)
158 {
159    if (console_msg_pending) {
160       do_messages(ua, cmd);
161    }
162    return 1;
163 }
164
165 #ifdef DEVELOPER
166 static void do_storage_die(UAContext *ua, STORE *store)
167 {
168    BSOCK *sd;
169    JCR *jcr = ua->jcr;
170    USTORE lstore;
171    
172    lstore.store = store;
173    pm_strcpy(lstore.store_source, _("unknown source"));
174    set_wstorage(jcr, &lstore);
175    /* Try connecting for up to 15 seconds */
176    ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
177       store->name(), store->address, store->SDport);
178    if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
179       ua->error_msg(_("Failed to connect to Storage daemon.\n"));
180       return;
181    }
182    Dmsg0(120, _("Connected to storage daemon\n"));
183    sd = jcr->store_bsock;
184    sd->fsend(".die");
185    if (sd->recv() >= 0) {
186       ua->send_msg("%s", sd->msg);
187    }
188    sd->signal(BNET_TERMINATE);
189    sd->close();
190    jcr->store_bsock = NULL;
191    return;
192 }
193
194 static void do_client_die(UAContext *ua, CLIENT *client)
195 {
196    BSOCK *fd;
197
198    /* Connect to File daemon */
199
200    ua->jcr->client = client;
201    /* Try to connect for 15 seconds */
202    ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
203       client->name(), client->address, client->FDport);
204    if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
205       ua->error_msg(_("Failed to connect to Client.\n"));
206       return;
207    }
208    Dmsg0(120, "Connected to file daemon\n");
209    fd = ua->jcr->file_bsock;
210    fd->fsend(".die");
211    if (fd->recv() >= 0) {
212       ua->send_msg("%s", fd->msg);
213    }
214    fd->signal(BNET_TERMINATE);
215    fd->close();
216    ua->jcr->file_bsock = NULL;
217    return;
218 }
219
220 /*
221  * Create segmentation fault
222  */
223 static bool diecmd(UAContext *ua, const char *cmd)
224 {
225    STORE *store;
226    CLIENT *client;
227    int i;
228    JCR *jcr = NULL;
229    int a;
230
231    Dmsg1(120, "diecmd:%s:\n", cmd);
232
233    /* General debug? */
234    for (i=1; i<ua->argc; i++) {
235       if (strcasecmp(ua->argk[i], "dir") == 0 ||
236           strcasecmp(ua->argk[i], "director") == 0) {
237          ua->send_msg(_("The Director will segment fault.\n"));
238          a = jcr->JobId; /* ref NULL pointer */
239          jcr->JobId = 1000; /* another ref NULL pointer */
240          return 1;
241       }
242       if (strcasecmp(ua->argk[i], "client") == 0 ||
243           strcasecmp(ua->argk[i], "fd") == 0) {
244          client = NULL;
245          if (ua->argv[i]) {
246             client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
247             if (client) {
248                do_client_die(ua, client);
249                return 1;
250             }
251          }
252          client = select_client_resource(ua);
253          if (client) {
254             do_client_die(ua, client);
255             return 1;
256          }
257       }
258
259       if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
260           strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
261           strcasecmp(ua->argk[i], NT_("sd")) == 0) {
262          store = NULL;
263          if (ua->argv[i]) {
264             store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
265             if (store) {
266                do_storage_die(ua, store);
267                return 1;
268             }
269          }
270          store = get_storage_resource(ua, false/*no default*/);
271          if (store) {
272             do_storage_die(ua, store);
273             return 1;
274          }
275       }
276    }
277    /*
278     * We didn't find an appropriate keyword above, so
279     * prompt the user.
280     */
281    start_prompt(ua, _("Available daemons are: \n"));
282    add_prompt(ua, _("Director"));
283    add_prompt(ua, _("Storage"));
284    add_prompt(ua, _("Client"));
285    switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
286    case 0:                         /* Director */
287       ua->send_msg(_("The Director will segment fault.\n"));
288       a = jcr->JobId; /* ref NULL pointer */
289       jcr->JobId = 1000; /* another ref NULL pointer */
290       break;
291    case 1:
292       store = get_storage_resource(ua, false/*no default*/);
293       if (store) {
294          do_storage_die(ua, store);
295       }
296       break;
297    case 2:
298       client = select_client_resource(ua);
299       if (client) {
300          do_client_die(ua, client);
301       }
302       break;
303    default:
304       break;
305    }
306    return true;
307 }
308
309 #else
310
311 /*
312  * Dummy routine for non-development version
313  */
314 static bool diecmd(UAContext *ua, const char *cmd)
315 {
316    return true;
317 }
318
319 #endif
320
321 static bool jobscmd(UAContext *ua, const char *cmd)
322 {
323    JOB *job;
324    LockRes();
325    foreach_res(job, R_JOB) {
326       if (acl_access_ok(ua, Job_ACL, job->name())) {
327          ua->send_msg("%s\n", job->name());
328       }
329    }
330    UnlockRes();
331    return true;
332 }
333
334 static bool filesetscmd(UAContext *ua, const char *cmd)
335 {
336    FILESET *fs;
337    LockRes();
338    foreach_res(fs, R_FILESET) {
339       if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
340          ua->send_msg("%s\n", fs->name());
341       }
342    }
343    UnlockRes();
344    return true;
345 }
346
347 static bool clientscmd(UAContext *ua, const char *cmd)
348 {
349    CLIENT *client;       
350    LockRes();
351    foreach_res(client, R_CLIENT) {
352       if (acl_access_ok(ua, Client_ACL, client->name())) {
353          ua->send_msg("%s\n", client->name());
354       }
355    }
356    UnlockRes();
357    return true;
358 }
359
360 static bool msgscmd(UAContext *ua, const char *cmd)
361 {
362    MSGS *msgs = NULL;
363    LockRes();
364    foreach_res(msgs, R_MSGS) {
365       ua->send_msg("%s\n", msgs->name());
366    }
367    UnlockRes();
368    return true;
369 }
370
371 static bool poolscmd(UAContext *ua, const char *cmd)
372 {
373    POOL *pool;       
374    LockRes();
375    foreach_res(pool, R_POOL) {
376       if (acl_access_ok(ua, Pool_ACL, pool->name())) {
377          ua->send_msg("%s\n", pool->name());
378       }
379    }
380    UnlockRes();
381    return true;
382 }
383
384 static bool storagecmd(UAContext *ua, const char *cmd)
385 {
386    STORE *store;
387    LockRes();
388    foreach_res(store, R_STORAGE) {
389       if (acl_access_ok(ua, Storage_ACL, store->name())) {
390          ua->send_msg("%s\n", store->name());
391       }
392    }
393    UnlockRes();
394    return true;
395 }
396
397
398 static bool typescmd(UAContext *ua, const char *cmd)
399 {
400    ua->send_msg("Backup\n");
401    ua->send_msg("Restore\n");
402    ua->send_msg("Admin\n");
403    ua->send_msg("Verify\n");
404    ua->send_msg("Migrate\n");
405    return true;
406 }
407
408
409 /*
410  * If this command is called, it tells the director that we
411  *  are a program that wants a sort of API, and hence,
412  *  we will probably suppress certain output, include more
413  *  error codes, and most of all send back a good number
414  *  of new signals that indicate whether or not the command
415  *  succeeded.
416  */
417 static bool api_cmd(UAContext *ua, const char *cmd)
418 {
419    if (ua->argc == 2) {
420       ua->api = atoi(ua->argk[1]);
421    } else {
422       ua->api = 1;
423    }
424    return true;
425 }
426
427 static int client_backups_handler(void *ctx, int num_field, char **row)
428 {
429    UAContext *ua = (UAContext *)ctx;
430    ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
431       row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
432    return 0;
433 }
434
435 /*
436  * Return the backups for this client 
437  *
438  *  .backups client=xxx fileset=yyy
439  *
440  */
441 static bool backupscmd(UAContext *ua, const char *cmd)
442 {
443    if (!open_client_db(ua)) {
444       return true;
445    }
446    if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 || 
447        strcmp(ua->argk[2], "fileset") != 0) {
448       return true;
449    }
450    if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
451        !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
452       ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
453       return true;
454    }
455    Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
456    if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
457       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
458       return true;
459    }
460    return true;
461 }
462
463 static int sql_handler(void *ctx, int num_field, char **row)
464 {
465    UAContext *ua = (UAContext *)ctx;
466    POOL_MEM rows(PM_MESSAGE);
467
468    for (int i=0; num_field--; i++) {
469       if (i == 0) {
470          pm_strcpy(rows, row[0]);
471       } else {
472          pm_strcat(rows, row[i]);
473       }
474       pm_strcat(rows, "\t");
475    }
476    ua->send_msg(rows.c_str());
477    return 0;
478 }
479
480 static bool sql_cmd(UAContext *ua, const char *cmd)
481 {
482    int index;
483    if (!open_client_db(ua)) {
484       return true;
485    }
486    index = find_arg_with_value(ua, "query");
487    if (index < 0) {
488       ua->error_msg(_("query keyword not found.\n"));
489       return true;
490    }
491    if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
492       Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
493       ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
494       return true;
495    }
496    return true;
497 }
498       
499
500
501 static bool levelscmd(UAContext *ua, const char *cmd)
502 {
503    ua->send_msg("Incremental\n");
504    ua->send_msg("Full\n");
505    ua->send_msg("Differential\n");
506    ua->send_msg("Catalog\n");
507    ua->send_msg("InitCatalog\n");
508    ua->send_msg("VolumeToCatalog\n");
509    return true;
510 }
511
512 /*
513  * Return default values for a job
514  */
515 static bool defaultscmd(UAContext *ua, const char *cmd)
516 {
517    JOB *job;
518    CLIENT *client;
519    STORE *storage;
520    POOL *pool;
521    char ed1[50];
522
523    if (ua->argc != 2 || !ua->argv[1]) {
524       return true;
525    }
526
527    /* Job defaults */   
528    if (strcmp(ua->argk[1], "job") == 0) {
529       if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
530          return true;
531       }
532       job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
533       if (job) {
534          USTORE store;
535          ua->send_msg("job=%s", job->name());
536          ua->send_msg("pool=%s", job->pool->name());
537          ua->send_msg("messages=%s", job->messages->name());
538          ua->send_msg("client=%s", job->client->name());
539          get_job_storage(&store, job, NULL);
540          ua->send_msg("storage=%s", store.store->name());
541          ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
542          ua->send_msg("level=%s", level_to_str(job->JobLevel));
543          ua->send_msg("type=%s", job_type_to_str(job->JobType));
544          ua->send_msg("fileset=%s", job->fileset->name());
545          ua->send_msg("enabled=%d", job->enabled);
546          ua->send_msg("catalog=%s", job->client->catalog->name());
547       }
548    } 
549    /* Client defaults */
550    else if (strcmp(ua->argk[1], "client") == 0) {
551       if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
552          return true;   
553       }
554       client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
555       if (client) {
556          ua->send_msg("client=%s", client->name());
557          ua->send_msg("address=%s", client->address);
558          ua->send_msg("fdport=%d", client->FDport);
559          ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
560          ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
561          ua->send_msg("autoprune=%d", client->AutoPrune);
562          ua->send_msg("catalog=%s", client->catalog->name());
563       }
564    }
565    /* Storage defaults */
566    else if (strcmp(ua->argk[1], "storage") == 0) {
567       if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
568          return true;
569       }
570       storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
571       DEVICE *device;
572       if (storage) {
573          ua->send_msg("storage=%s", storage->name());
574          ua->send_msg("address=%s", storage->address);
575          ua->send_msg("enabled=%d", storage->enabled);
576          ua->send_msg("media_type=%s", storage->media_type);
577          ua->send_msg("sdport=%d", storage->SDport);
578          device = (DEVICE *)storage->device->first();
579          ua->send_msg("device=%s", device->name());
580          if (storage->device->size() > 1) {
581             while ((device = (DEVICE *)storage->device->next())) {
582                ua->send_msg(",%s", device->name());
583             }
584          }
585       }
586    }
587    /* Pool defaults */
588    else if (strcmp(ua->argk[1], "pool") == 0) {
589       if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
590          return true;
591       }
592       pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
593       if (pool) {
594          ua->send_msg("pool=%s", pool->name());
595          ua->send_msg("pool_type=%s", pool->pool_type);
596          ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
597          ua->send_msg("use_volume_once=%d", pool->use_volume_once);
598          ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
599          ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
600          ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
601          ua->send_msg("max_volumes=%d", pool->max_volumes);
602          ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
603          ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
604          ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
605          ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
606          ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
607          ua->send_msg("auto_prune=%d", pool->AutoPrune);
608          ua->send_msg("recycle=%d", pool->Recycle);
609       }
610    }
611    return true;
612 }