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 ua->error_msg("%s%s", ua->argk[0], _(": is an invalid command.\n"));
177 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
179 if (!open_new_client_db(ua)) {
183 int pos = find_arg_with_value(ua, "jobid");
184 if (pos != -1 && is_a_number_list(ua->argv[pos])) {
185 bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, ua->argv[pos]);
187 /* update cache for all jobids */
188 bvfs_update_cache(ua->jcr, ua->db);
195 static int bvfs_result_handler(void *ctx, int fields, char **row)
197 UAContext *ua = (UAContext *)ctx;
200 char *fileid=row[BVFS_FileId];
201 char *lstat=row[BVFS_LStat];
202 char *jobid=row[BVFS_JobId];
204 char empty[] = "A A A A A A A A A A A A A A";
207 /* We need to deal with non existant path */
208 if (!fileid || !is_a_number(fileid)) {
214 memset(&statp, 0, sizeof(struct stat));
215 decode_stat(lstat, &statp, sizeof(statp), &LinkFI);
217 Dmsg1(100, "type=%s\n", row[0]);
218 if (bvfs_is_dir(row)) {
219 char *path = bvfs_basename_dir(row[BVFS_Name]);
220 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
223 } else if (bvfs_is_version(row)) {
224 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
225 row[BVFS_FilenameId], fileid, jobid,
226 lstat, row[BVFS_Md5], row[BVFS_VolName],
227 row[BVFS_VolInchanger]);
229 } else if (bvfs_is_file(row)) {
230 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
231 row[BVFS_FilenameId], fileid, jobid,
232 lstat, row[BVFS_Name]);
238 static bool bvfs_parse_arg_version(UAContext *ua,
249 for (int i=1; i<ua->argc; i++) {
250 if (fnid && strcasecmp(ua->argk[i], NT_("fnid")) == 0) {
251 if (is_a_number(ua->argv[i])) {
252 *fnid = str_to_int64(ua->argv[i]);
256 if (strcasecmp(ua->argk[i], NT_("client")) == 0) {
257 *client = ua->argv[i];
260 if (copies && strcasecmp(ua->argk[i], NT_("copies")) == 0) {
264 if (versions && strcasecmp(ua->argk[i], NT_("versions")) == 0) {
268 return (*client && *fnid > 0);
271 static bool bvfs_parse_arg(UAContext *ua,
272 DBId_t *pathid, char **path, char **jobid,
274 int *limit, int *offset)
283 for (int i=1; i<ua->argc; i++) {
284 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
285 if (is_a_number(ua->argv[i])) {
286 *pathid = str_to_int64(ua->argv[i]);
290 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
294 if (strcasecmp(ua->argk[i], NT_("username")) == 0) {
295 *username = ua->argv[i];
298 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
299 if (is_a_number_list(ua->argv[i])) {
300 *jobid = ua->argv[i];
304 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
305 if (is_a_number(ua->argv[i])) {
306 *limit = str_to_int64(ua->argv[i]);
310 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
311 if (is_a_number(ua->argv[i])) {
312 *offset = str_to_int64(ua->argv[i]);
317 if (!((*pathid || *path) && *jobid)) {
321 if (!open_client_db(ua)) {
328 /* .bvfs_cleanup path=b2XXXXX
330 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
333 if ((i = find_arg_with_value(ua, "path")) >= 0) {
335 Bvfs fs(ua->jcr, ua->db);
336 fs.drop_restore_list(ua->argv[i]);
341 /* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
343 static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
346 int limit=2000, offset=0, i;
347 char *path=NULL, *jobid=NULL, *username=NULL;
348 char *empty = (char *)"";
349 char *fileid, *dirid, *hardlink;
350 fileid = dirid = hardlink = empty;
352 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
355 ua->error_msg("Can't find jobid, pathid or path argument\n");
356 return true; /* not enough param */
359 Bvfs fs(ua->jcr, ua->db);
360 fs.set_username(username);
361 fs.set_jobids(jobid);
363 if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
364 fileid = ua->argv[i];
366 if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
369 if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
370 hardlink = ua->argv[i];
373 if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
374 ua->send_msg("OK\n");
376 ua->error_msg("Can't create restore list\n");
382 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
383 * .bvfs_lsfiles jobid=1,2,3,4 path=/
385 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
388 int limit=2000, offset=0;
389 char *path=NULL, *jobid=NULL, *username=NULL;
393 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
396 ua->error_msg("Can't find jobid, pathid or path argument\n");
397 return true; /* not enough param */
399 if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
400 pattern = ua->argv[i];
403 Bvfs fs(ua->jcr, ua->db);
404 fs.set_username(username);
405 fs.set_jobids(jobid);
406 fs.set_handler(bvfs_result_handler, ua);
409 fs.set_pattern(pattern);
417 fs.set_offset(offset);
425 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
426 * .bvfs_lsdirs jobid=1,2,3,4 path=/
427 * .bvfs_lsdirs jobid=1,2,3,4 path=
429 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
432 int limit=2000, offset=0;
433 char *path=NULL, *jobid=NULL, *username=NULL;
435 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
438 ua->error_msg("Can't find jobid, pathid or path argument\n");
439 return true; /* not enough param */
442 Bvfs fs(ua->jcr, ua->db);
443 fs.set_username(username);
444 fs.set_jobids(jobid);
446 fs.set_handler(bvfs_result_handler, ua);
454 fs.set_offset(offset);
456 fs.ls_special_dirs();
463 * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
466 static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
468 DBId_t pathid=0, fnid=0;
469 int limit=2000, offset=0;
470 char *path=NULL, *jobid=NULL, *client=NULL, *username=NULL;
471 bool copies=false, versions=false;
472 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
475 ua->error_msg("Can't find jobid, pathid or path argument\n");
476 return true; /* not enough param */
479 if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
481 ua->error_msg("Can't find client or fnid argument\n");
482 return true; /* not enough param */
485 Bvfs fs(ua->jcr, ua->db);
487 fs.set_see_all_versions(versions);
488 fs.set_see_copies(copies);
489 fs.set_handler(bvfs_result_handler, ua);
490 fs.set_offset(offset);
491 fs.get_all_file_versions(pathid, fnid, client);
496 /* .bvfs_get_jobids jobid=1
497 * -> returns needed jobids to restore
498 * .bvfs_get_jobids jobid=1 all
499 * -> returns needed jobids to restore with all filesets a JobId=1 time
501 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
504 db_list_ctx jobids, tempids;
508 dbid_list ids; /* Store all FileSetIds for this client */
510 if (!open_client_db(ua)) {
514 memset(&jr, 0, sizeof(JOB_DBR));
515 if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
516 jr.JobId = str_to_int64(ua->argv[pos]);
519 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
520 ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
521 ua->cmd, db_strerror(ua->db));
525 /* If we have the "all" option, we do a search on all defined fileset
528 if (find_arg(ua, "all") > 0) {
529 edit_int64(jr.ClientId, ed1);
530 Mmsg(query, uar_sel_filesetid, ed1);
531 db_get_query_dbids(ua->jcr, ua->db, query, ids);
534 ids.DBId[0] = jr.FileSetId;
537 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
539 /* Foreach different FileSet, we build a restore jobid list */
540 for (int i=0; i < ids.num_ids; i++) {
541 jr.FileSetId = ids.DBId[i];
542 if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
548 ua->send_msg("%s\n", jobids.list);
552 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
558 static bool dot_help_cmd(UAContext *ua, const char *cmd)
564 static bool getmsgscmd(UAContext *ua, const char *cmd)
566 if (console_msg_pending) {
567 do_messages(ua, cmd);
573 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
579 lstore.store = store;
580 pm_strcpy(lstore.store_source, _("unknown source"));
581 set_wstorage(jcr, &lstore);
582 /* Try connecting for up to 15 seconds */
583 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
584 store->name(), store->address, store->SDport);
585 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
586 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
589 Dmsg0(120, _("Connected to storage daemon\n"));
590 sd = jcr->store_bsock;
591 sd->fsend("%s", cmd);
592 if (sd->recv() >= 0) {
593 ua->send_msg("%s", sd->msg);
595 sd->signal(BNET_TERMINATE);
597 jcr->store_bsock = NULL;
601 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
605 /* Connect to File daemon */
607 ua->jcr->client = client;
608 /* Try to connect for 15 seconds */
609 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
610 client->name(), client->address, client->FDport);
611 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
612 ua->error_msg(_("Failed to connect to Client.\n"));
615 Dmsg0(120, "Connected to file daemon\n");
616 fd = ua->jcr->file_bsock;
617 fd->fsend("%s", cmd);
618 if (fd->recv() >= 0) {
619 ua->send_msg("%s", fd->msg);
621 fd->signal(BNET_TERMINATE);
623 ua->jcr->file_bsock = NULL;
630 * .exit (no arg => .quit)
632 static bool admin_cmds(UAContext *ua, const char *cmd)
634 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
638 bool do_deadlock=false;
639 const char *remote_cmd;
643 if (strncmp(ua->argk[0], ".die", 4) == 0) {
644 if (find_arg(ua, "deadlock") > 0) {
646 remote_cmd = ".die deadlock";
650 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
651 remote_cmd = "sm_dump";
652 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
655 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
659 for (i=1; i<ua->argc; i++) {
660 if (strcasecmp(ua->argk[i], "dir") == 0 ||
661 strcasecmp(ua->argk[i], "director") == 0) {
664 if (strcasecmp(ua->argk[i], "client") == 0 ||
665 strcasecmp(ua->argk[i], "fd") == 0) {
668 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
671 client = select_client_resource(ua);
675 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
676 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
677 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
680 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
683 store = get_storage_resource(ua, false/*no default*/);
688 if (!dir && !store && !client) {
690 * We didn't find an appropriate keyword above, so
693 start_prompt(ua, _("Available daemons are: \n"));
694 add_prompt(ua, _("Director"));
695 add_prompt(ua, _("Storage"));
696 add_prompt(ua, _("Client"));
697 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
698 case 0: /* Director */
702 store = get_storage_resource(ua, false/*no default*/);
705 client = select_client_resource(ua);
713 do_storage_cmd(ua, store, remote_cmd);
717 do_client_cmd(ua, client, remote_cmd);
721 if (strncmp(remote_cmd, ".die", 4) == 0) {
723 ua->send_msg(_("The Director will generate a deadlock.\n"));
727 ua->send_msg(_("The Director will segment fault.\n"));
728 a = jcr->JobId; /* ref NULL pointer */
729 jcr->JobId = 1000; /* another ref NULL pointer */
731 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
732 sm_dump(false, true);
733 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
734 dot_quit_cmd(ua, cmd);
744 * Dummy routine for non-development version
746 static bool admin_cmds(UAContext *ua, const char *cmd)
748 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
755 * Can use an argument to filter on JobType
758 static bool jobscmd(UAContext *ua, const char *cmd)
763 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
764 type = ua->argv[pos][0];
767 foreach_res(job, R_JOB) {
768 if (!type || type == job->JobType) {
769 if (acl_access_ok(ua, Job_ACL, job->name())) {
770 ua->send_msg("%s\n", job->name());
778 static bool filesetscmd(UAContext *ua, const char *cmd)
782 foreach_res(fs, R_FILESET) {
783 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
784 ua->send_msg("%s\n", fs->name());
791 static bool clientscmd(UAContext *ua, const char *cmd)
795 foreach_res(client, R_CLIENT) {
796 if (acl_access_ok(ua, Client_ACL, client->name())) {
797 ua->send_msg("%s\n", client->name());
804 static bool msgscmd(UAContext *ua, const char *cmd)
808 foreach_res(msgs, R_MSGS) {
809 ua->send_msg("%s\n", msgs->name());
815 static bool poolscmd(UAContext *ua, const char *cmd)
819 foreach_res(pool, R_POOL) {
820 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
821 ua->send_msg("%s\n", pool->name());
828 static bool storagecmd(UAContext *ua, const char *cmd)
832 foreach_res(store, R_STORAGE) {
833 if (acl_access_ok(ua, Storage_ACL, store->name())) {
834 ua->send_msg("%s\n", store->name());
841 static bool aopcmd(UAContext *ua, const char *cmd)
843 ua->send_msg("None\n");
844 ua->send_msg("Truncate\n");
848 static bool typescmd(UAContext *ua, const char *cmd)
850 ua->send_msg("Backup\n");
851 ua->send_msg("Restore\n");
852 ua->send_msg("Admin\n");
853 ua->send_msg("Verify\n");
854 ua->send_msg("Migrate\n");
855 ua->send_msg("Copy\n");
860 * If this command is called, it tells the director that we
861 * are a program that wants a sort of API, and hence,
862 * we will probably suppress certain output, include more
863 * error codes, and most of all send back a good number
864 * of new signals that indicate whether or not the command
867 static bool api_cmd(UAContext *ua, const char *cmd)
870 ua->api = atoi(ua->argk[1]);
877 static int client_backups_handler(void *ctx, int num_field, char **row)
879 UAContext *ua = (UAContext *)ctx;
880 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
881 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
886 * Return the backups for this client
888 * .backups client=xxx fileset=yyy
891 static bool backupscmd(UAContext *ua, const char *cmd)
893 if (!open_client_db(ua)) {
896 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
897 strcmp(ua->argk[2], "fileset") != 0) {
900 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
901 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
902 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
905 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
906 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
907 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
913 static int sql_handler(void *ctx, int num_field, char **row)
915 UAContext *ua = (UAContext *)ctx;
916 POOL_MEM rows(PM_MESSAGE);
918 /* Check for nonsense */
919 if (num_field == 0 || row == NULL || row[0] == NULL) {
920 return 0; /* nothing returned */
922 for (int i=0; num_field--; i++) {
924 pm_strcpy(rows, NPRT(row[0]));
926 pm_strcat(rows, NPRT(row[i]));
928 pm_strcat(rows, "\t");
930 if (!rows.c_str() || !*rows.c_str()) {
933 ua->send_msg("%s", rows.c_str());
938 static bool sql_cmd(UAContext *ua, const char *cmd)
941 if (!open_client_db(ua)) {
944 index = find_arg_with_value(ua, "query");
946 ua->error_msg(_("query keyword not found.\n"));
949 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
950 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
951 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
957 static int one_handler(void *ctx, int num_field, char **row)
959 UAContext *ua = (UAContext *)ctx;
960 ua->send_msg("%s\n", row[0]);
964 static bool mediatypescmd(UAContext *ua, const char *cmd)
966 if (!open_client_db(ua)) {
969 if (!db_sql_query(ua->db,
970 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
971 one_handler, (void *)ua))
973 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
978 static bool mediacmd(UAContext *ua, const char *cmd)
980 if (!open_client_db(ua)) {
983 if (!db_sql_query(ua->db,
984 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
985 one_handler, (void *)ua))
987 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
992 static bool locationscmd(UAContext *ua, const char *cmd)
994 if (!open_client_db(ua)) {
997 if (!db_sql_query(ua->db,
998 "SELECT DISTINCT Location FROM Location ORDER BY Location",
999 one_handler, (void *)ua))
1001 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
1006 static bool levelscmd(UAContext *ua, const char *cmd)
1009 /* Note some levels are blank, which means none is needed */
1010 if (ua->argc == 1) {
1011 for (i=0; joblevels[i].level_name; i++) {
1012 if (joblevels[i].level_name[0] != ' ') {
1013 ua->send_msg("%s\n", joblevels[i].level_name);
1016 } else if (ua->argc == 2) {
1018 /* Assume that first argument is the Job Type */
1019 for (i=0; jobtypes[i].type_name; i++) {
1020 if (strcasecmp(ua->argk[1], jobtypes[i].type_name) == 0) {
1021 jobtype = jobtypes[i].job_type;
1025 for (i=0; joblevels[i].level_name; i++) {
1026 if ((joblevels[i].job_type == jobtype) && (joblevels[i].level_name[0] != ' ')) {
1027 ua->send_msg("%s\n", joblevels[i].level_name);
1035 static bool volstatuscmd(UAContext *ua, const char *cmd)
1037 ua->send_msg("Append\n");
1038 ua->send_msg("Full\n");
1039 ua->send_msg("Used\n");
1040 ua->send_msg("Recycle\n");
1041 ua->send_msg("Purged\n");
1042 ua->send_msg("Cleaning\n");
1043 ua->send_msg("Error\n");
1048 * Return default values for a job
1050 static bool defaultscmd(UAContext *ua, const char *cmd)
1058 if (ua->argc != 2 || !ua->argv[1]) {
1063 if (strcmp(ua->argk[1], "job") == 0) {
1064 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1067 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1070 ua->send_msg("job=%s", job->name());
1071 ua->send_msg("pool=%s", job->pool->name());
1072 ua->send_msg("messages=%s", job->messages->name());
1073 ua->send_msg("client=%s", job->client->name());
1074 get_job_storage(&store, job, NULL);
1075 ua->send_msg("storage=%s", store.store->name());
1076 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1077 ua->send_msg("level=%s", level_to_str(job->JobLevel));
1078 ua->send_msg("type=%s", job_type_to_str(job->JobType));
1079 ua->send_msg("fileset=%s", job->fileset->name());
1080 ua->send_msg("enabled=%d", job->enabled);
1081 ua->send_msg("catalog=%s", job->client->catalog->name());
1084 /* Client defaults */
1085 else if (strcmp(ua->argk[1], "client") == 0) {
1086 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1089 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1091 ua->send_msg("client=%s", client->name());
1092 ua->send_msg("address=%s", client->address);
1093 ua->send_msg("fdport=%d", client->FDport);
1094 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1095 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1096 ua->send_msg("autoprune=%d", client->AutoPrune);
1097 ua->send_msg("catalog=%s", client->catalog->name());
1100 /* Storage defaults */
1101 else if (strcmp(ua->argk[1], "storage") == 0) {
1102 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1105 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1108 ua->send_msg("storage=%s", storage->name());
1109 ua->send_msg("address=%s", storage->address);
1110 ua->send_msg("enabled=%d", storage->enabled);
1111 ua->send_msg("media_type=%s", storage->media_type);
1112 ua->send_msg("sdport=%d", storage->SDport);
1113 device = (DEVICE *)storage->device->first();
1114 ua->send_msg("device=%s", device->name());
1115 if (storage->device->size() > 1) {
1116 while ((device = (DEVICE *)storage->device->next())) {
1117 ua->send_msg(",%s", device->name());
1123 else if (strcmp(ua->argk[1], "pool") == 0) {
1124 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1127 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1129 ua->send_msg("pool=%s", pool->name());
1130 ua->send_msg("pool_type=%s", pool->pool_type);
1131 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1132 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1133 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1134 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1135 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1136 ua->send_msg("max_volumes=%d", pool->max_volumes);
1137 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1138 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1139 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1140 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1141 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1142 ua->send_msg("auto_prune=%d", pool->AutoPrune);
1143 ua->send_msg("recycle=%d", pool->Recycle);
1144 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1145 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));