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 int console_msg_pending;
42 extern char my_name[];
44 /* Imported functions */
45 extern int statuscmd(UAContext *ua, char *cmd);
46 extern int listcmd(UAContext *ua, char *cmd);
47 extern int showcmd(UAContext *ua, char *cmd);
48 extern int messagescmd(UAContext *ua, char *cmd);
49 extern int autodisplaycmd(UAContext *ua, char *cmd);
50 extern int sqlquerycmd(UAContext *ua, char *cmd);
51 extern int querycmd(UAContext *ua, char *cmd);
52 extern int runcmd(UAContext *ua, char *cmd);
53 extern int retentioncmd(UAContext *ua, char *cmd);
54 extern int prunecmd(UAContext *ua, char *cmd);
55 extern int purgecmd(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_("prune"), prunecmd, _("prune expired records from catalog")},
87 { N_("purge"), purgecmd, _("purge records from catalog")},
88 { N_("run"), runcmd, _("run <job-name>")},
89 { N_("setdebug"), setdebugcmd, _("sets debug level")},
90 { N_("show"), showcmd, _("show (resource records) [jobs | pools | ... | all]")},
91 { N_("sqlquery"), sqlquerycmd, _("use SQL to query catalog")},
92 { N_("status"), statuscmd, _("status [storage | client]=<name>")},
93 { N_("unmount"), unmountcmd, _("unmount <storage-name>")},
94 { N_("update"), updatecmd, _("update Volume or Pool")},
95 { N_("use"), usecmd, _("use catalog xxx")},
96 { N_("version"), versioncmd, _("print Director version")},
97 { N_("quit"), quitcmd, _("quit")},
98 { N_("query"), querycmd, _("query catalog")},
99 { N_("exit"), quitcmd, _("exit = quit")},
101 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
104 * Execute a command from the UA
106 int do_a_command(UAContext *ua, char *cmd)
115 Dmsg1(20, "Command: %s\n", ua->UA_sock->msg);
120 len = strlen(ua->argk[0]);
121 for (i=0; i<comsize; i++) /* search for command */
122 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
123 stat = (*commands[i].func)(ua, cmd); /* go execute command */
128 strcat(ua->UA_sock->msg, _(": is an illegal command\n"));
129 ua->UA_sock->msglen = strlen(ua->UA_sock->msg);
130 bnet_send(ua->UA_sock);
137 * Add Volumes to an existing Pool
140 static int addcmd(UAContext *ua, char *cmd)
144 int num, i, max, startnum;
146 char name[MAX_NAME_LENGTH];
149 "You probably don't want to be using this command since it\n"
150 "creates database records without labeling the Volumes.\n"
151 "You probably want to use the label command.\n\n"));
157 memset(&pr, 0, sizeof(pr));
158 memset(&mr, 0, sizeof(mr));
160 if (!get_pool_dbr(ua, &pr)) {
164 Dmsg4(20, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
165 pr.MaxVols, pr.PoolType);
167 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
168 bsendmsg(ua, _("Pool already has maximum volumes = %d\n"), pr.MaxVols);
170 if (!get_cmd(ua, _("Enter new maximum (zero for unlimited): "))) {
173 pr.MaxVols = atoi(ua->cmd);
174 if (pr.MaxVols < 0) {
175 bsendmsg(ua, _("Max vols must be zero or greater.\n"));
182 if (!get_media_type(ua, mr.MediaType)) {
186 if (pr.MaxVols == 0) {
189 max = pr.MaxVols - pr.NumVols;
193 sprintf(buf, _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
194 if (!get_cmd(ua, buf)) {
198 if (num < 0 || num > max) {
199 bsendmsg(ua, _("The number must be between 0 and %d\n"), max);
206 if (!get_cmd(ua, _("Enter Volume name: "))) {
210 if (!get_cmd(ua, _("Enter base volume name: "))) {
214 if (strchr(ua->cmd, '|')) {
215 bsendmsg(ua, _("Illegal character | in a volume name.\n"));
218 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
219 bsendmsg(ua, _("Volume name too long.\n"));
223 strcpy(name, ua->cmd);
225 strcat(name, "%04d");
228 if (!get_cmd(ua, _("Enter the starting number: "))) {
231 startnum = atoi(ua->cmd);
233 bsendmsg(ua, _("Start number must be greater than zero.\n"));
243 mr.PoolId = pr.PoolId;
244 strcpy(mr.VolStatus, "Append");
245 mr.Recycle = pr.Recycle;
246 mr.VolRetention = pr.VolRetention;
247 for (i=startnum; i < num+startnum; i++) {
248 sprintf(mr.VolumeName, name, i);
249 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
250 if (!db_create_media_record(ua->db, &mr)) {
251 bsendmsg(ua, db_strerror(ua->db));
255 first_id = mr.PoolId;
259 Dmsg0(200, "Update pool record.\n");
260 if (db_update_pool_record(ua->db, &pr) != 1) {
261 bsendmsg(ua, db_strerror(ua->db));
264 bsendmsg(ua, _("%d Volumes created in pool %s\n"), num, pr.Name);
270 * Turn auto mount on/off
275 int automountcmd(UAContext *ua, char *cmd)
280 if (!get_cmd(ua, _("Turn on or off? "))) {
288 ua->automount = (strcasecmp(onoff, _("off")) == 0) ? 0 : 1;
296 static int cancelcmd(UAContext *ua, char *cmd)
302 char JobName[MAX_NAME_LENGTH];
308 for (i=1; i<ua->argc; i++) {
309 if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
313 if (!(jcr=get_jcr_by_id(atoi(ua->argv[i])))) {
314 bsendmsg(ua, _("JobId %d is not running.\n"), atoi(ua->argv[i]));
318 } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
322 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
323 bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
329 /* If we still do not have a jcr,
330 * throw up a list and ask the user to select one.
333 /* Count Jobs running */
335 for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
336 if (jcr->JobId == 0) { /* this is us */
337 free_locked_jcr(jcr);
341 free_locked_jcr(jcr);
346 bsendmsg(ua, _("No Jobs running.\n"));
349 start_prompt(ua, _("Select Job:\n"));
351 for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
352 if (jcr->JobId == 0) { /* this is us */
353 free_locked_jcr(jcr);
356 add_prompt(ua, jcr->Job);
357 free_locked_jcr(jcr);
361 if (do_prompt(ua, _("Choose Job to cancel"), JobName) < 0) {
365 if (!get_cmd(ua, _("Confirm cancel (yes/no): "))) {
368 if (strcasecmp(ua->cmd, _("yes")) != 0) {
372 jcr = get_jcr_by_full_name(JobName);
374 bsendmsg(ua, _("Job %s not found.\n"), JobName);
379 switch (jcr->JobStatus) {
381 jcr->JobStatus = JS_Cancelled;
382 bsendmsg(ua, _("JobId %d, Job %s marked to be cancelled.\n"),
383 jcr->JobId, jcr->Job);
389 jcr->JobStatus = JS_Cancelled;
390 /* Cancel File daemon */
391 ua->jcr->client = jcr->client;
392 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
393 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
397 Dmsg0(200, "Connected to file daemon\n");
398 fd = ua->jcr->file_bsock;
399 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
400 while (bnet_recv(fd) > 0) {
401 bsendmsg(ua, "%s", fd->msg);
403 bnet_sig(fd, BNET_TERMINATE);
405 ua->jcr->file_bsock = NULL;
407 /* Cancel Storage daemon */
408 ua->jcr->store = jcr->store;
409 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
410 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
414 Dmsg0(200, "Connected to storage daemon\n");
415 sd = ua->jcr->store_bsock;
416 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
417 while (bnet_recv(sd) > 0) {
418 bsendmsg(ua, "%s", sd->msg);
420 bnet_sig(sd, BNET_TERMINATE);
422 ua->jcr->store_bsock = NULL;
431 * Create a pool record from a given Pool resource
432 * Also called from backup.c
433 * Returns: -1 on error
434 * 0 record already exists
438 int create_pool(B_DB *db, POOL *pool)
442 memset(&pr, 0, sizeof(POOL_DBR));
444 strcpy(pr.Name, pool->hdr.name);
446 if (db_get_pool_record(db, &pr)) {
447 return 0; /* exists */
450 strcpy(pr.PoolType, pool->pool_type);
451 pr.MaxVols = pool->max_volumes;
453 pr.UseOnce = pool->use_volume_once;
454 pr.UseCatalog = pool->use_catalog;
455 pr.AcceptAnyVolume = pool->accept_any_volume;
456 pr.Recycle = pool->Recycle;
457 pr.VolRetention = pool->VolRetention;
458 pr.AutoPrune = pool->AutoPrune;
459 if (pool->label_format) {
460 strcpy(pr.LabelFormat, pool->label_format);
462 strcpy(pr.LabelFormat, "*"); /* none */
465 if (!db_create_pool_record(db, &pr)) {
466 return -1; /* error */
474 * Create a Pool Record in the database.
475 * It is always created from the Resource record.
477 static int createcmd(UAContext *ua, char *cmd)
485 pool = get_pool_resource(ua);
490 switch (create_pool(ua->db, pool)) {
492 bsendmsg(ua, _("Error: Pool %s already exists.\n\
493 Use update to change it.\n"), pool->hdr.name);
497 bsendmsg(ua, db_strerror(ua->db));
503 bsendmsg(ua, _("Pool %s created.\n"), pool->hdr.name);
511 * Update a Pool Record in the database.
512 * It is always updated from the Resource record.
514 * update pool=<pool-name>
515 * updates pool from Pool resource
516 * update media pool=<pool-name> volume=<volume-name>
517 * changes pool info for volume
519 static int updatecmd(UAContext *ua, char *cmd)
521 static char *kw[] = {
531 switch (find_arg_keyword(ua, kw)) {
543 start_prompt(ua, _("Update choice:\n"));
544 add_prompt(ua, _("Pool from resource"));
545 add_prompt(ua, _("Volume parameters"));
546 switch (do_prompt(ua, _("Choose catalog item to update"), NULL)) {
560 * Update a media record -- allows you to change the
561 * Volume status. E.g. if you want Bacula to stop
562 * writing on the volume, set it to anything other
565 static int update_volume(UAContext *ua)
570 static char *kw[] = {
576 memset(&pr, 0, sizeof(pr));
577 memset(&mr, 0, sizeof(mr));
578 if (!get_pool_dbr(ua, &pr)) {
581 mr.PoolId = pr.PoolId;
582 mr.VolumeName[0] = 0;
584 i = find_arg_keyword(ua, kw);
585 if (i == 0 && ua->argv[i]) {
586 strcpy(mr.VolumeName, ua->argv[i]);
588 if (mr.VolumeName[0] == 0) {
589 db_list_media_records(ua->db, &mr, prtit, ua);
590 if (!get_cmd(ua, _("Enter Volume name to update: "))) {
593 strcpy(mr.VolumeName, ua->cmd);
596 for (int done=0; !done; ) {
598 if (!db_get_media_record(ua->db, &mr)) {
599 bsendmsg(ua, _("Volume record for %s not found.\n"), mr.VolumeName);
602 start_prompt(ua, _("Parameters to modify:\n"));
603 add_prompt(ua, _("Volume Status"));
604 add_prompt(ua, _("Volume Retention Period"));
605 add_prompt(ua, _("Recycle Flag"));
606 add_prompt(ua, _("Slot"));
607 add_prompt(ua, _("Done"));
608 switch (do_prompt(ua, _("Select paramter to modify"), NULL)) {
609 case 0: /* Volume Status */
610 /* Modify Volume Status */
611 bsendmsg(ua, _("Current value is: %s\n"), mr.VolStatus);
612 start_prompt(ua, _("Possible Values are:\n"));
613 add_prompt(ua, "Append");
614 add_prompt(ua, "Archive");
615 add_prompt(ua, "Disabled");
616 add_prompt(ua, "Full");
617 if (strcmp(mr.VolStatus, "Purged") == 0) {
618 add_prompt(ua, "Recycle");
620 add_prompt(ua, "Read-Only");
621 if (do_prompt(ua, _("Choose new Volume Status"), ua->cmd) < 0) {
624 strcpy(mr.VolStatus, ua->cmd);
625 query = get_pool_memory(PM_MESSAGE);
626 Mmsg(&query, "UPDATE Media SET VolStatus=\"%s\" WHERE MediaId=%d",
627 mr.VolStatus, mr.MediaId);
628 if (!db_sql_query(ua->db, query, NULL, NULL)) {
629 bsendmsg(ua, "%s", db_strerror(ua->db));
631 free_pool_memory(query);
633 case 1: /* Retention */
634 bsendmsg(ua, _("Current value is: %s\n"),
635 edit_btime(mr.VolRetention, ed1));
636 if (!get_cmd(ua, _("Enter Volume Retention period: "))) {
639 if (!string_to_btime(ua->cmd, &mr.VolRetention)) {
640 bsendmsg(ua, _("Invalid retention period specified.\n"));
643 query = get_pool_memory(PM_MESSAGE);
644 Mmsg(&query, "UPDATE Media SET VolRetention=%s WHERE MediaId=%d",
645 edit_uint64(mr.VolRetention, ed1), mr.MediaId);
646 if (!db_sql_query(ua->db, query, NULL, NULL)) {
647 bsendmsg(ua, "%s", db_strerror(ua->db));
649 free_pool_memory(query);
651 case 2: /* Recycle */
653 bsendmsg(ua, _("Current value is: %s\n"),
654 mr.Recycle==1?_("yes"):_("no"));
655 if (!get_cmd(ua, _("Enter new Recycle status: "))) {
658 if (strcasecmp(ua->cmd, _("yes")) == 0) {
660 } else if (strcasecmp(ua->cmd, _("no")) == 0) {
663 bsendmsg(ua, _("Invalid recycle status specified.\n"));
666 query = get_pool_memory(PM_MESSAGE);
667 Mmsg(&query, "UPDATE Media SET Recycle=%d WHERE MediaId=%d",
668 recycle, mr.MediaId);
669 if (!db_sql_query(ua->db, query, NULL, NULL)) {
670 bsendmsg(ua, "%s", db_strerror(ua->db));
672 free_pool_memory(query);
677 bsendmsg(ua, _("Current value is: %d\n"), mr.Slot);
678 if (!get_cmd(ua, _("Enter new Slot: "))) {
681 slot = atoi(ua->cmd);
683 bsendmsg(ua, _("Invalid slot, it must be 0 or greater\n"));
685 } else if (pr.MaxVols > 0 && slot >(int)pr.MaxVols) {
686 bsendmsg(ua, _("Invalid slot, it must be between 0 and %d\n"),
690 query = get_pool_memory(PM_MESSAGE);
691 Mmsg(&query, "UPDATE Media SET Slot=%d WHERE MediaId=%d",
693 if (!db_sql_query(ua->db, query, NULL, NULL)) {
694 bsendmsg(ua, "%s", db_strerror(ua->db));
696 bsendmsg(ua, "New value is: %d\n", slot);
698 free_pool_memory(query);
702 default: /* Done or error */
703 bsendmsg(ua, "Selection done.\n");
711 * Update pool record -- pull info from current POOL resource
713 static int update_pool(UAContext *ua)
720 pool = get_pool_resource(ua);
725 memset(&pr, 0, sizeof(pr));
726 strcpy(pr.Name, pool->hdr.name);
727 if (!get_pool_dbr(ua, &pr)) {
730 strcpy(pr.PoolType, pool->pool_type);
731 if (pr.MaxVols != (uint32_t) (pool->max_volumes)) {
732 pr.MaxVols = pool->max_volumes;
734 if (pr.MaxVols != 0 && pr.MaxVols < pr.NumVols) {
735 pr.MaxVols = pr.NumVols;
737 pr.UseOnce = pool->use_volume_once;
738 pr.UseCatalog = pool->use_catalog;
739 pr.AcceptAnyVolume = pool->accept_any_volume;
740 if (pool->label_format) {
741 strcpy(pr.LabelFormat, pool->label_format);
743 strcpy(pr.LabelFormat, "*"); /* none */
745 id = db_update_pool_record(ua->db, &pr);
747 bsendmsg(ua, _("db_update_pool_record returned %d. ERR=%s\n"),
748 id, db_strerror(ua->db));
750 bsendmsg(ua, _("Pool DB record updated from resource.\n"));
755 static void do_storage_setdebug(UAContext *ua, STORE *store, int level)
759 ua->jcr->store = store;
760 /* Try connecting for up to 15 seconds */
761 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"),
762 store->hdr.name, store->address, store->SDport);
763 if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
764 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
767 Dmsg0(20, _("Connected to storage daemon\n"));
768 sd = ua->jcr->store_bsock;
769 bnet_fsend(sd, "setdebug=%d\n", level);
770 if (bnet_recv(sd) > 0) {
771 bsendmsg(ua, "%s", sd->msg);
773 bnet_sig(sd, BNET_TERMINATE);
775 ua->jcr->store_bsock = NULL;
779 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level)
783 /* Connect to File daemon */
785 ua->jcr->client = client;
786 /* Try to connect for 15 seconds */
787 bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"),
788 client->hdr.name, client->address, client->FDport);
789 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
790 bsendmsg(ua, _("Failed to connect to Client.\n"));
793 Dmsg0(20, "Connected to file daemon\n");
794 fd = ua->jcr->file_bsock;
795 bnet_fsend(fd, "setdebug=%d\n", level);
796 if (bnet_recv(fd) > 0) {
797 bsendmsg(ua, "%s", fd->msg);
799 bnet_sig(fd, BNET_TERMINATE);
801 ua->jcr->file_bsock = NULL;
807 static void do_all_setdebug(UAContext *ua, int level)
809 STORE *store, **unique_store;
810 CLIENT *client, **unique_client;
816 /* Count Storage items */
819 for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
821 unique_store = (STORE **) malloc(i * sizeof(STORE));
822 /* Find Unique Storage address/port */
823 store = (STORE *)GetNextRes(R_STORAGE, NULL);
825 unique_store[i++] = store;
826 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
828 for (j=0; j<i; j++) {
829 if (strcmp(unique_store[j]->address, store->address) == 0 &&
830 unique_store[j]->SDport == store->SDport) {
836 unique_store[i++] = store;
837 Dmsg2(40, "Stuffing: %s:%d\n", store->address, store->SDport);
842 /* Call each unique Storage daemon */
843 for (j=0; j<i; j++) {
844 do_storage_setdebug(ua, unique_store[j], level);
848 /* Count Client items */
851 for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
853 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
854 /* Find Unique Client address/port */
855 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
857 unique_client[i++] = client;
858 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
860 for (j=0; j<i; j++) {
861 if (strcmp(unique_client[j]->address, client->address) == 0 &&
862 unique_client[j]->FDport == client->FDport) {
868 unique_client[i++] = client;
869 Dmsg2(40, "Stuffing: %s:%d\n", client->address, client->FDport);
874 /* Call each unique File daemon */
875 for (j=0; j<i; j++) {
876 do_client_setdebug(ua, unique_client[j], level);
882 * setdebug level=nn all
884 static int setdebugcmd(UAContext *ua, char *cmd)
894 Dmsg1(20, "setdebug:%s:\n", cmd);
897 for (i=1; i<ua->argc; i++) {
898 if (strcasecmp(ua->argk[i], _("level")) == 0 && ua->argv[i]) {
899 level = atoi(ua->argv[i]);
904 if (!get_cmd(ua, _("Enter new debug level: "))) {
907 level = atoi(ua->cmd);
910 bsendmsg(ua, _("level cannot be negative.\n"));
915 for (i=1; i<ua->argc; i++) {
916 if (strcasecmp(ua->argk[i], _("all")) == 0) {
917 do_all_setdebug(ua, level);
920 if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
921 strcasecmp(ua->argk[i], _("director")) == 0) {
925 if (strcasecmp(ua->argk[i], _("client")) == 0) {
928 client = (CLIENT *) GetResWithName(R_CLIENT, ua->argv[i]);
930 do_client_setdebug(ua, client, level);
934 client = select_client_resource(ua);
936 do_client_setdebug(ua, client, level);
940 store = get_storage_resource(ua, cmd);
942 do_storage_setdebug(ua, store, level);
948 * We didn't find an appropriate keyword above, so
951 start_prompt(ua, _("Available daemons are: \n"));
952 add_prompt(ua, _("Director"));
953 add_prompt(ua, _("Storage"));
954 add_prompt(ua, _("Client"));
955 add_prompt(ua, _("All"));
956 switch(do_prompt(ua, _("Select daemon type to set debug level"), NULL)) {
957 case 0: /* Director */
961 store = get_storage_resource(ua, cmd);
963 do_storage_setdebug(ua, store, level);
967 client = select_client_resource(ua);
969 do_client_setdebug(ua, client, level);
973 do_all_setdebug(ua, level);
984 * Delete Pool records (should purge Media with it).
986 * delete pool=<pool-name>
987 * delete media pool=<pool-name> volume=<name>
989 static int deletecmd(UAContext *ua, char *cmd)
991 static char *keywords[] = {
1001 "In general it is not a good idea to delete either a\n"
1002 "Pool or Media since in both cases, you may delete Media\n"
1003 "that contain data.\n\n"));
1005 switch (find_arg_keyword(ua, keywords)) {
1015 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
1023 bsendmsg(ua, _("Nothing done.\n"));
1030 * Delete media records from database -- dangerous
1032 static int delete_volume(UAContext *ua)
1037 if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
1040 bsendmsg(ua, _("\nThis command will delete volume %s\n"
1041 "and all Jobs saved on that volume from the Catalog\n"),
1044 if (!get_cmd(ua, _("If you want to continue enter pretty please: "))) {
1047 if (strcmp(ua->cmd, _("pretty please")) == 0) {
1048 db_delete_media_record(ua->db, &mr);
1054 * Delete a pool record from the database -- dangerous
1056 static int delete_pool(UAContext *ua)
1060 memset(&pr, 0, sizeof(pr));
1062 if (!get_pool_dbr(ua, &pr)) {
1065 if (!get_cmd(ua, _("If you want to continue enter pretty please: "))) {
1068 if (strcmp(ua->cmd, _("pretty please")) == 0) {
1069 db_delete_pool_record(ua->db, &pr);
1078 * label storage=xxx volume=vvv
1080 static int labelcmd(UAContext *ua, char *cmd)
1084 char dev_name[MAX_NAME_LENGTH];
1088 int mounted = FALSE;
1090 static char *keyword[] = {
1097 store = get_storage_resource(ua, cmd);
1102 i = find_arg_keyword(ua, keyword);
1103 if (i >=0 && ua->argv[i]) {
1104 strcpy(ua->cmd, ua->argv[i]);
1109 if (!get_cmd(ua, _("Enter new Volume name: "))) {
1113 if (strchr(ua->cmd, '|')) {
1114 bsendmsg(ua, _("Illegal character | in a volume name.\n"));
1117 if (strlen(ua->cmd) >= MAX_NAME_LENGTH) {
1118 bsendmsg(ua, _("Volume name too long.\n"));
1122 memset(&mr, 0, sizeof(mr));
1123 strcpy(mr.VolumeName, ua->cmd);
1124 if (db_get_media_record(ua->db, &mr)) {
1125 bsendmsg(ua, _("Media record for Volume %s already exists.\n"),
1129 strcpy(mr.MediaType, store->media_type);
1131 memset(&pr, 0, sizeof(pr));
1132 if (!select_pool_dbr(ua, &pr)) {
1135 mr.PoolId = pr.PoolId;
1136 strcpy(mr.VolStatus, "Append");
1137 mr.Recycle = pr.Recycle;
1138 mr.VolRetention = pr.VolRetention;
1140 ua->jcr->store = store;
1141 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
1142 store->hdr.name, store->address, store->SDport);
1143 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1144 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1147 sd = ua->jcr->store_bsock;
1148 strcpy(dev_name, store->dev_name);
1149 bash_spaces(dev_name);
1150 bash_spaces(mr.VolumeName);
1151 bash_spaces(mr.MediaType);
1152 bash_spaces(pr.Name);
1153 bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s"),
1154 dev_name, mr.VolumeName, pr.Name, mr.MediaType);
1155 bsendmsg(ua, "Sending label command ...\n");
1156 while (bget_msg(sd, 0) > 0) {
1157 bsendmsg(ua, "%s", sd->msg);
1158 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
1162 ua->jcr->store_bsock = NULL;
1163 unbash_spaces(dev_name);
1164 unbash_spaces(mr.VolumeName);
1165 unbash_spaces(mr.MediaType);
1166 unbash_spaces(pr.Name);
1168 if (db_create_media_record(ua->db, &mr)) {
1169 bsendmsg(ua, _("Media record for Volume=%s successfully created.\n"),
1171 if (ua->automount) {
1172 bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
1173 bash_spaces(dev_name);
1174 bnet_fsend(sd, "mount %s", dev_name);
1175 unbash_spaces(dev_name);
1176 while (bnet_recv(sd) > 0) {
1177 bsendmsg(ua, "%s", sd->msg);
1179 * 3001 OK mount. Device=xxx or
1180 * 3001 Mounted Volume vvvv
1182 if (strncmp(sd->msg, "3001 ", 5) == 0) {
1184 /***** ****FIXME***** find job waiting for
1185 ***** mount, and change to waiting for SD
1191 bsendmsg(ua, "%s", db_strerror(ua->db));
1195 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
1197 bnet_sig(sd, BNET_TERMINATE);
1202 static void do_mount_cmd(int mount, UAContext *ua, char *cmd)
1206 char dev_name[MAX_NAME_LENGTH];
1212 Dmsg1(20, "mount: %s\n", ua->UA_sock->msg);
1214 store = get_storage_resource(ua, cmd);
1219 Dmsg2(20, "Found storage, MediaType=%s DevName=%s\n",
1220 store->media_type, store->dev_name);
1222 ua->jcr->store = store;
1223 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1224 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1227 sd = ua->jcr->store_bsock;
1228 strcpy(dev_name, store->dev_name);
1229 bash_spaces(dev_name);
1231 bnet_fsend(sd, "mount %s", dev_name);
1233 bnet_fsend(sd, "unmount %s", dev_name);
1235 while (bnet_recv(sd) > 0) {
1236 bsendmsg(ua, "%s", sd->msg);
1237 if (strncmp(sd->msg, "3001 OK mount.", 14) == 0) {
1238 /***** ****FIXME**** fix JobStatus */
1241 bnet_sig(sd, BNET_TERMINATE);
1243 ua->jcr->store_bsock = NULL;
1247 * mount [storage | device] <name>
1249 static int mountcmd(UAContext *ua, char *cmd)
1251 do_mount_cmd(1, ua, cmd); /* mount */
1257 * unmount [storage | device] <name>
1259 static int unmountcmd(UAContext *ua, char *cmd)
1261 do_mount_cmd(0, ua, cmd); /* unmount */
1268 * use catalog=<name>
1270 static int usecmd(UAContext *ua, char *cmd)
1272 CAT *oldcatalog, *catalog;
1275 close_db(ua); /* close any previously open db */
1276 oldcatalog = ua->catalog;
1278 if (!(catalog = get_catalog_resource(ua))) {
1279 ua->catalog = oldcatalog;
1281 ua->catalog = catalog;
1284 bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
1285 ua->catalog->hdr.name, ua->catalog->db_name);
1290 int quitcmd(UAContext *ua, char *cmd)
1296 static int helpcmd(UAContext *ua, char *cmd)
1301 bnet_fsend(ua->UA_sock, _(" Command Description\n ======= ===========\n"));
1302 for (i=0; i<comsize; i++) {
1303 bnet_fsend(ua->UA_sock, _(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1305 bnet_fsend(ua->UA_sock, "\n");
1309 static int versioncmd(UAContext *ua, char *cmd)
1311 bsendmsg(ua, "%s Version: " VERSION " (" DATE ")\n", my_name);
1316 /* A bit brain damaged in that if the user has not done
1317 * a "use catalog xxx" command, we simply find the first
1318 * catalog resource and open it.
1320 int open_db(UAContext *ua)
1327 ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1330 bnet_fsend(ua->UA_sock, _("Could not find a Catalog resource\n"));
1333 bnet_fsend(ua->UA_sock, _("Using default Catalog name=%s DB=%s\n"),
1334 ua->catalog->hdr.name, ua->catalog->db_name);
1338 Dmsg0(50, "Open database\n");
1339 ua->db = db_init_database(ua->catalog->db_name, ua->catalog->db_user,
1340 ua->catalog->db_password);
1341 if (!db_open_database(ua->db)) {
1342 bnet_fsend(ua->UA_sock, _("Could not open DB %s: ERR=%s"),
1343 ua->catalog->db_name, db_strerror(ua->db));
1347 ua->jcr->db = ua->db;
1348 Dmsg1(50, "DB %s opened\n", ua->catalog->db_name);
1352 void close_db(UAContext *ua)
1355 db_close_database(ua->db);