2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2010 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 three of the GNU Affero 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 Affero 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
42 #include "cats/bvfs.h"
43 #include "findlib/find.h"
45 /* Imported variables */
47 /* Imported functions */
48 extern void do_messages(UAContext *ua, const char *cmd);
49 extern int quit_cmd(UAContext *ua, const char *cmd);
50 extern int qhelp_cmd(UAContext *ua, const char *cmd);
51 extern bool dot_status_cmd(UAContext *ua, const char *cmd);
54 /* Forward referenced functions */
55 static bool admin_cmds(UAContext *ua, const char *cmd);
56 static bool jobscmd(UAContext *ua, const char *cmd);
57 static bool filesetscmd(UAContext *ua, const char *cmd);
58 static bool clientscmd(UAContext *ua, const char *cmd);
59 static bool msgscmd(UAContext *ua, const char *cmd);
60 static bool poolscmd(UAContext *ua, const char *cmd);
61 static bool storagecmd(UAContext *ua, const char *cmd);
62 static bool defaultscmd(UAContext *ua, const char *cmd);
63 static bool typescmd(UAContext *ua, const char *cmd);
64 static bool backupscmd(UAContext *ua, const char *cmd);
65 static bool levelscmd(UAContext *ua, const char *cmd);
66 static bool getmsgscmd(UAContext *ua, const char *cmd);
67 static bool volstatuscmd(UAContext *ua, const char *cmd);
68 static bool mediatypescmd(UAContext *ua, const char *cmd);
69 static bool locationscmd(UAContext *ua, const char *cmd);
70 static bool mediacmd(UAContext *ua, const char *cmd);
71 static bool aopcmd(UAContext *ua, const char *cmd);
73 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd);
74 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd);
75 static bool dot_bvfs_update(UAContext *ua, const char *cmd);
76 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd);
77 static bool dot_bvfs_versions(UAContext *ua, const char *cmd);
78 static bool dot_bvfs_restore(UAContext *ua, const char *cmd);
79 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd);
81 static bool api_cmd(UAContext *ua, const char *cmd);
82 static bool sql_cmd(UAContext *ua, const char *cmd);
83 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
84 static bool dot_help_cmd(UAContext *ua, const char *cmd);
85 static int one_handler(void *ctx, int num_field, char **row);
87 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;};
88 static struct cmdstruct commands[] = { /* help */ /* can be used in runscript */
89 { NT_(".api"), api_cmd, NULL, false},
90 { NT_(".backups"), backupscmd, NULL, false},
91 { NT_(".clients"), clientscmd, NULL, true},
92 { NT_(".defaults"), defaultscmd, NULL, false},
93 { NT_(".die"), admin_cmds, NULL, false},
94 { NT_(".dump"), admin_cmds, NULL, false},
95 { NT_(".exit"), admin_cmds, NULL, false},
96 { NT_(".filesets"), filesetscmd, NULL, false},
97 { NT_(".help"), dot_help_cmd, NULL, false},
98 { NT_(".jobs"), jobscmd, NULL, true},
99 { NT_(".levels"), levelscmd, NULL, false},
100 { NT_(".messages"), getmsgscmd, NULL, false},
101 { NT_(".msgs"), msgscmd, NULL, false},
102 { NT_(".pools"), poolscmd, NULL, true},
103 { NT_(".quit"), dot_quit_cmd, NULL, false},
104 { NT_(".sql"), sql_cmd, NULL, false},
105 { NT_(".status"), dot_status_cmd, NULL, false},
106 { NT_(".storage"), storagecmd, NULL, true},
107 { NT_(".volstatus"), volstatuscmd, NULL, true},
108 { NT_(".media"), mediacmd, NULL, true},
109 { NT_(".mediatypes"), mediatypescmd, NULL, true},
110 { NT_(".locations"), locationscmd, NULL, true},
111 { NT_(".actiononpurge"),aopcmd, NULL, true},
112 { NT_(".bvfs_lsdirs"), dot_bvfs_lsdirs, NULL, true},
113 { NT_(".bvfs_lsfiles"),dot_bvfs_lsfiles, NULL, true},
114 { NT_(".bvfs_update"), dot_bvfs_update, NULL, true},
115 { NT_(".bvfs_get_jobids"), dot_bvfs_get_jobids, NULL, true},
116 { NT_(".bvfs_versions"), dot_bvfs_versions, NULL, true},
117 { NT_(".bvfs_restore"), dot_bvfs_restore, NULL, true},
118 { NT_(".bvfs_cleanup"), dot_bvfs_cleanup, NULL, true},
119 { NT_(".types"), typescmd, NULL, false}
121 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
124 * Execute a command from the UA
126 bool do_a_dot_command(UAContext *ua)
132 BSOCK *user = ua->UA_sock;
134 Dmsg1(1400, "Dot command: %s\n", user->msg);
139 len = strlen(ua->argk[0]);
141 if (ua->api) user->signal(BNET_CMD_BEGIN);
142 if (ua->api) user->signal(BNET_CMD_OK);
143 return true; /* no op */
145 for (i=0; i<comsize; i++) { /* search for command */
146 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
147 /* Check if this command is authorized in RunScript */
148 if (ua->runscript && !commands[i].use_in_rs) {
149 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
153 /* Check if command permitted, but "quit" is always OK */
154 if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
155 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
158 Dmsg1(100, "Cmd: %s\n", ua->cmd);
160 if (ua->api) user->signal(BNET_CMD_BEGIN);
161 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
162 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
169 pm_strcat(user->msg, _(": is an invalid command.\n"));
170 ua->error_msg("%s", user->msg);
176 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
178 if (!open_new_client_db(ua)) {
182 int pos = find_arg_with_value(ua, "jobid");
183 if (pos != -1 && is_a_number_list(ua->argv[pos])) {
185 pm_strcpy(jobids, ua->argv[pos]);
186 bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, jobids.c_str());
188 /* update cache for all jobids */
189 bvfs_update_cache(ua->jcr, ua->db);
196 static int bvfs_result_handler(void *ctx, int fields, char **row)
198 UAContext *ua = (UAContext *)ctx;
201 char *fileid=row[BVFS_FileId];
202 char *lstat=row[BVFS_LStat];
203 char *jobid=row[BVFS_JobId];
205 char empty[] = "A A A A A A A A A A A A A A";
208 /* We need to deal with non existant path */
209 if (!fileid || !is_a_number(fileid)) {
215 memset(&statp, 0, sizeof(struct stat));
216 decode_stat(lstat, &statp, &LinkFI);
218 Dmsg1(100, "type=%s\n", row[0]);
219 if (bvfs_is_dir(row)) {
220 char *path = bvfs_basename_dir(row[BVFS_Name]);
221 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
224 } else if (bvfs_is_version(row)) {
225 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
226 row[BVFS_FilenameId], fileid, jobid,
227 lstat, row[BVFS_Md5], row[BVFS_VolName],
228 row[BVFS_VolInchanger]);
230 } else if (bvfs_is_file(row)) {
231 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
232 row[BVFS_FilenameId], fileid, jobid,
233 lstat, row[BVFS_Name]);
239 static bool bvfs_parse_arg_version(UAContext *ua,
250 for (int i=1; i<ua->argc; i++) {
251 if (fnid && strcasecmp(ua->argk[i], NT_("fnid")) == 0) {
252 if (is_a_number(ua->argv[i])) {
253 *fnid = str_to_int64(ua->argv[i]);
257 if (strcasecmp(ua->argk[i], NT_("client")) == 0) {
258 *client = ua->argv[i];
261 if (copies && strcasecmp(ua->argk[i], NT_("copies")) == 0) {
265 if (versions && strcasecmp(ua->argk[i], NT_("versions")) == 0) {
269 return (*client && *fnid > 0);
272 static bool bvfs_parse_arg(UAContext *ua,
273 DBId_t *pathid, char **path, char **jobid,
274 int *limit, int *offset)
282 for (int i=1; i<ua->argc; i++) {
283 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
284 if (is_a_number(ua->argv[i])) {
285 *pathid = str_to_int64(ua->argv[i]);
289 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
293 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
294 if (is_a_number_list(ua->argv[i])) {
295 *jobid = ua->argv[i];
299 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
300 if (is_a_number(ua->argv[i])) {
301 *limit = str_to_int64(ua->argv[i]);
305 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
306 if (is_a_number(ua->argv[i])) {
307 *offset = str_to_int64(ua->argv[i]);
312 if (!((*pathid || *path) && *jobid)) {
316 if (!open_client_db(ua)) {
323 /* .bvfs_cleanup path=b2XXXXX
325 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
328 if ((i = find_arg_with_value(ua, "path")) >= 0) {
330 Bvfs fs(ua->jcr, ua->db);
331 fs.drop_restore_list(ua->argv[i]);
336 /* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
338 static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
341 int limit=2000, offset=0, i;
342 char *path=NULL, *jobid=NULL;
343 char *empty = (char *)"";
344 char *fileid, *dirid, *hardlink, *id;
345 id = fileid = dirid = hardlink = empty;
347 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
350 ua->error_msg("Can't find jobid, pathid or path argument\n");
351 return true; /* not enough param */
354 Bvfs fs(ua->jcr, ua->db);
355 fs.set_jobids(jobid);
357 if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
358 fileid = ua->argv[i];
360 if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
363 if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
364 hardlink = ua->argv[i];
367 if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
368 ua->send_msg("OK\n");
370 ua->error_msg("Can't create restore list\n");
376 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
377 * .bvfs_lsfiles jobid=1,2,3,4 path=/
379 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
382 int limit=2000, offset=0;
383 char *path=NULL, *jobid=NULL;
387 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
390 ua->error_msg("Can't find jobid, pathid or path argument\n");
391 return true; /* not enough param */
393 if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
394 pattern = ua->argv[i];
397 Bvfs fs(ua->jcr, ua->db);
398 fs.set_jobids(jobid);
399 fs.set_handler(bvfs_result_handler, ua);
402 fs.set_pattern(pattern);
410 fs.set_offset(offset);
418 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
419 * .bvfs_lsdirs jobid=1,2,3,4 path=/
420 * .bvfs_lsdirs jobid=1,2,3,4 path=
422 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
425 int limit=2000, offset=0;
426 char *path=NULL, *jobid=NULL;
428 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
431 ua->error_msg("Can't find jobid, pathid or path argument\n");
432 return true; /* not enough param */
435 Bvfs fs(ua->jcr, ua->db);
436 fs.set_jobids(jobid);
438 fs.set_handler(bvfs_result_handler, ua);
446 fs.set_offset(offset);
448 fs.ls_special_dirs();
455 * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
458 static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
460 DBId_t pathid=0, fnid=0;
461 int limit=2000, offset=0;
462 char *path=NULL, *jobid=NULL, *client=NULL;
463 bool copies=false, versions=false;
464 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
467 ua->error_msg("Can't find jobid, pathid or path argument\n");
468 return true; /* not enough param */
471 if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
473 ua->error_msg("Can't find client or fnid argument\n");
474 return true; /* not enough param */
477 Bvfs fs(ua->jcr, ua->db);
479 fs.set_see_all_versions(versions);
480 fs.set_see_copies(copies);
481 fs.set_handler(bvfs_result_handler, ua);
482 fs.set_offset(offset);
483 fs.get_all_file_versions(pathid, fnid, client);
488 /* .bvfs_get_jobids jobid=1
489 * -> returns needed jobids to restore
490 * .bvfs_get_jobids jobid=1 all
491 * -> returns needed jobids to restore with all filesets a JobId=1 time
493 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
496 db_list_ctx jobids, tempids;
500 dbid_list ids; /* Store all FileSetIds for this client */
502 if (!open_client_db(ua)) {
506 memset(&jr, 0, sizeof(JOB_DBR));
507 if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
508 jr.JobId = str_to_int64(ua->argv[pos]);
511 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
512 ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
513 ua->cmd, db_strerror(ua->db));
517 /* If we have the "all" option, we do a search on all defined fileset
520 if (find_arg(ua, "all") > 0) {
521 edit_int64(jr.ClientId, ed1);
522 Mmsg(query, uar_sel_filesetid, ed1);
523 db_get_query_dbids(ua->jcr, ua->db, query, ids);
526 ids.DBId[0] = jr.FileSetId;
529 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
531 /* Foreach different FileSet, we build a restore jobid list */
532 for (int i=0; i < ids.num_ids; i++) {
533 jr.FileSetId = ids.DBId[i];
534 if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
540 ua->send_msg("%s\n", jobids.list);
544 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
550 static bool dot_help_cmd(UAContext *ua, const char *cmd)
556 static bool getmsgscmd(UAContext *ua, const char *cmd)
558 if (console_msg_pending) {
559 do_messages(ua, cmd);
565 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
571 lstore.store = store;
572 pm_strcpy(lstore.store_source, _("unknown source"));
573 set_wstorage(jcr, &lstore);
574 /* Try connecting for up to 15 seconds */
575 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
576 store->name(), store->address, store->SDport);
577 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
578 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
581 Dmsg0(120, _("Connected to storage daemon\n"));
582 sd = jcr->store_bsock;
583 sd->fsend("%s", cmd);
584 if (sd->recv() >= 0) {
585 ua->send_msg("%s", sd->msg);
587 sd->signal(BNET_TERMINATE);
589 jcr->store_bsock = NULL;
593 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
597 /* Connect to File daemon */
599 ua->jcr->client = client;
600 /* Try to connect for 15 seconds */
601 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
602 client->name(), client->address, client->FDport);
603 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
604 ua->error_msg(_("Failed to connect to Client.\n"));
607 Dmsg0(120, "Connected to file daemon\n");
608 fd = ua->jcr->file_bsock;
609 fd->fsend("%s", cmd);
610 if (fd->recv() >= 0) {
611 ua->send_msg("%s", fd->msg);
613 fd->signal(BNET_TERMINATE);
615 ua->jcr->file_bsock = NULL;
622 * .exit (no arg => .quit)
624 static bool admin_cmds(UAContext *ua, const char *cmd)
626 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
630 bool do_deadlock=false;
631 const char *remote_cmd;
635 if (strncmp(ua->argk[0], ".die", 4) == 0) {
636 if (find_arg(ua, "deadlock") > 0) {
638 remote_cmd = ".die deadlock";
642 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
643 remote_cmd = "sm_dump";
644 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
647 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
651 for (i=1; i<ua->argc; i++) {
652 if (strcasecmp(ua->argk[i], "dir") == 0 ||
653 strcasecmp(ua->argk[i], "director") == 0) {
656 if (strcasecmp(ua->argk[i], "client") == 0 ||
657 strcasecmp(ua->argk[i], "fd") == 0) {
660 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
663 client = select_client_resource(ua);
667 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
668 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
669 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
672 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
675 store = get_storage_resource(ua, false/*no default*/);
680 if (!dir && !store && !client) {
682 * We didn't find an appropriate keyword above, so
685 start_prompt(ua, _("Available daemons are: \n"));
686 add_prompt(ua, _("Director"));
687 add_prompt(ua, _("Storage"));
688 add_prompt(ua, _("Client"));
689 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
690 case 0: /* Director */
694 store = get_storage_resource(ua, false/*no default*/);
697 client = select_client_resource(ua);
705 do_storage_cmd(ua, store, remote_cmd);
709 do_client_cmd(ua, client, remote_cmd);
713 if (strncmp(remote_cmd, ".die", 4) == 0) {
715 ua->send_msg(_("The Director will generate a deadlock.\n"));
719 ua->send_msg(_("The Director will segment fault.\n"));
720 a = jcr->JobId; /* ref NULL pointer */
721 jcr->JobId = 1000; /* another ref NULL pointer */
723 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
724 sm_dump(false, true);
725 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
726 dot_quit_cmd(ua, cmd);
736 * Dummy routine for non-development version
738 static bool admin_cmds(UAContext *ua, const char *cmd)
740 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
747 * Can use an argument to filter on JobType
750 static bool jobscmd(UAContext *ua, const char *cmd)
755 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
756 type = ua->argv[pos][0];
759 foreach_res(job, R_JOB) {
760 if (!type || type == job->JobType) {
761 if (acl_access_ok(ua, Job_ACL, job->name())) {
762 ua->send_msg("%s\n", job->name());
770 static bool filesetscmd(UAContext *ua, const char *cmd)
774 foreach_res(fs, R_FILESET) {
775 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
776 ua->send_msg("%s\n", fs->name());
783 static bool clientscmd(UAContext *ua, const char *cmd)
787 foreach_res(client, R_CLIENT) {
788 if (acl_access_ok(ua, Client_ACL, client->name())) {
789 ua->send_msg("%s\n", client->name());
796 static bool msgscmd(UAContext *ua, const char *cmd)
800 foreach_res(msgs, R_MSGS) {
801 ua->send_msg("%s\n", msgs->name());
807 static bool poolscmd(UAContext *ua, const char *cmd)
811 foreach_res(pool, R_POOL) {
812 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
813 ua->send_msg("%s\n", pool->name());
820 static bool storagecmd(UAContext *ua, const char *cmd)
824 foreach_res(store, R_STORAGE) {
825 if (acl_access_ok(ua, Storage_ACL, store->name())) {
826 ua->send_msg("%s\n", store->name());
833 static bool aopcmd(UAContext *ua, const char *cmd)
835 ua->send_msg("None\n");
836 ua->send_msg("Truncate\n");
840 static bool typescmd(UAContext *ua, const char *cmd)
842 ua->send_msg("Backup\n");
843 ua->send_msg("Restore\n");
844 ua->send_msg("Admin\n");
845 ua->send_msg("Verify\n");
846 ua->send_msg("Migrate\n");
847 ua->send_msg("Copy\n");
852 * If this command is called, it tells the director that we
853 * are a program that wants a sort of API, and hence,
854 * we will probably suppress certain output, include more
855 * error codes, and most of all send back a good number
856 * of new signals that indicate whether or not the command
859 static bool api_cmd(UAContext *ua, const char *cmd)
862 ua->api = atoi(ua->argk[1]);
869 static int client_backups_handler(void *ctx, int num_field, char **row)
871 UAContext *ua = (UAContext *)ctx;
872 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
873 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
878 * Return the backups for this client
880 * .backups client=xxx fileset=yyy
883 static bool backupscmd(UAContext *ua, const char *cmd)
885 if (!open_client_db(ua)) {
888 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
889 strcmp(ua->argk[2], "fileset") != 0) {
892 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
893 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
894 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
897 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
898 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
899 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
905 static int sql_handler(void *ctx, int num_field, char **row)
907 UAContext *ua = (UAContext *)ctx;
908 POOL_MEM rows(PM_MESSAGE);
910 /* Check for nonsense */
911 if (num_field == 0 || row == NULL || row[0] == NULL) {
912 return 0; /* nothing returned */
914 for (int i=0; num_field--; i++) {
916 pm_strcpy(rows, NPRT(row[0]));
918 pm_strcat(rows, NPRT(row[i]));
920 pm_strcat(rows, "\t");
922 if (!rows.c_str() || !*rows.c_str()) {
925 ua->send_msg("%s", rows.c_str());
930 static bool sql_cmd(UAContext *ua, const char *cmd)
933 if (!open_client_db(ua)) {
936 index = find_arg_with_value(ua, "query");
938 ua->error_msg(_("query keyword not found.\n"));
941 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
942 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
943 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
949 static int one_handler(void *ctx, int num_field, char **row)
951 UAContext *ua = (UAContext *)ctx;
952 ua->send_msg("%s\n", row[0]);
956 static bool mediatypescmd(UAContext *ua, const char *cmd)
958 if (!open_client_db(ua)) {
961 if (!db_sql_query(ua->db,
962 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
963 one_handler, (void *)ua))
965 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
970 static bool mediacmd(UAContext *ua, const char *cmd)
972 if (!open_client_db(ua)) {
975 if (!db_sql_query(ua->db,
976 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
977 one_handler, (void *)ua))
979 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
984 static bool locationscmd(UAContext *ua, const char *cmd)
986 if (!open_client_db(ua)) {
989 if (!db_sql_query(ua->db,
990 "SELECT DISTINCT Location FROM Location ORDER BY Location",
991 one_handler, (void *)ua))
993 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
998 static bool levelscmd(UAContext *ua, const char *cmd)
1000 ua->send_msg("Incremental\n");
1001 ua->send_msg("Full\n");
1002 ua->send_msg("Differential\n");
1003 ua->send_msg("VirtualFull\n");
1004 ua->send_msg("Catalog\n");
1005 ua->send_msg("InitCatalog\n");
1006 ua->send_msg("VolumeToCatalog\n");
1007 ua->send_msg("Base\n");
1011 static bool volstatuscmd(UAContext *ua, const char *cmd)
1013 ua->send_msg("Append\n");
1014 ua->send_msg("Full\n");
1015 ua->send_msg("Used\n");
1016 ua->send_msg("Recycle\n");
1017 ua->send_msg("Purged\n");
1018 ua->send_msg("Cleaning\n");
1019 ua->send_msg("Error\n");
1024 * Return default values for a job
1026 static bool defaultscmd(UAContext *ua, const char *cmd)
1034 if (ua->argc != 2 || !ua->argv[1]) {
1039 if (strcmp(ua->argk[1], "job") == 0) {
1040 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1043 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1046 ua->send_msg("job=%s", job->name());
1047 ua->send_msg("pool=%s", job->pool->name());
1048 ua->send_msg("messages=%s", job->messages->name());
1049 ua->send_msg("client=%s", job->client->name());
1050 get_job_storage(&store, job, NULL);
1051 ua->send_msg("storage=%s", store.store->name());
1052 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1053 ua->send_msg("level=%s", level_to_str(job->JobLevel));
1054 ua->send_msg("type=%s", job_type_to_str(job->JobType));
1055 ua->send_msg("fileset=%s", job->fileset->name());
1056 ua->send_msg("enabled=%d", job->enabled);
1057 ua->send_msg("catalog=%s", job->client->catalog->name());
1060 /* Client defaults */
1061 else if (strcmp(ua->argk[1], "client") == 0) {
1062 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1065 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1067 ua->send_msg("client=%s", client->name());
1068 ua->send_msg("address=%s", client->address);
1069 ua->send_msg("fdport=%d", client->FDport);
1070 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1071 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1072 ua->send_msg("autoprune=%d", client->AutoPrune);
1073 ua->send_msg("catalog=%s", client->catalog->name());
1076 /* Storage defaults */
1077 else if (strcmp(ua->argk[1], "storage") == 0) {
1078 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1081 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1084 ua->send_msg("storage=%s", storage->name());
1085 ua->send_msg("address=%s", storage->address);
1086 ua->send_msg("enabled=%d", storage->enabled);
1087 ua->send_msg("media_type=%s", storage->media_type);
1088 ua->send_msg("sdport=%d", storage->SDport);
1089 device = (DEVICE *)storage->device->first();
1090 ua->send_msg("device=%s", device->name());
1091 if (storage->device->size() > 1) {
1092 while ((device = (DEVICE *)storage->device->next())) {
1093 ua->send_msg(",%s", device->name());
1099 else if (strcmp(ua->argk[1], "pool") == 0) {
1100 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1103 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1105 ua->send_msg("pool=%s", pool->name());
1106 ua->send_msg("pool_type=%s", pool->pool_type);
1107 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1108 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1109 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1110 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1111 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1112 ua->send_msg("max_volumes=%d", pool->max_volumes);
1113 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1114 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1115 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1116 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1117 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1118 ua->send_msg("auto_prune=%d", pool->AutoPrune);
1119 ua->send_msg("recycle=%d", pool->Recycle);
1120 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1121 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));