2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2007 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 */
47 extern struct s_res resources[];
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);
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);
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);
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}
96 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
99 * Execute a command from the UA
101 int do_a_dot_command(UAContext *ua, const char *cmd)
107 BSOCK *user = ua->UA_sock;
109 Dmsg1(1400, "Dot command: %s\n", user->msg);
114 len = strlen(ua->argk[0]);
116 if (ua->api) user->signal(BNET_CMD_BEGIN);
117 if (ua->api) user->signal(BNET_CMD_OK);
118 return 1; /* no op */
120 for (i=0; i<comsize; i++) { /* search for command */
121 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
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)) {
128 Dmsg1(100, "Cmd: %s\n", cmd);
130 if (ua->api) user->signal(BNET_CMD_BEGIN);
131 ok = (*commands[i].func)(ua, cmd); /* go execute command */
138 pm_strcat(user->msg, _(": is an invalid command.\n"));
139 user->msglen = strlen(user->msg);
142 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
146 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
152 static bool dot_help_cmd(UAContext *ua, const char *cmd)
158 static bool getmsgscmd(UAContext *ua, const char *cmd)
160 if (console_msg_pending) {
161 do_messages(ua, cmd);
167 static void do_storage_die(UAContext *ua, STORE *store)
173 lstore.store = store;
174 pm_strcpy(lstore.store_source, _("unknown source"));
175 set_wstorage(jcr, &lstore);
176 /* Try connecting for up to 15 seconds */
177 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
178 store->name(), store->address, store->SDport);
179 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
180 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
183 Dmsg0(120, _("Connected to storage daemon\n"));
184 sd = jcr->store_bsock;
186 if (sd->recv() >= 0) {
187 ua->send_msg("%s", sd->msg);
189 sd->signal(BNET_TERMINATE);
191 jcr->store_bsock = NULL;
195 static void do_client_die(UAContext *ua, CLIENT *client)
199 /* Connect to File daemon */
201 ua->jcr->client = client;
202 /* Try to connect for 15 seconds */
203 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
204 client->name(), client->address, client->FDport);
205 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
206 ua->error_msg(_("Failed to connect to Client.\n"));
209 Dmsg0(120, "Connected to file daemon\n");
210 fd = ua->jcr->file_bsock;
212 if (fd->recv() >= 0) {
213 ua->send_msg("%s", fd->msg);
215 fd->signal(BNET_TERMINATE);
217 ua->jcr->file_bsock = NULL;
222 * Create segmentation fault
224 static bool diecmd(UAContext *ua, const char *cmd)
232 Dmsg1(120, "diecmd:%s:\n", cmd);
235 for (i=1; i<ua->argc; i++) {
236 if (strcasecmp(ua->argk[i], "dir") == 0 ||
237 strcasecmp(ua->argk[i], "director") == 0) {
238 ua->send_msg(_("The Director will segment fault.\n"));
239 a = jcr->JobId; /* ref NULL pointer */
240 jcr->JobId = 1000; /* another ref NULL pointer */
243 if (strcasecmp(ua->argk[i], "client") == 0 ||
244 strcasecmp(ua->argk[i], "fd") == 0) {
247 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
249 do_client_die(ua, client);
253 client = select_client_resource(ua);
255 do_client_die(ua, client);
260 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
261 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
262 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
265 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
267 do_storage_die(ua, store);
271 store = get_storage_resource(ua, false/*no default*/);
273 do_storage_die(ua, store);
279 * We didn't find an appropriate keyword above, so
282 start_prompt(ua, _("Available daemons are: \n"));
283 add_prompt(ua, _("Director"));
284 add_prompt(ua, _("Storage"));
285 add_prompt(ua, _("Client"));
286 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
287 case 0: /* Director */
288 ua->send_msg(_("The Director will segment fault.\n"));
289 a = jcr->JobId; /* ref NULL pointer */
290 jcr->JobId = 1000; /* another ref NULL pointer */
293 store = get_storage_resource(ua, false/*no default*/);
295 do_storage_die(ua, store);
299 client = select_client_resource(ua);
301 do_client_die(ua, client);
313 * Dummy routine for non-development version
315 static bool diecmd(UAContext *ua, const char *cmd)
322 static bool jobscmd(UAContext *ua, const char *cmd)
326 foreach_res(job, R_JOB) {
327 if (acl_access_ok(ua, Job_ACL, job->name())) {
328 ua->send_msg("%s\n", job->name());
335 static bool filesetscmd(UAContext *ua, const char *cmd)
339 foreach_res(fs, R_FILESET) {
340 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
341 ua->send_msg("%s\n", fs->name());
348 static bool clientscmd(UAContext *ua, const char *cmd)
352 foreach_res(client, R_CLIENT) {
353 if (acl_access_ok(ua, Client_ACL, client->name())) {
354 ua->send_msg("%s\n", client->name());
361 static bool msgscmd(UAContext *ua, const char *cmd)
365 foreach_res(msgs, R_MSGS) {
366 ua->send_msg("%s\n", msgs->name());
372 static bool poolscmd(UAContext *ua, const char *cmd)
376 foreach_res(pool, R_POOL) {
377 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
378 ua->send_msg("%s\n", pool->name());
385 static bool storagecmd(UAContext *ua, const char *cmd)
389 foreach_res(store, R_STORAGE) {
390 if (acl_access_ok(ua, Storage_ACL, store->name())) {
391 ua->send_msg("%s\n", store->name());
399 static bool typescmd(UAContext *ua, const char *cmd)
401 ua->send_msg("Backup\n");
402 ua->send_msg("Restore\n");
403 ua->send_msg("Admin\n");
404 ua->send_msg("Verify\n");
405 ua->send_msg("Migrate\n");
411 * If this command is called, it tells the director that we
412 * are a program that wants a sort of API, and hence,
413 * we will probably suppress certain output, include more
414 * error codes, and most of all send back a good number
415 * of new signals that indicate whether or not the command
418 static bool api_cmd(UAContext *ua, const char *cmd)
421 ua->api = atoi(ua->argk[1]);
428 static int client_backups_handler(void *ctx, int num_field, char **row)
430 UAContext *ua = (UAContext *)ctx;
431 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
432 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
437 * Return the backups for this client
439 * .backups client=xxx fileset=yyy
442 static bool backupscmd(UAContext *ua, const char *cmd)
444 if (!open_client_db(ua)) {
447 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
448 strcmp(ua->argk[2], "fileset") != 0) {
451 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
452 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
453 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
456 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
457 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
458 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
464 static int sql_handler(void *ctx, int num_field, char **row)
466 UAContext *ua = (UAContext *)ctx;
467 POOL_MEM rows(PM_MESSAGE);
469 for (int i=0; num_field--; i++) {
471 pm_strcpy(rows, row[0]);
473 pm_strcat(rows, row[i]);
475 pm_strcat(rows, "\t");
477 ua->send_msg(rows.c_str());
481 static bool sql_cmd(UAContext *ua, const char *cmd)
484 if (!open_client_db(ua)) {
487 index = find_arg_with_value(ua, "query");
489 ua->error_msg(_("query keyword not found.\n"));
492 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
493 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
494 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
502 static bool levelscmd(UAContext *ua, const char *cmd)
504 ua->send_msg("Incremental\n");
505 ua->send_msg("Full\n");
506 ua->send_msg("Differential\n");
507 ua->send_msg("Catalog\n");
508 ua->send_msg("InitCatalog\n");
509 ua->send_msg("VolumeToCatalog\n");
514 * Return default values for a job
516 static bool defaultscmd(UAContext *ua, const char *cmd)
524 if (ua->argc != 2 || !ua->argv[1]) {
529 if (strcmp(ua->argk[1], "job") == 0) {
530 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
533 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
536 ua->send_msg("job=%s", job->name());
537 ua->send_msg("pool=%s", job->pool->name());
538 ua->send_msg("messages=%s", job->messages->name());
539 ua->send_msg("client=%s", job->client->name());
540 get_job_storage(&store, job, NULL);
541 ua->send_msg("storage=%s", store.store->name());
542 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
543 ua->send_msg("level=%s", level_to_str(job->JobLevel));
544 ua->send_msg("type=%s", job_type_to_str(job->JobType));
545 ua->send_msg("fileset=%s", job->fileset->name());
546 ua->send_msg("enabled=%d", job->enabled);
547 ua->send_msg("catalog=%s", job->client->catalog->name());
550 /* Client defaults */
551 else if (strcmp(ua->argk[1], "client") == 0) {
552 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
555 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
557 ua->send_msg("client=%s", client->name());
558 ua->send_msg("address=%s", client->address);
559 ua->send_msg("fdport=%d", client->FDport);
560 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
561 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
562 ua->send_msg("autoprune=%d", client->AutoPrune);
563 ua->send_msg("catalog=%s", client->catalog->name());
566 /* Storage defaults */
567 else if (strcmp(ua->argk[1], "storage") == 0) {
568 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
571 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
574 ua->send_msg("storage=%s", storage->name());
575 ua->send_msg("address=%s", storage->address);
576 ua->send_msg("enabled=%d", storage->enabled);
577 ua->send_msg("media_type=%s", storage->media_type);
578 ua->send_msg("sdport=%d", storage->SDport);
579 device = (DEVICE *)storage->device->first();
580 ua->send_msg("device=%s", device->name());
581 if (storage->device->size() > 1) {
582 while ((device = (DEVICE *)storage->device->next())) {
583 ua->send_msg(",%s", device->name());
589 else if (strcmp(ua->argk[1], "pool") == 0) {
590 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
593 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
595 ua->send_msg("pool=%s", pool->name());
596 ua->send_msg("pool_type=%s", pool->pool_type);
597 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
598 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
599 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
600 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
601 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
602 ua->send_msg("max_volumes=%d", pool->max_volumes);
603 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
604 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
605 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
606 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
607 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
608 ua->send_msg("auto_prune=%d", pool->AutoPrune);
609 ua->send_msg("recycle=%d", pool->Recycle);