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"), true},
126 { NT_("exit"), quit_cmd, _("exit = quit"), false},
127 { NT_("gui"), gui_cmd, _("gui [on|off] -- non-interactive gui mode"), false},
128 { NT_("help"), help_cmd, _("print this command"), false},
129 { NT_("label"), label_cmd, _("label a tape"), false},
130 { NT_("list"), list_cmd, _("list [pools | jobs | jobtotals | media <pool=pool-name> | "
131 "\n files <jobid=nn> | copies <jobid=nn>]; from catalog"), true},
132 { NT_("llist"), llist_cmd, _("full or long list like list command"), true},
133 { NT_("messages"), messagescmd, _("messages"), false},
134 { NT_("memory"), memory_cmd, _("print current memory usage"), true},
135 { NT_("mount"), mount_cmd, _("mount storage=<storage-name> [ slot=<num> ] [ drive=<num> ] "
136 "\n or mount [ jobid=<id> | job=<job-name> ]"), false},
137 { NT_("prune"), prunecmd, _("prune files|jobs|volume client=<client-name> volume=<volume-name> "
138 "\n prune expired records from catalog"), true},
139 { NT_("purge"), purgecmd, _("purge records from catalog"), true},
140 { NT_("python"), python_cmd, _("python control commands"), false},
141 { NT_("quit"), quit_cmd, _("quit"), false},
142 { NT_("query"), querycmd, _("query catalog"), false},
143 { NT_("restore"), restore_cmd, _("restore files"), false},
144 { NT_("relabel"), relabel_cmd, _("relabel storage=<storage-name> oldvolume=<old-volume-name> "
145 "\n volume=<newvolume-name> -- relabel a tape"), false},
146 { NT_("release"), release_cmd, _("release <storage-name>"), false},
147 { NT_("reload"), reload_cmd, _("reload conf file"), true},
148 { NT_("run"), run_cmd, _("run job=<job-name> client=<client-name> fileset=<FileSet-name> "
149 "\n level=<level-keyword> storage=<storage-name> where=<directory-prefix> "
150 "\n when=<universal-time-specification> yes"), false}, /* need to be check */
151 { NT_("status"), status_cmd, _("status [all | dir=<dir-name> | director | client=<client-name> |"
152 "\n storage=<storage-name> | days=nnn]"), true},
153 { NT_("setdebug"), setdebug_cmd, _("setdebug level=nn [trace=0/1 client=<client-name> |"
154 "\n dir | director | storage=<storage-name> | all] -- sets debug level"), true},
155 { NT_("setip"), setip_cmd, _("sets new client address -- if authorized"), false},
156 { NT_("show"), show_cmd, _("show (resource records) [jobs | pools | ... | all]"), true},
157 { NT_("sqlquery"), sqlquerycmd, _("use SQL to query catalog"), false},
158 { NT_("time"), time_cmd, _("print current time"), true},
159 { NT_("trace"), trace_cmd, _("turn on/off trace to file"), true},
160 { NT_("unmount"), unmount_cmd, _("unmount storage=<storage-name> [ drive=<num> ] "
161 "\n or unmount [ jobid=<id> | job=<job-name> ]"), false},
162 { NT_("umount"), unmount_cmd, _("umount - for old-time Unix guys, see unmount"),false},
163 { NT_("update"), update_cmd, _("update Volume, Pool or slots"), true},
164 { NT_("use"), use_cmd, _("use <database-name> -- catalog xxx"), false},
165 { NT_("var"), var_cmd, _("does variable expansion"), false},
166 { NT_("version"), version_cmd, _("print Director version"), true},
167 { NT_("wait"), wait_cmd, _("wait [<jobname=name> | <jobid=nnn> | <ujobid=complete_name>] -- "
168 "\n wait until no jobs are running"), false}
171 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
174 * Execute a command from the UA
176 bool do_a_command(UAContext *ua)
182 BSOCK *user = ua->UA_sock;
185 Dmsg1(900, "Command: %s\n", ua->argk[0]);
190 while (ua->jcr->wstorage->size()) {
191 ua->jcr->wstorage->remove(0);
194 len = strlen(ua->argk[0]);
195 for (i=0; i<comsize; i++) { /* search for command */
196 if (strncasecmp(ua->argk[0], commands[i].key, len) == 0) {
197 /* Check if command permitted, but "quit" is always OK */
198 if (strcmp(ua->argk[0], NT_("quit")) != 0 &&
199 !acl_access_ok(ua, Command_ACL, ua->argk[0], len)) {
202 /* Check if this command is authorized in RunScript */
203 if (ua->runscript && !commands[i].use_in_rs) {
204 ua->error_msg(_("Can't use %s command in a runscript"), ua->argk[0]);
207 if (ua->api) user->signal(BNET_CMD_BEGIN);
208 ok = (*commands[i].func)(ua, ua->cmd); /* go execute command */
209 if (ua->api) user->signal(ok?BNET_CMD_OK:BNET_CMD_FAILED);
215 ua->error_msg(_("%s: is an invalid command.\n"), ua->argk[0]);
222 * This is a common routine used to stuff the Pool DB record defaults
223 * into the Media DB record just before creating a media (Volume)
226 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
228 mr->PoolId = pr->PoolId;
229 bstrncpy(mr->VolStatus, NT_("Append"), sizeof(mr->VolStatus));
230 mr->Recycle = pr->Recycle;
231 mr->VolRetention = pr->VolRetention;
232 mr->VolUseDuration = pr->VolUseDuration;
233 mr->RecyclePoolId = pr->RecyclePoolId;
234 mr->MaxVolJobs = pr->MaxVolJobs;
235 mr->MaxVolFiles = pr->MaxVolFiles;
236 mr->MaxVolBytes = pr->MaxVolBytes;
237 mr->LabelType = pr->LabelType;
243 * Add Volumes to an existing Pool
245 static int add_cmd(UAContext *ua, const char *cmd)
249 int num, i, max, startnum;
251 char name[MAX_NAME_LENGTH];
253 int Slot = 0, InChanger = 0;
256 "You probably don't want to be using this command since it\n"
257 "creates database records without labeling the Volumes.\n"
258 "You probably want to use the \"label\" command.\n\n"));
260 if (!open_client_db(ua)) {
264 memset(&pr, 0, sizeof(pr));
265 memset(&mr, 0, sizeof(mr));
267 if (!get_pool_dbr(ua, &pr)) {
271 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
272 pr.MaxVols, pr.PoolType);
274 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
275 ua->warning_msg(_("Pool already has maximum volumes=%d\n"), pr.MaxVols);
276 if (!get_pint(ua, _("Enter new maximum (zero for unlimited): "))) {
279 pr.MaxVols = ua->pint32_val;
283 if ((store = get_storage_resource(ua, false/*no default*/)) != NULL) {
284 bstrncpy(mr.MediaType, store->media_type, sizeof(mr.MediaType));
285 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
289 if (pr.MaxVols == 0) {
292 max = pr.MaxVols - pr.NumVols;
296 bsnprintf(buf, sizeof(buf), _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
297 if (!get_pint(ua, buf)) {
300 num = ua->pint32_val;
301 if (num < 0 || num > max) {
302 ua->warning_msg(_("The number must be between 0 and %d\n"), max);
310 if (!get_cmd(ua, _("Enter Volume name: "))) {
314 if (!get_cmd(ua, _("Enter base volume name: "))) {
318 /* Don't allow | in Volume name because it is the volume separator character */
319 if (!is_volume_name_legal(ua, ua->cmd)) {
322 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
323 ua->warning_msg(_("Volume name too long.\n"));
326 if (strlen(ua->cmd) == 0) {
327 ua->warning_msg(_("Volume name must be at least one character long.\n"));
333 bstrncpy(name, ua->cmd, sizeof(name));
335 bstrncat(name, "%04d", sizeof(name));
338 if (!get_pint(ua, _("Enter the starting number: "))) {
341 startnum = ua->pint32_val;
343 ua->warning_msg(_("Start number must be greater than zero.\n"));
353 if (store && store->autochanger) {
354 if (!get_pint(ua, _("Enter slot (0 for none): "))) {
357 Slot = ua->pint32_val;
358 if (!get_yesno(ua, _("InChanger? yes/no: "))) {
361 InChanger = ua->pint32_val;
364 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
365 for (i=startnum; i < num+startnum; i++) {
366 bsnprintf(mr.VolumeName, sizeof(mr.VolumeName), name, i);
368 mr.InChanger = InChanger;
369 mr.StorageId = store->StorageId;
371 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
372 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
373 ua->error_msg("%s", db_strerror(ua->db));
377 first_id = mr.PoolId;
381 Dmsg0(200, "Update pool record.\n");
382 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
383 ua->warning_msg("%s", db_strerror(ua->db));
386 ua->send_msg(_("%d Volumes created in pool %s\n"), num, pr.Name);
392 * Turn auto mount on/off
397 int automount_cmd(UAContext *ua, const char *cmd)
402 if (!get_cmd(ua, _("Turn on or off? "))) {
410 ua->automount = (strcasecmp(onoff, NT_("off")) == 0) ? 0 : 1;
418 static int cancel_cmd(UAContext *ua, const char *cmd)
423 char JobName[MAX_NAME_LENGTH];
425 for (i=1; i<ua->argc; i++) {
426 if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
431 JobId = str_to_int64(ua->argv[i]);
432 if (!(jcr=get_jcr_by_id(JobId))) {
433 ua->error_msg(_("JobId %s is not running. Use Job name to cancel inactive jobs.\n"), ua->argv[i]);
437 } else if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
441 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
442 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
443 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
444 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
447 } else if (strcasecmp(ua->argk[i], NT_("ujobid")) == 0) {
451 if (!(jcr=get_jcr_by_full_name(ua->argv[i]))) {
452 ua->warning_msg(_("Warning Job %s is not running. Continuing anyway ...\n"), ua->argv[i]);
453 jcr = new_jcr(sizeof(JCR), dird_free_jcr);
454 bstrncpy(jcr->Job, ua->argv[i], sizeof(jcr->Job));
461 if (jcr->job && !acl_access_ok(ua, Job_ACL, jcr->job->name())) {
462 ua->error_msg(_("Unauthorized command from this console.\n"));
467 * If we still do not have a jcr,
468 * throw up a list and ask the user to select one.
471 int tjobs = 0; /* total # number jobs */
472 /* Count Jobs running */
474 if (jcr->JobId == 0) { /* this is us */
477 tjobs++; /* count of all jobs */
478 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
479 continue; /* skip not authorized */
481 njobs++; /* count of authorized jobs */
485 if (njobs == 0) { /* no authorized */
487 ua->send_msg(_("No Jobs running.\n"));
489 ua->send_msg(_("None of your jobs are running.\n"));
494 start_prompt(ua, _("Select Job:\n"));
497 if (jcr->JobId == 0) { /* this is us */
500 if (!acl_access_ok(ua, Job_ACL, jcr->job->name())) {
501 continue; /* skip not authorized */
503 bsnprintf(buf, sizeof(buf), _("JobId=%s Job=%s"), edit_int64(jcr->JobId, ed1), jcr->Job);
508 if (do_prompt(ua, _("Job"), _("Choose Job to cancel"), buf, sizeof(buf)) < 0) {
511 if (ua->api && njobs == 1) {
513 bsnprintf(nbuf, sizeof(nbuf), _("Cancel: %s\n\n%s"), buf,
514 _("Confirm cancel?"));
515 if (!get_yesno(ua, nbuf) || ua->pint32_val == 0) {
520 if (!get_yesno(ua, _("Confirm cancel (yes/no): ")) || ua->pint32_val == 0) {
525 sscanf(buf, "JobId=%d Job=%127s", &njobs, JobName);
526 jcr = get_jcr_by_full_name(JobName);
528 ua->warning_msg(_("Job \"%s\" not found.\n"), JobName);
533 ret = cancel_job(ua, jcr);
539 * This is a common routine to create or update a
540 * Pool DB base record from a Pool Resource. We handle
541 * the setting of MaxVols and NumVols slightly differently
542 * depending on if we are creating the Pool or we are
543 * simply bringing it into agreement with the resource (updage).
545 * Caution : RecyclePoolId isn't setup in this function.
546 * You can use set_pooldbr_recyclepoolid();
549 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op)
551 bstrncpy(pr->PoolType, pool->pool_type, sizeof(pr->PoolType));
552 if (op == POOL_OP_CREATE) {
553 pr->MaxVols = pool->max_volumes;
555 } else { /* update pool */
556 if (pr->MaxVols != pool->max_volumes) {
557 pr->MaxVols = pool->max_volumes;
559 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
560 pr->MaxVols = pr->NumVols;
563 pr->LabelType = pool->LabelType;
564 pr->UseOnce = pool->use_volume_once;
565 pr->UseCatalog = pool->use_catalog;
566 pr->Recycle = pool->Recycle;
567 pr->VolRetention = pool->VolRetention;
568 pr->VolUseDuration = pool->VolUseDuration;
569 pr->MaxVolJobs = pool->MaxVolJobs;
570 pr->MaxVolFiles = pool->MaxVolFiles;
571 pr->MaxVolBytes = pool->MaxVolBytes;
572 pr->AutoPrune = pool->AutoPrune;
573 pr->Recycle = pool->Recycle;
574 if (pool->label_format) {
575 bstrncpy(pr->LabelFormat, pool->label_format, sizeof(pr->LabelFormat));
577 bstrncpy(pr->LabelFormat, "*", sizeof(pr->LabelFormat)); /* none */
581 /* set/update Pool.RecyclePoolId and Pool.ScratchPoolId in Catalog */
582 int update_pool_references(JCR *jcr, B_DB *db, POOL *pool)
586 if (!pool->RecyclePool && !pool->ScratchPool) {
590 memset(&pr, 0, sizeof(POOL_DBR));
591 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
593 if (!db_get_pool_record(jcr, db, &pr)) {
594 return -1; /* not exists in database */
597 set_pooldbr_from_poolres(&pr, pool, POOL_OP_UPDATE);
599 if (!set_pooldbr_references(jcr, db, &pr, pool)) {
600 return -1; /* error */
603 if (!db_update_pool_record(jcr, db, &pr)) {
604 return -1; /* error */
609 /* set POOL_DBR.RecyclePoolId and POOL_DBR.ScratchPoolId from Pool resource
610 * works with set_pooldbr_from_poolres
612 bool set_pooldbr_references(JCR *jcr, B_DB *db, POOL_DBR *pr, POOL *pool)
617 if (pool->RecyclePool) {
618 memset(&rpool, 0, sizeof(POOL_DBR));
620 bstrncpy(rpool.Name, pool->RecyclePool->name(), sizeof(rpool.Name));
621 if (db_get_pool_record(jcr, db, &rpool)) {
622 pr->RecyclePoolId = rpool.PoolId;
624 Jmsg(jcr, M_WARNING, 0,
625 _("Can't set %s RecyclePool to %s, %s is not in database.\n" \
626 "Try to update it with 'update pool=%s'\n"),
627 pool->name(), rpool.Name, rpool.Name,pool->name());
631 } else { /* no RecyclePool used, set it to 0 */
632 pr->RecyclePoolId = 0;
635 if (pool->ScratchPool) {
636 memset(&rpool, 0, sizeof(POOL_DBR));
638 bstrncpy(rpool.Name, pool->ScratchPool->name(), sizeof(rpool.Name));
639 if (db_get_pool_record(jcr, db, &rpool)) {
640 pr->ScratchPoolId = rpool.PoolId;
642 Jmsg(jcr, M_WARNING, 0,
643 _("Can't set %s ScratchPool to %s, %s is not in database.\n" \
644 "Try to update it with 'update pool=%s'\n"),
645 pool->name(), rpool.Name, rpool.Name,pool->name());
648 } else { /* no ScratchPool used, set it to 0 */
649 pr->ScratchPoolId = 0;
657 * Create a pool record from a given Pool resource
658 * Also called from backup.c
659 * Returns: -1 on error
660 * 0 record already exists
664 int create_pool(JCR *jcr, B_DB *db, POOL *pool, e_pool_op op)
668 memset(&pr, 0, sizeof(POOL_DBR));
670 bstrncpy(pr.Name, pool->name(), sizeof(pr.Name));
672 if (db_get_pool_record(jcr, db, &pr)) {
674 if (op == POOL_OP_UPDATE) { /* update request */
675 set_pooldbr_from_poolres(&pr, pool, op);
676 set_pooldbr_references(jcr, db, &pr, pool);
677 db_update_pool_record(jcr, db, &pr);
679 return 0; /* exists */
682 set_pooldbr_from_poolres(&pr, pool, op);
683 set_pooldbr_references(jcr, db, &pr, pool);
685 if (!db_create_pool_record(jcr, db, &pr)) {
686 return -1; /* error */
694 * Create a Pool Record in the database.
695 * It is always created from the Resource record.
697 static int create_cmd(UAContext *ua, const char *cmd)
701 if (!open_client_db(ua)) {
705 pool = get_pool_resource(ua);
710 switch (create_pool(ua->jcr, ua->db, pool, POOL_OP_CREATE)) {
712 ua->error_msg(_("Error: Pool %s already exists.\n"
713 "Use update to change it.\n"), pool->name());
717 ua->error_msg("%s", db_strerror(ua->db));
723 ua->send_msg(_("Pool %s created.\n"), pool->name());
728 extern DIRRES *director;
729 extern char *configfile;
732 * Python control command
733 * python restart (restarts interpreter)
735 static int python_cmd(UAContext *ua, const char *cmd)
738 init_python_interpreter_args python_args;
740 if (ua->argc >= 2 && strcasecmp(ua->argk[1], NT_("restart")) == 0) {
741 term_python_interpreter();
743 python_args.progname = director->name();
744 python_args.scriptdir = director->scripts_directory;
745 python_args.modulename = "DirStartUp";
746 python_args.configfile = configfile;
747 python_args.workingdir = director->working_directory;
748 python_args.job_getattr = job_getattr;
749 python_args.job_setattr = job_setattr;
751 init_python_interpreter(&python_args);
753 ua->send_msg(_("Python interpreter restarted.\n"));
755 #endif /* HAVE_PYTHON */
756 ua->warning_msg(_("Nothing done.\n"));
759 #endif /* HAVE_PYTHON */
765 * Set a new address in a Client resource. We do this only
766 * if the Console name is the same as the Client name
767 * and the Console can access the client.
769 static int setip_cmd(UAContext *ua, const char *cmd)
773 if (!ua->cons || !acl_access_ok(ua, Client_ACL, ua->cons->name())) {
774 ua->error_msg(_("Unauthorized command from this console.\n"));
778 client = GetClientResWithName(ua->cons->name());
781 ua->error_msg(_("Client \"%s\" not found.\n"), ua->cons->name());
784 if (client->address) {
785 free(client->address);
787 /* MA Bug 6 remove ifdef */
788 sockaddr_to_ascii(&(ua->UA_sock->client_addr), buf, sizeof(buf));
789 client->address = bstrdup(buf);
790 ua->send_msg(_("Client \"%s\" address set to %s\n"),
791 client->name(), client->address);
798 static void do_en_disable_cmd(UAContext *ua, bool setting)
803 i = find_arg_with_value(ua, NT_("job"));
805 job = select_job_resource(ua);
811 job = GetJobResWithName(ua->argv[i]);
815 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
819 if (!acl_access_ok(ua, Job_ACL, job->name())) {
820 ua->error_msg(_("Unauthorized command from this console.\n"));
823 job->enabled = setting;
824 ua->send_msg(_("Job \"%s\" %sabled\n"), job->name(), setting?"en":"dis");
828 static int enable_cmd(UAContext *ua, const char *cmd)
830 do_en_disable_cmd(ua, true);
834 static int disable_cmd(UAContext *ua, const char *cmd)
836 do_en_disable_cmd(ua, false);
841 static void do_storage_setdebug(UAContext *ua, STORE *store, int level, int trace_flag)
847 lstore.store = store;
848 pm_strcpy(lstore.store_source, _("unknown source"));
849 set_wstorage(jcr, &lstore);
850 /* Try connecting for up to 15 seconds */
851 ua->send_msg(_("Connecting to Storage daemon %s at %s:%d\n"),
852 store->name(), store->address, store->SDport);
853 if (!connect_to_storage_daemon(jcr, 1, 15, 0)) {
854 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
857 Dmsg0(120, _("Connected to storage daemon\n"));
858 sd = jcr->store_bsock;
859 sd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
860 if (sd->recv() >= 0) {
861 ua->send_msg("%s", sd->msg);
863 sd->signal(BNET_TERMINATE);
865 jcr->store_bsock = NULL;
869 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level, int trace_flag)
873 /* Connect to File daemon */
875 ua->jcr->client = client;
876 /* Try to connect for 15 seconds */
877 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
878 client->name(), client->address, client->FDport);
879 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
880 ua->error_msg(_("Failed to connect to Client.\n"));
883 Dmsg0(120, "Connected to file daemon\n");
884 fd = ua->jcr->file_bsock;
885 fd->fsend("setdebug=%d trace=%d\n", level, trace_flag);
886 if (fd->recv() >= 0) {
887 ua->send_msg("%s", fd->msg);
889 fd->signal(BNET_TERMINATE);
891 ua->jcr->file_bsock = NULL;
896 static void do_all_setdebug(UAContext *ua, int level, int trace_flag)
898 STORE *store, **unique_store;
899 CLIENT *client, **unique_client;
905 /* Count Storage items */
909 foreach_res(store, R_STORAGE) {
912 unique_store = (STORE **) malloc(i * sizeof(STORE));
913 /* Find Unique Storage address/port */
914 store = (STORE *)GetNextRes(R_STORAGE, NULL);
916 unique_store[i++] = store;
917 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
919 for (j=0; j<i; j++) {
920 if (strcmp(unique_store[j]->address, store->address) == 0 &&
921 unique_store[j]->SDport == store->SDport) {
927 unique_store[i++] = store;
928 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
933 /* Call each unique Storage daemon */
934 for (j=0; j<i; j++) {
935 do_storage_setdebug(ua, unique_store[j], level, trace_flag);
939 /* Count Client items */
943 foreach_res(client, R_CLIENT) {
946 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
947 /* Find Unique Client address/port */
948 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
950 unique_client[i++] = client;
951 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
953 for (j=0; j<i; j++) {
954 if (strcmp(unique_client[j]->address, client->address) == 0 &&
955 unique_client[j]->FDport == client->FDport) {
961 unique_client[i++] = client;
962 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
967 /* Call each unique File daemon */
968 for (j=0; j<i; j++) {
969 do_client_setdebug(ua, unique_client[j], level, trace_flag);
975 * setdebug level=nn all trace=1/0
977 static int setdebug_cmd(UAContext *ua, const char *cmd)
985 Dmsg1(120, "setdebug:%s:\n", cmd);
988 i = find_arg_with_value(ua, "level");
990 level = atoi(ua->argv[i]);
993 if (!get_pint(ua, _("Enter new debug level: "))) {
996 level = ua->pint32_val;
999 /* Look for trace flag. -1 => not change */
1000 i = find_arg_with_value(ua, "trace");
1002 trace_flag = atoi(ua->argv[i]);
1003 if (trace_flag > 0) {
1008 /* General debug? */
1009 for (i=1; i<ua->argc; i++) {
1010 if (strcasecmp(ua->argk[i], "all") == 0) {
1011 do_all_setdebug(ua, level, trace_flag);
1014 if (strcasecmp(ua->argk[i], "dir") == 0 ||
1015 strcasecmp(ua->argk[i], "director") == 0) {
1016 debug_level = level;
1017 set_trace(trace_flag);
1020 if (strcasecmp(ua->argk[i], "client") == 0 ||
1021 strcasecmp(ua->argk[i], "fd") == 0) {
1024 client = GetClientResWithName(ua->argv[i]);
1026 do_client_setdebug(ua, client, level, trace_flag);
1030 client = select_client_resource(ua);
1032 do_client_setdebug(ua, client, level, trace_flag);
1037 if (strcasecmp(ua->argk[i], NT_("store")) == 0 ||
1038 strcasecmp(ua->argk[i], NT_("storage")) == 0 ||
1039 strcasecmp(ua->argk[i], NT_("sd")) == 0) {
1042 store = GetStoreResWithName(ua->argv[i]);
1044 do_storage_setdebug(ua, store, level, trace_flag);
1048 store = get_storage_resource(ua, false/*no default*/);
1050 do_storage_setdebug(ua, store, level, trace_flag);
1056 * We didn't find an appropriate keyword above, so
1059 start_prompt(ua, _("Available daemons are: \n"));
1060 add_prompt(ua, _("Director"));
1061 add_prompt(ua, _("Storage"));
1062 add_prompt(ua, _("Client"));
1063 add_prompt(ua, _("All"));
1064 switch(do_prompt(ua, "", _("Select daemon type to set debug level"), NULL, 0)) {
1065 case 0: /* Director */
1066 debug_level = level;
1067 set_trace(trace_flag);
1070 store = get_storage_resource(ua, false/*no default*/);
1072 do_storage_setdebug(ua, store, level, trace_flag);
1076 client = select_client_resource(ua);
1078 do_client_setdebug(ua, client, level, trace_flag);
1082 do_all_setdebug(ua, level, trace_flag);
1091 * Turn debug tracing to file on/off
1093 static int trace_cmd(UAContext *ua, const char *cmd)
1097 if (ua->argc != 2) {
1098 if (!get_cmd(ua, _("Turn on or off? "))) {
1103 onoff = ua->argk[1];
1106 set_trace((strcasecmp(onoff, NT_("off")) == 0) ? false : true);
1111 static int var_cmd(UAContext *ua, const char *cmd)
1113 POOLMEM *val = get_pool_memory(PM_FNAME);
1116 if (!open_client_db(ua)) {
1119 for (var=ua->cmd; *var != ' '; ) { /* skip command */
1122 while (*var == ' ') { /* skip spaces */
1125 Dmsg1(100, "Var=%s:\n", var);
1126 variable_expansion(ua->jcr, var, &val);
1127 ua->send_msg("%s\n", val);
1128 free_pool_memory(val);
1132 static int estimate_cmd(UAContext *ua, const char *cmd)
1135 CLIENT *client = NULL;
1136 FILESET *fileset = NULL;
1138 char since[MAXSTRING];
1142 jcr->set_JobLevel(L_FULL);
1143 for (int i=1; i<ua->argc; i++) {
1144 if (strcasecmp(ua->argk[i], NT_("client")) == 0 ||
1145 strcasecmp(ua->argk[i], NT_("fd")) == 0) {
1147 client = GetClientResWithName(ua->argv[i]);
1149 ua->error_msg(_("Client \"%s\" not found.\n"), ua->argv[i]);
1154 ua->error_msg(_("Client name missing.\n"));
1158 if (strcasecmp(ua->argk[i], NT_("job")) == 0) {
1160 job = GetJobResWithName(ua->argv[i]);
1162 ua->error_msg(_("Job \"%s\" not found.\n"), ua->argv[i]);
1165 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1166 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1171 ua->error_msg(_("Job name missing.\n"));
1176 if (strcasecmp(ua->argk[i], NT_("fileset")) == 0) {
1178 fileset = GetFileSetResWithName(ua->argv[i]);
1180 ua->error_msg(_("Fileset \"%s\" not found.\n"), ua->argv[i]);
1183 if (!acl_access_ok(ua, FileSet_ACL, fileset->name())) {
1184 ua->error_msg(_("No authorization for FileSet \"%s\"\n"), fileset->name());
1189 ua->error_msg(_("Fileset name missing.\n"));
1193 if (strcasecmp(ua->argk[i], NT_("listing")) == 0) {
1197 if (strcasecmp(ua->argk[i], NT_("level")) == 0) {
1199 if (!get_level_from_name(ua->jcr, ua->argv[i])) {
1200 ua->error_msg(_("Level \"%s\" not valid.\n"), ua->argv[i]);
1204 ua->error_msg(_("Level value missing.\n"));
1208 if (strcasecmp(ua->argk[i], NT_("accurate")) == 0) {
1209 if (!is_yesno(ua->argv[i], &accurate)) {
1210 ua->error_msg(_("Invalid value for accurate. "
1211 "It must be yes or no.\n"));
1215 if (!job && !(client && fileset)) {
1216 if (!(job = select_job_resource(ua))) {
1221 job = GetJobResWithName(ua->argk[1]);
1223 ua->error_msg(_("No job specified.\n"));
1226 if (!acl_access_ok(ua, Job_ACL, job->name())) {
1227 ua->error_msg(_("No authorization for Job \"%s\"\n"), job->name());
1232 client = job->client;
1235 fileset = job->fileset;
1237 jcr->client = client;
1238 jcr->fileset = fileset;
1240 if (job->pool->catalog) {
1241 ua->catalog = job->pool->catalog;
1243 ua->catalog = client->catalog;
1251 jcr->set_JobType(JT_BACKUP);
1252 init_jcr_job_record(jcr);
1254 if (!get_or_create_client_record(jcr)) {
1257 if (!get_or_create_fileset_record(jcr)) {
1261 get_level_since_time(ua->jcr, since, sizeof(since));
1263 ua->send_msg(_("Connecting to Client %s at %s:%d\n"),
1264 jcr->client->name(), jcr->client->address, jcr->client->FDport);
1265 if (!connect_to_file_daemon(jcr, 1, 15, 0)) {
1266 ua->error_msg(_("Failed to connect to Client.\n"));
1270 if (!send_include_list(jcr)) {
1271 ua->error_msg(_("Error sending include list.\n"));
1275 if (!send_exclude_list(jcr)) {
1276 ua->error_msg(_("Error sending exclude list.\n"));
1280 /* The level string change if accurate mode is enabled */
1281 if (accurate >= 0) {
1282 jcr->accurate = accurate;
1284 jcr->accurate = job->accurate;
1287 if (!send_level_command(jcr)) {
1292 * If the job is in accurate mode, we send the list of
1295 Dmsg1(40, "estimate accurate=%i\n", jcr->accurate);
1296 if (!send_accurate_current_files(jcr)) {
1300 bnet_fsend(jcr->file_bsock, "estimate listing=%d\n", listing);
1301 while (bnet_recv(jcr->file_bsock) >= 0) {
1302 ua->send_msg("%s", jcr->file_bsock->msg);
1306 if (jcr->file_bsock) {
1307 bnet_sig(jcr->file_bsock, BNET_TERMINATE);
1308 bnet_close(jcr->file_bsock);
1309 jcr->file_bsock = NULL;
1318 static int time_cmd(UAContext *ua, const char *cmd)
1321 time_t ttime = time(NULL);
1323 (void)localtime_r(&ttime, &tm);
1324 strftime(sdt, sizeof(sdt), "%d-%b-%Y %H:%M:%S", &tm);
1325 ua->send_msg("%s\n", sdt);
1330 * reload the conf file
1332 extern "C" void reload_config(int sig);
1334 static int reload_cmd(UAContext *ua, const char *cmd)
1341 * Delete Pool records (should purge Media with it).
1343 * delete pool=<pool-name>
1344 * delete volume pool=<pool-name> volume=<name>
1347 static int delete_cmd(UAContext *ua, const char *cmd)
1349 static const char *keywords[] = {
1355 if (!open_client_db(ua)) {
1359 switch (find_arg_keyword(ua, keywords)) {
1368 while ((i=find_arg(ua, "jobid")) > 0) {
1370 *ua->argk[i] = 0; /* zap keyword already visited */
1378 "In general it is not a good idea to delete either a\n"
1379 "Pool or a Volume since they may contain data.\n\n"));
1381 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1392 ua->warning_msg(_("Nothing done.\n"));
1400 * delete_job has been modified to parse JobID lists like the
1402 * delete JobID=3,4,6,7-11,14
1404 * Thanks to Phil Stracchino for the above addition.
1407 static void delete_job(UAContext *ua)
1412 int i = find_arg_with_value(ua, NT_("jobid"));
1414 if (strchr(ua->argv[i], ',') != NULL || strchr(ua->argv[i], '-') != NULL) {
1415 s = bstrdup(ua->argv[i]);
1418 * We could use strtok() here. But we're not going to, because:
1419 * (a) strtok() is deprecated, having been replaced by strsep();
1420 * (b) strtok() is broken in significant ways.
1421 * we could use strsep() instead, but it's not universally available.
1422 * so we grow our own using strchr().
1424 sep = strchr(tok, ',');
1425 while (sep != NULL) {
1427 if (strchr(tok, '-')) {
1428 delete_job_id_range(ua, tok);
1430 JobId = str_to_int64(tok);
1431 do_job_delete(ua, JobId);
1434 sep = strchr(tok, ',');
1436 /* pick up the last token */
1437 if (strchr(tok, '-')) {
1438 delete_job_id_range(ua, tok);
1440 JobId = str_to_int64(tok);
1441 do_job_delete(ua, JobId);
1446 JobId = str_to_int64(ua->argv[i]);
1447 do_job_delete(ua, JobId);
1449 } else if (!get_pint(ua, _("Enter JobId to delete: "))) {
1452 JobId = ua->int64_val;
1453 do_job_delete(ua, JobId);
1458 * we call delete_job_id_range to parse range tokens and iterate over ranges
1460 static void delete_job_id_range(UAContext *ua, char *tok)
1465 tok2 = strchr(tok, '-');
1468 j1 = str_to_int64(tok);
1469 j2 = str_to_int64(tok2);
1470 for (j=j1; j<=j2; j++) {
1471 do_job_delete(ua, j);
1476 * do_job_delete now performs the actual delete operation atomically
1478 static void do_job_delete(UAContext *ua, JobId_t JobId)
1482 edit_int64(JobId, ed1);
1483 purge_jobs_from_catalog(ua, ed1);
1484 ua->send_msg(_("Job %s and associated records deleted from the catalog.\n"), ed1);
1488 * Delete media records from database -- dangerous
1490 static int delete_volume(UAContext *ua)
1495 if (!select_media_dbr(ua, &mr)) {
1498 ua->warning_msg(_("\nThis command will delete volume %s\n"
1499 "and all Jobs saved on that volume from the Catalog\n"),
1502 if (find_arg(ua, "yes") >= 0) {
1503 ua->pint32_val = 1; /* Have "yes" on command line already" */
1505 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Volume \"%s\"? (yes/no): "),
1507 if (!get_yesno(ua, buf)) {
1511 if (ua->pint32_val) {
1512 db_delete_media_record(ua->jcr, ua->db, &mr);
1518 * Delete a pool record from the database -- dangerous
1520 static int delete_pool(UAContext *ua)
1525 memset(&pr, 0, sizeof(pr));
1527 if (!get_pool_dbr(ua, &pr)) {
1530 bsnprintf(buf, sizeof(buf), _("Are you sure you want to delete Pool \"%s\"? (yes/no): "),
1532 if (!get_yesno(ua, buf)) {
1535 if (ua->pint32_val) {
1536 db_delete_pool_record(ua->jcr, ua->db, &pr);
1541 int memory_cmd(UAContext *ua, const char *cmd)
1543 list_dir_status_header(ua);
1544 sm_dump(false, true);
1548 static void do_mount_cmd(UAContext *ua, const char *command)
1553 char dev_name[MAX_NAME_LENGTH];
1557 if (!open_client_db(ua)) {
1560 Dmsg2(120, "%s: %s\n", command, ua->UA_sock->msg);
1562 store.store = get_storage_resource(ua, true/*arg is storage*/);
1566 pm_strcpy(store.store_source, _("unknown source"));
1567 set_wstorage(jcr, &store);
1568 drive = get_storage_drive(ua, store.store);
1569 if (strcmp(command, "mount") == 0) {
1570 slot = get_storage_slot(ua, store.store);
1573 Dmsg3(120, "Found storage, MediaType=%s DevName=%s drive=%d\n",
1574 store.store->media_type, store.store->dev_name(), drive);
1576 if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
1577 ua->error_msg(_("Failed to connect to Storage daemon.\n"));
1580 sd = jcr->store_bsock;
1581 bstrncpy(dev_name, store.store->dev_name(), sizeof(dev_name));
1582 bash_spaces(dev_name);
1584 bnet_fsend(sd, "%s %s drive=%d slot=%d", command, dev_name, drive, slot);
1586 bnet_fsend(sd, "%s %s drive=%d", command, dev_name, drive);
1588 while (bnet_recv(sd) >= 0) {
1589 ua->send_msg("%s", sd->msg);
1591 bnet_sig(sd, BNET_TERMINATE);
1593 jcr->store_bsock = NULL;
1597 * mount [storage=<name>] [drive=nn] [slot=mm]
1599 static int mount_cmd(UAContext *ua, const char *cmd)
1601 do_mount_cmd(ua, "mount"); /* mount */
1607 * unmount [storage=<name>] [drive=nn]
1609 static int unmount_cmd(UAContext *ua, const char *cmd)
1611 do_mount_cmd(ua, "unmount"); /* unmount */
1617 * release [storage=<name>] [drive=nn]
1619 static int release_cmd(UAContext *ua, const char *cmd)
1621 do_mount_cmd(ua, "release"); /* release */
1628 * use catalog=<name>
1630 static int use_cmd(UAContext *ua, const char *cmd)
1632 CAT *oldcatalog, *catalog;
1635 close_db(ua); /* close any previously open db */
1636 oldcatalog = ua->catalog;
1638 if (!(catalog = get_catalog_resource(ua))) {
1639 ua->catalog = oldcatalog;
1641 ua->catalog = catalog;
1644 ua->send_msg(_("Using Catalog name=%s DB=%s\n"),
1645 ua->catalog->name(), ua->catalog->db_name);
1650 int quit_cmd(UAContext *ua, const char *cmd)
1656 /* Handler to get job status */
1657 static int status_handler(void *ctx, int num_fields, char **row)
1659 char *val = (char *)ctx;
1664 *val = '?'; /* Unknown by default */
1671 * Wait until no job is running
1673 int wait_cmd(UAContext *ua, const char *cmd)
1677 time_t stop_time = 0;
1681 * Wait until no job is running
1683 if (ua->argc == 1) {
1684 bmicrosleep(0, 200000); /* let job actually start */
1685 for (bool running=true; running; ) {
1688 if (jcr->JobId != 0) {
1702 i = find_arg_with_value(ua, NT_("timeout"));
1703 if (i > 0 && ua->argv[i]) {
1704 stop_time = time(NULL) + str_to_int64(ua->argv[i]);
1707 /* we have jobid, jobname or ujobid argument */
1709 uint32_t jobid = 0 ;
1711 if (!open_client_db(ua)) {
1712 ua->error_msg(_("ERR: Can't open db\n")) ;
1716 for (int i=1; i<ua->argc; i++) {
1717 if (strcasecmp(ua->argk[i], "jobid") == 0) {
1721 jobid = str_to_int64(ua->argv[i]);
1723 } else if (strcasecmp(ua->argk[i], "jobname") == 0 ||
1724 strcasecmp(ua->argk[i], "job") == 0) {
1728 jcr=get_jcr_by_partial_name(ua->argv[i]) ;
1730 jobid = jcr->JobId ;
1734 } else if (strcasecmp(ua->argk[i], "ujobid") == 0) {
1738 jcr=get_jcr_by_full_name(ua->argv[i]) ;
1740 jobid = jcr->JobId ;
1744 /* Wait for a mount request */
1745 } else if (strcasecmp(ua->argk[i], "mount") == 0) {
1746 for (bool waiting=false; !waiting; ) {
1748 if (jcr->JobId != 0 &&
1749 (jcr->JobStatus == JS_WaitMedia || jcr->JobStatus == JS_WaitMount)) {
1758 if (stop_time && (time(NULL) >= stop_time)) {
1759 ua->warning_msg(_("Wait on mount timed out\n"));
1769 ua->error_msg(_("ERR: Job was not found\n"));
1774 * We wait the end of a specific job
1777 bmicrosleep(0, 200000); /* let job actually start */
1778 for (bool running=true; running; ) {
1781 jcr=get_jcr_by_id(jobid) ;
1794 * We have to get JobStatus
1798 char jobstatus = '?'; /* Unknown by default */
1801 bsnprintf(buf, sizeof(buf),
1802 "SELECT JobStatus FROM Job WHERE JobId='%i'", jobid);
1805 db_sql_query(ua->db, buf,
1806 status_handler, (void *)&jobstatus);
1808 switch (jobstatus) {
1810 status = 1 ; /* Warning */
1814 case JS_ErrorTerminated:
1816 status = 2 ; /* Critical */
1821 status = 0 ; /* Ok */
1825 status = 3 ; /* Unknown */
1829 ua->send_msg("JobId=%i\n", jobid) ;
1830 ua->send_msg("JobStatus=%s (%c)\n",
1831 job_status_to_str(jobstatus),
1834 if (ua->gui || ua->api) {
1835 ua->send_msg("ExitStatus=%i\n", status) ;
1842 static int help_cmd(UAContext *ua, const char *cmd)
1846 ua->send_msg(_(" Command Description\n ======= ===========\n"));
1847 for (i=0; i<comsize; i++) {
1848 ua->send_msg(_(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1850 ua->send_msg(_("\nWhen at a prompt, entering a period cancels the command.\n\n"));
1854 int qhelp_cmd(UAContext *ua, const char *cmd)
1858 for (i=0; i<comsize; i++) {
1859 ua->send_msg("%s %s\n", commands[i].key, _(commands[i].help));
1865 static int version_cmd(UAContext *ua, const char *cmd)
1867 ua->send_msg(_("%s Version: %s (%s) %s %s %s %s\n"), my_name, VERSION, BDATE,
1868 HOST_OS, DISTNAME, DISTVER, NPRTB(director->verid));
1873 * Test code -- turned on only for debug testing
1875 static int version_cmd(UAContext *ua, const char *cmd)
1878 POOL_MEM query(PM_MESSAGE);
1880 Mmsg(query, "select MediaId from Media,Pool where Pool.PoolId=Media.PoolId and Pool.Name='Full'");
1881 db_get_query_dbids(ua->jcr, ua->db, query, ids);
1882 ua->send_msg("num_ids=%d max_ids=%d tot_ids=%d\n", ids.num_ids, ids.max_ids, ids.tot_ids);
1883 for (int i=0; i < ids.num_ids; i++) {
1884 ua->send_msg("id=%d\n", ids.DBId[i]);
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)
1980 ua->catalog = get_catalog_resource(ua);
1982 ua->error_msg( _("Could not find a Catalog resource\n"));
1987 ua->jcr->catalog = ua->catalog;
1989 Dmsg0(100, "UA Open database\n");
1990 ua->db = db_init(ua->jcr, ua->catalog->db_driver, ua->catalog->db_name,
1991 ua->catalog->db_user,
1992 ua->catalog->db_password, ua->catalog->db_address,
1993 ua->catalog->db_port, ua->catalog->db_socket,
1994 ua->catalog->mult_db_connections);
1995 if (!ua->db || !db_open_database(ua->jcr, ua->db)) {
1996 ua->error_msg(_("Could not open catalog database \"%s\".\n"),
1997 ua->catalog->db_name);
1999 ua->error_msg("%s", db_strerror(ua->db));
2004 ua->jcr->db = ua->db;
2006 ua->send_msg(_("Using Catalog \"%s\"\n"), ua->catalog->name());
2008 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
2012 void close_db(UAContext *ua)
2015 db_close_database(ua->jcr, ua->db);