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->ActionOnPurge = pr->ActionOnPurge;
235 mr->RecyclePoolId = pr->RecyclePoolId;
236 mr->MaxVolJobs = pr->MaxVolJobs;
237 mr->MaxVolFiles = pr->MaxVolFiles;
238 mr->MaxVolBytes = pr->MaxVolBytes;
239 mr->LabelType = pr->LabelType;
245 * Add Volumes to an existing Pool
247 static int add_cmd(UAContext *ua, const char *cmd)
251 int num, i, max, startnum;
253 char name[MAX_NAME_LENGTH];
255 int Slot = 0, InChanger = 0;
258 "You probably don't want to be using this command since it\n"
259 "creates database records without labeling the Volumes.\n"
260 "You probably want to use the \"label\" command.\n\n"));
262 if (!open_client_db(ua)) {
266 memset(&pr, 0, sizeof(pr));
267 memset(&mr, 0, sizeof(mr));
269 if (!get_pool_dbr(ua, &pr)) {
273 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
274 pr.MaxVols, pr.PoolType);
276 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
277 ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
278 if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
281 pr.MaxVols = ua->pint32_val;
285 if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
286 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
287 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
291 if (pr.MaxVols == 0) {
294 max = pr.MaxVols - pr.NumVols;
298 bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
299 if (!get_pint(ua, buf)) {
302 num = ua->pint32_val;
303 if (num < 0 || num > max) {
304 ua->warning_msg(_("The number must be between 0 and %d\n"), max);
312 if (!get_cmd(ua, _("Enter Volume name: "))) {
316 if (!get_cmd(ua, _("Enter base volume name: "))) {
320 /* Don't allow | in Volume name because it is the volume separator character */
321 if (!is_volume_name_legal(ua, ua->cmd)) {
324 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
325 ua->warning_msg(_("Volume name too long.\n"));
328 if (strlen(ua->cmd) == 0) {
329 ua->warning_msg(_("Volume name must be at least one character long.\n"));
335 bstrncpy(name, ua->cmd, sizeof(name));
337 bstrncat(name, "%04d", sizeof(name));
340 if (!get_pint(ua, _("Enter the starting number: "))) {
343 startnum = ua->pint32_val;
345 ua->warning_msg(_("Start number must be greater than zero.\n"));
355 if (store && store->autochanger) {
356 if (!get_pint(ua, _("Enter slot (0 for none): "))) {
359 Slot = ua->pint32_val;
360 if (!get_yesno(ua, _("InChanger? yes/no: "))) {
363 InChanger = ua->pint32_val;
366 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
367 for (i=startnum; i < num+startnum; i++) {
368 bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
370 mr.InChanger = InChanger;
371 mr.StorageId = store->StorageId;
373 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
374 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
375 ua->error_msg("%s", db_strerror(ua->db));
379 first_id = mr.PoolId;
383 Dmsg0(200, "Update pool record.\n");
384 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
385 ua->warning_msg("%s", db_strerror(ua->db));
388 ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
394 * Turn auto mount on/off
399 int automount_cmd(UAContext *ua, const char *cmd)
404 if (!get_cmd(ua, _("Turn on or off? "))) {
412 ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
420 static int cancel_cmd(UAContext *ua, const char *cmd)
425 char JobName[MAX_NAME_LENGTH];
427 for (i=1; i<ua->argc; i++) {
428 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
433 JobId = str_to_int64(ua->argv[i]);
434 if (!(jcr=get_jcr_by_id(JobId))) {
435 ua->error_msg(_("JobId %s is not running. Use Job name to cancel inactive jobs.\n"), ua->argv[i]);
439 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
443 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
444 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
445 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
446 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
449 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
453 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
454 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
455 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
456 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
463 if (jcr->job && !acl_access_ok(ua, Job_ACL, jcr->job->name())) {
464 ua->error_msg(_("Unauthorized command from this console.\n"));
469 * If we still do not have a jcr,
470 * throw up a list and ask the user to select one.
473 int tjobs = 0; /* total # number jobs */
474 /* Count Jobs running */
476 if (jcr->JobId == 0) { /* this is us */
479 tjobs++; /* count of all jobs */
480 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
481 continue; /* skip not authorized */
483 njobs++; /* count of authorized jobs */
487 if (njobs == 0) { /* no authorized */
489 ua->send_msg(_("No Jobs running.\n"));
491 ua->send_msg(_("None of your jobs are running.\n"));
496 start_prompt(ua, _("Select Job:\n"));
499 if (jcr->JobId == 0) { /* this is us */
502 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
503 continue; /* skip not authorized */
505 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
510 if (do_prompt(ua, _("Job"), _("Choose Job to cancel"), buf, sizeof(buf)) < 0) {
513 if (ua->api && njobs == 1) {
515 bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf,
516 _("Confirm cancel?"));
517 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
522 if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
527 sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
528 jcr = get_jcr_by_full_name(JobName);
530 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
535 ret = cancel_job(ua, jcr);
541 * This is a common routine to create or update a
542 * Pool DB base record from a Pool Resource. We handle
543 * the setting of MaxVols and NumVols slightly differently
544 * depending on if we are creating the Pool or we are
545 * simply bringing it into agreement with the resource (updage).
547 * Caution : RecyclePoolId isn't setup in this function.
548 * You can use set_pooldbr_recyclepoolid();
551 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
553 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
554 if (op == POOL_OP_CREATE) {
555 pr->MaxVols = pool->max_volumes;
557 } else { /* update pool */
558 if (pr->MaxVols != pool->max_volumes) {
559 pr->MaxVols = pool->max_volumes;
561 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
562 pr->MaxVols = pr->NumVols;
565 pr->LabelType = pool->LabelType;
566 pr->UseOnce = pool->use_volume_once;
567 pr->UseCatalog = pool->use_catalog;
568 pr->Recycle = pool->Recycle;
569 pr->VolRetention = pool->VolRetention;
570 pr->VolUseDuration = pool->VolUseDuration;
571 pr->MaxVolJobs = pool->MaxVolJobs;
572 pr->MaxVolFiles = pool->MaxVolFiles;
573 pr->MaxVolBytes = pool->MaxVolBytes;
574 pr->AutoPrune = pool->AutoPrune;
575 pr->ActionOnPurge = pool->action_on_purge;
576 pr->Recycle = pool->Recycle;
577 if (pool->label_format) {
578 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
580 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
584 /* set/update Pool.RecyclePoolId and Pool.ScratchPoolId in Catalog */
585 int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
589 if (!pool->RecyclePool && !pool->ScratchPool) {
593 memset(&pr, 0, sizeof(POOL_DBR));
594 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
596 if (!db_get_pool_record(jcr, db, &pr)) {
597 return -1; /* not exists in database */
600 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
602 if (!set_pooldbr_references(jcr, db, &pr, pool)) {
603 return -1; /* error */
606 if (!db_update_pool_record(jcr, db, &pr)) {
607 return -1; /* error */
612 /* set POOL_DBR.RecyclePoolId and POOL_DBR.ScratchPoolId from Pool resource
613 * works with set_pooldbr_from_poolres
615 bool set_pooldbr_references(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
620 if (pool->RecyclePool) {
621 memset(&rpool, 0, sizeof(POOL_DBR));
623 bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
624 if (db_get_pool_record(jcr, db, &rpool)) {
625 pr->RecyclePoolId = rpool.PoolId;
627 Jmsg(jcr, M_WARNING, 0,
628 _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
629 "Try to update it with 'update pool=%s'\n"),
630 pool->name(), rpool.Name, rpool.Name,pool->name());
634 } else { /* no RecyclePool used, set it to 0 */
635 pr->RecyclePoolId = 0;
638 if (pool->ScratchPool) {
639 memset(&rpool, 0, sizeof(POOL_DBR));
641 bstrncpy(rpool.Name, pool->ScratchPool->name(), sizeof(rpool.Name));
642 if (db_get_pool_record(jcr, db, &rpool)) {
643 pr->ScratchPoolId = rpool.PoolId;
645 Jmsg(jcr, M_WARNING, 0,
646 _("Can't set %s ScratchPool to %s, %s is not in database.\n" \
647 "Try to update it with 'update pool=%s'\n"),
648 pool->name(), rpool.Name, rpool.Name,pool->name());
651 } else { /* no ScratchPool used, set it to 0 */
652 pr->ScratchPoolId = 0;
660 * Create a pool record from a given Pool resource
661 * Also called from backup.c
662 * Returns: -1 on error
663 * 0 record already exists
667 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
671 memset(&pr, 0, sizeof(POOL_DBR));
673 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
675 if (db_get_pool_record(jcr, db, &pr)) {
677 if (op == POOL_OP_UPDATE) { /* update request */
678 set_pooldbr_from_poolres(&pr, pool, op);
679 set_pooldbr_references(jcr, db, &pr, pool);
680 db_update_pool_record(jcr, db, &pr);
682 return 0; /* exists */
685 set_pooldbr_from_poolres(&pr, pool, op);
686 set_pooldbr_references(jcr, db, &pr, pool);
688 if (!db_create_pool_record(jcr, db, &pr)) {
689 return -1; /* error */
697 * Create a Pool Record in the database.
698 * It is always created from the Resource record.
700 static int create_cmd(UAContext *ua, const char *cmd)
704 if (!open_client_db(ua)) {
708 pool = get_pool_resource(ua);
713 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
715 ua->error_msg(_("Error: Pool %s already exists.\n"
716 "Use update to change it.\n"), pool->name());
720 ua->error_msg("%s", db_strerror(ua->db));
726 ua->send_msg(_("Pool %s created.\n"), pool->name());
731 extern DIRRES *director;
732 extern char *configfile;
735 * Python control command
736 * python restart (restarts interpreter)
738 static int python_cmd(UAContext *ua, const char *cmd)
741 init_python_interpreter_args python_args;
743 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
744 term_python_interpreter();
746 python_args.progname = director->name();
747 python_args.scriptdir = director->scripts_directory;
748 python_args.modulename = "DirStartUp";
749 python_args.configfile = configfile;
750 python_args.workingdir = director->working_directory;
751 python_args.job_getattr = job_getattr;
752 python_args.job_setattr = job_setattr;
754 init_python_interpreter(&python_args);
756 ua->send_msg(_("Python interpreter restarted.\n"));
758 #endif /* HAVE_PYTHON */
759 ua->warning_msg(_("Nothing done.\n"));
762 #endif /* HAVE_PYTHON */
768 * Set a new address in a Client resource. We do this only
769 * if the Console name is the same as the Client name
770 * and the Console can access the client.
772 static int setip_cmd(UAContext *ua, const char *cmd)
776 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
777 ua->error_msg(_("Unauthorized command from this console.\n"));
781 client = GetClientResWithName(ua->cons->name());
784 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
787 if (client->address) {
788 free(client->address);
790 /* MA Bug 6 remove ifdef */
791 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
792 client->address = bstrdup(buf);
793 ua->send_msg(_("Client \"%s\" address set to %s\n"),
794 client->name(), client->address);
801 static void do_en_disable_cmd(UAContext *ua, bool setting)
806 i = find_arg_with_value(ua, NT_("job"));
808 job = select_enable_disable_job_resource(ua, setting);
814 job = GetJobResWithName(ua->argv[i]);
818 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
822 if (!acl_access_ok(ua, Job_ACL, job->name())) {
823 ua->error_msg(_("Unauthorized command from this console.\n"));
826 job->enabled = setting;
827 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
831 static int enable_cmd(UAContext *ua, const char *cmd)
833 do_en_disable_cmd(ua, true);
837 static int disable_cmd(UAContext *ua, const char *cmd)
839 do_en_disable_cmd(ua, false);
844 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
850 lstore.store = store;
851 pm_strcpy(lstore.store_source, _("unknown source"));
852 set_wstorage(jcr, &lstore);
853 /* Try connecting for up to 15 seconds */
854 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
855 store->name(), store->address, store->SDport);
856 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
857 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
860 Dmsg0(120, _("Connected to storage daemon\n"));
861 sd = jcr->store_bsock;
862 sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
863 if (sd->recv() >= 0) {
864 ua->send_msg("%s", sd->msg);
866 sd->signal(BNET_TERMINATE);
868 jcr->store_bsock = NULL;
872 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
876 /* Connect to File daemon */
878 ua->jcr->client = client;
879 /* Try to connect for 15 seconds */
880 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
881 client->name(), client->address, client->FDport);
882 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
883 ua->error_msg(_("Failed to connect to Client.\n"));
886 Dmsg0(120, "Connected to file daemon\n");
887 fd = ua->jcr->file_bsock;
888 fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
889 if (fd->recv() >= 0) {
890 ua->send_msg("%s", fd->msg);
892 fd->signal(BNET_TERMINATE);
894 ua->jcr->file_bsock = NULL;
899 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
901 STORE *store, **unique_store;
902 CLIENT *client, **unique_client;
908 /* Count Storage items */
912 foreach_res(store, R_STORAGE) {
915 unique_store = (STORE **) malloc(i * sizeof(STORE));
916 /* Find Unique Storage address/port */
917 store = (STORE *)GetNextRes(R_STORAGE, NULL);
919 unique_store[i++] = store;
920 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
922 for (j=0; j<i; j++) {
923 if (strcmp(unique_store[j]->address, store->address) == 0 &&
924 unique_store[j]->SDport == store->SDport) {
930 unique_store[i++] = store;
931 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
936 /* Call each unique Storage daemon */
937 for (j=0; j<i; j++) {
938 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
942 /* Count Client items */
946 foreach_res(client, R_CLIENT) {
949 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
950 /* Find Unique Client address/port */
951 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
953 unique_client[i++] = client;
954 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
956 for (j=0; j<i; j++) {
957 if (strcmp(unique_client[j]->address, client->address) == 0 &&
958 unique_client[j]->FDport == client->FDport) {
964 unique_client[i++] = client;
965 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
970 /* Call each unique File daemon */
971 for (j=0; j<i; j++) {
972 do_client_setdebug(ua, unique_client[j], level, trace_flag);
978 * setdebug level=nn all trace=1/0
980 static int setdebug_cmd(UAContext *ua, const char *cmd)
988 Dmsg1(120, "setdebug:%s:\n", cmd);
991 i = find_arg_with_value(ua, "level");
993 level = atoi(ua->argv[i]);
996 if (!get_pint(ua, _("Enter new debug level: "))) {
999 level = ua->pint32_val;
1002 /* Look for trace flag. -1 => not change */
1003 i = find_arg_with_value(ua, "trace");
1005 trace_flag = atoi(ua->argv[i]);
1006 if (trace_flag > 0) {
1011 /* General debug? */
1012 for (i=1; i<ua->argc; i++) {
1013 if (strcasecmp(ua->argk[i], "all") == 0) {
1014 do_all_setdebug(ua, level, trace_flag);
1017 if (strcasecmp(ua->argk[i], "dir") == 0 ||
1018 strcasecmp(ua->argk[i], "director") == 0) {
1019 debug_level = level;
1020 set_trace(trace_flag);
1023 if (strcasecmp(ua->argk[i], "client") == 0 ||
1024 strcasecmp(ua->argk[i], "fd") == 0) {
1027 client = GetClientResWithName(ua->argv[i]);
1029 do_client_setdebug(ua, client, level, trace_flag);
1033 client = select_client_resource(ua);
1035 do_client_setdebug(ua, client, level, trace_flag);
1040 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
1041 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1042 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1045 store = GetStoreResWithName(ua->argv[i]);
1047 do_storage_setdebug(ua, store, level, trace_flag);
1051 store = get_storage_resource(ua, false/*no default*/);
1053 do_storage_setdebug(ua, store, level, trace_flag);
1059 * We didn't find an appropriate keyword above, so
1062 start_prompt(ua, _("Available daemons are: \n"));
1063 add_prompt(ua, _("Director"));
1064 add_prompt(ua, _("Storage"));
1065 add_prompt(ua, _("Client"));
1066 add_prompt(ua, _("All"));
1067 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1068 case 0: /* Director */
1069 debug_level = level;
1070 set_trace(trace_flag);
1073 store = get_storage_resource(ua, false/*no default*/);
1075 do_storage_setdebug(ua, store, level, trace_flag);
1079 client = select_client_resource(ua);
1081 do_client_setdebug(ua, client, level, trace_flag);
1085 do_all_setdebug(ua, level, trace_flag);
1094 * Turn debug tracing to file on/off
1096 static int trace_cmd(UAContext *ua, const char *cmd)
1100 if (ua->argc != 2) {
1101 if (!get_cmd(ua, _("Turn on or off? "))) {
1106 onoff = ua->argk[1];
1109 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1114 static int var_cmd(UAContext *ua, const char *cmd)
1116 POOLMEM *val = get_pool_memory(PM_FNAME);
1119 if (!open_client_db(ua)) {
1122 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1125 while (*var == ' ') { /* skip spaces */
1128 Dmsg1(100, "Var=%s:\n", var);
1129 variable_expansion(ua->jcr, var, &val);
1130 ua->send_msg("%s\n", val);
1131 free_pool_memory(val);
1135 static int estimate_cmd(UAContext *ua, const char *cmd)
1138 CLIENT *client = NULL;
1139 FILESET *fileset = NULL;
1141 char since[MAXSTRING];
1145 jcr->set_JobLevel(L_FULL);
1146 for (int i=1; i<ua->argc; i++) {
1147 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1148 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1150 client = GetClientResWithName(ua->argv[i]);
1152 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1155 if (!acl_access_ok(ua, Client_ACL, client->name())) {
1156 ua->error_msg(_("No authorization for Client \"%s\"\n"), client->name());
1161 ua->error_msg(_("Client name missing.\n"));
1165 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1167 job = GetJobResWithName(ua->argv[i]);
1169 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1172 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1173 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1178 ua->error_msg(_("Job name missing.\n"));
1183 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1185 fileset = GetFileSetResWithName(ua->argv[i]);
1187 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1190 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1191 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1196 ua->error_msg(_("Fileset name missing.\n"));
1200 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1204 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1206 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1207 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1211 ua->error_msg(_("Level value missing.\n"));
1215 if (strcasecmp(ua->argk[i], NT_("accurate")) == 0) {
1216 if (!is_yesno(ua->argv[i], &accurate)) {
1217 ua->error_msg(_("Invalid value for accurate. "
1218 "It must be yes or no.\n"));
1222 if (!job && !(client && fileset)) {
1223 if (!(job = select_job_resource(ua))) {
1228 job = GetJobResWithName(ua->argk[1]);
1230 ua->error_msg(_("No job specified.\n"));
1233 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1234 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1239 client = job->client;
1242 fileset = job->fileset;
1244 jcr->client = client;
1245 jcr->fileset = fileset;
1247 if (job->pool->catalog) {
1248 ua->catalog = job->pool->catalog;
1250 ua->catalog = client->catalog;
1258 jcr->set_JobType(JT_BACKUP);
1259 init_jcr_job_record(jcr);
1261 if (!get_or_create_client_record(jcr)) {
1264 if (!get_or_create_fileset_record(jcr)) {
1268 get_level_since_time(ua->jcr, since, sizeof(since));
1270 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1271 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1272 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1273 ua->error_msg(_("Failed to connect to Client.\n"));
1277 if (!send_include_list(jcr)) {
1278 ua->error_msg(_("Error sending include list.\n"));
1282 if (!send_exclude_list(jcr)) {
1283 ua->error_msg(_("Error sending exclude list.\n"));
1287 /* The level string change if accurate mode is enabled */
1288 if (accurate >= 0) {
1289 jcr->accurate = accurate;
1291 jcr->accurate = job->accurate;
1294 if (!send_level_command(jcr)) {
1299 * If the job is in accurate mode, we send the list of
1302 Dmsg1(40, "estimate accurate=%d\n", jcr->accurate);
1303 if (!send_accurate_current_files(jcr)) {
1307 bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1308 while (bnet_recv(jcr->file_bsock) >= 0) {
1309 ua->send_msg("%s", jcr->file_bsock->msg);
1313 if (jcr->file_bsock) {
1314 bnet_sig(jcr->file_bsock, BNET_TERMINATE);
1315 bnet_close(jcr->file_bsock);
1316 jcr->file_bsock = NULL;
1325 static int time_cmd(UAContext *ua, const char *cmd)
1328 time_t ttime = time(NULL);
1330 (void)localtime_r(&ttime, &tm);
1331 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1332 ua->send_msg("%s\n", sdt);
1337 * reload the conf file
1339 extern "C" void reload_config(int sig);
1341 static int reload_cmd(UAContext *ua, const char *cmd)
1348 * Delete Pool records (should purge Media with it).
1350 * delete pool=<pool-name>
1351 * delete volume pool=<pool-name> volume=<name>
1354 static int delete_cmd(UAContext *ua, const char *cmd)
1356 static const char *keywords[] = {
1362 if (!open_client_db(ua)) {
1366 switch (find_arg_keyword(ua, keywords)) {
1375 while ((i=find_arg(ua, "jobid")) > 0) {
1377 *ua->argk[i] = 0; /* zap keyword already visited */
1385 "In general it is not a good idea to delete either a\n"
1386 "Pool or a Volume since they may contain data.\n\n"));
1388 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1399 ua->warning_msg(_("Nothing done.\n"));
1407 * delete_job has been modified to parse JobID lists like the
1409 * delete JobID=3,4,6,7-11,14
1411 * Thanks to Phil Stracchino for the above addition.
1414 static void delete_job(UAContext *ua)
1419 int i = find_arg_with_value(ua, NT_("jobid"));
1421 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1422 s = bstrdup(ua->argv[i]);
1425 * We could use strtok() here. But we're not going to, because:
1426 * (a) strtok() is deprecated, having been replaced by strsep();
1427 * (b) strtok() is broken in significant ways.
1428 * we could use strsep() instead, but it's not universally available.
1429 * so we grow our own using strchr().
1431 sep = strchr(tok, ',');
1432 while (sep != NULL) {
1434 if (strchr(tok, '-')) {
1435 delete_job_id_range(ua, tok);
1437 JobId = str_to_int64(tok);
1438 do_job_delete(ua, JobId);
1441 sep = strchr(tok, ',');
1443 /* pick up the last token */
1444 if (strchr(tok, '-')) {
1445 delete_job_id_range(ua, tok);
1447 JobId = str_to_int64(tok);
1448 do_job_delete(ua, JobId);
1453 JobId = str_to_int64(ua->argv[i]);
1454 do_job_delete(ua, JobId);
1456 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1459 JobId = ua->int64_val;
1460 do_job_delete(ua, JobId);
1465 * we call delete_job_id_range to parse range tokens and iterate over ranges
1467 static void delete_job_id_range(UAContext *ua, char *tok)
1472 tok2 = strchr(tok, '-');
1475 j1 = str_to_int64(tok);
1476 j2 = str_to_int64(tok2);
1477 for (j=j1; j<=j2; j++) {
1478 do_job_delete(ua, j);
1483 * do_job_delete now performs the actual delete operation atomically
1485 static void do_job_delete(UAContext *ua, JobId_t JobId)
1489 edit_int64(JobId, ed1);
1490 purge_jobs_from_catalog(ua, ed1);
1491 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1495 * Delete media records from database -- dangerous
1497 static int delete_volume(UAContext *ua)
1502 if (!select_media_dbr(ua, &mr)) {
1505 ua->warning_msg(_("\nThis command will delete volume %s\n"
1506 "and all Jobs saved on that volume from the Catalog\n"),
1509 if (find_arg(ua, "yes") >= 0) {
1510 ua->pint32_val = 1; /* Have "yes" on command line already" */
1512 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1514 if (!get_yesno(ua, buf)) {
1518 if (ua->pint32_val) {
1519 db_delete_media_record(ua->jcr, ua->db, &mr);
1525 * Delete a pool record from the database -- dangerous
1527 static int delete_pool(UAContext *ua)
1532 memset(&pr, 0, sizeof(pr));
1534 if (!get_pool_dbr(ua, &pr)) {
1537 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1539 if (!get_yesno(ua, buf)) {
1542 if (ua->pint32_val) {
1543 db_delete_pool_record(ua->jcr, ua->db, &pr);
1548 int memory_cmd(UAContext *ua, const char *cmd)
1550 list_dir_status_header(ua);
1551 sm_dump(false, true);
1555 static void do_mount_cmd(UAContext *ua, const char *command)
1560 char dev_name[MAX_NAME_LENGTH];
1564 if (!open_client_db(ua)) {
1567 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1569 store.store = get_storage_resource(ua, true/*arg is storage*/);
1573 pm_strcpy(store.store_source, _("unknown source"));
1574 set_wstorage(jcr, &store);
1575 drive = get_storage_drive(ua, store.store);
1576 if (strcmp(command, "mount") == 0) {
1577 slot = get_storage_slot(ua, store.store);
1580 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1581 store.store->media_type, store.store->dev_name(), drive);
1583 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1584 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1587 sd = jcr->store_bsock;
1588 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1589 bash_spaces(dev_name);
1591 bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1593 bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1595 while (bnet_recv(sd) >= 0) {
1596 ua->send_msg("%s", sd->msg);
1598 bnet_sig(sd, BNET_TERMINATE);
1600 jcr->store_bsock = NULL;
1604 * mount [storage=<name>] [drive=nn] [slot=mm]
1606 static int mount_cmd(UAContext *ua, const char *cmd)
1608 do_mount_cmd(ua, "mount"); /* mount */
1614 * unmount [storage=<name>] [drive=nn]
1616 static int unmount_cmd(UAContext *ua, const char *cmd)
1618 do_mount_cmd(ua, "unmount"); /* unmount */
1624 * release [storage=<name>] [drive=nn]
1626 static int release_cmd(UAContext *ua, const char *cmd)
1628 do_mount_cmd(ua, "release"); /* release */
1635 * use catalog=<name>
1637 static int use_cmd(UAContext *ua, const char *cmd)
1639 CAT *oldcatalog, *catalog;
1642 close_db(ua); /* close any previously open db */
1643 oldcatalog = ua->catalog;
1645 if (!(catalog = get_catalog_resource(ua))) {
1646 ua->catalog = oldcatalog;
1648 ua->catalog = catalog;
1651 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1652 ua->catalog->name(), ua->catalog->db_name);
1657 int quit_cmd(UAContext *ua, const char *cmd)
1663 /* Handler to get job status */
1664 static int status_handler(void *ctx, int num_fields, char **row)
1666 char *val = (char *)ctx;
1671 *val = '?'; /* Unknown by default */
1678 * Wait until no job is running
1680 int wait_cmd(UAContext *ua, const char *cmd)
1684 time_t stop_time = 0;
1688 * Wait until no job is running
1690 if (ua->argc == 1) {
1691 bmicrosleep(0, 200000); /* let job actually start */
1692 for (bool running=true; running; ) {
1695 if (jcr->JobId != 0) {
1709 i = find_arg_with_value(ua, NT_("timeout"));
1710 if (i > 0 && ua->argv[i]) {
1711 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1714 /* we have jobid, jobname or ujobid argument */
1716 uint32_t jobid = 0 ;
1718 if (!open_client_db(ua)) {
1719 ua->error_msg(_("ERR: Can't open db\n")) ;
1723 for (int i=1; i<ua->argc; i++) {
1724 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1728 jobid = str_to_int64(ua->argv[i]);
1730 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1731 strcasecmp(ua->argk[i], "job") == 0) {
1735 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1737 jobid = jcr->JobId ;
1741 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1745 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1747 jobid = jcr->JobId ;
1751 /* Wait for a mount request */
1752 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1753 for (bool waiting=false; !waiting; ) {
1755 if (jcr->JobId != 0 &&
1756 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1765 if (stop_time && (time(NULL) >= stop_time)) {
1766 ua->warning_msg(_("Wait on mount timed out\n"));
1776 ua->error_msg(_("ERR: Job was not found\n"));
1781 * We wait the end of a specific job
1784 bmicrosleep(0, 200000); /* let job actually start */
1785 for (bool running=true; running; ) {
1788 jcr=get_jcr_by_id(jobid) ;
1801 * We have to get JobStatus
1805 char jobstatus = '?'; /* Unknown by default */
1808 bsnprintf(buf, sizeof(buf),
1809 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1812 db_sql_query(ua->db, buf,
1813 status_handler, (void *)&jobstatus);
1815 switch (jobstatus) {
1817 status = 1 ; /* Warning */
1821 case JS_ErrorTerminated:
1823 status = 2 ; /* Critical */
1828 status = 0 ; /* Ok */
1832 status = 3 ; /* Unknown */
1836 ua->send_msg("JobId=%i\n", jobid) ;
1837 ua->send_msg("JobStatus=%s (%c)\n",
1838 job_status_to_str(jobstatus),
1841 if (ua->gui || ua->api) {
1842 ua->send_msg("ExitStatus=%i\n", status) ;
1849 static int help_cmd(UAContext *ua, const char *cmd)
1853 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1854 for (i=0; i<comsize; i++) {
1855 ua->send_msg(_(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1857 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1861 int qhelp_cmd(UAContext *ua, const char *cmd)
1865 for (i=0; i<comsize; i++) {
1866 ua->send_msg("%s %s\n", commands[i].key, _(commands[i].help));
1872 static int version_cmd(UAContext *ua, const char *cmd)
1874 ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
1875 HOST_OS, DISTNAME, DISTVER, NPRTB(director->verid));
1880 * Test code -- turned on only for debug testing
1882 static int version_cmd(UAContext *ua, const char *cmd)
1885 POOL_MEM query(PM_MESSAGE);
1887 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1888 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1889 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1890 for (int i=0; i < ids.num_ids; i++) {
1891 ua->send_msg("id=%d\n", ids.DBId[i]);
1899 * This call explicitly checks for a catalog=xxx and
1900 * if given, opens that catalog. It also checks for
1901 * client=xxx and if found, opens the catalog
1902 * corresponding to that client. If we still don't
1903 * have a catalog, look for a Job keyword and get the
1904 * catalog from its client record.
1906 bool open_client_db(UAContext *ua)
1913 /* Try for catalog keyword */
1914 i = find_arg_with_value(ua, NT_("catalog"));
1916 if (!acl_access_ok(ua, Catalog_ACL, ua->argv[i])) {
1917 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), ua->argv[i]);
1920 catalog = GetCatalogResWithName(ua->argv[i]);
1922 if (ua->catalog && ua->catalog != catalog) {
1925 ua->catalog = catalog;
1930 /* Try for client keyword */
1931 i = find_arg_with_value(ua, NT_("client"));
1933 if (!acl_access_ok(ua, Client_ACL, ua->argv[i])) {
1934 ua->error_msg(_("No authorization for Client \"%s\"\n"), ua->argv[i]);
1937 client = GetClientResWithName(ua->argv[i]);
1939 catalog = client->catalog;
1940 if (ua->catalog && ua->catalog != catalog) {
1943 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1944 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1947 ua->catalog = catalog;
1952 /* Try for Job keyword */
1953 i = find_arg_with_value(ua, NT_("job"));
1955 if (!acl_access_ok(ua, Job_ACL, ua->argv[i])) {
1956 ua->error_msg(_("No authorization for Job \"%s\"\n"), ua->argv[i]);
1959 job = GetJobResWithName(ua->argv[i]);
1961 catalog = job->client->catalog;
1962 if (ua->catalog && ua->catalog != catalog) {
1965 if (!acl_access_ok(ua, Catalog_ACL, catalog->name())) {
1966 ua->error_msg(_("No authorization for Catalog \"%s\"\n"), catalog->name());
1969 ua->catalog = catalog;
1979 * Open the catalog database.
1981 bool open_db(UAContext *ua)
1987 ua->catalog = get_catalog_resource(ua);
1989 ua->error_msg( _("Could not find a Catalog resource\n"));
1994 ua->jcr->catalog = ua->catalog;
1996 Dmsg0(100, "UA Open database\n");
1997 ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
1998 ua->catalog->db_user,
1999 ua->catalog->db_password, ua->catalog->db_address,
2000 ua->catalog->db_port, ua->catalog->db_socket,
2001 ua->catalog->mult_db_connections);
2002 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
2003 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
2004 ua->catalog->db_name);
2006 ua->error_msg("%s", db_strerror(ua->db));
2011 ua->jcr->db = ua->db;
2013 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
2015 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
2019 void close_db(UAContext *ua)
2022 db_close_database(ua->jcr, ua->db);