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 plus additions
11 that are listed in the file LICENSE.
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)) {
129 if (ua->api) user->signal(BNET_CMD_BEGIN);
130 ok = (*commands[i].func)(ua, cmd); /* go execute command */
137 pm_strcat(user->msg, _(": is an invalid command.\n"));
138 user->msglen = strlen(user->msg);
141 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
145 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
151 static bool dot_help_cmd(UAContext *ua, const char *cmd)
157 static bool getmsgscmd(UAContext *ua, const char *cmd)
159 if (console_msg_pending) {
160 do_messages(ua, cmd);
166 static void do_storage_die(UAContext *ua, STORE *store)
172 lstore.store = store;
173 pm_strcpy(lstore.store_source, _("unknown source"));
174 set_wstorage(jcr, &lstore);
175 /* Try connecting for up to 15 seconds */
176 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
177 store->name(), store->address, store->SDport);
178 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
179 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
182 Dmsg0(120, _("Connected to storage daemon\n"));
183 sd = jcr->store_bsock;
185 if (sd->recv() >= 0) {
186 ua->send_msg("%s", sd->msg);
188 sd->signal(BNET_TERMINATE);
190 jcr->store_bsock = NULL;
194 static void do_client_die(UAContext *ua, CLIENT *client)
198 /* Connect to File daemon */
200 ua->jcr->client = client;
201 /* Try to connect for 15 seconds */
202 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
203 client->name(), client->address, client->FDport);
204 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
205 ua->error_msg(_("Failed to connect to Client.\n"));
208 Dmsg0(120, "Connected to file daemon\n");
209 fd = ua->jcr->file_bsock;
211 if (fd->recv() >= 0) {
212 ua->send_msg("%s", fd->msg);
214 fd->signal(BNET_TERMINATE);
216 ua->jcr->file_bsock = NULL;
221 * Create segmentation fault
223 static bool diecmd(UAContext *ua, const char *cmd)
231 Dmsg1(120, "diecmd:%s:\n", cmd);
234 for (i=1; i<ua->argc; i++) {
235 if (strcasecmp(ua->argk[i], "dir") == 0 ||
236 strcasecmp(ua->argk[i], "director") == 0) {
237 ua->send_msg(_("The Director will segment fault.\n"));
238 a = jcr->JobId; /* ref NULL pointer */
239 jcr->JobId = 1000; /* another ref NULL pointer */
242 if (strcasecmp(ua->argk[i], "client") == 0 ||
243 strcasecmp(ua->argk[i], "fd") == 0) {
246 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
248 do_client_die(ua, client);
252 client = select_client_resource(ua);
254 do_client_die(ua, client);
259 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
260 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
261 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
264 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
266 do_storage_die(ua, store);
270 store = get_storage_resource(ua, false/*no default*/);
272 do_storage_die(ua, store);
278 * We didn't find an appropriate keyword above, so
281 start_prompt(ua, _("Available daemons are: \n"));
282 add_prompt(ua, _("Director"));
283 add_prompt(ua, _("Storage"));
284 add_prompt(ua, _("Client"));
285 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
286 case 0: /* Director */
287 ua->send_msg(_("The Director will segment fault.\n"));
288 a = jcr->JobId; /* ref NULL pointer */
289 jcr->JobId = 1000; /* another ref NULL pointer */
292 store = get_storage_resource(ua, false/*no default*/);
294 do_storage_die(ua, store);
298 client = select_client_resource(ua);
300 do_client_die(ua, client);
312 * Dummy routine for non-development version
314 static bool diecmd(UAContext *ua, const char *cmd)
321 static bool jobscmd(UAContext *ua, const char *cmd)
325 foreach_res(job, R_JOB) {
326 if (acl_access_ok(ua, Job_ACL, job->name())) {
327 ua->send_msg("%s\n", job->name());
334 static bool filesetscmd(UAContext *ua, const char *cmd)
338 foreach_res(fs, R_FILESET) {
339 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
340 ua->send_msg("%s\n", fs->name());
347 static bool clientscmd(UAContext *ua, const char *cmd)
351 foreach_res(client, R_CLIENT) {
352 if (acl_access_ok(ua, Client_ACL, client->name())) {
353 ua->send_msg("%s\n", client->name());
360 static bool msgscmd(UAContext *ua, const char *cmd)
364 foreach_res(msgs, R_MSGS) {
365 ua->send_msg("%s\n", msgs->name());
371 static bool poolscmd(UAContext *ua, const char *cmd)
375 foreach_res(pool, R_POOL) {
376 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
377 ua->send_msg("%s\n", pool->name());
384 static bool storagecmd(UAContext *ua, const char *cmd)
388 foreach_res(store, R_STORAGE) {
389 if (acl_access_ok(ua, Storage_ACL, store->name())) {
390 ua->send_msg("%s\n", store->name());
398 static bool typescmd(UAContext *ua, const char *cmd)
400 ua->send_msg("Backup\n");
401 ua->send_msg("Restore\n");
402 ua->send_msg("Admin\n");
403 ua->send_msg("Verify\n");
404 ua->send_msg("Migrate\n");
410 * If this command is called, it tells the director that we
411 * are a program that wants a sort of API, and hence,
412 * we will probably suppress certain output, include more
413 * error codes, and most of all send back a good number
414 * of new signals that indicate whether or not the command
417 static bool api_cmd(UAContext *ua, const char *cmd)
420 ua->api = atoi(ua->argk[1]);
427 static int client_backups_handler(void *ctx, int num_field, char **row)
429 UAContext *ua = (UAContext *)ctx;
430 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
431 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
436 * Return the backups for this client
438 * .backups client=xxx fileset=yyy
441 static bool backupscmd(UAContext *ua, const char *cmd)
443 if (!open_client_db(ua)) {
446 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
447 strcmp(ua->argk[2], "fileset") != 0) {
450 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
451 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
452 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
455 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
456 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
457 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
463 static int sql_handler(void *ctx, int num_field, char **row)
465 UAContext *ua = (UAContext *)ctx;
466 POOL_MEM rows(PM_MESSAGE);
468 for (int i=0; num_field--; i++) {
470 pm_strcpy(rows, row[0]);
472 pm_strcat(rows, row[i]);
474 pm_strcat(rows, "\t");
476 ua->send_msg(rows.c_str());
480 static bool sql_cmd(UAContext *ua, const char *cmd)
483 if (!open_client_db(ua)) {
486 index = find_arg_with_value(ua, "query");
488 ua->error_msg(_("query keyword not found.\n"));
491 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
492 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
493 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
501 static bool levelscmd(UAContext *ua, const char *cmd)
503 ua->send_msg("Incremental\n");
504 ua->send_msg("Full\n");
505 ua->send_msg("Differential\n");
506 ua->send_msg("Catalog\n");
507 ua->send_msg("InitCatalog\n");
508 ua->send_msg("VolumeToCatalog\n");
513 * Return default values for a job
515 static bool defaultscmd(UAContext *ua, const char *cmd)
523 if (ua->argc != 2 || !ua->argv[1]) {
528 if (strcmp(ua->argk[1], "job") == 0) {
529 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
532 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
535 ua->send_msg("job=%s", job->name());
536 ua->send_msg("pool=%s", job->pool->name());
537 ua->send_msg("messages=%s", job->messages->name());
538 ua->send_msg("client=%s", job->client->name());
539 get_job_storage(&store, job, NULL);
540 ua->send_msg("storage=%s", store.store->name());
541 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
542 ua->send_msg("level=%s", level_to_str(job->JobLevel));
543 ua->send_msg("type=%s", job_type_to_str(job->JobType));
544 ua->send_msg("fileset=%s", job->fileset->name());
545 ua->send_msg("enabled=%d", job->enabled);
546 ua->send_msg("catalog=%s", job->client->catalog->name());
549 /* Client defaults */
550 else if (strcmp(ua->argk[1], "client") == 0) {
551 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
554 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
556 ua->send_msg("client=%s", client->name());
557 ua->send_msg("address=%s", client->address);
558 ua->send_msg("fdport=%d", client->FDport);
559 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
560 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
561 ua->send_msg("autoprune=%d", client->AutoPrune);
562 ua->send_msg("catalog=%s", client->catalog->name());
565 /* Storage defaults */
566 else if (strcmp(ua->argk[1], "storage") == 0) {
567 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
570 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
573 ua->send_msg("storage=%s", storage->name());
574 ua->send_msg("address=%s", storage->address);
575 ua->send_msg("enabled=%d", storage->enabled);
576 ua->send_msg("media_type=%s", storage->media_type);
577 ua->send_msg("sdport=%d", storage->SDport);
578 device = (DEVICE *)storage->device->first();
579 ua->send_msg("device=%s", device->name());
580 if (storage->device->size() > 1) {
581 while ((device = (DEVICE *)storage->device->next())) {
582 ua->send_msg(",%s", device->name());
588 else if (strcmp(ua->argk[1], "pool") == 0) {
589 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
592 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
594 ua->send_msg("pool=%s", pool->name());
595 ua->send_msg("pool_type=%s", pool->pool_type);
596 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
597 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
598 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
599 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
600 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
601 ua->send_msg("max_volumes=%d", pool->max_volumes);
602 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
603 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
604 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
605 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
606 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
607 ua->send_msg("auto_prune=%d", pool->AutoPrune);
608 ua->send_msg("recycle=%d", pool->Recycle);