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);
72 static bool aopcmd(UAContext *ua, const char *cmd);
74 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd);
75 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd);
76 static bool dot_bvfs_update(UAContext *ua, const char *cmd);
78 static bool api_cmd(UAContext *ua, const char *cmd);
79 static bool sql_cmd(UAContext *ua, const char *cmd);
80 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
81 static bool dot_help_cmd(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_(".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)
170 if (!open_client_db(ua)) {
174 int pos = find_arg_with_value(ua, "jobid");
175 if (pos != -1 && is_a_number_list(ua->argv[pos])) {
177 pm_strcpy(jobids, ua->argv[pos]);
178 bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, jobids.c_str());
180 /* update cache for all jobids */
181 bvfs_update_cache(ua->jcr, ua->db);
186 static int bvfs_result_handler(void *ctx, int fields, char **row)
188 UAContext *ua = (UAContext *)ctx;
193 char empty[] = "A A A A A A A A A A A A A A";
195 lstat = (row[BVFS_LStat] && row[BVFS_LStat][0])?row[BVFS_LStat]:empty;
196 fileid = (row[BVFS_FileId] && row[BVFS_FileId][0])?row[BVFS_FileId]:"0";
198 memset(&statp, 0, sizeof(struct stat));
199 decode_stat(lstat, &statp, &LinkFI);
201 Dmsg1(0, "type=%s\n", row[0]);
202 if (bvfs_is_dir(row)) {
203 char *path = bvfs_basename_dir(row[BVFS_Name]);
204 ua->send_msg("%s\t0\t%s\t%s\t%s\t%s\n", row[BVFS_PathId], fileid,
205 row[BVFS_JobId], row[BVFS_LStat], path);
207 } else if (bvfs_is_file(row)) {
208 ua->send_msg("%s\t%s\t%s\t%s\t%s\t%s\n", row[BVFS_PathId],
209 row[BVFS_FilenameId], fileid, row[BVFS_JobId],
210 row[BVFS_LStat], row[BVFS_Name]);
216 static bool bvfs_parse_arg(UAContext *ua,
217 DBId_t *pathid, char **path, char **jobid,
218 int *limit, int *offset)
226 for (int i=1; i<ua->argc; i++) {
227 if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
228 if (is_a_number(ua->argv[i])) {
229 *pathid = str_to_int64(ua->argv[i]);
232 if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
236 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
237 if (is_a_number_list(ua->argv[i])) {
238 *jobid = ua->argv[i];
242 if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
243 if (is_a_number(ua->argv[i])) {
244 *limit = str_to_int64(ua->argv[i]);
248 if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
249 if (is_a_number(ua->argv[i])) {
250 *offset = str_to_int64(ua->argv[i]);
255 if (!((*pathid || *path) && *jobid)) {
259 if (!open_client_db(ua)) {
267 * .bvfs_lsfiles jobid=1,2,3,4 pathid=10
268 * .bvfs_lsfiles jobid=1,2,3,4 path=/
270 static bool dot_bvfs_lsfiles(UAContext *ua, const char *cmd)
273 int limit=2000, offset=0;
274 char *path=NULL, *jobid=NULL;
276 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
279 ua->error_msg("Can't find jobid, pathid or path argument\n");
280 return true; /* not enough param */
283 Bvfs fs(ua->jcr, ua->db);
284 fs.set_jobids(jobid);
285 fs.set_handler(bvfs_result_handler, ua);
294 fs.set_offset(offset);
302 * .bvfs_lsdirs jobid=1,2,3,4 pathid=10
303 * .bvfs_lsdirs jobid=1,2,3,4 path=/
304 * .bvfs_lsdirs jobid=1,2,3,4 path=
306 static bool dot_bvfs_lsdirs(UAContext *ua, const char *cmd)
309 int limit=2000, offset=0;
310 char *path=NULL, *jobid=NULL;
312 if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
315 ua->error_msg("Can't find jobid, pathid or path argument\n");
316 return true; /* not enough param */
319 Bvfs fs(ua->jcr, ua->db);
320 fs.set_jobids(jobid);
322 fs.set_handler(bvfs_result_handler, ua);
330 fs.set_offset(offset);
332 fs.ls_special_dirs();
338 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
344 static bool dot_help_cmd(UAContext *ua, const char *cmd)
350 static bool getmsgscmd(UAContext *ua, const char *cmd)
352 if (console_msg_pending) {
353 do_messages(ua, cmd);
359 static void do_storage_die(UAContext *ua, STORE *store)
365 lstore.store = store;
366 pm_strcpy(lstore.store_source, _("unknown source"));
367 set_wstorage(jcr, &lstore);
368 /* Try connecting for up to 15 seconds */
369 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
370 store->name(), store->address, store->SDport);
371 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
372 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
375 Dmsg0(120, _("Connected to storage daemon\n"));
376 sd = jcr->store_bsock;
378 if (sd->recv() >= 0) {
379 ua->send_msg("%s", sd->msg);
381 sd->signal(BNET_TERMINATE);
383 jcr->store_bsock = NULL;
387 static void do_client_die(UAContext *ua, CLIENT *client)
391 /* Connect to File daemon */
393 ua->jcr->client = client;
394 /* Try to connect for 15 seconds */
395 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
396 client->name(), client->address, client->FDport);
397 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
398 ua->error_msg(_("Failed to connect to Client.\n"));
401 Dmsg0(120, "Connected to file daemon\n");
402 fd = ua->jcr->file_bsock;
404 if (fd->recv() >= 0) {
405 ua->send_msg("%s", fd->msg);
407 fd->signal(BNET_TERMINATE);
409 ua->jcr->file_bsock = NULL;
414 * Create segmentation fault
416 static bool diecmd(UAContext *ua, const char *cmd)
424 Dmsg1(120, "diecmd:%s:\n", cmd);
427 for (i=1; i<ua->argc; i++) {
428 if (strcasecmp(ua->argk[i], "dir") == 0 ||
429 strcasecmp(ua->argk[i], "director") == 0) {
430 ua->send_msg(_("The Director will segment fault.\n"));
431 a = jcr->JobId; /* ref NULL pointer */
432 jcr->JobId = 1000; /* another ref NULL pointer */
435 if (strcasecmp(ua->argk[i], "client") == 0 ||
436 strcasecmp(ua->argk[i], "fd") == 0) {
439 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]);
441 do_client_die(ua, client);
445 client = select_client_resource(ua);
447 do_client_die(ua, client);
452 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
453 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
454 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
457 store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]);
459 do_storage_die(ua, store);
463 store = get_storage_resource(ua, false/*no default*/);
465 do_storage_die(ua, store);
471 * We didn't find an appropriate keyword above, so
474 start_prompt(ua, _("Available daemons are: \n"));
475 add_prompt(ua, _("Director"));
476 add_prompt(ua, _("Storage"));
477 add_prompt(ua, _("Client"));
478 switch(do_prompt(ua, "", _("Select daemon type to make die"), NULL, 0)) {
479 case 0: /* Director */
480 ua->send_msg(_("The Director will segment fault.\n"));
481 a = jcr->JobId; /* ref NULL pointer */
482 jcr->JobId = 1000; /* another ref NULL pointer */
485 store = get_storage_resource(ua, false/*no default*/);
487 do_storage_die(ua, store);
491 client = select_client_resource(ua);
493 do_client_die(ua, client);
505 * Dummy routine for non-development version
507 static bool diecmd(UAContext *ua, const char *cmd)
514 static bool jobscmd(UAContext *ua, const char *cmd)
518 foreach_res(job, R_JOB) {
519 if (acl_access_ok(ua, Job_ACL, job->name())) {
520 ua->send_msg("%s\n", job->name());
527 static bool filesetscmd(UAContext *ua, const char *cmd)
531 foreach_res(fs, R_FILESET) {
532 if (acl_access_ok(ua, FileSet_ACL, fs->name())) {
533 ua->send_msg("%s\n", fs->name());
540 static bool clientscmd(UAContext *ua, const char *cmd)
544 foreach_res(client, R_CLIENT) {
545 if (acl_access_ok(ua, Client_ACL, client->name())) {
546 ua->send_msg("%s\n", client->name());
553 static bool msgscmd(UAContext *ua, const char *cmd)
557 foreach_res(msgs, R_MSGS) {
558 ua->send_msg("%s\n", msgs->name());
564 static bool poolscmd(UAContext *ua, const char *cmd)
568 foreach_res(pool, R_POOL) {
569 if (acl_access_ok(ua, Pool_ACL, pool->name())) {
570 ua->send_msg("%s\n", pool->name());
577 static bool storagecmd(UAContext *ua, const char *cmd)
581 foreach_res(store, R_STORAGE) {
582 if (acl_access_ok(ua, Storage_ACL, store->name())) {
583 ua->send_msg("%s\n", store->name());
590 static bool aopcmd(UAContext *ua, const char *cmd)
592 ua->send_msg("None\n");
593 ua->send_msg("Truncate\n");
597 static bool typescmd(UAContext *ua, const char *cmd)
599 ua->send_msg("Backup\n");
600 ua->send_msg("Restore\n");
601 ua->send_msg("Admin\n");
602 ua->send_msg("Verify\n");
603 ua->send_msg("Migrate\n");
608 * If this command is called, it tells the director that we
609 * are a program that wants a sort of API, and hence,
610 * we will probably suppress certain output, include more
611 * error codes, and most of all send back a good number
612 * of new signals that indicate whether or not the command
615 static bool api_cmd(UAContext *ua, const char *cmd)
618 ua->api = atoi(ua->argk[1]);
625 static int client_backups_handler(void *ctx, int num_field, char **row)
627 UAContext *ua = (UAContext *)ctx;
628 ua->send_msg("| %s | %s | %s | %s | %s | %s | %s | %s |\n",
629 row[0], row[1], row[2], row[3], row[4], row[5], row[6], row[7], row[8]);
634 * Return the backups for this client
636 * .backups client=xxx fileset=yyy
639 static bool backupscmd(UAContext *ua, const char *cmd)
641 if (!open_client_db(ua)) {
644 if (ua->argc != 3 || strcmp(ua->argk[1], "client") != 0 ||
645 strcmp(ua->argk[2], "fileset") != 0) {
648 if (!acl_access_ok(ua, Client_ACL, ua->argv[1]) ||
649 !acl_access_ok(ua, FileSet_ACL, ua->argv[2])) {
650 ua->error_msg(_("Access to specified Client or FileSet not allowed.\n"));
653 Mmsg(ua->cmd, client_backups, ua->argv[1], ua->argv[2]);
654 if (!db_sql_query(ua->db, ua->cmd, client_backups_handler, (void *)ua)) {
655 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
661 static int sql_handler(void *ctx, int num_field, char **row)
663 UAContext *ua = (UAContext *)ctx;
664 POOL_MEM rows(PM_MESSAGE);
666 /* Check for nonsense */
667 if (num_field == 0 || row == NULL || row[0] == NULL) {
668 return 0; /* nothing returned */
670 for (int i=0; num_field--; i++) {
672 pm_strcpy(rows, NPRT(row[0]));
674 pm_strcat(rows, NPRT(row[i]));
676 pm_strcat(rows, "\t");
678 if (!rows.c_str() || !*rows.c_str()) {
681 ua->send_msg("%s", rows.c_str());
686 static bool sql_cmd(UAContext *ua, const char *cmd)
689 if (!open_client_db(ua)) {
692 index = find_arg_with_value(ua, "query");
694 ua->error_msg(_("query keyword not found.\n"));
697 if (!db_sql_query(ua->db, ua->argv[index], sql_handler, (void *)ua)) {
698 Dmsg1(100, "Query failed: ERR=%s\n", db_strerror(ua->db));
699 ua->error_msg(_("Query failed: %s. ERR=%s\n"), ua->cmd, db_strerror(ua->db));
705 static int one_handler(void *ctx, int num_field, char **row)
707 UAContext *ua = (UAContext *)ctx;
708 ua->send_msg("%s\n", row[0]);
712 static bool mediatypescmd(UAContext *ua, const char *cmd)
714 if (!open_client_db(ua)) {
717 if (!db_sql_query(ua->db,
718 "SELECT DISTINCT MediaType FROM MediaType ORDER BY MediaType",
719 one_handler, (void *)ua))
721 ua->error_msg(_("List MediaType failed: ERR=%s\n"), db_strerror(ua->db));
726 static bool mediacmd(UAContext *ua, const char *cmd)
728 if (!open_client_db(ua)) {
731 if (!db_sql_query(ua->db,
732 "SELECT DISTINCT Media.VolumeName FROM Media ORDER BY VolumeName",
733 one_handler, (void *)ua))
735 ua->error_msg(_("List Media failed: ERR=%s\n"), db_strerror(ua->db));
740 static bool locationscmd(UAContext *ua, const char *cmd)
742 if (!open_client_db(ua)) {
745 if (!db_sql_query(ua->db,
746 "SELECT DISTINCT Location FROM Location ORDER BY Location",
747 one_handler, (void *)ua))
749 ua->error_msg(_("List Location failed: ERR=%s\n"), db_strerror(ua->db));
754 static bool levelscmd(UAContext *ua, const char *cmd)
756 ua->send_msg("Incremental\n");
757 ua->send_msg("Full\n");
758 ua->send_msg("Differential\n");
759 ua->send_msg("VirtualFull\n");
760 ua->send_msg("Catalog\n");
761 ua->send_msg("InitCatalog\n");
762 ua->send_msg("VolumeToCatalog\n");
766 static bool volstatuscmd(UAContext *ua, const char *cmd)
768 ua->send_msg("Append\n");
769 ua->send_msg("Full\n");
770 ua->send_msg("Used\n");
771 ua->send_msg("Recycle\n");
772 ua->send_msg("Purged\n");
773 ua->send_msg("Cleaning\n");
774 ua->send_msg("Error\n");
779 * Return default values for a job
781 static bool defaultscmd(UAContext *ua, const char *cmd)
789 if (ua->argc != 2 || !ua->argv[1]) {
794 if (strcmp(ua->argk[1], "job") == 0) {
795 if (!acl_access_ok(ua, Job_ACL, ua->argv[1])) {
798 job = (JOB *)GetResWithName(R_JOB, ua->argv[1]);
801 ua->send_msg("job=%s", job->name());
802 ua->send_msg("pool=%s", job->pool->name());
803 ua->send_msg("messages=%s", job->messages->name());
804 ua->send_msg("client=%s", job->client->name());
805 get_job_storage(&store, job, NULL);
806 ua->send_msg("storage=%s", store.store->name());
807 ua->send_msg("where=%s", job->RestoreWhere?job->RestoreWhere:"");
808 ua->send_msg("level=%s", level_to_str(job->JobLevel));
809 ua->send_msg("type=%s", job_type_to_str(job->JobType));
810 ua->send_msg("fileset=%s", job->fileset->name());
811 ua->send_msg("enabled=%d", job->enabled);
812 ua->send_msg("catalog=%s", job->client->catalog->name());
815 /* Client defaults */
816 else if (strcmp(ua->argk[1], "client") == 0) {
817 if (!acl_access_ok(ua, Client_ACL, ua->argv[1])) {
820 client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[1]);
822 ua->send_msg("client=%s", client->name());
823 ua->send_msg("address=%s", client->address);
824 ua->send_msg("fdport=%d", client->FDport);
825 ua->send_msg("file_retention=%s", edit_uint64(client->FileRetention, ed1));
826 ua->send_msg("job_retention=%s", edit_uint64(client->JobRetention, ed1));
827 ua->send_msg("autoprune=%d", client->AutoPrune);
828 ua->send_msg("catalog=%s", client->catalog->name());
831 /* Storage defaults */
832 else if (strcmp(ua->argk[1], "storage") == 0) {
833 if (!acl_access_ok(ua, Storage_ACL, ua->argv[1])) {
836 storage = (STORE *)GetResWithName(R_STORAGE, ua->argv[1]);
839 ua->send_msg("storage=%s", storage->name());
840 ua->send_msg("address=%s", storage->address);
841 ua->send_msg("enabled=%d", storage->enabled);
842 ua->send_msg("media_type=%s", storage->media_type);
843 ua->send_msg("sdport=%d", storage->SDport);
844 device = (DEVICE *)storage->device->first();
845 ua->send_msg("device=%s", device->name());
846 if (storage->device->size() > 1) {
847 while ((device = (DEVICE *)storage->device->next())) {
848 ua->send_msg(",%s", device->name());
854 else if (strcmp(ua->argk[1], "pool") == 0) {
855 if (!acl_access_ok(ua, Pool_ACL, ua->argv[1])) {
858 pool = (POOL *)GetResWithName(R_POOL, ua->argv[1]);
860 ua->send_msg("pool=%s", pool->name());
861 ua->send_msg("pool_type=%s", pool->pool_type);
862 ua->send_msg("label_format=%s", pool->label_format?pool->label_format:"");
863 ua->send_msg("use_volume_once=%d", pool->use_volume_once);
864 ua->send_msg("purge_oldest_volume=%d", pool->purge_oldest_volume);
865 ua->send_msg("recycle_oldest_volume=%d", pool->recycle_oldest_volume);
866 ua->send_msg("recycle_current_volume=%d", pool->recycle_current_volume);
867 ua->send_msg("max_volumes=%d", pool->max_volumes);
868 ua->send_msg("vol_retention=%s", edit_uint64(pool->VolRetention, ed1));
869 ua->send_msg("vol_use_duration=%s", edit_uint64(pool->VolUseDuration, ed1));
870 ua->send_msg("max_vol_jobs=%d", pool->MaxVolJobs);
871 ua->send_msg("max_vol_files=%d", pool->MaxVolFiles);
872 ua->send_msg("max_vol_bytes=%s", edit_uint64(pool->MaxVolBytes, ed1));
873 ua->send_msg("auto_prune=%d", pool->AutoPrune);
874 ua->send_msg("recycle=%d", pool->Recycle);