2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2012 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
32 * Kern Sibbald, September MM
41 #undef _POSIX_C_SOURCE
44 #include "lib/pythonlib.h"
46 /* Imported Functions */
47 extern PyObject *job_getattr(PyObject *self, char *attrname);
48 extern int job_setattr(PyObject *self, char *attrname, PyObject *value);
50 #endif /* HAVE_PYTHON */
52 /* Imported subroutines */
54 /* Imported variables */
55 extern jobq_t job_queue; /* job queue */
58 /* Imported functions */
59 extern int autodisplay_cmd(UAContext *ua, const char *cmd);
60 extern int gui_cmd(UAContext *ua, const char *cmd);
61 extern int label_cmd(UAContext *ua, const char *cmd);
62 extern int list_cmd(UAContext *ua, const char *cmd);
63 extern int llist_cmd(UAContext *ua, const char *cmd);
64 extern int messagescmd(UAContext *ua, const char *cmd);
65 extern int prunecmd(UAContext *ua, const char *cmd);
66 extern int purgecmd(UAContext *ua, const char *cmd);
67 extern int querycmd(UAContext *ua, const char *cmd);
68 extern int relabel_cmd(UAContext *ua, const char *cmd);
69 extern int restore_cmd(UAContext *ua, const char *cmd);
70 extern int retentioncmd(UAContext *ua, const char *cmd);
71 extern int show_cmd(UAContext *ua, const char *cmd);
72 extern int sqlquerycmd(UAContext *ua, const char *cmd);
73 extern int status_cmd(UAContext *ua, const char *cmd);
74 extern int update_cmd(UAContext *ua, const char *cmd);
76 /* Forward referenced functions */
77 static int add_cmd(UAContext *ua, const char *cmd);
78 static int automount_cmd(UAContext *ua, const char *cmd);
79 static int cancel_cmd(UAContext *ua, const char *cmd);
80 static int create_cmd(UAContext *ua, const char *cmd);
81 static int delete_cmd(UAContext *ua, const char *cmd);
82 static int disable_cmd(UAContext *ua, const char *cmd);
83 static int enable_cmd(UAContext *ua, const char *cmd);
84 static int estimate_cmd(UAContext *ua, const char *cmd);
85 static int help_cmd(UAContext *ua, const char *cmd);
86 static int memory_cmd(UAContext *ua, const char *cmd);
87 static int mount_cmd(UAContext *ua, const char *cmd);
88 static int python_cmd(UAContext *ua, const char *cmd);
89 static int release_cmd(UAContext *ua, const char *cmd);
90 static int reload_cmd(UAContext *ua, const char *cmd);
91 static int setdebug_cmd(UAContext *ua, const char *cmd);
92 static int setip_cmd(UAContext *ua, const char *cmd);
93 static int time_cmd(UAContext *ua, const char *cmd);
94 static int trace_cmd(UAContext *ua, const char *cmd);
95 static int unmount_cmd(UAContext *ua, const char *cmd);
96 static int use_cmd(UAContext *ua, const char *cmd);
97 static int var_cmd(UAContext *ua, const char *cmd);
98 static int version_cmd(UAContext *ua, const char *cmd);
99 static int wait_cmd(UAContext *ua, const char *cmd);
101 static void do_job_delete(UAContext *ua, JobId_t JobId);
102 static bool delete_job_id_range(UAContext *ua, char *tok);
103 static int delete_volume(UAContext *ua);
104 static int delete_pool(UAContext *ua);
105 static void delete_job(UAContext *ua);
107 int qhelp_cmd(UAContext *ua, const char *cmd);
108 int quit_cmd(UAContext *ua, const char *cmd);
110 /* not all in alphabetical order. New commands are added after existing commands with similar letters
111 to prevent breakage of existing user scripts. */
113 const char *key; /* command */
114 int (*func)(UAContext *ua, const char *cmd); /* handler */
115 const char *help; /* main purpose */
116 const char *usage; /* all arguments to build usage */
117 const bool use_in_rs; /* Can use it in Console RunScript */
119 static struct cmdstruct commands[] = { /* Can use it in Console RunScript*/
120 { NT_("add"), add_cmd, _("Add media to a pool"), NT_("pool=<pool-name> storage=<storage> jobid=<JobId>"), false},
121 { NT_("autodisplay"), autodisplay_cmd,_("Autodisplay console messages"), NT_("on | off"), false},
122 { NT_("automount"), automount_cmd, _("Automount after label"), NT_("on | off"), false},
123 { NT_("cancel"), cancel_cmd, _("Cancel a job"), NT_("jobid=<number> job=<job-name> ujobid=<unique-jobid>"), false},
124 { NT_("create"), create_cmd, _("Create DB Pool from resource"), NT_("pool=<pool-name>"), false},
125 { NT_("delete"), delete_cmd, _("Delete volume, pool or job"), NT_("volume=<vol-name> pool=<pool-name> jobid=<id>"), true},
126 { NT_("disable"), disable_cmd, _("Disable a job"), NT_("job=<name>"), true},
127 { NT_("enable"), enable_cmd, _("Enable a job"), NT_("job=<name>"), true},
128 { NT_("estimate"), estimate_cmd, _("Performs FileSet estimate, listing gives full listing"),
129 NT_("fileset=<fs> client=<cli> level=<level> accurate=<yes/no> job=<job> listing"), true},
131 { NT_("exit"), quit_cmd, _("Terminate Bconsole session"), NT_(""), false},
132 { NT_("gui"), gui_cmd, _("Non-interactive gui mode"), NT_("on | off"), false},
133 { NT_("help"), help_cmd, _("Print help on specific command"),
134 NT_("add autodisplay automount cancel create delete disable\n\tenable estimate exit gui label list llist"
135 "\n\tmessages memory mount prune purge python quit query\n\trestore relabel release reload run status"
136 "\n\tsetdebug setip show sqlquery time trace unmount\n\tumount update use var version wait"), false},
138 { NT_("label"), label_cmd, _("Label a tape"), NT_("storage=<storage> volume=<vol> pool=<pool> slot=<slot> barcodes"), false},
139 { NT_("list"), list_cmd, _("List objects from catalog"),
140 NT_("pools | jobs | jobtotals | volume | media <pool=pool-name> | files jobid=<nn> | copies jobid=<nn>"), true},
142 { NT_("llist"), llist_cmd, _("Full or long list like list command"),
143 NT_("pools | jobs | jobtotals | media <pool=pool-name> | files jobid=<nn> | copies jobid=<nn>"), true},
145 { NT_("messages"), messagescmd, _("Display pending messages"), NT_(""), false},
146 { NT_("memory"), memory_cmd, _("Print current memory usage"), NT_(""), true},
147 { NT_("mount"), mount_cmd, _("Mount storage"),
148 NT_("storage=<storage-name> slot=<num> drive=<num> [ jobid=<id> | job=<job-name> ]"), false},
150 { NT_("prune"), prunecmd, _("Prune expired records from catalog"),
151 NT_("files | jobs | pool=<pool> | client=<client-name> | volume=<volume-name> "), true},
153 { NT_("purge"), purgecmd, _("Purge records from catalog"), NT_("files jobs volume=<vol> [action=<action> devicetype=<type> pool=<pool> allpools storage=<st> drive=<num>]"), true},
154 { NT_("python"), python_cmd, _("Python control commands"), NT_(""), false},
155 { NT_("quit"), quit_cmd, _("Terminate Bconsole session"), NT_(""), false},
156 { NT_("query"), querycmd, _("Query catalog"), NT_(""), false},
157 { NT_("restore"), restore_cmd, _("Restore files"),
158 NT_("where=</path> client=<client> storage=<storage> bootstrap=<file> "
160 "\n\tcomment=<text> jobid=<jobid> done select all"), false},
162 { NT_("relabel"), relabel_cmd, _("Relabel a tape"),
163 NT_("storage=<storage-name> oldvolume=<old-volume-name>\n\tvolume=<newvolume-name> pool=<pool>"), false},
165 { NT_("release"), release_cmd, _("Release storage"), NT_("storage=<storage-name>"), false},
166 { NT_("reload"), reload_cmd, _("Reload conf file"), NT_(""), true},
167 { NT_("run"), run_cmd, _("Run a job"),
168 NT_("job=<job-name> client=<client-name>\n\tfileset=<FileSet-name> level=<level-keyword>\n\tstorage=<storage-name>"
169 "where=<directory-prefix>\n\twhen=<universal-time-specification>\n\tcomment=<text> yes"), false},
171 { NT_("status"), status_cmd, _("Report status"),
172 NT_("all | dir=<dir-name> | director | client=<client-name> | storage=<storage-name> slots | days=nnn"), true},
174 { NT_("setdebug"), setdebug_cmd, _("Sets debug level"),
175 NT_("level=<nn> trace=0/1 client=<client-name> | dir | storage=<storage-name> | all"), true},
177 { NT_("setip"), setip_cmd, _("Sets new client address -- if authorized"), NT_(""), false},
178 { NT_("show"), show_cmd, _("Show resource records"),
179 NT_("job=<xxx> | pool=<yyy> | fileset=<aaa> schedule=<sss> | client=<zzz> | disabled | all"), true},
181 { NT_("sqlquery"), sqlquerycmd, _("Use SQL to query catalog"), NT_(""), false},
182 { NT_("time"), time_cmd, _("Print current time"), NT_(""), true},
183 { NT_("trace"), trace_cmd, _("Turn on/off trace to file"), NT_("on | off"), true},
184 { NT_("unmount"), unmount_cmd, _("Unmount storage"),
185 NT_("storage=<storage-name> [ drive=<num> ] | jobid=<id> | job=<job-name>"), false},
187 { NT_("umount"), unmount_cmd, _("Umount - for old-time Unix guys, see unmount"),
188 NT_("storage=<storage-name> [ drive=<num> ] | jobid=<id> | job=<job-name>"), false},
190 { NT_("update"), update_cmd, _("Update volume, pool or stats"),
191 NT_("stats\n\tpool=<poolname>\n\tslots storage=<storage> scan"
192 "\n\tvolume=<volname> volstatus=<status> volretention=<time-def>"
193 "\n\t pool=<pool> recycle=<yes/no> slot=<number>\n\t inchanger=<yes/no>"
194 "\n\t maxvolbytes=<size> maxvolfiles=<nb> maxvoljobs=<nb>"
195 "\n\t enable=<yes/no> recyclepool=<pool> actiononpurge=<action>"),true},
196 { NT_("use"), use_cmd, _("Use catalog xxx"), NT_("catalog=<catalog>"), false},
197 { NT_("var"), var_cmd, _("Does variable expansion"), NT_(""), false},
198 { NT_("version"), version_cmd, _("Print Director version"), NT_(""), true},
199 { NT_("wait"), wait_cmd, _("Wait until no jobs are running"),
200 NT_("jobname=<name> | jobid=<nnn> | ujobid=<complete_name>"), false}
203 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
206 * Execute a command from the UA
208 bool do_a_command(UAContext *ua)
214 BSOCK *user = ua->UA_sock;
217 Dmsg1(900, "Command: %s\n", ua->argk[0]);
222 while (ua->jcr->wstorage->size()) {
223 ua->jcr->wstorage->remove(0);
226 len = strlen(ua->argk[0]);
227 for (i=0; i<comsize; i++) { /* search for command */
228 if (strncasecmp(ua->argk[0], commands[i].key, len) == 0) {
229 /* Check if command permitted, but "quit" is always OK */
230 if (strcmp(ua->argk[0], NT_("quit")) != 0 &&
231 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
234 /* Check if this command is authorized in RunScript */
235 if (ua->runscript && !commands[i].use_in_rs) {
236 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
239 if (ua->api) user->signal(BNET_CMD_BEGIN);
240 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
241 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
247 ua->error_msg(_("%s: is an invalid command.\n"), ua->argk[0]);
254 * This is a common routine used to stuff the Pool DB record defaults
255 * into the Media DB record just before creating a media (Volume)
258 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
260 mr->PoolId = pr->PoolId;
261 bstrncpy(mr->VolStatus, NT_("Append"), sizeof(mr->VolStatus));
262 mr->Recycle = pr->Recycle;
263 mr->VolRetention = pr->VolRetention;
264 mr->VolUseDuration = pr->VolUseDuration;
265 mr->ActionOnPurge = pr->ActionOnPurge;
266 mr->RecyclePoolId = pr->RecyclePoolId;
267 mr->MaxVolJobs = pr->MaxVolJobs;
268 mr->MaxVolFiles = pr->MaxVolFiles;
269 mr->MaxVolBytes = pr->MaxVolBytes;
270 mr->LabelType = pr->LabelType;
276 * Add Volumes to an existing Pool
278 static int add_cmd(UAContext *ua, const char *cmd)
282 int num, i, max, startnum;
283 char name[MAX_NAME_LENGTH];
285 int Slot = 0, InChanger = 0;
288 "You probably don't want to be using this command since it\n"
289 "creates database records without labeling the Volumes.\n"
290 "You probably want to use the \"label\" command.\n\n"));
292 if (!open_client_db(ua)) {
296 memset(&pr, 0, sizeof(pr));
298 if (!get_pool_dbr(ua, &pr)) {
302 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
303 pr.MaxVols, pr.PoolType);
305 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
306 ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
307 if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
310 pr.MaxVols = ua->pint32_val;
314 if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
315 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
316 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
320 if (pr.MaxVols == 0) {
323 max = pr.MaxVols - pr.NumVols;
327 bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
328 if (!get_pint(ua, buf)) {
331 num = ua->pint32_val;
332 if (num < 0 || num > max) {
333 ua->warning_msg(_("The number must be between 0 and %d\n"), max);
341 if (!get_cmd(ua, _("Enter Volume name: "))) {
345 if (!get_cmd(ua, _("Enter base volume name: "))) {
349 /* Don't allow | in Volume name because it is the volume separator character */
350 if (!is_volume_name_legal(ua, ua->cmd)) {
353 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
354 ua->warning_msg(_("Volume name too long.\n"));
357 if (strlen(ua->cmd) == 0) {
358 ua->warning_msg(_("Volume name must be at least one character long.\n"));
364 bstrncpy(name, ua->cmd, sizeof(name));
366 bstrncat(name, "%04d", sizeof(name));
369 if (!get_pint(ua, _("Enter the starting number: "))) {
372 startnum = ua->pint32_val;
374 ua->warning_msg(_("Start number must be greater than zero.\n"));
384 if (store && store->autochanger) {
385 if (!get_pint(ua, _("Enter slot (0 for none): "))) {
388 Slot = ua->pint32_val;
389 if (!get_yesno(ua, _("InChanger? yes/no: "))) {
392 InChanger = ua->pint32_val;
395 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
396 for (i=startnum; i < num+startnum; i++) {
397 bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
399 mr.InChanger = InChanger;
401 set_storageid_in_mr(store, &mr);
402 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
403 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
404 ua->error_msg("%s", db_strerror(ua->db));
409 Dmsg0(200, "Update pool record.\n");
410 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
411 ua->warning_msg("%s", db_strerror(ua->db));
414 ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
420 * Turn auto mount on/off
425 int automount_cmd(UAContext *ua, const char *cmd)
430 if (!get_cmd(ua, _("Turn on or off? "))) {
438 ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
445 static int cancel_cmd(UAContext *ua, const char *cmd)
447 JCR *jcr = select_running_job(ua, "cancel");
451 int ret = cancel_job(ua, jcr);
457 * This is a common routine to create or update a
458 * Pool DB base record from a Pool Resource. We handle
459 * the setting of MaxVols and NumVols slightly differently
460 * depending on if we are creating the Pool or we are
461 * simply bringing it into agreement with the resource (updage).
463 * Caution : RecyclePoolId isn't setup in this function.
464 * You can use set_pooldbr_recyclepoolid();
467 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
469 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
470 if (op == POOL_OP_CREATE) {
471 pr->MaxVols = pool->max_volumes;
473 } else { /* update pool */
474 if (pr->MaxVols != pool->max_volumes) {
475 pr->MaxVols = pool->max_volumes;
477 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
478 pr->MaxVols = pr->NumVols;
481 pr->LabelType = pool->LabelType;
482 pr->UseOnce = pool->use_volume_once;
483 pr->UseCatalog = pool->use_catalog;
484 pr->Recycle = pool->Recycle;
485 pr->VolRetention = pool->VolRetention;
486 pr->VolUseDuration = pool->VolUseDuration;
487 pr->MaxVolJobs = pool->MaxVolJobs;
488 pr->MaxVolFiles = pool->MaxVolFiles;
489 pr->MaxVolBytes = pool->MaxVolBytes;
490 pr->AutoPrune = pool->AutoPrune;
491 pr->ActionOnPurge = pool->action_on_purge;
492 pr->Recycle = pool->Recycle;
493 if (pool->label_format) {
494 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
496 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
500 /* set/update Pool.RecyclePoolId and Pool.ScratchPoolId in Catalog */
501 int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
505 if (!pool->RecyclePool && !pool->ScratchPool) {
509 memset(&pr, 0, sizeof(POOL_DBR));
510 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
512 if (!db_get_pool_record(jcr, db, &pr)) {
513 return -1; /* not exists in database */
516 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
518 if (!set_pooldbr_references(jcr, db, &pr, pool)) {
519 return -1; /* error */
522 if (!db_update_pool_record(jcr, db, &pr)) {
523 return -1; /* error */
528 /* set POOL_DBR.RecyclePoolId and POOL_DBR.ScratchPoolId from Pool resource
529 * works with set_pooldbr_from_poolres
531 bool set_pooldbr_references(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
536 if (pool->RecyclePool) {
537 memset(&rpool, 0, sizeof(POOL_DBR));
539 bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
540 if (db_get_pool_record(jcr, db, &rpool)) {
541 pr->RecyclePoolId = rpool.PoolId;
543 Jmsg(jcr, M_WARNING, 0,
544 _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
545 "Try to update it with 'update pool=%s'\n"),
546 pool->name(), rpool.Name, rpool.Name,pool->name());
550 } else { /* no RecyclePool used, set it to 0 */
551 pr->RecyclePoolId = 0;
554 if (pool->ScratchPool) {
555 memset(&rpool, 0, sizeof(POOL_DBR));
557 bstrncpy(rpool.Name, pool->ScratchPool->name(), sizeof(rpool.Name));
558 if (db_get_pool_record(jcr, db, &rpool)) {
559 pr->ScratchPoolId = rpool.PoolId;
561 Jmsg(jcr, M_WARNING, 0,
562 _("Can't set %s ScratchPool to %s, %s is not in database.\n" \
563 "Try to update it with 'update pool=%s'\n"),
564 pool->name(), rpool.Name, rpool.Name,pool->name());
567 } else { /* no ScratchPool used, set it to 0 */
568 pr->ScratchPoolId = 0;
576 * Create a pool record from a given Pool resource
577 * Also called from backup.c
578 * Returns: -1 on error
579 * 0 record already exists
583 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
587 memset(&pr, 0, sizeof(POOL_DBR));
589 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
591 if (db_get_pool_record(jcr, db, &pr)) {
593 if (op == POOL_OP_UPDATE) { /* update request */
594 set_pooldbr_from_poolres(&pr, pool, op);
595 set_pooldbr_references(jcr, db, &pr, pool);
596 db_update_pool_record(jcr, db, &pr);
598 return 0; /* exists */
601 set_pooldbr_from_poolres(&pr, pool, op);
602 set_pooldbr_references(jcr, db, &pr, pool);
604 if (!db_create_pool_record(jcr, db, &pr)) {
605 return -1; /* error */
613 * Create a Pool Record in the database.
614 * It is always created from the Resource record.
616 static int create_cmd(UAContext *ua, const char *cmd)
620 if (!open_client_db(ua)) {
624 pool = get_pool_resource(ua);
629 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
631 ua->error_msg(_("Error: Pool %s already exists.\n"
632 "Use update to change it.\n"), pool->name());
636 ua->error_msg("%s", db_strerror(ua->db));
642 ua->send_msg(_("Pool %s created.\n"), pool->name());
647 extern DIRRES *director;
648 extern char *configfile;
651 * Python control command
652 * python restart (restarts interpreter)
654 static int python_cmd(UAContext *ua, const char *cmd)
657 init_python_interpreter_args python_args;
659 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
660 term_python_interpreter();
662 python_args.progname = director->name();
663 python_args.scriptdir = director->scripts_directory;
664 python_args.modulename = "DirStartUp";
665 python_args.configfile = configfile;
666 python_args.workingdir = director->working_directory;
667 python_args.job_getattr = job_getattr;
668 python_args.job_setattr = job_setattr;
670 init_python_interpreter(&python_args);
672 ua->send_msg(_("Python interpreter restarted.\n"));
674 #endif /* HAVE_PYTHON */
675 ua->warning_msg(_("Nothing done.\n"));
678 #endif /* HAVE_PYTHON */
683 * Set a new address in a Client resource. We do this only
684 * if the Console name is the same as the Client name
685 * and the Console can access the client.
687 static int setip_cmd(UAContext *ua, const char *cmd)
691 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
692 ua->error_msg(_("Unauthorized command from this console.\n"));
696 client = GetClientResWithName(ua->cons->name());
699 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
702 if (client->address) {
703 free(client->address);
705 /* MA Bug 6 remove ifdef */
706 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
707 client->address = bstrdup(buf);
708 ua->send_msg(_("Client \"%s\" address set to %s\n"),
709 client->name(), client->address);
716 static void do_en_disable_cmd(UAContext *ua, bool setting)
721 i = find_arg_with_value(ua, NT_("job"));
723 job = select_enable_disable_job_resource(ua, setting);
729 job = GetJobResWithName(ua->argv[i]);
733 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
737 if (!acl_access_ok(ua, Job_ACL, job->name())) {
738 ua->error_msg(_("Unauthorized command from this console.\n"));
741 job->enabled = setting;
742 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
746 static int enable_cmd(UAContext *ua, const char *cmd)
748 do_en_disable_cmd(ua, true);
752 static int disable_cmd(UAContext *ua, const char *cmd)
754 do_en_disable_cmd(ua, false);
758 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
764 lstore.store = store;
765 pm_strcpy(lstore.store_source, _("unknown source"));
766 set_wstorage(jcr, &lstore);
767 /* Try connecting for up to 15 seconds */
768 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
769 store->name(), store->address, store->SDport);
770 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
771 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
774 Dmsg0(120, _("Connected to storage daemon\n"));
775 sd = jcr->store_bsock;
776 sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
777 if (sd->recv() >= 0) {
778 ua->send_msg("%s", sd->msg);
780 sd->signal(BNET_TERMINATE);
782 jcr->store_bsock = NULL;
787 * For the client, we have the following values that can be set
788 * level = debug level
789 * trace = send debug output to a file
790 * hangup = how many records to send to SD before hanging up
791 * obviously this is most useful for testing restarting
794 static void do_client_setdebug(UAContext *ua, CLIENT *client,
795 int level, int trace, int hangup)
799 /* Connect to File daemon */
801 ua->jcr->client = client;
802 /* Try to connect for 15 seconds */
803 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
804 client->name(), client->address, client->FDport);
805 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
806 ua->error_msg(_("Failed to connect to Client.\n"));
809 Dmsg0(120, "Connected to file daemon\n");
810 fd = ua->jcr->file_bsock;
811 fd->fsend("setdebug=%d trace=%d hangup=%d\n", level, trace, hangup);
812 if (fd->recv() >= 0) {
813 ua->send_msg("%s", fd->msg);
815 fd->signal(BNET_TERMINATE);
817 ua->jcr->file_bsock = NULL;
822 static void do_all_setdebug(UAContext *ua, int level, int trace_flag, int hangup)
824 STORE *store, **unique_store;
825 CLIENT *client, **unique_client;
831 /* Count Storage items */
835 foreach_res(store, R_STORAGE) {
838 unique_store = (STORE **) malloc(i * sizeof(STORE));
839 /* Find Unique Storage address/port */
840 store = (STORE *)GetNextRes(R_STORAGE, NULL);
842 unique_store[i++] = store;
843 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
845 for (j=0; j<i; j++) {
846 if (strcmp(unique_store[j]->address, store->address) == 0 &&
847 unique_store[j]->SDport == store->SDport) {
853 unique_store[i++] = store;
854 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
859 /* Call each unique Storage daemon */
860 for (j=0; j<i; j++) {
861 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
865 /* Count Client items */
869 foreach_res(client, R_CLIENT) {
872 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
873 /* Find Unique Client address/port */
874 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
876 unique_client[i++] = client;
877 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
879 for (j=0; j<i; j++) {
880 if (strcmp(unique_client[j]->address, client->address) == 0 &&
881 unique_client[j]->FDport == client->FDport) {
887 unique_client[i++] = client;
888 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
893 /* Call each unique File daemon */
894 for (j=0; j<i; j++) {
895 do_client_setdebug(ua, unique_client[j], level, trace_flag, hangup);
901 * setdebug level=nn all trace=1/0
903 static int setdebug_cmd(UAContext *ua, const char *cmd)
912 Dmsg1(120, "setdebug:%s:\n", cmd);
915 i = find_arg_with_value(ua, "level");
917 level = atoi(ua->argv[i]);
920 if (!get_pint(ua, _("Enter new debug level: "))) {
923 level = ua->pint32_val;
926 /* Look for trace flag. -1 => not change */
927 i = find_arg_with_value(ua, "trace");
929 trace_flag = atoi(ua->argv[i]);
930 if (trace_flag > 0) {
935 /* Look for hangup (debug only)flag. -1 => not change */
936 i = find_arg_with_value(ua, "hangup");
938 hangup = atoi(ua->argv[i]);
943 for (i=1; i<ua->argc; i++) {
944 if (strcasecmp(ua->argk[i], "all") == 0) {
945 do_all_setdebug(ua, level, trace_flag, hangup);
948 if (strcasecmp(ua->argk[i], "dir") == 0 ||
949 strcasecmp(ua->argk[i], "director") == 0) {
951 set_trace(trace_flag);
954 if (strcasecmp(ua->argk[i], "client") == 0 ||
955 strcasecmp(ua->argk[i], "fd") == 0) {
958 client = GetClientResWithName(ua->argv[i]);
960 do_client_setdebug(ua, client, level, trace_flag, hangup);
964 client = select_client_resource(ua);
966 do_client_setdebug(ua, client, level, trace_flag, hangup);
971 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
972 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
973 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
976 store = GetStoreResWithName(ua->argv[i]);
978 do_storage_setdebug(ua, store, level, trace_flag);
982 store = get_storage_resource(ua, false/*no default*/);
984 do_storage_setdebug(ua, store, level, trace_flag);
990 * We didn't find an appropriate keyword above, so
993 start_prompt(ua, _("Available daemons are: \n"));
994 add_prompt(ua, _("Director"));
995 add_prompt(ua, _("Storage"));
996 add_prompt(ua, _("Client"));
997 add_prompt(ua, _("All"));
998 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
999 case 0: /* Director */
1000 debug_level = level;
1001 set_trace(trace_flag);
1004 store = get_storage_resource(ua, false/*no default*/);
1006 do_storage_setdebug(ua, store, level, trace_flag);
1010 client = select_client_resource(ua);
1012 do_client_setdebug(ua, client, level, trace_flag, hangup);
1016 do_all_setdebug(ua, level, trace_flag, hangup);
1025 * Turn debug tracing to file on/off
1027 static int trace_cmd(UAContext *ua, const char *cmd)
1031 if (ua->argc != 2) {
1032 if (!get_cmd(ua, _("Turn on or off? "))) {
1037 onoff = ua->argk[1];
1040 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1045 static int var_cmd(UAContext *ua, const char *cmd)
1047 POOLMEM *val = get_pool_memory(PM_FNAME);
1050 if (!open_client_db(ua)) {
1053 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1056 while (*var == ' ') { /* skip spaces */
1059 Dmsg1(100, "Var=%s:\n", var);
1060 variable_expansion(ua->jcr, var, &val);
1061 ua->send_msg("%s\n", val);
1062 free_pool_memory(val);
1066 static int estimate_cmd(UAContext *ua, const char *cmd)
1069 CLIENT *client = NULL;
1070 FILESET *fileset = NULL;
1072 char since[MAXSTRING];
1076 jcr->setJobLevel(L_FULL);
1077 for (int i=1; i<ua->argc; i++) {
1078 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1079 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1081 client = GetClientResWithName(ua->argv[i]);
1083 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1086 if (!acl_access_ok(ua, Client_ACL, client->name())) {
1087 ua->error_msg(_("No authorization for Client \"%s\"\n"), client->name());
1092 ua->error_msg(_("Client name missing.\n"));
1096 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1098 job = GetJobResWithName(ua->argv[i]);
1100 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1103 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1104 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1109 ua->error_msg(_("Job name missing.\n"));
1114 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1116 fileset = GetFileSetResWithName(ua->argv[i]);
1118 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1121 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1122 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1127 ua->error_msg(_("Fileset name missing.\n"));
1131 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1135 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1137 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1138 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1142 ua->error_msg(_("Level value missing.\n"));
1146 if (strcasecmp(ua->argk[i], NT_("accurate")) == 0) {
1148 if (!is_yesno(ua->argv[i], &accurate)) {
1149 ua->error_msg(_("Invalid value for accurate. "
1150 "It must be yes or no.\n"));
1154 ua->error_msg(_("Accurate value missing.\n"));
1159 if (!job && !(client && fileset)) {
1160 if (!(job = select_job_resource(ua))) {
1165 job = GetJobResWithName(ua->argk[1]);
1167 ua->error_msg(_("No job specified.\n"));
1170 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1171 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1176 client = job->client;
1179 fileset = job->fileset;
1181 jcr->client = client;
1182 jcr->fileset = fileset;
1184 if (job->pool->catalog) {
1185 ua->catalog = job->pool->catalog;
1187 ua->catalog = client->catalog;
1195 jcr->setJobType(JT_BACKUP);
1196 jcr->start_time = time(NULL);
1197 init_jcr_job_record(jcr);
1199 if (!get_or_create_client_record(jcr)) {
1202 if (!get_or_create_fileset_record(jcr)) {
1206 get_level_since_time(ua->jcr, since, sizeof(since));
1208 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1209 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1210 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1211 ua->error_msg(_("Failed to connect to Client.\n"));
1215 /* The level string change if accurate mode is enabled */
1216 if (accurate >= 0) {
1217 jcr->accurate = accurate;
1219 jcr->accurate = job->accurate;
1222 if (!send_level_command(jcr)) {
1226 if (!send_include_list(jcr)) {
1227 ua->error_msg(_("Error sending include list.\n"));
1231 if (!send_exclude_list(jcr)) {
1232 ua->error_msg(_("Error sending exclude list.\n"));
1237 * If the job is in accurate mode, we send the list of
1240 Dmsg1(40, "estimate accurate=%d\n", jcr->accurate);
1241 if (!send_accurate_current_files(jcr)) {
1245 jcr->file_bsock->fsend("estimate listing=%d\n", listing);
1246 while (jcr->file_bsock->recv() >= 0) {
1247 ua->send_msg("%s", jcr->file_bsock->msg);
1251 if (jcr->file_bsock) {
1252 jcr->file_bsock->signal(BNET_TERMINATE);
1253 jcr->file_bsock->close();
1254 jcr->file_bsock = NULL;
1263 static int time_cmd(UAContext *ua, const char *cmd)
1266 time_t ttime = time(NULL);
1268 (void)localtime_r(&ttime, &tm);
1269 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1270 ua->send_msg("%s\n", sdt);
1275 * reload the conf file
1277 extern "C" void reload_config(int sig);
1279 static int reload_cmd(UAContext *ua, const char *cmd)
1286 * Delete Pool records (should purge Media with it).
1288 * delete pool=<pool-name>
1289 * delete volume pool=<pool-name> volume=<name>
1292 static int delete_cmd(UAContext *ua, const char *cmd)
1294 static const char *keywords[] = {
1300 if (!open_client_db(ua)) {
1304 switch (find_arg_keyword(ua, keywords)) {
1313 while ((i=find_arg(ua, "jobid")) > 0) {
1315 *ua->argk[i] = 0; /* zap keyword already visited */
1323 "In general it is not a good idea to delete either a\n"
1324 "Pool or a Volume since they may contain data.\n\n"));
1326 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1337 ua->warning_msg(_("Nothing done.\n"));
1345 * delete_job has been modified to parse JobID lists like the
1347 * delete JobID=3,4,6,7-11,14
1349 * Thanks to Phil Stracchino for the above addition.
1352 static void delete_job(UAContext *ua)
1357 int i = find_arg_with_value(ua, NT_("jobid"));
1359 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1360 s = bstrdup(ua->argv[i]);
1363 * We could use strtok() here. But we're not going to, because:
1364 * (a) strtok() is deprecated, having been replaced by strsep();
1365 * (b) strtok() is broken in significant ways.
1366 * we could use strsep() instead, but it's not universally available.
1367 * so we grow our own using strchr().
1369 sep = strchr(tok, ',');
1370 while (sep != NULL) {
1372 if (!delete_job_id_range(ua, tok)) {
1373 JobId = str_to_int64(tok);
1374 do_job_delete(ua, JobId);
1377 sep = strchr(tok, ',');
1379 /* pick up the last token */
1380 if (!delete_job_id_range(ua, tok)) {
1381 JobId = str_to_int64(tok);
1382 do_job_delete(ua, JobId);
1387 JobId = str_to_int64(ua->argv[i]);
1388 do_job_delete(ua, JobId);
1390 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1393 JobId = ua->int64_val;
1394 do_job_delete(ua, JobId);
1399 * we call delete_job_id_range to parse range tokens and iterate over ranges
1401 static bool delete_job_id_range(UAContext *ua, char *tok)
1406 tok2 = strchr(tok, '-');
1412 j1 = str_to_int64(tok);
1413 j2 = str_to_int64(tok2);
1414 for (j=j1; j<=j2; j++) {
1415 do_job_delete(ua, j);
1421 * do_job_delete now performs the actual delete operation atomically
1423 static void do_job_delete(UAContext *ua, JobId_t JobId)
1427 edit_int64(JobId, ed1);
1428 purge_jobs_from_catalog(ua, ed1);
1429 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1433 * Delete media records from database -- dangerous
1435 static int delete_volume(UAContext *ua)
1441 if (!select_media_dbr(ua, &mr)) {
1444 ua->warning_msg(_("\nThis command will delete volume %s\n"
1445 "and all Jobs saved on that volume from the Catalog\n"),
1448 if (find_arg(ua, "yes") >= 0) {
1449 ua->pint32_val = 1; /* Have "yes" on command line already" */
1451 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1453 if (!get_yesno(ua, buf)) {
1457 if (!ua->pint32_val) {
1461 /* If not purged, do it */
1462 if (strcmp(mr.VolStatus, "Purged") != 0) {
1463 if (!db_get_volume_jobids(ua->jcr, ua->db, &mr, &lst)) {
1464 ua->error_msg(_("Can't list jobs on this volume\n"));
1468 purge_jobs_from_catalog(ua, lst.list);
1472 db_delete_media_record(ua->jcr, ua->db, &mr);
1477 * Delete a pool record from the database -- dangerous
1479 static int delete_pool(UAContext *ua)
1484 memset(&pr, 0, sizeof(pr));
1486 if (!get_pool_dbr(ua, &pr)) {
1489 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1491 if (!get_yesno(ua, buf)) {
1494 if (ua->pint32_val) {
1495 db_delete_pool_record(ua->jcr, ua->db, &pr);
1500 int memory_cmd(UAContext *ua, const char *cmd)
1502 garbage_collect_memory();
1503 list_dir_status_header(ua);
1504 sm_dump(false, true);
1508 static void do_mount_cmd(UAContext *ua, const char *command)
1513 char dev_name[MAX_NAME_LENGTH];
1517 if (!open_client_db(ua)) {
1520 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1522 store.store = get_storage_resource(ua, true/*arg is storage*/);
1526 pm_strcpy(store.store_source, _("unknown source"));
1527 set_wstorage(jcr, &store);
1528 drive = get_storage_drive(ua, store.store);
1529 if (strcmp(command, "mount") == 0) {
1530 slot = get_storage_slot(ua, store.store);
1533 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1534 store.store->media_type, store.store->dev_name(), drive);
1536 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1537 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1540 sd = jcr->store_bsock;
1541 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1542 bash_spaces(dev_name);
1544 sd->fsend("%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1546 sd->fsend("%s %s drive=%d", command, dev_name, drive);
1548 while (sd->recv() >= 0) {
1549 ua->send_msg("%s", sd->msg);
1551 sd->signal(BNET_TERMINATE);
1553 jcr->store_bsock = NULL;
1557 * mount [storage=<name>] [drive=nn] [slot=mm]
1559 static int mount_cmd(UAContext *ua, const char *cmd)
1561 do_mount_cmd(ua, "mount"); /* mount */
1567 * unmount [storage=<name>] [drive=nn]
1569 static int unmount_cmd(UAContext *ua, const char *cmd)
1571 do_mount_cmd(ua, "unmount"); /* unmount */
1577 * release [storage=<name>] [drive=nn]
1579 static int release_cmd(UAContext *ua, const char *cmd)
1581 do_mount_cmd(ua, "release"); /* release */
1588 * use catalog=<name>
1590 static int use_cmd(UAContext *ua, const char *cmd)
1592 CAT *oldcatalog, *catalog;
1595 close_db(ua); /* close any previously open db */
1596 oldcatalog = ua->catalog;
1598 if (!(catalog = get_catalog_resource(ua))) {
1599 ua->catalog = oldcatalog;
1601 ua->catalog = catalog;
1604 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1605 ua->catalog->name(), ua->catalog->db_name);
1610 int quit_cmd(UAContext *ua, const char *cmd)
1616 /* Handler to get job status */
1617 static int status_handler(void *ctx, int num_fields, char **row)
1619 char *val = (char *)ctx;
1624 *val = '?'; /* Unknown by default */
1631 * Wait until no job is running
1633 int wait_cmd(UAContext *ua, const char *cmd)
1637 time_t stop_time = 0;
1641 * Wait until no job is running
1643 if (ua->argc == 1) {
1644 bmicrosleep(0, 200000); /* let job actually start */
1645 for (bool running=true; running; ) {
1648 if (jcr->JobId != 0) {
1662 i = find_arg_with_value(ua, NT_("timeout"));
1663 if (i > 0 && ua->argv[i]) {
1664 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1667 /* we have jobid, jobname or ujobid argument */
1669 uint32_t jobid = 0 ;
1671 if (!open_client_db(ua)) {
1672 ua->error_msg(_("ERR: Can't open db\n")) ;
1676 for (int i=1; i<ua->argc; i++) {
1677 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1681 jobid = str_to_int64(ua->argv[i]);
1683 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1684 strcasecmp(ua->argk[i], "job") == 0) {
1688 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1690 jobid = jcr->JobId ;
1694 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1698 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1700 jobid = jcr->JobId ;
1704 /* Wait for a mount request */
1705 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1706 for (bool waiting=false; !waiting; ) {
1708 if (jcr->JobId != 0 &&
1709 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1718 if (stop_time && (time(NULL) >= stop_time)) {
1719 ua->warning_msg(_("Wait on mount timed out\n"));
1729 ua->error_msg(_("ERR: Job was not found\n"));
1734 * We wait the end of a specific job
1737 bmicrosleep(0, 200000); /* let job actually start */
1738 for (bool running=true; running; ) {
1741 jcr=get_jcr_by_id(jobid) ;
1754 * We have to get JobStatus
1758 char jobstatus = '?'; /* Unknown by default */
1761 bsnprintf(buf, sizeof(buf),
1762 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1765 db_sql_query(ua->db, buf,
1766 status_handler, (void *)&jobstatus);
1768 switch (jobstatus) {
1770 status = 1 ; /* Warning */
1774 case JS_ErrorTerminated:
1776 status = 2 ; /* Critical */
1781 status = 0 ; /* Ok */
1785 status = 3 ; /* Unknown */
1789 ua->send_msg("JobId=%i\n", jobid) ;
1790 ua->send_msg("JobStatus=%s (%c)\n",
1791 job_status_to_str(jobstatus),
1794 if (ua->gui || ua->api) {
1795 ua->send_msg("ExitStatus=%i\n", status) ;
1802 static int help_cmd(UAContext *ua, const char *cmd)
1805 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1806 for (i=0; i<comsize; i++) {
1807 if (ua->argc == 2) {
1808 if (!strcasecmp(ua->argk[1], commands[i].key)) {
1809 ua->send_msg(_(" %-13s %s\n\nArguments:\n\t%s\n"), commands[i].key,
1810 commands[i].help, commands[i].usage);
1814 ua->send_msg(_(" %-13s %s\n"), commands[i].key, commands[i].help);
1817 if (i == comsize && ua->argc == 2) {
1818 ua->send_msg(_("\nCan't find %s command.\n\n"), ua->argk[1]);
1820 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1824 int qhelp_cmd(UAContext *ua, const char *cmd)
1827 /* Want to display only commands */
1828 j = find_arg(ua, NT_("all"));
1830 for (i=0; i<comsize; i++) {
1831 ua->send_msg("%s\n", commands[i].key);
1835 /* Want to display a specific help section */
1836 j = find_arg_with_value(ua, NT_("item"));
1837 if (j >= 0 && ua->argk[j]) {
1838 for (i=0; i<comsize; i++) {
1839 if (bstrcmp(commands[i].key, ua->argv[j])) {
1840 ua->send_msg("%s\n", commands[i].usage);
1846 /* Want to display everything */
1847 for (i=0; i<comsize; i++) {
1848 ua->send_msg("%s %s -- %s\n", commands[i].key, commands[i].help, commands[i].usage);
1854 static int version_cmd(UAContext *ua, const char *cmd)
1856 ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
1857 HOST_OS, DISTNAME, DISTVER, NPRTB(director->verid));
1862 * Test code -- turned on only for debug testing
1864 static int version_cmd(UAContext *ua, const char *cmd)
1867 POOL_MEM query(PM_MESSAGE);
1869 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1870 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1871 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1872 for (int i=0; i < ids.num_ids; i++) {
1873 ua->send_msg("id=%d\n", ids.DBId[i]);
1881 * This call uses open_client_db() and force a
1882 * new dedicated connection to the catalog
1884 bool open_new_client_db(UAContext *ua)
1888 /* Force a new dedicated connection */
1890 ua->force_mult_db_connections = true;
1891 ret = open_client_db(ua);
1892 ua->force_mult_db_connections = false;
1897 * This call explicitly checks for a catalog=xxx and
1898 * if given, opens that catalog. It also checks for
1899 * client=xxx and if found, opens the catalog
1900 * corresponding to that client. If we still don't
1901 * have a catalog, look for a Job keyword and get the
1902 * catalog from its client record.
1904 bool open_client_db(UAContext *ua)
1911 /* Try for catalog keyword */
1912 i = find_arg_with_value(ua, NT_("catalog"));
1914 if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1915 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1918 catalog = GetCatalogResWithName(ua->argv[i]);
1920 if (ua->catalog && ua->catalog != catalog) {
1923 ua->catalog = catalog;
1928 /* Try for client keyword */
1929 i = find_arg_with_value(ua, NT_("client"));
1931 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1932 ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1935 client = GetClientResWithName(ua->argv[i]);
1937 catalog = client->catalog;
1938 if (ua->catalog && ua->catalog != catalog) {
1941 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1942 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1945 ua->catalog = catalog;
1950 /* Try for Job keyword */
1951 i = find_arg_with_value(ua, NT_("job"));
1953 if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
1954 ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
1957 job = GetJobResWithName(ua->argv[i]);
1959 catalog = job->client->catalog;
1960 if (ua->catalog && ua->catalog != catalog) {
1963 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1964 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1967 ua->catalog = catalog;
1977 * Open the catalog database.
1979 bool open_db(UAContext *ua)
1987 ua->catalog = get_catalog_resource(ua);
1989 ua->error_msg( _("Could not find a Catalog resource\n"));
1994 /* Some modules like bvfs need their own catalog connection */
1995 mult_db_conn = ua->catalog->mult_db_connections;
1996 if (ua->force_mult_db_connections) {
1997 mult_db_conn = true;
2000 ua->jcr->catalog = ua->catalog;
2002 Dmsg0(100, "UA Open database\n");
2003 ua->db = db_init_database(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
2004 ua->catalog->db_user,
2005 ua->catalog->db_password, ua->catalog->db_address,
2006 ua->catalog->db_port, ua->catalog->db_socket,
2007 mult_db_conn, ua->catalog->disable_batch_insert);
2008 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
2009 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
2010 ua->catalog->db_name);
2012 ua->error_msg("%s", db_strerror(ua->db));
2017 ua->jcr->db = ua->db;
2019 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
2021 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
2025 void close_db(UAContext *ua)
2028 db_close_database(ua->jcr, ua->db);