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 if (!bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, ua->argv[pos])) {
190 ua->error_msg("ERROR: BVFS reported a problem for %s\n",
194 /* update cache for all jobids */
195 bvfs_update_cache(ua->jcr, ua->db);
202 static bool dot_bvfs_clear_cache(UAContext *ua, const char *cmd)
204 if (!open_new_client_db(ua)) {
208 int pos = find_arg(ua, "yes");
210 Bvfs fs(ua->jcr, ua->db);
212 ua->info_msg("OK\n");
214 ua->error_msg("Can't find 'yes' argument\n");
221 static int bvfs_result_handler(void *ctx, int fields, char **row)
223 UAContext *ua = (UAContext *)ctx;
226 char *fileid=row[BVFS_FileId];
227 char *lstat=row[BVFS_LStat];
228 char *jobid=row[BVFS_JobId];
230 char empty[] = "A A A A A A A A A A A A A A";
233 /* We need to deal with non existant path */
234 if (!fileid || !is_a_number(fileid)) {
240 memset(&statp, 0, sizeof(struct stat));
241 decode_stat(lstat, &statp, sizeof(statp), &LinkFI);
243 Dmsg1(100, "type=%s\n", row[0]);
244 if (bvfs_is_dir(row)) {
245 char *path = bvfs_basename_dir(row[BVFS_Name]);
246 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
249 } else if (bvfs_is_version(row)) {
250 ua->send_msg("%s\t%s\t%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_Md5], row[BVFS_VolName],
253 row[BVFS_VolInchanger]);
255 } else if (bvfs_is_file(row)) {
256 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
257 row[BVFS_FilenameId], fileid, jobid,
258 lstat, row[BVFS_Name]);
264 static bool bvfs_parse_arg_version(UAContext *ua,
275 for (int i=1; i<ua->argc; i++) {
276 if (fnid && strcasecmp(ua->argk[i], NT_("fnid")) == 0) {
277 if (is_a_number(ua->argv[i])) {
278 *fnid = str_to_int64(ua->argv[i]);
282 if (strcasecmp(ua->argk[i], NT_("client")) == 0) {
283 *client = ua->argv[i];
286 if (copies && strcasecmp(ua->argk[i], NT_("copies")) == 0) {
290 if (versions && strcasecmp(ua->argk[i], NT_("versions")) == 0) {
294 return (*client && *fnid > 0);
297 static bool bvfs_parse_arg(UAContext *ua,
298 DBId_t *pathid, char **path, char **jobid,
300 int *limit, int *offset)
309 for (int i=1; i<ua->argc; i++) {
310 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
311 if (is_a_number(ua->argv[i])) {
312 *pathid = str_to_int64(ua->argv[i]);
316 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
320 if (strcasecmp(ua->argk[i], NT_("username")) == 0) {
321 *username = ua->argv[i];
324 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
325 if (is_a_number_list(ua->argv[i])) {
326 *jobid = ua->argv[i];
330 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
331 if (is_a_number(ua->argv[i])) {
332 *limit = str_to_int64(ua->argv[i]);
336 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
337 if (is_a_number(ua->argv[i])) {
338 *offset = str_to_int64(ua->argv[i]);
343 if (!((*pathid || *path) && *jobid)) {
347 if (!open_client_db(ua)) {
354 /* .bvfs_cleanup path=b2XXXXX
356 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
359 if ((i = find_arg_with_value(ua, "path")) >= 0) {
361 Bvfs fs(ua->jcr, ua->db);
362 fs.drop_restore_list(ua->argv[i]);
367 /* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
369 static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
372 int limit=2000, offset=0, i;
373 char *path=NULL, *jobid=NULL, *username=NULL;
374 char *empty = (char *)"";
375 char *fileid, *dirid, *hardlink;
376 fileid = dirid = hardlink = empty;
378 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
381 ua->error_msg("Can't find jobid, pathid or path argument\n");
382 return true; /* not enough param */
385 Bvfs fs(ua->jcr, ua->db);
386 fs.set_username(username);
387 fs.set_jobids(jobid);
389 if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
390 fileid = ua->argv[i];
392 if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
395 if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
396 hardlink = ua->argv[i];
399 if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
400 ua->send_msg("OK\n");
402 ua->error_msg("Can't create restore list\n");
408 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
409 * .bvfs_lsfiles jobid=1,2,3,4 path=/
411 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
414 int limit=2000, offset=0;
415 char *path=NULL, *jobid=NULL, *username=NULL;
419 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
422 ua->error_msg("Can't find jobid, pathid or path argument\n");
423 return true; /* not enough param */
425 if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
426 pattern = ua->argv[i];
429 Bvfs fs(ua->jcr, ua->db);
430 fs.set_username(username);
431 fs.set_jobids(jobid);
432 fs.set_handler(bvfs_result_handler, ua);
435 fs.set_pattern(pattern);
443 fs.set_offset(offset);
451 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
452 * .bvfs_lsdirs jobid=1,2,3,4 path=/
453 * .bvfs_lsdirs jobid=1,2,3,4 path=
455 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
458 int limit=2000, offset=0;
459 char *path=NULL, *jobid=NULL, *username=NULL;
461 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
464 ua->error_msg("Can't find jobid, pathid or path argument\n");
465 return true; /* not enough param */
468 Bvfs fs(ua->jcr, ua->db);
469 fs.set_username(username);
470 fs.set_jobids(jobid);
472 fs.set_handler(bvfs_result_handler, ua);
480 fs.set_offset(offset);
482 fs.ls_special_dirs();
489 * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
492 static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
494 DBId_t pathid=0, fnid=0;
495 int limit=2000, offset=0;
496 char *path=NULL, *jobid=NULL, *client=NULL, *username=NULL;
497 bool copies=false, versions=false;
498 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
501 ua->error_msg("Can't find jobid, pathid or path argument\n");
502 return true; /* not enough param */
505 if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
507 ua->error_msg("Can't find client or fnid argument\n");
508 return true; /* not enough param */
511 Bvfs fs(ua->jcr, ua->db);
513 fs.set_see_all_versions(versions);
514 fs.set_see_copies(copies);
515 fs.set_handler(bvfs_result_handler, ua);
516 fs.set_offset(offset);
517 fs.get_all_file_versions(pathid, fnid, client);
522 /* .bvfs_get_jobids jobid=1
523 * -> returns needed jobids to restore
524 * .bvfs_get_jobids jobid=1 all
525 * -> returns needed jobids to restore with all filesets a JobId=1 time
526 * .bvfs_get_jobids ujobid=JobName
527 * -> returns needed jobids to restore
529 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
532 db_list_ctx jobids, tempids;
536 dbid_list ids; /* Store all FileSetIds for this client */
538 if (!open_client_db(ua)) {
542 memset(&jr, 0, sizeof(JOB_DBR));
544 if ((pos = find_arg_with_value(ua, "ujobid")) >= 0) {
545 bstrncpy(jr.Job, ua->argv[pos], sizeof(jr.Job));
548 if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
549 jr.JobId = str_to_int64(ua->argv[pos]);
552 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
553 ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
554 ua->cmd, db_strerror(ua->db));
558 /* When in level base, we don't rely on any Full/Incr/Diff */
559 if (jr.JobLevel == L_BASE) {
560 ua->send_msg("%s\n", edit_int64(jr.JobId, ed1));
564 /* If we have the "all" option, we do a search on all defined fileset
567 if (find_arg(ua, "all") > 0) {
568 edit_int64(jr.ClientId, ed1);
569 Mmsg(query, uar_sel_filesetid, ed1);
570 db_get_query_dbids(ua->jcr, ua->db, query, ids);
573 ids.DBId[0] = jr.FileSetId;
576 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
578 /* Foreach different FileSet, we build a restore jobid list */
579 for (int i=0; i < ids.num_ids; i++) {
580 jr.FileSetId = ids.DBId[i];
581 if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
587 ua->send_msg("%s\n", jobids.list);
591 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
597 static bool dot_help_cmd(UAContext *ua, const char *cmd)
603 static bool getmsgscmd(UAContext *ua, const char *cmd)
605 if (console_msg_pending) {
606 do_messages(ua, cmd);
612 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
618 lstore.store = store;
619 pm_strcpy(lstore.store_source, _("unknown source"));
620 set_wstorage(jcr, &lstore);
621 /* Try connecting for up to 15 seconds */
622 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
623 store->name(), store->address, store->SDport);
624 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
625 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
628 Dmsg0(120, _("Connected to storage daemon\n"));
629 sd = jcr->store_bsock;
630 sd->fsend("%s", cmd);
631 if (sd->recv() >= 0) {
632 ua->send_msg("%s", sd->msg);
634 sd->signal(BNET_TERMINATE);
636 jcr->store_bsock = NULL;
640 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
644 /* Connect to File daemon */
646 ua->jcr->client = client;
647 /* Try to connect for 15 seconds */
648 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
649 client->name(), client->address, client->FDport);
650 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
651 ua->error_msg(_("Failed to connect to Client.\n"));
654 Dmsg0(120, "Connected to file daemon\n");
655 fd = ua->jcr->file_bsock;
656 fd->fsend("%s", cmd);
657 if (fd->recv() >= 0) {
658 ua->send_msg("%s", fd->msg);
660 fd->signal(BNET_TERMINATE);
662 ua->jcr->file_bsock = NULL;
669 * .exit (no arg => .quit)
671 static bool admin_cmds(UAContext *ua, const char *cmd)
673 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
677 bool do_deadlock=false;
678 const char *remote_cmd;
682 if (strncmp(ua->argk[0], ".die", 4) == 0) {
683 if (find_arg(ua, "deadlock") > 0) {
685 remote_cmd = ".die deadlock";
689 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
690 remote_cmd = "sm_dump";
691 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
694 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
698 for (i=1; i<ua->argc; i++) {
699 if (strcasecmp(ua->argk[i], "dir") == 0 ||
700 strcasecmp(ua->argk[i], "director") == 0) {
703 if (strcasecmp(ua->argk[i], "client") == 0 ||
704 strcasecmp(ua->argk[i], "fd") == 0) {
707 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
710 client = select_client_resource(ua);
714 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
715 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
716 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
719 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
722 store = get_storage_resource(ua, false/*no default*/);
727 if (!dir && !store && !client) {
729 * We didn't find an appropriate keyword above, so
732 start_prompt(ua, _("Available daemons are: \n"));
733 add_prompt(ua, _("Director"));
734 add_prompt(ua, _("Storage"));
735 add_prompt(ua, _("Client"));
736 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
737 case 0: /* Director */
741 store = get_storage_resource(ua, false/*no default*/);
744 client = select_client_resource(ua);
752 do_storage_cmd(ua, store, remote_cmd);
756 do_client_cmd(ua, client, remote_cmd);
760 if (strncmp(remote_cmd, ".die", 4) == 0) {
762 ua->send_msg(_("The Director will generate a deadlock.\n"));
766 ua->send_msg(_("The Director will segment fault.\n"));
767 a = jcr->JobId; /* ref NULL pointer */
768 jcr->JobId = 1000; /* another ref NULL pointer */
771 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
772 sm_dump(false, true);
773 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
774 dot_quit_cmd(ua, cmd);
784 * Dummy routine for non-development version
786 static bool admin_cmds(UAContext *ua, const char *cmd)
788 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
795 * Can use an argument to filter on JobType
798 static bool jobscmd(UAContext *ua, const char *cmd)
803 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
804 type = ua->argv[pos][0];
807 foreach_res(job, R_JOB) {
808 if (!type || type == job->JobType) {
809 if (acl_access_ok(ua, Job_ACL, job->name())) {
810 ua->send_msg("%s\n", job->name());
818 static bool filesetscmd(UAContext *ua, const char *cmd)
822 foreach_res(fs, R_FILESET) {
823 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
824 ua->send_msg("%s\n", fs->name());
831 static bool catalogscmd(UAContext *ua, const char *cmd)
835 foreach_res(cat, R_CATALOG) {
836 if (acl_access_ok(ua, Catalog_ACL, cat->name())) {
837 ua->send_msg("%s\n", cat->name());
844 static bool clientscmd(UAContext *ua, const char *cmd)
848 foreach_res(client, R_CLIENT) {
849 if (acl_access_ok(ua, Client_ACL, client->name())) {
850 ua->send_msg("%s\n", client->name());
857 static bool msgscmd(UAContext *ua, const char *cmd)
861 foreach_res(msgs, R_MSGS) {
862 ua->send_msg("%s\n", msgs->name());
868 static bool poolscmd(UAContext *ua, const char *cmd)
872 foreach_res(pool, R_POOL) {
873 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
874 ua->send_msg("%s\n", pool->name());
881 static bool storagecmd(UAContext *ua, const char *cmd)
885 foreach_res(store, R_STORAGE) {
886 if (acl_access_ok(ua, Storage_ACL, store->name())) {
887 ua->send_msg("%s\n", store->name());
894 static bool aopcmd(UAContext *ua, const char *cmd)
896 ua->send_msg("None\n");
897 ua->send_msg("Truncate\n");
901 static bool typescmd(UAContext *ua, const char *cmd)
903 ua->send_msg("Backup\n");
904 ua->send_msg("Restore\n");
905 ua->send_msg("Admin\n");
906 ua->send_msg("Verify\n");
907 ua->send_msg("Migrate\n");
908 ua->send_msg("Copy\n");
913 * If this command is called, it tells the director that we
914 * are a program that wants a sort of API, and hence,
915 * we will probably suppress certain output, include more
916 * error codes, and most of all send back a good number
917 * of new signals that indicate whether or not the command
920 static bool api_cmd(UAContext *ua, const char *cmd)
923 ua->api = atoi(ua->argk[1]);
930 static int client_backups_handler(void *ctx, int num_field, char **row)
932 UAContext *ua = (UAContext *)ctx;
933 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
934 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
939 * Return the backups for this client
941 * .backups client=xxx fileset=yyy
944 static bool backupscmd(UAContext *ua, const char *cmd)
946 if (!open_client_db(ua)) {
949 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
950 strcmp(ua->argk[2], "fileset") != 0) {
953 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
954 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
955 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
958 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
959 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
960 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
966 static int sql_handler(void *ctx, int num_field, char **row)
968 UAContext *ua = (UAContext *)ctx;
969 POOL_MEM rows(PM_MESSAGE);
971 /* Check for nonsense */
972 if (num_field == 0 || row == NULL || row[0] == NULL) {
973 return 0; /* nothing returned */
975 for (int i=0; num_field--; i++) {
977 pm_strcpy(rows, NPRT(row[0]));
979 pm_strcat(rows, NPRT(row[i]));
981 pm_strcat(rows, "\t");
983 if (!rows.c_str() || !*rows.c_str()) {
986 ua->send_msg("%s", rows.c_str());
991 static bool sql_cmd(UAContext *ua, const char *cmd)
994 if (!open_client_db(ua)) {
997 index = find_arg_with_value(ua, "query");
999 ua->error_msg(_("query keyword not found.\n"));
1002 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
1003 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
1004 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
1010 static int one_handler(void *ctx, int num_field, char **row)
1012 UAContext *ua = (UAContext *)ctx;
1013 ua->send_msg("%s\n", row[0]);
1017 static bool mediatypescmd(UAContext *ua, const char *cmd)
1019 if (!open_client_db(ua)) {
1022 if (!db_sql_query(ua->db,
1023 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
1024 one_handler, (void *)ua))
1026 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
1031 static bool mediacmd(UAContext *ua, const char *cmd)
1033 if (!open_client_db(ua)) {
1036 if (!db_sql_query(ua->db,
1037 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
1038 one_handler, (void *)ua))
1040 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
1045 static bool locationscmd(UAContext *ua, const char *cmd)
1047 if (!open_client_db(ua)) {
1050 if (!db_sql_query(ua->db,
1051 "SELECT DISTINCT Location FROM Location ORDER BY Location",
1052 one_handler, (void *)ua))
1054 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
1059 static bool levelscmd(UAContext *ua, const char *cmd)
1062 /* Note some levels are blank, which means none is needed */
1063 if (ua->argc == 1) {
1064 for (i=0; joblevels[i].level_name; i++) {
1065 if (joblevels[i].level_name[0] != ' ') {
1066 ua->send_msg("%s\n", joblevels[i].level_name);
1069 } else if (ua->argc == 2) {
1071 /* Assume that first argument is the Job Type */
1072 for (i=0; jobtypes[i].type_name; i++) {
1073 if (strcasecmp(ua->argk[1], jobtypes[i].type_name) == 0) {
1074 jobtype = jobtypes[i].job_type;
1078 for (i=0; joblevels[i].level_name; i++) {
1079 if ((joblevels[i].job_type == jobtype) && (joblevels[i].level_name[0] != ' ')) {
1080 ua->send_msg("%s\n", joblevels[i].level_name);
1088 static bool volstatuscmd(UAContext *ua, const char *cmd)
1090 ua->send_msg("Append\n");
1091 ua->send_msg("Full\n");
1092 ua->send_msg("Used\n");
1093 ua->send_msg("Recycle\n");
1094 ua->send_msg("Purged\n");
1095 ua->send_msg("Cleaning\n");
1096 ua->send_msg("Error\n");
1101 * Return default values for a job
1103 static bool defaultscmd(UAContext *ua, const char *cmd)
1111 if (ua->argc != 2 || !ua->argv[1]) {
1116 if (strcmp(ua->argk[1], "job") == 0) {
1117 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1120 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1123 ua->send_msg("job=%s", job->name());
1124 ua->send_msg("pool=%s", job->pool->name());
1125 ua->send_msg("messages=%s", job->messages->name());
1126 ua->send_msg("client=%s", job->client->name());
1127 get_job_storage(&store, job, NULL);
1128 ua->send_msg("storage=%s", store.store->name());
1129 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1130 ua->send_msg("level=%s", level_to_str(job->JobLevel));
1131 ua->send_msg("type=%s", job_type_to_str(job->JobType));
1132 ua->send_msg("fileset=%s", job->fileset->name());
1133 ua->send_msg("enabled=%d", job->enabled);
1134 ua->send_msg("catalog=%s", job->client->catalog->name());
1137 /* Client defaults */
1138 else if (strcmp(ua->argk[1], "client") == 0) {
1139 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1142 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1144 ua->send_msg("client=%s", client->name());
1145 ua->send_msg("address=%s", client->address);
1146 ua->send_msg("fdport=%d", client->FDport);
1147 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1148 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1149 ua->send_msg("autoprune=%d", client->AutoPrune);
1150 ua->send_msg("catalog=%s", client->catalog->name());
1153 /* Storage defaults */
1154 else if (strcmp(ua->argk[1], "storage") == 0) {
1155 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1158 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1161 ua->send_msg("storage=%s", storage->name());
1162 ua->send_msg("address=%s", storage->address);
1163 ua->send_msg("enabled=%d", storage->enabled);
1164 ua->send_msg("media_type=%s", storage->media_type);
1165 ua->send_msg("sdport=%d", storage->SDport);
1166 device = (DEVICE *)storage->device->first();
1167 ua->send_msg("device=%s", device->name());
1168 if (storage->device->size() > 1) {
1169 while ((device = (DEVICE *)storage->device->next())) {
1170 ua->send_msg(",%s", device->name());
1176 else if (strcmp(ua->argk[1], "pool") == 0) {
1177 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1180 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1182 ua->send_msg("pool=%s", pool->name());
1183 ua->send_msg("pool_type=%s", pool->pool_type);
1184 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1185 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1186 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1187 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1188 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1189 ua->send_msg("max_volumes=%d", pool->max_volumes);
1190 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1191 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1192 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1193 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1194 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1195 ua->send_msg("auto_prune=%d", pool->AutoPrune);
1196 ua->send_msg("recycle=%d", pool->Recycle);
1197 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1198 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));