2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2008 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 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.
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; };
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}
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) {
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)) {
125 Dmsg1(100, "Cmd: %s\n", ua->cmd);
127 if (ua->api) user->signal(BNET_CMD_BEGIN);
128 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
135 pm_strcat(user->msg, _(": is an invalid command.\n"));
136 ua->error_msg("%s", user->msg);
139 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
143 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
149 static bool dot_help_cmd(UAContext *ua, const char *cmd)
155 static bool getmsgscmd(UAContext *ua, const char *cmd)
157 if (console_msg_pending) {
158 do_messages(ua, cmd);
164 static void do_storage_die(UAContext *ua, STORE *store)
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"));
180 Dmsg0(120, _("Connected to storage daemon\n"));
181 sd = jcr->store_bsock;
183 if (sd->recv() >= 0) {
184 ua->send_msg("%s", sd->msg);
186 sd->signal(BNET_TERMINATE);
188 jcr->store_bsock = NULL;
192 static void do_client_die(UAContext *ua, CLIENT *client)
196 /* Connect to File daemon */
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"));
206 Dmsg0(120, "Connected to file daemon\n");
207 fd = ua->jcr->file_bsock;
209 if (fd->recv() >= 0) {
210 ua->send_msg("%s", fd->msg);
212 fd->signal(BNET_TERMINATE);
214 ua->jcr->file_bsock = NULL;
219 * Create segmentation fault
221 static bool diecmd(UAContext *ua, const char *cmd)
229 Dmsg1(120, "diecmd:%s:\n", cmd);
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 */
240 if (strcasecmp(ua->argk[i], "client") == 0 ||
241 strcasecmp(ua->argk[i], "fd") == 0) {
244 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
246 do_client_die(ua, client);
250 client = select_client_resource(ua);
252 do_client_die(ua, client);
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) {
262 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
264 do_storage_die(ua, store);
268 store = get_storage_resource(ua, false/*no default*/);
270 do_storage_die(ua, store);
276 * We didn't find an appropriate keyword above, so
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 */
290 store = get_storage_resource(ua, false/*no default*/);
292 do_storage_die(ua, store);
296 client = select_client_resource(ua);
298 do_client_die(ua, client);
310 * Dummy routine for non-development version
312 static bool diecmd(UAContext *ua, const char *cmd)
319 static bool jobscmd(UAContext *ua, const char *cmd)
323 foreach_res(job, R_JOB) {
324 if (acl_access_ok(ua, Job_ACL, job->name())) {
325 ua->send_msg("%s\n", job->name());
332 static bool filesetscmd(UAContext *ua, const char *cmd)
336 foreach_res(fs, R_FILESET) {
337 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
338 ua->send_msg("%s\n", fs->name());
345 static bool clientscmd(UAContext *ua, const char *cmd)
349 foreach_res(client, R_CLIENT) {
350 if (acl_access_ok(ua, Client_ACL, client->name())) {
351 ua->send_msg("%s\n", client->name());
358 static bool msgscmd(UAContext *ua, const char *cmd)
362 foreach_res(msgs, R_MSGS) {
363 ua->send_msg("%s\n", msgs->name());
369 static bool poolscmd(UAContext *ua, const char *cmd)
373 foreach_res(pool, R_POOL) {
374 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
375 ua->send_msg("%s\n", pool->name());
382 static bool storagecmd(UAContext *ua, const char *cmd)
386 foreach_res(store, R_STORAGE) {
387 if (acl_access_ok(ua, Storage_ACL, store->name())) {
388 ua->send_msg("%s\n", store->name());
396 static bool typescmd(UAContext *ua, const char *cmd)
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");
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
415 static bool api_cmd(UAContext *ua, const char *cmd)
418 ua->api = atoi(ua->argk[1]);
425 static int client_backups_handler(void *ctx, int num_field, char **row)
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]);
434 * Return the backups for this client
436 * .backups client=xxx fileset=yyy
439 static bool backupscmd(UAContext *ua, const char *cmd)
441 if (!open_client_db(ua)) {
444 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
445 strcmp(ua->argk[2], "fileset") != 0) {
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"));
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));
461 static int sql_handler(void *ctx, int num_field, char **row)
463 UAContext *ua = (UAContext *)ctx;
464 POOL_MEM rows(PM_MESSAGE);
466 for (int i=0; num_field--; i++) {
468 pm_strcpy(rows, NPRT(row[0]));
470 pm_strcat(rows, NPRT(row[i]));
472 pm_strcat(rows, "\t");
474 if (!rows.c_str() || !*rows.c_str()) {
477 ua->send_msg("%s", rows.c_str());
482 static bool sql_cmd(UAContext *ua, const char *cmd)
485 if (!open_client_db(ua)) {
488 index = find_arg_with_value(ua, "query");
490 ua->error_msg(_("query keyword not found.\n"));
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));
503 static bool levelscmd(UAContext *ua, const char *cmd)
505 ua->send_msg("Incremental\n");
506 ua->send_msg("Full\n");
507 ua->send_msg("Differential\n");
508 ua->send_msg("Catalog\n");
509 ua->send_msg("InitCatalog\n");
510 ua->send_msg("VolumeToCatalog\n");
515 * Return default values for a job
517 static bool defaultscmd(UAContext *ua, const char *cmd)
525 if (ua->argc != 2 || !ua->argv[1]) {
530 if (strcmp(ua->argk[1], "job") == 0) {
531 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
534 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
537 ua->send_msg("job=%s", job->name());
538 ua->send_msg("pool=%s", job->pool->name());
539 ua->send_msg("messages=%s", job->messages->name());
540 ua->send_msg("client=%s", job->client->name());
541 get_job_storage(&store, job, NULL);
542 ua->send_msg("storage=%s", store.store->name());
543 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
544 ua->send_msg("level=%s", level_to_str(job->JobLevel));
545 ua->send_msg("type=%s", job_type_to_str(job->JobType));
546 ua->send_msg("fileset=%s", job->fileset->name());
547 ua->send_msg("enabled=%d", job->enabled);
548 ua->send_msg("catalog=%s", job->client->catalog->name());
551 /* Client defaults */
552 else if (strcmp(ua->argk[1], "client") == 0) {
553 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
556 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
558 ua->send_msg("client=%s", client->name());
559 ua->send_msg("address=%s", client->address);
560 ua->send_msg("fdport=%d", client->FDport);
561 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
562 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
563 ua->send_msg("autoprune=%d", client->AutoPrune);
564 ua->send_msg("catalog=%s", client->catalog->name());
567 /* Storage defaults */
568 else if (strcmp(ua->argk[1], "storage") == 0) {
569 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
572 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
575 ua->send_msg("storage=%s", storage->name());
576 ua->send_msg("address=%s", storage->address);
577 ua->send_msg("enabled=%d", storage->enabled);
578 ua->send_msg("media_type=%s", storage->media_type);
579 ua->send_msg("sdport=%d", storage->SDport);
580 device = (DEVICE *)storage->device->first();
581 ua->send_msg("device=%s", device->name());
582 if (storage->device->size() > 1) {
583 while ((device = (DEVICE *)storage->device->next())) {
584 ua->send_msg(",%s", device->name());
590 else if (strcmp(ua->argk[1], "pool") == 0) {
591 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
594 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
596 ua->send_msg("pool=%s", pool->name());
597 ua->send_msg("pool_type=%s", pool->pool_type);
598 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
599 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
600 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
601 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
602 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
603 ua->send_msg("max_volumes=%d", pool->max_volumes);
604 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
605 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
606 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
607 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
608 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
609 ua->send_msg("auto_prune=%d", pool->AutoPrune);
610 ua->send_msg("recycle=%d", pool->Recycle);