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");
211 ua->error_msg("Can't find 'yes' argument\n");
218 static int bvfs_result_handler(void *ctx, int fields, char **row)
220 UAContext *ua = (UAContext *)ctx;
223 char *fileid=row[BVFS_FileId];
224 char *lstat=row[BVFS_LStat];
225 char *jobid=row[BVFS_JobId];
227 char empty[] = "A A A A A A A A A A A A A A";
230 /* We need to deal with non existant path */
231 if (!fileid || !is_a_number(fileid)) {
237 memset(&statp, 0, sizeof(struct stat));
238 decode_stat(lstat, &statp, sizeof(statp), &LinkFI);
240 Dmsg1(100, "type=%s\n", row[0]);
241 if (bvfs_is_dir(row)) {
242 char *path = bvfs_basename_dir(row[BVFS_Name]);
243 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
246 } else if (bvfs_is_version(row)) {
247 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
248 row[BVFS_FilenameId], fileid, jobid,
249 lstat, row[BVFS_Md5], row[BVFS_VolName],
250 row[BVFS_VolInchanger]);
252 } else if (bvfs_is_file(row)) {
253 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
254 row[BVFS_FilenameId], fileid, jobid,
255 lstat, row[BVFS_Name]);
261 static bool bvfs_parse_arg_version(UAContext *ua,
272 for (int i=1; i<ua->argc; i++) {
273 if (fnid && strcasecmp(ua->argk[i], NT_("fnid")) == 0) {
274 if (is_a_number(ua->argv[i])) {
275 *fnid = str_to_int64(ua->argv[i]);
279 if (strcasecmp(ua->argk[i], NT_("client")) == 0) {
280 *client = ua->argv[i];
283 if (copies && strcasecmp(ua->argk[i], NT_("copies")) == 0) {
287 if (versions && strcasecmp(ua->argk[i], NT_("versions")) == 0) {
291 return (*client && *fnid > 0);
294 static bool bvfs_parse_arg(UAContext *ua,
295 DBId_t *pathid, char **path, char **jobid,
297 int *limit, int *offset)
306 for (int i=1; i<ua->argc; i++) {
307 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
308 if (is_a_number(ua->argv[i])) {
309 *pathid = str_to_int64(ua->argv[i]);
313 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
317 if (strcasecmp(ua->argk[i], NT_("username")) == 0) {
318 *username = ua->argv[i];
321 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
322 if (is_a_number_list(ua->argv[i])) {
323 *jobid = ua->argv[i];
327 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
328 if (is_a_number(ua->argv[i])) {
329 *limit = str_to_int64(ua->argv[i]);
333 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
334 if (is_a_number(ua->argv[i])) {
335 *offset = str_to_int64(ua->argv[i]);
340 if (!((*pathid || *path) && *jobid)) {
344 if (!open_client_db(ua)) {
351 /* .bvfs_cleanup path=b2XXXXX
353 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
356 if ((i = find_arg_with_value(ua, "path")) >= 0) {
358 Bvfs fs(ua->jcr, ua->db);
359 fs.drop_restore_list(ua->argv[i]);
364 /* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
366 static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
369 int limit=2000, offset=0, i;
370 char *path=NULL, *jobid=NULL, *username=NULL;
371 char *empty = (char *)"";
372 char *fileid, *dirid, *hardlink;
373 fileid = dirid = hardlink = empty;
375 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
378 ua->error_msg("Can't find jobid, pathid or path argument\n");
379 return true; /* not enough param */
382 Bvfs fs(ua->jcr, ua->db);
383 fs.set_username(username);
384 fs.set_jobids(jobid);
386 if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
387 fileid = ua->argv[i];
389 if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
392 if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
393 hardlink = ua->argv[i];
396 if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
397 ua->send_msg("OK\n");
399 ua->error_msg("Can't create restore list\n");
405 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
406 * .bvfs_lsfiles jobid=1,2,3,4 path=/
408 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
411 int limit=2000, offset=0;
412 char *path=NULL, *jobid=NULL, *username=NULL;
416 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
419 ua->error_msg("Can't find jobid, pathid or path argument\n");
420 return true; /* not enough param */
422 if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
423 pattern = ua->argv[i];
426 Bvfs fs(ua->jcr, ua->db);
427 fs.set_username(username);
428 fs.set_jobids(jobid);
429 fs.set_handler(bvfs_result_handler, ua);
432 fs.set_pattern(pattern);
440 fs.set_offset(offset);
448 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
449 * .bvfs_lsdirs jobid=1,2,3,4 path=/
450 * .bvfs_lsdirs jobid=1,2,3,4 path=
452 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
455 int limit=2000, offset=0;
456 char *path=NULL, *jobid=NULL, *username=NULL;
458 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
461 ua->error_msg("Can't find jobid, pathid or path argument\n");
462 return true; /* not enough param */
465 Bvfs fs(ua->jcr, ua->db);
466 fs.set_username(username);
467 fs.set_jobids(jobid);
469 fs.set_handler(bvfs_result_handler, ua);
477 fs.set_offset(offset);
479 fs.ls_special_dirs();
486 * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
489 static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
491 DBId_t pathid=0, fnid=0;
492 int limit=2000, offset=0;
493 char *path=NULL, *jobid=NULL, *client=NULL, *username=NULL;
494 bool copies=false, versions=false;
495 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
498 ua->error_msg("Can't find jobid, pathid or path argument\n");
499 return true; /* not enough param */
502 if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
504 ua->error_msg("Can't find client or fnid argument\n");
505 return true; /* not enough param */
508 Bvfs fs(ua->jcr, ua->db);
510 fs.set_see_all_versions(versions);
511 fs.set_see_copies(copies);
512 fs.set_handler(bvfs_result_handler, ua);
513 fs.set_offset(offset);
514 fs.get_all_file_versions(pathid, fnid, client);
519 /* .bvfs_get_jobids jobid=1
520 * -> returns needed jobids to restore
521 * .bvfs_get_jobids jobid=1 all
522 * -> returns needed jobids to restore with all filesets a JobId=1 time
524 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
527 db_list_ctx jobids, tempids;
531 dbid_list ids; /* Store all FileSetIds for this client */
533 if (!open_client_db(ua)) {
537 memset(&jr, 0, sizeof(JOB_DBR));
538 if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
539 jr.JobId = str_to_int64(ua->argv[pos]);
542 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
543 ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
544 ua->cmd, db_strerror(ua->db));
548 /* When in level base, we don't rely on any Full/Incr/Diff */
549 if (jr.JobLevel == L_BASE) {
550 ua->send_msg("%s\n", edit_int64(jr.JobId, ed1));
554 /* If we have the "all" option, we do a search on all defined fileset
557 if (find_arg(ua, "all") > 0) {
558 edit_int64(jr.ClientId, ed1);
559 Mmsg(query, uar_sel_filesetid, ed1);
560 db_get_query_dbids(ua->jcr, ua->db, query, ids);
563 ids.DBId[0] = jr.FileSetId;
566 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
568 /* Foreach different FileSet, we build a restore jobid list */
569 for (int i=0; i < ids.num_ids; i++) {
570 jr.FileSetId = ids.DBId[i];
571 if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
577 ua->send_msg("%s\n", jobids.list);
581 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
587 static bool dot_help_cmd(UAContext *ua, const char *cmd)
593 static bool getmsgscmd(UAContext *ua, const char *cmd)
595 if (console_msg_pending) {
596 do_messages(ua, cmd);
602 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
608 lstore.store = store;
609 pm_strcpy(lstore.store_source, _("unknown source"));
610 set_wstorage(jcr, &lstore);
611 /* Try connecting for up to 15 seconds */
612 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
613 store->name(), store->address, store->SDport);
614 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
615 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
618 Dmsg0(120, _("Connected to storage daemon\n"));
619 sd = jcr->store_bsock;
620 sd->fsend("%s", cmd);
621 if (sd->recv() >= 0) {
622 ua->send_msg("%s", sd->msg);
624 sd->signal(BNET_TERMINATE);
626 jcr->store_bsock = NULL;
630 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
634 /* Connect to File daemon */
636 ua->jcr->client = client;
637 /* Try to connect for 15 seconds */
638 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
639 client->name(), client->address, client->FDport);
640 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
641 ua->error_msg(_("Failed to connect to Client.\n"));
644 Dmsg0(120, "Connected to file daemon\n");
645 fd = ua->jcr->file_bsock;
646 fd->fsend("%s", cmd);
647 if (fd->recv() >= 0) {
648 ua->send_msg("%s", fd->msg);
650 fd->signal(BNET_TERMINATE);
652 ua->jcr->file_bsock = NULL;
659 * .exit (no arg => .quit)
661 static bool admin_cmds(UAContext *ua, const char *cmd)
663 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
667 bool do_deadlock=false;
668 const char *remote_cmd;
672 if (strncmp(ua->argk[0], ".die", 4) == 0) {
673 if (find_arg(ua, "deadlock") > 0) {
675 remote_cmd = ".die deadlock";
679 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
680 remote_cmd = "sm_dump";
681 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
684 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
688 for (i=1; i<ua->argc; i++) {
689 if (strcasecmp(ua->argk[i], "dir") == 0 ||
690 strcasecmp(ua->argk[i], "director") == 0) {
693 if (strcasecmp(ua->argk[i], "client") == 0 ||
694 strcasecmp(ua->argk[i], "fd") == 0) {
697 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
700 client = select_client_resource(ua);
704 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
705 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
706 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
709 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
712 store = get_storage_resource(ua, false/*no default*/);
717 if (!dir && !store && !client) {
719 * We didn't find an appropriate keyword above, so
722 start_prompt(ua, _("Available daemons are: \n"));
723 add_prompt(ua, _("Director"));
724 add_prompt(ua, _("Storage"));
725 add_prompt(ua, _("Client"));
726 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
727 case 0: /* Director */
731 store = get_storage_resource(ua, false/*no default*/);
734 client = select_client_resource(ua);
742 do_storage_cmd(ua, store, remote_cmd);
746 do_client_cmd(ua, client, remote_cmd);
750 if (strncmp(remote_cmd, ".die", 4) == 0) {
752 ua->send_msg(_("The Director will generate a deadlock.\n"));
756 ua->send_msg(_("The Director will segment fault.\n"));
757 a = jcr->JobId; /* ref NULL pointer */
758 jcr->JobId = 1000; /* another ref NULL pointer */
761 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
762 sm_dump(false, true);
763 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
764 dot_quit_cmd(ua, cmd);
774 * Dummy routine for non-development version
776 static bool admin_cmds(UAContext *ua, const char *cmd)
778 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
785 * Can use an argument to filter on JobType
788 static bool jobscmd(UAContext *ua, const char *cmd)
793 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
794 type = ua->argv[pos][0];
797 foreach_res(job, R_JOB) {
798 if (!type || type == job->JobType) {
799 if (acl_access_ok(ua, Job_ACL, job->name())) {
800 ua->send_msg("%s\n", job->name());
808 static bool filesetscmd(UAContext *ua, const char *cmd)
812 foreach_res(fs, R_FILESET) {
813 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
814 ua->send_msg("%s\n", fs->name());
821 static bool catalogscmd(UAContext *ua, const char *cmd)
825 foreach_res(cat, R_CATALOG) {
826 if (acl_access_ok(ua, Catalog_ACL, cat->name())) {
827 ua->send_msg("%s\n", cat->name());
834 static bool clientscmd(UAContext *ua, const char *cmd)
838 foreach_res(client, R_CLIENT) {
839 if (acl_access_ok(ua, Client_ACL, client->name())) {
840 ua->send_msg("%s\n", client->name());
847 static bool msgscmd(UAContext *ua, const char *cmd)
851 foreach_res(msgs, R_MSGS) {
852 ua->send_msg("%s\n", msgs->name());
858 static bool poolscmd(UAContext *ua, const char *cmd)
862 foreach_res(pool, R_POOL) {
863 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
864 ua->send_msg("%s\n", pool->name());
871 static bool storagecmd(UAContext *ua, const char *cmd)
875 foreach_res(store, R_STORAGE) {
876 if (acl_access_ok(ua, Storage_ACL, store->name())) {
877 ua->send_msg("%s\n", store->name());
884 static bool aopcmd(UAContext *ua, const char *cmd)
886 ua->send_msg("None\n");
887 ua->send_msg("Truncate\n");
891 static bool typescmd(UAContext *ua, const char *cmd)
893 ua->send_msg("Backup\n");
894 ua->send_msg("Restore\n");
895 ua->send_msg("Admin\n");
896 ua->send_msg("Verify\n");
897 ua->send_msg("Migrate\n");
898 ua->send_msg("Copy\n");
903 * If this command is called, it tells the director that we
904 * are a program that wants a sort of API, and hence,
905 * we will probably suppress certain output, include more
906 * error codes, and most of all send back a good number
907 * of new signals that indicate whether or not the command
910 static bool api_cmd(UAContext *ua, const char *cmd)
913 ua->api = atoi(ua->argk[1]);
920 static int client_backups_handler(void *ctx, int num_field, char **row)
922 UAContext *ua = (UAContext *)ctx;
923 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
924 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
929 * Return the backups for this client
931 * .backups client=xxx fileset=yyy
934 static bool backupscmd(UAContext *ua, const char *cmd)
936 if (!open_client_db(ua)) {
939 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
940 strcmp(ua->argk[2], "fileset") != 0) {
943 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
944 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
945 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
948 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
949 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
950 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
956 static int sql_handler(void *ctx, int num_field, char **row)
958 UAContext *ua = (UAContext *)ctx;
959 POOL_MEM rows(PM_MESSAGE);
961 /* Check for nonsense */
962 if (num_field == 0 || row == NULL || row[0] == NULL) {
963 return 0; /* nothing returned */
965 for (int i=0; num_field--; i++) {
967 pm_strcpy(rows, NPRT(row[0]));
969 pm_strcat(rows, NPRT(row[i]));
971 pm_strcat(rows, "\t");
973 if (!rows.c_str() || !*rows.c_str()) {
976 ua->send_msg("%s", rows.c_str());
981 static bool sql_cmd(UAContext *ua, const char *cmd)
984 if (!open_client_db(ua)) {
987 index = find_arg_with_value(ua, "query");
989 ua->error_msg(_("query keyword not found.\n"));
992 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
993 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
994 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
1000 static int one_handler(void *ctx, int num_field, char **row)
1002 UAContext *ua = (UAContext *)ctx;
1003 ua->send_msg("%s\n", row[0]);
1007 static bool mediatypescmd(UAContext *ua, const char *cmd)
1009 if (!open_client_db(ua)) {
1012 if (!db_sql_query(ua->db,
1013 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
1014 one_handler, (void *)ua))
1016 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
1021 static bool mediacmd(UAContext *ua, const char *cmd)
1023 if (!open_client_db(ua)) {
1026 if (!db_sql_query(ua->db,
1027 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
1028 one_handler, (void *)ua))
1030 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
1035 static bool locationscmd(UAContext *ua, const char *cmd)
1037 if (!open_client_db(ua)) {
1040 if (!db_sql_query(ua->db,
1041 "SELECT DISTINCT Location FROM Location ORDER BY Location",
1042 one_handler, (void *)ua))
1044 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
1049 static bool levelscmd(UAContext *ua, const char *cmd)
1052 /* Note some levels are blank, which means none is needed */
1053 if (ua->argc == 1) {
1054 for (i=0; joblevels[i].level_name; i++) {
1055 if (joblevels[i].level_name[0] != ' ') {
1056 ua->send_msg("%s\n", joblevels[i].level_name);
1059 } else if (ua->argc == 2) {
1061 /* Assume that first argument is the Job Type */
1062 for (i=0; jobtypes[i].type_name; i++) {
1063 if (strcasecmp(ua->argk[1], jobtypes[i].type_name) == 0) {
1064 jobtype = jobtypes[i].job_type;
1068 for (i=0; joblevels[i].level_name; i++) {
1069 if ((joblevels[i].job_type == jobtype) && (joblevels[i].level_name[0] != ' ')) {
1070 ua->send_msg("%s\n", joblevels[i].level_name);
1078 static bool volstatuscmd(UAContext *ua, const char *cmd)
1080 ua->send_msg("Append\n");
1081 ua->send_msg("Full\n");
1082 ua->send_msg("Used\n");
1083 ua->send_msg("Recycle\n");
1084 ua->send_msg("Purged\n");
1085 ua->send_msg("Cleaning\n");
1086 ua->send_msg("Error\n");
1091 * Return default values for a job
1093 static bool defaultscmd(UAContext *ua, const char *cmd)
1101 if (ua->argc != 2 || !ua->argv[1]) {
1106 if (strcmp(ua->argk[1], "job") == 0) {
1107 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1110 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1113 ua->send_msg("job=%s", job->name());
1114 ua->send_msg("pool=%s", job->pool->name());
1115 ua->send_msg("messages=%s", job->messages->name());
1116 ua->send_msg("client=%s", job->client->name());
1117 get_job_storage(&store, job, NULL);
1118 ua->send_msg("storage=%s", store.store->name());
1119 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1120 ua->send_msg("level=%s", level_to_str(job->JobLevel));
1121 ua->send_msg("type=%s", job_type_to_str(job->JobType));
1122 ua->send_msg("fileset=%s", job->fileset->name());
1123 ua->send_msg("enabled=%d", job->enabled);
1124 ua->send_msg("catalog=%s", job->client->catalog->name());
1127 /* Client defaults */
1128 else if (strcmp(ua->argk[1], "client") == 0) {
1129 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1132 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1134 ua->send_msg("client=%s", client->name());
1135 ua->send_msg("address=%s", client->address);
1136 ua->send_msg("fdport=%d", client->FDport);
1137 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1138 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1139 ua->send_msg("autoprune=%d", client->AutoPrune);
1140 ua->send_msg("catalog=%s", client->catalog->name());
1143 /* Storage defaults */
1144 else if (strcmp(ua->argk[1], "storage") == 0) {
1145 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1148 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1151 ua->send_msg("storage=%s", storage->name());
1152 ua->send_msg("address=%s", storage->address);
1153 ua->send_msg("enabled=%d", storage->enabled);
1154 ua->send_msg("media_type=%s", storage->media_type);
1155 ua->send_msg("sdport=%d", storage->SDport);
1156 device = (DEVICE *)storage->device->first();
1157 ua->send_msg("device=%s", device->name());
1158 if (storage->device->size() > 1) {
1159 while ((device = (DEVICE *)storage->device->next())) {
1160 ua->send_msg(",%s", device->name());
1166 else if (strcmp(ua->argk[1], "pool") == 0) {
1167 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1170 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1172 ua->send_msg("pool=%s", pool->name());
1173 ua->send_msg("pool_type=%s", pool->pool_type);
1174 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1175 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1176 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1177 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1178 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1179 ua->send_msg("max_volumes=%d", pool->max_volumes);
1180 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1181 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1182 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1183 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1184 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1185 ua->send_msg("auto_prune=%d", pool->AutoPrune);
1186 ua->send_msg("recycle=%d", pool->Recycle);
1187 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1188 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));