2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version two of the GNU General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Bacula Director -- User Agent Commands
32 * Kern Sibbald, September MM
42 #undef _POSIX_C_SOURCE
45 #include "lib/pythonlib.h"
47 /* Imported Functions */
48 extern PyObject *job_getattr(PyObject *self, char *attrname);
49 extern int job_setattr(PyObject *self, char *attrname, PyObject *value);
51 #endif /* HAVE_PYTHON */
53 /* Imported subroutines */
55 /* Imported variables */
56 extern jobq_t job_queue; /* job queue */
59 /* Imported functions */
60 extern int autodisplay_cmd(UAContext *ua, const char *cmd);
61 extern int gui_cmd(UAContext *ua, const char *cmd);
62 extern int label_cmd(UAContext *ua, const char *cmd);
63 extern int list_cmd(UAContext *ua, const char *cmd);
64 extern int llist_cmd(UAContext *ua, const char *cmd);
65 extern int messagescmd(UAContext *ua, const char *cmd);
66 extern int prunecmd(UAContext *ua, const char *cmd);
67 extern int purgecmd(UAContext *ua, const char *cmd);
68 extern int querycmd(UAContext *ua, const char *cmd);
69 extern int relabel_cmd(UAContext *ua, const char *cmd);
70 extern int restore_cmd(UAContext *ua, const char *cmd);
71 extern int retentioncmd(UAContext *ua, const char *cmd);
72 extern int show_cmd(UAContext *ua, const char *cmd);
73 extern int sqlquerycmd(UAContext *ua, const char *cmd);
74 extern int status_cmd(UAContext *ua, const char *cmd);
75 extern int update_cmd(UAContext *ua, const char *cmd);
77 /* Forward referenced functions */
78 static int add_cmd(UAContext *ua, const char *cmd);
79 static int automount_cmd(UAContext *ua, const char *cmd);
80 static int cancel_cmd(UAContext *ua, const char *cmd);
81 static int create_cmd(UAContext *ua, const char *cmd);
82 static int delete_cmd(UAContext *ua, const char *cmd);
83 static int disable_cmd(UAContext *ua, const char *cmd);
84 static int enable_cmd(UAContext *ua, const char *cmd);
85 static int estimate_cmd(UAContext *ua, const char *cmd);
86 static int help_cmd(UAContext *ua, const char *cmd);
87 static int memory_cmd(UAContext *ua, const char *cmd);
88 static int mount_cmd(UAContext *ua, const char *cmd);
89 static int python_cmd(UAContext *ua, const char *cmd);
90 static int release_cmd(UAContext *ua, const char *cmd);
91 static int reload_cmd(UAContext *ua, const char *cmd);
92 static int setdebug_cmd(UAContext *ua, const char *cmd);
93 static int setip_cmd(UAContext *ua, const char *cmd);
94 static int time_cmd(UAContext *ua, const char *cmd);
95 static int trace_cmd(UAContext *ua, const char *cmd);
96 static int unmount_cmd(UAContext *ua, const char *cmd);
97 static int use_cmd(UAContext *ua, const char *cmd);
98 static int var_cmd(UAContext *ua, const char *cmd);
99 static int version_cmd(UAContext *ua, const char *cmd);
100 static int wait_cmd(UAContext *ua, const char *cmd);
102 static void do_job_delete(UAContext *ua, JobId_t JobId);
103 static void delete_job_id_range(UAContext *ua, char *tok);
104 static int delete_volume(UAContext *ua);
105 static int delete_pool(UAContext *ua);
106 static void delete_job(UAContext *ua);
108 int qhelp_cmd(UAContext *ua, const char *cmd);
109 int quit_cmd(UAContext *ua, const char *cmd);
111 /* not all in alphabetical order. New commands are added after existing commands with similar letters
112 to prevent breakage of existing user scripts. */
113 struct cmdstruct { const char *key; int (*func)(UAContext *ua, const char *cmd); const char *help; const bool use_in_rs;};
114 static struct cmdstruct commands[] = { /* Can use it in Console RunScript*/
115 { NT_("add"), add_cmd, _("add [pool=<pool-name> storage=<storage> jobid=<JobId>] -- "
116 "\n add media to a pool"), false},
117 { NT_("autodisplay"), autodisplay_cmd, _("autodisplay [on|off] -- console messages"),false},
118 { NT_("automount"), automount_cmd, _("automount [on|off] -- after label"), false},
119 { NT_("cancel"), cancel_cmd, _("cancel [jobid=<number> job=<job-name> ujobid=<unique-jobid>] -- "
120 "\n cancel a job"), false},
121 { NT_("create"), create_cmd, _("create [pool=<pool-name>] -- create DB Pool from resource"), false},
122 { NT_("delete"), delete_cmd, _("delete [volume=<vol-name> pool=<pool-name> job jobid=<id>]"), true},
123 { NT_("disable"), disable_cmd, _("disable <job=name> -- disable a job"), true},
124 { NT_("enable"), enable_cmd, _("enable <job=name> -- enable a job"), true},
125 { NT_("estimate"), estimate_cmd, _("performs FileSet estimate, listing gives full listing"
126 "\n you can make it more accurate with accurate=yes/no"), true},
127 { NT_("exit"), quit_cmd, _("exit = quit"), false},
128 { NT_("gui"), gui_cmd, _("gui [on|off] -- non-interactive gui mode"), false},
129 { NT_("help"), help_cmd, _("print this command"), false},
130 { NT_("label"), label_cmd, _("label a tape"), false},
131 { NT_("list"), list_cmd, _("list [pools | jobs | jobtotals | media <pool=pool-name> | "
132 "\n files <jobid=nn> | copies <jobid=nn>]; from catalog"), true},
133 { NT_("llist"), llist_cmd, _("full or long list like list command"), true},
134 { NT_("messages"), messagescmd, _("messages"), false},
135 { NT_("memory"), memory_cmd, _("print current memory usage"), true},
136 { NT_("mount"), mount_cmd, _("mount storage=<storage-name> [ slot=<num> ] [ drive=<num> ] "
137 "\n or mount [ jobid=<id> | job=<job-name> ]"), false},
138 { NT_("prune"), prunecmd, _("prune files|jobs|volume client=<client-name> volume=<volume-name> "
139 "\n prune expired records from catalog"), true},
140 { NT_("purge"), purgecmd, _("purge records from catalog"), true},
141 { NT_("python"), python_cmd, _("python control commands"), false},
142 { NT_("quit"), quit_cmd, _("quit"), false},
143 { NT_("query"), querycmd, _("query catalog"), false},
144 { NT_("restore"), restore_cmd, _("restore files"), false},
145 { NT_("relabel"), relabel_cmd, _("relabel storage=<storage-name> oldvolume=<old-volume-name> "
146 "\n volume=<newvolume-name> -- relabel a tape"), false},
147 { NT_("release"), release_cmd, _("release <storage-name>"), false},
148 { NT_("reload"), reload_cmd, _("reload conf file"), true},
149 { NT_("run"), run_cmd, _("run job=<job-name> client=<client-name> fileset=<FileSet-name> "
150 "\n level=<level-keyword> storage=<storage-name> where=<directory-prefix> "
151 "\n when=<universal-time-specification> yes"), false}, /* need to be check */
152 { NT_("status"), status_cmd, _("status [all | dir=<dir-name> | director | client=<client-name> |"
153 "\n storage=<storage-name> | days=nnn]"), true},
154 { NT_("setdebug"), setdebug_cmd, _("setdebug level=nn [trace=0/1 client=<client-name> |"
155 "\n dir | director | storage=<storage-name> | all] -- sets debug level"), true},
156 { NT_("setip"), setip_cmd, _("sets new client address -- if authorized"), false},
157 { NT_("show"), show_cmd, _("show (resource records) [jobs | pools | ... | all]"), true},
158 { NT_("sqlquery"), sqlquerycmd, _("use SQL to query catalog"), false},
159 { NT_("time"), time_cmd, _("print current time"), true},
160 { NT_("trace"), trace_cmd, _("turn on/off trace to file"), true},
161 { NT_("unmount"), unmount_cmd, _("unmount storage=<storage-name> [ drive=<num> ] "
162 "\n or unmount [ jobid=<id> | job=<job-name> ]"), false},
163 { NT_("umount"), unmount_cmd, _("umount - for old-time Unix guys, see unmount"),false},
164 { NT_("update"), update_cmd, _("update Volume, Pool or slots"), true},
165 { NT_("use"), use_cmd, _("use <database-name> -- catalog xxx"), false},
166 { NT_("var"), var_cmd, _("does variable expansion"), false},
167 { NT_("version"), version_cmd, _("print Director version"), true},
168 { NT_("wait"), wait_cmd, _("wait [<jobname=name> | <jobid=nnn> | <ujobid=complete_name>] -- "
169 "\n wait until no jobs are running"), false}
172 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
175 * Execute a command from the UA
177 bool do_a_command(UAContext *ua)
183 BSOCK *user = ua->UA_sock;
186 Dmsg1(900, "Command: %s\n", ua->argk[0]);
191 while (ua->jcr->wstorage->size()) {
192 ua->jcr->wstorage->remove(0);
195 len = strlen(ua->argk[0]);
196 for (i=0; i<comsize; i++) { /* search for command */
197 if (strncasecmp(ua->argk[0], commands[i].key, len) == 0) {
198 /* Check if command permitted, but "quit" is always OK */
199 if (strcmp(ua->argk[0], NT_("quit")) != 0 &&
200 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
203 /* Check if this command is authorized in RunScript */
204 if (ua->runscript && !commands[i].use_in_rs) {
205 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
208 if (ua->api) user->signal(BNET_CMD_BEGIN);
209 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
210 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
216 ua->error_msg(_("%s: is an invalid command.\n"), ua->argk[0]);
223 * This is a common routine used to stuff the Pool DB record defaults
224 * into the Media DB record just before creating a media (Volume)
227 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
229 mr->PoolId = pr->PoolId;
230 bstrncpy(mr->VolStatus, NT_("Append"), sizeof(mr->VolStatus));
231 mr->Recycle = pr->Recycle;
232 mr->VolRetention = pr->VolRetention;
233 mr->VolUseDuration = pr->VolUseDuration;
234 mr->RecyclePoolId = pr->RecyclePoolId;
235 mr->MaxVolJobs = pr->MaxVolJobs;
236 mr->MaxVolFiles = pr->MaxVolFiles;
237 mr->MaxVolBytes = pr->MaxVolBytes;
238 mr->LabelType = pr->LabelType;
244 * Add Volumes to an existing Pool
246 static int add_cmd(UAContext *ua, const char *cmd)
250 int num, i, max, startnum;
252 char name[MAX_NAME_LENGTH];
254 int Slot = 0, InChanger = 0;
257 "You probably don't want to be using this command since it\n"
258 "creates database records without labeling the Volumes.\n"
259 "You probably want to use the \"label\" command.\n\n"));
261 if (!open_client_db(ua)) {
265 memset(&pr, 0, sizeof(pr));
266 memset(&mr, 0, sizeof(mr));
268 if (!get_pool_dbr(ua, &pr)) {
272 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
273 pr.MaxVols, pr.PoolType);
275 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
276 ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
277 if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
280 pr.MaxVols = ua->pint32_val;
284 if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
285 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
286 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
290 if (pr.MaxVols == 0) {
293 max = pr.MaxVols - pr.NumVols;
297 bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
298 if (!get_pint(ua, buf)) {
301 num = ua->pint32_val;
302 if (num < 0 || num > max) {
303 ua->warning_msg(_("The number must be between 0 and %d\n"), max);
311 if (!get_cmd(ua, _("Enter Volume name: "))) {
315 if (!get_cmd(ua, _("Enter base volume name: "))) {
319 /* Don't allow | in Volume name because it is the volume separator character */
320 if (!is_volume_name_legal(ua, ua->cmd)) {
323 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
324 ua->warning_msg(_("Volume name too long.\n"));
327 if (strlen(ua->cmd) == 0) {
328 ua->warning_msg(_("Volume name must be at least one character long.\n"));
334 bstrncpy(name, ua->cmd, sizeof(name));
336 bstrncat(name, "%04d", sizeof(name));
339 if (!get_pint(ua, _("Enter the starting number: "))) {
342 startnum = ua->pint32_val;
344 ua->warning_msg(_("Start number must be greater than zero.\n"));
354 if (store && store->autochanger) {
355 if (!get_pint(ua, _("Enter slot (0 for none): "))) {
358 Slot = ua->pint32_val;
359 if (!get_yesno(ua, _("InChanger? yes/no: "))) {
362 InChanger = ua->pint32_val;
365 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
366 for (i=startnum; i < num+startnum; i++) {
367 bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
369 mr.InChanger = InChanger;
370 mr.StorageId = store->StorageId;
372 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
373 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
374 ua->error_msg("%s", db_strerror(ua->db));
378 first_id = mr.PoolId;
382 Dmsg0(200, "Update pool record.\n");
383 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
384 ua->warning_msg("%s", db_strerror(ua->db));
387 ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
393 * Turn auto mount on/off
398 int automount_cmd(UAContext *ua, const char *cmd)
403 if (!get_cmd(ua, _("Turn on or off? "))) {
411 ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
419 static int cancel_cmd(UAContext *ua, const char *cmd)
424 char JobName[MAX_NAME_LENGTH];
426 for (i=1; i<ua->argc; i++) {
427 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
432 JobId = str_to_int64(ua->argv[i]);
433 if (!(jcr=get_jcr_by_id(JobId))) {
434 ua->error_msg(_("JobId %s is not running. Use Job name to cancel inactive jobs.\n"), ua->argv[i]);
438 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
442 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
443 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
444 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
445 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
448 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
452 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
453 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
454 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
455 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
462 if (jcr->job && !acl_access_ok(ua, Job_ACL, jcr->job->name())) {
463 ua->error_msg(_("Unauthorized command from this console.\n"));
468 * If we still do not have a jcr,
469 * throw up a list and ask the user to select one.
472 int tjobs = 0; /* total # number jobs */
473 /* Count Jobs running */
475 if (jcr->JobId == 0) { /* this is us */
478 tjobs++; /* count of all jobs */
479 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
480 continue; /* skip not authorized */
482 njobs++; /* count of authorized jobs */
486 if (njobs == 0) { /* no authorized */
488 ua->send_msg(_("No Jobs running.\n"));
490 ua->send_msg(_("None of your jobs are running.\n"));
495 start_prompt(ua, _("Select Job:\n"));
498 if (jcr->JobId == 0) { /* this is us */
501 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
502 continue; /* skip not authorized */
504 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
509 if (do_prompt(ua, _("Job"), _("Choose Job to cancel"), buf, sizeof(buf)) < 0) {
512 if (ua->api && njobs == 1) {
514 bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf,
515 _("Confirm cancel?"));
516 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
521 if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
526 sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
527 jcr = get_jcr_by_full_name(JobName);
529 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
534 ret = cancel_job(ua, jcr);
540 * This is a common routine to create or update a
541 * Pool DB base record from a Pool Resource. We handle
542 * the setting of MaxVols and NumVols slightly differently
543 * depending on if we are creating the Pool or we are
544 * simply bringing it into agreement with the resource (updage).
546 * Caution : RecyclePoolId isn't setup in this function.
547 * You can use set_pooldbr_recyclepoolid();
550 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
552 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
553 if (op == POOL_OP_CREATE) {
554 pr->MaxVols = pool->max_volumes;
556 } else { /* update pool */
557 if (pr->MaxVols != pool->max_volumes) {
558 pr->MaxVols = pool->max_volumes;
560 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
561 pr->MaxVols = pr->NumVols;
564 pr->LabelType = pool->LabelType;
565 pr->UseOnce = pool->use_volume_once;
566 pr->UseCatalog = pool->use_catalog;
567 pr->Recycle = pool->Recycle;
568 pr->VolRetention = pool->VolRetention;
569 pr->VolUseDuration = pool->VolUseDuration;
570 pr->MaxVolJobs = pool->MaxVolJobs;
571 pr->MaxVolFiles = pool->MaxVolFiles;
572 pr->MaxVolBytes = pool->MaxVolBytes;
573 pr->AutoPrune = pool->AutoPrune;
574 pr->Recycle = pool->Recycle;
575 if (pool->label_format) {
576 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
578 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
582 /* set/update Pool.RecyclePoolId and Pool.ScratchPoolId in Catalog */
583 int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
587 if (!pool->RecyclePool && !pool->ScratchPool) {
591 memset(&pr, 0, sizeof(POOL_DBR));
592 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
594 if (!db_get_pool_record(jcr, db, &pr)) {
595 return -1; /* not exists in database */
598 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
600 if (!set_pooldbr_references(jcr, db, &pr, pool)) {
601 return -1; /* error */
604 if (!db_update_pool_record(jcr, db, &pr)) {
605 return -1; /* error */
610 /* set POOL_DBR.RecyclePoolId and POOL_DBR.ScratchPoolId from Pool resource
611 * works with set_pooldbr_from_poolres
613 bool set_pooldbr_references(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
618 if (pool->RecyclePool) {
619 memset(&rpool, 0, sizeof(POOL_DBR));
621 bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
622 if (db_get_pool_record(jcr, db, &rpool)) {
623 pr->RecyclePoolId = rpool.PoolId;
625 Jmsg(jcr, M_WARNING, 0,
626 _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
627 "Try to update it with 'update pool=%s'\n"),
628 pool->name(), rpool.Name, rpool.Name,pool->name());
632 } else { /* no RecyclePool used, set it to 0 */
633 pr->RecyclePoolId = 0;
636 if (pool->ScratchPool) {
637 memset(&rpool, 0, sizeof(POOL_DBR));
639 bstrncpy(rpool.Name, pool->ScratchPool->name(), sizeof(rpool.Name));
640 if (db_get_pool_record(jcr, db, &rpool)) {
641 pr->ScratchPoolId = rpool.PoolId;
643 Jmsg(jcr, M_WARNING, 0,
644 _("Can't set %s ScratchPool to %s, %s is not in database.\n" \
645 "Try to update it with 'update pool=%s'\n"),
646 pool->name(), rpool.Name, rpool.Name,pool->name());
649 } else { /* no ScratchPool used, set it to 0 */
650 pr->ScratchPoolId = 0;
658 * Create a pool record from a given Pool resource
659 * Also called from backup.c
660 * Returns: -1 on error
661 * 0 record already exists
665 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
669 memset(&pr, 0, sizeof(POOL_DBR));
671 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
673 if (db_get_pool_record(jcr, db, &pr)) {
675 if (op == POOL_OP_UPDATE) { /* update request */
676 set_pooldbr_from_poolres(&pr, pool, op);
677 set_pooldbr_references(jcr, db, &pr, pool);
678 db_update_pool_record(jcr, db, &pr);
680 return 0; /* exists */
683 set_pooldbr_from_poolres(&pr, pool, op);
684 set_pooldbr_references(jcr, db, &pr, pool);
686 if (!db_create_pool_record(jcr, db, &pr)) {
687 return -1; /* error */
695 * Create a Pool Record in the database.
696 * It is always created from the Resource record.
698 static int create_cmd(UAContext *ua, const char *cmd)
702 if (!open_client_db(ua)) {
706 pool = get_pool_resource(ua);
711 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
713 ua->error_msg(_("Error: Pool %s already exists.\n"
714 "Use update to change it.\n"), pool->name());
718 ua->error_msg("%s", db_strerror(ua->db));
724 ua->send_msg(_("Pool %s created.\n"), pool->name());
729 extern DIRRES *director;
730 extern char *configfile;
733 * Python control command
734 * python restart (restarts interpreter)
736 static int python_cmd(UAContext *ua, const char *cmd)
739 init_python_interpreter_args python_args;
741 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
742 term_python_interpreter();
744 python_args.progname = director->name();
745 python_args.scriptdir = director->scripts_directory;
746 python_args.modulename = "DirStartUp";
747 python_args.configfile = configfile;
748 python_args.workingdir = director->working_directory;
749 python_args.job_getattr = job_getattr;
750 python_args.job_setattr = job_setattr;
752 init_python_interpreter(&python_args);
754 ua->send_msg(_("Python interpreter restarted.\n"));
756 #endif /* HAVE_PYTHON */
757 ua->warning_msg(_("Nothing done.\n"));
760 #endif /* HAVE_PYTHON */
766 * Set a new address in a Client resource. We do this only
767 * if the Console name is the same as the Client name
768 * and the Console can access the client.
770 static int setip_cmd(UAContext *ua, const char *cmd)
774 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
775 ua->error_msg(_("Unauthorized command from this console.\n"));
779 client = GetClientResWithName(ua->cons->name());
782 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
785 if (client->address) {
786 free(client->address);
788 /* MA Bug 6 remove ifdef */
789 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
790 client->address = bstrdup(buf);
791 ua->send_msg(_("Client \"%s\" address set to %s\n"),
792 client->name(), client->address);
799 static void do_en_disable_cmd(UAContext *ua, bool setting)
804 i = find_arg_with_value(ua, NT_("job"));
806 job = select_job_resource(ua);
812 job = GetJobResWithName(ua->argv[i]);
816 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
820 if (!acl_access_ok(ua, Job_ACL, job->name())) {
821 ua->error_msg(_("Unauthorized command from this console.\n"));
824 job->enabled = setting;
825 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
829 static int enable_cmd(UAContext *ua, const char *cmd)
831 do_en_disable_cmd(ua, true);
835 static int disable_cmd(UAContext *ua, const char *cmd)
837 do_en_disable_cmd(ua, false);
842 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
848 lstore.store = store;
849 pm_strcpy(lstore.store_source, _("unknown source"));
850 set_wstorage(jcr, &lstore);
851 /* Try connecting for up to 15 seconds */
852 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
853 store->name(), store->address, store->SDport);
854 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
855 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
858 Dmsg0(120, _("Connected to storage daemon\n"));
859 sd = jcr->store_bsock;
860 sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
861 if (sd->recv() >= 0) {
862 ua->send_msg("%s", sd->msg);
864 sd->signal(BNET_TERMINATE);
866 jcr->store_bsock = NULL;
870 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
874 /* Connect to File daemon */
876 ua->jcr->client = client;
877 /* Try to connect for 15 seconds */
878 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
879 client->name(), client->address, client->FDport);
880 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
881 ua->error_msg(_("Failed to connect to Client.\n"));
884 Dmsg0(120, "Connected to file daemon\n");
885 fd = ua->jcr->file_bsock;
886 fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
887 if (fd->recv() >= 0) {
888 ua->send_msg("%s", fd->msg);
890 fd->signal(BNET_TERMINATE);
892 ua->jcr->file_bsock = NULL;
897 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
899 STORE *store, **unique_store;
900 CLIENT *client, **unique_client;
906 /* Count Storage items */
910 foreach_res(store, R_STORAGE) {
913 unique_store = (STORE **) malloc(i * sizeof(STORE));
914 /* Find Unique Storage address/port */
915 store = (STORE *)GetNextRes(R_STORAGE, NULL);
917 unique_store[i++] = store;
918 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
920 for (j=0; j<i; j++) {
921 if (strcmp(unique_store[j]->address, store->address) == 0 &&
922 unique_store[j]->SDport == store->SDport) {
928 unique_store[i++] = store;
929 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
934 /* Call each unique Storage daemon */
935 for (j=0; j<i; j++) {
936 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
940 /* Count Client items */
944 foreach_res(client, R_CLIENT) {
947 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
948 /* Find Unique Client address/port */
949 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
951 unique_client[i++] = client;
952 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
954 for (j=0; j<i; j++) {
955 if (strcmp(unique_client[j]->address, client->address) == 0 &&
956 unique_client[j]->FDport == client->FDport) {
962 unique_client[i++] = client;
963 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
968 /* Call each unique File daemon */
969 for (j=0; j<i; j++) {
970 do_client_setdebug(ua, unique_client[j], level, trace_flag);
976 * setdebug level=nn all trace=1/0
978 static int setdebug_cmd(UAContext *ua, const char *cmd)
986 Dmsg1(120, "setdebug:%s:\n", cmd);
989 i = find_arg_with_value(ua, "level");
991 level = atoi(ua->argv[i]);
994 if (!get_pint(ua, _("Enter new debug level: "))) {
997 level = ua->pint32_val;
1000 /* Look for trace flag. -1 => not change */
1001 i = find_arg_with_value(ua, "trace");
1003 trace_flag = atoi(ua->argv[i]);
1004 if (trace_flag > 0) {
1009 /* General debug? */
1010 for (i=1; i<ua->argc; i++) {
1011 if (strcasecmp(ua->argk[i], "all") == 0) {
1012 do_all_setdebug(ua, level, trace_flag);
1015 if (strcasecmp(ua->argk[i], "dir") == 0 ||
1016 strcasecmp(ua->argk[i], "director") == 0) {
1017 debug_level = level;
1018 set_trace(trace_flag);
1021 if (strcasecmp(ua->argk[i], "client") == 0 ||
1022 strcasecmp(ua->argk[i], "fd") == 0) {
1025 client = GetClientResWithName(ua->argv[i]);
1027 do_client_setdebug(ua, client, level, trace_flag);
1031 client = select_client_resource(ua);
1033 do_client_setdebug(ua, client, level, trace_flag);
1038 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
1039 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1040 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1043 store = GetStoreResWithName(ua->argv[i]);
1045 do_storage_setdebug(ua, store, level, trace_flag);
1049 store = get_storage_resource(ua, false/*no default*/);
1051 do_storage_setdebug(ua, store, level, trace_flag);
1057 * We didn't find an appropriate keyword above, so
1060 start_prompt(ua, _("Available daemons are: \n"));
1061 add_prompt(ua, _("Director"));
1062 add_prompt(ua, _("Storage"));
1063 add_prompt(ua, _("Client"));
1064 add_prompt(ua, _("All"));
1065 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1066 case 0: /* Director */
1067 debug_level = level;
1068 set_trace(trace_flag);
1071 store = get_storage_resource(ua, false/*no default*/);
1073 do_storage_setdebug(ua, store, level, trace_flag);
1077 client = select_client_resource(ua);
1079 do_client_setdebug(ua, client, level, trace_flag);
1083 do_all_setdebug(ua, level, trace_flag);
1092 * Turn debug tracing to file on/off
1094 static int trace_cmd(UAContext *ua, const char *cmd)
1098 if (ua->argc != 2) {
1099 if (!get_cmd(ua, _("Turn on or off? "))) {
1104 onoff = ua->argk[1];
1107 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1112 static int var_cmd(UAContext *ua, const char *cmd)
1114 POOLMEM *val = get_pool_memory(PM_FNAME);
1117 if (!open_client_db(ua)) {
1120 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1123 while (*var == ' ') { /* skip spaces */
1126 Dmsg1(100, "Var=%s:\n", var);
1127 variable_expansion(ua->jcr, var, &val);
1128 ua->send_msg("%s\n", val);
1129 free_pool_memory(val);
1133 static int estimate_cmd(UAContext *ua, const char *cmd)
1136 CLIENT *client = NULL;
1137 FILESET *fileset = NULL;
1139 char since[MAXSTRING];
1143 jcr->set_JobLevel(L_FULL);
1144 for (int i=1; i<ua->argc; i++) {
1145 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1146 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1148 client = GetClientResWithName(ua->argv[i]);
1150 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1155 ua->error_msg(_("Client name missing.\n"));
1159 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1161 job = GetJobResWithName(ua->argv[i]);
1163 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1166 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1167 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1172 ua->error_msg(_("Job name missing.\n"));
1177 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1179 fileset = GetFileSetResWithName(ua->argv[i]);
1181 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1184 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1185 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1190 ua->error_msg(_("Fileset name missing.\n"));
1194 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1198 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1200 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1201 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1205 ua->error_msg(_("Level value missing.\n"));
1209 if (strcasecmp(ua->argk[i], NT_("accurate")) == 0) {
1210 if (!is_yesno(ua->argv[i], &accurate)) {
1211 ua->error_msg(_("Invalid value for accurate. "
1212 "It must be yes or no.\n"));
1216 if (!job && !(client && fileset)) {
1217 if (!(job = select_job_resource(ua))) {
1222 job = GetJobResWithName(ua->argk[1]);
1224 ua->error_msg(_("No job specified.\n"));
1227 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1228 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1233 client = job->client;
1236 fileset = job->fileset;
1238 jcr->client = client;
1239 jcr->fileset = fileset;
1241 if (job->pool->catalog) {
1242 ua->catalog = job->pool->catalog;
1244 ua->catalog = client->catalog;
1252 jcr->set_JobType(JT_BACKUP);
1253 init_jcr_job_record(jcr);
1255 if (!get_or_create_client_record(jcr)) {
1258 if (!get_or_create_fileset_record(jcr)) {
1262 get_level_since_time(ua->jcr, since, sizeof(since));
1264 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1265 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1266 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1267 ua->error_msg(_("Failed to connect to Client.\n"));
1271 if (!send_include_list(jcr)) {
1272 ua->error_msg(_("Error sending include list.\n"));
1276 if (!send_exclude_list(jcr)) {
1277 ua->error_msg(_("Error sending exclude list.\n"));
1281 /* The level string change if accurate mode is enabled */
1282 if (accurate >= 0) {
1283 jcr->accurate = accurate;
1285 jcr->accurate = job->accurate;
1288 if (!send_level_command(jcr)) {
1293 * If the job is in accurate mode, we send the list of
1296 Dmsg1(40, "estimate accurate=%i\n", jcr->accurate);
1297 if (!send_accurate_current_files(jcr)) {
1301 bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1302 while (bnet_recv(jcr->file_bsock) >= 0) {
1303 ua->send_msg("%s", jcr->file_bsock->msg);
1307 if (jcr->file_bsock) {
1308 bnet_sig(jcr->file_bsock, BNET_TERMINATE);
1309 bnet_close(jcr->file_bsock);
1310 jcr->file_bsock = NULL;
1319 static int time_cmd(UAContext *ua, const char *cmd)
1322 time_t ttime = time(NULL);
1324 (void)localtime_r(&ttime, &tm);
1325 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1326 ua->send_msg("%s\n", sdt);
1331 * reload the conf file
1333 extern "C" void reload_config(int sig);
1335 static int reload_cmd(UAContext *ua, const char *cmd)
1342 * Delete Pool records (should purge Media with it).
1344 * delete pool=<pool-name>
1345 * delete volume pool=<pool-name> volume=<name>
1348 static int delete_cmd(UAContext *ua, const char *cmd)
1350 static const char *keywords[] = {
1356 if (!open_client_db(ua)) {
1360 switch (find_arg_keyword(ua, keywords)) {
1369 while ((i=find_arg(ua, "jobid")) > 0) {
1371 *ua->argk[i] = 0; /* zap keyword already visited */
1379 "In general it is not a good idea to delete either a\n"
1380 "Pool or a Volume since they may contain data.\n\n"));
1382 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1393 ua->warning_msg(_("Nothing done.\n"));
1401 * delete_job has been modified to parse JobID lists like the
1403 * delete JobID=3,4,6,7-11,14
1405 * Thanks to Phil Stracchino for the above addition.
1408 static void delete_job(UAContext *ua)
1413 int i = find_arg_with_value(ua, NT_("jobid"));
1415 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1416 s = bstrdup(ua->argv[i]);
1419 * We could use strtok() here. But we're not going to, because:
1420 * (a) strtok() is deprecated, having been replaced by strsep();
1421 * (b) strtok() is broken in significant ways.
1422 * we could use strsep() instead, but it's not universally available.
1423 * so we grow our own using strchr().
1425 sep = strchr(tok, ',');
1426 while (sep != NULL) {
1428 if (strchr(tok, '-')) {
1429 delete_job_id_range(ua, tok);
1431 JobId = str_to_int64(tok);
1432 do_job_delete(ua, JobId);
1435 sep = strchr(tok, ',');
1437 /* pick up the last token */
1438 if (strchr(tok, '-')) {
1439 delete_job_id_range(ua, tok);
1441 JobId = str_to_int64(tok);
1442 do_job_delete(ua, JobId);
1447 JobId = str_to_int64(ua->argv[i]);
1448 do_job_delete(ua, JobId);
1450 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1453 JobId = ua->int64_val;
1454 do_job_delete(ua, JobId);
1459 * we call delete_job_id_range to parse range tokens and iterate over ranges
1461 static void delete_job_id_range(UAContext *ua, char *tok)
1466 tok2 = strchr(tok, '-');
1469 j1 = str_to_int64(tok);
1470 j2 = str_to_int64(tok2);
1471 for (j=j1; j<=j2; j++) {
1472 do_job_delete(ua, j);
1477 * do_job_delete now performs the actual delete operation atomically
1479 static void do_job_delete(UAContext *ua, JobId_t JobId)
1483 edit_int64(JobId, ed1);
1484 purge_jobs_from_catalog(ua, ed1);
1485 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1489 * Delete media records from database -- dangerous
1491 static int delete_volume(UAContext *ua)
1496 if (!select_media_dbr(ua, &mr)) {
1499 ua->warning_msg(_("\nThis command will delete volume %s\n"
1500 "and all Jobs saved on that volume from the Catalog\n"),
1503 if (find_arg(ua, "yes") >= 0) {
1504 ua->pint32_val = 1; /* Have "yes" on command line already" */
1506 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1508 if (!get_yesno(ua, buf)) {
1512 if (ua->pint32_val) {
1513 db_delete_media_record(ua->jcr, ua->db, &mr);
1519 * Delete a pool record from the database -- dangerous
1521 static int delete_pool(UAContext *ua)
1526 memset(&pr, 0, sizeof(pr));
1528 if (!get_pool_dbr(ua, &pr)) {
1531 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1533 if (!get_yesno(ua, buf)) {
1536 if (ua->pint32_val) {
1537 db_delete_pool_record(ua->jcr, ua->db, &pr);
1542 int memory_cmd(UAContext *ua, const char *cmd)
1544 list_dir_status_header(ua);
1545 sm_dump(false, true);
1549 static void do_mount_cmd(UAContext *ua, const char *command)
1554 char dev_name[MAX_NAME_LENGTH];
1558 if (!open_client_db(ua)) {
1561 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1563 store.store = get_storage_resource(ua, true/*arg is storage*/);
1567 pm_strcpy(store.store_source, _("unknown source"));
1568 set_wstorage(jcr, &store);
1569 drive = get_storage_drive(ua, store.store);
1570 if (strcmp(command, "mount") == 0) {
1571 slot = get_storage_slot(ua, store.store);
1574 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1575 store.store->media_type, store.store->dev_name(), drive);
1577 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1578 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1581 sd = jcr->store_bsock;
1582 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1583 bash_spaces(dev_name);
1585 bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1587 bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1589 while (bnet_recv(sd) >= 0) {
1590 ua->send_msg("%s", sd->msg);
1592 bnet_sig(sd, BNET_TERMINATE);
1594 jcr->store_bsock = NULL;
1598 * mount [storage=<name>] [drive=nn] [slot=mm]
1600 static int mount_cmd(UAContext *ua, const char *cmd)
1602 do_mount_cmd(ua, "mount"); /* mount */
1608 * unmount [storage=<name>] [drive=nn]
1610 static int unmount_cmd(UAContext *ua, const char *cmd)
1612 do_mount_cmd(ua, "unmount"); /* unmount */
1618 * release [storage=<name>] [drive=nn]
1620 static int release_cmd(UAContext *ua, const char *cmd)
1622 do_mount_cmd(ua, "release"); /* release */
1629 * use catalog=<name>
1631 static int use_cmd(UAContext *ua, const char *cmd)
1633 CAT *oldcatalog, *catalog;
1636 close_db(ua); /* close any previously open db */
1637 oldcatalog = ua->catalog;
1639 if (!(catalog = get_catalog_resource(ua))) {
1640 ua->catalog = oldcatalog;
1642 ua->catalog = catalog;
1645 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1646 ua->catalog->name(), ua->catalog->db_name);
1651 int quit_cmd(UAContext *ua, const char *cmd)
1657 /* Handler to get job status */
1658 static int status_handler(void *ctx, int num_fields, char **row)
1660 char *val = (char *)ctx;
1665 *val = '?'; /* Unknown by default */
1672 * Wait until no job is running
1674 int wait_cmd(UAContext *ua, const char *cmd)
1678 time_t stop_time = 0;
1682 * Wait until no job is running
1684 if (ua->argc == 1) {
1685 bmicrosleep(0, 200000); /* let job actually start */
1686 for (bool running=true; running; ) {
1689 if (jcr->JobId != 0) {
1703 i = find_arg_with_value(ua, NT_("timeout"));
1704 if (i > 0 && ua->argv[i]) {
1705 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1708 /* we have jobid, jobname or ujobid argument */
1710 uint32_t jobid = 0 ;
1712 if (!open_client_db(ua)) {
1713 ua->error_msg(_("ERR: Can't open db\n")) ;
1717 for (int i=1; i<ua->argc; i++) {
1718 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1722 jobid = str_to_int64(ua->argv[i]);
1724 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1725 strcasecmp(ua->argk[i], "job") == 0) {
1729 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1731 jobid = jcr->JobId ;
1735 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1739 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1741 jobid = jcr->JobId ;
1745 /* Wait for a mount request */
1746 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1747 for (bool waiting=false; !waiting; ) {
1749 if (jcr->JobId != 0 &&
1750 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1759 if (stop_time && (time(NULL) >= stop_time)) {
1760 ua->warning_msg(_("Wait on mount timed out\n"));
1770 ua->error_msg(_("ERR: Job was not found\n"));
1775 * We wait the end of a specific job
1778 bmicrosleep(0, 200000); /* let job actually start */
1779 for (bool running=true; running; ) {
1782 jcr=get_jcr_by_id(jobid) ;
1795 * We have to get JobStatus
1799 char jobstatus = '?'; /* Unknown by default */
1802 bsnprintf(buf, sizeof(buf),
1803 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1806 db_sql_query(ua->db, buf,
1807 status_handler, (void *)&jobstatus);
1809 switch (jobstatus) {
1811 status = 1 ; /* Warning */
1815 case JS_ErrorTerminated:
1817 status = 2 ; /* Critical */
1822 status = 0 ; /* Ok */
1826 status = 3 ; /* Unknown */
1830 ua->send_msg("JobId=%i\n", jobid) ;
1831 ua->send_msg("JobStatus=%s (%c)\n",
1832 job_status_to_str(jobstatus),
1835 if (ua->gui || ua->api) {
1836 ua->send_msg("ExitStatus=%i\n", status) ;
1843 static int help_cmd(UAContext *ua, const char *cmd)
1847 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1848 for (i=0; i<comsize; i++) {
1849 ua->send_msg(_(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1851 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1855 int qhelp_cmd(UAContext *ua, const char *cmd)
1859 for (i=0; i<comsize; i++) {
1860 ua->send_msg("%s %s\n", commands[i].key, _(commands[i].help));
1866 static int version_cmd(UAContext *ua, const char *cmd)
1868 ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
1869 HOST_OS, DISTNAME, DISTVER, NPRTB(director->verid));
1874 * Test code -- turned on only for debug testing
1876 static int version_cmd(UAContext *ua, const char *cmd)
1879 POOL_MEM query(PM_MESSAGE);
1881 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1882 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1883 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1884 for (int i=0; i < ids.num_ids; i++) {
1885 ua->send_msg("id=%d\n", ids.DBId[i]);
1893 * This call explicitly checks for a catalog=xxx and
1894 * if given, opens that catalog. It also checks for
1895 * client=xxx and if found, opens the catalog
1896 * corresponding to that client. If we still don't
1897 * have a catalog, look for a Job keyword and get the
1898 * catalog from its client record.
1900 bool open_client_db(UAContext *ua)
1907 /* Try for catalog keyword */
1908 i = find_arg_with_value(ua, NT_("catalog"));
1910 if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1911 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1914 catalog = GetCatalogResWithName(ua->argv[i]);
1916 if (ua->catalog && ua->catalog != catalog) {
1919 ua->catalog = catalog;
1924 /* Try for client keyword */
1925 i = find_arg_with_value(ua, NT_("client"));
1927 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1928 ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1931 client = GetClientResWithName(ua->argv[i]);
1933 catalog = client->catalog;
1934 if (ua->catalog && ua->catalog != catalog) {
1937 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1938 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1941 ua->catalog = catalog;
1946 /* Try for Job keyword */
1947 i = find_arg_with_value(ua, NT_("job"));
1949 if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
1950 ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
1953 job = GetJobResWithName(ua->argv[i]);
1955 catalog = job->client->catalog;
1956 if (ua->catalog && ua->catalog != catalog) {
1959 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1960 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1963 ua->catalog = catalog;
1973 * Open the catalog database.
1975 bool open_db(UAContext *ua)
1981 ua->catalog = get_catalog_resource(ua);
1983 ua->error_msg( _("Could not find a Catalog resource\n"));
1988 ua->jcr->catalog = ua->catalog;
1990 Dmsg0(100, "UA Open database\n");
1991 ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
1992 ua->catalog->db_user,
1993 ua->catalog->db_password, ua->catalog->db_address,
1994 ua->catalog->db_port, ua->catalog->db_socket,
1995 ua->catalog->mult_db_connections);
1996 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
1997 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
1998 ua->catalog->db_name);
2000 ua->error_msg("%s", db_strerror(ua->db));
2005 ua->jcr->db = ua->db;
2007 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
2009 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
2013 void close_db(UAContext *ua)
2016 db_close_database(ua->jcr, ua->db);