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 */
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 bool do_a_dot_command(UAContext *ua)
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 true; /* 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", ua->cmd);
130 if (ua->api) user->signal(BNET_CMD_BEGIN);
131 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
138 pm_strcat(user->msg, _(": is an invalid command.\n"));
139 ua->error_msg("%s", 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, NPRT(row[0]));
473 pm_strcat(rows, NPRT(row[i]));
475 pm_strcat(rows, "\t");
477 if (!rows.c_str() || !*rows.c_str()) {
480 ua->send_msg("%s", rows.c_str());
485 static bool sql_cmd(UAContext *ua, const char *cmd)
488 if (!open_client_db(ua)) {
491 index = find_arg_with_value(ua, "query");
493 ua->error_msg(_("query keyword not found.\n"));
496 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
497 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
498 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
506 static bool levelscmd(UAContext *ua, const char *cmd)
508 ua->send_msg("Incremental\n");
509 ua->send_msg("Full\n");
510 ua->send_msg("Differential\n");
511 ua->send_msg("Catalog\n");
512 ua->send_msg("InitCatalog\n");
513 ua->send_msg("VolumeToCatalog\n");
518 * Return default values for a job
520 static bool defaultscmd(UAContext *ua, const char *cmd)
528 if (ua->argc != 2 || !ua->argv[1]) {
533 if (strcmp(ua->argk[1], "job") == 0) {
534 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
537 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
540 ua->send_msg("job=%s", job->name());
541 ua->send_msg("pool=%s", job->pool->name());
542 ua->send_msg("messages=%s", job->messages->name());
543 ua->send_msg("client=%s", job->client->name());
544 get_job_storage(&store, job, NULL);
545 ua->send_msg("storage=%s", store.store->name());
546 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
547 ua->send_msg("level=%s", level_to_str(job->JobLevel));
548 ua->send_msg("type=%s", job_type_to_str(job->JobType));
549 ua->send_msg("fileset=%s", job->fileset->name());
550 ua->send_msg("enabled=%d", job->enabled);
551 ua->send_msg("catalog=%s", job->client->catalog->name());
554 /* Client defaults */
555 else if (strcmp(ua->argk[1], "client") == 0) {
556 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
559 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
561 ua->send_msg("client=%s", client->name());
562 ua->send_msg("address=%s", client->address);
563 ua->send_msg("fdport=%d", client->FDport);
564 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
565 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
566 ua->send_msg("autoprune=%d", client->AutoPrune);
567 ua->send_msg("catalog=%s", client->catalog->name());
570 /* Storage defaults */
571 else if (strcmp(ua->argk[1], "storage") == 0) {
572 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
575 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
578 ua->send_msg("storage=%s", storage->name());
579 ua->send_msg("address=%s", storage->address);
580 ua->send_msg("enabled=%d", storage->enabled);
581 ua->send_msg("media_type=%s", storage->media_type);
582 ua->send_msg("sdport=%d", storage->SDport);
583 device = (DEVICE *)storage->device->first();
584 ua->send_msg("device=%s", device->name());
585 if (storage->device->size() > 1) {
586 while ((device = (DEVICE *)storage->device->next())) {
587 ua->send_msg(",%s", device->name());
593 else if (strcmp(ua->argk[1], "pool") == 0) {
594 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
597 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
599 ua->send_msg("pool=%s", pool->name());
600 ua->send_msg("pool_type=%s", pool->pool_type);
601 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
602 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
603 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
604 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
605 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
606 ua->send_msg("max_volumes=%d", pool->max_volumes);
607 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
608 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
609 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
610 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
611 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
612 ua->send_msg("auto_prune=%d", pool->AutoPrune);
613 ua->send_msg("recycle=%d", pool->Recycle);