2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2010 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 */
47 /* Imported functions */
48 extern void do_messages(UAContext *ua, const char *cmd);
49 extern int quit_cmd(UAContext *ua, const char *cmd);
50 extern int qhelp_cmd(UAContext *ua, const char *cmd);
51 extern bool dot_status_cmd(UAContext *ua, const char *cmd);
54 /* Forward referenced functions */
55 static bool admin_cmds(UAContext *ua, const char *cmd);
56 static bool jobscmd(UAContext *ua, const char *cmd);
57 static bool filesetscmd(UAContext *ua, const char *cmd);
58 static bool clientscmd(UAContext *ua, const char *cmd);
59 static bool msgscmd(UAContext *ua, const char *cmd);
60 static bool poolscmd(UAContext *ua, const char *cmd);
61 static bool storagecmd(UAContext *ua, const char *cmd);
62 static bool defaultscmd(UAContext *ua, const char *cmd);
63 static bool typescmd(UAContext *ua, const char *cmd);
64 static bool backupscmd(UAContext *ua, const char *cmd);
65 static bool levelscmd(UAContext *ua, const char *cmd);
66 static bool getmsgscmd(UAContext *ua, const char *cmd);
67 static bool volstatuscmd(UAContext *ua, const char *cmd);
68 static bool mediatypescmd(UAContext *ua, const char *cmd);
69 static bool locationscmd(UAContext *ua, const char *cmd);
70 static bool mediacmd(UAContext *ua, const char *cmd);
71 static bool aopcmd(UAContext *ua, const char *cmd);
73 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd);
74 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd);
75 static bool dot_bvfs_update(UAContext *ua, const char *cmd);
77 static bool api_cmd(UAContext *ua, const char *cmd);
78 static bool sql_cmd(UAContext *ua, const char *cmd);
79 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
80 static bool dot_help_cmd(UAContext *ua, const char *cmd);
82 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;};
83 static struct cmdstruct commands[] = { /* help */ /* can be used in runscript */
84 { NT_(".api"), api_cmd, NULL, false},
85 { NT_(".backups"), backupscmd, NULL, false},
86 { NT_(".clients"), clientscmd, NULL, true},
87 { NT_(".defaults"), defaultscmd, NULL, false},
88 { NT_(".die"), admin_cmds, NULL, false},
89 { NT_(".dump"), admin_cmds, NULL, false},
90 { NT_(".exit"), admin_cmds, NULL, false},
91 { NT_(".filesets"), filesetscmd, NULL, false},
92 { NT_(".help"), dot_help_cmd, NULL, false},
93 { NT_(".jobs"), jobscmd, NULL, true},
94 { NT_(".levels"), levelscmd, NULL, false},
95 { NT_(".messages"), getmsgscmd, NULL, false},
96 { NT_(".msgs"), msgscmd, NULL, false},
97 { NT_(".pools"), poolscmd, NULL, true},
98 { NT_(".quit"), dot_quit_cmd, NULL, false},
99 { NT_(".sql"), sql_cmd, NULL, false},
100 { NT_(".status"), dot_status_cmd, NULL, false},
101 { NT_(".storage"), storagecmd, NULL, true},
102 { NT_(".volstatus"), volstatuscmd, NULL, true},
103 { NT_(".media"), mediacmd, NULL, true},
104 { NT_(".mediatypes"), mediatypescmd, NULL, true},
105 { NT_(".locations"), locationscmd, NULL, true},
106 { NT_(".actiononpurge"),aopcmd, NULL, true},
107 { NT_(".bvfs_lsdirs"), dot_bvfs_lsdirs, NULL, true},
108 { NT_(".bvfs_lsfiles"),dot_bvfs_lsfiles,NULL, true},
109 { NT_(".bvfs_update"), dot_bvfs_update, NULL, true},
110 { NT_(".types"), typescmd, NULL, false}
112 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
115 * Execute a command from the UA
117 bool do_a_dot_command(UAContext *ua)
123 BSOCK *user = ua->UA_sock;
125 Dmsg1(1400, "Dot command: %s\n", user->msg);
130 len = strlen(ua->argk[0]);
132 if (ua->api) user->signal(BNET_CMD_BEGIN);
133 if (ua->api) user->signal(BNET_CMD_OK);
134 return true; /* no op */
136 for (i=0; i<comsize; i++) { /* search for command */
137 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
138 /* Check if this command is authorized in RunScript */
139 if (ua->runscript && !commands[i].use_in_rs) {
140 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
144 /* Check if command permitted, but "quit" is always OK */
145 if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
146 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
149 Dmsg1(100, "Cmd: %s\n", ua->cmd);
151 if (ua->api) user->signal(BNET_CMD_BEGIN);
152 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
153 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
160 pm_strcat(user->msg, _(": is an invalid command.\n"));
161 ua->error_msg("%s", user->msg);
167 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
169 if (!open_new_client_db(ua)) {
173 int pos = find_arg_with_value(ua, "jobid");
174 if (pos != -1 && is_a_number_list(ua->argv[pos])) {
176 pm_strcpy(jobids, ua->argv[pos]);
177 bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, jobids.c_str());
179 /* update cache for all jobids */
180 bvfs_update_cache(ua->jcr, ua->db);
187 static int bvfs_result_handler(void *ctx, int fields, char **row)
189 UAContext *ua = (UAContext *)ctx;
192 char *fileid=row[BVFS_FileId];
193 char *lstat=row[BVFS_LStat];
194 char *jobid=row[BVFS_JobId];
196 char empty[] = "A A A A A A A A A A A A A A";
199 /* We need to deal with non existant path */
200 if (!fileid || !is_a_number(fileid)) {
206 memset(&statp, 0, sizeof(struct stat));
207 decode_stat(lstat, &statp, &LinkFI);
209 Dmsg1(100, "type=%s\n", row[0]);
210 if (bvfs_is_dir(row)) {
211 char *path = bvfs_basename_dir(row[BVFS_Name]);
212 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
215 } else if (bvfs_is_file(row)) {
216 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
217 row[BVFS_FilenameId], fileid, jobid,
218 lstat, row[BVFS_Name]);
224 static bool bvfs_parse_arg(UAContext *ua,
225 DBId_t *pathid, char **path, char **jobid,
226 int *limit, int *offset)
234 for (int i=1; i<ua->argc; i++) {
235 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
236 if (is_a_number(ua->argv[i])) {
237 *pathid = str_to_int64(ua->argv[i]);
240 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
244 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
245 if (is_a_number_list(ua->argv[i])) {
246 *jobid = ua->argv[i];
250 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
251 if (is_a_number(ua->argv[i])) {
252 *limit = str_to_int64(ua->argv[i]);
256 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
257 if (is_a_number(ua->argv[i])) {
258 *offset = str_to_int64(ua->argv[i]);
263 if (!((*pathid || *path) && *jobid)) {
267 if (!open_client_db(ua)) {
275 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
276 * .bvfs_lsfiles jobid=1,2,3,4 path=/
278 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
281 int limit=2000, offset=0;
282 char *path=NULL, *jobid=NULL;
284 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
287 ua->error_msg("Can't find jobid, pathid or path argument\n");
288 return true; /* not enough param */
291 Bvfs fs(ua->jcr, ua->db);
292 fs.set_jobids(jobid);
293 fs.set_handler(bvfs_result_handler, ua);
302 fs.set_offset(offset);
310 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
311 * .bvfs_lsdirs jobid=1,2,3,4 path=/
312 * .bvfs_lsdirs jobid=1,2,3,4 path=
314 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
317 int limit=2000, offset=0;
318 char *path=NULL, *jobid=NULL;
320 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
323 ua->error_msg("Can't find jobid, pathid or path argument\n");
324 return true; /* not enough param */
327 Bvfs fs(ua->jcr, ua->db);
328 fs.set_jobids(jobid);
330 fs.set_handler(bvfs_result_handler, ua);
338 fs.set_offset(offset);
340 fs.ls_special_dirs();
346 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
352 static bool dot_help_cmd(UAContext *ua, const char *cmd)
358 static bool getmsgscmd(UAContext *ua, const char *cmd)
360 if (console_msg_pending) {
361 do_messages(ua, cmd);
367 static void do_storage_cmd(UAContext *ua, STORE *store, const char *cmd)
373 lstore.store = store;
374 pm_strcpy(lstore.store_source, _("unknown source"));
375 set_wstorage(jcr, &lstore);
376 /* Try connecting for up to 15 seconds */
377 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
378 store->name(), store->address, store->SDport);
379 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
380 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
383 Dmsg0(120, _("Connected to storage daemon\n"));
384 sd = jcr->store_bsock;
385 sd->fsend("%s", cmd);
386 if (sd->recv() >= 0) {
387 ua->send_msg("%s", sd->msg);
389 sd->signal(BNET_TERMINATE);
391 jcr->store_bsock = NULL;
395 static void do_client_cmd(UAContext *ua, CLIENT *client, const char *cmd)
399 /* Connect to File daemon */
401 ua->jcr->client = client;
402 /* Try to connect for 15 seconds */
403 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
404 client->name(), client->address, client->FDport);
405 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
406 ua->error_msg(_("Failed to connect to Client.\n"));
409 Dmsg0(120, "Connected to file daemon\n");
410 fd = ua->jcr->file_bsock;
411 fd->fsend("%s", cmd);
412 if (fd->recv() >= 0) {
413 ua->send_msg("%s", fd->msg);
415 fd->signal(BNET_TERMINATE);
417 ua->jcr->file_bsock = NULL;
424 * .exit (no arg => .quit)
426 static bool admin_cmds(UAContext *ua, const char *cmd)
428 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
432 bool do_deadlock=false;
433 const char *remote_cmd;
437 if (strncmp(ua->argk[0], ".die", 4) == 0) {
438 if (find_arg(ua, "deadlock") > 0) {
440 remote_cmd = ".die deadlock";
444 } else if (strncmp(ua->argk[0], ".dump", 5) == 0) {
445 remote_cmd = "sm_dump";
446 } else if (strncmp(ua->argk[0], ".exit", 5) == 0) {
449 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
453 for (i=1; i<ua->argc; i++) {
454 if (strcasecmp(ua->argk[i], "dir") == 0 ||
455 strcasecmp(ua->argk[i], "director") == 0) {
458 if (strcasecmp(ua->argk[i], "client") == 0 ||
459 strcasecmp(ua->argk[i], "fd") == 0) {
462 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
465 client = select_client_resource(ua);
469 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
470 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
471 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
474 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
477 store = get_storage_resource(ua, false/*no default*/);
482 if (!dir && !store && !client) {
484 * We didn't find an appropriate keyword above, so
487 start_prompt(ua, _("Available daemons are: \n"));
488 add_prompt(ua, _("Director"));
489 add_prompt(ua, _("Storage"));
490 add_prompt(ua, _("Client"));
491 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
492 case 0: /* Director */
496 store = get_storage_resource(ua, false/*no default*/);
499 client = select_client_resource(ua);
507 do_storage_cmd(ua, store, remote_cmd);
511 do_client_cmd(ua, client, remote_cmd);
515 if (strncmp(remote_cmd, ".die", 4) == 0) {
517 ua->send_msg(_("The Director will generate a deadlock.\n"));
521 ua->send_msg(_("The Director will segment fault.\n"));
522 a = jcr->JobId; /* ref NULL pointer */
523 jcr->JobId = 1000; /* another ref NULL pointer */
525 } else if (strncmp(remote_cmd, ".dump", 5) == 0) {
526 sm_dump(false, true);
527 } else if (strncmp(remote_cmd, ".exit", 5) == 0) {
528 dot_quit_cmd(ua, cmd);
538 * Dummy routine for non-development version
540 static bool admin_cmds(UAContext *ua, const char *cmd)
542 ua->error_msg(_("Unknown command: %s\n"), ua->argk[0]);
549 * Can use an argument to filter on JobType
552 static bool jobscmd(UAContext *ua, const char *cmd)
557 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
558 type = ua->argv[pos][0];
561 foreach_res(job, R_JOB) {
562 if (!type || type == job->JobType) {
563 if (acl_access_ok(ua, Job_ACL, job->name())) {
564 ua->send_msg("%s\n", job->name());
572 static bool filesetscmd(UAContext *ua, const char *cmd)
576 foreach_res(fs, R_FILESET) {
577 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
578 ua->send_msg("%s\n", fs->name());
585 static bool clientscmd(UAContext *ua, const char *cmd)
589 foreach_res(client, R_CLIENT) {
590 if (acl_access_ok(ua, Client_ACL, client->name())) {
591 ua->send_msg("%s\n", client->name());
598 static bool msgscmd(UAContext *ua, const char *cmd)
602 foreach_res(msgs, R_MSGS) {
603 ua->send_msg("%s\n", msgs->name());
609 static bool poolscmd(UAContext *ua, const char *cmd)
613 foreach_res(pool, R_POOL) {
614 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
615 ua->send_msg("%s\n", pool->name());
622 static bool storagecmd(UAContext *ua, const char *cmd)
626 foreach_res(store, R_STORAGE) {
627 if (acl_access_ok(ua, Storage_ACL, store->name())) {
628 ua->send_msg("%s\n", store->name());
635 static bool aopcmd(UAContext *ua, const char *cmd)
637 ua->send_msg("None\n");
638 ua->send_msg("Truncate\n");
642 static bool typescmd(UAContext *ua, const char *cmd)
644 ua->send_msg("Backup\n");
645 ua->send_msg("Restore\n");
646 ua->send_msg("Admin\n");
647 ua->send_msg("Verify\n");
648 ua->send_msg("Migrate\n");
649 ua->send_msg("Copy\n");
654 * If this command is called, it tells the director that we
655 * are a program that wants a sort of API, and hence,
656 * we will probably suppress certain output, include more
657 * error codes, and most of all send back a good number
658 * of new signals that indicate whether or not the command
661 static bool api_cmd(UAContext *ua, const char *cmd)
664 ua->api = atoi(ua->argk[1]);
671 static int client_backups_handler(void *ctx, int num_field, char **row)
673 UAContext *ua = (UAContext *)ctx;
674 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
675 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
680 * Return the backups for this client
682 * .backups client=xxx fileset=yyy
685 static bool backupscmd(UAContext *ua, const char *cmd)
687 if (!open_client_db(ua)) {
690 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
691 strcmp(ua->argk[2], "fileset") != 0) {
694 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
695 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
696 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
699 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
700 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
701 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
707 static int sql_handler(void *ctx, int num_field, char **row)
709 UAContext *ua = (UAContext *)ctx;
710 POOL_MEM rows(PM_MESSAGE);
712 /* Check for nonsense */
713 if (num_field == 0 || row == NULL || row[0] == NULL) {
714 return 0; /* nothing returned */
716 for (int i=0; num_field--; i++) {
718 pm_strcpy(rows, NPRT(row[0]));
720 pm_strcat(rows, NPRT(row[i]));
722 pm_strcat(rows, "\t");
724 if (!rows.c_str() || !*rows.c_str()) {
727 ua->send_msg("%s", rows.c_str());
732 static bool sql_cmd(UAContext *ua, const char *cmd)
735 if (!open_client_db(ua)) {
738 index = find_arg_with_value(ua, "query");
740 ua->error_msg(_("query keyword not found.\n"));
743 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
744 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
745 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
751 static int one_handler(void *ctx, int num_field, char **row)
753 UAContext *ua = (UAContext *)ctx;
754 ua->send_msg("%s\n", row[0]);
758 static bool mediatypescmd(UAContext *ua, const char *cmd)
760 if (!open_client_db(ua)) {
763 if (!db_sql_query(ua->db,
764 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
765 one_handler, (void *)ua))
767 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
772 static bool mediacmd(UAContext *ua, const char *cmd)
774 if (!open_client_db(ua)) {
777 if (!db_sql_query(ua->db,
778 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
779 one_handler, (void *)ua))
781 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
786 static bool locationscmd(UAContext *ua, const char *cmd)
788 if (!open_client_db(ua)) {
791 if (!db_sql_query(ua->db,
792 "SELECT DISTINCT Location FROM Location ORDER BY Location",
793 one_handler, (void *)ua))
795 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
800 static bool levelscmd(UAContext *ua, const char *cmd)
802 ua->send_msg("Incremental\n");
803 ua->send_msg("Full\n");
804 ua->send_msg("Differential\n");
805 ua->send_msg("VirtualFull\n");
806 ua->send_msg("Catalog\n");
807 ua->send_msg("InitCatalog\n");
808 ua->send_msg("VolumeToCatalog\n");
809 ua->send_msg("Base\n");
813 static bool volstatuscmd(UAContext *ua, const char *cmd)
815 ua->send_msg("Append\n");
816 ua->send_msg("Full\n");
817 ua->send_msg("Used\n");
818 ua->send_msg("Recycle\n");
819 ua->send_msg("Purged\n");
820 ua->send_msg("Cleaning\n");
821 ua->send_msg("Error\n");
826 * Return default values for a job
828 static bool defaultscmd(UAContext *ua, const char *cmd)
836 if (ua->argc != 2 || !ua->argv[1]) {
841 if (strcmp(ua->argk[1], "job") == 0) {
842 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
845 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
848 ua->send_msg("job=%s", job->name());
849 ua->send_msg("pool=%s", job->pool->name());
850 ua->send_msg("messages=%s", job->messages->name());
851 ua->send_msg("client=%s", job->client->name());
852 get_job_storage(&store, job, NULL);
853 ua->send_msg("storage=%s", store.store->name());
854 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
855 ua->send_msg("level=%s", level_to_str(job->JobLevel));
856 ua->send_msg("type=%s", job_type_to_str(job->JobType));
857 ua->send_msg("fileset=%s", job->fileset->name());
858 ua->send_msg("enabled=%d", job->enabled);
859 ua->send_msg("catalog=%s", job->client->catalog->name());
862 /* Client defaults */
863 else if (strcmp(ua->argk[1], "client") == 0) {
864 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
867 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
869 ua->send_msg("client=%s", client->name());
870 ua->send_msg("address=%s", client->address);
871 ua->send_msg("fdport=%d", client->FDport);
872 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
873 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
874 ua->send_msg("autoprune=%d", client->AutoPrune);
875 ua->send_msg("catalog=%s", client->catalog->name());
878 /* Storage defaults */
879 else if (strcmp(ua->argk[1], "storage") == 0) {
880 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
883 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
886 ua->send_msg("storage=%s", storage->name());
887 ua->send_msg("address=%s", storage->address);
888 ua->send_msg("enabled=%d", storage->enabled);
889 ua->send_msg("media_type=%s", storage->media_type);
890 ua->send_msg("sdport=%d", storage->SDport);
891 device = (DEVICE *)storage->device->first();
892 ua->send_msg("device=%s", device->name());
893 if (storage->device->size() > 1) {
894 while ((device = (DEVICE *)storage->device->next())) {
895 ua->send_msg(",%s", device->name());
901 else if (strcmp(ua->argk[1], "pool") == 0) {
902 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
905 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
907 ua->send_msg("pool=%s", pool->name());
908 ua->send_msg("pool_type=%s", pool->pool_type);
909 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
910 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
911 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
912 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
913 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
914 ua->send_msg("max_volumes=%d", pool->max_volumes);
915 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
916 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
917 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
918 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
919 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
920 ua->send_msg("auto_prune=%d", pool->AutoPrune);
921 ua->send_msg("recycle=%d", pool->Recycle);
922 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
923 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));