2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2011 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])) {
184 bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, ua->argv[pos]);
186 /* update cache for all jobids */
187 bvfs_update_cache(ua->jcr, ua->db);
194 static int bvfs_result_handler(void *ctx, int fields, char **row)
196 UAContext *ua = (UAContext *)ctx;
199 char *fileid=row[BVFS_FileId];
200 char *lstat=row[BVFS_LStat];
201 char *jobid=row[BVFS_JobId];
203 char empty[] = "A A A A A A A A A A A A A A";
206 /* We need to deal with non existant path */
207 if (!fileid || !is_a_number(fileid)) {
213 memset(&statp, 0, sizeof(struct stat));
214 decode_stat(lstat, &statp, sizeof(statp), &LinkFI);
216 Dmsg1(100, "type=%s\n", row[0]);
217 if (bvfs_is_dir(row)) {
218 char *path = bvfs_basename_dir(row[BVFS_Name]);
219 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
222 } else if (bvfs_is_version(row)) {
223 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
224 row[BVFS_FilenameId], fileid, jobid,
225 lstat, row[BVFS_Md5], row[BVFS_VolName],
226 row[BVFS_VolInchanger]);
228 } else if (bvfs_is_file(row)) {
229 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
230 row[BVFS_FilenameId], fileid, jobid,
231 lstat, row[BVFS_Name]);
237 static bool bvfs_parse_arg_version(UAContext *ua,
248 for (int i=1; i<ua->argc; i++) {
249 if (fnid && strcasecmp(ua->argk[i], NT_("fnid")) == 0) {
250 if (is_a_number(ua->argv[i])) {
251 *fnid = str_to_int64(ua->argv[i]);
255 if (strcasecmp(ua->argk[i], NT_("client")) == 0) {
256 *client = ua->argv[i];
259 if (copies && strcasecmp(ua->argk[i], NT_("copies")) == 0) {
263 if (versions && strcasecmp(ua->argk[i], NT_("versions")) == 0) {
267 return (*client && *fnid > 0);
270 static bool bvfs_parse_arg(UAContext *ua,
271 DBId_t *pathid, char **path, char **jobid,
273 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_("username")) == 0) {
294 *username = ua->argv[i];
297 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
298 if (is_a_number_list(ua->argv[i])) {
299 *jobid = ua->argv[i];
303 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
304 if (is_a_number(ua->argv[i])) {
305 *limit = str_to_int64(ua->argv[i]);
309 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
310 if (is_a_number(ua->argv[i])) {
311 *offset = str_to_int64(ua->argv[i]);
316 if (!((*pathid || *path) && *jobid)) {
320 if (!open_client_db(ua)) {
327 /* .bvfs_cleanup path=b2XXXXX
329 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
332 if ((i = find_arg_with_value(ua, "path")) >= 0) {
334 Bvfs fs(ua->jcr, ua->db);
335 fs.drop_restore_list(ua->argv[i]);
340 /* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
342 static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
345 int limit=2000, offset=0, i;
346 char *path=NULL, *jobid=NULL, *username=NULL;
347 char *empty = (char *)"";
348 char *fileid, *dirid, *hardlink;
349 fileid = dirid = hardlink = empty;
351 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
354 ua->error_msg("Can't find jobid, pathid or path argument\n");
355 return true; /* not enough param */
358 Bvfs fs(ua->jcr, ua->db);
359 fs.set_username(username);
360 fs.set_jobids(jobid);
362 if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
363 fileid = ua->argv[i];
365 if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
368 if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
369 hardlink = ua->argv[i];
372 if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
373 ua->send_msg("OK\n");
375 ua->error_msg("Can't create restore list\n");
381 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
382 * .bvfs_lsfiles jobid=1,2,3,4 path=/
384 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
387 int limit=2000, offset=0;
388 char *path=NULL, *jobid=NULL, *username=NULL;
392 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
395 ua->error_msg("Can't find jobid, pathid or path argument\n");
396 return true; /* not enough param */
398 if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
399 pattern = ua->argv[i];
402 Bvfs fs(ua->jcr, ua->db);
403 fs.set_username(username);
404 fs.set_jobids(jobid);
405 fs.set_handler(bvfs_result_handler, ua);
408 fs.set_pattern(pattern);
416 fs.set_offset(offset);
424 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
425 * .bvfs_lsdirs jobid=1,2,3,4 path=/
426 * .bvfs_lsdirs jobid=1,2,3,4 path=
428 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
431 int limit=2000, offset=0;
432 char *path=NULL, *jobid=NULL, *username=NULL;
434 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
437 ua->error_msg("Can't find jobid, pathid or path argument\n");
438 return true; /* not enough param */
441 Bvfs fs(ua->jcr, ua->db);
442 fs.set_username(username);
443 fs.set_jobids(jobid);
445 fs.set_handler(bvfs_result_handler, ua);
453 fs.set_offset(offset);
455 fs.ls_special_dirs();
462 * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
465 static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
467 DBId_t pathid=0, fnid=0;
468 int limit=2000, offset=0;
469 char *path=NULL, *jobid=NULL, *client=NULL, *username=NULL;
470 bool copies=false, versions=false;
471 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
474 ua->error_msg("Can't find jobid, pathid or path argument\n");
475 return true; /* not enough param */
478 if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
480 ua->error_msg("Can't find client or fnid argument\n");
481 return true; /* not enough param */
484 Bvfs fs(ua->jcr, ua->db);
486 fs.set_see_all_versions(versions);
487 fs.set_see_copies(copies);
488 fs.set_handler(bvfs_result_handler, ua);
489 fs.set_offset(offset);
490 fs.get_all_file_versions(pathid, fnid, client);
495 /* .bvfs_get_jobids jobid=1
496 * -> returns needed jobids to restore
497 * .bvfs_get_jobids jobid=1 all
498 * -> returns needed jobids to restore with all filesets a JobId=1 time
500 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
503 db_list_ctx jobids, tempids;
507 dbid_list ids; /* Store all FileSetIds for this client */
509 if (!open_client_db(ua)) {
513 memset(&jr, 0, sizeof(JOB_DBR));
514 if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
515 jr.JobId = str_to_int64(ua->argv[pos]);
518 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
519 ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
520 ua->cmd, db_strerror(ua->db));
524 /* If we have the "all" option, we do a search on all defined fileset
527 if (find_arg(ua, "all") > 0) {
528 edit_int64(jr.ClientId, ed1);
529 Mmsg(query, uar_sel_filesetid, ed1);
530 db_get_query_dbids(ua->jcr, ua->db, query, ids);
533 ids.DBId[0] = jr.FileSetId;
536 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
538 /* Foreach different FileSet, we build a restore jobid list */
539 for (int i=0; i < ids.num_ids; i++) {
540 jr.FileSetId = ids.DBId[i];
541 if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
547 ua->send_msg("%s\n", jobids.list);
551 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
557 static bool dot_help_cmd(UAContext *ua, const char *cmd)
563 static bool getmsgscmd(UAContext *ua, const char *cmd)
565 if (console_msg_pending) {
566 do_messages(ua, cmd);
572 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
578 lstore.store = store;
579 pm_strcpy(lstore.store_source, _("unknown source"));
580 set_wstorage(jcr, &lstore);
581 /* Try connecting for up to 15 seconds */
582 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
583 store->name(), store->address, store->SDport);
584 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
585 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
588 Dmsg0(120, _("Connected to storage daemon\n"));
589 sd = jcr->store_bsock;
590 sd->fsend("%s", cmd);
591 if (sd->recv() >= 0) {
592 ua->send_msg("%s", sd->msg);
594 sd->signal(BNET_TERMINATE);
596 jcr->store_bsock = NULL;
600 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
604 /* Connect to File daemon */
606 ua->jcr->client = client;
607 /* Try to connect for 15 seconds */
608 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
609 client->name(), client->address, client->FDport);
610 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
611 ua->error_msg(_("Failed to connect to Client.\n"));
614 Dmsg0(120, "Connected to file daemon\n");
615 fd = ua->jcr->file_bsock;
616 fd->fsend("%s", cmd);
617 if (fd->recv() >= 0) {
618 ua->send_msg("%s", fd->msg);
620 fd->signal(BNET_TERMINATE);
622 ua->jcr->file_bsock = NULL;
629 * .exit (no arg => .quit)
631 static bool admin_cmds(UAContext *ua, const char *cmd)
633 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
637 bool do_deadlock=false;
638 const char *remote_cmd;
642 if (strncmp(ua->argk[0], ".die", 4) == 0) {
643 if (find_arg(ua, "deadlock") > 0) {
645 remote_cmd = ".die deadlock";
649 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
650 remote_cmd = "sm_dump";
651 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
654 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
658 for (i=1; i<ua->argc; i++) {
659 if (strcasecmp(ua->argk[i], "dir") == 0 ||
660 strcasecmp(ua->argk[i], "director") == 0) {
663 if (strcasecmp(ua->argk[i], "client") == 0 ||
664 strcasecmp(ua->argk[i], "fd") == 0) {
667 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
670 client = select_client_resource(ua);
674 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
675 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
676 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
679 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
682 store = get_storage_resource(ua, false/*no default*/);
687 if (!dir && !store && !client) {
689 * We didn't find an appropriate keyword above, so
692 start_prompt(ua, _("Available daemons are: \n"));
693 add_prompt(ua, _("Director"));
694 add_prompt(ua, _("Storage"));
695 add_prompt(ua, _("Client"));
696 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
697 case 0: /* Director */
701 store = get_storage_resource(ua, false/*no default*/);
704 client = select_client_resource(ua);
712 do_storage_cmd(ua, store, remote_cmd);
716 do_client_cmd(ua, client, remote_cmd);
720 if (strncmp(remote_cmd, ".die", 4) == 0) {
722 ua->send_msg(_("The Director will generate a deadlock.\n"));
726 ua->send_msg(_("The Director will segment fault.\n"));
727 a = jcr->JobId; /* ref NULL pointer */
728 jcr->JobId = 1000; /* another ref NULL pointer */
730 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
731 sm_dump(false, true);
732 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
733 dot_quit_cmd(ua, cmd);
743 * Dummy routine for non-development version
745 static bool admin_cmds(UAContext *ua, const char *cmd)
747 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
754 * Can use an argument to filter on JobType
757 static bool jobscmd(UAContext *ua, const char *cmd)
762 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
763 type = ua->argv[pos][0];
766 foreach_res(job, R_JOB) {
767 if (!type || type == job->JobType) {
768 if (acl_access_ok(ua, Job_ACL, job->name())) {
769 ua->send_msg("%s\n", job->name());
777 static bool filesetscmd(UAContext *ua, const char *cmd)
781 foreach_res(fs, R_FILESET) {
782 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
783 ua->send_msg("%s\n", fs->name());
790 static bool clientscmd(UAContext *ua, const char *cmd)
794 foreach_res(client, R_CLIENT) {
795 if (acl_access_ok(ua, Client_ACL, client->name())) {
796 ua->send_msg("%s\n", client->name());
803 static bool msgscmd(UAContext *ua, const char *cmd)
807 foreach_res(msgs, R_MSGS) {
808 ua->send_msg("%s\n", msgs->name());
814 static bool poolscmd(UAContext *ua, const char *cmd)
818 foreach_res(pool, R_POOL) {
819 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
820 ua->send_msg("%s\n", pool->name());
827 static bool storagecmd(UAContext *ua, const char *cmd)
831 foreach_res(store, R_STORAGE) {
832 if (acl_access_ok(ua, Storage_ACL, store->name())) {
833 ua->send_msg("%s\n", store->name());
840 static bool aopcmd(UAContext *ua, const char *cmd)
842 ua->send_msg("None\n");
843 ua->send_msg("Truncate\n");
847 static bool typescmd(UAContext *ua, const char *cmd)
849 ua->send_msg("Backup\n");
850 ua->send_msg("Restore\n");
851 ua->send_msg("Admin\n");
852 ua->send_msg("Verify\n");
853 ua->send_msg("Migrate\n");
854 ua->send_msg("Copy\n");
859 * If this command is called, it tells the director that we
860 * are a program that wants a sort of API, and hence,
861 * we will probably suppress certain output, include more
862 * error codes, and most of all send back a good number
863 * of new signals that indicate whether or not the command
866 static bool api_cmd(UAContext *ua, const char *cmd)
869 ua->api = atoi(ua->argk[1]);
876 static int client_backups_handler(void *ctx, int num_field, char **row)
878 UAContext *ua = (UAContext *)ctx;
879 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
880 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
885 * Return the backups for this client
887 * .backups client=xxx fileset=yyy
890 static bool backupscmd(UAContext *ua, const char *cmd)
892 if (!open_client_db(ua)) {
895 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
896 strcmp(ua->argk[2], "fileset") != 0) {
899 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
900 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
901 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
904 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
905 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
906 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
912 static int sql_handler(void *ctx, int num_field, char **row)
914 UAContext *ua = (UAContext *)ctx;
915 POOL_MEM rows(PM_MESSAGE);
917 /* Check for nonsense */
918 if (num_field == 0 || row == NULL || row[0] == NULL) {
919 return 0; /* nothing returned */
921 for (int i=0; num_field--; i++) {
923 pm_strcpy(rows, NPRT(row[0]));
925 pm_strcat(rows, NPRT(row[i]));
927 pm_strcat(rows, "\t");
929 if (!rows.c_str() || !*rows.c_str()) {
932 ua->send_msg("%s", rows.c_str());
937 static bool sql_cmd(UAContext *ua, const char *cmd)
940 if (!open_client_db(ua)) {
943 index = find_arg_with_value(ua, "query");
945 ua->error_msg(_("query keyword not found.\n"));
948 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
949 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
950 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
956 static int one_handler(void *ctx, int num_field, char **row)
958 UAContext *ua = (UAContext *)ctx;
959 ua->send_msg("%s\n", row[0]);
963 static bool mediatypescmd(UAContext *ua, const char *cmd)
965 if (!open_client_db(ua)) {
968 if (!db_sql_query(ua->db,
969 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
970 one_handler, (void *)ua))
972 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
977 static bool mediacmd(UAContext *ua, const char *cmd)
979 if (!open_client_db(ua)) {
982 if (!db_sql_query(ua->db,
983 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
984 one_handler, (void *)ua))
986 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
991 static bool locationscmd(UAContext *ua, const char *cmd)
993 if (!open_client_db(ua)) {
996 if (!db_sql_query(ua->db,
997 "SELECT DISTINCT Location FROM Location ORDER BY Location",
998 one_handler, (void *)ua))
1000 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
1005 static bool levelscmd(UAContext *ua, const char *cmd)
1007 ua->send_msg("Incremental\n");
1008 ua->send_msg("Full\n");
1009 ua->send_msg("Differential\n");
1010 ua->send_msg("VirtualFull\n");
1011 ua->send_msg("Catalog\n");
1012 ua->send_msg("InitCatalog\n");
1013 ua->send_msg("VolumeToCatalog\n");
1014 ua->send_msg("Base\n");
1018 static bool volstatuscmd(UAContext *ua, const char *cmd)
1020 ua->send_msg("Append\n");
1021 ua->send_msg("Full\n");
1022 ua->send_msg("Used\n");
1023 ua->send_msg("Recycle\n");
1024 ua->send_msg("Purged\n");
1025 ua->send_msg("Cleaning\n");
1026 ua->send_msg("Error\n");
1031 * Return default values for a job
1033 static bool defaultscmd(UAContext *ua, const char *cmd)
1041 if (ua->argc != 2 || !ua->argv[1]) {
1046 if (strcmp(ua->argk[1], "job") == 0) {
1047 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1050 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1053 ua->send_msg("job=%s", job->name());
1054 ua->send_msg("pool=%s", job->pool->name());
1055 ua->send_msg("messages=%s", job->messages->name());
1056 ua->send_msg("client=%s", job->client->name());
1057 get_job_storage(&store, job, NULL);
1058 ua->send_msg("storage=%s", store.store->name());
1059 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1060 ua->send_msg("level=%s", level_to_str(job->JobLevel));
1061 ua->send_msg("type=%s", job_type_to_str(job->JobType));
1062 ua->send_msg("fileset=%s", job->fileset->name());
1063 ua->send_msg("enabled=%d", job->enabled);
1064 ua->send_msg("catalog=%s", job->client->catalog->name());
1067 /* Client defaults */
1068 else if (strcmp(ua->argk[1], "client") == 0) {
1069 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1072 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1074 ua->send_msg("client=%s", client->name());
1075 ua->send_msg("address=%s", client->address);
1076 ua->send_msg("fdport=%d", client->FDport);
1077 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1078 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1079 ua->send_msg("autoprune=%d", client->AutoPrune);
1080 ua->send_msg("catalog=%s", client->catalog->name());
1083 /* Storage defaults */
1084 else if (strcmp(ua->argk[1], "storage") == 0) {
1085 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1088 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1091 ua->send_msg("storage=%s", storage->name());
1092 ua->send_msg("address=%s", storage->address);
1093 ua->send_msg("enabled=%d", storage->enabled);
1094 ua->send_msg("media_type=%s", storage->media_type);
1095 ua->send_msg("sdport=%d", storage->SDport);
1096 device = (DEVICE *)storage->device->first();
1097 ua->send_msg("device=%s", device->name());
1098 if (storage->device->size() > 1) {
1099 while ((device = (DEVICE *)storage->device->next())) {
1100 ua->send_msg(",%s", device->name());
1106 else if (strcmp(ua->argk[1], "pool") == 0) {
1107 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1110 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1112 ua->send_msg("pool=%s", pool->name());
1113 ua->send_msg("pool_type=%s", pool->pool_type);
1114 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1115 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1116 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1117 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1118 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1119 ua->send_msg("max_volumes=%d", pool->max_volumes);
1120 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1121 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1122 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1123 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1124 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1125 ua->send_msg("auto_prune=%d", pool->AutoPrune);
1126 ua->send_msg("recycle=%d", pool->Recycle);
1127 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1128 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));