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 */
46 extern struct s_jl joblevels[];
47 extern struct s_jt jobtypes[];
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 admin_cmds(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);
69 static bool volstatuscmd(UAContext *ua, const char *cmd);
70 static bool mediatypescmd(UAContext *ua, const char *cmd);
71 static bool locationscmd(UAContext *ua, const char *cmd);
72 static bool mediacmd(UAContext *ua, const char *cmd);
73 static bool aopcmd(UAContext *ua, const char *cmd);
75 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd);
76 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd);
77 static bool dot_bvfs_update(UAContext *ua, const char *cmd);
78 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd);
79 static bool dot_bvfs_versions(UAContext *ua, const char *cmd);
80 static bool dot_bvfs_restore(UAContext *ua, const char *cmd);
81 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd);
83 static bool api_cmd(UAContext *ua, const char *cmd);
84 static bool sql_cmd(UAContext *ua, const char *cmd);
85 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
86 static bool dot_help_cmd(UAContext *ua, const char *cmd);
87 static int one_handler(void *ctx, int num_field, char **row);
89 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;};
90 static struct cmdstruct commands[] = { /* help */ /* can be used in runscript */
91 { NT_(".api"), api_cmd, NULL, false},
92 { NT_(".backups"), backupscmd, NULL, false},
93 { NT_(".clients"), clientscmd, NULL, true},
94 { NT_(".defaults"), defaultscmd, NULL, false},
95 { NT_(".die"), admin_cmds, NULL, false},
96 { NT_(".dump"), admin_cmds, NULL, false},
97 { NT_(".exit"), admin_cmds, NULL, false},
98 { NT_(".filesets"), filesetscmd, NULL, false},
99 { NT_(".help"), dot_help_cmd, NULL, false},
100 { NT_(".jobs"), jobscmd, NULL, true},
101 { NT_(".levels"), levelscmd, NULL, false},
102 { NT_(".messages"), getmsgscmd, NULL, false},
103 { NT_(".msgs"), msgscmd, NULL, false},
104 { NT_(".pools"), poolscmd, NULL, true},
105 { NT_(".quit"), dot_quit_cmd, NULL, false},
106 { NT_(".sql"), sql_cmd, NULL, false},
107 { NT_(".status"), dot_status_cmd, NULL, false},
108 { NT_(".storage"), storagecmd, NULL, true},
109 { NT_(".volstatus"), volstatuscmd, NULL, true},
110 { NT_(".media"), mediacmd, NULL, true},
111 { NT_(".mediatypes"), mediatypescmd, NULL, true},
112 { NT_(".locations"), locationscmd, NULL, true},
113 { NT_(".actiononpurge"),aopcmd, NULL, true},
114 { NT_(".bvfs_lsdirs"), dot_bvfs_lsdirs, NULL, true},
115 { NT_(".bvfs_lsfiles"),dot_bvfs_lsfiles, NULL, true},
116 { NT_(".bvfs_update"), dot_bvfs_update, NULL, true},
117 { NT_(".bvfs_get_jobids"), dot_bvfs_get_jobids, NULL, true},
118 { NT_(".bvfs_versions"), dot_bvfs_versions, NULL, true},
119 { NT_(".bvfs_restore"), dot_bvfs_restore, NULL, true},
120 { NT_(".bvfs_cleanup"), dot_bvfs_cleanup, NULL, true},
121 { NT_(".types"), typescmd, NULL, false}
123 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
126 * Execute a command from the UA
128 bool do_a_dot_command(UAContext *ua)
134 BSOCK *user = ua->UA_sock;
136 Dmsg1(1400, "Dot command: %s\n", user->msg);
141 len = strlen(ua->argk[0]);
143 if (ua->api) user->signal(BNET_CMD_BEGIN);
144 if (ua->api) user->signal(BNET_CMD_OK);
145 return true; /* no op */
147 for (i=0; i<comsize; i++) { /* search for command */
148 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
149 /* Check if this command is authorized in RunScript */
150 if (ua->runscript && !commands[i].use_in_rs) {
151 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
155 /* Check if command permitted, but "quit" is always OK */
156 if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
157 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
160 Dmsg1(100, "Cmd: %s\n", ua->cmd);
162 if (ua->api) user->signal(BNET_CMD_BEGIN);
163 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
164 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
171 pm_strcat(user->msg, _(": is an invalid command.\n"));
172 ua->error_msg("%s", user->msg);
178 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
180 if (!open_new_client_db(ua)) {
184 int pos = find_arg_with_value(ua, "jobid");
185 if (pos != -1 && is_a_number_list(ua->argv[pos])) {
186 bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, ua->argv[pos]);
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, sizeof(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,
275 int *limit, int *offset)
284 for (int i=1; i<ua->argc; i++) {
285 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
286 if (is_a_number(ua->argv[i])) {
287 *pathid = str_to_int64(ua->argv[i]);
291 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
295 if (strcasecmp(ua->argk[i], NT_("username")) == 0) {
296 *username = ua->argv[i];
299 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
300 if (is_a_number_list(ua->argv[i])) {
301 *jobid = ua->argv[i];
305 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
306 if (is_a_number(ua->argv[i])) {
307 *limit = str_to_int64(ua->argv[i]);
311 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
312 if (is_a_number(ua->argv[i])) {
313 *offset = str_to_int64(ua->argv[i]);
318 if (!((*pathid || *path) && *jobid)) {
322 if (!open_client_db(ua)) {
329 /* .bvfs_cleanup path=b2XXXXX
331 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
334 if ((i = find_arg_with_value(ua, "path")) >= 0) {
336 Bvfs fs(ua->jcr, ua->db);
337 fs.drop_restore_list(ua->argv[i]);
342 /* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
344 static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
347 int limit=2000, offset=0, i;
348 char *path=NULL, *jobid=NULL, *username=NULL;
349 char *empty = (char *)"";
350 char *fileid, *dirid, *hardlink;
351 fileid = dirid = hardlink = empty;
353 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
356 ua->error_msg("Can't find jobid, pathid or path argument\n");
357 return true; /* not enough param */
360 Bvfs fs(ua->jcr, ua->db);
361 fs.set_username(username);
362 fs.set_jobids(jobid);
364 if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
365 fileid = ua->argv[i];
367 if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
370 if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
371 hardlink = ua->argv[i];
374 if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
375 ua->send_msg("OK\n");
377 ua->error_msg("Can't create restore list\n");
383 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
384 * .bvfs_lsfiles jobid=1,2,3,4 path=/
386 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
389 int limit=2000, offset=0;
390 char *path=NULL, *jobid=NULL, *username=NULL;
394 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
397 ua->error_msg("Can't find jobid, pathid or path argument\n");
398 return true; /* not enough param */
400 if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
401 pattern = ua->argv[i];
404 Bvfs fs(ua->jcr, ua->db);
405 fs.set_username(username);
406 fs.set_jobids(jobid);
407 fs.set_handler(bvfs_result_handler, ua);
410 fs.set_pattern(pattern);
418 fs.set_offset(offset);
426 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
427 * .bvfs_lsdirs jobid=1,2,3,4 path=/
428 * .bvfs_lsdirs jobid=1,2,3,4 path=
430 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
433 int limit=2000, offset=0;
434 char *path=NULL, *jobid=NULL, *username=NULL;
436 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
439 ua->error_msg("Can't find jobid, pathid or path argument\n");
440 return true; /* not enough param */
443 Bvfs fs(ua->jcr, ua->db);
444 fs.set_username(username);
445 fs.set_jobids(jobid);
447 fs.set_handler(bvfs_result_handler, ua);
455 fs.set_offset(offset);
457 fs.ls_special_dirs();
464 * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
467 static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
469 DBId_t pathid=0, fnid=0;
470 int limit=2000, offset=0;
471 char *path=NULL, *jobid=NULL, *client=NULL, *username=NULL;
472 bool copies=false, versions=false;
473 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
476 ua->error_msg("Can't find jobid, pathid or path argument\n");
477 return true; /* not enough param */
480 if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
482 ua->error_msg("Can't find client or fnid argument\n");
483 return true; /* not enough param */
486 Bvfs fs(ua->jcr, ua->db);
488 fs.set_see_all_versions(versions);
489 fs.set_see_copies(copies);
490 fs.set_handler(bvfs_result_handler, ua);
491 fs.set_offset(offset);
492 fs.get_all_file_versions(pathid, fnid, client);
497 /* .bvfs_get_jobids jobid=1
498 * -> returns needed jobids to restore
499 * .bvfs_get_jobids jobid=1 all
500 * -> returns needed jobids to restore with all filesets a JobId=1 time
502 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
505 db_list_ctx jobids, tempids;
509 dbid_list ids; /* Store all FileSetIds for this client */
511 if (!open_client_db(ua)) {
515 memset(&jr, 0, sizeof(JOB_DBR));
516 if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
517 jr.JobId = str_to_int64(ua->argv[pos]);
520 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
521 ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
522 ua->cmd, db_strerror(ua->db));
526 /* If we have the "all" option, we do a search on all defined fileset
529 if (find_arg(ua, "all") > 0) {
530 edit_int64(jr.ClientId, ed1);
531 Mmsg(query, uar_sel_filesetid, ed1);
532 db_get_query_dbids(ua->jcr, ua->db, query, ids);
535 ids.DBId[0] = jr.FileSetId;
538 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
540 /* Foreach different FileSet, we build a restore jobid list */
541 for (int i=0; i < ids.num_ids; i++) {
542 jr.FileSetId = ids.DBId[i];
543 if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
549 ua->send_msg("%s\n", jobids.list);
553 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
559 static bool dot_help_cmd(UAContext *ua, const char *cmd)
565 static bool getmsgscmd(UAContext *ua, const char *cmd)
567 if (console_msg_pending) {
568 do_messages(ua, cmd);
574 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
580 lstore.store = store;
581 pm_strcpy(lstore.store_source, _("unknown source"));
582 set_wstorage(jcr, &lstore);
583 /* Try connecting for up to 15 seconds */
584 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
585 store->name(), store->address, store->SDport);
586 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
587 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
590 Dmsg0(120, _("Connected to storage daemon\n"));
591 sd = jcr->store_bsock;
592 sd->fsend("%s", cmd);
593 if (sd->recv() >= 0) {
594 ua->send_msg("%s", sd->msg);
596 sd->signal(BNET_TERMINATE);
598 jcr->store_bsock = NULL;
602 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
606 /* Connect to File daemon */
608 ua->jcr->client = client;
609 /* Try to connect for 15 seconds */
610 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
611 client->name(), client->address, client->FDport);
612 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
613 ua->error_msg(_("Failed to connect to Client.\n"));
616 Dmsg0(120, "Connected to file daemon\n");
617 fd = ua->jcr->file_bsock;
618 fd->fsend("%s", cmd);
619 if (fd->recv() >= 0) {
620 ua->send_msg("%s", fd->msg);
622 fd->signal(BNET_TERMINATE);
624 ua->jcr->file_bsock = NULL;
631 * .exit (no arg => .quit)
633 static bool admin_cmds(UAContext *ua, const char *cmd)
635 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
639 bool do_deadlock=false;
640 const char *remote_cmd;
644 if (strncmp(ua->argk[0], ".die", 4) == 0) {
645 if (find_arg(ua, "deadlock") > 0) {
647 remote_cmd = ".die deadlock";
651 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
652 remote_cmd = "sm_dump";
653 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
656 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
660 for (i=1; i<ua->argc; i++) {
661 if (strcasecmp(ua->argk[i], "dir") == 0 ||
662 strcasecmp(ua->argk[i], "director") == 0) {
665 if (strcasecmp(ua->argk[i], "client") == 0 ||
666 strcasecmp(ua->argk[i], "fd") == 0) {
669 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
672 client = select_client_resource(ua);
676 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
677 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
678 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
681 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
684 store = get_storage_resource(ua, false/*no default*/);
689 if (!dir && !store && !client) {
691 * We didn't find an appropriate keyword above, so
694 start_prompt(ua, _("Available daemons are: \n"));
695 add_prompt(ua, _("Director"));
696 add_prompt(ua, _("Storage"));
697 add_prompt(ua, _("Client"));
698 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
699 case 0: /* Director */
703 store = get_storage_resource(ua, false/*no default*/);
706 client = select_client_resource(ua);
714 do_storage_cmd(ua, store, remote_cmd);
718 do_client_cmd(ua, client, remote_cmd);
722 if (strncmp(remote_cmd, ".die", 4) == 0) {
724 ua->send_msg(_("The Director will generate a deadlock.\n"));
728 ua->send_msg(_("The Director will segment fault.\n"));
729 a = jcr->JobId; /* ref NULL pointer */
730 jcr->JobId = 1000; /* another ref NULL pointer */
732 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
733 sm_dump(false, true);
734 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
735 dot_quit_cmd(ua, cmd);
745 * Dummy routine for non-development version
747 static bool admin_cmds(UAContext *ua, const char *cmd)
749 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
756 * Can use an argument to filter on JobType
759 static bool jobscmd(UAContext *ua, const char *cmd)
764 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
765 type = ua->argv[pos][0];
768 foreach_res(job, R_JOB) {
769 if (!type || type == job->JobType) {
770 if (acl_access_ok(ua, Job_ACL, job->name())) {
771 ua->send_msg("%s\n", job->name());
779 static bool filesetscmd(UAContext *ua, const char *cmd)
783 foreach_res(fs, R_FILESET) {
784 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
785 ua->send_msg("%s\n", fs->name());
792 static bool clientscmd(UAContext *ua, const char *cmd)
796 foreach_res(client, R_CLIENT) {
797 if (acl_access_ok(ua, Client_ACL, client->name())) {
798 ua->send_msg("%s\n", client->name());
805 static bool msgscmd(UAContext *ua, const char *cmd)
809 foreach_res(msgs, R_MSGS) {
810 ua->send_msg("%s\n", msgs->name());
816 static bool poolscmd(UAContext *ua, const char *cmd)
820 foreach_res(pool, R_POOL) {
821 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
822 ua->send_msg("%s\n", pool->name());
829 static bool storagecmd(UAContext *ua, const char *cmd)
833 foreach_res(store, R_STORAGE) {
834 if (acl_access_ok(ua, Storage_ACL, store->name())) {
835 ua->send_msg("%s\n", store->name());
842 static bool aopcmd(UAContext *ua, const char *cmd)
844 ua->send_msg("None\n");
845 ua->send_msg("Truncate\n");
849 static bool typescmd(UAContext *ua, const char *cmd)
851 ua->send_msg("Backup\n");
852 ua->send_msg("Restore\n");
853 ua->send_msg("Admin\n");
854 ua->send_msg("Verify\n");
855 ua->send_msg("Migrate\n");
856 ua->send_msg("Copy\n");
861 * If this command is called, it tells the director that we
862 * are a program that wants a sort of API, and hence,
863 * we will probably suppress certain output, include more
864 * error codes, and most of all send back a good number
865 * of new signals that indicate whether or not the command
868 static bool api_cmd(UAContext *ua, const char *cmd)
871 ua->api = atoi(ua->argk[1]);
878 static int client_backups_handler(void *ctx, int num_field, char **row)
880 UAContext *ua = (UAContext *)ctx;
881 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
882 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
887 * Return the backups for this client
889 * .backups client=xxx fileset=yyy
892 static bool backupscmd(UAContext *ua, const char *cmd)
894 if (!open_client_db(ua)) {
897 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
898 strcmp(ua->argk[2], "fileset") != 0) {
901 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
902 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
903 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
906 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
907 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
908 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
914 static int sql_handler(void *ctx, int num_field, char **row)
916 UAContext *ua = (UAContext *)ctx;
917 POOL_MEM rows(PM_MESSAGE);
919 /* Check for nonsense */
920 if (num_field == 0 || row == NULL || row[0] == NULL) {
921 return 0; /* nothing returned */
923 for (int i=0; num_field--; i++) {
925 pm_strcpy(rows, NPRT(row[0]));
927 pm_strcat(rows, NPRT(row[i]));
929 pm_strcat(rows, "\t");
931 if (!rows.c_str() || !*rows.c_str()) {
934 ua->send_msg("%s", rows.c_str());
939 static bool sql_cmd(UAContext *ua, const char *cmd)
942 if (!open_client_db(ua)) {
945 index = find_arg_with_value(ua, "query");
947 ua->error_msg(_("query keyword not found.\n"));
950 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
951 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
952 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
958 static int one_handler(void *ctx, int num_field, char **row)
960 UAContext *ua = (UAContext *)ctx;
961 ua->send_msg("%s\n", row[0]);
965 static bool mediatypescmd(UAContext *ua, const char *cmd)
967 if (!open_client_db(ua)) {
970 if (!db_sql_query(ua->db,
971 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
972 one_handler, (void *)ua))
974 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
979 static bool mediacmd(UAContext *ua, const char *cmd)
981 if (!open_client_db(ua)) {
984 if (!db_sql_query(ua->db,
985 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
986 one_handler, (void *)ua))
988 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
993 static bool locationscmd(UAContext *ua, const char *cmd)
995 if (!open_client_db(ua)) {
998 if (!db_sql_query(ua->db,
999 "SELECT DISTINCT Location FROM Location ORDER BY Location",
1000 one_handler, (void *)ua))
1002 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
1007 static bool levelscmd(UAContext *ua, const char *cmd)
1010 /* Note some levels are blank, which means none is needed */
1011 if (ua->argc == 1) {
1012 for (i=0; joblevels[i].level_name; i++) {
1013 if (joblevels[i].level_name[0] != ' ') {
1014 ua->send_msg("%s\n", joblevels[i].level_name);
1017 } else if (ua->argc == 2) {
1019 /* Assume that first argument is the Job Type */
1020 for (i=0; jobtypes[i].type_name; i++) {
1021 if (strcasecmp(ua->argk[1], jobtypes[i].type_name) == 0) {
1022 jobtype = jobtypes[i].job_type;
1026 for (i=0; joblevels[i].level_name; i++) {
1027 if ((joblevels[i].job_type == jobtype) && (joblevels[i].level_name[0] != ' ')) {
1028 ua->send_msg("%s\n", joblevels[i].level_name);
1036 static bool volstatuscmd(UAContext *ua, const char *cmd)
1038 ua->send_msg("Append\n");
1039 ua->send_msg("Full\n");
1040 ua->send_msg("Used\n");
1041 ua->send_msg("Recycle\n");
1042 ua->send_msg("Purged\n");
1043 ua->send_msg("Cleaning\n");
1044 ua->send_msg("Error\n");
1049 * Return default values for a job
1051 static bool defaultscmd(UAContext *ua, const char *cmd)
1059 if (ua->argc != 2 || !ua->argv[1]) {
1064 if (strcmp(ua->argk[1], "job") == 0) {
1065 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1068 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1071 ua->send_msg("job=%s", job->name());
1072 ua->send_msg("pool=%s", job->pool->name());
1073 ua->send_msg("messages=%s", job->messages->name());
1074 ua->send_msg("client=%s", job->client->name());
1075 get_job_storage(&store, job, NULL);
1076 ua->send_msg("storage=%s", store.store->name());
1077 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1078 ua->send_msg("level=%s", level_to_str(job->JobLevel));
1079 ua->send_msg("type=%s", job_type_to_str(job->JobType));
1080 ua->send_msg("fileset=%s", job->fileset->name());
1081 ua->send_msg("enabled=%d", job->enabled);
1082 ua->send_msg("catalog=%s", job->client->catalog->name());
1085 /* Client defaults */
1086 else if (strcmp(ua->argk[1], "client") == 0) {
1087 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1090 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1092 ua->send_msg("client=%s", client->name());
1093 ua->send_msg("address=%s", client->address);
1094 ua->send_msg("fdport=%d", client->FDport);
1095 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1096 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1097 ua->send_msg("autoprune=%d", client->AutoPrune);
1098 ua->send_msg("catalog=%s", client->catalog->name());
1101 /* Storage defaults */
1102 else if (strcmp(ua->argk[1], "storage") == 0) {
1103 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1106 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1109 ua->send_msg("storage=%s", storage->name());
1110 ua->send_msg("address=%s", storage->address);
1111 ua->send_msg("enabled=%d", storage->enabled);
1112 ua->send_msg("media_type=%s", storage->media_type);
1113 ua->send_msg("sdport=%d", storage->SDport);
1114 device = (DEVICE *)storage->device->first();
1115 ua->send_msg("device=%s", device->name());
1116 if (storage->device->size() > 1) {
1117 while ((device = (DEVICE *)storage->device->next())) {
1118 ua->send_msg(",%s", device->name());
1124 else if (strcmp(ua->argk[1], "pool") == 0) {
1125 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1128 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1130 ua->send_msg("pool=%s", pool->name());
1131 ua->send_msg("pool_type=%s", pool->pool_type);
1132 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1133 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1134 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1135 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1136 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1137 ua->send_msg("max_volumes=%d", pool->max_volumes);
1138 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1139 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1140 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1141 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1142 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1143 ua->send_msg("auto_prune=%d", pool->AutoPrune);
1144 ua->send_msg("recycle=%d", pool->Recycle);
1145 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1146 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));