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
527 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
530 db_list_ctx jobids, tempids;
534 dbid_list ids; /* Store all FileSetIds for this client */
536 if (!open_client_db(ua)) {
540 memset(&jr, 0, sizeof(JOB_DBR));
541 if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
542 jr.JobId = str_to_int64(ua->argv[pos]);
545 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
546 ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
547 ua->cmd, db_strerror(ua->db));
551 /* When in level base, we don't rely on any Full/Incr/Diff */
552 if (jr.JobLevel == L_BASE) {
553 ua->send_msg("%s\n", edit_int64(jr.JobId, ed1));
557 /* If we have the "all" option, we do a search on all defined fileset
560 if (find_arg(ua, "all") > 0) {
561 edit_int64(jr.ClientId, ed1);
562 Mmsg(query, uar_sel_filesetid, ed1);
563 db_get_query_dbids(ua->jcr, ua->db, query, ids);
566 ids.DBId[0] = jr.FileSetId;
569 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
571 /* Foreach different FileSet, we build a restore jobid list */
572 for (int i=0; i < ids.num_ids; i++) {
573 jr.FileSetId = ids.DBId[i];
574 if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
580 ua->send_msg("%s\n", jobids.list);
584 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
590 static bool dot_help_cmd(UAContext *ua, const char *cmd)
596 static bool getmsgscmd(UAContext *ua, const char *cmd)
598 if (console_msg_pending) {
599 do_messages(ua, cmd);
605 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
611 lstore.store = store;
612 pm_strcpy(lstore.store_source, _("unknown source"));
613 set_wstorage(jcr, &lstore);
614 /* Try connecting for up to 15 seconds */
615 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
616 store->name(), store->address, store->SDport);
617 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
618 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
621 Dmsg0(120, _("Connected to storage daemon\n"));
622 sd = jcr->store_bsock;
623 sd->fsend("%s", cmd);
624 if (sd->recv() >= 0) {
625 ua->send_msg("%s", sd->msg);
627 sd->signal(BNET_TERMINATE);
629 jcr->store_bsock = NULL;
633 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
637 /* Connect to File daemon */
639 ua->jcr->client = client;
640 /* Try to connect for 15 seconds */
641 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
642 client->name(), client->address, client->FDport);
643 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
644 ua->error_msg(_("Failed to connect to Client.\n"));
647 Dmsg0(120, "Connected to file daemon\n");
648 fd = ua->jcr->file_bsock;
649 fd->fsend("%s", cmd);
650 if (fd->recv() >= 0) {
651 ua->send_msg("%s", fd->msg);
653 fd->signal(BNET_TERMINATE);
655 ua->jcr->file_bsock = NULL;
662 * .exit (no arg => .quit)
664 static bool admin_cmds(UAContext *ua, const char *cmd)
666 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
670 bool do_deadlock=false;
671 const char *remote_cmd;
675 if (strncmp(ua->argk[0], ".die", 4) == 0) {
676 if (find_arg(ua, "deadlock") > 0) {
678 remote_cmd = ".die deadlock";
682 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
683 remote_cmd = "sm_dump";
684 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
687 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
691 for (i=1; i<ua->argc; i++) {
692 if (strcasecmp(ua->argk[i], "dir") == 0 ||
693 strcasecmp(ua->argk[i], "director") == 0) {
696 if (strcasecmp(ua->argk[i], "client") == 0 ||
697 strcasecmp(ua->argk[i], "fd") == 0) {
700 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
703 client = select_client_resource(ua);
707 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
708 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
709 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
712 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
715 store = get_storage_resource(ua, false/*no default*/);
720 if (!dir && !store && !client) {
722 * We didn't find an appropriate keyword above, so
725 start_prompt(ua, _("Available daemons are: \n"));
726 add_prompt(ua, _("Director"));
727 add_prompt(ua, _("Storage"));
728 add_prompt(ua, _("Client"));
729 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
730 case 0: /* Director */
734 store = get_storage_resource(ua, false/*no default*/);
737 client = select_client_resource(ua);
745 do_storage_cmd(ua, store, remote_cmd);
749 do_client_cmd(ua, client, remote_cmd);
753 if (strncmp(remote_cmd, ".die", 4) == 0) {
755 ua->send_msg(_("The Director will generate a deadlock.\n"));
759 ua->send_msg(_("The Director will segment fault.\n"));
760 a = jcr->JobId; /* ref NULL pointer */
761 jcr->JobId = 1000; /* another ref NULL pointer */
764 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
765 sm_dump(false, true);
766 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
767 dot_quit_cmd(ua, cmd);
777 * Dummy routine for non-development version
779 static bool admin_cmds(UAContext *ua, const char *cmd)
781 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
788 * Can use an argument to filter on JobType
791 static bool jobscmd(UAContext *ua, const char *cmd)
796 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
797 type = ua->argv[pos][0];
800 foreach_res(job, R_JOB) {
801 if (!type || type == job->JobType) {
802 if (acl_access_ok(ua, Job_ACL, job->name())) {
803 ua->send_msg("%s\n", job->name());
811 static bool filesetscmd(UAContext *ua, const char *cmd)
815 foreach_res(fs, R_FILESET) {
816 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
817 ua->send_msg("%s\n", fs->name());
824 static bool catalogscmd(UAContext *ua, const char *cmd)
828 foreach_res(cat, R_CATALOG) {
829 if (acl_access_ok(ua, Catalog_ACL, cat->name())) {
830 ua->send_msg("%s\n", cat->name());
837 static bool clientscmd(UAContext *ua, const char *cmd)
841 foreach_res(client, R_CLIENT) {
842 if (acl_access_ok(ua, Client_ACL, client->name())) {
843 ua->send_msg("%s\n", client->name());
850 static bool msgscmd(UAContext *ua, const char *cmd)
854 foreach_res(msgs, R_MSGS) {
855 ua->send_msg("%s\n", msgs->name());
861 static bool poolscmd(UAContext *ua, const char *cmd)
865 foreach_res(pool, R_POOL) {
866 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
867 ua->send_msg("%s\n", pool->name());
874 static bool storagecmd(UAContext *ua, const char *cmd)
878 foreach_res(store, R_STORAGE) {
879 if (acl_access_ok(ua, Storage_ACL, store->name())) {
880 ua->send_msg("%s\n", store->name());
887 static bool aopcmd(UAContext *ua, const char *cmd)
889 ua->send_msg("None\n");
890 ua->send_msg("Truncate\n");
894 static bool typescmd(UAContext *ua, const char *cmd)
896 ua->send_msg("Backup\n");
897 ua->send_msg("Restore\n");
898 ua->send_msg("Admin\n");
899 ua->send_msg("Verify\n");
900 ua->send_msg("Migrate\n");
901 ua->send_msg("Copy\n");
906 * If this command is called, it tells the director that we
907 * are a program that wants a sort of API, and hence,
908 * we will probably suppress certain output, include more
909 * error codes, and most of all send back a good number
910 * of new signals that indicate whether or not the command
913 static bool api_cmd(UAContext *ua, const char *cmd)
916 ua->api = atoi(ua->argk[1]);
923 static int client_backups_handler(void *ctx, int num_field, char **row)
925 UAContext *ua = (UAContext *)ctx;
926 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
927 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
932 * Return the backups for this client
934 * .backups client=xxx fileset=yyy
937 static bool backupscmd(UAContext *ua, const char *cmd)
939 if (!open_client_db(ua)) {
942 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
943 strcmp(ua->argk[2], "fileset") != 0) {
946 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
947 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
948 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
951 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
952 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
953 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
959 static int sql_handler(void *ctx, int num_field, char **row)
961 UAContext *ua = (UAContext *)ctx;
962 POOL_MEM rows(PM_MESSAGE);
964 /* Check for nonsense */
965 if (num_field == 0 || row == NULL || row[0] == NULL) {
966 return 0; /* nothing returned */
968 for (int i=0; num_field--; i++) {
970 pm_strcpy(rows, NPRT(row[0]));
972 pm_strcat(rows, NPRT(row[i]));
974 pm_strcat(rows, "\t");
976 if (!rows.c_str() || !*rows.c_str()) {
979 ua->send_msg("%s", rows.c_str());
984 static bool sql_cmd(UAContext *ua, const char *cmd)
987 if (!open_client_db(ua)) {
990 index = find_arg_with_value(ua, "query");
992 ua->error_msg(_("query keyword not found.\n"));
995 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
996 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
997 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
1003 static int one_handler(void *ctx, int num_field, char **row)
1005 UAContext *ua = (UAContext *)ctx;
1006 ua->send_msg("%s\n", row[0]);
1010 static bool mediatypescmd(UAContext *ua, const char *cmd)
1012 if (!open_client_db(ua)) {
1015 if (!db_sql_query(ua->db,
1016 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
1017 one_handler, (void *)ua))
1019 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
1024 static bool mediacmd(UAContext *ua, const char *cmd)
1026 if (!open_client_db(ua)) {
1029 if (!db_sql_query(ua->db,
1030 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
1031 one_handler, (void *)ua))
1033 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
1038 static bool locationscmd(UAContext *ua, const char *cmd)
1040 if (!open_client_db(ua)) {
1043 if (!db_sql_query(ua->db,
1044 "SELECT DISTINCT Location FROM Location ORDER BY Location",
1045 one_handler, (void *)ua))
1047 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
1052 static bool levelscmd(UAContext *ua, const char *cmd)
1055 /* Note some levels are blank, which means none is needed */
1056 if (ua->argc == 1) {
1057 for (i=0; joblevels[i].level_name; i++) {
1058 if (joblevels[i].level_name[0] != ' ') {
1059 ua->send_msg("%s\n", joblevels[i].level_name);
1062 } else if (ua->argc == 2) {
1064 /* Assume that first argument is the Job Type */
1065 for (i=0; jobtypes[i].type_name; i++) {
1066 if (strcasecmp(ua->argk[1], jobtypes[i].type_name) == 0) {
1067 jobtype = jobtypes[i].job_type;
1071 for (i=0; joblevels[i].level_name; i++) {
1072 if ((joblevels[i].job_type == jobtype) && (joblevels[i].level_name[0] != ' ')) {
1073 ua->send_msg("%s\n", joblevels[i].level_name);
1081 static bool volstatuscmd(UAContext *ua, const char *cmd)
1083 ua->send_msg("Append\n");
1084 ua->send_msg("Full\n");
1085 ua->send_msg("Used\n");
1086 ua->send_msg("Recycle\n");
1087 ua->send_msg("Purged\n");
1088 ua->send_msg("Cleaning\n");
1089 ua->send_msg("Error\n");
1094 * Return default values for a job
1096 static bool defaultscmd(UAContext *ua, const char *cmd)
1104 if (ua->argc != 2 || !ua->argv[1]) {
1109 if (strcmp(ua->argk[1], "job") == 0) {
1110 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1113 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1116 ua->send_msg("job=%s", job->name());
1117 ua->send_msg("pool=%s", job->pool->name());
1118 ua->send_msg("messages=%s", job->messages->name());
1119 ua->send_msg("client=%s", job->client->name());
1120 get_job_storage(&store, job, NULL);
1121 ua->send_msg("storage=%s", store.store->name());
1122 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1123 ua->send_msg("level=%s", level_to_str(job->JobLevel));
1124 ua->send_msg("type=%s", job_type_to_str(job->JobType));
1125 ua->send_msg("fileset=%s", job->fileset->name());
1126 ua->send_msg("enabled=%d", job->enabled);
1127 ua->send_msg("catalog=%s", job->client->catalog->name());
1130 /* Client defaults */
1131 else if (strcmp(ua->argk[1], "client") == 0) {
1132 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1135 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1137 ua->send_msg("client=%s", client->name());
1138 ua->send_msg("address=%s", client->address);
1139 ua->send_msg("fdport=%d", client->FDport);
1140 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1141 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1142 ua->send_msg("autoprune=%d", client->AutoPrune);
1143 ua->send_msg("catalog=%s", client->catalog->name());
1146 /* Storage defaults */
1147 else if (strcmp(ua->argk[1], "storage") == 0) {
1148 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1151 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1154 ua->send_msg("storage=%s", storage->name());
1155 ua->send_msg("address=%s", storage->address);
1156 ua->send_msg("enabled=%d", storage->enabled);
1157 ua->send_msg("media_type=%s", storage->media_type);
1158 ua->send_msg("sdport=%d", storage->SDport);
1159 device = (DEVICE *)storage->device->first();
1160 ua->send_msg("device=%s", device->name());
1161 if (storage->device->size() > 1) {
1162 while ((device = (DEVICE *)storage->device->next())) {
1163 ua->send_msg(",%s", device->name());
1169 else if (strcmp(ua->argk[1], "pool") == 0) {
1170 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1173 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1175 ua->send_msg("pool=%s", pool->name());
1176 ua->send_msg("pool_type=%s", pool->pool_type);
1177 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1178 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1179 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1180 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1181 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1182 ua->send_msg("max_volumes=%d", pool->max_volumes);
1183 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1184 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1185 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1186 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1187 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1188 ua->send_msg("auto_prune=%d", pool->AutoPrune);
1189 ua->send_msg("recycle=%d", pool->Recycle);
1190 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1191 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));