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