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);
74 static bool catalogscmd(UAContext *ua, const char *cmd);
76 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd);
77 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd);
78 static bool dot_bvfs_update(UAContext *ua, const char *cmd);
79 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd);
80 static bool dot_bvfs_versions(UAContext *ua, const char *cmd);
81 static bool dot_bvfs_restore(UAContext *ua, const char *cmd);
82 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd);
83 static bool dot_bvfs_clear_cache(UAContext *ua, const char *cmd);
85 static bool api_cmd(UAContext *ua, const char *cmd);
86 static bool sql_cmd(UAContext *ua, const char *cmd);
87 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
88 static bool dot_help_cmd(UAContext *ua, const char *cmd);
89 static int one_handler(void *ctx, int num_field, char **row);
91 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;};
92 static struct cmdstruct commands[] = { /* help */ /* can be used in runscript */
93 { NT_(".api"), api_cmd, NULL, false},
94 { NT_(".backups"), backupscmd, NULL, false},
95 { NT_(".clients"), clientscmd, NULL, true},
96 { NT_(".catalogs"), catalogscmd, NULL, false},
97 { NT_(".defaults"), defaultscmd, NULL, false},
98 { NT_(".die"), admin_cmds, NULL, false},
99 { NT_(".dump"), admin_cmds, NULL, false},
100 { NT_(".exit"), admin_cmds, NULL, false},
101 { NT_(".filesets"), filesetscmd, NULL, false},
102 { NT_(".help"), dot_help_cmd, NULL, false},
103 { NT_(".jobs"), jobscmd, NULL, true},
104 { NT_(".levels"), levelscmd, NULL, false},
105 { NT_(".messages"), getmsgscmd, NULL, false},
106 { NT_(".msgs"), msgscmd, NULL, false},
107 { NT_(".pools"), poolscmd, NULL, true},
108 { NT_(".quit"), dot_quit_cmd, NULL, false},
109 { NT_(".sql"), sql_cmd, NULL, false},
110 { NT_(".status"), dot_status_cmd, NULL, false},
111 { NT_(".storage"), storagecmd, NULL, true},
112 { NT_(".volstatus"), volstatuscmd, NULL, true},
113 { NT_(".media"), mediacmd, NULL, true},
114 { NT_(".mediatypes"), mediatypescmd, NULL, true},
115 { NT_(".locations"), locationscmd, NULL, true},
116 { NT_(".actiononpurge"),aopcmd, NULL, true},
117 { NT_(".bvfs_lsdirs"), dot_bvfs_lsdirs, NULL, true},
118 { NT_(".bvfs_lsfiles"),dot_bvfs_lsfiles, NULL, true},
119 { NT_(".bvfs_update"), dot_bvfs_update, NULL, true},
120 { NT_(".bvfs_get_jobids"), dot_bvfs_get_jobids, NULL, true},
121 { NT_(".bvfs_versions"), dot_bvfs_versions, NULL, true},
122 { NT_(".bvfs_restore"), dot_bvfs_restore, NULL, true},
123 { NT_(".bvfs_cleanup"), dot_bvfs_cleanup, NULL, true},
124 { NT_(".bvfs_clear_cache"),dot_bvfs_clear_cache,NULL, false},
125 { NT_(".types"), typescmd, NULL, false}
127 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
130 * Execute a command from the UA
132 bool do_a_dot_command(UAContext *ua)
138 BSOCK *user = ua->UA_sock;
140 Dmsg1(1400, "Dot command: %s\n", user->msg);
145 len = strlen(ua->argk[0]);
147 if (ua->api) user->signal(BNET_CMD_BEGIN);
148 if (ua->api) user->signal(BNET_CMD_OK);
149 return true; /* no op */
151 for (i=0; i<comsize; i++) { /* search for command */
152 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
153 /* Check if this command is authorized in RunScript */
154 if (ua->runscript && !commands[i].use_in_rs) {
155 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
159 /* Check if command permitted, but "quit" is always OK */
160 if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
161 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
164 Dmsg1(100, "Cmd: %s\n", ua->cmd);
166 if (ua->api) user->signal(BNET_CMD_BEGIN);
167 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
168 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
175 ua->error_msg("%s%s", ua->argk[0], _(": is an invalid command.\n"));
181 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
183 if (!open_new_client_db(ua)) {
187 int pos = find_arg_with_value(ua, "jobid");
188 if (pos != -1 && is_a_number_list(ua->argv[pos])) {
189 bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, ua->argv[pos]);
191 /* update cache for all jobids */
192 bvfs_update_cache(ua->jcr, ua->db);
199 static bool dot_bvfs_clear_cache(UAContext *ua, const char *cmd)
201 if (!open_new_client_db(ua)) {
205 int pos = find_arg(ua, "yes");
207 Bvfs fs(ua->jcr, ua->db);
209 ua->info_msg("OK\n");
215 static int bvfs_result_handler(void *ctx, int fields, char **row)
217 UAContext *ua = (UAContext *)ctx;
220 char *fileid=row[BVFS_FileId];
221 char *lstat=row[BVFS_LStat];
222 char *jobid=row[BVFS_JobId];
224 char empty[] = "A A A A A A A A A A A A A A";
227 /* We need to deal with non existant path */
228 if (!fileid || !is_a_number(fileid)) {
234 memset(&statp, 0, sizeof(struct stat));
235 decode_stat(lstat, &statp, sizeof(statp), &LinkFI);
237 Dmsg1(100, "type=%s\n", row[0]);
238 if (bvfs_is_dir(row)) {
239 char *path = bvfs_basename_dir(row[BVFS_Name]);
240 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
243 } else if (bvfs_is_version(row)) {
244 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
245 row[BVFS_FilenameId], fileid, jobid,
246 lstat, row[BVFS_Md5], row[BVFS_VolName],
247 row[BVFS_VolInchanger]);
249 } else if (bvfs_is_file(row)) {
250 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
251 row[BVFS_FilenameId], fileid, jobid,
252 lstat, row[BVFS_Name]);
258 static bool bvfs_parse_arg_version(UAContext *ua,
269 for (int i=1; i<ua->argc; i++) {
270 if (fnid && strcasecmp(ua->argk[i], NT_("fnid")) == 0) {
271 if (is_a_number(ua->argv[i])) {
272 *fnid = str_to_int64(ua->argv[i]);
276 if (strcasecmp(ua->argk[i], NT_("client")) == 0) {
277 *client = ua->argv[i];
280 if (copies && strcasecmp(ua->argk[i], NT_("copies")) == 0) {
284 if (versions && strcasecmp(ua->argk[i], NT_("versions")) == 0) {
288 return (*client && *fnid > 0);
291 static bool bvfs_parse_arg(UAContext *ua,
292 DBId_t *pathid, char **path, char **jobid,
294 int *limit, int *offset)
303 for (int i=1; i<ua->argc; i++) {
304 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
305 if (is_a_number(ua->argv[i])) {
306 *pathid = str_to_int64(ua->argv[i]);
310 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
314 if (strcasecmp(ua->argk[i], NT_("username")) == 0) {
315 *username = ua->argv[i];
318 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
319 if (is_a_number_list(ua->argv[i])) {
320 *jobid = ua->argv[i];
324 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
325 if (is_a_number(ua->argv[i])) {
326 *limit = str_to_int64(ua->argv[i]);
330 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
331 if (is_a_number(ua->argv[i])) {
332 *offset = str_to_int64(ua->argv[i]);
337 if (!((*pathid || *path) && *jobid)) {
341 if (!open_client_db(ua)) {
348 /* .bvfs_cleanup path=b2XXXXX
350 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
353 if ((i = find_arg_with_value(ua, "path")) >= 0) {
355 Bvfs fs(ua->jcr, ua->db);
356 fs.drop_restore_list(ua->argv[i]);
361 /* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
363 static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
366 int limit=2000, offset=0, i;
367 char *path=NULL, *jobid=NULL, *username=NULL;
368 char *empty = (char *)"";
369 char *fileid, *dirid, *hardlink;
370 fileid = dirid = hardlink = empty;
372 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
375 ua->error_msg("Can't find jobid, pathid or path argument\n");
376 return true; /* not enough param */
379 Bvfs fs(ua->jcr, ua->db);
380 fs.set_username(username);
381 fs.set_jobids(jobid);
383 if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
384 fileid = ua->argv[i];
386 if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
389 if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
390 hardlink = ua->argv[i];
393 if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
394 ua->send_msg("OK\n");
396 ua->error_msg("Can't create restore list\n");
402 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
403 * .bvfs_lsfiles jobid=1,2,3,4 path=/
405 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
408 int limit=2000, offset=0;
409 char *path=NULL, *jobid=NULL, *username=NULL;
413 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
416 ua->error_msg("Can't find jobid, pathid or path argument\n");
417 return true; /* not enough param */
419 if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
420 pattern = ua->argv[i];
423 Bvfs fs(ua->jcr, ua->db);
424 fs.set_username(username);
425 fs.set_jobids(jobid);
426 fs.set_handler(bvfs_result_handler, ua);
429 fs.set_pattern(pattern);
437 fs.set_offset(offset);
445 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
446 * .bvfs_lsdirs jobid=1,2,3,4 path=/
447 * .bvfs_lsdirs jobid=1,2,3,4 path=
449 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
452 int limit=2000, offset=0;
453 char *path=NULL, *jobid=NULL, *username=NULL;
455 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
458 ua->error_msg("Can't find jobid, pathid or path argument\n");
459 return true; /* not enough param */
462 Bvfs fs(ua->jcr, ua->db);
463 fs.set_username(username);
464 fs.set_jobids(jobid);
466 fs.set_handler(bvfs_result_handler, ua);
474 fs.set_offset(offset);
476 fs.ls_special_dirs();
483 * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
486 static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
488 DBId_t pathid=0, fnid=0;
489 int limit=2000, offset=0;
490 char *path=NULL, *jobid=NULL, *client=NULL, *username=NULL;
491 bool copies=false, versions=false;
492 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
495 ua->error_msg("Can't find jobid, pathid or path argument\n");
496 return true; /* not enough param */
499 if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
501 ua->error_msg("Can't find client or fnid argument\n");
502 return true; /* not enough param */
505 Bvfs fs(ua->jcr, ua->db);
507 fs.set_see_all_versions(versions);
508 fs.set_see_copies(copies);
509 fs.set_handler(bvfs_result_handler, ua);
510 fs.set_offset(offset);
511 fs.get_all_file_versions(pathid, fnid, client);
516 /* .bvfs_get_jobids jobid=1
517 * -> returns needed jobids to restore
518 * .bvfs_get_jobids jobid=1 all
519 * -> returns needed jobids to restore with all filesets a JobId=1 time
521 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
524 db_list_ctx jobids, tempids;
528 dbid_list ids; /* Store all FileSetIds for this client */
530 if (!open_client_db(ua)) {
534 memset(&jr, 0, sizeof(JOB_DBR));
535 if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
536 jr.JobId = str_to_int64(ua->argv[pos]);
539 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
540 ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
541 ua->cmd, db_strerror(ua->db));
545 /* If we have the "all" option, we do a search on all defined fileset
548 if (find_arg(ua, "all") > 0) {
549 edit_int64(jr.ClientId, ed1);
550 Mmsg(query, uar_sel_filesetid, ed1);
551 db_get_query_dbids(ua->jcr, ua->db, query, ids);
554 ids.DBId[0] = jr.FileSetId;
557 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
559 /* Foreach different FileSet, we build a restore jobid list */
560 for (int i=0; i < ids.num_ids; i++) {
561 jr.FileSetId = ids.DBId[i];
562 if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
568 ua->send_msg("%s\n", jobids.list);
572 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
578 static bool dot_help_cmd(UAContext *ua, const char *cmd)
584 static bool getmsgscmd(UAContext *ua, const char *cmd)
586 if (console_msg_pending) {
587 do_messages(ua, cmd);
593 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
599 lstore.store = store;
600 pm_strcpy(lstore.store_source, _("unknown source"));
601 set_wstorage(jcr, &lstore);
602 /* Try connecting for up to 15 seconds */
603 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
604 store->name(), store->address, store->SDport);
605 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
606 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
609 Dmsg0(120, _("Connected to storage daemon\n"));
610 sd = jcr->store_bsock;
611 sd->fsend("%s", cmd);
612 if (sd->recv() >= 0) {
613 ua->send_msg("%s", sd->msg);
615 sd->signal(BNET_TERMINATE);
617 jcr->store_bsock = NULL;
621 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
625 /* Connect to File daemon */
627 ua->jcr->client = client;
628 /* Try to connect for 15 seconds */
629 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
630 client->name(), client->address, client->FDport);
631 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
632 ua->error_msg(_("Failed to connect to Client.\n"));
635 Dmsg0(120, "Connected to file daemon\n");
636 fd = ua->jcr->file_bsock;
637 fd->fsend("%s", cmd);
638 if (fd->recv() >= 0) {
639 ua->send_msg("%s", fd->msg);
641 fd->signal(BNET_TERMINATE);
643 ua->jcr->file_bsock = NULL;
650 * .exit (no arg => .quit)
652 static bool admin_cmds(UAContext *ua, const char *cmd)
654 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
658 bool do_deadlock=false;
659 const char *remote_cmd;
663 if (strncmp(ua->argk[0], ".die", 4) == 0) {
664 if (find_arg(ua, "deadlock") > 0) {
666 remote_cmd = ".die deadlock";
670 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
671 remote_cmd = "sm_dump";
672 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
675 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
679 for (i=1; i<ua->argc; i++) {
680 if (strcasecmp(ua->argk[i], "dir") == 0 ||
681 strcasecmp(ua->argk[i], "director") == 0) {
684 if (strcasecmp(ua->argk[i], "client") == 0 ||
685 strcasecmp(ua->argk[i], "fd") == 0) {
688 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
691 client = select_client_resource(ua);
695 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
696 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
697 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
700 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
703 store = get_storage_resource(ua, false/*no default*/);
708 if (!dir && !store && !client) {
710 * We didn't find an appropriate keyword above, so
713 start_prompt(ua, _("Available daemons are: \n"));
714 add_prompt(ua, _("Director"));
715 add_prompt(ua, _("Storage"));
716 add_prompt(ua, _("Client"));
717 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
718 case 0: /* Director */
722 store = get_storage_resource(ua, false/*no default*/);
725 client = select_client_resource(ua);
733 do_storage_cmd(ua, store, remote_cmd);
737 do_client_cmd(ua, client, remote_cmd);
741 if (strncmp(remote_cmd, ".die", 4) == 0) {
743 ua->send_msg(_("The Director will generate a deadlock.\n"));
747 ua->send_msg(_("The Director will segment fault.\n"));
748 a = jcr->JobId; /* ref NULL pointer */
749 jcr->JobId = 1000; /* another ref NULL pointer */
752 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
753 sm_dump(false, true);
754 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
755 dot_quit_cmd(ua, cmd);
765 * Dummy routine for non-development version
767 static bool admin_cmds(UAContext *ua, const char *cmd)
769 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
776 * Can use an argument to filter on JobType
779 static bool jobscmd(UAContext *ua, const char *cmd)
784 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
785 type = ua->argv[pos][0];
788 foreach_res(job, R_JOB) {
789 if (!type || type == job->JobType) {
790 if (acl_access_ok(ua, Job_ACL, job->name())) {
791 ua->send_msg("%s\n", job->name());
799 static bool filesetscmd(UAContext *ua, const char *cmd)
803 foreach_res(fs, R_FILESET) {
804 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
805 ua->send_msg("%s\n", fs->name());
812 static bool catalogscmd(UAContext *ua, const char *cmd)
816 foreach_res(cat, R_CATALOG) {
817 if (acl_access_ok(ua, Catalog_ACL, cat->name())) {
818 ua->send_msg("%s\n", cat->name());
825 static bool clientscmd(UAContext *ua, const char *cmd)
829 foreach_res(client, R_CLIENT) {
830 if (acl_access_ok(ua, Client_ACL, client->name())) {
831 ua->send_msg("%s\n", client->name());
838 static bool msgscmd(UAContext *ua, const char *cmd)
842 foreach_res(msgs, R_MSGS) {
843 ua->send_msg("%s\n", msgs->name());
849 static bool poolscmd(UAContext *ua, const char *cmd)
853 foreach_res(pool, R_POOL) {
854 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
855 ua->send_msg("%s\n", pool->name());
862 static bool storagecmd(UAContext *ua, const char *cmd)
866 foreach_res(store, R_STORAGE) {
867 if (acl_access_ok(ua, Storage_ACL, store->name())) {
868 ua->send_msg("%s\n", store->name());
875 static bool aopcmd(UAContext *ua, const char *cmd)
877 ua->send_msg("None\n");
878 ua->send_msg("Truncate\n");
882 static bool typescmd(UAContext *ua, const char *cmd)
884 ua->send_msg("Backup\n");
885 ua->send_msg("Restore\n");
886 ua->send_msg("Admin\n");
887 ua->send_msg("Verify\n");
888 ua->send_msg("Migrate\n");
889 ua->send_msg("Copy\n");
894 * If this command is called, it tells the director that we
895 * are a program that wants a sort of API, and hence,
896 * we will probably suppress certain output, include more
897 * error codes, and most of all send back a good number
898 * of new signals that indicate whether or not the command
901 static bool api_cmd(UAContext *ua, const char *cmd)
904 ua->api = atoi(ua->argk[1]);
911 static int client_backups_handler(void *ctx, int num_field, char **row)
913 UAContext *ua = (UAContext *)ctx;
914 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
915 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
920 * Return the backups for this client
922 * .backups client=xxx fileset=yyy
925 static bool backupscmd(UAContext *ua, const char *cmd)
927 if (!open_client_db(ua)) {
930 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
931 strcmp(ua->argk[2], "fileset") != 0) {
934 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
935 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
936 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
939 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
940 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
941 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
947 static int sql_handler(void *ctx, int num_field, char **row)
949 UAContext *ua = (UAContext *)ctx;
950 POOL_MEM rows(PM_MESSAGE);
952 /* Check for nonsense */
953 if (num_field == 0 || row == NULL || row[0] == NULL) {
954 return 0; /* nothing returned */
956 for (int i=0; num_field--; i++) {
958 pm_strcpy(rows, NPRT(row[0]));
960 pm_strcat(rows, NPRT(row[i]));
962 pm_strcat(rows, "\t");
964 if (!rows.c_str() || !*rows.c_str()) {
967 ua->send_msg("%s", rows.c_str());
972 static bool sql_cmd(UAContext *ua, const char *cmd)
975 if (!open_client_db(ua)) {
978 index = find_arg_with_value(ua, "query");
980 ua->error_msg(_("query keyword not found.\n"));
983 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
984 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
985 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
991 static int one_handler(void *ctx, int num_field, char **row)
993 UAContext *ua = (UAContext *)ctx;
994 ua->send_msg("%s\n", row[0]);
998 static bool mediatypescmd(UAContext *ua, const char *cmd)
1000 if (!open_client_db(ua)) {
1003 if (!db_sql_query(ua->db,
1004 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
1005 one_handler, (void *)ua))
1007 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
1012 static bool mediacmd(UAContext *ua, const char *cmd)
1014 if (!open_client_db(ua)) {
1017 if (!db_sql_query(ua->db,
1018 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
1019 one_handler, (void *)ua))
1021 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
1026 static bool locationscmd(UAContext *ua, const char *cmd)
1028 if (!open_client_db(ua)) {
1031 if (!db_sql_query(ua->db,
1032 "SELECT DISTINCT Location FROM Location ORDER BY Location",
1033 one_handler, (void *)ua))
1035 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
1040 static bool levelscmd(UAContext *ua, const char *cmd)
1043 /* Note some levels are blank, which means none is needed */
1044 if (ua->argc == 1) {
1045 for (i=0; joblevels[i].level_name; i++) {
1046 if (joblevels[i].level_name[0] != ' ') {
1047 ua->send_msg("%s\n", joblevels[i].level_name);
1050 } else if (ua->argc == 2) {
1052 /* Assume that first argument is the Job Type */
1053 for (i=0; jobtypes[i].type_name; i++) {
1054 if (strcasecmp(ua->argk[1], jobtypes[i].type_name) == 0) {
1055 jobtype = jobtypes[i].job_type;
1059 for (i=0; joblevels[i].level_name; i++) {
1060 if ((joblevels[i].job_type == jobtype) && (joblevels[i].level_name[0] != ' ')) {
1061 ua->send_msg("%s\n", joblevels[i].level_name);
1069 static bool volstatuscmd(UAContext *ua, const char *cmd)
1071 ua->send_msg("Append\n");
1072 ua->send_msg("Full\n");
1073 ua->send_msg("Used\n");
1074 ua->send_msg("Recycle\n");
1075 ua->send_msg("Purged\n");
1076 ua->send_msg("Cleaning\n");
1077 ua->send_msg("Error\n");
1082 * Return default values for a job
1084 static bool defaultscmd(UAContext *ua, const char *cmd)
1092 if (ua->argc != 2 || !ua->argv[1]) {
1097 if (strcmp(ua->argk[1], "job") == 0) {
1098 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1101 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1104 ua->send_msg("job=%s", job->name());
1105 ua->send_msg("pool=%s", job->pool->name());
1106 ua->send_msg("messages=%s", job->messages->name());
1107 ua->send_msg("client=%s", job->client->name());
1108 get_job_storage(&store, job, NULL);
1109 ua->send_msg("storage=%s", store.store->name());
1110 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1111 ua->send_msg("level=%s", level_to_str(job->JobLevel));
1112 ua->send_msg("type=%s", job_type_to_str(job->JobType));
1113 ua->send_msg("fileset=%s", job->fileset->name());
1114 ua->send_msg("enabled=%d", job->enabled);
1115 ua->send_msg("catalog=%s", job->client->catalog->name());
1118 /* Client defaults */
1119 else if (strcmp(ua->argk[1], "client") == 0) {
1120 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1123 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1125 ua->send_msg("client=%s", client->name());
1126 ua->send_msg("address=%s", client->address);
1127 ua->send_msg("fdport=%d", client->FDport);
1128 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1129 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1130 ua->send_msg("autoprune=%d", client->AutoPrune);
1131 ua->send_msg("catalog=%s", client->catalog->name());
1134 /* Storage defaults */
1135 else if (strcmp(ua->argk[1], "storage") == 0) {
1136 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1139 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1142 ua->send_msg("storage=%s", storage->name());
1143 ua->send_msg("address=%s", storage->address);
1144 ua->send_msg("enabled=%d", storage->enabled);
1145 ua->send_msg("media_type=%s", storage->media_type);
1146 ua->send_msg("sdport=%d", storage->SDport);
1147 device = (DEVICE *)storage->device->first();
1148 ua->send_msg("device=%s", device->name());
1149 if (storage->device->size() > 1) {
1150 while ((device = (DEVICE *)storage->device->next())) {
1151 ua->send_msg(",%s", device->name());
1157 else if (strcmp(ua->argk[1], "pool") == 0) {
1158 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1161 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1163 ua->send_msg("pool=%s", pool->name());
1164 ua->send_msg("pool_type=%s", pool->pool_type);
1165 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1166 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1167 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1168 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1169 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1170 ua->send_msg("max_volumes=%d", pool->max_volumes);
1171 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1172 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1173 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1174 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1175 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1176 ua->send_msg("auto_prune=%d", pool->AutoPrune);
1177 ua->send_msg("recycle=%d", pool->Recycle);
1178 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1179 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));