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
43 #include "cats/bvfs.h"
44 #include "findlib/find.h"
46 /* Imported variables */
48 /* Imported functions */
49 extern void do_messages(UAContext *ua, const char *cmd);
50 extern int quit_cmd(UAContext *ua, const char *cmd);
51 extern int qhelp_cmd(UAContext *ua, const char *cmd);
52 extern bool dot_status_cmd(UAContext *ua, const char *cmd);
55 /* Forward referenced functions */
56 static bool diecmd(UAContext *ua, const char *cmd);
57 static bool jobscmd(UAContext *ua, const char *cmd);
58 static bool filesetscmd(UAContext *ua, const char *cmd);
59 static bool clientscmd(UAContext *ua, const char *cmd);
60 static bool msgscmd(UAContext *ua, const char *cmd);
61 static bool poolscmd(UAContext *ua, const char *cmd);
62 static bool storagecmd(UAContext *ua, const char *cmd);
63 static bool defaultscmd(UAContext *ua, const char *cmd);
64 static bool typescmd(UAContext *ua, const char *cmd);
65 static bool backupscmd(UAContext *ua, const char *cmd);
66 static bool levelscmd(UAContext *ua, const char *cmd);
67 static bool getmsgscmd(UAContext *ua, const char *cmd);
68 static bool volstatuscmd(UAContext *ua, const char *cmd);
69 static bool mediatypescmd(UAContext *ua, const char *cmd);
70 static bool locationscmd(UAContext *ua, const char *cmd);
71 static bool mediacmd(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);
81 static bool helpscmd(UAContext *ua, const char *cmd);
83 struct cmdstruct { const char *key; bool (*func)(UAContext *ua, const char *cmd); const char *help;const bool use_in_rs;};
84 static struct cmdstruct commands[] = { /* help */ /* can be used in runscript */
85 { NT_(".api"), api_cmd, NULL, false},
86 { NT_(".backups"), backupscmd, NULL, false},
87 { NT_(".clients"), clientscmd, NULL, true},
88 { NT_(".defaults"), defaultscmd, NULL, false},
89 { NT_(".die"), diecmd, 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_(".bvfs_lsdirs"), dot_bvfs_lsdirs, NULL, true},
107 { NT_(".bvfs_lsfiles"),dot_bvfs_lsfiles,NULL, true},
108 { NT_(".bvfs_update"), dot_bvfs_update, NULL, true},
109 { NT_(".types"), typescmd, NULL, false}
111 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
114 * Execute a command from the UA
116 bool do_a_dot_command(UAContext *ua)
122 BSOCK *user = ua->UA_sock;
124 Dmsg1(1400, "Dot command: %s\n", user->msg);
129 len = strlen(ua->argk[0]);
131 if (ua->api) user->signal(BNET_CMD_BEGIN);
132 if (ua->api) user->signal(BNET_CMD_OK);
133 return true; /* no op */
135 for (i=0; i<comsize; i++) { /* search for command */
136 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
137 /* Check if this command is authorized in RunScript */
138 if (ua->runscript && !commands[i].use_in_rs) {
139 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
143 /* Check if command permitted, but "quit" is always OK */
144 if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
145 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
148 Dmsg1(100, "Cmd: %s\n", ua->cmd);
150 if (ua->api) user->signal(BNET_CMD_BEGIN);
151 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
152 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
159 pm_strcat(user->msg, _(": is an invalid command.\n"));
160 ua->error_msg("%s", user->msg);
166 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
169 if (!open_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);
185 static int bvfs_result_handler(void *ctx, int fields, char **row)
187 UAContext *ua = (UAContext *)ctx;
192 char empty[] = "A A A A A A A A A A A A A A";
194 lstat = (row[BVFS_LStat] && row[BVFS_LStat][0])?row[BVFS_LStat]:empty;
195 fileid = (row[BVFS_FileId] && row[BVFS_FileId][0])?row[BVFS_FileId]:"0";
197 memset(&statp, 0, sizeof(struct stat));
198 decode_stat(lstat, &statp, &LinkFI);
200 Dmsg1(0, "type=%s\n", row[0]);
201 if (bvfs_is_dir(row)) {
202 char *path = bvfs_basename_dir(row[BVFS_Name]);
203 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
204 row[BVFS_JobId], row[BVFS_LStat], path);
206 } else if (bvfs_is_file(row)) {
207 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
208 row[BVFS_FilenameId], fileid, row[BVFS_JobId],
209 row[BVFS_LStat], row[BVFS_Name]);
215 static bool bvfs_parse_arg(UAContext *ua,
216 DBId_t *pathid, char **path, char **jobid,
217 int *limit, int *offset)
225 for (int i=1; i<ua->argc; i++) {
226 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
227 if (is_a_number(ua->argv[i])) {
228 *pathid = str_to_int64(ua->argv[i]);
231 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
235 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
236 if (is_a_number_list(ua->argv[i])) {
237 *jobid = ua->argv[i];
241 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
242 if (is_a_number(ua->argv[i])) {
243 *limit = str_to_int64(ua->argv[i]);
247 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
248 if (is_a_number(ua->argv[i])) {
249 *offset = str_to_int64(ua->argv[i]);
254 if (!((*pathid || *path) && *jobid)) {
258 if (!open_client_db(ua)) {
266 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
267 * .bvfs_lsfiles jobid=1,2,3,4 path=/
269 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
272 int limit=2000, offset=0;
273 char *path=NULL, *jobid=NULL;
275 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
278 ua->error_msg("Can't find jobid, pathid or path argument\n");
279 return true; /* not enough param */
282 Bvfs fs(ua->jcr, ua->db);
283 fs.set_jobids(jobid);
284 fs.set_handler(bvfs_result_handler, ua);
293 fs.set_offset(offset);
301 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
302 * .bvfs_lsdirs jobid=1,2,3,4 path=/
303 * .bvfs_lsdirs jobid=1,2,3,4 path=
305 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
308 int limit=2000, offset=0;
309 char *path=NULL, *jobid=NULL;
311 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
314 ua->error_msg("Can't find jobid, pathid or path argument\n");
315 return true; /* not enough param */
318 Bvfs fs(ua->jcr, ua->db);
319 fs.set_jobids(jobid);
321 fs.set_handler(bvfs_result_handler, ua);
329 fs.set_offset(offset);
331 fs.ls_special_dirs();
337 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
343 static bool dot_help_cmd(UAContext *ua, const char *cmd)
349 static bool getmsgscmd(UAContext *ua, const char *cmd)
351 if (console_msg_pending) {
352 do_messages(ua, cmd);
358 static void do_storage_die(UAContext *ua, STORE *store)
364 lstore.store = store;
365 pm_strcpy(lstore.store_source, _("unknown source"));
366 set_wstorage(jcr, &lstore);
367 /* Try connecting for up to 15 seconds */
368 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
369 store->name(), store->address, store->SDport);
370 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
371 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
374 Dmsg0(120, _("Connected to storage daemon\n"));
375 sd = jcr->store_bsock;
377 if (sd->recv() >= 0) {
378 ua->send_msg("%s", sd->msg);
380 sd->signal(BNET_TERMINATE);
382 jcr->store_bsock = NULL;
386 static void do_client_die(UAContext *ua, CLIENT *client)
390 /* Connect to File daemon */
392 ua->jcr->client = client;
393 /* Try to connect for 15 seconds */
394 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
395 client->name(), client->address, client->FDport);
396 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
397 ua->error_msg(_("Failed to connect to Client.\n"));
400 Dmsg0(120, "Connected to file daemon\n");
401 fd = ua->jcr->file_bsock;
403 if (fd->recv() >= 0) {
404 ua->send_msg("%s", fd->msg);
406 fd->signal(BNET_TERMINATE);
408 ua->jcr->file_bsock = NULL;
413 * Create segmentation fault
415 static bool diecmd(UAContext *ua, const char *cmd)
423 Dmsg1(120, "diecmd:%s:\n", cmd);
426 for (i=1; i<ua->argc; i++) {
427 if (strcasecmp(ua->argk[i], "dir") == 0 ||
428 strcasecmp(ua->argk[i], "director") == 0) {
429 ua->send_msg(_("The Director will segment fault.\n"));
430 a = jcr->JobId; /* ref NULL pointer */
431 jcr->JobId = 1000; /* another ref NULL pointer */
434 if (strcasecmp(ua->argk[i], "client") == 0 ||
435 strcasecmp(ua->argk[i], "fd") == 0) {
438 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
440 do_client_die(ua, client);
444 client = select_client_resource(ua);
446 do_client_die(ua, client);
451 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
452 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
453 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
456 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
458 do_storage_die(ua, store);
462 store = get_storage_resource(ua, false/*no default*/);
464 do_storage_die(ua, store);
470 * We didn't find an appropriate keyword above, so
473 start_prompt(ua, _("Available daemons are: \n"));
474 add_prompt(ua, _("Director"));
475 add_prompt(ua, _("Storage"));
476 add_prompt(ua, _("Client"));
477 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
478 case 0: /* Director */
479 ua->send_msg(_("The Director will segment fault.\n"));
480 a = jcr->JobId; /* ref NULL pointer */
481 jcr->JobId = 1000; /* another ref NULL pointer */
484 store = get_storage_resource(ua, false/*no default*/);
486 do_storage_die(ua, store);
490 client = select_client_resource(ua);
492 do_client_die(ua, client);
504 * Dummy routine for non-development version
506 static bool diecmd(UAContext *ua, const char *cmd)
513 static bool jobscmd(UAContext *ua, const char *cmd)
517 foreach_res(job, R_JOB) {
518 if (acl_access_ok(ua, Job_ACL, job->name())) {
519 ua->send_msg("%s\n", job->name());
526 static bool filesetscmd(UAContext *ua, const char *cmd)
530 foreach_res(fs, R_FILESET) {
531 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
532 ua->send_msg("%s\n", fs->name());
539 static bool clientscmd(UAContext *ua, const char *cmd)
543 foreach_res(client, R_CLIENT) {
544 if (acl_access_ok(ua, Client_ACL, client->name())) {
545 ua->send_msg("%s\n", client->name());
552 static bool msgscmd(UAContext *ua, const char *cmd)
556 foreach_res(msgs, R_MSGS) {
557 ua->send_msg("%s\n", msgs->name());
563 static bool poolscmd(UAContext *ua, const char *cmd)
567 foreach_res(pool, R_POOL) {
568 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
569 ua->send_msg("%s\n", pool->name());
576 static bool storagecmd(UAContext *ua, const char *cmd)
580 foreach_res(store, R_STORAGE) {
581 if (acl_access_ok(ua, Storage_ACL, store->name())) {
582 ua->send_msg("%s\n", store->name());
590 static bool typescmd(UAContext *ua, const char *cmd)
592 ua->send_msg("Backup\n");
593 ua->send_msg("Restore\n");
594 ua->send_msg("Admin\n");
595 ua->send_msg("Verify\n");
596 ua->send_msg("Migrate\n");
602 * If this command is called, it tells the director that we
603 * are a program that wants a sort of API, and hence,
604 * we will probably suppress certain output, include more
605 * error codes, and most of all send back a good number
606 * of new signals that indicate whether or not the command
609 static bool api_cmd(UAContext *ua, const char *cmd)
612 ua->api = atoi(ua->argk[1]);
619 static int client_backups_handler(void *ctx, int num_field, char **row)
621 UAContext *ua = (UAContext *)ctx;
622 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
623 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
628 * Return the backups for this client
630 * .backups client=xxx fileset=yyy
633 static bool backupscmd(UAContext *ua, const char *cmd)
635 if (!open_client_db(ua)) {
638 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
639 strcmp(ua->argk[2], "fileset") != 0) {
642 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
643 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
644 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
647 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
648 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
649 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
655 static int sql_handler(void *ctx, int num_field, char **row)
657 UAContext *ua = (UAContext *)ctx;
658 POOL_MEM rows(PM_MESSAGE);
660 /* Check for nonsense */
661 if (num_field == 0 || row == NULL || row[0] == NULL) {
662 return 0; /* nothing returned */
664 for (int i=0; num_field--; i++) {
666 pm_strcpy(rows, NPRT(row[0]));
668 pm_strcat(rows, NPRT(row[i]));
670 pm_strcat(rows, "\t");
672 if (!rows.c_str() || !*rows.c_str()) {
675 ua->send_msg("%s", rows.c_str());
680 static bool sql_cmd(UAContext *ua, const char *cmd)
683 if (!open_client_db(ua)) {
686 index = find_arg_with_value(ua, "query");
688 ua->error_msg(_("query keyword not found.\n"));
691 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
692 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
693 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
699 static int one_handler(void *ctx, int num_field, char **row)
701 UAContext *ua = (UAContext *)ctx;
702 ua->send_msg("%s\n", row[0]);
706 static bool mediatypescmd(UAContext *ua, const char *cmd)
708 if (!open_client_db(ua)) {
711 if (!db_sql_query(ua->db,
712 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
713 one_handler, (void *)ua))
715 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
720 static bool mediacmd(UAContext *ua, const char *cmd)
722 if (!open_client_db(ua)) {
725 if (!db_sql_query(ua->db,
726 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
727 one_handler, (void *)ua))
729 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
734 static bool locationscmd(UAContext *ua, const char *cmd)
736 if (!open_client_db(ua)) {
739 if (!db_sql_query(ua->db,
740 "SELECT DISTINCT Location FROM Location ORDER BY Location",
741 one_handler, (void *)ua))
743 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
748 static bool levelscmd(UAContext *ua, const char *cmd)
750 ua->send_msg("Incremental\n");
751 ua->send_msg("Full\n");
752 ua->send_msg("Differential\n");
753 ua->send_msg("VirtualFull\n");
754 ua->send_msg("Catalog\n");
755 ua->send_msg("InitCatalog\n");
756 ua->send_msg("VolumeToCatalog\n");
760 static bool volstatuscmd(UAContext *ua, const char *cmd)
762 ua->send_msg("Append\n");
763 ua->send_msg("Full\n");
764 ua->send_msg("Used\n");
765 ua->send_msg("Recycle\n");
766 ua->send_msg("Purged\n");
767 ua->send_msg("Cleaning\n");
768 ua->send_msg("Error\n");
773 * Return default values for a job
775 static bool defaultscmd(UAContext *ua, const char *cmd)
783 if (ua->argc != 2 || !ua->argv[1]) {
788 if (strcmp(ua->argk[1], "job") == 0) {
789 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
792 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
795 ua->send_msg("job=%s", job->name());
796 ua->send_msg("pool=%s", job->pool->name());
797 ua->send_msg("messages=%s", job->messages->name());
798 ua->send_msg("client=%s", job->client->name());
799 get_job_storage(&store, job, NULL);
800 ua->send_msg("storage=%s", store.store->name());
801 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
802 ua->send_msg("level=%s", level_to_str(job->JobLevel));
803 ua->send_msg("type=%s", job_type_to_str(job->JobType));
804 ua->send_msg("fileset=%s", job->fileset->name());
805 ua->send_msg("enabled=%d", job->enabled);
806 ua->send_msg("catalog=%s", job->client->catalog->name());
809 /* Client defaults */
810 else if (strcmp(ua->argk[1], "client") == 0) {
811 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
814 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
816 ua->send_msg("client=%s", client->name());
817 ua->send_msg("address=%s", client->address);
818 ua->send_msg("fdport=%d", client->FDport);
819 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
820 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
821 ua->send_msg("autoprune=%d", client->AutoPrune);
822 ua->send_msg("catalog=%s", client->catalog->name());
825 /* Storage defaults */
826 else if (strcmp(ua->argk[1], "storage") == 0) {
827 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
830 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
833 ua->send_msg("storage=%s", storage->name());
834 ua->send_msg("address=%s", storage->address);
835 ua->send_msg("enabled=%d", storage->enabled);
836 ua->send_msg("media_type=%s", storage->media_type);
837 ua->send_msg("sdport=%d", storage->SDport);
838 device = (DEVICE *)storage->device->first();
839 ua->send_msg("device=%s", device->name());
840 if (storage->device->size() > 1) {
841 while ((device = (DEVICE *)storage->device->next())) {
842 ua->send_msg(",%s", device->name());
848 else if (strcmp(ua->argk[1], "pool") == 0) {
849 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
852 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
854 ua->send_msg("pool=%s", pool->name());
855 ua->send_msg("pool_type=%s", pool->pool_type);
856 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
857 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
858 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
859 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
860 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
861 ua->send_msg("max_volumes=%d", pool->max_volumes);
862 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
863 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
864 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
865 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
866 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
867 ua->send_msg("auto_prune=%d", pool->AutoPrune);
868 ua->send_msg("recycle=%d", pool->Recycle);