2 Bacula® - The Network Backup Solution
4 Copyright (C) 2002-2009 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 two of the GNU 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 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 die_or_dump_cmd(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"), die_or_dump_cmd, NULL, false},
89 { NT_(".dump"), die_or_dump_cmd, NULL, false},
90 { NT_(".exit"), dot_quit_cmd, 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;
422 * Create segmentation fault or dump memory
424 static bool die_or_dump_cmd(UAContext *ua, const char *cmd)
426 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
430 bool do_deadlock=false;
431 const char *remote_cmd="sm_dump";
435 if (!strncmp(ua->argk[0], ".die", 4)) {
436 if (find_arg(ua, "deadlock") > 0) {
438 remote_cmd = ".die deadlock";
444 for (i=1; i<ua->argc; i++) {
445 if (strcasecmp(ua->argk[i], "dir") == 0 ||
446 strcasecmp(ua->argk[i], "director") == 0) {
449 if (strcasecmp(ua->argk[i], "client") == 0 ||
450 strcasecmp(ua->argk[i], "fd") == 0) {
453 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
456 client = select_client_resource(ua);
460 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
461 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
462 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
465 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
468 store = get_storage_resource(ua, false/*no default*/);
473 if (!dir && !store && !client) {
475 * We didn't find an appropriate keyword above, so
478 start_prompt(ua, _("Available daemons are: \n"));
479 add_prompt(ua, _("Director"));
480 add_prompt(ua, _("Storage"));
481 add_prompt(ua, _("Client"));
482 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
483 case 0: /* Director */
487 store = get_storage_resource(ua, false/*no default*/);
490 client = select_client_resource(ua);
498 do_storage_cmd(ua, store, remote_cmd);
502 do_client_cmd(ua, client, remote_cmd);
506 if (!strncmp(remote_cmd, ".die", 4)) {
508 ua->send_msg(_("The Director will generate a deadlock.\n"));
512 ua->send_msg(_("The Director will segment fault.\n"));
513 a = jcr->JobId; /* ref NULL pointer */
514 jcr->JobId = 1000; /* another ref NULL pointer */
517 sm_dump(false, true);
527 * Dummy routine for non-development version
529 static bool die_or_dump_cmd(UAContext *ua, const char *cmd)
537 * Can use an argument to filter on JobType
540 static bool jobscmd(UAContext *ua, const char *cmd)
545 if ((pos = find_arg_with_value(ua, "type")) >= 0) {
546 type = ua->argv[pos][0];
549 foreach_res(job, R_JOB) {
550 if (!type || type == job->JobType) {
551 if (acl_access_ok(ua, Job_ACL, job->name())) {
552 ua->send_msg("%s\n", job->name());
560 static bool filesetscmd(UAContext *ua, const char *cmd)
564 foreach_res(fs, R_FILESET) {
565 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
566 ua->send_msg("%s\n", fs->name());
573 static bool clientscmd(UAContext *ua, const char *cmd)
577 foreach_res(client, R_CLIENT) {
578 if (acl_access_ok(ua, Client_ACL, client->name())) {
579 ua->send_msg("%s\n", client->name());
586 static bool msgscmd(UAContext *ua, const char *cmd)
590 foreach_res(msgs, R_MSGS) {
591 ua->send_msg("%s\n", msgs->name());
597 static bool poolscmd(UAContext *ua, const char *cmd)
601 foreach_res(pool, R_POOL) {
602 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
603 ua->send_msg("%s\n", pool->name());
610 static bool storagecmd(UAContext *ua, const char *cmd)
614 foreach_res(store, R_STORAGE) {
615 if (acl_access_ok(ua, Storage_ACL, store->name())) {
616 ua->send_msg("%s\n", store->name());
623 static bool aopcmd(UAContext *ua, const char *cmd)
625 ua->send_msg("None\n");
626 ua->send_msg("Truncate\n");
630 static bool typescmd(UAContext *ua, const char *cmd)
632 ua->send_msg("Backup\n");
633 ua->send_msg("Restore\n");
634 ua->send_msg("Admin\n");
635 ua->send_msg("Verify\n");
636 ua->send_msg("Migrate\n");
637 ua->send_msg("Copy\n");
642 * If this command is called, it tells the director that we
643 * are a program that wants a sort of API, and hence,
644 * we will probably suppress certain output, include more
645 * error codes, and most of all send back a good number
646 * of new signals that indicate whether or not the command
649 static bool api_cmd(UAContext *ua, const char *cmd)
652 ua->api = atoi(ua->argk[1]);
659 static int client_backups_handler(void *ctx, int num_field, char **row)
661 UAContext *ua = (UAContext *)ctx;
662 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
663 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
668 * Return the backups for this client
670 * .backups client=xxx fileset=yyy
673 static bool backupscmd(UAContext *ua, const char *cmd)
675 if (!open_client_db(ua)) {
678 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
679 strcmp(ua->argk[2], "fileset") != 0) {
682 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
683 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
684 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
687 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
688 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
689 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
695 static int sql_handler(void *ctx, int num_field, char **row)
697 UAContext *ua = (UAContext *)ctx;
698 POOL_MEM rows(PM_MESSAGE);
700 /* Check for nonsense */
701 if (num_field == 0 || row == NULL || row[0] == NULL) {
702 return 0; /* nothing returned */
704 for (int i=0; num_field--; i++) {
706 pm_strcpy(rows, NPRT(row[0]));
708 pm_strcat(rows, NPRT(row[i]));
710 pm_strcat(rows, "\t");
712 if (!rows.c_str() || !*rows.c_str()) {
715 ua->send_msg("%s", rows.c_str());
720 static bool sql_cmd(UAContext *ua, const char *cmd)
723 if (!open_client_db(ua)) {
726 index = find_arg_with_value(ua, "query");
728 ua->error_msg(_("query keyword not found.\n"));
731 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
732 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
733 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
739 static int one_handler(void *ctx, int num_field, char **row)
741 UAContext *ua = (UAContext *)ctx;
742 ua->send_msg("%s\n", row[0]);
746 static bool mediatypescmd(UAContext *ua, const char *cmd)
748 if (!open_client_db(ua)) {
751 if (!db_sql_query(ua->db,
752 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
753 one_handler, (void *)ua))
755 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
760 static bool mediacmd(UAContext *ua, const char *cmd)
762 if (!open_client_db(ua)) {
765 if (!db_sql_query(ua->db,
766 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
767 one_handler, (void *)ua))
769 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
774 static bool locationscmd(UAContext *ua, const char *cmd)
776 if (!open_client_db(ua)) {
779 if (!db_sql_query(ua->db,
780 "SELECT DISTINCT Location FROM Location ORDER BY Location",
781 one_handler, (void *)ua))
783 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
788 static bool levelscmd(UAContext *ua, const char *cmd)
790 ua->send_msg("Incremental\n");
791 ua->send_msg("Full\n");
792 ua->send_msg("Differential\n");
793 ua->send_msg("VirtualFull\n");
794 ua->send_msg("Catalog\n");
795 ua->send_msg("InitCatalog\n");
796 ua->send_msg("VolumeToCatalog\n");
797 ua->send_msg("Base\n");
801 static bool volstatuscmd(UAContext *ua, const char *cmd)
803 ua->send_msg("Append\n");
804 ua->send_msg("Full\n");
805 ua->send_msg("Used\n");
806 ua->send_msg("Recycle\n");
807 ua->send_msg("Purged\n");
808 ua->send_msg("Cleaning\n");
809 ua->send_msg("Error\n");
814 * Return default values for a job
816 static bool defaultscmd(UAContext *ua, const char *cmd)
824 if (ua->argc != 2 || !ua->argv[1]) {
829 if (strcmp(ua->argk[1], "job") == 0) {
830 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
833 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
836 ua->send_msg("job=%s", job->name());
837 ua->send_msg("pool=%s", job->pool->name());
838 ua->send_msg("messages=%s", job->messages->name());
839 ua->send_msg("client=%s", job->client->name());
840 get_job_storage(&store, job, NULL);
841 ua->send_msg("storage=%s", store.store->name());
842 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
843 ua->send_msg("level=%s", level_to_str(job->JobLevel));
844 ua->send_msg("type=%s", job_type_to_str(job->JobType));
845 ua->send_msg("fileset=%s", job->fileset->name());
846 ua->send_msg("enabled=%d", job->enabled);
847 ua->send_msg("catalog=%s", job->client->catalog->name());
850 /* Client defaults */
851 else if (strcmp(ua->argk[1], "client") == 0) {
852 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
855 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
857 ua->send_msg("client=%s", client->name());
858 ua->send_msg("address=%s", client->address);
859 ua->send_msg("fdport=%d", client->FDport);
860 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
861 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
862 ua->send_msg("autoprune=%d", client->AutoPrune);
863 ua->send_msg("catalog=%s", client->catalog->name());
866 /* Storage defaults */
867 else if (strcmp(ua->argk[1], "storage") == 0) {
868 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
871 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
874 ua->send_msg("storage=%s", storage->name());
875 ua->send_msg("address=%s", storage->address);
876 ua->send_msg("enabled=%d", storage->enabled);
877 ua->send_msg("media_type=%s", storage->media_type);
878 ua->send_msg("sdport=%d", storage->SDport);
879 device = (DEVICE *)storage->device->first();
880 ua->send_msg("device=%s", device->name());
881 if (storage->device->size() > 1) {
882 while ((device = (DEVICE *)storage->device->next())) {
883 ua->send_msg(",%s", device->name());
889 else if (strcmp(ua->argk[1], "pool") == 0) {
890 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
893 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
895 ua->send_msg("pool=%s", pool->name());
896 ua->send_msg("pool_type=%s", pool->pool_type);
897 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
898 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
899 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
900 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
901 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
902 ua->send_msg("max_volumes=%d", pool->max_volumes);
903 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
904 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
905 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
906 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
907 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
908 ua->send_msg("auto_prune=%d", pool->AutoPrune);
909 ua->send_msg("recycle=%d", pool->Recycle);
910 ua->send_msg("file_retention=%s", edit_uint64(pool->FileRetention, ed1));
911 ua->send_msg("job_retention=%s", edit_uint64(pool->JobRetention, ed1));