3 * Bacula Director -- User Agent Commands
5 * Kern Sibbald, September MM
11 Copyright (C) 2000, 2001, 2002 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);
138 * Add Volumes to an existing Pool
141 static int addcmd(UAContext *ua, char *cmd)
145 int num, i, max, startnum;
147 char name[MAX_NAME_LENGTH];
152 "You probably don't want to be using this command since it\n"
153 "creates database records without labeling the Volumes.\n"
154 "You probably want to use the \"label\" command.\n\n"));
160 memset(&pr, 0, sizeof(pr));
161 memset(&mr, 0, sizeof(mr));
163 if (!get_pool_dbr(ua, &pr)) {
167 Dmsg4(120, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
168 pr.MaxVols, pr.PoolType);
170 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
171 bsendmsg(ua, _("Pool already has maximum volumes = %d\n"), pr.MaxVols);
173 if (!get_cmd(ua, _("Enter new maximum (zero for unlimited): "))) {
176 pr.MaxVols = atoi(ua->cmd);
177 if (pr.MaxVols < 0) {
178 bsendmsg(ua, _("Max vols must be zero or greater.\n"));
186 if ((store = get_storage_resource(ua, cmd)) != NULL) {
187 strcpy(mr.MediaType, store->media_type);
189 if (!get_media_type(ua, mr.MediaType)) {
194 if (pr.MaxVols == 0) {
197 max = pr.MaxVols - pr.NumVols;
201 sprintf(buf, _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
202 if (!get_cmd(ua, buf)) {
206 if (num < 0 || num > max) {
207 bsendmsg(ua, _("The number must be between 0 and %d\n"), max);
214 if (!get_cmd(ua, _("Enter Volume name: "))) {
218 if (!get_cmd(ua, _("Enter base volume name: "))) {
222 /* Don't allow | in Volume name because it is the volume separator character */
223 if (strchr(ua->cmd, '|')) {
224 bsendmsg(ua, _("Illegal character | in a volume name.\n"));
227 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
228 bsendmsg(ua, _("Volume name too long.\n"));
231 if (strlen(ua->cmd) == 0) {
232 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
236 strcpy(name, ua->cmd);
238 strcat(name, "%04d");
241 if (!get_cmd(ua, _("Enter the starting number: "))) {
244 startnum = atoi(ua->cmd);
246 bsendmsg(ua, _("Start number must be greater than zero.\n"));
256 if (store && store->autochanger) {
257 if (!get_cmd(ua, _("Enter slot (0 for none): "))) {
260 slot = atoi(ua->cmd);
263 mr.PoolId = pr.PoolId;
264 strcpy(mr.VolStatus, "Append");
265 mr.Recycle = pr.Recycle;
266 mr.VolRetention = pr.VolRetention;
267 mr.VolUseDuration = pr.VolUseDuration;
268 mr.MaxVolJobs = pr.MaxVolJobs;
269 for (i=startnum; i < num+startnum; i++) {
270 sprintf(mr.VolumeName, name, i);
272 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
273 if (!db_create_media_record(ua->db, &mr)) {
274 bsendmsg(ua, db_strerror(ua->db));
278 first_id = mr.PoolId;
282 Dmsg0(200, "Update pool record.\n");
283 if (db_update_pool_record(ua->db, &pr) != 1) {
284 bsendmsg(ua, db_strerror(ua->db));
287 bsendmsg(ua, _("%d Volumes created in pool %s\n"), num, pr.Name);
293 * Turn auto mount on/off
298 int automountcmd(UAContext *ua, char *cmd)
303 if (!get_cmd(ua, _("Turn on or off? "))) {
311 ua->automount = (strcasecmp(onoff, _("off")) == 0) ? 0 : 1;
319 static int cancelcmd(UAContext *ua, char *cmd)
325 char JobName[MAX_NAME_LENGTH];
331 for (i=1; i<ua->argc; i++) {
332 if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
336 if (!(jcr=get_jcr_by_id(atoi(ua->argv[i])))) {
337 bsendmsg(ua, _("JobId %d is not running.\n"), atoi(ua->argv[i]));
341 } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
345 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
346 bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
352 /* If we still do not have a jcr,
353 * throw up a list and ask the user to select one.
356 /* Count Jobs running */
358 for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
359 if (jcr->JobId == 0) { /* this is us */
360 free_locked_jcr(jcr);
364 free_locked_jcr(jcr);
369 bsendmsg(ua, _("No Jobs running.\n"));
372 start_prompt(ua, _("Select Job:\n"));
374 for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
375 if (jcr->JobId == 0) { /* this is us */
376 free_locked_jcr(jcr);
379 add_prompt(ua, jcr->Job);
380 free_locked_jcr(jcr);
384 if (do_prompt(ua, _("Choose Job to cancel"), JobName) < 0) {
388 if (!get_cmd(ua, _("Confirm cancel (yes/no): "))) {
391 if (strcasecmp(ua->cmd, _("yes")) != 0) {
395 jcr = get_jcr_by_full_name(JobName);
397 bsendmsg(ua, _("Job %s not found.\n"), JobName);
402 switch (jcr->JobStatus) {
404 jcr->JobStatus = JS_Cancelled;
405 bsendmsg(ua, _("JobId %d, Job %s marked to be cancelled.\n"),
406 jcr->JobId, jcr->Job);
412 jcr->JobStatus = JS_Cancelled;
413 /* Cancel File daemon */
414 ua->jcr->client = jcr->client;
415 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
416 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
420 Dmsg0(200, "Connected to file daemon\n");
421 fd = ua->jcr->file_bsock;
422 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
423 while (bnet_recv(fd) >= 0) {
424 bsendmsg(ua, "%s", fd->msg);
426 bnet_sig(fd, BNET_TERMINATE);
428 ua->jcr->file_bsock = NULL;
430 /* Cancel Storage daemon */
431 ua->jcr->store = jcr->store;
432 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
433 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
437 Dmsg0(200, "Connected to storage daemon\n");
438 sd = ua->jcr->store_bsock;
439 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
440 while (bnet_recv(sd) >= 0) {
441 bsendmsg(ua, "%s", sd->msg);
443 bnet_sig(sd, BNET_TERMINATE);
445 ua->jcr->store_bsock = NULL;
454 * Create a pool record from a given Pool resource
455 * Also called from backup.c
456 * Returns: -1 on error
457 * 0 record already exists
461 int create_pool(B_DB *db, POOL *pool)
465 memset(&pr, 0, sizeof(POOL_DBR));
467 strcpy(pr.Name, pool->hdr.name);
469 if (db_get_pool_record(db, &pr)) {
470 return 0; /* exists */
473 strcpy(pr.PoolType, pool->pool_type);
474 pr.MaxVols = pool->max_volumes;
476 pr.UseOnce = pool->use_volume_once;
477 pr.UseCatalog = pool->use_catalog;
478 pr.AcceptAnyVolume = pool->accept_any_volume;
479 pr.Recycle = pool->Recycle;
480 pr.VolRetention = pool->VolRetention;
481 pr.VolUseDuration = pool->VolUseDuration;
482 pr.MaxVolJobs = pool->MaxVolJobs;
483 pr.AutoPrune = pool->AutoPrune;
484 if (pool->label_format) {
485 strcpy(pr.LabelFormat, pool->label_format);
487 strcpy(pr.LabelFormat, "*"); /* none */
490 if (!db_create_pool_record(db, &pr)) {
491 return -1; /* error */
499 * Create a Pool Record in the database.
500 * It is always created from the Resource record.
502 static int createcmd(UAContext *ua, char *cmd)
510 pool = get_pool_resource(ua);
515 switch (create_pool(ua->db, pool)) {
517 bsendmsg(ua, _("Error: Pool %s already exists.\n\
518 Use update to change it.\n"), pool->hdr.name);
522 bsendmsg(ua, db_strerror(ua->db));
528 bsendmsg(ua, _("Pool %s created.\n"), pool->hdr.name);
536 * Update a Pool Record in the database.
537 * It is always updated from the Resource record.
539 * update pool=<pool-name>
540 * updates pool from Pool resource
541 * update media pool=<pool-name> volume=<volume-name>
542 * changes pool info for volume
544 static int updatecmd(UAContext *ua, char *cmd)
546 static char *kw[] = {
556 switch (find_arg_keyword(ua, kw)) {
568 start_prompt(ua, _("Update choice:\n"));
569 add_prompt(ua, _("Volume parameters"));
570 add_prompt(ua, _("Pool from resource"));
571 switch (do_prompt(ua, _("Choose catalog item to update"), NULL)) {
585 * Update a media record -- allows you to change the
586 * Volume status. E.g. if you want Bacula to stop
587 * writing on the volume, set it to anything other
590 static int update_volume(UAContext *ua)
597 if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
601 for (int done=0; !done; ) {
602 if (!db_get_media_record(ua->db, &mr)) {
603 if (mr.MediaId != 0) {
604 bsendmsg(ua, _("Volume record for MediaId %d not found.\n"), mr.MediaId);
606 bsendmsg(ua, _("Volume record for %s not found.\n"), mr.VolumeName);
610 bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
611 start_prompt(ua, _("Parameters to modify:\n"));
612 add_prompt(ua, _("Volume Status"));
613 add_prompt(ua, _("Volume Retention Period"));
614 add_prompt(ua, _("Volume Use Duration"));
615 add_prompt(ua, _("Maximum Volume Jobs"));
616 add_prompt(ua, _("Recycle Flag"));
617 add_prompt(ua, _("Slot"));
618 add_prompt(ua, _("Done"));
619 switch (do_prompt(ua, _("Select parameter to modify"), NULL)) {
620 case 0: /* Volume Status */
621 /* Modify Volume Status */
622 bsendmsg(ua, _("Current value is: %s\n"), mr.VolStatus);
623 start_prompt(ua, _("Possible Values are:\n"));
624 add_prompt(ua, "Append"); /* Better not translate these as */
625 add_prompt(ua, "Archive"); /* They are known in the database code */
626 add_prompt(ua, "Disabled");
627 add_prompt(ua, "Full");
628 add_prompt(ua, "Used");
629 if (strcmp(mr.VolStatus, "Purged") == 0) {
630 add_prompt(ua, "Recycle");
632 add_prompt(ua, "Read-Only");
633 if (do_prompt(ua, _("Choose new Volume Status"), ua->cmd) < 0) {
636 strcpy(mr.VolStatus, ua->cmd);
637 query = get_pool_memory(PM_MESSAGE);
638 Mmsg(&query, "UPDATE Media SET VolStatus='%s' WHERE MediaId=%u",
639 mr.VolStatus, mr.MediaId);
640 if (!db_sql_query(ua->db, query, NULL, NULL)) {
641 bsendmsg(ua, "%s", db_strerror(ua->db));
643 free_pool_memory(query);
645 case 1: /* Retention */
646 bsendmsg(ua, _("Current value is: %s\n"),
647 edit_utime(mr.VolRetention, ed1));
648 if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
651 if (!duration_to_utime(ua->cmd, &mr.VolRetention)) {
652 bsendmsg(ua, _("Invalid retention period specified.\n"));
655 query = get_pool_memory(PM_MESSAGE);
656 Mmsg(&query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%u",
657 edit_uint64(mr.VolRetention, ed1), mr.MediaId);
658 if (!db_sql_query(ua->db, query, NULL, NULL)) {
659 bsendmsg(ua, "%s", db_strerror(ua->db));
661 free_pool_memory(query);
664 case 2: /* Use Duration */
665 bsendmsg(ua, _("Current value is: %s\n"),
666 edit_utime(mr.VolUseDuration, ed1));
667 if (!get_cmd(ua, _("Enter Volume Use Duration: "))) {
670 if (!duration_to_utime(ua->cmd, &mr.VolUseDuration)) {
671 bsendmsg(ua, _("Invalid use duration specified.\n"));
674 query = get_pool_memory(PM_MESSAGE);
675 Mmsg(&query, "UPDATE Media SET VolUseDuration=%s WHERE MediaId=%u",
676 edit_uint64(mr.VolUseDuration, ed1), mr.MediaId);
677 if (!db_sql_query(ua->db, query, NULL, NULL)) {
678 bsendmsg(ua, "%s", db_strerror(ua->db));
680 free_pool_memory(query);
683 case 3: /* Max Jobs */
685 bsendmsg(ua, _("Current value is: %u\n"), mr.MaxVolJobs);
686 if (!get_cmd(ua, _("Enter new Maximum Jobs: "))) {
689 maxjobs = atoi(ua->cmd);
691 bsendmsg(ua, _("Invalid number, it must be 0 or greater\n"));
694 query = get_pool_memory(PM_MESSAGE);
695 Mmsg(&query, "UPDATE Media SET MaxVolJobs=%u WHERE MediaId=%u",
696 maxjobs, mr.MediaId);
697 if (!db_sql_query(ua->db, query, NULL, NULL)) {
698 bsendmsg(ua, "%s", db_strerror(ua->db));
700 bsendmsg(ua, "New value is: %u\n", maxjobs);
702 free_pool_memory(query);
706 case 4: /* Recycle */
708 bsendmsg(ua, _("Current value is: %s\n"),
709 mr.Recycle==1?_("yes"):_("no"));
710 if (!get_cmd(ua, _("Enter new Recycle status: "))) {
713 if (strcasecmp(ua->cmd, _("yes")) == 0) {
715 } else if (strcasecmp(ua->cmd, _("no")) == 0) {
718 bsendmsg(ua, _("Invalid recycle status specified.\n"));
721 query = get_pool_memory(PM_MESSAGE);
722 Mmsg(&query, "UPDATE Media SET Recycle=%d WHERE MediaId=%u",
723 recycle, mr.MediaId);
724 if (!db_sql_query(ua->db, query, NULL, NULL)) {
725 bsendmsg(ua, "%s", db_strerror(ua->db));
727 free_pool_memory(query);
732 bsendmsg(ua, _("Current value is: %d\n"), mr.Slot);
733 if (!get_cmd(ua, _("Enter new Slot: "))) {
736 slot = atoi(ua->cmd);
738 bsendmsg(ua, _("Invalid slot, it must be 0 or greater\n"));
740 } else if (pr.MaxVols > 0 && slot >(int)pr.MaxVols) {
741 bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"),
745 query = get_pool_memory(PM_MESSAGE);
746 Mmsg(&query, "UPDATE Media SET Slot=%d WHERE MediaId=%u",
748 if (!db_sql_query(ua->db, query, NULL, NULL)) {
749 bsendmsg(ua, "%s", db_strerror(ua->db));
751 bsendmsg(ua, "New value is: %d\n", slot);
753 free_pool_memory(query);
756 default: /* Done or error */
757 bsendmsg(ua, "Selection done.\n");
765 * Update pool record -- pull info from current POOL resource
767 static int update_pool(UAContext *ua)
774 pool = get_pool_resource(ua);
779 memset(&pr, 0, sizeof(pr));
780 strcpy(pr.Name, pool->hdr.name);
781 if (!get_pool_dbr(ua, &pr)) {
784 strcpy(pr.PoolType, pool->pool_type);
785 if (pr.MaxVols != pool->max_volumes) {
786 pr.MaxVols = pool->max_volumes;
788 if (pr.MaxVols != 0 && pr.MaxVols < pr.NumVols) {
789 pr.MaxVols = pr.NumVols;
791 pr.UseOnce = pool->use_volume_once;
792 pr.UseCatalog = pool->use_catalog;
793 pr.AcceptAnyVolume = pool->accept_any_volume;
794 pr.VolRetention = pool->VolRetention;
795 pr.VolUseDuration = pool->VolUseDuration;
796 pr.MaxVolJobs = pool->MaxVolJobs;
797 if (pool->label_format) {
798 strcpy(pr.LabelFormat, pool->label_format);
800 strcpy(pr.LabelFormat, "*"); /* none */
802 id = db_update_pool_record(ua->db, &pr);
804 bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
805 id, db_strerror(ua->db));
807 bsendmsg(ua, _("Pool DB record updated from resource.\n"));
812 static void do_storage_setdebug(UAContext *ua, STORE *store, int level)
816 ua->jcr->store = store;
817 /* Try connecting for up to 15 seconds */
818 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"),
819 store->hdr.name, store->address, store->SDport);
820 if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
821 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
824 Dmsg0(120, _("Connected to storage daemon\n"));
825 sd = ua->jcr->store_bsock;
826 bnet_fsend(sd, "setdebug=%d\n", level);
827 if (bnet_recv(sd) >= 0) {
828 bsendmsg(ua, "%s", sd->msg);
830 bnet_sig(sd, BNET_TERMINATE);
832 ua->jcr->store_bsock = NULL;
836 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level)
840 /* Connect to File daemon */
842 ua->jcr->client = client;
843 /* Try to connect for 15 seconds */
844 bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"),
845 client->hdr.name, client->address, client->FDport);
846 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
847 bsendmsg(ua, _("Failed to connect to Client.\n"));
850 Dmsg0(120, "Connected to file daemon\n");
851 fd = ua->jcr->file_bsock;
852 bnet_fsend(fd, "setdebug=%d\n", level);
853 if (bnet_recv(fd) >= 0) {
854 bsendmsg(ua, "%s", fd->msg);
856 bnet_sig(fd, BNET_TERMINATE);
858 ua->jcr->file_bsock = NULL;
864 static void do_all_setdebug(UAContext *ua, int level)
866 STORE *store, **unique_store;
867 CLIENT *client, **unique_client;
873 /* Count Storage items */
876 for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
878 unique_store = (STORE **) malloc(i * sizeof(STORE));
879 /* Find Unique Storage address/port */
880 store = (STORE *)GetNextRes(R_STORAGE, NULL);
882 unique_store[i++] = store;
883 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
885 for (j=0; j<i; j++) {
886 if (strcmp(unique_store[j]->address, store->address) == 0 &&
887 unique_store[j]->SDport == store->SDport) {
893 unique_store[i++] = store;
894 Dmsg2(140, "Stuffing: %s:%d\n", store->address, store->SDport);
899 /* Call each unique Storage daemon */
900 for (j=0; j<i; j++) {
901 do_storage_setdebug(ua, unique_store[j], level);
905 /* Count Client items */
908 for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
910 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
911 /* Find Unique Client address/port */
912 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
914 unique_client[i++] = client;
915 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
917 for (j=0; j<i; j++) {
918 if (strcmp(unique_client[j]->address, client->address) == 0 &&
919 unique_client[j]->FDport == client->FDport) {
925 unique_client[i++] = client;
926 Dmsg2(140, "Stuffing: %s:%d\n", client->address, client->FDport);
931 /* Call each unique File daemon */
932 for (j=0; j<i; j++) {
933 do_client_setdebug(ua, unique_client[j], level);
939 * setdebug level=nn all
941 static int setdebugcmd(UAContext *ua, char *cmd)
951 Dmsg1(120, "setdebug:%s:\n", cmd);
954 for (i=1; i<ua->argc; i++) {
955 if (strcasecmp(ua->argk[i], _("level")) == 0 && ua->argv[i]) {
956 level = atoi(ua->argv[i]);
961 if (!get_cmd(ua, _("Enter new debug level: "))) {
964 level = atoi(ua->cmd);
967 bsendmsg(ua, _("level cannot be negative.\n"));
972 for (i=1; i<ua->argc; i++) {
973 if (strcasecmp(ua->argk[i], _("all")) == 0) {
974 do_all_setdebug(ua, level);
977 if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
978 strcasecmp(ua->argk[i], _("director")) == 0) {
982 if (strcasecmp(ua->argk[i], _("client")) == 0) {
985 client = (CLIENT *) GetResWithName(R_CLIENT, ua->argv[i]);
987 do_client_setdebug(ua, client, level);
991 client = select_client_resource(ua);
993 do_client_setdebug(ua, client, level);
997 store = get_storage_resource(ua, cmd);
999 do_storage_setdebug(ua, store, level);
1005 * We didn't find an appropriate keyword above, so
1008 start_prompt(ua, _("Available daemons are: \n"));
1009 add_prompt(ua, _("Director"));
1010 add_prompt(ua, _("Storage"));
1011 add_prompt(ua, _("Client"));
1012 add_prompt(ua, _("All"));
1013 switch(do_prompt(ua, _("Select daemon type to set debug level"), NULL)) {
1014 case 0: /* Director */
1015 debug_level = level;
1018 store = get_storage_resource(ua, cmd);
1020 do_storage_setdebug(ua, store, level);
1024 client = select_client_resource(ua);
1026 do_client_setdebug(ua, client, level);
1030 do_all_setdebug(ua, level);
1041 * Delete Pool records (should purge Media with it).
1043 * delete pool=<pool-name>
1044 * delete media pool=<pool-name> volume=<name>
1046 static int deletecmd(UAContext *ua, char *cmd)
1048 static char *keywords[] = {
1058 "In general it is not a good idea to delete either a\n"
1059 "Pool or a Volume since they may contain data.\n\n"));
1061 switch (find_arg_keyword(ua, keywords)) {
1071 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1079 bsendmsg(ua, _("Nothing done.\n"));
1086 * Delete media records from database -- dangerous
1088 static int delete_volume(UAContext *ua)
1093 if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
1096 bsendmsg(ua, _("\nThis command will delete volume %s\n"
1097 "and all Jobs saved on that volume from the Catalog\n"),
1100 if (!get_cmd(ua, _("Are you sure you want to delete this Volume? (yes/no): "))) {
1103 if (strcasecmp(ua->cmd, _("yes")) == 0) {
1104 db_delete_media_record(ua->db, &mr);
1110 * Delete a pool record from the database -- dangerous
1112 static int delete_pool(UAContext *ua)
1116 memset(&pr, 0, sizeof(pr));
1118 if (!get_pool_dbr(ua, &pr)) {
1121 if (!get_cmd(ua, _("Are you sure you want to delete this Pool? (yes/no): "))) {
1124 if (strcasecmp(ua->cmd, _("yes")) == 0) {
1125 db_delete_pool_record(ua->db, &pr);
1134 * label storage=xxx volume=vvv
1136 static int labelcmd(UAContext *ua, char *cmd)
1140 char dev_name[MAX_NAME_LENGTH];
1144 int mounted = FALSE;
1147 static char *keyword[] = {
1154 store = get_storage_resource(ua, cmd);
1159 i = find_arg_keyword(ua, keyword);
1160 if (i >=0 && ua->argv[i]) {
1161 strcpy(ua->cmd, ua->argv[i]);
1166 if (!get_cmd(ua, _("Enter new Volume name: "))) {
1170 if (strchr(ua->cmd, '|')) {
1171 bsendmsg(ua, _("Illegal character | in a volume name.\n"));
1174 if (strlen(ua->cmd) >= MAX_NAME_LENGTH) {
1175 bsendmsg(ua, _("Volume name too long.\n"));
1178 if (strlen(ua->cmd) == 0) {
1179 bsendmsg(ua, _("Volume name must be at least one character long.\n"));
1184 memset(&mr, 0, sizeof(mr));
1185 strcpy(mr.VolumeName, ua->cmd);
1186 if (db_get_media_record(ua->db, &mr)) {
1187 bsendmsg(ua, _("Media record for Volume %s already exists.\n"),
1192 /* Do some more checking on slot ****FIXME**** */
1193 if (store->autochanger) {
1194 if (!get_cmd(ua, _("Enter slot (0 for none): "))) {
1197 slot = atoi(ua->cmd);
1199 strcpy(mr.MediaType, store->media_type);
1202 memset(&pr, 0, sizeof(pr));
1203 if (!select_pool_dbr(ua, &pr)) {
1206 mr.PoolId = pr.PoolId;
1207 strcpy(mr.VolStatus, "Append");
1208 mr.Recycle = pr.Recycle;
1209 mr.VolRetention = pr.VolRetention;
1211 ua->jcr->store = store;
1212 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
1213 store->hdr.name, store->address, store->SDport);
1214 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1215 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1218 sd = ua->jcr->store_bsock;
1219 strcpy(dev_name, store->dev_name);
1220 bash_spaces(dev_name);
1221 bash_spaces(mr.VolumeName);
1222 bash_spaces(mr.MediaType);
1223 bash_spaces(pr.Name);
1224 bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d"),
1225 dev_name, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot);
1226 bsendmsg(ua, "Sending label command ...\n");
1227 while (bget_msg(sd, 0) >= 0) {
1228 bsendmsg(ua, "%s", sd->msg);
1229 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
1233 ua->jcr->store_bsock = NULL;
1234 unbash_spaces(dev_name);
1235 unbash_spaces(mr.VolumeName);
1236 unbash_spaces(mr.MediaType);
1237 unbash_spaces(pr.Name);
1239 mr.Recycle = pr.Recycle;
1240 mr.VolRetention = pr.VolRetention;
1241 mr.VolUseDuration = pr.VolUseDuration;
1242 mr.MaxVolJobs = pr.MaxVolJobs;
1243 if (db_create_media_record(ua->db, &mr)) {
1244 bsendmsg(ua, _("Media record for Volume=%s successfully created.\n"),
1246 if (ua->automount) {
1247 bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
1248 bash_spaces(dev_name);
1249 bnet_fsend(sd, "mount %s", dev_name);
1250 unbash_spaces(dev_name);
1251 while (bnet_recv(sd) >= 0) {
1252 bsendmsg(ua, "%s", sd->msg);
1254 * 3001 OK mount. Device=xxx or
1255 * 3001 Mounted Volume vvvv
1257 if (strncmp(sd->msg, "3001 ", 5) == 0) {
1259 /***** ****FIXME***** find job waiting for
1260 ***** mount, and change to waiting for SD
1266 bsendmsg(ua, "%s", db_strerror(ua->db));
1270 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
1272 bnet_sig(sd, BNET_TERMINATE);
1277 static void do_mount_cmd(int mount, UAContext *ua, char *cmd)
1281 char dev_name[MAX_NAME_LENGTH];
1287 Dmsg1(120, "mount: %s\n", ua->UA_sock->msg);
1289 store = get_storage_resource(ua, cmd);
1294 Dmsg2(120, "Found storage, MediaType=%s DevName=%s\n",
1295 store->media_type, store->dev_name);
1297 ua->jcr->store = store;
1298 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1299 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1302 sd = ua->jcr->store_bsock;
1303 strcpy(dev_name, store->dev_name);
1304 bash_spaces(dev_name);
1306 bnet_fsend(sd, "mount %s", dev_name);
1308 bnet_fsend(sd, "unmount %s", dev_name);
1310 while (bnet_recv(sd) >= 0) {
1311 bsendmsg(ua, "%s", sd->msg);
1312 if (strncmp(sd->msg, "3001 OK mount.", 14) == 0) {
1313 /***** ****FIXME**** fix JobStatus */
1316 bnet_sig(sd, BNET_TERMINATE);
1318 ua->jcr->store_bsock = NULL;
1322 * mount [storage | device] <name>
1324 static int mountcmd(UAContext *ua, char *cmd)
1326 do_mount_cmd(1, ua, cmd); /* mount */
1332 * unmount [storage | device] <name>
1334 static int unmountcmd(UAContext *ua, char *cmd)
1336 do_mount_cmd(0, ua, cmd); /* unmount */
1343 * use catalog=<name>
1345 static int usecmd(UAContext *ua, char *cmd)
1347 CAT *oldcatalog, *catalog;
1350 close_db(ua); /* close any previously open db */
1351 oldcatalog = ua->catalog;
1353 if (!(catalog = get_catalog_resource(ua))) {
1354 ua->catalog = oldcatalog;
1356 ua->catalog = catalog;
1359 bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
1360 ua->catalog->hdr.name, ua->catalog->db_name);
1365 int quitcmd(UAContext *ua, char *cmd)
1371 static int helpcmd(UAContext *ua, char *cmd)
1376 bsendmsg(ua, _(" Command Description\n ======= ===========\n"));
1377 for (i=0; i<comsize; i++) {
1378 bsendmsg(ua, _(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1384 static int versioncmd(UAContext *ua, char *cmd)
1386 bsendmsg(ua, "%s Version: " VERSION " (" DATE ")\n", my_name);
1391 /* A bit brain damaged in that if the user has not done
1392 * a "use catalog xxx" command, we simply find the first
1393 * catalog resource and open it.
1395 int open_db(UAContext *ua)
1402 ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1405 bnet_fsend(ua->UA_sock, _("Could not find a Catalog resource\n"));
1408 bnet_fsend(ua->UA_sock, _("Using default Catalog name=%s DB=%s\n"),
1409 ua->catalog->hdr.name, ua->catalog->db_name);
1413 Dmsg0(150, "Open database\n");
1414 ua->db = db_init_database(NULL, ua->catalog->db_name, ua->catalog->db_user,
1415 ua->catalog->db_password);
1416 if (!db_open_database(ua->db)) {
1417 bnet_fsend(ua->UA_sock, _("Could not open DB %s: ERR=%s"),
1418 ua->catalog->db_name, db_strerror(ua->db));
1422 ua->jcr->db = ua->db;
1423 Dmsg1(150, "DB %s opened\n", ua->catalog->db_name);
1427 void close_db(UAContext *ua)
1430 db_close_database(ua->db);