2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2009 Free Software Foundation Europe e.V.
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
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.
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
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.
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.
36 * Kern Sibbald, April MMII
44 /* Imported variables */
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);
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);
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);
72 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;};
73 static struct cmdstruct commands[] = { /* help */ /* can be used in runscript */
74 { NT_(".api"), api_cmd, NULL, false},
75 { NT_(".backups"), backupscmd, NULL, false},
76 { NT_(".clients"), clientscmd, NULL, true},
77 { NT_(".defaults"), defaultscmd, NULL, false},
78 { NT_(".die"), diecmd, NULL, false},
79 { NT_(".exit"), dot_quit_cmd, NULL, false},
80 { NT_(".filesets"), filesetscmd, NULL, false},
81 { NT_(".help"), dot_help_cmd, NULL, false},
82 { NT_(".jobs"), jobscmd, NULL, true},
83 { NT_(".levels"), levelscmd, NULL, false},
84 { NT_(".messages"), getmsgscmd, NULL, false},
85 { NT_(".msgs"), msgscmd, NULL, false},
86 { NT_(".pools"), poolscmd, NULL, true},
87 { NT_(".quit"), dot_quit_cmd, NULL, false},
88 { NT_(".sql"), sql_cmd, NULL, false},
89 { NT_(".status"), dot_status_cmd, NULL, false},
90 { NT_(".storage"), storagecmd, NULL, true},
91 { NT_(".types"), typescmd, NULL, false}
93 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
96 * Execute a command from the UA
98 bool do_a_dot_command(UAContext *ua)
104 BSOCK *user = ua->UA_sock;
106 Dmsg1(1400, "Dot command: %s\n", user->msg);
111 len = strlen(ua->argk[0]);
113 if (ua->api) user->signal(BNET_CMD_BEGIN);
114 if (ua->api) user->signal(BNET_CMD_OK);
115 return true; /* no op */
117 for (i=0; i<comsize; i++) { /* search for command */
118 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
119 /* Check if this command is authorized in RunScript */
120 if (ua->runscript && !commands[i].use_in_rs) {
121 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
125 /* Check if command permitted, but "quit" is always OK */
126 if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
127 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
130 Dmsg1(100, "Cmd: %s\n", ua->cmd);
132 if (ua->api) user->signal(BNET_CMD_BEGIN);
133 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
134 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
141 pm_strcat(user->msg, _(": is an invalid command.\n"));
142 ua->error_msg("%s", user->msg);
148 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
154 static bool dot_help_cmd(UAContext *ua, const char *cmd)
160 static bool getmsgscmd(UAContext *ua, const char *cmd)
162 if (console_msg_pending) {
163 do_messages(ua, cmd);
169 static void do_storage_die(UAContext *ua, STORE *store)
175 lstore.store = store;
176 pm_strcpy(lstore.store_source, _("unknown source"));
177 set_wstorage(jcr, &lstore);
178 /* Try connecting for up to 15 seconds */
179 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
180 store->name(), store->address, store->SDport);
181 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
182 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
185 Dmsg0(120, _("Connected to storage daemon\n"));
186 sd = jcr->store_bsock;
188 if (sd->recv() >= 0) {
189 ua->send_msg("%s", sd->msg);
191 sd->signal(BNET_TERMINATE);
193 jcr->store_bsock = NULL;
197 static void do_client_die(UAContext *ua, CLIENT *client)
201 /* Connect to File daemon */
203 ua->jcr->client = client;
204 /* Try to connect for 15 seconds */
205 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
206 client->name(), client->address, client->FDport);
207 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
208 ua->error_msg(_("Failed to connect to Client.\n"));
211 Dmsg0(120, "Connected to file daemon\n");
212 fd = ua->jcr->file_bsock;
214 if (fd->recv() >= 0) {
215 ua->send_msg("%s", fd->msg);
217 fd->signal(BNET_TERMINATE);
219 ua->jcr->file_bsock = NULL;
224 * Create segmentation fault
226 static bool diecmd(UAContext *ua, const char *cmd)
234 Dmsg1(120, "diecmd:%s:\n", cmd);
237 for (i=1; i<ua->argc; i++) {
238 if (strcasecmp(ua->argk[i], "dir") == 0 ||
239 strcasecmp(ua->argk[i], "director") == 0) {
240 ua->send_msg(_("The Director will segment fault.\n"));
241 a = jcr->JobId; /* ref NULL pointer */
242 jcr->JobId = 1000; /* another ref NULL pointer */
245 if (strcasecmp(ua->argk[i], "client") == 0 ||
246 strcasecmp(ua->argk[i], "fd") == 0) {
249 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
251 do_client_die(ua, client);
255 client = select_client_resource(ua);
257 do_client_die(ua, client);
262 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
263 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
264 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
267 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
269 do_storage_die(ua, store);
273 store = get_storage_resource(ua, false/*no default*/);
275 do_storage_die(ua, store);
281 * We didn't find an appropriate keyword above, so
284 start_prompt(ua, _("Available daemons are: \n"));
285 add_prompt(ua, _("Director"));
286 add_prompt(ua, _("Storage"));
287 add_prompt(ua, _("Client"));
288 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
289 case 0: /* Director */
290 ua->send_msg(_("The Director will segment fault.\n"));
291 a = jcr->JobId; /* ref NULL pointer */
292 jcr->JobId = 1000; /* another ref NULL pointer */
295 store = get_storage_resource(ua, false/*no default*/);
297 do_storage_die(ua, store);
301 client = select_client_resource(ua);
303 do_client_die(ua, client);
315 * Dummy routine for non-development version
317 static bool diecmd(UAContext *ua, const char *cmd)
324 static bool jobscmd(UAContext *ua, const char *cmd)
328 foreach_res(job, R_JOB) {
329 if (acl_access_ok(ua, Job_ACL, job->name())) {
330 ua->send_msg("%s\n", job->name());
337 static bool filesetscmd(UAContext *ua, const char *cmd)
341 foreach_res(fs, R_FILESET) {
342 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
343 ua->send_msg("%s\n", fs->name());
350 static bool clientscmd(UAContext *ua, const char *cmd)
354 foreach_res(client, R_CLIENT) {
355 if (acl_access_ok(ua, Client_ACL, client->name())) {
356 ua->send_msg("%s\n", client->name());
363 static bool msgscmd(UAContext *ua, const char *cmd)
367 foreach_res(msgs, R_MSGS) {
368 ua->send_msg("%s\n", msgs->name());
374 static bool poolscmd(UAContext *ua, const char *cmd)
378 foreach_res(pool, R_POOL) {
379 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
380 ua->send_msg("%s\n", pool->name());
387 static bool storagecmd(UAContext *ua, const char *cmd)
391 foreach_res(store, R_STORAGE) {
392 if (acl_access_ok(ua, Storage_ACL, store->name())) {
393 ua->send_msg("%s\n", store->name());
401 static bool typescmd(UAContext *ua, const char *cmd)
403 ua->send_msg("Backup\n");
404 ua->send_msg("Restore\n");
405 ua->send_msg("Admin\n");
406 ua->send_msg("Verify\n");
407 ua->send_msg("Migrate\n");
413 * If this command is called, it tells the director that we
414 * are a program that wants a sort of API, and hence,
415 * we will probably suppress certain output, include more
416 * error codes, and most of all send back a good number
417 * of new signals that indicate whether or not the command
420 static bool api_cmd(UAContext *ua, const char *cmd)
423 ua->api = atoi(ua->argk[1]);
430 static int client_backups_handler(void *ctx, int num_field, char **row)
432 UAContext *ua = (UAContext *)ctx;
433 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
434 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
439 * Return the backups for this client
441 * .backups client=xxx fileset=yyy
444 static bool backupscmd(UAContext *ua, const char *cmd)
446 if (!open_client_db(ua)) {
449 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
450 strcmp(ua->argk[2], "fileset") != 0) {
453 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
454 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
455 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
458 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
459 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
460 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
466 static int sql_handler(void *ctx, int num_field, char **row)
468 UAContext *ua = (UAContext *)ctx;
469 POOL_MEM rows(PM_MESSAGE);
471 /* Check for nonsense */
472 if (num_field == 0 || row == NULL || row[0] == NULL) {
473 return 0; /* nothing returned */
475 for (int i=0; num_field--; i++) {
477 pm_strcpy(rows, NPRT(row[0]));
479 pm_strcat(rows, NPRT(row[i]));
481 pm_strcat(rows, "\t");
483 if (!rows.c_str() || !*rows.c_str()) {
486 ua->send_msg("%s", rows.c_str());
491 static bool sql_cmd(UAContext *ua, const char *cmd)
494 if (!open_client_db(ua)) {
497 index = find_arg_with_value(ua, "query");
499 ua->error_msg(_("query keyword not found.\n"));
502 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
503 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
504 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
512 static bool levelscmd(UAContext *ua, const char *cmd)
514 ua->send_msg("Incremental\n");
515 ua->send_msg("Full\n");
516 ua->send_msg("Differential\n");
517 ua->send_msg("VirtualFull\n");
518 ua->send_msg("Catalog\n");
519 ua->send_msg("InitCatalog\n");
520 ua->send_msg("VolumeToCatalog\n");
525 * Return default values for a job
527 static bool defaultscmd(UAContext *ua, const char *cmd)
535 if (ua->argc != 2 || !ua->argv[1]) {
540 if (strcmp(ua->argk[1], "job") == 0) {
541 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
544 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
547 ua->send_msg("job=%s", job->name());
548 ua->send_msg("pool=%s", job->pool->name());
549 ua->send_msg("messages=%s", job->messages->name());
550 ua->send_msg("client=%s", job->client->name());
551 get_job_storage(&store, job, NULL);
552 ua->send_msg("storage=%s", store.store->name());
553 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
554 ua->send_msg("level=%s", level_to_str(job->JobLevel));
555 ua->send_msg("type=%s", job_type_to_str(job->JobType));
556 ua->send_msg("fileset=%s", job->fileset->name());
557 ua->send_msg("enabled=%d", job->enabled);
558 ua->send_msg("catalog=%s", job->client->catalog->name());
561 /* Client defaults */
562 else if (strcmp(ua->argk[1], "client") == 0) {
563 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
566 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
568 ua->send_msg("client=%s", client->name());
569 ua->send_msg("address=%s", client->address);
570 ua->send_msg("fdport=%d", client->FDport);
571 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
572 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
573 ua->send_msg("autoprune=%d", client->AutoPrune);
574 ua->send_msg("catalog=%s", client->catalog->name());
577 /* Storage defaults */
578 else if (strcmp(ua->argk[1], "storage") == 0) {
579 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
582 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
585 ua->send_msg("storage=%s", storage->name());
586 ua->send_msg("address=%s", storage->address);
587 ua->send_msg("enabled=%d", storage->enabled);
588 ua->send_msg("media_type=%s", storage->media_type);
589 ua->send_msg("sdport=%d", storage->SDport);
590 device = (DEVICE *)storage->device->first();
591 ua->send_msg("device=%s", device->name());
592 if (storage->device->size() > 1) {
593 while ((device = (DEVICE *)storage->device->next())) {
594 ua->send_msg(",%s", device->name());
600 else if (strcmp(ua->argk[1], "pool") == 0) {
601 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
604 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
606 ua->send_msg("pool=%s", pool->name());
607 ua->send_msg("pool_type=%s", pool->pool_type);
608 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
609 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
610 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
611 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
612 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
613 ua->send_msg("max_volumes=%d", pool->max_volumes);
614 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
615 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
616 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
617 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
618 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
619 ua->send_msg("auto_prune=%d", pool->AutoPrune);
620 ua->send_msg("recycle=%d", pool->Recycle);