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])) {
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, &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,
272 int *limit, int *offset)
280 for (int i=1; i<ua->argc; i++) {
281 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
282 if (is_a_number(ua->argv[i])) {
283 *pathid = str_to_int64(ua->argv[i]);
287 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
291 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
292 if (is_a_number_list(ua->argv[i])) {
293 *jobid = ua->argv[i];
297 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
298 if (is_a_number(ua->argv[i])) {
299 *limit = str_to_int64(ua->argv[i]);
303 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
304 if (is_a_number(ua->argv[i])) {
305 *offset = str_to_int64(ua->argv[i]);
310 if (!((*pathid || *path) && *jobid)) {
314 if (!open_client_db(ua)) {
321 /* .bvfs_cleanup path=b2XXXXX
323 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
326 if ((i = find_arg_with_value(ua, "path")) >= 0) {
328 Bvfs fs(ua->jcr, ua->db);
329 fs.drop_restore_list(ua->argv[i]);
334 /* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
336 static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
339 int limit=2000, offset=0, i;
340 char *path=NULL, *jobid=NULL;
341 char *empty = (char *)"";
342 char *fileid, *dirid, *hardlink, *id;
343 id = fileid = dirid = hardlink = empty;
345 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
348 ua->error_msg("Can't find jobid, pathid or path argument\n");
349 return true; /* not enough param */
352 Bvfs fs(ua->jcr, ua->db);
353 fs.set_jobids(jobid);
355 if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
356 fileid = ua->argv[i];
358 if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
361 if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
362 hardlink = ua->argv[i];
365 if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
366 ua->send_msg("OK\n");
368 ua->error_msg("Can't create restore list\n");
374 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
375 * .bvfs_lsfiles jobid=1,2,3,4 path=/
377 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
380 int limit=2000, offset=0;
381 char *path=NULL, *jobid=NULL;
385 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
388 ua->error_msg("Can't find jobid, pathid or path argument\n");
389 return true; /* not enough param */
391 if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
392 pattern = ua->argv[i];
395 Bvfs fs(ua->jcr, ua->db);
396 fs.set_jobids(jobid);
397 fs.set_handler(bvfs_result_handler, ua);
400 fs.set_pattern(pattern);
408 fs.set_offset(offset);
416 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
417 * .bvfs_lsdirs jobid=1,2,3,4 path=/
418 * .bvfs_lsdirs jobid=1,2,3,4 path=
420 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
423 int limit=2000, offset=0;
424 char *path=NULL, *jobid=NULL;
426 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
429 ua->error_msg("Can't find jobid, pathid or path argument\n");
430 return true; /* not enough param */
433 Bvfs fs(ua->jcr, ua->db);
434 fs.set_jobids(jobid);
436 fs.set_handler(bvfs_result_handler, ua);
444 fs.set_offset(offset);
446 fs.ls_special_dirs();
453 * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
456 static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
458 DBId_t pathid=0, fnid=0;
459 int limit=2000, offset=0;
460 char *path=NULL, *jobid=NULL, *client=NULL;
461 bool copies=false, versions=false;
462 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
465 ua->error_msg("Can't find jobid, pathid or path argument\n");
466 return true; /* not enough param */
469 if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
471 ua->error_msg("Can't find client or fnid argument\n");
472 return true; /* not enough param */
475 Bvfs fs(ua->jcr, ua->db);
477 fs.set_see_all_versions(versions);
478 fs.set_see_copies(copies);
479 fs.set_handler(bvfs_result_handler, ua);
480 fs.set_offset(offset);
481 fs.get_all_file_versions(pathid, fnid, client);
486 /* .bvfs_get_jobids jobid=1
487 * -> returns needed jobids to restore
488 * .bvfs_get_jobids jobid=1 all
489 * -> returns needed jobids to restore with all filesets a JobId=1 time
491 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
494 db_list_ctx jobids, tempids;
498 dbid_list ids; /* Store all FileSetIds for this client */
500 if (!open_client_db(ua)) {
504 memset(&jr, 0, sizeof(JOB_DBR));
505 if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
506 jr.JobId = str_to_int64(ua->argv[pos]);
509 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
510 ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
511 ua->cmd, db_strerror(ua->db));
515 /* If we have the "all" option, we do a search on all defined fileset
518 if (find_arg(ua, "all") > 0) {
519 edit_int64(jr.ClientId, ed1);
520 Mmsg(query, uar_sel_filesetid, ed1);
521 db_get_query_dbids(ua->jcr, ua->db, query, ids);
524 ids.DBId[0] = jr.FileSetId;
527 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
529 /* Foreach different FileSet, we build a restore jobid list */
530 for (int i=0; i < ids.num_ids; i++) {
531 jr.FileSetId = ids.DBId[i];
532 if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
538 ua->send_msg("%s\n", jobids.list);
542 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
548 static bool dot_help_cmd(UAContext *ua, const char *cmd)
554 static bool getmsgscmd(UAContext *ua, const char *cmd)
556 if (console_msg_pending) {
557 do_messages(ua, cmd);
563 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
569 lstore.store = store;
570 pm_strcpy(lstore.store_source, _("unknown source"));
571 set_wstorage(jcr, &lstore);
572 /* Try connecting for up to 15 seconds */
573 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
574 store->name(), store->address, store->SDport);
575 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
576 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
579 Dmsg0(120, _("Connected to storage daemon\n"));
580 sd = jcr->store_bsock;
581 sd->fsend("%s", cmd);
582 if (sd->recv() >= 0) {
583 ua->send_msg("%s", sd->msg);
585 sd->signal(BNET_TERMINATE);
587 jcr->store_bsock = NULL;
591 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
595 /* Connect to File daemon */
597 ua->jcr->client = client;
598 /* Try to connect for 15 seconds */
599 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
600 client->name(), client->address, client->FDport);
601 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
602 ua->error_msg(_("Failed to connect to Client.\n"));
605 Dmsg0(120, "Connected to file daemon\n");
606 fd = ua->jcr->file_bsock;
607 fd->fsend("%s", cmd);
608 if (fd->recv() >= 0) {
609 ua->send_msg("%s", fd->msg);
611 fd->signal(BNET_TERMINATE);
613 ua->jcr->file_bsock = NULL;
620 * .exit (no arg => .quit)
622 static bool admin_cmds(UAContext *ua, const char *cmd)
624 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
628 bool do_deadlock=false;
629 const char *remote_cmd;
633 if (strncmp(ua->argk[0], ".die", 4) == 0) {
634 if (find_arg(ua, "deadlock") > 0) {
636 remote_cmd = ".die deadlock";
640 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
641 remote_cmd = "sm_dump";
642 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
645 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
649 for (i=1; i<ua->argc; i++) {
650 if (strcasecmp(ua->argk[i], "dir") == 0 ||
651 strcasecmp(ua->argk[i], "director") == 0) {
654 if (strcasecmp(ua->argk[i], "client") == 0 ||
655 strcasecmp(ua->argk[i], "fd") == 0) {
658 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
661 client = select_client_resource(ua);
665 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
666 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
667 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
670 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
673 store = get_storage_resource(ua, false/*no default*/);
678 if (!dir && !store && !client) {
680 * We didn't find an appropriate keyword above, so
683 start_prompt(ua, _("Available daemons are: \n"));
684 add_prompt(ua, _("Director"));
685 add_prompt(ua, _("Storage"));
686 add_prompt(ua, _("Client"));
687 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
688 case 0: /* Director */
692 store = get_storage_resource(ua, false/*no default*/);
695 client = select_client_resource(ua);
703 do_storage_cmd(ua, store, remote_cmd);
707 do_client_cmd(ua, client, remote_cmd);
711 if (strncmp(remote_cmd, ".die", 4) == 0) {
713 ua->send_msg(_("The Director will generate a deadlock.\n"));
717 ua->send_msg(_("The Director will segment fault.\n"));
718 a = jcr->JobId; /* ref NULL pointer */
719 jcr->JobId = 1000; /* another ref NULL pointer */
721 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
722 sm_dump(false, true);
723 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
724 dot_quit_cmd(ua, cmd);
734 * Dummy routine for non-development version
736 static bool admin_cmds(UAContext *ua, const char *cmd)
738 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
745 * Can use an argument to filter on JobType
748 static bool jobscmd(UAContext *ua, const char *cmd)
753 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
754 type = ua->argv[pos][0];
757 foreach_res(job, R_JOB) {
758 if (!type || type == job->JobType) {
759 if (acl_access_ok(ua, Job_ACL, job->name())) {
760 ua->send_msg("%s\n", job->name());
768 static bool filesetscmd(UAContext *ua, const char *cmd)
772 foreach_res(fs, R_FILESET) {
773 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
774 ua->send_msg("%s\n", fs->name());
781 static bool clientscmd(UAContext *ua, const char *cmd)
785 foreach_res(client, R_CLIENT) {
786 if (acl_access_ok(ua, Client_ACL, client->name())) {
787 ua->send_msg("%s\n", client->name());
794 static bool msgscmd(UAContext *ua, const char *cmd)
798 foreach_res(msgs, R_MSGS) {
799 ua->send_msg("%s\n", msgs->name());
805 static bool poolscmd(UAContext *ua, const char *cmd)
809 foreach_res(pool, R_POOL) {
810 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
811 ua->send_msg("%s\n", pool->name());
818 static bool storagecmd(UAContext *ua, const char *cmd)
822 foreach_res(store, R_STORAGE) {
823 if (acl_access_ok(ua, Storage_ACL, store->name())) {
824 ua->send_msg("%s\n", store->name());
831 static bool aopcmd(UAContext *ua, const char *cmd)
833 ua->send_msg("None\n");
834 ua->send_msg("Truncate\n");
838 static bool typescmd(UAContext *ua, const char *cmd)
840 ua->send_msg("Backup\n");
841 ua->send_msg("Restore\n");
842 ua->send_msg("Admin\n");
843 ua->send_msg("Verify\n");
844 ua->send_msg("Migrate\n");
845 ua->send_msg("Copy\n");
850 * If this command is called, it tells the director that we
851 * are a program that wants a sort of API, and hence,
852 * we will probably suppress certain output, include more
853 * error codes, and most of all send back a good number
854 * of new signals that indicate whether or not the command
857 static bool api_cmd(UAContext *ua, const char *cmd)
860 ua->api = atoi(ua->argk[1]);
867 static int client_backups_handler(void *ctx, int num_field, char **row)
869 UAContext *ua = (UAContext *)ctx;
870 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
871 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
876 * Return the backups for this client
878 * .backups client=xxx fileset=yyy
881 static bool backupscmd(UAContext *ua, const char *cmd)
883 if (!open_client_db(ua)) {
886 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
887 strcmp(ua->argk[2], "fileset") != 0) {
890 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
891 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
892 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
895 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
896 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
897 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
903 static int sql_handler(void *ctx, int num_field, char **row)
905 UAContext *ua = (UAContext *)ctx;
906 POOL_MEM rows(PM_MESSAGE);
908 /* Check for nonsense */
909 if (num_field == 0 || row == NULL || row[0] == NULL) {
910 return 0; /* nothing returned */
912 for (int i=0; num_field--; i++) {
914 pm_strcpy(rows, NPRT(row[0]));
916 pm_strcat(rows, NPRT(row[i]));
918 pm_strcat(rows, "\t");
920 if (!rows.c_str() || !*rows.c_str()) {
923 ua->send_msg("%s", rows.c_str());
928 static bool sql_cmd(UAContext *ua, const char *cmd)
931 if (!open_client_db(ua)) {
934 index = find_arg_with_value(ua, "query");
936 ua->error_msg(_("query keyword not found.\n"));
939 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
940 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
941 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
947 static int one_handler(void *ctx, int num_field, char **row)
949 UAContext *ua = (UAContext *)ctx;
950 ua->send_msg("%s\n", row[0]);
954 static bool mediatypescmd(UAContext *ua, const char *cmd)
956 if (!open_client_db(ua)) {
959 if (!db_sql_query(ua->db,
960 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
961 one_handler, (void *)ua))
963 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
968 static bool mediacmd(UAContext *ua, const char *cmd)
970 if (!open_client_db(ua)) {
973 if (!db_sql_query(ua->db,
974 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
975 one_handler, (void *)ua))
977 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
982 static bool locationscmd(UAContext *ua, const char *cmd)
984 if (!open_client_db(ua)) {
987 if (!db_sql_query(ua->db,
988 "SELECT DISTINCT Location FROM Location ORDER BY Location",
989 one_handler, (void *)ua))
991 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
996 static bool levelscmd(UAContext *ua, const char *cmd)
998 ua->send_msg("Incremental\n");
999 ua->send_msg("Full\n");
1000 ua->send_msg("Differential\n");
1001 ua->send_msg("VirtualFull\n");
1002 ua->send_msg("Catalog\n");
1003 ua->send_msg("InitCatalog\n");
1004 ua->send_msg("VolumeToCatalog\n");
1005 ua->send_msg("Base\n");
1009 static bool volstatuscmd(UAContext *ua, const char *cmd)
1011 ua->send_msg("Append\n");
1012 ua->send_msg("Full\n");
1013 ua->send_msg("Used\n");
1014 ua->send_msg("Recycle\n");
1015 ua->send_msg("Purged\n");
1016 ua->send_msg("Cleaning\n");
1017 ua->send_msg("Error\n");
1022 * Return default values for a job
1024 static bool defaultscmd(UAContext *ua, const char *cmd)
1032 if (ua->argc != 2 || !ua->argv[1]) {
1037 if (strcmp(ua->argk[1], "job") == 0) {
1038 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1041 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1044 ua->send_msg("job=%s", job->name());
1045 ua->send_msg("pool=%s", job->pool->name());
1046 ua->send_msg("messages=%s", job->messages->name());
1047 ua->send_msg("client=%s", job->client->name());
1048 get_job_storage(&store, job, NULL);
1049 ua->send_msg("storage=%s", store.store->name());
1050 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1051 ua->send_msg("level=%s", level_to_str(job->JobLevel));
1052 ua->send_msg("type=%s", job_type_to_str(job->JobType));
1053 ua->send_msg("fileset=%s", job->fileset->name());
1054 ua->send_msg("enabled=%d", job->enabled);
1055 ua->send_msg("catalog=%s", job->client->catalog->name());
1058 /* Client defaults */
1059 else if (strcmp(ua->argk[1], "client") == 0) {
1060 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1063 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1065 ua->send_msg("client=%s", client->name());
1066 ua->send_msg("address=%s", client->address);
1067 ua->send_msg("fdport=%d", client->FDport);
1068 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1069 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1070 ua->send_msg("autoprune=%d", client->AutoPrune);
1071 ua->send_msg("catalog=%s", client->catalog->name());
1074 /* Storage defaults */
1075 else if (strcmp(ua->argk[1], "storage") == 0) {
1076 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1079 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1082 ua->send_msg("storage=%s", storage->name());
1083 ua->send_msg("address=%s", storage->address);
1084 ua->send_msg("enabled=%d", storage->enabled);
1085 ua->send_msg("media_type=%s", storage->media_type);
1086 ua->send_msg("sdport=%d", storage->SDport);
1087 device = (DEVICE *)storage->device->first();
1088 ua->send_msg("device=%s", device->name());
1089 if (storage->device->size() > 1) {
1090 while ((device = (DEVICE *)storage->device->next())) {
1091 ua->send_msg(",%s", device->name());
1097 else if (strcmp(ua->argk[1], "pool") == 0) {
1098 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1101 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1103 ua->send_msg("pool=%s", pool->name());
1104 ua->send_msg("pool_type=%s", pool->pool_type);
1105 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1106 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1107 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1108 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1109 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1110 ua->send_msg("max_volumes=%d", pool->max_volumes);
1111 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1112 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1113 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1114 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1115 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1116 ua->send_msg("auto_prune=%d", pool->AutoPrune);
1117 ua->send_msg("recycle=%d", pool->Recycle);
1118 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1119 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));