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);
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"), diecmd, NULL, false},
89 { NT_(".exit"), dot_quit_cmd, NULL, false},
90 { NT_(".filesets"), filesetscmd, NULL, false},
91 { NT_(".help"), dot_help_cmd, NULL, false},
92 { NT_(".jobs"), jobscmd, NULL, true},
93 { NT_(".levels"), levelscmd, NULL, false},
94 { NT_(".messages"), getmsgscmd, NULL, false},
95 { NT_(".msgs"), msgscmd, NULL, false},
96 { NT_(".pools"), poolscmd, NULL, true},
97 { NT_(".quit"), dot_quit_cmd, NULL, false},
98 { NT_(".sql"), sql_cmd, NULL, false},
99 { NT_(".status"), dot_status_cmd, NULL, false},
100 { NT_(".storage"), storagecmd, NULL, true},
101 { NT_(".volstatus"), volstatuscmd, NULL, true},
102 { NT_(".media"), mediacmd, NULL, true},
103 { NT_(".mediatypes"), mediatypescmd, NULL, true},
104 { NT_(".locations"), locationscmd, NULL, true},
105 { NT_(".bvfs_lsdirs"), dot_bvfs_lsdirs, NULL, true},
106 { NT_(".bvfs_lsfiles"),dot_bvfs_lsfiles,NULL, true},
107 { NT_(".bvfs_update"), dot_bvfs_update, NULL, true},
108 { NT_(".types"), typescmd, NULL, false}
110 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
113 * Execute a command from the UA
115 bool do_a_dot_command(UAContext *ua)
121 BSOCK *user = ua->UA_sock;
123 Dmsg1(1400, "Dot command: %s\n", user->msg);
128 len = strlen(ua->argk[0]);
130 if (ua->api) user->signal(BNET_CMD_BEGIN);
131 if (ua->api) user->signal(BNET_CMD_OK);
132 return true; /* no op */
134 for (i=0; i<comsize; i++) { /* search for command */
135 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
136 /* Check if this command is authorized in RunScript */
137 if (ua->runscript && !commands[i].use_in_rs) {
138 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
142 /* Check if command permitted, but "quit" is always OK */
143 if (strcmp(ua->argk[0], NT_(".quit")) != 0 &&
144 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
147 Dmsg1(100, "Cmd: %s\n", ua->cmd);
149 if (ua->api) user->signal(BNET_CMD_BEGIN);
150 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
151 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
158 pm_strcat(user->msg, _(": is an invalid command.\n"));
159 ua->error_msg("%s", user->msg);
165 static bool dot_bvfs_update(UAContext *ua, const char *cmd)
168 if (!open_client_db(ua)) {
172 int pos = find_arg_with_value(ua, "jobid");
173 if (pos != -1 && is_a_number_list(ua->argv[pos])) {
175 pm_strcpy(jobids, ua->argv[pos]);
176 bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, jobids.c_str());
178 /* update cache for all jobids */
179 bvfs_update_cache(ua->jcr, ua->db);
184 static int bvfs_result_handler(void *ctx, int fields, char **row)
186 UAContext *ua = (UAContext *)ctx;
191 char empty[] = "A A A A A A A A A A A A A A";
193 lstat = (row[BVFS_LStat] && row[BVFS_LStat][0])?row[BVFS_LStat]:empty;
194 fileid = (row[BVFS_FileId] && row[BVFS_FileId][0])?row[BVFS_FileId]:"0";
196 memset(&statp, 0, sizeof(struct stat));
197 decode_stat(lstat, &statp, &LinkFI);
199 Dmsg1(0, "type=%s\n", row[0]);
200 if (bvfs_is_dir(row)) {
201 char *path = bvfs_basename_dir(row[BVFS_Name]);
202 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
203 row[BVFS_JobId], row[BVFS_LStat], path);
205 } else if (bvfs_is_file(row)) {
206 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
207 row[BVFS_FilenameId], fileid, row[BVFS_JobId],
208 row[BVFS_LStat], row[BVFS_Name]);
214 static bool bvfs_parse_arg(UAContext *ua,
215 DBId_t *pathid, char **path, char **jobid,
216 int *limit, int *offset)
224 for (int i=1; i<ua->argc; i++) {
225 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
226 if (is_a_number(ua->argv[i])) {
227 *pathid = str_to_int64(ua->argv[i]);
230 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
234 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
235 if (is_a_number_list(ua->argv[i])) {
236 *jobid = ua->argv[i];
240 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
241 if (is_a_number(ua->argv[i])) {
242 *limit = str_to_int64(ua->argv[i]);
246 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
247 if (is_a_number(ua->argv[i])) {
248 *offset = str_to_int64(ua->argv[i]);
253 if (!((*pathid || *path) && *jobid)) {
257 if (!open_client_db(ua)) {
265 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
266 * .bvfs_lsfiles jobid=1,2,3,4 path=/
268 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
271 int limit=2000, offset=0;
272 char *path=NULL, *jobid=NULL;
274 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
277 ua->error_msg("Can't find jobid, pathid or path argument\n");
278 return true; /* not enough param */
281 Bvfs fs(ua->jcr, ua->db);
282 fs.set_jobids(jobid);
283 fs.set_handler(bvfs_result_handler, ua);
292 fs.set_offset(offset);
300 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
301 * .bvfs_lsdirs jobid=1,2,3,4 path=/
302 * .bvfs_lsdirs jobid=1,2,3,4 path=
304 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
307 int limit=2000, offset=0;
308 char *path=NULL, *jobid=NULL;
310 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
313 ua->error_msg("Can't find jobid, pathid or path argument\n");
314 return true; /* not enough param */
317 Bvfs fs(ua->jcr, ua->db);
318 fs.set_jobids(jobid);
320 fs.set_handler(bvfs_result_handler, ua);
328 fs.set_offset(offset);
330 fs.ls_special_dirs();
336 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
342 static bool dot_help_cmd(UAContext *ua, const char *cmd)
348 static bool getmsgscmd(UAContext *ua, const char *cmd)
350 if (console_msg_pending) {
351 do_messages(ua, cmd);
357 static void do_storage_die(UAContext *ua, STORE *store)
363 lstore.store = store;
364 pm_strcpy(lstore.store_source, _("unknown source"));
365 set_wstorage(jcr, &lstore);
366 /* Try connecting for up to 15 seconds */
367 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
368 store->name(), store->address, store->SDport);
369 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
370 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
373 Dmsg0(120, _("Connected to storage daemon\n"));
374 sd = jcr->store_bsock;
376 if (sd->recv() >= 0) {
377 ua->send_msg("%s", sd->msg);
379 sd->signal(BNET_TERMINATE);
381 jcr->store_bsock = NULL;
385 static void do_client_die(UAContext *ua, CLIENT *client)
389 /* Connect to File daemon */
391 ua->jcr->client = client;
392 /* Try to connect for 15 seconds */
393 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
394 client->name(), client->address, client->FDport);
395 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
396 ua->error_msg(_("Failed to connect to Client.\n"));
399 Dmsg0(120, "Connected to file daemon\n");
400 fd = ua->jcr->file_bsock;
402 if (fd->recv() >= 0) {
403 ua->send_msg("%s", fd->msg);
405 fd->signal(BNET_TERMINATE);
407 ua->jcr->file_bsock = NULL;
412 * Create segmentation fault
414 static bool diecmd(UAContext *ua, const char *cmd)
422 Dmsg1(120, "diecmd:%s:\n", cmd);
425 for (i=1; i<ua->argc; i++) {
426 if (strcasecmp(ua->argk[i], "dir") == 0 ||
427 strcasecmp(ua->argk[i], "director") == 0) {
428 ua->send_msg(_("The Director will segment fault.\n"));
429 a = jcr->JobId; /* ref NULL pointer */
430 jcr->JobId = 1000; /* another ref NULL pointer */
433 if (strcasecmp(ua->argk[i], "client") == 0 ||
434 strcasecmp(ua->argk[i], "fd") == 0) {
437 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
439 do_client_die(ua, client);
443 client = select_client_resource(ua);
445 do_client_die(ua, client);
450 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
451 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
452 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
455 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
457 do_storage_die(ua, store);
461 store = get_storage_resource(ua, false/*no default*/);
463 do_storage_die(ua, store);
469 * We didn't find an appropriate keyword above, so
472 start_prompt(ua, _("Available daemons are: \n"));
473 add_prompt(ua, _("Director"));
474 add_prompt(ua, _("Storage"));
475 add_prompt(ua, _("Client"));
476 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
477 case 0: /* Director */
478 ua->send_msg(_("The Director will segment fault.\n"));
479 a = jcr->JobId; /* ref NULL pointer */
480 jcr->JobId = 1000; /* another ref NULL pointer */
483 store = get_storage_resource(ua, false/*no default*/);
485 do_storage_die(ua, store);
489 client = select_client_resource(ua);
491 do_client_die(ua, client);
503 * Dummy routine for non-development version
505 static bool diecmd(UAContext *ua, const char *cmd)
512 static bool jobscmd(UAContext *ua, const char *cmd)
516 foreach_res(job, R_JOB) {
517 if (acl_access_ok(ua, Job_ACL, job->name())) {
518 ua->send_msg("%s\n", job->name());
525 static bool filesetscmd(UAContext *ua, const char *cmd)
529 foreach_res(fs, R_FILESET) {
530 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
531 ua->send_msg("%s\n", fs->name());
538 static bool clientscmd(UAContext *ua, const char *cmd)
542 foreach_res(client, R_CLIENT) {
543 if (acl_access_ok(ua, Client_ACL, client->name())) {
544 ua->send_msg("%s\n", client->name());
551 static bool msgscmd(UAContext *ua, const char *cmd)
555 foreach_res(msgs, R_MSGS) {
556 ua->send_msg("%s\n", msgs->name());
562 static bool poolscmd(UAContext *ua, const char *cmd)
566 foreach_res(pool, R_POOL) {
567 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
568 ua->send_msg("%s\n", pool->name());
575 static bool storagecmd(UAContext *ua, const char *cmd)
579 foreach_res(store, R_STORAGE) {
580 if (acl_access_ok(ua, Storage_ACL, store->name())) {
581 ua->send_msg("%s\n", store->name());
589 static bool typescmd(UAContext *ua, const char *cmd)
591 ua->send_msg("Backup\n");
592 ua->send_msg("Restore\n");
593 ua->send_msg("Admin\n");
594 ua->send_msg("Verify\n");
595 ua->send_msg("Migrate\n");
601 * If this command is called, it tells the director that we
602 * are a program that wants a sort of API, and hence,
603 * we will probably suppress certain output, include more
604 * error codes, and most of all send back a good number
605 * of new signals that indicate whether or not the command
608 static bool api_cmd(UAContext *ua, const char *cmd)
611 ua->api = atoi(ua->argk[1]);
618 static int client_backups_handler(void *ctx, int num_field, char **row)
620 UAContext *ua = (UAContext *)ctx;
621 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
622 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
627 * Return the backups for this client
629 * .backups client=xxx fileset=yyy
632 static bool backupscmd(UAContext *ua, const char *cmd)
634 if (!open_client_db(ua)) {
637 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
638 strcmp(ua->argk[2], "fileset") != 0) {
641 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
642 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
643 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
646 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
647 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
648 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
654 static int sql_handler(void *ctx, int num_field, char **row)
656 UAContext *ua = (UAContext *)ctx;
657 POOL_MEM rows(PM_MESSAGE);
659 /* Check for nonsense */
660 if (num_field == 0 || row == NULL || row[0] == NULL) {
661 return 0; /* nothing returned */
663 for (int i=0; num_field--; i++) {
665 pm_strcpy(rows, NPRT(row[0]));
667 pm_strcat(rows, NPRT(row[i]));
669 pm_strcat(rows, "\t");
671 if (!rows.c_str() || !*rows.c_str()) {
674 ua->send_msg("%s", rows.c_str());
679 static bool sql_cmd(UAContext *ua, const char *cmd)
682 if (!open_client_db(ua)) {
685 index = find_arg_with_value(ua, "query");
687 ua->error_msg(_("query keyword not found.\n"));
690 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
691 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
692 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
698 static int one_handler(void *ctx, int num_field, char **row)
700 UAContext *ua = (UAContext *)ctx;
701 ua->send_msg("%s\n", row[0]);
705 static bool mediatypescmd(UAContext *ua, const char *cmd)
707 if (!open_client_db(ua)) {
710 if (!db_sql_query(ua->db,
711 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
712 one_handler, (void *)ua))
714 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
719 static bool mediacmd(UAContext *ua, const char *cmd)
721 if (!open_client_db(ua)) {
724 if (!db_sql_query(ua->db,
725 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
726 one_handler, (void *)ua))
728 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
733 static bool locationscmd(UAContext *ua, const char *cmd)
735 if (!open_client_db(ua)) {
738 if (!db_sql_query(ua->db,
739 "SELECT DISTINCT Location FROM Location ORDER BY Location",
740 one_handler, (void *)ua))
742 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
747 static bool levelscmd(UAContext *ua, const char *cmd)
749 ua->send_msg("Incremental\n");
750 ua->send_msg("Full\n");
751 ua->send_msg("Differential\n");
752 ua->send_msg("VirtualFull\n");
753 ua->send_msg("Catalog\n");
754 ua->send_msg("InitCatalog\n");
755 ua->send_msg("VolumeToCatalog\n");
759 static bool volstatuscmd(UAContext *ua, const char *cmd)
761 ua->send_msg("Append\n");
762 ua->send_msg("Full\n");
763 ua->send_msg("Used\n");
764 ua->send_msg("Recycle\n");
765 ua->send_msg("Purged\n");
766 ua->send_msg("Cleaning\n");
767 ua->send_msg("Error\n");
772 * Return default values for a job
774 static bool defaultscmd(UAContext *ua, const char *cmd)
782 if (ua->argc != 2 || !ua->argv[1]) {
787 if (strcmp(ua->argk[1], "job") == 0) {
788 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
791 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
794 ua->send_msg("job=%s", job->name());
795 ua->send_msg("pool=%s", job->pool->name());
796 ua->send_msg("messages=%s", job->messages->name());
797 ua->send_msg("client=%s", job->client->name());
798 get_job_storage(&store, job, NULL);
799 ua->send_msg("storage=%s", store.store->name());
800 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
801 ua->send_msg("level=%s", level_to_str(job->JobLevel));
802 ua->send_msg("type=%s", job_type_to_str(job->JobType));
803 ua->send_msg("fileset=%s", job->fileset->name());
804 ua->send_msg("enabled=%d", job->enabled);
805 ua->send_msg("catalog=%s", job->client->catalog->name());
808 /* Client defaults */
809 else if (strcmp(ua->argk[1], "client") == 0) {
810 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
813 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
815 ua->send_msg("client=%s", client->name());
816 ua->send_msg("address=%s", client->address);
817 ua->send_msg("fdport=%d", client->FDport);
818 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
819 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
820 ua->send_msg("autoprune=%d", client->AutoPrune);
821 ua->send_msg("catalog=%s", client->catalog->name());
824 /* Storage defaults */
825 else if (strcmp(ua->argk[1], "storage") == 0) {
826 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
829 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
832 ua->send_msg("storage=%s", storage->name());
833 ua->send_msg("address=%s", storage->address);
834 ua->send_msg("enabled=%d", storage->enabled);
835 ua->send_msg("media_type=%s", storage->media_type);
836 ua->send_msg("sdport=%d", storage->SDport);
837 device = (DEVICE *)storage->device->first();
838 ua->send_msg("device=%s", device->name());
839 if (storage->device->size() > 1) {
840 while ((device = (DEVICE *)storage->device->next())) {
841 ua->send_msg(",%s", device->name());
847 else if (strcmp(ua->argk[1], "pool") == 0) {
848 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
851 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
853 ua->send_msg("pool=%s", pool->name());
854 ua->send_msg("pool_type=%s", pool->pool_type);
855 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
856 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
857 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
858 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
859 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
860 ua->send_msg("max_volumes=%d", pool->max_volumes);
861 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
862 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
863 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
864 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
865 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
866 ua->send_msg("auto_prune=%d", pool->AutoPrune);
867 ua->send_msg("recycle=%d", pool->Recycle);