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);
84 static bool api_cmd(UAContext *ua, const char *cmd);
85 static bool sql_cmd(UAContext *ua, const char *cmd);
86 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
87 static bool dot_help_cmd(UAContext *ua, const char *cmd);
88 static int one_handler(void *ctx, int num_field, char **row);
90 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;};
91 static struct cmdstruct commands[] = { /* help */ /* can be used in runscript */
92 { NT_(".api"), api_cmd, NULL, false},
93 { NT_(".backups"), backupscmd, NULL, false},
94 { NT_(".clients"), clientscmd, NULL, true},
95 { NT_(".catalogs"), catalogscmd, NULL, false},
96 { NT_(".defaults"), defaultscmd, NULL, false},
97 { NT_(".die"), admin_cmds, NULL, false},
98 { NT_(".dump"), admin_cmds, NULL, false},
99 { NT_(".exit"), admin_cmds, NULL, false},
100 { NT_(".filesets"), filesetscmd, NULL, false},
101 { NT_(".help"), dot_help_cmd, NULL, false},
102 { NT_(".jobs"), jobscmd, NULL, true},
103 { NT_(".levels"), levelscmd, NULL, false},
104 { NT_(".messages"), getmsgscmd, NULL, false},
105 { NT_(".msgs"), msgscmd, NULL, false},
106 { NT_(".pools"), poolscmd, NULL, true},
107 { NT_(".quit"), dot_quit_cmd, NULL, false},
108 { NT_(".sql"), sql_cmd, NULL, false},
109 { NT_(".status"), dot_status_cmd, NULL, false},
110 { NT_(".storage"), storagecmd, NULL, true},
111 { NT_(".volstatus"), volstatuscmd, NULL, true},
112 { NT_(".media"), mediacmd, NULL, true},
113 { NT_(".mediatypes"), mediatypescmd, NULL, true},
114 { NT_(".locations"), locationscmd, NULL, true},
115 { NT_(".actiononpurge"),aopcmd, NULL, true},
116 { NT_(".bvfs_lsdirs"), dot_bvfs_lsdirs, NULL, true},
117 { NT_(".bvfs_lsfiles"),dot_bvfs_lsfiles, NULL, true},
118 { NT_(".bvfs_update"), dot_bvfs_update, NULL, true},
119 { NT_(".bvfs_get_jobids"), dot_bvfs_get_jobids, NULL, true},
120 { NT_(".bvfs_versions"), dot_bvfs_versions, NULL, true},
121 { NT_(".bvfs_restore"), dot_bvfs_restore, NULL, true},
122 { NT_(".bvfs_cleanup"), dot_bvfs_cleanup, NULL, true},
123 { NT_(".types"), typescmd, NULL, false}
125 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
128 * Execute a command from the UA
130 bool do_a_dot_command(UAContext *ua)
136 BSOCK *user = ua->UA_sock;
138 Dmsg1(1400, "Dot command: %s\n", user->msg);
143 len = strlen(ua->argk[0]);
145 if (ua->api) user->signal(BNET_CMD_BEGIN);
146 if (ua->api) user->signal(BNET_CMD_OK);
147 return true; /* no op */
149 for (i=0; i<comsize; i++) { /* search for command */
150 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
151 /* Check if this command is authorized in RunScript */
152 if (ua->runscript && !commands[i].use_in_rs) {
153 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
157 /* Check if command permitted, but "quit" is always OK */
158 if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
159 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
162 Dmsg1(100, "Cmd: %s\n", ua->cmd);
164 if (ua->api) user->signal(BNET_CMD_BEGIN);
165 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
166 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
173 ua->error_msg("%s%s", ua->argk[0], _(": is an invalid command.\n"));
179 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
181 if (!open_new_client_db(ua)) {
185 int pos = find_arg_with_value(ua, "jobid");
186 if (pos != -1 && is_a_number_list(ua->argv[pos])) {
187 bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, ua->argv[pos]);
189 /* update cache for all jobids */
190 bvfs_update_cache(ua->jcr, ua->db);
197 static int bvfs_result_handler(void *ctx, int fields, char **row)
199 UAContext *ua = (UAContext *)ctx;
202 char *fileid=row[BVFS_FileId];
203 char *lstat=row[BVFS_LStat];
204 char *jobid=row[BVFS_JobId];
206 char empty[] = "A A A A A A A A A A A A A A";
209 /* We need to deal with non existant path */
210 if (!fileid || !is_a_number(fileid)) {
216 memset(&statp, 0, sizeof(struct stat));
217 decode_stat(lstat, &statp, sizeof(statp), &LinkFI);
219 Dmsg1(100, "type=%s\n", row[0]);
220 if (bvfs_is_dir(row)) {
221 char *path = bvfs_basename_dir(row[BVFS_Name]);
222 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
225 } else if (bvfs_is_version(row)) {
226 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
227 row[BVFS_FilenameId], fileid, jobid,
228 lstat, row[BVFS_Md5], row[BVFS_VolName],
229 row[BVFS_VolInchanger]);
231 } else if (bvfs_is_file(row)) {
232 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
233 row[BVFS_FilenameId], fileid, jobid,
234 lstat, row[BVFS_Name]);
240 static bool bvfs_parse_arg_version(UAContext *ua,
251 for (int i=1; i<ua->argc; i++) {
252 if (fnid && strcasecmp(ua->argk[i], NT_("fnid")) == 0) {
253 if (is_a_number(ua->argv[i])) {
254 *fnid = str_to_int64(ua->argv[i]);
258 if (strcasecmp(ua->argk[i], NT_("client")) == 0) {
259 *client = ua->argv[i];
262 if (copies && strcasecmp(ua->argk[i], NT_("copies")) == 0) {
266 if (versions && strcasecmp(ua->argk[i], NT_("versions")) == 0) {
270 return (*client && *fnid > 0);
273 static bool bvfs_parse_arg(UAContext *ua,
274 DBId_t *pathid, char **path, char **jobid,
276 int *limit, int *offset)
285 for (int i=1; i<ua->argc; i++) {
286 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
287 if (is_a_number(ua->argv[i])) {
288 *pathid = str_to_int64(ua->argv[i]);
292 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
296 if (strcasecmp(ua->argk[i], NT_("username")) == 0) {
297 *username = ua->argv[i];
300 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
301 if (is_a_number_list(ua->argv[i])) {
302 *jobid = ua->argv[i];
306 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
307 if (is_a_number(ua->argv[i])) {
308 *limit = str_to_int64(ua->argv[i]);
312 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
313 if (is_a_number(ua->argv[i])) {
314 *offset = str_to_int64(ua->argv[i]);
319 if (!((*pathid || *path) && *jobid)) {
323 if (!open_client_db(ua)) {
330 /* .bvfs_cleanup path=b2XXXXX
332 static bool dot_bvfs_cleanup(UAContext *ua, const char *cmd)
335 if ((i = find_arg_with_value(ua, "path")) >= 0) {
337 Bvfs fs(ua->jcr, ua->db);
338 fs.drop_restore_list(ua->argv[i]);
343 /* .bvfs_restore path=b2XXXXX jobid=1,2 fileid=1,2 dirid=1,2 hardlink=1,2,3,4
345 static bool dot_bvfs_restore(UAContext *ua, const char *cmd)
348 int limit=2000, offset=0, i;
349 char *path=NULL, *jobid=NULL, *username=NULL;
350 char *empty = (char *)"";
351 char *fileid, *dirid, *hardlink;
352 fileid = dirid = hardlink = empty;
354 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
357 ua->error_msg("Can't find jobid, pathid or path argument\n");
358 return true; /* not enough param */
361 Bvfs fs(ua->jcr, ua->db);
362 fs.set_username(username);
363 fs.set_jobids(jobid);
365 if ((i = find_arg_with_value(ua, "fileid")) >= 0) {
366 fileid = ua->argv[i];
368 if ((i = find_arg_with_value(ua, "dirid")) >= 0) {
371 if ((i = find_arg_with_value(ua, "hardlink")) >= 0) {
372 hardlink = ua->argv[i];
375 if (fs.compute_restore_list(fileid, dirid, hardlink, path)) {
376 ua->send_msg("OK\n");
378 ua->error_msg("Can't create restore list\n");
384 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
385 * .bvfs_lsfiles jobid=1,2,3,4 path=/
387 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
390 int limit=2000, offset=0;
391 char *path=NULL, *jobid=NULL, *username=NULL;
395 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
398 ua->error_msg("Can't find jobid, pathid or path argument\n");
399 return true; /* not enough param */
401 if ((i = find_arg_with_value(ua, "pattern")) >= 0) {
402 pattern = ua->argv[i];
405 Bvfs fs(ua->jcr, ua->db);
406 fs.set_username(username);
407 fs.set_jobids(jobid);
408 fs.set_handler(bvfs_result_handler, ua);
411 fs.set_pattern(pattern);
419 fs.set_offset(offset);
427 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
428 * .bvfs_lsdirs jobid=1,2,3,4 path=/
429 * .bvfs_lsdirs jobid=1,2,3,4 path=
431 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
434 int limit=2000, offset=0;
435 char *path=NULL, *jobid=NULL, *username=NULL;
437 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
440 ua->error_msg("Can't find jobid, pathid or path argument\n");
441 return true; /* not enough param */
444 Bvfs fs(ua->jcr, ua->db);
445 fs.set_username(username);
446 fs.set_jobids(jobid);
448 fs.set_handler(bvfs_result_handler, ua);
456 fs.set_offset(offset);
458 fs.ls_special_dirs();
465 * .bvfs_versions jobid=x fnid=10 pathid=10 copies versions
468 static bool dot_bvfs_versions(UAContext *ua, const char *cmd)
470 DBId_t pathid=0, fnid=0;
471 int limit=2000, offset=0;
472 char *path=NULL, *jobid=NULL, *client=NULL, *username=NULL;
473 bool copies=false, versions=false;
474 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid, &username,
477 ua->error_msg("Can't find jobid, pathid or path argument\n");
478 return true; /* not enough param */
481 if (!bvfs_parse_arg_version(ua, &client, &fnid, &versions, &copies))
483 ua->error_msg("Can't find client or fnid argument\n");
484 return true; /* not enough param */
487 Bvfs fs(ua->jcr, ua->db);
489 fs.set_see_all_versions(versions);
490 fs.set_see_copies(copies);
491 fs.set_handler(bvfs_result_handler, ua);
492 fs.set_offset(offset);
493 fs.get_all_file_versions(pathid, fnid, client);
498 /* .bvfs_get_jobids jobid=1
499 * -> returns needed jobids to restore
500 * .bvfs_get_jobids jobid=1 all
501 * -> returns needed jobids to restore with all filesets a JobId=1 time
503 static bool dot_bvfs_get_jobids(UAContext *ua, const char *cmd)
506 db_list_ctx jobids, tempids;
510 dbid_list ids; /* Store all FileSetIds for this client */
512 if (!open_client_db(ua)) {
516 memset(&jr, 0, sizeof(JOB_DBR));
517 if ((pos = find_arg_with_value(ua, "jobid")) >= 0) {
518 jr.JobId = str_to_int64(ua->argv[pos]);
521 if (!db_get_job_record(ua->jcr, ua->db, &jr)) {
522 ua->error_msg(_("Unable to get Job record for JobId=%s: ERR=%s\n"),
523 ua->cmd, db_strerror(ua->db));
527 /* If we have the "all" option, we do a search on all defined fileset
530 if (find_arg(ua, "all") > 0) {
531 edit_int64(jr.ClientId, ed1);
532 Mmsg(query, uar_sel_filesetid, ed1);
533 db_get_query_dbids(ua->jcr, ua->db, query, ids);
536 ids.DBId[0] = jr.FileSetId;
539 jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
541 /* Foreach different FileSet, we build a restore jobid list */
542 for (int i=0; i < ids.num_ids; i++) {
543 jr.FileSetId = ids.DBId[i];
544 if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &tempids)) {
550 ua->send_msg("%s\n", jobids.list);
554 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
560 static bool dot_help_cmd(UAContext *ua, const char *cmd)
566 static bool getmsgscmd(UAContext *ua, const char *cmd)
568 if (console_msg_pending) {
569 do_messages(ua, cmd);
575 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
581 lstore.store = store;
582 pm_strcpy(lstore.store_source, _("unknown source"));
583 set_wstorage(jcr, &lstore);
584 /* Try connecting for up to 15 seconds */
585 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
586 store->name(), store->address, store->SDport);
587 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
588 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
591 Dmsg0(120, _("Connected to storage daemon\n"));
592 sd = jcr->store_bsock;
593 sd->fsend("%s", cmd);
594 if (sd->recv() >= 0) {
595 ua->send_msg("%s", sd->msg);
597 sd->signal(BNET_TERMINATE);
599 jcr->store_bsock = NULL;
603 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
607 /* Connect to File daemon */
609 ua->jcr->client = client;
610 /* Try to connect for 15 seconds */
611 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
612 client->name(), client->address, client->FDport);
613 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
614 ua->error_msg(_("Failed to connect to Client.\n"));
617 Dmsg0(120, "Connected to file daemon\n");
618 fd = ua->jcr->file_bsock;
619 fd->fsend("%s", cmd);
620 if (fd->recv() >= 0) {
621 ua->send_msg("%s", fd->msg);
623 fd->signal(BNET_TERMINATE);
625 ua->jcr->file_bsock = NULL;
632 * .exit (no arg => .quit)
634 static bool admin_cmds(UAContext *ua, const char *cmd)
636 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
640 bool do_deadlock=false;
641 const char *remote_cmd;
645 if (strncmp(ua->argk[0], ".die", 4) == 0) {
646 if (find_arg(ua, "deadlock") > 0) {
648 remote_cmd = ".die deadlock";
652 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
653 remote_cmd = "sm_dump";
654 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
657 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
661 for (i=1; i<ua->argc; i++) {
662 if (strcasecmp(ua->argk[i], "dir") == 0 ||
663 strcasecmp(ua->argk[i], "director") == 0) {
666 if (strcasecmp(ua->argk[i], "client") == 0 ||
667 strcasecmp(ua->argk[i], "fd") == 0) {
670 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
673 client = select_client_resource(ua);
677 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
678 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
679 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
682 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
685 store = get_storage_resource(ua, false/*no default*/);
690 if (!dir && !store && !client) {
692 * We didn't find an appropriate keyword above, so
695 start_prompt(ua, _("Available daemons are: \n"));
696 add_prompt(ua, _("Director"));
697 add_prompt(ua, _("Storage"));
698 add_prompt(ua, _("Client"));
699 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
700 case 0: /* Director */
704 store = get_storage_resource(ua, false/*no default*/);
707 client = select_client_resource(ua);
715 do_storage_cmd(ua, store, remote_cmd);
719 do_client_cmd(ua, client, remote_cmd);
723 if (strncmp(remote_cmd, ".die", 4) == 0) {
725 ua->send_msg(_("The Director will generate a deadlock.\n"));
729 ua->send_msg(_("The Director will segment fault.\n"));
730 a = jcr->JobId; /* ref NULL pointer */
731 jcr->JobId = 1000; /* another ref NULL pointer */
733 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
734 sm_dump(false, true);
735 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
736 dot_quit_cmd(ua, cmd);
746 * Dummy routine for non-development version
748 static bool admin_cmds(UAContext *ua, const char *cmd)
750 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
757 * Can use an argument to filter on JobType
760 static bool jobscmd(UAContext *ua, const char *cmd)
765 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
766 type = ua->argv[pos][0];
769 foreach_res(job, R_JOB) {
770 if (!type || type == job->JobType) {
771 if (acl_access_ok(ua, Job_ACL, job->name())) {
772 ua->send_msg("%s\n", job->name());
780 static bool filesetscmd(UAContext *ua, const char *cmd)
784 foreach_res(fs, R_FILESET) {
785 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
786 ua->send_msg("%s\n", fs->name());
793 static bool catalogscmd(UAContext *ua, const char *cmd)
797 foreach_res(cat, R_CATALOG) {
798 if (acl_access_ok(ua, Catalog_ACL, cat->name())) {
799 ua->send_msg("%s\n", cat->name());
806 static bool clientscmd(UAContext *ua, const char *cmd)
810 foreach_res(client, R_CLIENT) {
811 if (acl_access_ok(ua, Client_ACL, client->name())) {
812 ua->send_msg("%s\n", client->name());
819 static bool msgscmd(UAContext *ua, const char *cmd)
823 foreach_res(msgs, R_MSGS) {
824 ua->send_msg("%s\n", msgs->name());
830 static bool poolscmd(UAContext *ua, const char *cmd)
834 foreach_res(pool, R_POOL) {
835 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
836 ua->send_msg("%s\n", pool->name());
843 static bool storagecmd(UAContext *ua, const char *cmd)
847 foreach_res(store, R_STORAGE) {
848 if (acl_access_ok(ua, Storage_ACL, store->name())) {
849 ua->send_msg("%s\n", store->name());
856 static bool aopcmd(UAContext *ua, const char *cmd)
858 ua->send_msg("None\n");
859 ua->send_msg("Truncate\n");
863 static bool typescmd(UAContext *ua, const char *cmd)
865 ua->send_msg("Backup\n");
866 ua->send_msg("Restore\n");
867 ua->send_msg("Admin\n");
868 ua->send_msg("Verify\n");
869 ua->send_msg("Migrate\n");
870 ua->send_msg("Copy\n");
875 * If this command is called, it tells the director that we
876 * are a program that wants a sort of API, and hence,
877 * we will probably suppress certain output, include more
878 * error codes, and most of all send back a good number
879 * of new signals that indicate whether or not the command
882 static bool api_cmd(UAContext *ua, const char *cmd)
885 ua->api = atoi(ua->argk[1]);
892 static int client_backups_handler(void *ctx, int num_field, char **row)
894 UAContext *ua = (UAContext *)ctx;
895 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
896 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
901 * Return the backups for this client
903 * .backups client=xxx fileset=yyy
906 static bool backupscmd(UAContext *ua, const char *cmd)
908 if (!open_client_db(ua)) {
911 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
912 strcmp(ua->argk[2], "fileset") != 0) {
915 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
916 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
917 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
920 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
921 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
922 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
928 static int sql_handler(void *ctx, int num_field, char **row)
930 UAContext *ua = (UAContext *)ctx;
931 POOL_MEM rows(PM_MESSAGE);
933 /* Check for nonsense */
934 if (num_field == 0 || row == NULL || row[0] == NULL) {
935 return 0; /* nothing returned */
937 for (int i=0; num_field--; i++) {
939 pm_strcpy(rows, NPRT(row[0]));
941 pm_strcat(rows, NPRT(row[i]));
943 pm_strcat(rows, "\t");
945 if (!rows.c_str() || !*rows.c_str()) {
948 ua->send_msg("%s", rows.c_str());
953 static bool sql_cmd(UAContext *ua, const char *cmd)
956 if (!open_client_db(ua)) {
959 index = find_arg_with_value(ua, "query");
961 ua->error_msg(_("query keyword not found.\n"));
964 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
965 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
966 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
972 static int one_handler(void *ctx, int num_field, char **row)
974 UAContext *ua = (UAContext *)ctx;
975 ua->send_msg("%s\n", row[0]);
979 static bool mediatypescmd(UAContext *ua, const char *cmd)
981 if (!open_client_db(ua)) {
984 if (!db_sql_query(ua->db,
985 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
986 one_handler, (void *)ua))
988 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
993 static bool mediacmd(UAContext *ua, const char *cmd)
995 if (!open_client_db(ua)) {
998 if (!db_sql_query(ua->db,
999 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
1000 one_handler, (void *)ua))
1002 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
1007 static bool locationscmd(UAContext *ua, const char *cmd)
1009 if (!open_client_db(ua)) {
1012 if (!db_sql_query(ua->db,
1013 "SELECT DISTINCT Location FROM Location ORDER BY Location",
1014 one_handler, (void *)ua))
1016 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
1021 static bool levelscmd(UAContext *ua, const char *cmd)
1024 /* Note some levels are blank, which means none is needed */
1025 if (ua->argc == 1) {
1026 for (i=0; joblevels[i].level_name; i++) {
1027 if (joblevels[i].level_name[0] != ' ') {
1028 ua->send_msg("%s\n", joblevels[i].level_name);
1031 } else if (ua->argc == 2) {
1033 /* Assume that first argument is the Job Type */
1034 for (i=0; jobtypes[i].type_name; i++) {
1035 if (strcasecmp(ua->argk[1], jobtypes[i].type_name) == 0) {
1036 jobtype = jobtypes[i].job_type;
1040 for (i=0; joblevels[i].level_name; i++) {
1041 if ((joblevels[i].job_type == jobtype) && (joblevels[i].level_name[0] != ' ')) {
1042 ua->send_msg("%s\n", joblevels[i].level_name);
1050 static bool volstatuscmd(UAContext *ua, const char *cmd)
1052 ua->send_msg("Append\n");
1053 ua->send_msg("Full\n");
1054 ua->send_msg("Used\n");
1055 ua->send_msg("Recycle\n");
1056 ua->send_msg("Purged\n");
1057 ua->send_msg("Cleaning\n");
1058 ua->send_msg("Error\n");
1063 * Return default values for a job
1065 static bool defaultscmd(UAContext *ua, const char *cmd)
1073 if (ua->argc != 2 || !ua->argv[1]) {
1078 if (strcmp(ua->argk[1], "job") == 0) {
1079 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
1082 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
1085 ua->send_msg("job=%s", job->name());
1086 ua->send_msg("pool=%s", job->pool->name());
1087 ua->send_msg("messages=%s", job->messages->name());
1088 ua->send_msg("client=%s", job->client->name());
1089 get_job_storage(&store, job, NULL);
1090 ua->send_msg("storage=%s", store.store->name());
1091 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
1092 ua->send_msg("level=%s", level_to_str(job->JobLevel));
1093 ua->send_msg("type=%s", job_type_to_str(job->JobType));
1094 ua->send_msg("fileset=%s", job->fileset->name());
1095 ua->send_msg("enabled=%d", job->enabled);
1096 ua->send_msg("catalog=%s", job->client->catalog->name());
1099 /* Client defaults */
1100 else if (strcmp(ua->argk[1], "client") == 0) {
1101 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
1104 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
1106 ua->send_msg("client=%s", client->name());
1107 ua->send_msg("address=%s", client->address);
1108 ua->send_msg("fdport=%d", client->FDport);
1109 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
1110 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
1111 ua->send_msg("autoprune=%d", client->AutoPrune);
1112 ua->send_msg("catalog=%s", client->catalog->name());
1115 /* Storage defaults */
1116 else if (strcmp(ua->argk[1], "storage") == 0) {
1117 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
1120 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
1123 ua->send_msg("storage=%s", storage->name());
1124 ua->send_msg("address=%s", storage->address);
1125 ua->send_msg("enabled=%d", storage->enabled);
1126 ua->send_msg("media_type=%s", storage->media_type);
1127 ua->send_msg("sdport=%d", storage->SDport);
1128 device = (DEVICE *)storage->device->first();
1129 ua->send_msg("device=%s", device->name());
1130 if (storage->device->size() > 1) {
1131 while ((device = (DEVICE *)storage->device->next())) {
1132 ua->send_msg(",%s", device->name());
1138 else if (strcmp(ua->argk[1], "pool") == 0) {
1139 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
1142 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
1144 ua->send_msg("pool=%s", pool->name());
1145 ua->send_msg("pool_type=%s", pool->pool_type);
1146 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
1147 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
1148 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
1149 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
1150 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
1151 ua->send_msg("max_volumes=%d", pool->max_volumes);
1152 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
1153 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
1154 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
1155 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
1156 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
1157 ua->send_msg("auto_prune=%d", pool->AutoPrune);
1158 ua->send_msg("recycle=%d", pool->Recycle);
1159 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
1160 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));