2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2011 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;
284 char name[MAX_NAME_LENGTH];
286 int Slot = 0, InChanger = 0;
289 "You probably don't want to be using this command since it\n"
290 "creates database records without labeling the Volumes.\n"
291 "You probably want to use the \"label\" command.\n\n"));
293 if (!open_client_db(ua)) {
297 memset(&pr, 0, sizeof(pr));
298 memset(&mr, 0, sizeof(mr));
300 if (!get_pool_dbr(ua, &pr)) {
304 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
305 pr.MaxVols, pr.PoolType);
307 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
308 ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
309 if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
312 pr.MaxVols = ua->pint32_val;
316 if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
317 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
318 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
322 if (pr.MaxVols == 0) {
325 max = pr.MaxVols - pr.NumVols;
329 bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
330 if (!get_pint(ua, buf)) {
333 num = ua->pint32_val;
334 if (num < 0 || num > max) {
335 ua->warning_msg(_("The number must be between 0 and %d\n"), max);
343 if (!get_cmd(ua, _("Enter Volume name: "))) {
347 if (!get_cmd(ua, _("Enter base volume name: "))) {
351 /* Don't allow | in Volume name because it is the volume separator character */
352 if (!is_volume_name_legal(ua, ua->cmd)) {
355 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
356 ua->warning_msg(_("Volume name too long.\n"));
359 if (strlen(ua->cmd) == 0) {
360 ua->warning_msg(_("Volume name must be at least one character long.\n"));
366 bstrncpy(name, ua->cmd, sizeof(name));
368 bstrncat(name, "%04d", sizeof(name));
371 if (!get_pint(ua, _("Enter the starting number: "))) {
374 startnum = ua->pint32_val;
376 ua->warning_msg(_("Start number must be greater than zero.\n"));
386 if (store && store->autochanger) {
387 if (!get_pint(ua, _("Enter slot (0 for none): "))) {
390 Slot = ua->pint32_val;
391 if (!get_yesno(ua, _("InChanger? yes/no: "))) {
394 InChanger = ua->pint32_val;
397 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
398 for (i=startnum; i < num+startnum; i++) {
399 bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
401 mr.InChanger = InChanger;
402 mr.StorageId = store->StorageId;
404 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
405 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
406 ua->error_msg("%s", db_strerror(ua->db));
410 first_id = mr.PoolId;
414 Dmsg0(200, "Update pool record.\n");
415 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
416 ua->warning_msg("%s", db_strerror(ua->db));
419 ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
425 * Turn auto mount on/off
430 int automount_cmd(UAContext *ua, const char *cmd)
435 if (!get_cmd(ua, _("Turn on or off? "))) {
443 ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
450 static int cancel_cmd(UAContext *ua, const char *cmd)
452 JCR *jcr = select_running_job(ua, "cancel");
456 int ret = cancel_job(ua, jcr);
462 * This is a common routine to create or update a
463 * Pool DB base record from a Pool Resource. We handle
464 * the setting of MaxVols and NumVols slightly differently
465 * depending on if we are creating the Pool or we are
466 * simply bringing it into agreement with the resource (updage).
468 * Caution : RecyclePoolId isn't setup in this function.
469 * You can use set_pooldbr_recyclepoolid();
472 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
474 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
475 if (op == POOL_OP_CREATE) {
476 pr->MaxVols = pool->max_volumes;
478 } else { /* update pool */
479 if (pr->MaxVols != pool->max_volumes) {
480 pr->MaxVols = pool->max_volumes;
482 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
483 pr->MaxVols = pr->NumVols;
486 pr->LabelType = pool->LabelType;
487 pr->UseOnce = pool->use_volume_once;
488 pr->UseCatalog = pool->use_catalog;
489 pr->Recycle = pool->Recycle;
490 pr->VolRetention = pool->VolRetention;
491 pr->VolUseDuration = pool->VolUseDuration;
492 pr->MaxVolJobs = pool->MaxVolJobs;
493 pr->MaxVolFiles = pool->MaxVolFiles;
494 pr->MaxVolBytes = pool->MaxVolBytes;
495 pr->AutoPrune = pool->AutoPrune;
496 pr->ActionOnPurge = pool->action_on_purge;
497 pr->Recycle = pool->Recycle;
498 if (pool->label_format) {
499 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
501 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
505 /* set/update Pool.RecyclePoolId and Pool.ScratchPoolId in Catalog */
506 int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
510 if (!pool->RecyclePool && !pool->ScratchPool) {
514 memset(&pr, 0, sizeof(POOL_DBR));
515 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
517 if (!db_get_pool_record(jcr, db, &pr)) {
518 return -1; /* not exists in database */
521 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
523 if (!set_pooldbr_references(jcr, db, &pr, pool)) {
524 return -1; /* error */
527 if (!db_update_pool_record(jcr, db, &pr)) {
528 return -1; /* error */
533 /* set POOL_DBR.RecyclePoolId and POOL_DBR.ScratchPoolId from Pool resource
534 * works with set_pooldbr_from_poolres
536 bool set_pooldbr_references(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
541 if (pool->RecyclePool) {
542 memset(&rpool, 0, sizeof(POOL_DBR));
544 bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
545 if (db_get_pool_record(jcr, db, &rpool)) {
546 pr->RecyclePoolId = rpool.PoolId;
548 Jmsg(jcr, M_WARNING, 0,
549 _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
550 "Try to update it with 'update pool=%s'\n"),
551 pool->name(), rpool.Name, rpool.Name,pool->name());
555 } else { /* no RecyclePool used, set it to 0 */
556 pr->RecyclePoolId = 0;
559 if (pool->ScratchPool) {
560 memset(&rpool, 0, sizeof(POOL_DBR));
562 bstrncpy(rpool.Name, pool->ScratchPool->name(), sizeof(rpool.Name));
563 if (db_get_pool_record(jcr, db, &rpool)) {
564 pr->ScratchPoolId = rpool.PoolId;
566 Jmsg(jcr, M_WARNING, 0,
567 _("Can't set %s ScratchPool to %s, %s is not in database.\n" \
568 "Try to update it with 'update pool=%s'\n"),
569 pool->name(), rpool.Name, rpool.Name,pool->name());
572 } else { /* no ScratchPool used, set it to 0 */
573 pr->ScratchPoolId = 0;
581 * Create a pool record from a given Pool resource
582 * Also called from backup.c
583 * Returns: -1 on error
584 * 0 record already exists
588 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
592 memset(&pr, 0, sizeof(POOL_DBR));
594 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
596 if (db_get_pool_record(jcr, db, &pr)) {
598 if (op == POOL_OP_UPDATE) { /* update request */
599 set_pooldbr_from_poolres(&pr, pool, op);
600 set_pooldbr_references(jcr, db, &pr, pool);
601 db_update_pool_record(jcr, db, &pr);
603 return 0; /* exists */
606 set_pooldbr_from_poolres(&pr, pool, op);
607 set_pooldbr_references(jcr, db, &pr, pool);
609 if (!db_create_pool_record(jcr, db, &pr)) {
610 return -1; /* error */
618 * Create a Pool Record in the database.
619 * It is always created from the Resource record.
621 static int create_cmd(UAContext *ua, const char *cmd)
625 if (!open_client_db(ua)) {
629 pool = get_pool_resource(ua);
634 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
636 ua->error_msg(_("Error: Pool %s already exists.\n"
637 "Use update to change it.\n"), pool->name());
641 ua->error_msg("%s", db_strerror(ua->db));
647 ua->send_msg(_("Pool %s created.\n"), pool->name());
652 extern DIRRES *director;
653 extern char *configfile;
656 * Python control command
657 * python restart (restarts interpreter)
659 static int python_cmd(UAContext *ua, const char *cmd)
662 init_python_interpreter_args python_args;
664 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
665 term_python_interpreter();
667 python_args.progname = director->name();
668 python_args.scriptdir = director->scripts_directory;
669 python_args.modulename = "DirStartUp";
670 python_args.configfile = configfile;
671 python_args.workingdir = director->working_directory;
672 python_args.job_getattr = job_getattr;
673 python_args.job_setattr = job_setattr;
675 init_python_interpreter(&python_args);
677 ua->send_msg(_("Python interpreter restarted.\n"));
679 #endif /* HAVE_PYTHON */
680 ua->warning_msg(_("Nothing done.\n"));
683 #endif /* HAVE_PYTHON */
688 * Set a new address in a Client resource. We do this only
689 * if the Console name is the same as the Client name
690 * and the Console can access the client.
692 static int setip_cmd(UAContext *ua, const char *cmd)
696 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
697 ua->error_msg(_("Unauthorized command from this console.\n"));
701 client = GetClientResWithName(ua->cons->name());
704 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
707 if (client->address) {
708 free(client->address);
710 /* MA Bug 6 remove ifdef */
711 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
712 client->address = bstrdup(buf);
713 ua->send_msg(_("Client \"%s\" address set to %s\n"),
714 client->name(), client->address);
721 static void do_en_disable_cmd(UAContext *ua, bool setting)
726 i = find_arg_with_value(ua, NT_("job"));
728 job = select_enable_disable_job_resource(ua, setting);
734 job = GetJobResWithName(ua->argv[i]);
738 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
742 if (!acl_access_ok(ua, Job_ACL, job->name())) {
743 ua->error_msg(_("Unauthorized command from this console.\n"));
746 job->enabled = setting;
747 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
751 static int enable_cmd(UAContext *ua, const char *cmd)
753 do_en_disable_cmd(ua, true);
757 static int disable_cmd(UAContext *ua, const char *cmd)
759 do_en_disable_cmd(ua, false);
763 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
769 lstore.store = store;
770 pm_strcpy(lstore.store_source, _("unknown source"));
771 set_wstorage(jcr, &lstore);
772 /* Try connecting for up to 15 seconds */
773 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
774 store->name(), store->address, store->SDport);
775 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
776 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
779 Dmsg0(120, _("Connected to storage daemon\n"));
780 sd = jcr->store_bsock;
781 sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
782 if (sd->recv() >= 0) {
783 ua->send_msg("%s", sd->msg);
785 sd->signal(BNET_TERMINATE);
787 jcr->store_bsock = NULL;
792 * For the client, we have the following values that can be set
793 * level = debug level
794 * trace = send debug output to a file
795 * hangup = how many records to send to SD before hanging up
796 * obviously this is most useful for testing restarting
799 static void do_client_setdebug(UAContext *ua, CLIENT *client,
800 int level, int trace, int hangup)
804 /* Connect to File daemon */
806 ua->jcr->client = client;
807 /* Try to connect for 15 seconds */
808 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
809 client->name(), client->address, client->FDport);
810 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
811 ua->error_msg(_("Failed to connect to Client.\n"));
814 Dmsg0(120, "Connected to file daemon\n");
815 fd = ua->jcr->file_bsock;
816 fd->fsend("setdebug=%d trace=%d hangup=%d\n", level, trace, hangup);
817 if (fd->recv() >= 0) {
818 ua->send_msg("%s", fd->msg);
820 fd->signal(BNET_TERMINATE);
822 ua->jcr->file_bsock = NULL;
827 static void do_all_setdebug(UAContext *ua, int level, int trace_flag, int hangup)
829 STORE *store, **unique_store;
830 CLIENT *client, **unique_client;
836 /* Count Storage items */
840 foreach_res(store, R_STORAGE) {
843 unique_store = (STORE **) malloc(i * sizeof(STORE));
844 /* Find Unique Storage address/port */
845 store = (STORE *)GetNextRes(R_STORAGE, NULL);
847 unique_store[i++] = store;
848 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
850 for (j=0; j<i; j++) {
851 if (strcmp(unique_store[j]->address, store->address) == 0 &&
852 unique_store[j]->SDport == store->SDport) {
858 unique_store[i++] = store;
859 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
864 /* Call each unique Storage daemon */
865 for (j=0; j<i; j++) {
866 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
870 /* Count Client items */
874 foreach_res(client, R_CLIENT) {
877 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
878 /* Find Unique Client address/port */
879 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
881 unique_client[i++] = client;
882 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
884 for (j=0; j<i; j++) {
885 if (strcmp(unique_client[j]->address, client->address) == 0 &&
886 unique_client[j]->FDport == client->FDport) {
892 unique_client[i++] = client;
893 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
898 /* Call each unique File daemon */
899 for (j=0; j<i; j++) {
900 do_client_setdebug(ua, unique_client[j], level, trace_flag, hangup);
906 * setdebug level=nn all trace=1/0
908 static int setdebug_cmd(UAContext *ua, const char *cmd)
917 Dmsg1(120, "setdebug:%s:\n", cmd);
920 i = find_arg_with_value(ua, "level");
922 level = atoi(ua->argv[i]);
925 if (!get_pint(ua, _("Enter new debug level: "))) {
928 level = ua->pint32_val;
931 /* Look for trace flag. -1 => not change */
932 i = find_arg_with_value(ua, "trace");
934 trace_flag = atoi(ua->argv[i]);
935 if (trace_flag > 0) {
940 /* Look for hangup (debug only)flag. -1 => not change */
941 i = find_arg_with_value(ua, "hangup");
943 hangup = atoi(ua->argv[i]);
948 for (i=1; i<ua->argc; i++) {
949 if (strcasecmp(ua->argk[i], "all") == 0) {
950 do_all_setdebug(ua, level, trace_flag, hangup);
953 if (strcasecmp(ua->argk[i], "dir") == 0 ||
954 strcasecmp(ua->argk[i], "director") == 0) {
956 set_trace(trace_flag);
959 if (strcasecmp(ua->argk[i], "client") == 0 ||
960 strcasecmp(ua->argk[i], "fd") == 0) {
963 client = GetClientResWithName(ua->argv[i]);
965 do_client_setdebug(ua, client, level, trace_flag, hangup);
969 client = select_client_resource(ua);
971 do_client_setdebug(ua, client, level, trace_flag, hangup);
976 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
977 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
978 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
981 store = GetStoreResWithName(ua->argv[i]);
983 do_storage_setdebug(ua, store, level, trace_flag);
987 store = get_storage_resource(ua, false/*no default*/);
989 do_storage_setdebug(ua, store, level, trace_flag);
995 * We didn't find an appropriate keyword above, so
998 start_prompt(ua, _("Available daemons are: \n"));
999 add_prompt(ua, _("Director"));
1000 add_prompt(ua, _("Storage"));
1001 add_prompt(ua, _("Client"));
1002 add_prompt(ua, _("All"));
1003 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1004 case 0: /* Director */
1005 debug_level = level;
1006 set_trace(trace_flag);
1009 store = get_storage_resource(ua, false/*no default*/);
1011 do_storage_setdebug(ua, store, level, trace_flag);
1015 client = select_client_resource(ua);
1017 do_client_setdebug(ua, client, level, trace_flag, hangup);
1021 do_all_setdebug(ua, level, trace_flag, hangup);
1030 * Turn debug tracing to file on/off
1032 static int trace_cmd(UAContext *ua, const char *cmd)
1036 if (ua->argc != 2) {
1037 if (!get_cmd(ua, _("Turn on or off? "))) {
1042 onoff = ua->argk[1];
1045 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1050 static int var_cmd(UAContext *ua, const char *cmd)
1052 POOLMEM *val = get_pool_memory(PM_FNAME);
1055 if (!open_client_db(ua)) {
1058 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1061 while (*var == ' ') { /* skip spaces */
1064 Dmsg1(100, "Var=%s:\n", var);
1065 variable_expansion(ua->jcr, var, &val);
1066 ua->send_msg("%s\n", val);
1067 free_pool_memory(val);
1071 static int estimate_cmd(UAContext *ua, const char *cmd)
1074 CLIENT *client = NULL;
1075 FILESET *fileset = NULL;
1077 char since[MAXSTRING];
1081 jcr->setJobLevel(L_FULL);
1082 for (int i=1; i<ua->argc; i++) {
1083 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1084 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1086 client = GetClientResWithName(ua->argv[i]);
1088 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1091 if (!acl_access_ok(ua, Client_ACL, client->name())) {
1092 ua->error_msg(_("No authorization for Client \"%s\"\n"), client->name());
1097 ua->error_msg(_("Client name missing.\n"));
1101 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1103 job = GetJobResWithName(ua->argv[i]);
1105 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1108 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1109 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1114 ua->error_msg(_("Job name missing.\n"));
1119 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1121 fileset = GetFileSetResWithName(ua->argv[i]);
1123 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1126 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1127 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1132 ua->error_msg(_("Fileset name missing.\n"));
1136 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1140 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1142 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1143 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1147 ua->error_msg(_("Level value missing.\n"));
1151 if (strcasecmp(ua->argk[i], NT_("accurate")) == 0) {
1152 if (!is_yesno(ua->argv[i], &accurate)) {
1153 ua->error_msg(_("Invalid value for accurate. "
1154 "It must be yes or no.\n"));
1158 if (!job && !(client && fileset)) {
1159 if (!(job = select_job_resource(ua))) {
1164 job = GetJobResWithName(ua->argk[1]);
1166 ua->error_msg(_("No job specified.\n"));
1169 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1170 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1175 client = job->client;
1178 fileset = job->fileset;
1180 jcr->client = client;
1181 jcr->fileset = fileset;
1183 if (job->pool->catalog) {
1184 ua->catalog = job->pool->catalog;
1186 ua->catalog = client->catalog;
1194 jcr->setJobType(JT_BACKUP);
1195 init_jcr_job_record(jcr);
1197 if (!get_or_create_client_record(jcr)) {
1200 if (!get_or_create_fileset_record(jcr)) {
1204 get_level_since_time(ua->jcr, since, sizeof(since));
1206 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1207 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1208 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1209 ua->error_msg(_("Failed to connect to Client.\n"));
1213 if (!send_include_list(jcr)) {
1214 ua->error_msg(_("Error sending include list.\n"));
1218 if (!send_exclude_list(jcr)) {
1219 ua->error_msg(_("Error sending exclude list.\n"));
1223 /* The level string change if accurate mode is enabled */
1224 if (accurate >= 0) {
1225 jcr->accurate = accurate;
1227 jcr->accurate = job->accurate;
1230 if (!send_level_command(jcr)) {
1235 * If the job is in accurate mode, we send the list of
1238 Dmsg1(40, "estimate accurate=%d\n", jcr->accurate);
1239 if (!send_accurate_current_files(jcr)) {
1243 jcr->file_bsock->fsend("estimate listing=%d\n", listing);
1244 while (jcr->file_bsock->recv() >= 0) {
1245 ua->send_msg("%s", jcr->file_bsock->msg);
1249 if (jcr->file_bsock) {
1250 jcr->file_bsock->signal(BNET_TERMINATE);
1251 jcr->file_bsock->close();
1252 jcr->file_bsock = NULL;
1261 static int time_cmd(UAContext *ua, const char *cmd)
1264 time_t ttime = time(NULL);
1266 (void)localtime_r(&ttime, &tm);
1267 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1268 ua->send_msg("%s\n", sdt);
1273 * reload the conf file
1275 extern "C" void reload_config(int sig);
1277 static int reload_cmd(UAContext *ua, const char *cmd)
1284 * Delete Pool records (should purge Media with it).
1286 * delete pool=<pool-name>
1287 * delete volume pool=<pool-name> volume=<name>
1290 static int delete_cmd(UAContext *ua, const char *cmd)
1292 static const char *keywords[] = {
1298 if (!open_client_db(ua)) {
1302 switch (find_arg_keyword(ua, keywords)) {
1311 while ((i=find_arg(ua, "jobid")) > 0) {
1313 *ua->argk[i] = 0; /* zap keyword already visited */
1321 "In general it is not a good idea to delete either a\n"
1322 "Pool or a Volume since they may contain data.\n\n"));
1324 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1335 ua->warning_msg(_("Nothing done.\n"));
1343 * delete_job has been modified to parse JobID lists like the
1345 * delete JobID=3,4,6,7-11,14
1347 * Thanks to Phil Stracchino for the above addition.
1350 static void delete_job(UAContext *ua)
1355 int i = find_arg_with_value(ua, NT_("jobid"));
1357 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1358 s = bstrdup(ua->argv[i]);
1361 * We could use strtok() here. But we're not going to, because:
1362 * (a) strtok() is deprecated, having been replaced by strsep();
1363 * (b) strtok() is broken in significant ways.
1364 * we could use strsep() instead, but it's not universally available.
1365 * so we grow our own using strchr().
1367 sep = strchr(tok, ',');
1368 while (sep != NULL) {
1370 if (!delete_job_id_range(ua, tok)) {
1371 JobId = str_to_int64(tok);
1372 do_job_delete(ua, JobId);
1375 sep = strchr(tok, ',');
1377 /* pick up the last token */
1378 if (!delete_job_id_range(ua, tok)) {
1379 JobId = str_to_int64(tok);
1380 do_job_delete(ua, JobId);
1385 JobId = str_to_int64(ua->argv[i]);
1386 do_job_delete(ua, JobId);
1388 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1391 JobId = ua->int64_val;
1392 do_job_delete(ua, JobId);
1397 * we call delete_job_id_range to parse range tokens and iterate over ranges
1399 static bool delete_job_id_range(UAContext *ua, char *tok)
1404 tok2 = strchr(tok, '-');
1410 j1 = str_to_int64(tok);
1411 j2 = str_to_int64(tok2);
1412 for (j=j1; j<=j2; j++) {
1413 do_job_delete(ua, j);
1419 * do_job_delete now performs the actual delete operation atomically
1421 static void do_job_delete(UAContext *ua, JobId_t JobId)
1425 edit_int64(JobId, ed1);
1426 purge_jobs_from_catalog(ua, ed1);
1427 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1431 * Delete media records from database -- dangerous
1433 static int delete_volume(UAContext *ua)
1439 if (!select_media_dbr(ua, &mr)) {
1442 ua->warning_msg(_("\nThis command will delete volume %s\n"
1443 "and all Jobs saved on that volume from the Catalog\n"),
1446 if (find_arg(ua, "yes") >= 0) {
1447 ua->pint32_val = 1; /* Have "yes" on command line already" */
1449 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1451 if (!get_yesno(ua, buf)) {
1455 if (!ua->pint32_val) {
1459 /* If not purged, do it */
1460 if (strcmp(mr.VolStatus, "Purged") != 0) {
1461 if (!db_get_volume_jobids(ua->jcr, ua->db, &mr, &lst)) {
1462 ua->error_msg(_("Can't list jobs on this volume\n"));
1466 purge_jobs_from_catalog(ua, lst.list);
1470 db_delete_media_record(ua->jcr, ua->db, &mr);
1475 * Delete a pool record from the database -- dangerous
1477 static int delete_pool(UAContext *ua)
1482 memset(&pr, 0, sizeof(pr));
1484 if (!get_pool_dbr(ua, &pr)) {
1487 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1489 if (!get_yesno(ua, buf)) {
1492 if (ua->pint32_val) {
1493 db_delete_pool_record(ua->jcr, ua->db, &pr);
1498 int memory_cmd(UAContext *ua, const char *cmd)
1500 garbage_collect_memory();
1501 list_dir_status_header(ua);
1502 sm_dump(false, true);
1506 static void do_mount_cmd(UAContext *ua, const char *command)
1511 char dev_name[MAX_NAME_LENGTH];
1515 if (!open_client_db(ua)) {
1518 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1520 store.store = get_storage_resource(ua, true/*arg is storage*/);
1524 pm_strcpy(store.store_source, _("unknown source"));
1525 set_wstorage(jcr, &store);
1526 drive = get_storage_drive(ua, store.store);
1527 if (strcmp(command, "mount") == 0) {
1528 slot = get_storage_slot(ua, store.store);
1531 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1532 store.store->media_type, store.store->dev_name(), drive);
1534 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1535 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1538 sd = jcr->store_bsock;
1539 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1540 bash_spaces(dev_name);
1542 sd->fsend("%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1544 sd->fsend("%s %s drive=%d", command, dev_name, drive);
1546 while (sd->recv() >= 0) {
1547 ua->send_msg("%s", sd->msg);
1549 sd->signal(BNET_TERMINATE);
1551 jcr->store_bsock = NULL;
1555 * mount [storage=<name>] [drive=nn] [slot=mm]
1557 static int mount_cmd(UAContext *ua, const char *cmd)
1559 do_mount_cmd(ua, "mount"); /* mount */
1565 * unmount [storage=<name>] [drive=nn]
1567 static int unmount_cmd(UAContext *ua, const char *cmd)
1569 do_mount_cmd(ua, "unmount"); /* unmount */
1575 * release [storage=<name>] [drive=nn]
1577 static int release_cmd(UAContext *ua, const char *cmd)
1579 do_mount_cmd(ua, "release"); /* release */
1586 * use catalog=<name>
1588 static int use_cmd(UAContext *ua, const char *cmd)
1590 CAT *oldcatalog, *catalog;
1593 close_db(ua); /* close any previously open db */
1594 oldcatalog = ua->catalog;
1596 if (!(catalog = get_catalog_resource(ua))) {
1597 ua->catalog = oldcatalog;
1599 ua->catalog = catalog;
1602 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1603 ua->catalog->name(), ua->catalog->db_name);
1608 int quit_cmd(UAContext *ua, const char *cmd)
1614 /* Handler to get job status */
1615 static int status_handler(void *ctx, int num_fields, char **row)
1617 char *val = (char *)ctx;
1622 *val = '?'; /* Unknown by default */
1629 * Wait until no job is running
1631 int wait_cmd(UAContext *ua, const char *cmd)
1635 time_t stop_time = 0;
1639 * Wait until no job is running
1641 if (ua->argc == 1) {
1642 bmicrosleep(0, 200000); /* let job actually start */
1643 for (bool running=true; running; ) {
1646 if (jcr->JobId != 0) {
1660 i = find_arg_with_value(ua, NT_("timeout"));
1661 if (i > 0 && ua->argv[i]) {
1662 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1665 /* we have jobid, jobname or ujobid argument */
1667 uint32_t jobid = 0 ;
1669 if (!open_client_db(ua)) {
1670 ua->error_msg(_("ERR: Can't open db\n")) ;
1674 for (int i=1; i<ua->argc; i++) {
1675 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1679 jobid = str_to_int64(ua->argv[i]);
1681 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1682 strcasecmp(ua->argk[i], "job") == 0) {
1686 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1688 jobid = jcr->JobId ;
1692 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1696 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1698 jobid = jcr->JobId ;
1702 /* Wait for a mount request */
1703 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1704 for (bool waiting=false; !waiting; ) {
1706 if (jcr->JobId != 0 &&
1707 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1716 if (stop_time && (time(NULL) >= stop_time)) {
1717 ua->warning_msg(_("Wait on mount timed out\n"));
1727 ua->error_msg(_("ERR: Job was not found\n"));
1732 * We wait the end of a specific job
1735 bmicrosleep(0, 200000); /* let job actually start */
1736 for (bool running=true; running; ) {
1739 jcr=get_jcr_by_id(jobid) ;
1752 * We have to get JobStatus
1756 char jobstatus = '?'; /* Unknown by default */
1759 bsnprintf(buf, sizeof(buf),
1760 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1763 db_sql_query(ua->db, buf,
1764 status_handler, (void *)&jobstatus);
1766 switch (jobstatus) {
1768 status = 1 ; /* Warning */
1772 case JS_ErrorTerminated:
1774 status = 2 ; /* Critical */
1779 status = 0 ; /* Ok */
1783 status = 3 ; /* Unknown */
1787 ua->send_msg("JobId=%i\n", jobid) ;
1788 ua->send_msg("JobStatus=%s (%c)\n",
1789 job_status_to_str(jobstatus),
1792 if (ua->gui || ua->api) {
1793 ua->send_msg("ExitStatus=%i\n", status) ;
1800 static int help_cmd(UAContext *ua, const char *cmd)
1803 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1804 for (i=0; i<comsize; i++) {
1805 if (ua->argc == 2) {
1806 if (!strcasecmp(ua->argk[1], commands[i].key)) {
1807 ua->send_msg(_(" %-13s %s\n\nArguments:\n\t%s\n"), commands[i].key,
1808 commands[i].help, commands[i].usage);
1812 ua->send_msg(_(" %-13s %s\n"), commands[i].key, commands[i].help);
1815 if (i == comsize && ua->argc == 2) {
1816 ua->send_msg(_("\nCan't find %s command.\n\n"), ua->argk[1]);
1818 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1822 int qhelp_cmd(UAContext *ua, const char *cmd)
1825 /* Want to display only commands */
1826 j = find_arg(ua, NT_("all"));
1828 for (i=0; i<comsize; i++) {
1829 ua->send_msg("%s\n", commands[i].key);
1833 /* Want to display a specific help section */
1834 j = find_arg_with_value(ua, NT_("item"));
1835 if (j >= 0 && ua->argk[j]) {
1836 for (i=0; i<comsize; i++) {
1837 if (bstrcmp(commands[i].key, ua->argv[j])) {
1838 ua->send_msg("%s\n", commands[i].usage);
1844 /* Want to display everything */
1845 for (i=0; i<comsize; i++) {
1846 ua->send_msg("%s %s -- %s\n", commands[i].key, commands[i].help, commands[i].usage);
1852 static int version_cmd(UAContext *ua, const char *cmd)
1854 ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
1855 HOST_OS, DISTNAME, DISTVER, NPRTB(director->verid));
1860 * Test code -- turned on only for debug testing
1862 static int version_cmd(UAContext *ua, const char *cmd)
1865 POOL_MEM query(PM_MESSAGE);
1867 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1868 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1869 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1870 for (int i=0; i < ids.num_ids; i++) {
1871 ua->send_msg("id=%d\n", ids.DBId[i]);
1879 * This call uses open_client_db() and force a
1880 * new dedicated connection to the catalog
1882 bool open_new_client_db(UAContext *ua)
1886 /* Force a new dedicated connection */
1888 ua->force_mult_db_connections = true;
1889 ret = open_client_db(ua);
1890 ua->force_mult_db_connections = false;
1895 * This call explicitly checks for a catalog=xxx and
1896 * if given, opens that catalog. It also checks for
1897 * client=xxx and if found, opens the catalog
1898 * corresponding to that client. If we still don't
1899 * have a catalog, look for a Job keyword and get the
1900 * catalog from its client record.
1902 bool open_client_db(UAContext *ua)
1909 /* Try for catalog keyword */
1910 i = find_arg_with_value(ua, NT_("catalog"));
1912 if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1913 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1916 catalog = GetCatalogResWithName(ua->argv[i]);
1918 if (ua->catalog && ua->catalog != catalog) {
1921 ua->catalog = catalog;
1926 /* Try for client keyword */
1927 i = find_arg_with_value(ua, NT_("client"));
1929 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1930 ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1933 client = GetClientResWithName(ua->argv[i]);
1935 catalog = client->catalog;
1936 if (ua->catalog && ua->catalog != catalog) {
1939 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1940 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1943 ua->catalog = catalog;
1948 /* Try for Job keyword */
1949 i = find_arg_with_value(ua, NT_("job"));
1951 if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
1952 ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
1955 job = GetJobResWithName(ua->argv[i]);
1957 catalog = job->client->catalog;
1958 if (ua->catalog && ua->catalog != catalog) {
1961 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1962 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1965 ua->catalog = catalog;
1975 * Open the catalog database.
1977 bool open_db(UAContext *ua)
1985 ua->catalog = get_catalog_resource(ua);
1987 ua->error_msg( _("Could not find a Catalog resource\n"));
1992 /* Some modules like bvfs need their own catalog connection */
1993 mult_db_conn = ua->catalog->mult_db_connections;
1994 if (ua->force_mult_db_connections) {
1995 mult_db_conn = true;
1998 ua->jcr->catalog = ua->catalog;
2000 Dmsg0(100, "UA Open database\n");
2001 ua->db = db_init_database(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
2002 ua->catalog->db_user,
2003 ua->catalog->db_password, ua->catalog->db_address,
2004 ua->catalog->db_port, ua->catalog->db_socket,
2005 mult_db_conn, ua->catalog->disable_batch_insert);
2006 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
2007 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
2008 ua->catalog->db_name);
2010 ua->error_msg("%s", db_strerror(ua->db));
2015 ua->jcr->db = ua->db;
2017 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
2019 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
2023 void close_db(UAContext *ua)
2026 db_close_database(ua->jcr, ua->db);