3 * Bacula Director -- User Agent Commands
5 * Kern Sibbald, September MM
11 Copyright (C) 2000-2003 Kern Sibbald and John Walker
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License as
15 published by the Free Software Foundation; either version 2 of
16 the License, or (at your option) any later version.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 General Public License for more details.
23 You should have received a copy of the GNU General Public
24 License along with this program; if not, write to the Free
25 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
34 /* Imported subroutines */
35 extern void run_job(JCR *jcr);
37 /* Imported variables */
40 extern struct s_res resources[];
41 extern char my_name[];
43 /* Imported functions */
44 extern int statuscmd(UAContext *ua, char *cmd);
45 extern int listcmd(UAContext *ua, char *cmd);
46 extern int showcmd(UAContext *ua, char *cmd);
47 extern int messagescmd(UAContext *ua, char *cmd);
48 extern int autodisplaycmd(UAContext *ua, char *cmd);
49 extern int sqlquerycmd(UAContext *ua, char *cmd);
50 extern int querycmd(UAContext *ua, char *cmd);
51 extern int runcmd(UAContext *ua, char *cmd);
52 extern int retentioncmd(UAContext *ua, char *cmd);
53 extern int prunecmd(UAContext *ua, char *cmd);
54 extern int purgecmd(UAContext *ua, char *cmd);
55 extern int restorecmd(UAContext *ua, char *cmd);
57 /* Forward referenced functions */
58 static int addcmd(UAContext *ua, char *cmd), createcmd(UAContext *ua, char *cmd), cancelcmd(UAContext *ua, char *cmd);
59 static int setdebugcmd(UAContext *ua, char *cmd);
60 static int helpcmd(UAContext *ua, char *cmd);
61 static int deletecmd(UAContext *ua, char *cmd);
62 static int usecmd(UAContext *ua, char *cmd), unmountcmd(UAContext *ua, char *cmd);
63 static int labelcmd(UAContext *ua, char *cmd), mountcmd(UAContext *ua, char *cmd), updatecmd(UAContext *ua, char *cmd);
64 static int versioncmd(UAContext *ua, char *cmd), automountcmd(UAContext *ua, char *cmd);
65 static int update_volume(UAContext *ua);
66 static int update_pool(UAContext *ua);
67 static int delete_volume(UAContext *ua);
68 static int delete_pool(UAContext *ua);
70 int quitcmd(UAContext *ua, char *cmd);
73 struct cmdstruct { char *key; int (*func)(UAContext *ua, char *cmd); char *help; };
74 static struct cmdstruct commands[] = {
75 { N_("add"), addcmd, _("add media to a pool")},
76 { N_("autodisplay"), autodisplaycmd, _("autodisplay [on/off] -- console messages")},
77 { N_("automount"), automountcmd, _("automount [on/off] -- after label")},
78 { N_("cancel"), cancelcmd, _("cancel job=nnn -- cancel a job")},
79 { N_("create"), createcmd, _("create DB Pool from resource")},
80 { N_("delete"), deletecmd, _("delete [pool=<pool-name> | media volume=<volume-name>]")},
81 { N_("help"), helpcmd, _("print this command")},
82 { N_("label"), labelcmd, _("label a tape")},
83 { N_("list"), listcmd, _("list [pools | jobs | jobtotals | media <pool> | files job=<nn>]; from catalog")},
84 { N_("messages"), messagescmd, _("messages")},
85 { N_("mount"), mountcmd, _("mount <storage-name>")},
86 { N_("restore"), restorecmd, _("restore files")},
87 { N_("prune"), prunecmd, _("prune expired records from catalog")},
88 { N_("purge"), purgecmd, _("purge records from catalog")},
89 { N_("run"), runcmd, _("run <job-name>")},
90 { N_("setdebug"), setdebugcmd, _("sets debug level")},
91 { N_("show"), showcmd, _("show (resource records) [jobs | pools | ... | all]")},
92 { N_("sqlquery"), sqlquerycmd, _("use SQL to query catalog")},
93 { N_("status"), statuscmd, _("status [storage | client]=<name>")},
94 { N_("unmount"), unmountcmd, _("unmount <storage-name>")},
95 { N_("update"), updatecmd, _("update Volume or Pool")},
96 { N_("use"), usecmd, _("use catalog xxx")},
97 { N_("version"), versioncmd, _("print Director version")},
98 { N_("quit"), quitcmd, _("quit")},
99 { N_("query"), querycmd, _("query catalog")},
100 { N_("exit"), quitcmd, _("exit = quit")},
102 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
105 * Execute a command from the UA
107 int do_a_command(UAContext *ua, char *cmd)
116 Dmsg1(120, "Command: %s\n", ua->UA_sock->msg);
121 len = strlen(ua->argk[0]);
122 for (i=0; i<comsize; i++) /* search for command */
123 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
124 stat = (*commands[i].func)(ua, cmd); /* go execute command */
129 strcat(ua->UA_sock->msg, _(": is an illegal command\n"));
130 ua->UA_sock->msglen = strlen(ua->UA_sock->msg);
131 bnet_send(ua->UA_sock);
137 * This is a common routine used to stuff the Pool DB record defaults
138 * into the Media DB record just before creating a media (Volume)
141 void set_pool_dbr_defaults_in_media_dbr(MEDIA_DBR *mr, POOL_DBR *pr)
143 mr->PoolId = pr->PoolId;
144 strcpy(mr->VolStatus, "Append");
145 mr->Recycle = pr->Recycle;
146 mr->VolRetention = pr->VolRetention;
147 mr->VolUseDuration = pr->VolUseDuration;
148 mr->MaxVolJobs = pr->MaxVolJobs;
149 mr->MaxVolFiles = pr->MaxVolFiles;
150 mr->MaxVolBytes = pr->MaxVolBytes;
155 * Add Volumes to an existing Pool
158 static int addcmd(UAContext *ua, char *cmd)
162 int num, i, max, startnum;
164 char name[MAX_NAME_LENGTH];
169 "You probably don't want to be using this command since it\n"
170 "creates database records without labeling the Volumes.\n"
171 "You probably want to use the \"label\" command.\n\n"));
177 memset(&pr, 0, sizeof(pr));
178 memset(&mr, 0, sizeof(mr));
180 if (!get_pool_dbr(ua, &pr)) {
184 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
185 pr.MaxVols, pr.PoolType);
187 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
188 bsendmsg(ua, _("Pool already has maximum volumes = %d\n"), pr.MaxVols);
190 if (!get_cmd(ua, _("Enter new maximum (zero for unlimited): "))) {
193 pr.MaxVols = atoi(ua->cmd);
194 if (pr.MaxVols < 0) {
195 bsendmsg(ua, _("Max vols must be zero or greater.\n"));
203 if ((store = get_storage_resource(ua, cmd)) != NULL) {
204 strcpy(mr.MediaType, store->media_type);
205 } else if (!get_media_type(ua, mr.MediaType, sizeof(mr.MediaType))) {
209 if (pr.MaxVols == 0) {
212 max = pr.MaxVols - pr.NumVols;
216 sprintf(buf, _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
217 if (!get_cmd(ua, buf)) {
221 if (num < 0 || num > max) {
222 bsendmsg(ua, _("The number must be between 0 and %d\n"), max);
229 if (!get_cmd(ua, _("Enter Volume name: "))) {
233 if (!get_cmd(ua, _("Enter base volume name: "))) {
237 /* Don't allow | in Volume name because it is the volume separator character */
238 if (strchr(ua->cmd, '|')) {
239 bsendmsg(ua, _("Illegal character | in a volume name.\n"));
242 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
243 bsendmsg(ua, _("Volume name too long.\n"));
246 if (strlen(ua->cmd) == 0) {
247 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
251 strcpy(name, ua->cmd);
253 strcat(name, "%04d");
256 if (!get_cmd(ua, _("Enter the starting number: "))) {
259 startnum = atoi(ua->cmd);
261 bsendmsg(ua, _("Start number must be greater than zero.\n"));
271 if (store && store->autochanger) {
272 if (!get_cmd(ua, _("Enter slot (0 for none): "))) {
275 slot = atoi(ua->cmd);
278 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
279 for (i=startnum; i < num+startnum; i++) {
280 sprintf(mr.VolumeName, name, i);
282 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
283 if (!db_create_media_record(ua->jcr, ua->db, &mr)) {
284 bsendmsg(ua, db_strerror(ua->db));
288 first_id = mr.PoolId;
292 Dmsg0(200, "Update pool record.\n");
293 if (db_update_pool_record(ua->jcr, ua->db, &pr) != 1) {
294 bsendmsg(ua, db_strerror(ua->db));
297 bsendmsg(ua, _("%d Volumes created in pool %s\n"), num, pr.Name);
303 * Turn auto mount on/off
308 int automountcmd(UAContext *ua, char *cmd)
313 if (!get_cmd(ua, _("Turn on or off? "))) {
321 ua->automount = (strcasecmp(onoff, _("off")) == 0) ? 0 : 1;
329 static int cancelcmd(UAContext *ua, char *cmd)
335 char JobName[MAX_NAME_LENGTH];
341 for (i=1; i<ua->argc; i++) {
342 if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
346 if (!(jcr=get_jcr_by_id(atoi(ua->argv[i])))) {
347 bsendmsg(ua, _("JobId %d is not running.\n"), atoi(ua->argv[i]));
351 } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
355 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
356 bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
362 /* If we still do not have a jcr,
363 * throw up a list and ask the user to select one.
366 /* Count Jobs running */
368 for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
369 if (jcr->JobId == 0) { /* this is us */
370 free_locked_jcr(jcr);
374 free_locked_jcr(jcr);
379 bsendmsg(ua, _("No Jobs running.\n"));
382 start_prompt(ua, _("Select Job:\n"));
384 for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
385 if (jcr->JobId == 0) { /* this is us */
386 free_locked_jcr(jcr);
389 add_prompt(ua, jcr->Job);
390 free_locked_jcr(jcr);
394 if (do_prompt(ua, _("Choose Job to cancel"), JobName, sizeof(JobName)) < 0) {
398 if (!get_cmd(ua, _("Confirm cancel (yes/no): "))) {
401 if (strcasecmp(ua->cmd, _("yes")) != 0) {
405 jcr = get_jcr_by_full_name(JobName);
407 bsendmsg(ua, _("Job %s not found.\n"), JobName);
412 switch (jcr->JobStatus) {
414 set_jcr_job_status(jcr, JS_Cancelled);
415 bsendmsg(ua, _("JobId %d, Job %s marked to be cancelled.\n"),
416 jcr->JobId, jcr->Job);
422 set_jcr_job_status(jcr, JS_Cancelled);
423 /* Cancel File daemon */
424 ua->jcr->client = jcr->client;
425 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
426 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
430 Dmsg0(200, "Connected to file daemon\n");
431 fd = ua->jcr->file_bsock;
432 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
433 while (bnet_recv(fd) >= 0) {
434 bsendmsg(ua, "%s", fd->msg);
436 bnet_sig(fd, BNET_TERMINATE);
438 ua->jcr->file_bsock = NULL;
440 /* Cancel Storage daemon */
441 ua->jcr->store = jcr->store;
442 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
443 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
447 Dmsg0(200, "Connected to storage daemon\n");
448 sd = ua->jcr->store_bsock;
449 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
450 while (bnet_recv(sd) >= 0) {
451 bsendmsg(ua, "%s", sd->msg);
453 bnet_sig(sd, BNET_TERMINATE);
455 ua->jcr->store_bsock = NULL;
464 * This is a common routine to create or update a
465 * Pool DB base record from a Pool Resource. We handle
466 * the setting of MaxVols and NumVols slightly differently
467 * depending on if we are creating the Pool or we are
468 * simply bringing it into agreement with the resource (updage).
470 void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, int create)
472 strcpy(pr->PoolType, pool->pool_type);
474 pr->MaxVols = pool->max_volumes;
476 } else { /* update pool */
477 if (pr->MaxVols != pool->max_volumes) {
478 pr->MaxVols = pool->max_volumes;
480 if (pr->MaxVols != 0 && pr->MaxVols < pr->NumVols) {
481 pr->MaxVols = pr->NumVols;
484 pr->UseOnce = pool->use_volume_once;
485 pr->UseCatalog = pool->use_catalog;
486 pr->AcceptAnyVolume = pool->accept_any_volume;
487 pr->Recycle = pool->Recycle;
488 pr->VolRetention = pool->VolRetention;
489 pr->VolUseDuration = pool->VolUseDuration;
490 pr->MaxVolJobs = pool->MaxVolJobs;
491 pr->MaxVolFiles = pool->MaxVolFiles;
492 pr->MaxVolBytes = pool->MaxVolBytes;
493 if (pool->label_format) {
494 strcpy(pr->LabelFormat, pool->label_format);
496 strcpy(pr->LabelFormat, "*"); /* none */
502 * Create a pool record from a given Pool resource
503 * Also called from backup.c
504 * Returns: -1 on error
505 * 0 record already exists
509 int create_pool(JCR *jcr, B_DB *db, POOL *pool)
513 memset(&pr, 0, sizeof(POOL_DBR));
515 strcpy(pr.Name, pool->hdr.name);
517 if (db_get_pool_record(jcr, db, &pr)) {
518 return 0; /* exists */
521 set_pooldbr_from_poolres(&pr, pool, 1);
523 if (!db_create_pool_record(jcr, db, &pr)) {
524 return -1; /* error */
532 * Create a Pool Record in the database.
533 * It is always created from the Resource record.
535 static int createcmd(UAContext *ua, char *cmd)
543 pool = get_pool_resource(ua);
548 switch (create_pool(ua->jcr, ua->db, pool)) {
550 bsendmsg(ua, _("Error: Pool %s already exists.\n\
551 Use update to change it.\n"), pool->hdr.name);
555 bsendmsg(ua, db_strerror(ua->db));
561 bsendmsg(ua, _("Pool %s created.\n"), pool->hdr.name);
569 * Update a Pool Record in the database.
570 * It is always updated from the Resource record.
572 * update pool=<pool-name>
573 * updates pool from Pool resource
574 * update media pool=<pool-name> volume=<volume-name>
575 * changes pool info for volume
577 static int updatecmd(UAContext *ua, char *cmd)
579 static char *kw[] = {
589 switch (find_arg_keyword(ua, kw)) {
601 start_prompt(ua, _("Update choice:\n"));
602 add_prompt(ua, _("Volume parameters"));
603 add_prompt(ua, _("Pool from resource"));
604 switch (do_prompt(ua, _("Choose catalog item to update"), NULL, 0)) {
618 * Update a media record -- allows you to change the
619 * Volume status. E.g. if you want Bacula to stop
620 * writing on the volume, set it to anything other
623 static int update_volume(UAContext *ua)
630 if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
634 for (int done=0; !done; ) {
635 if (!db_get_media_record(ua->jcr, ua->db, &mr)) {
636 if (mr.MediaId != 0) {
637 bsendmsg(ua, _("Volume record for MediaId %d not found.\n"), mr.MediaId);
639 bsendmsg(ua, _("Volume record for %s not found.\n"), mr.VolumeName);
643 bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
644 start_prompt(ua, _("Parameters to modify:\n"));
645 add_prompt(ua, _("Volume Status"));
646 add_prompt(ua, _("Volume Retention Period"));
647 add_prompt(ua, _("Volume Use Duration"));
648 add_prompt(ua, _("Maximum Volume Jobs"));
649 add_prompt(ua, _("Maximum Volume Files"));
650 add_prompt(ua, _("Maximum Volume Bytes"));
651 add_prompt(ua, _("Recycle Flag"));
652 add_prompt(ua, _("Slot"));
653 add_prompt(ua, _("Volume Files"));
654 add_prompt(ua, _("Done"));
655 switch (do_prompt(ua, _("Select parameter to modify"), NULL, 0)) {
656 case 0: /* Volume Status */
657 /* Modify Volume Status */
658 bsendmsg(ua, _("Current Volume status is: %s\n"), mr.VolStatus);
659 start_prompt(ua, _("Possible Values are:\n"));
660 add_prompt(ua, "Append"); /* Better not translate these as */
661 add_prompt(ua, "Archive"); /* They are known in the database code */
662 add_prompt(ua, "Disabled");
663 add_prompt(ua, "Full");
664 add_prompt(ua, "Used");
665 if (strcmp(mr.VolStatus, "Purged") == 0) {
666 add_prompt(ua, "Recycle");
668 add_prompt(ua, "Read-Only");
669 if (do_prompt(ua, _("Choose new Volume Status"), ua->cmd, sizeof(mr.VolStatus)) < 0) {
672 bstrncpy(mr.VolStatus, ua->cmd, sizeof(mr.VolStatus));
673 query = get_pool_memory(PM_MESSAGE);
674 Mmsg(&query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%u",
675 mr.VolStatus, mr.MediaId);
676 if (!db_sql_query(ua->db, query, NULL, NULL)) {
677 bsendmsg(ua, "%s", db_strerror(ua->db));
679 bsendmsg(ua, _("New Volume status is: %s\n"), mr.VolStatus);
681 free_pool_memory(query);
683 case 1: /* Retention */
684 bsendmsg(ua, _("Current retention seconds is: %s\n"),
685 edit_utime(mr.VolRetention, ed1));
686 if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
689 if (!duration_to_utime(ua->cmd, &mr.VolRetention)) {
690 bsendmsg(ua, _("Invalid retention period specified.\n"));
693 query = get_pool_memory(PM_MESSAGE);
694 Mmsg(&query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%u",
695 edit_uint64(mr.VolRetention, ed1), mr.MediaId);
696 if (!db_sql_query(ua->db, query, NULL, NULL)) {
697 bsendmsg(ua, "%s", db_strerror(ua->db));
699 bsendmsg(ua, _("New retention seconds is: %s\n"),
700 edit_utime(mr.VolRetention, ed1));
702 free_pool_memory(query);
705 case 2: /* Use Duration */
706 bsendmsg(ua, _("Current use duration is: %s\n"),
707 edit_utime(mr.VolUseDuration, ed1));
708 if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
711 if (!duration_to_utime(ua->cmd, &mr.VolUseDuration)) {
712 bsendmsg(ua, _("Invalid use duration specified.\n"));
715 query = get_pool_memory(PM_MESSAGE);
716 Mmsg(&query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%u",
717 edit_uint64(mr.VolUseDuration, ed1), mr.MediaId);
718 if (!db_sql_query(ua->db, query, NULL, NULL)) {
719 bsendmsg(ua, "%s", db_strerror(ua->db));
721 bsendmsg(ua, _("New use duration is: %s\n"),
722 edit_utime(mr.VolUseDuration, ed1));
724 free_pool_memory(query);
727 case 3: /* Max Jobs */
729 bsendmsg(ua, _("Current max jobs is: %u\n"), mr.MaxVolJobs);
730 if (!get_cmd(ua, _("Enter new Maximum Jobs: "))) {
733 maxjobs = atoi(ua->cmd);
735 bsendmsg(ua, _("Invalid number, it must be 0 or greater\n"));
738 query = get_pool_memory(PM_MESSAGE);
739 Mmsg(&query, "UPDATE Media SET MaxVolJobs=%u WHERE MediaId=%u",
740 maxjobs, mr.MediaId);
741 if (!db_sql_query(ua->db, query, NULL, NULL)) {
742 bsendmsg(ua, "%s", db_strerror(ua->db));
744 bsendmsg(ua, _("New max jobs is: %u\n"), maxjobs);
746 free_pool_memory(query);
749 case 4: /* Max Files */
751 bsendmsg(ua, _("Current max files is: %u\n"), mr.MaxVolFiles);
752 if (!get_cmd(ua, _("Enter new Maximum Files: "))) {
755 maxfiles = atoi(ua->cmd);
757 bsendmsg(ua, _("Invalid number, it must be 0 or greater\n"));
760 query = get_pool_memory(PM_MESSAGE);
761 Mmsg(&query, "UPDATE Media SET MaxVolFiles=%u WHERE MediaId=%u",
762 maxfiles, mr.MediaId);
763 if (!db_sql_query(ua->db, query, NULL, NULL)) {
764 bsendmsg(ua, "%s", db_strerror(ua->db));
766 bsendmsg(ua, _("New max files is: %u\n"), maxfiles);
768 free_pool_memory(query);
771 case 5: /* Max Bytes */
773 bsendmsg(ua, _("Current value is: %s\n"), edit_uint64(mr.MaxVolBytes, ed1));
774 if (!get_cmd(ua, _("Enter new Maximum Bytes: "))) {
777 if (!size_to_uint64(ua->cmd, strlen(ua->cmd), &maxbytes)) {
778 bsendmsg(ua, _("Invalid byte size specification.\n"));
781 query = get_pool_memory(PM_MESSAGE);
782 Mmsg(&query, "UPDATE Media SET MaxVolBytes=%s WHERE MediaId=%u",
783 edit_uint64(maxbytes, ed1), mr.MediaId);
784 if (!db_sql_query(ua->db, query, NULL, NULL)) {
785 bsendmsg(ua, "%s", db_strerror(ua->db));
787 bsendmsg(ua, _("New Max bytes is: %s\n"), edit_uint64(maxbytes, ed1));
789 free_pool_memory(query);
793 case 6: /* Recycle */
795 bsendmsg(ua, _("Current recycle flag is: %s\n"),
796 mr.Recycle==1?_("yes"):_("no"));
797 if (!get_cmd(ua, _("Enter new Recycle status: "))) {
800 if (strcasecmp(ua->cmd, _("yes")) == 0) {
802 } else if (strcasecmp(ua->cmd, _("no")) == 0) {
805 bsendmsg(ua, _("Invalid recycle status specified.\n"));
808 query = get_pool_memory(PM_MESSAGE);
809 Mmsg(&query, "UPDATE Media SET Recycle=%d WHERE MediaId=%u",
810 recycle, mr.MediaId);
811 if (!db_sql_query(ua->db, query, NULL, NULL)) {
812 bsendmsg(ua, "%s", db_strerror(ua->db));
814 bsendmsg(ua, _("New recycle flag is: %s\n"),
815 mr.Recycle==1?_("yes"):_("no"));
817 free_pool_memory(query);
822 bsendmsg(ua, _("Current Slot is: %d\n"), mr.Slot);
823 if (!get_cmd(ua, _("Enter new Slot: "))) {
826 slot = atoi(ua->cmd);
828 bsendmsg(ua, _("Invalid slot, it must be 0 or greater\n"));
830 } else if (pr.MaxVols > 0 && slot >(int)pr.MaxVols) {
831 bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"),
835 query = get_pool_memory(PM_MESSAGE);
836 Mmsg(&query, "UPDATE Media SET Slot=%d WHERE MediaId=%u",
838 if (!db_sql_query(ua->db, query, NULL, NULL)) {
839 bsendmsg(ua, "%s", db_strerror(ua->db));
841 bsendmsg(ua, "New Slot is: %d\n", slot);
843 free_pool_memory(query);
846 case 8: /* Volume Files */
848 bsendmsg(ua, _("Warning changing Volume Files can result\n"
849 "in loss of data on your Volume\n\n"));
850 bsendmsg(ua, _("Current Volume Files is: %u\n"), mr.VolFiles);
851 if (!get_cmd(ua, _("Enter new number of Files for Volume: "))) {
854 VolFiles = atoi(ua->cmd);
856 bsendmsg(ua, _("Invalid number, it must be 0 or greater\n"));
859 if (VolFiles != (int)(mr.VolFiles + 1)) {
860 bsendmsg(ua, _("Normally, you should only increase Volume Files by one!\n"));
861 if (!get_cmd(ua, _("Continue? (yes/no): ")) ||
862 strcasecmp(ua->cmd, "yes") != 0) {
866 query = get_pool_memory(PM_MESSAGE);
867 Mmsg(&query, "UPDATE Media SET VolFiles=%u WHERE MediaId=%u",
868 VolFiles, mr.MediaId);
869 if (!db_sql_query(ua->db, query, NULL, NULL)) {
870 bsendmsg(ua, "%s", db_strerror(ua->db));
872 bsendmsg(ua, _("New Volume Files is: %u\n"), VolFiles);
874 free_pool_memory(query);
877 default: /* Done or error */
878 bsendmsg(ua, "Selection done.\n");
886 * Update pool record -- pull info from current POOL resource
888 static int update_pool(UAContext *ua)
895 pool = get_pool_resource(ua);
900 memset(&pr, 0, sizeof(pr));
901 strcpy(pr.Name, pool->hdr.name);
902 if (!get_pool_dbr(ua, &pr)) {
906 set_pooldbr_from_poolres(&pr, pool, 0); /* update */
908 id = db_update_pool_record(ua->jcr, ua->db, &pr);
910 bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
911 id, db_strerror(ua->db));
913 bsendmsg(ua, _("Pool DB record updated from resource.\n"));
918 static void do_storage_setdebug(UAContext *ua, STORE *store, int level)
922 ua->jcr->store = store;
923 /* Try connecting for up to 15 seconds */
924 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"),
925 store->hdr.name, store->address, store->SDport);
926 if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
927 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
930 Dmsg0(120, _("Connected to storage daemon\n"));
931 sd = ua->jcr->store_bsock;
932 bnet_fsend(sd, "setdebug=%d\n", level);
933 if (bnet_recv(sd) >= 0) {
934 bsendmsg(ua, "%s", sd->msg);
936 bnet_sig(sd, BNET_TERMINATE);
938 ua->jcr->store_bsock = NULL;
942 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level)
946 /* Connect to File daemon */
948 ua->jcr->client = client;
949 /* Try to connect for 15 seconds */
950 bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"),
951 client->hdr.name, client->address, client->FDport);
952 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
953 bsendmsg(ua, _("Failed to connect to Client.\n"));
956 Dmsg0(120, "Connected to file daemon\n");
957 fd = ua->jcr->file_bsock;
958 bnet_fsend(fd, "setdebug=%d\n", level);
959 if (bnet_recv(fd) >= 0) {
960 bsendmsg(ua, "%s", fd->msg);
962 bnet_sig(fd, BNET_TERMINATE);
964 ua->jcr->file_bsock = NULL;
970 static void do_all_setdebug(UAContext *ua, int level)
972 STORE *store, **unique_store;
973 CLIENT *client, **unique_client;
979 /* Count Storage items */
982 for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
984 unique_store = (STORE **) malloc(i * sizeof(STORE));
985 /* Find Unique Storage address/port */
986 store = (STORE *)GetNextRes(R_STORAGE, NULL);
988 unique_store[i++] = store;
989 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
991 for (j=0; j<i; j++) {
992 if (strcmp(unique_store[j]->address, store->address) == 0 &&
993 unique_store[j]->SDport == store->SDport) {
999 unique_store[i++] = store;
1000 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
1005 /* Call each unique Storage daemon */
1006 for (j=0; j<i; j++) {
1007 do_storage_setdebug(ua, unique_store[j], level);
1011 /* Count Client items */
1014 for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
1016 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
1017 /* Find Unique Client address/port */
1018 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
1020 unique_client[i++] = client;
1021 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
1023 for (j=0; j<i; j++) {
1024 if (strcmp(unique_client[j]->address, client->address) == 0 &&
1025 unique_client[j]->FDport == client->FDport) {
1031 unique_client[i++] = client;
1032 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
1037 /* Call each unique File daemon */
1038 for (j=0; j<i; j++) {
1039 do_client_setdebug(ua, unique_client[j], level);
1041 free(unique_client);
1045 * setdebug level=nn all
1047 static int setdebugcmd(UAContext *ua, char *cmd)
1057 Dmsg1(120, "setdebug:%s:\n", cmd);
1060 for (i=1; i<ua->argc; i++) {
1061 if (strcasecmp(ua->argk[i], _("level")) == 0 && ua->argv[i]) {
1062 level = atoi(ua->argv[i]);
1067 if (!get_cmd(ua, _("Enter new debug level: "))) {
1070 level = atoi(ua->cmd);
1073 bsendmsg(ua, _("level cannot be negative.\n"));
1077 /* General debug? */
1078 for (i=1; i<ua->argc; i++) {
1079 if (strcasecmp(ua->argk[i], _("all")) == 0) {
1080 do_all_setdebug(ua, level);
1083 if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
1084 strcasecmp(ua->argk[i], _("director")) == 0) {
1085 debug_level = level;
1088 if (strcasecmp(ua->argk[i], _("client")) == 0) {
1091 client = (CLIENT *) GetResWithName(R_CLIENT, ua->argv[i]);
1093 do_client_setdebug(ua, client, level);
1097 client = select_client_resource(ua);
1099 do_client_setdebug(ua, client, level);
1103 store = get_storage_resource(ua, cmd);
1105 do_storage_setdebug(ua, store, level);
1111 * We didn't find an appropriate keyword above, so
1114 start_prompt(ua, _("Available daemons are: \n"));
1115 add_prompt(ua, _("Director"));
1116 add_prompt(ua, _("Storage"));
1117 add_prompt(ua, _("Client"));
1118 add_prompt(ua, _("All"));
1119 switch(do_prompt(ua, _("Select daemon type to set debug level"), NULL, 0)) {
1120 case 0: /* Director */
1121 debug_level = level;
1124 store = get_storage_resource(ua, cmd);
1126 do_storage_setdebug(ua, store, level);
1130 client = select_client_resource(ua);
1132 do_client_setdebug(ua, client, level);
1136 do_all_setdebug(ua, level);
1147 * Delete Pool records (should purge Media with it).
1149 * delete pool=<pool-name>
1150 * delete media pool=<pool-name> volume=<name>
1152 static int deletecmd(UAContext *ua, char *cmd)
1154 static char *keywords[] = {
1164 "In general it is not a good idea to delete either a\n"
1165 "Pool or a Volume since they may contain data.\n\n"));
1167 switch (find_arg_keyword(ua, keywords)) {
1177 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1185 bsendmsg(ua, _("Nothing done.\n"));
1192 * Delete media records from database -- dangerous
1194 static int delete_volume(UAContext *ua)
1199 if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
1202 bsendmsg(ua, _("\nThis command will delete volume %s\n"
1203 "and all Jobs saved on that volume from the Catalog\n"),
1206 if (!get_cmd(ua, _("Are you sure you want to delete this Volume? (yes/no): "))) {
1209 if (strcasecmp(ua->cmd, _("yes")) == 0) {
1210 db_delete_media_record(ua->jcr, ua->db, &mr);
1216 * Delete a pool record from the database -- dangerous
1218 static int delete_pool(UAContext *ua)
1222 memset(&pr, 0, sizeof(pr));
1224 if (!get_pool_dbr(ua, &pr)) {
1227 if (!get_cmd(ua, _("Are you sure you want to delete this Pool? (yes/no): "))) {
1230 if (strcasecmp(ua->cmd, _("yes")) == 0) {
1231 db_delete_pool_record(ua->jcr, ua->db, &pr);
1240 * label storage=xxx volume=vvv
1242 static int labelcmd(UAContext *ua, char *cmd)
1246 char dev_name[MAX_NAME_LENGTH];
1250 int mounted = FALSE;
1253 static char *keyword[] = {
1260 store = get_storage_resource(ua, cmd);
1265 i = find_arg_keyword(ua, keyword);
1266 if (i >=0 && ua->argv[i]) {
1267 strcpy(ua->cmd, ua->argv[i]);
1272 if (!get_cmd(ua, _("Enter new Volume name: "))) {
1276 if (strchr(ua->cmd, '|')) {
1277 bsendmsg(ua, _("Illegal character | in a volume name.\n"));
1280 if (strlen(ua->cmd) >= MAX_NAME_LENGTH) {
1281 bsendmsg(ua, _("Volume name too long.\n"));
1284 if (strlen(ua->cmd) == 0) {
1285 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
1290 memset(&mr, 0, sizeof(mr));
1291 strcpy(mr.VolumeName, ua->cmd);
1292 if (db_get_media_record(ua->jcr, ua->db, &mr)) {
1293 bsendmsg(ua, _("Media record for Volume %s already exists.\n"),
1298 /* Do some more checking on slot ****FIXME**** */
1299 if (store->autochanger) {
1300 if (!get_cmd(ua, _("Enter slot (0 for none): "))) {
1303 slot = atoi(ua->cmd);
1305 strcpy(mr.MediaType, store->media_type);
1308 memset(&pr, 0, sizeof(pr));
1309 if (!select_pool_dbr(ua, &pr)) {
1313 ua->jcr->store = store;
1314 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
1315 store->hdr.name, store->address, store->SDport);
1316 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1317 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1320 sd = ua->jcr->store_bsock;
1321 strcpy(dev_name, store->dev_name);
1322 bash_spaces(dev_name);
1323 bash_spaces(mr.VolumeName);
1324 bash_spaces(mr.MediaType);
1325 bash_spaces(pr.Name);
1326 bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d"),
1327 dev_name, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot);
1328 bsendmsg(ua, "Sending label command ...\n");
1329 while (bget_msg(sd, 0) >= 0) {
1330 bsendmsg(ua, "%s", sd->msg);
1331 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
1335 ua->jcr->store_bsock = NULL;
1336 unbash_spaces(dev_name);
1337 unbash_spaces(mr.VolumeName);
1338 unbash_spaces(mr.MediaType);
1339 unbash_spaces(pr.Name);
1340 mr.LabelDate = time(NULL);
1342 set_pool_dbr_defaults_in_media_dbr(&mr, &pr);
1343 if (db_create_media_record(ua->jcr, ua->db, &mr)) {
1344 bsendmsg(ua, _("Media record for Volume=%s successfully created.\n"),
1346 if (ua->automount) {
1347 bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
1348 bash_spaces(dev_name);
1349 bnet_fsend(sd, "mount %s", dev_name);
1350 unbash_spaces(dev_name);
1351 while (bnet_recv(sd) >= 0) {
1352 bsendmsg(ua, "%s", sd->msg);
1354 * 3001 OK mount. Device=xxx or
1355 * 3001 Mounted Volume vvvv
1357 if (strncmp(sd->msg, "3001 ", 5) == 0) {
1359 /***** ****FIXME***** find job waiting for
1360 ***** mount, and change to waiting for SD
1366 bsendmsg(ua, "%s", db_strerror(ua->db));
1370 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
1372 bnet_sig(sd, BNET_TERMINATE);
1377 static void do_mount_cmd(int mount, UAContext *ua, char *cmd)
1381 char dev_name[MAX_NAME_LENGTH];
1387 Dmsg1(120, "mount: %s\n", ua->UA_sock->msg);
1389 store = get_storage_resource(ua, cmd);
1394 Dmsg2(120, "Found storage, MediaType=%s DevName=%s\n",
1395 store->media_type, store->dev_name);
1397 ua->jcr->store = store;
1398 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1399 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1402 sd = ua->jcr->store_bsock;
1403 strcpy(dev_name, store->dev_name);
1404 bash_spaces(dev_name);
1406 bnet_fsend(sd, "mount %s", dev_name);
1408 bnet_fsend(sd, "unmount %s", dev_name);
1410 while (bnet_recv(sd) >= 0) {
1411 bsendmsg(ua, "%s", sd->msg);
1412 if (strncmp(sd->msg, "3001 OK mount.", 14) == 0) {
1413 /***** ****FIXME**** fix JobStatus */
1416 bnet_sig(sd, BNET_TERMINATE);
1418 ua->jcr->store_bsock = NULL;
1422 * mount [storage | device] <name>
1424 static int mountcmd(UAContext *ua, char *cmd)
1426 do_mount_cmd(1, ua, cmd); /* mount */
1432 * unmount [storage | device] <name>
1434 static int unmountcmd(UAContext *ua, char *cmd)
1436 do_mount_cmd(0, ua, cmd); /* unmount */
1443 * use catalog=<name>
1445 static int usecmd(UAContext *ua, char *cmd)
1447 CAT *oldcatalog, *catalog;
1450 close_db(ua); /* close any previously open db */
1451 oldcatalog = ua->catalog;
1453 if (!(catalog = get_catalog_resource(ua))) {
1454 ua->catalog = oldcatalog;
1456 ua->catalog = catalog;
1459 bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
1460 ua->catalog->hdr.name, ua->catalog->db_name);
1465 int quitcmd(UAContext *ua, char *cmd)
1471 static int helpcmd(UAContext *ua, char *cmd)
1476 bsendmsg(ua, _(" Command Description\n ======= ===========\n"));
1477 for (i=0; i<comsize; i++) {
1478 bsendmsg(ua, _(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1484 static int versioncmd(UAContext *ua, char *cmd)
1486 bsendmsg(ua, "%s Version: " VERSION " (" BDATE ")\n", my_name);
1491 /* A bit brain damaged in that if the user has not done
1492 * a "use catalog xxx" command, we simply find the first
1493 * catalog resource and open it.
1495 int open_db(UAContext *ua)
1502 ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1505 bsendmsg(ua, _("Could not find a Catalog resource\n"));
1508 bsendmsg(ua, _("Using default Catalog name=%s DB=%s\n"),
1509 ua->catalog->hdr.name, ua->catalog->db_name);
1513 Dmsg0(150, "Open database\n");
1514 ua->db = db_init_database(ua->jcr, ua->catalog->db_name, ua->catalog->db_user,
1515 ua->catalog->db_password, ua->catalog->db_address,
1516 ua->catalog->db_port, ua->catalog->db_socket);
1517 if (!db_open_database(ua->jcr, ua->db)) {
1518 bsendmsg(ua, _("Could not open DB %s: ERR=%s"),
1519 ua->catalog->db_name, db_strerror(ua->db));
1523 ua->jcr->db = ua->db;
1524 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1528 void close_db(UAContext *ua)
1531 db_close_database(ua->jcr, ua->db);