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;
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));
297 memset(&mr, 0, sizeof(mr));
299 if (!get_pool_dbr(ua, &pr)) {
303 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
304 pr.MaxVols, pr.PoolType);
306 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
307 ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
308 if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
311 pr.MaxVols = ua->pint32_val;
315 if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
316 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
317 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
321 if (pr.MaxVols == 0) {
324 max = pr.MaxVols - pr.NumVols;
328 bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
329 if (!get_pint(ua, buf)) {
332 num = ua->pint32_val;
333 if (num < 0 || num > max) {
334 ua->warning_msg(_("The number must be between 0 and %d\n"), max);
342 if (!get_cmd(ua, _("Enter Volume name: "))) {
346 if (!get_cmd(ua, _("Enter base volume name: "))) {
350 /* Don't allow | in Volume name because it is the volume separator character */
351 if (!is_volume_name_legal(ua, ua->cmd)) {
354 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
355 ua->warning_msg(_("Volume name too long.\n"));
358 if (strlen(ua->cmd) == 0) {
359 ua->warning_msg(_("Volume name must be at least one character long.\n"));
365 bstrncpy(name, ua->cmd, sizeof(name));
367 bstrncat(name, "%04d", sizeof(name));
370 if (!get_pint(ua, _("Enter the starting number: "))) {
373 startnum = ua->pint32_val;
375 ua->warning_msg(_("Start number must be greater than zero.\n"));
385 if (store && store->autochanger) {
386 if (!get_pint(ua, _("Enter slot (0 for none): "))) {
389 Slot = ua->pint32_val;
390 if (!get_yesno(ua, _("InChanger? yes/no: "))) {
393 InChanger = ua->pint32_val;
396 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
397 for (i=startnum; i < num+startnum; i++) {
398 bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
400 mr.InChanger = InChanger;
401 mr.StorageId = store->StorageId;
403 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
404 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
405 ua->error_msg("%s", db_strerror(ua->db));
410 Dmsg0(200, "Update pool record.\n");
411 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
412 ua->warning_msg("%s", db_strerror(ua->db));
415 ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
421 * Turn auto mount on/off
426 int automount_cmd(UAContext *ua, const char *cmd)
431 if (!get_cmd(ua, _("Turn on or off? "))) {
439 ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
446 static int cancel_cmd(UAContext *ua, const char *cmd)
448 JCR *jcr = select_running_job(ua, "cancel");
452 int ret = cancel_job(ua, jcr);
458 * This is a common routine to create or update a
459 * Pool DB base record from a Pool Resource. We handle
460 * the setting of MaxVols and NumVols slightly differently
461 * depending on if we are creating the Pool or we are
462 * simply bringing it into agreement with the resource (updage).
464 * Caution : RecyclePoolId isn't setup in this function.
465 * You can use set_pooldbr_recyclepoolid();
468 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
470 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
471 if (op == POOL_OP_CREATE) {
472 pr->MaxVols = pool->max_volumes;
474 } else { /* update pool */
475 if (pr->MaxVols != pool->max_volumes) {
476 pr->MaxVols = pool->max_volumes;
478 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
479 pr->MaxVols = pr->NumVols;
482 pr->LabelType = pool->LabelType;
483 pr->UseOnce = pool->use_volume_once;
484 pr->UseCatalog = pool->use_catalog;
485 pr->Recycle = pool->Recycle;
486 pr->VolRetention = pool->VolRetention;
487 pr->VolUseDuration = pool->VolUseDuration;
488 pr->MaxVolJobs = pool->MaxVolJobs;
489 pr->MaxVolFiles = pool->MaxVolFiles;
490 pr->MaxVolBytes = pool->MaxVolBytes;
491 pr->AutoPrune = pool->AutoPrune;
492 pr->ActionOnPurge = pool->action_on_purge;
493 pr->Recycle = pool->Recycle;
494 if (pool->label_format) {
495 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
497 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
501 /* set/update Pool.RecyclePoolId and Pool.ScratchPoolId in Catalog */
502 int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
506 if (!pool->RecyclePool && !pool->ScratchPool) {
510 memset(&pr, 0, sizeof(POOL_DBR));
511 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
513 if (!db_get_pool_record(jcr, db, &pr)) {
514 return -1; /* not exists in database */
517 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
519 if (!set_pooldbr_references(jcr, db, &pr, pool)) {
520 return -1; /* error */
523 if (!db_update_pool_record(jcr, db, &pr)) {
524 return -1; /* error */
529 /* set POOL_DBR.RecyclePoolId and POOL_DBR.ScratchPoolId from Pool resource
530 * works with set_pooldbr_from_poolres
532 bool set_pooldbr_references(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
537 if (pool->RecyclePool) {
538 memset(&rpool, 0, sizeof(POOL_DBR));
540 bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
541 if (db_get_pool_record(jcr, db, &rpool)) {
542 pr->RecyclePoolId = rpool.PoolId;
544 Jmsg(jcr, M_WARNING, 0,
545 _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
546 "Try to update it with 'update pool=%s'\n"),
547 pool->name(), rpool.Name, rpool.Name,pool->name());
551 } else { /* no RecyclePool used, set it to 0 */
552 pr->RecyclePoolId = 0;
555 if (pool->ScratchPool) {
556 memset(&rpool, 0, sizeof(POOL_DBR));
558 bstrncpy(rpool.Name, pool->ScratchPool->name(), sizeof(rpool.Name));
559 if (db_get_pool_record(jcr, db, &rpool)) {
560 pr->ScratchPoolId = rpool.PoolId;
562 Jmsg(jcr, M_WARNING, 0,
563 _("Can't set %s ScratchPool to %s, %s is not in database.\n" \
564 "Try to update it with 'update pool=%s'\n"),
565 pool->name(), rpool.Name, rpool.Name,pool->name());
568 } else { /* no ScratchPool used, set it to 0 */
569 pr->ScratchPoolId = 0;
577 * Create a pool record from a given Pool resource
578 * Also called from backup.c
579 * Returns: -1 on error
580 * 0 record already exists
584 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
588 memset(&pr, 0, sizeof(POOL_DBR));
590 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
592 if (db_get_pool_record(jcr, db, &pr)) {
594 if (op == POOL_OP_UPDATE) { /* update request */
595 set_pooldbr_from_poolres(&pr, pool, op);
596 set_pooldbr_references(jcr, db, &pr, pool);
597 db_update_pool_record(jcr, db, &pr);
599 return 0; /* exists */
602 set_pooldbr_from_poolres(&pr, pool, op);
603 set_pooldbr_references(jcr, db, &pr, pool);
605 if (!db_create_pool_record(jcr, db, &pr)) {
606 return -1; /* error */
614 * Create a Pool Record in the database.
615 * It is always created from the Resource record.
617 static int create_cmd(UAContext *ua, const char *cmd)
621 if (!open_client_db(ua)) {
625 pool = get_pool_resource(ua);
630 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
632 ua->error_msg(_("Error: Pool %s already exists.\n"
633 "Use update to change it.\n"), pool->name());
637 ua->error_msg("%s", db_strerror(ua->db));
643 ua->send_msg(_("Pool %s created.\n"), pool->name());
648 extern DIRRES *director;
649 extern char *configfile;
652 * Python control command
653 * python restart (restarts interpreter)
655 static int python_cmd(UAContext *ua, const char *cmd)
658 init_python_interpreter_args python_args;
660 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
661 term_python_interpreter();
663 python_args.progname = director->name();
664 python_args.scriptdir = director->scripts_directory;
665 python_args.modulename = "DirStartUp";
666 python_args.configfile = configfile;
667 python_args.workingdir = director->working_directory;
668 python_args.job_getattr = job_getattr;
669 python_args.job_setattr = job_setattr;
671 init_python_interpreter(&python_args);
673 ua->send_msg(_("Python interpreter restarted.\n"));
675 #endif /* HAVE_PYTHON */
676 ua->warning_msg(_("Nothing done.\n"));
679 #endif /* HAVE_PYTHON */
684 * Set a new address in a Client resource. We do this only
685 * if the Console name is the same as the Client name
686 * and the Console can access the client.
688 static int setip_cmd(UAContext *ua, const char *cmd)
692 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
693 ua->error_msg(_("Unauthorized command from this console.\n"));
697 client = GetClientResWithName(ua->cons->name());
700 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
703 if (client->address) {
704 free(client->address);
706 /* MA Bug 6 remove ifdef */
707 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
708 client->address = bstrdup(buf);
709 ua->send_msg(_("Client \"%s\" address set to %s\n"),
710 client->name(), client->address);
717 static void do_en_disable_cmd(UAContext *ua, bool setting)
722 i = find_arg_with_value(ua, NT_("job"));
724 job = select_enable_disable_job_resource(ua, setting);
730 job = GetJobResWithName(ua->argv[i]);
734 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
738 if (!acl_access_ok(ua, Job_ACL, job->name())) {
739 ua->error_msg(_("Unauthorized command from this console.\n"));
742 job->enabled = setting;
743 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
747 static int enable_cmd(UAContext *ua, const char *cmd)
749 do_en_disable_cmd(ua, true);
753 static int disable_cmd(UAContext *ua, const char *cmd)
755 do_en_disable_cmd(ua, false);
759 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
765 lstore.store = store;
766 pm_strcpy(lstore.store_source, _("unknown source"));
767 set_wstorage(jcr, &lstore);
768 /* Try connecting for up to 15 seconds */
769 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
770 store->name(), store->address, store->SDport);
771 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
772 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
775 Dmsg0(120, _("Connected to storage daemon\n"));
776 sd = jcr->store_bsock;
777 sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
778 if (sd->recv() >= 0) {
779 ua->send_msg("%s", sd->msg);
781 sd->signal(BNET_TERMINATE);
783 jcr->store_bsock = NULL;
788 * For the client, we have the following values that can be set
789 * level = debug level
790 * trace = send debug output to a file
791 * hangup = how many records to send to SD before hanging up
792 * obviously this is most useful for testing restarting
795 static void do_client_setdebug(UAContext *ua, CLIENT *client,
796 int level, int trace, int hangup)
800 /* Connect to File daemon */
802 ua->jcr->client = client;
803 /* Try to connect for 15 seconds */
804 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
805 client->name(), client->address, client->FDport);
806 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
807 ua->error_msg(_("Failed to connect to Client.\n"));
810 Dmsg0(120, "Connected to file daemon\n");
811 fd = ua->jcr->file_bsock;
812 fd->fsend("setdebug=%d trace=%d hangup=%d\n", level, trace, hangup);
813 if (fd->recv() >= 0) {
814 ua->send_msg("%s", fd->msg);
816 fd->signal(BNET_TERMINATE);
818 ua->jcr->file_bsock = NULL;
823 static void do_all_setdebug(UAContext *ua, int level, int trace_flag, int hangup)
825 STORE *store, **unique_store;
826 CLIENT *client, **unique_client;
832 /* Count Storage items */
836 foreach_res(store, R_STORAGE) {
839 unique_store = (STORE **) malloc(i * sizeof(STORE));
840 /* Find Unique Storage address/port */
841 store = (STORE *)GetNextRes(R_STORAGE, NULL);
843 unique_store[i++] = store;
844 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
846 for (j=0; j<i; j++) {
847 if (strcmp(unique_store[j]->address, store->address) == 0 &&
848 unique_store[j]->SDport == store->SDport) {
854 unique_store[i++] = store;
855 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
860 /* Call each unique Storage daemon */
861 for (j=0; j<i; j++) {
862 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
866 /* Count Client items */
870 foreach_res(client, R_CLIENT) {
873 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
874 /* Find Unique Client address/port */
875 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
877 unique_client[i++] = client;
878 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
880 for (j=0; j<i; j++) {
881 if (strcmp(unique_client[j]->address, client->address) == 0 &&
882 unique_client[j]->FDport == client->FDport) {
888 unique_client[i++] = client;
889 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
894 /* Call each unique File daemon */
895 for (j=0; j<i; j++) {
896 do_client_setdebug(ua, unique_client[j], level, trace_flag, hangup);
902 * setdebug level=nn all trace=1/0
904 static int setdebug_cmd(UAContext *ua, const char *cmd)
913 Dmsg1(120, "setdebug:%s:\n", cmd);
916 i = find_arg_with_value(ua, "level");
918 level = atoi(ua->argv[i]);
921 if (!get_pint(ua, _("Enter new debug level: "))) {
924 level = ua->pint32_val;
927 /* Look for trace flag. -1 => not change */
928 i = find_arg_with_value(ua, "trace");
930 trace_flag = atoi(ua->argv[i]);
931 if (trace_flag > 0) {
936 /* Look for hangup (debug only)flag. -1 => not change */
937 i = find_arg_with_value(ua, "hangup");
939 hangup = atoi(ua->argv[i]);
944 for (i=1; i<ua->argc; i++) {
945 if (strcasecmp(ua->argk[i], "all") == 0) {
946 do_all_setdebug(ua, level, trace_flag, hangup);
949 if (strcasecmp(ua->argk[i], "dir") == 0 ||
950 strcasecmp(ua->argk[i], "director") == 0) {
952 set_trace(trace_flag);
955 if (strcasecmp(ua->argk[i], "client") == 0 ||
956 strcasecmp(ua->argk[i], "fd") == 0) {
959 client = GetClientResWithName(ua->argv[i]);
961 do_client_setdebug(ua, client, level, trace_flag, hangup);
965 client = select_client_resource(ua);
967 do_client_setdebug(ua, client, level, trace_flag, hangup);
972 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
973 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
974 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
977 store = GetStoreResWithName(ua->argv[i]);
979 do_storage_setdebug(ua, store, level, trace_flag);
983 store = get_storage_resource(ua, false/*no default*/);
985 do_storage_setdebug(ua, store, level, trace_flag);
991 * We didn't find an appropriate keyword above, so
994 start_prompt(ua, _("Available daemons are: \n"));
995 add_prompt(ua, _("Director"));
996 add_prompt(ua, _("Storage"));
997 add_prompt(ua, _("Client"));
998 add_prompt(ua, _("All"));
999 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1000 case 0: /* Director */
1001 debug_level = level;
1002 set_trace(trace_flag);
1005 store = get_storage_resource(ua, false/*no default*/);
1007 do_storage_setdebug(ua, store, level, trace_flag);
1011 client = select_client_resource(ua);
1013 do_client_setdebug(ua, client, level, trace_flag, hangup);
1017 do_all_setdebug(ua, level, trace_flag, hangup);
1026 * Turn debug tracing to file on/off
1028 static int trace_cmd(UAContext *ua, const char *cmd)
1032 if (ua->argc != 2) {
1033 if (!get_cmd(ua, _("Turn on or off? "))) {
1038 onoff = ua->argk[1];
1041 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1046 static int var_cmd(UAContext *ua, const char *cmd)
1048 POOLMEM *val = get_pool_memory(PM_FNAME);
1051 if (!open_client_db(ua)) {
1054 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1057 while (*var == ' ') { /* skip spaces */
1060 Dmsg1(100, "Var=%s:\n", var);
1061 variable_expansion(ua->jcr, var, &val);
1062 ua->send_msg("%s\n", val);
1063 free_pool_memory(val);
1067 static int estimate_cmd(UAContext *ua, const char *cmd)
1070 CLIENT *client = NULL;
1071 FILESET *fileset = NULL;
1073 char since[MAXSTRING];
1077 jcr->setJobLevel(L_FULL);
1078 for (int i=1; i<ua->argc; i++) {
1079 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1080 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1082 client = GetClientResWithName(ua->argv[i]);
1084 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1087 if (!acl_access_ok(ua, Client_ACL, client->name())) {
1088 ua->error_msg(_("No authorization for Client \"%s\"\n"), client->name());
1093 ua->error_msg(_("Client name missing.\n"));
1097 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1099 job = GetJobResWithName(ua->argv[i]);
1101 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1104 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1105 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1110 ua->error_msg(_("Job name missing.\n"));
1115 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1117 fileset = GetFileSetResWithName(ua->argv[i]);
1119 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1122 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1123 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1128 ua->error_msg(_("Fileset name missing.\n"));
1132 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1136 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1138 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1139 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1143 ua->error_msg(_("Level value missing.\n"));
1147 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 if (!job && !(client && fileset)) {
1155 if (!(job = select_job_resource(ua))) {
1160 job = GetJobResWithName(ua->argk[1]);
1162 ua->error_msg(_("No job specified.\n"));
1165 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1166 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1171 client = job->client;
1174 fileset = job->fileset;
1176 jcr->client = client;
1177 jcr->fileset = fileset;
1179 if (job->pool->catalog) {
1180 ua->catalog = job->pool->catalog;
1182 ua->catalog = client->catalog;
1190 jcr->setJobType(JT_BACKUP);
1191 jcr->start_time = time(NULL);
1192 init_jcr_job_record(jcr);
1194 if (!get_or_create_client_record(jcr)) {
1197 if (!get_or_create_fileset_record(jcr)) {
1201 get_level_since_time(ua->jcr, since, sizeof(since));
1203 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1204 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1205 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1206 ua->error_msg(_("Failed to connect to Client.\n"));
1210 if (!send_include_list(jcr)) {
1211 ua->error_msg(_("Error sending include list.\n"));
1215 if (!send_exclude_list(jcr)) {
1216 ua->error_msg(_("Error sending exclude list.\n"));
1220 /* The level string change if accurate mode is enabled */
1221 if (accurate >= 0) {
1222 jcr->accurate = accurate;
1224 jcr->accurate = job->accurate;
1227 if (!send_level_command(jcr)) {
1232 * If the job is in accurate mode, we send the list of
1235 Dmsg1(40, "estimate accurate=%d\n", jcr->accurate);
1236 if (!send_accurate_current_files(jcr)) {
1240 jcr->file_bsock->fsend("estimate listing=%d\n", listing);
1241 while (jcr->file_bsock->recv() >= 0) {
1242 ua->send_msg("%s", jcr->file_bsock->msg);
1246 if (jcr->file_bsock) {
1247 jcr->file_bsock->signal(BNET_TERMINATE);
1248 jcr->file_bsock->close();
1249 jcr->file_bsock = NULL;
1258 static int time_cmd(UAContext *ua, const char *cmd)
1261 time_t ttime = time(NULL);
1263 (void)localtime_r(&ttime, &tm);
1264 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1265 ua->send_msg("%s\n", sdt);
1270 * reload the conf file
1272 extern "C" void reload_config(int sig);
1274 static int reload_cmd(UAContext *ua, const char *cmd)
1281 * Delete Pool records (should purge Media with it).
1283 * delete pool=<pool-name>
1284 * delete volume pool=<pool-name> volume=<name>
1287 static int delete_cmd(UAContext *ua, const char *cmd)
1289 static const char *keywords[] = {
1295 if (!open_client_db(ua)) {
1299 switch (find_arg_keyword(ua, keywords)) {
1308 while ((i=find_arg(ua, "jobid")) > 0) {
1310 *ua->argk[i] = 0; /* zap keyword already visited */
1318 "In general it is not a good idea to delete either a\n"
1319 "Pool or a Volume since they may contain data.\n\n"));
1321 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1332 ua->warning_msg(_("Nothing done.\n"));
1340 * delete_job has been modified to parse JobID lists like the
1342 * delete JobID=3,4,6,7-11,14
1344 * Thanks to Phil Stracchino for the above addition.
1347 static void delete_job(UAContext *ua)
1352 int i = find_arg_with_value(ua, NT_("jobid"));
1354 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1355 s = bstrdup(ua->argv[i]);
1358 * We could use strtok() here. But we're not going to, because:
1359 * (a) strtok() is deprecated, having been replaced by strsep();
1360 * (b) strtok() is broken in significant ways.
1361 * we could use strsep() instead, but it's not universally available.
1362 * so we grow our own using strchr().
1364 sep = strchr(tok, ',');
1365 while (sep != NULL) {
1367 if (!delete_job_id_range(ua, tok)) {
1368 JobId = str_to_int64(tok);
1369 do_job_delete(ua, JobId);
1372 sep = strchr(tok, ',');
1374 /* pick up the last token */
1375 if (!delete_job_id_range(ua, tok)) {
1376 JobId = str_to_int64(tok);
1377 do_job_delete(ua, JobId);
1382 JobId = str_to_int64(ua->argv[i]);
1383 do_job_delete(ua, JobId);
1385 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1388 JobId = ua->int64_val;
1389 do_job_delete(ua, JobId);
1394 * we call delete_job_id_range to parse range tokens and iterate over ranges
1396 static bool delete_job_id_range(UAContext *ua, char *tok)
1401 tok2 = strchr(tok, '-');
1407 j1 = str_to_int64(tok);
1408 j2 = str_to_int64(tok2);
1409 for (j=j1; j<=j2; j++) {
1410 do_job_delete(ua, j);
1416 * do_job_delete now performs the actual delete operation atomically
1418 static void do_job_delete(UAContext *ua, JobId_t JobId)
1422 edit_int64(JobId, ed1);
1423 purge_jobs_from_catalog(ua, ed1);
1424 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1428 * Delete media records from database -- dangerous
1430 static int delete_volume(UAContext *ua)
1436 if (!select_media_dbr(ua, &mr)) {
1439 ua->warning_msg(_("\nThis command will delete volume %s\n"
1440 "and all Jobs saved on that volume from the Catalog\n"),
1443 if (find_arg(ua, "yes") >= 0) {
1444 ua->pint32_val = 1; /* Have "yes" on command line already" */
1446 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1448 if (!get_yesno(ua, buf)) {
1452 if (!ua->pint32_val) {
1456 /* If not purged, do it */
1457 if (strcmp(mr.VolStatus, "Purged") != 0) {
1458 if (!db_get_volume_jobids(ua->jcr, ua->db, &mr, &lst)) {
1459 ua->error_msg(_("Can't list jobs on this volume\n"));
1463 purge_jobs_from_catalog(ua, lst.list);
1467 db_delete_media_record(ua->jcr, ua->db, &mr);
1472 * Delete a pool record from the database -- dangerous
1474 static int delete_pool(UAContext *ua)
1479 memset(&pr, 0, sizeof(pr));
1481 if (!get_pool_dbr(ua, &pr)) {
1484 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1486 if (!get_yesno(ua, buf)) {
1489 if (ua->pint32_val) {
1490 db_delete_pool_record(ua->jcr, ua->db, &pr);
1495 int memory_cmd(UAContext *ua, const char *cmd)
1497 garbage_collect_memory();
1498 list_dir_status_header(ua);
1499 sm_dump(false, true);
1503 static void do_mount_cmd(UAContext *ua, const char *command)
1508 char dev_name[MAX_NAME_LENGTH];
1512 if (!open_client_db(ua)) {
1515 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1517 store.store = get_storage_resource(ua, true/*arg is storage*/);
1521 pm_strcpy(store.store_source, _("unknown source"));
1522 set_wstorage(jcr, &store);
1523 drive = get_storage_drive(ua, store.store);
1524 if (strcmp(command, "mount") == 0) {
1525 slot = get_storage_slot(ua, store.store);
1528 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1529 store.store->media_type, store.store->dev_name(), drive);
1531 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1532 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1535 sd = jcr->store_bsock;
1536 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1537 bash_spaces(dev_name);
1539 sd->fsend("%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1541 sd->fsend("%s %s drive=%d", command, dev_name, drive);
1543 while (sd->recv() >= 0) {
1544 ua->send_msg("%s", sd->msg);
1546 sd->signal(BNET_TERMINATE);
1548 jcr->store_bsock = NULL;
1552 * mount [storage=<name>] [drive=nn] [slot=mm]
1554 static int mount_cmd(UAContext *ua, const char *cmd)
1556 do_mount_cmd(ua, "mount"); /* mount */
1562 * unmount [storage=<name>] [drive=nn]
1564 static int unmount_cmd(UAContext *ua, const char *cmd)
1566 do_mount_cmd(ua, "unmount"); /* unmount */
1572 * release [storage=<name>] [drive=nn]
1574 static int release_cmd(UAContext *ua, const char *cmd)
1576 do_mount_cmd(ua, "release"); /* release */
1583 * use catalog=<name>
1585 static int use_cmd(UAContext *ua, const char *cmd)
1587 CAT *oldcatalog, *catalog;
1590 close_db(ua); /* close any previously open db */
1591 oldcatalog = ua->catalog;
1593 if (!(catalog = get_catalog_resource(ua))) {
1594 ua->catalog = oldcatalog;
1596 ua->catalog = catalog;
1599 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1600 ua->catalog->name(), ua->catalog->db_name);
1605 int quit_cmd(UAContext *ua, const char *cmd)
1611 /* Handler to get job status */
1612 static int status_handler(void *ctx, int num_fields, char **row)
1614 char *val = (char *)ctx;
1619 *val = '?'; /* Unknown by default */
1626 * Wait until no job is running
1628 int wait_cmd(UAContext *ua, const char *cmd)
1632 time_t stop_time = 0;
1636 * Wait until no job is running
1638 if (ua->argc == 1) {
1639 bmicrosleep(0, 200000); /* let job actually start */
1640 for (bool running=true; running; ) {
1643 if (jcr->JobId != 0) {
1657 i = find_arg_with_value(ua, NT_("timeout"));
1658 if (i > 0 && ua->argv[i]) {
1659 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1662 /* we have jobid, jobname or ujobid argument */
1664 uint32_t jobid = 0 ;
1666 if (!open_client_db(ua)) {
1667 ua->error_msg(_("ERR: Can't open db\n")) ;
1671 for (int i=1; i<ua->argc; i++) {
1672 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1676 jobid = str_to_int64(ua->argv[i]);
1678 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1679 strcasecmp(ua->argk[i], "job") == 0) {
1683 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1685 jobid = jcr->JobId ;
1689 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1693 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1695 jobid = jcr->JobId ;
1699 /* Wait for a mount request */
1700 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1701 for (bool waiting=false; !waiting; ) {
1703 if (jcr->JobId != 0 &&
1704 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1713 if (stop_time && (time(NULL) >= stop_time)) {
1714 ua->warning_msg(_("Wait on mount timed out\n"));
1724 ua->error_msg(_("ERR: Job was not found\n"));
1729 * We wait the end of a specific job
1732 bmicrosleep(0, 200000); /* let job actually start */
1733 for (bool running=true; running; ) {
1736 jcr=get_jcr_by_id(jobid) ;
1749 * We have to get JobStatus
1753 char jobstatus = '?'; /* Unknown by default */
1756 bsnprintf(buf, sizeof(buf),
1757 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1760 db_sql_query(ua->db, buf,
1761 status_handler, (void *)&jobstatus);
1763 switch (jobstatus) {
1765 status = 1 ; /* Warning */
1769 case JS_ErrorTerminated:
1771 status = 2 ; /* Critical */
1776 status = 0 ; /* Ok */
1780 status = 3 ; /* Unknown */
1784 ua->send_msg("JobId=%i\n", jobid) ;
1785 ua->send_msg("JobStatus=%s (%c)\n",
1786 job_status_to_str(jobstatus),
1789 if (ua->gui || ua->api) {
1790 ua->send_msg("ExitStatus=%i\n", status) ;
1797 static int help_cmd(UAContext *ua, const char *cmd)
1800 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1801 for (i=0; i<comsize; i++) {
1802 if (ua->argc == 2) {
1803 if (!strcasecmp(ua->argk[1], commands[i].key)) {
1804 ua->send_msg(_(" %-13s %s\n\nArguments:\n\t%s\n"), commands[i].key,
1805 commands[i].help, commands[i].usage);
1809 ua->send_msg(_(" %-13s %s\n"), commands[i].key, commands[i].help);
1812 if (i == comsize && ua->argc == 2) {
1813 ua->send_msg(_("\nCan't find %s command.\n\n"), ua->argk[1]);
1815 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1819 int qhelp_cmd(UAContext *ua, const char *cmd)
1822 /* Want to display only commands */
1823 j = find_arg(ua, NT_("all"));
1825 for (i=0; i<comsize; i++) {
1826 ua->send_msg("%s\n", commands[i].key);
1830 /* Want to display a specific help section */
1831 j = find_arg_with_value(ua, NT_("item"));
1832 if (j >= 0 && ua->argk[j]) {
1833 for (i=0; i<comsize; i++) {
1834 if (bstrcmp(commands[i].key, ua->argv[j])) {
1835 ua->send_msg("%s\n", commands[i].usage);
1841 /* Want to display everything */
1842 for (i=0; i<comsize; i++) {
1843 ua->send_msg("%s %s -- %s\n", commands[i].key, commands[i].help, commands[i].usage);
1849 static int version_cmd(UAContext *ua, const char *cmd)
1851 ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
1852 HOST_OS, DISTNAME, DISTVER, NPRTB(director->verid));
1857 * Test code -- turned on only for debug testing
1859 static int version_cmd(UAContext *ua, const char *cmd)
1862 POOL_MEM query(PM_MESSAGE);
1864 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1865 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1866 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1867 for (int i=0; i < ids.num_ids; i++) {
1868 ua->send_msg("id=%d\n", ids.DBId[i]);
1876 * This call uses open_client_db() and force a
1877 * new dedicated connection to the catalog
1879 bool open_new_client_db(UAContext *ua)
1883 /* Force a new dedicated connection */
1885 ua->force_mult_db_connections = true;
1886 ret = open_client_db(ua);
1887 ua->force_mult_db_connections = false;
1892 * This call explicitly checks for a catalog=xxx and
1893 * if given, opens that catalog. It also checks for
1894 * client=xxx and if found, opens the catalog
1895 * corresponding to that client. If we still don't
1896 * have a catalog, look for a Job keyword and get the
1897 * catalog from its client record.
1899 bool open_client_db(UAContext *ua)
1906 /* Try for catalog keyword */
1907 i = find_arg_with_value(ua, NT_("catalog"));
1909 if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1910 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1913 catalog = GetCatalogResWithName(ua->argv[i]);
1915 if (ua->catalog && ua->catalog != catalog) {
1918 ua->catalog = catalog;
1923 /* Try for client keyword */
1924 i = find_arg_with_value(ua, NT_("client"));
1926 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1927 ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1930 client = GetClientResWithName(ua->argv[i]);
1932 catalog = client->catalog;
1933 if (ua->catalog && ua->catalog != catalog) {
1936 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1937 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1940 ua->catalog = catalog;
1945 /* Try for Job keyword */
1946 i = find_arg_with_value(ua, NT_("job"));
1948 if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
1949 ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
1952 job = GetJobResWithName(ua->argv[i]);
1954 catalog = job->client->catalog;
1955 if (ua->catalog && ua->catalog != catalog) {
1958 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1959 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1962 ua->catalog = catalog;
1972 * Open the catalog database.
1974 bool open_db(UAContext *ua)
1982 ua->catalog = get_catalog_resource(ua);
1984 ua->error_msg( _("Could not find a Catalog resource\n"));
1989 /* Some modules like bvfs need their own catalog connection */
1990 mult_db_conn = ua->catalog->mult_db_connections;
1991 if (ua->force_mult_db_connections) {
1992 mult_db_conn = true;
1995 ua->jcr->catalog = ua->catalog;
1997 Dmsg0(100, "UA Open database\n");
1998 ua->db = db_init_database(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
1999 ua->catalog->db_user,
2000 ua->catalog->db_password, ua->catalog->db_address,
2001 ua->catalog->db_port, ua->catalog->db_socket,
2002 mult_db_conn, ua->catalog->disable_batch_insert);
2003 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
2004 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
2005 ua->catalog->db_name);
2007 ua->error_msg("%s", db_strerror(ua->db));
2012 ua->jcr->db = ua->db;
2014 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
2016 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
2020 void close_db(UAContext *ua)
2023 db_close_database(ua->jcr, ua->db);