3 * Bacula Director -- User Agent Commands
5 * Kern Sibbald, September MM
9 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
11 This program is free software; you can redistribute it and/or
12 modify it under the terms of the GNU General Public License as
13 published by the Free Software Foundation; either version 2 of
14 the License, or (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 General Public License for more details.
21 You should have received a copy of the GNU General Public
22 License along with this program; if not, write to the Free
23 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
32 /* Imported subroutines */
33 extern void run_job(JCR *jcr);
35 /* Imported variables */
38 extern struct s_res resources[];
39 extern int console_msg_pending;
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);
56 /* Forward referenced functions */
57 static int addcmd(UAContext *ua, char *cmd), createcmd(UAContext *ua, char *cmd), cancelcmd(UAContext *ua, char *cmd);
58 static int setdebugcmd(UAContext *ua, char *cmd);
59 static int helpcmd(UAContext *ua, char *cmd);
60 static int deletecmd(UAContext *ua, char *cmd);
61 static int usecmd(UAContext *ua, char *cmd), unmountcmd(UAContext *ua, char *cmd);
62 static int labelcmd(UAContext *ua, char *cmd), mountcmd(UAContext *ua, char *cmd), updatecmd(UAContext *ua, char *cmd);
63 static int versioncmd(UAContext *ua, char *cmd), automountcmd(UAContext *ua, char *cmd);
64 static int update_media(UAContext *ua);
65 static int update_pool(UAContext *ua);
66 static int delete_media(UAContext *ua);
67 static int delete_pool(UAContext *ua);
69 int quitcmd(UAContext *ua, char *cmd);
72 struct cmdstruct { char *key; int (*func)(UAContext *ua, char *cmd); char *help; };
73 static struct cmdstruct commands[] = {
74 { N_("add"), addcmd, _("add media to a pool")},
75 { N_("autodisplay"), autodisplaycmd, _("autodisplay [on/off] -- console messages")},
76 { N_("automount"), automountcmd, _("automount [on/off] -- after label")},
77 { N_("cancel"), cancelcmd, _("cancel job=nnn -- cancel a job")},
78 { N_("create"), createcmd, _("create DB Pool from resource")},
79 { N_("delete"), deletecmd, _("delete [pool=<pool-name> | media volume=<volume-name>]")},
80 { N_("help"), helpcmd, _("print this command")},
81 { N_("label"), labelcmd, _("label a tape")},
82 { N_("list"), listcmd, _("list [pools | jobs | jobtotals | media <pool> | files job=<nn>]; from catalog")},
83 { N_("messages"), messagescmd, _("messages")},
84 { N_("mount"), mountcmd, _("mount <storage-name>")},
85 { N_("prune"), prunecmd, _("prune expired records from catalog")},
86 { N_("purge"), purgecmd, _("purge records from catalog")},
87 { N_("run"), runcmd, _("run <job-name>")},
88 { N_("setdebug"), setdebugcmd, _("sets debug level")},
89 { N_("show"), showcmd, _("show (resource records) [jobs | pools | ... | all]")},
90 { N_("sqlquery"), sqlquerycmd, _("use SQL to query catalog")},
91 { N_("status"), statuscmd, _("status [storage | client]=<name>")},
92 { N_("unmount"), unmountcmd, _("unmount <storage-name>")},
93 { N_("update"), updatecmd, _("update DB Pool from resource")},
94 { N_("use"), usecmd, _("use catalog xxx")},
95 { N_("version"), versioncmd, _("print Director version")},
96 { N_("quit"), quitcmd, _("quit")},
97 { N_("query"), querycmd, _("query catalog")},
98 { N_("exit"), quitcmd, _("exit = quit")},
100 #define comsize (sizeof(commands)/sizeof(struct cmdstruct))
103 * Execute a command from the UA
105 int do_a_command(UAContext *ua, char *cmd)
114 Dmsg1(20, "Command: %s\n", ua->UA_sock->msg);
119 len = strlen(ua->argk[0]);
120 for (i=0; i<comsize; i++) /* search for command */
121 if (strncasecmp(ua->argk[0], _(commands[i].key), len) == 0) {
122 stat = (*commands[i].func)(ua, cmd); /* go execute command */
127 strcat(ua->UA_sock->msg, _(": is an illegal command\n"));
128 ua->UA_sock->msglen = strlen(ua->UA_sock->msg);
129 bnet_send(ua->UA_sock);
136 * Add Volumes to an existing Pool
139 static int addcmd(UAContext *ua, char *cmd)
143 int num, i, max, startnum;
145 char name[MAX_NAME_LENGTH];
148 "You probably don't want to be using this command since it\n"
149 "creates database records without labeling the Volumes.\n"
150 "You probably want to use the label command.\n\n"));
156 memset(&pr, 0, sizeof(pr));
157 memset(&mr, 0, sizeof(mr));
159 if (!get_pool_dbr(ua, &pr)) {
163 Dmsg4(20, "id=%d Num=%d Max=%d type=%s\n", pr.PoolId, pr.NumVols,
164 pr.MaxVols, pr.PoolType);
166 while (pr.MaxVols > 0 && pr.NumVols >= pr.MaxVols) {
167 bsendmsg(ua, _("Pool already has maximum volumes = %d\n"), pr.MaxVols);
169 if (!get_cmd(ua, _("Enter new maximum (zero for unlimited): "))) {
172 pr.MaxVols = atoi(ua->cmd);
173 if (pr.MaxVols < 0) {
174 bsendmsg(ua, _("Max vols must be zero or greater.\n"));
181 if (!get_media_type(ua, mr.MediaType)) {
185 if (pr.MaxVols == 0) {
188 max = pr.MaxVols - pr.NumVols;
192 sprintf(buf, _("Enter number of Volumes to create. 0=>fixed name. Max=%d: "), max);
193 if (!get_cmd(ua, buf)) {
197 if (num < 0 || num > max) {
198 bsendmsg(ua, _("The number must be between 0 and %d\n"), max);
205 if (!get_cmd(ua, _("Enter Volume name: "))) {
209 if (!get_cmd(ua, _("Enter base volume name: "))) {
213 if (strchr(ua->cmd, '|')) {
214 bsendmsg(ua, _("Illegal character | in a volume name.\n"));
217 if (strlen(ua->cmd) >= MAX_NAME_LENGTH-10) {
218 bsendmsg(ua, _("Volume name too long.\n"));
222 strcpy(name, ua->cmd);
224 strcat(name, "%04d");
227 if (!get_cmd(ua, _("Enter the starting number: "))) {
230 startnum = atoi(ua->cmd);
232 bsendmsg(ua, _("Start number must be greater than zero.\n"));
242 mr.PoolId = pr.PoolId;
243 strcpy(mr.VolStatus, "Append");
244 mr.Recycle = pr.Recycle;
245 mr.VolRetention = pr.VolumeRetention;
246 for (i=startnum; i < num+startnum; i++) {
247 sprintf(mr.VolumeName, name, i);
248 Dmsg1(200, "Create Volume %s\n", mr.VolumeName);
249 if (!db_create_media_record(ua->db, &mr)) {
250 bsendmsg(ua, db_strerror(ua->db));
254 first_id = mr.PoolId;
258 Dmsg0(200, "Update pool record.\n");
259 if (db_update_pool_record(ua->db, &pr) != 1) {
260 bsendmsg(ua, db_strerror(ua->db));
263 bsendmsg(ua, _("%d Volumes created in pool %s\n"), num, pr.Name);
269 * Turn auto mount on/off
274 int automountcmd(UAContext *ua, char *cmd)
279 if (!get_cmd(ua, _("Turn on or off? "))) {
287 ua->automount = (strcasecmp(onoff, _("off")) == 0) ? 0 : 1;
295 static int cancelcmd(UAContext *ua, char *cmd)
301 char JobName[MAX_NAME_LENGTH];
307 for (i=1; i<ua->argc; i++) {
308 if (strcasecmp(ua->argk[i], _("jobid")) == 0) {
312 if (!(jcr=get_jcr_by_id(atoi(ua->argv[i])))) {
313 bsendmsg(ua, _("JobId %d is not running.\n"), atoi(ua->argv[i]));
317 } else if (strcasecmp(ua->argk[i], _("job")) == 0) {
321 if (!(jcr=get_jcr_by_partial_name(ua->argv[i]))) {
322 bsendmsg(ua, _("Job %s is not running.\n"), ua->argv[i]);
328 /* If we still do not have a jcr,
329 * throw up a list and ask the user to select one.
332 /* Count Jobs running */
334 for (jcr=NULL; (jcr=get_next_jcr(jcr)); njobs++) {
335 if (jcr->JobId == 0) { /* this is us */
336 free_locked_jcr(jcr);
340 free_locked_jcr(jcr);
344 bsendmsg(ua, _("No Jobs running.\n"));
347 start_prompt(ua, _("Select Job:\n"));
349 for (jcr=NULL; (jcr=get_next_jcr(jcr)); ) {
350 if (jcr->JobId == 0) { /* this is us */
351 free_locked_jcr(jcr);
354 add_prompt(ua, jcr->Job);
355 free_locked_jcr(jcr);
358 if (do_prompt(ua, _("Choose Job to cancel"), JobName) < 0) {
362 if (!get_cmd(ua, _("Confirm cancel (yes/no): "))) {
365 if (strcasecmp(ua->cmd, _("yes")) != 0) {
369 jcr = get_jcr_by_full_name(JobName);
371 bsendmsg(ua, _("Job %s not found.\n"), JobName);
376 switch (jcr->JobStatus) {
378 jcr->JobStatus = JS_Cancelled;
379 bsendmsg(ua, _("JobId %d, Job %s marked to be cancelled.\n"),
380 jcr->JobId, jcr->Job);
391 jcr->JobStatus = JS_Cancelled;
392 /* Cancel File daemon */
393 ua->jcr->client = jcr->client;
394 if (!connect_to_file_daemon(ua->jcr, 10, FDConnectTimeout, 1)) {
395 bsendmsg(ua, _("Failed to connect to File daemon.\n"));
399 Dmsg0(200, "Connected to file daemon\n");
400 fd = ua->jcr->file_bsock;
401 bnet_fsend(fd, "cancel Job=%s\n", jcr->Job);
402 while (bnet_recv(fd) > 0) {
403 bsendmsg(ua, "%s", fd->msg);
405 bnet_sig(fd, BNET_TERMINATE);
407 ua->jcr->file_bsock = NULL;
409 /* Cancel Storage daemon */
410 ua->jcr->store = jcr->store;
411 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
412 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
416 Dmsg0(200, "Connected to storage daemon\n");
417 sd = ua->jcr->store_bsock;
418 bnet_fsend(sd, "cancel Job=%s\n", jcr->Job);
419 while (bnet_recv(sd) > 0) {
420 bsendmsg(ua, "%s", sd->msg);
422 bnet_sig(sd, BNET_TERMINATE);
424 ua->jcr->store_bsock = NULL;
427 bsendmsg(ua, _("JobId %d Job %s Status=%c cannot be cancelled.\n"),
428 jcr->JobId, jcr->Job, jcr->JobStatus);
436 * Create a pool record from a given Pool resource
437 * Also called from backup.c
438 * Returns: -1 on error
439 * 0 record already exists
443 int create_pool(B_DB *db, POOL *pool)
447 memset(&pr, 0, sizeof(POOL_DBR));
449 strcpy(pr.Name, pool->hdr.name);
451 if (db_get_pool_record(db, &pr)) {
452 return 0; /* exists */
455 strcpy(pr.PoolType, pool->pool_type);
456 pr.MaxVols = pool->max_volumes;
458 pr.UseOnce = pool->use_volume_once;
459 pr.UseCatalog = pool->use_catalog;
460 pr.AcceptAnyVolume = pool->accept_any_volume;
461 if (pool->label_format) {
462 strcpy(pr.LabelFormat, pool->label_format);
464 strcpy(pr.LabelFormat, "*"); /* none */
467 if (!db_create_pool_record(db, &pr)) {
468 return -1; /* error */
476 * Create a Pool Record in the database.
477 * It is always created from the Resource record.
479 static int createcmd(UAContext *ua, char *cmd)
487 pool = get_pool_resource(ua);
492 switch (create_pool(ua->db, pool)) {
494 bsendmsg(ua, _("Error: Pool %s already exists.\n\
495 Use update to change it.\n"), pool->hdr.name);
499 bsendmsg(ua, db_strerror(ua->db));
512 * Update a Pool Record in the database.
513 * It is always updated from the Resource record.
515 * update pool=<pool-name>
516 * updates pool from Pool resource
517 * update media pool=<pool-name> volume=<volume-name>
518 * changes pool info for volume
520 static int updatecmd(UAContext *ua, char *cmd)
522 static char *kw[] = {
532 switch (find_arg_keyword(ua, kw)) {
544 start_prompt(ua, _("Update choice:\n"));
545 add_prompt(ua, _("pool"));
546 add_prompt(ua, _("media"));
547 switch (do_prompt(ua, _("Choose catalog item to update"), NULL)) {
561 * Update a media record -- allows you to change the
562 * Volume status. E.g. if you want Bacula to stop
563 * writing on the volume, set it to anything other
566 static int update_media(UAContext *ua)
571 static char *kw[] = {
575 memset(&pr, 0, sizeof(pr));
576 memset(&mr, 0, sizeof(mr));
577 if (!get_pool_dbr(ua, &pr)) {
580 mr.PoolId = pr.PoolId;
581 mr.VolumeName[0] = 0;
583 i = find_arg_keyword(ua, kw);
584 if (i == 0 && ua->argv[i]) {
585 strcpy(mr.VolumeName, ua->argv[i]);
587 if (mr.VolumeName[0] == 0) {
588 db_list_media_records(ua->db, &mr, prtit, ua);
589 if (!get_cmd(ua, _("Enter Volume name to update: "))) {
592 strcpy(mr.VolumeName, ua->cmd);
595 if (!db_get_media_record(ua->db, &mr)) {
596 bsendmsg(ua, _("Media record for %s not found.\n"), mr.VolumeName);
599 start_prompt(ua, _("Volume Status Values:\n"));
600 add_prompt(ua, "Append");
601 add_prompt(ua, "Archive");
602 add_prompt(ua, "Disabled");
603 add_prompt(ua, "Full");
604 add_prompt(ua, "Recycle");
605 add_prompt(ua, "Read-Only");
606 if (do_prompt(ua, _("Choose new Volume Status"), ua->cmd) < 0) {
609 strcpy(mr.VolStatus, ua->cmd);
610 db_update_media_record(ua->db, &mr);
615 * Update pool record -- pull info from current POOL resource
617 static int update_pool(UAContext *ua)
623 memset(&pr, 0, sizeof(pr));
624 if (!get_pool_dbr(ua, &pr)) {
628 strcpy(pr.PoolType, pool->pool_type);
629 if (pr.MaxVols != (uint32_t) (pool->max_volumes)) {
630 pr.MaxVols = pool->max_volumes;
632 if (pr.MaxVols != 0 && pr.MaxVols < pr.NumVols) {
633 pr.MaxVols = pr.NumVols;
635 pr.UseOnce = pool->use_volume_once;
636 pr.UseCatalog = pool->use_catalog;
637 pr.AcceptAnyVolume = pool->accept_any_volume;
638 if (pool->label_format) {
639 strcpy(pr.LabelFormat, pool->label_format);
641 strcpy(pr.LabelFormat, "*"); /* none */
643 id = db_update_pool_record(ua->db, &pr);
645 bsendmsg(ua, "Error: db_update_pool_record returned %d\n", id);
651 static void do_storage_setdebug(UAContext *ua, STORE *store, int level)
655 ua->jcr->store = store;
656 /* Try connecting for up to 15 seconds */
657 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d\n"),
658 store->hdr.name, store->address, store->SDport);
659 if (!connect_to_storage_daemon(ua->jcr, 1, 15, 0)) {
660 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
663 Dmsg0(20, _("Connected to storage daemon\n"));
664 sd = ua->jcr->store_bsock;
665 bnet_fsend(sd, "setdebug=%d\n", level);
666 if (bnet_recv(sd) > 0) {
667 bsendmsg(ua, "%s", sd->msg);
669 bnet_sig(sd, BNET_TERMINATE);
671 ua->jcr->store_bsock = NULL;
675 static void do_client_setdebug(UAContext *ua, CLIENT *client, int level)
679 /* Connect to File daemon */
681 ua->jcr->client = client;
682 /* Try to connect for 15 seconds */
683 bsendmsg(ua, _("Connecting to Client %s at %s:%d\n"),
684 client->hdr.name, client->address, client->FDport);
685 if (!connect_to_file_daemon(ua->jcr, 1, 15, 0)) {
686 bsendmsg(ua, _("Failed to connect to Client.\n"));
689 Dmsg0(20, "Connected to file daemon\n");
690 fd = ua->jcr->file_bsock;
691 bnet_fsend(fd, "setdebug=%d\n", level);
692 if (bnet_recv(fd) > 0) {
693 bsendmsg(ua, "%s", fd->msg);
695 bnet_sig(fd, BNET_TERMINATE);
697 ua->jcr->file_bsock = NULL;
703 static void do_all_setdebug(UAContext *ua, int level)
705 STORE *store, **unique_store;
706 CLIENT *client, **unique_client;
712 /* Count Storage items */
715 for (i=0; (store = (STORE *)GetNextRes(R_STORAGE, (RES *)store)); i++)
717 unique_store = (STORE **) malloc(i * sizeof(STORE));
718 /* Find Unique Storage address/port */
719 store = (STORE *)GetNextRes(R_STORAGE, NULL);
721 unique_store[i++] = store;
722 while ((store = (STORE *)GetNextRes(R_STORAGE, (RES *)store))) {
724 for (j=0; j<i; j++) {
725 if (strcmp(unique_store[j]->address, store->address) == 0 &&
726 unique_store[j]->SDport == store->SDport) {
732 unique_store[i++] = store;
733 Dmsg2(40, "Stuffing: %s:%d\n", store->address, store->SDport);
738 /* Call each unique Storage daemon */
739 for (j=0; j<i; j++) {
740 do_storage_setdebug(ua, unique_store[j], level);
744 /* Count Client items */
747 for (i=0; (client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client)); i++)
749 unique_client = (CLIENT **) malloc(i * sizeof(CLIENT));
750 /* Find Unique Client address/port */
751 client = (CLIENT *)GetNextRes(R_CLIENT, NULL);
753 unique_client[i++] = client;
754 while ((client = (CLIENT *)GetNextRes(R_CLIENT, (RES *)client))) {
756 for (j=0; j<i; j++) {
757 if (strcmp(unique_client[j]->address, client->address) == 0 &&
758 unique_client[j]->FDport == client->FDport) {
764 unique_client[i++] = client;
765 Dmsg2(40, "Stuffing: %s:%d\n", client->address, client->FDport);
770 /* Call each unique File daemon */
771 for (j=0; j<i; j++) {
772 do_client_setdebug(ua, unique_client[j], level);
778 * setdebug level=nn all
780 static int setdebugcmd(UAContext *ua, char *cmd)
790 Dmsg1(20, "setdebug:%s:\n", cmd);
793 for (i=1; i<ua->argc; i++) {
794 if (strcasecmp(ua->argk[i], _("level")) == 0 && ua->argv[i]) {
795 level = atoi(ua->argv[i]);
800 if (!get_cmd(ua, _("Enter new debug level: "))) {
803 level = atoi(ua->cmd);
806 bsendmsg(ua, _("level cannot be negative.\n"));
811 for (i=1; i<ua->argc; i++) {
812 if (strcasecmp(ua->argk[i], _("all")) == 0) {
813 do_all_setdebug(ua, level);
816 if (strcasecmp(ua->argk[i], _("dir")) == 0 ||
817 strcasecmp(ua->argk[i], _("director")) == 0) {
821 if (strcasecmp(ua->argk[i], _("client")) == 0) {
824 client = (CLIENT *) GetResWithName(R_CLIENT, ua->argv[i]);
826 do_client_setdebug(ua, client, level);
830 client = select_client_resource(ua);
832 do_client_setdebug(ua, client, level);
836 store = get_storage_resource(ua, cmd);
838 do_storage_setdebug(ua, store, level);
844 * We didn't find an appropriate keyword above, so
847 start_prompt(ua, _("Available daemons are: \n"));
848 add_prompt(ua, _("Director"));
849 add_prompt(ua, _("Storage"));
850 add_prompt(ua, _("Client"));
851 add_prompt(ua, _("All"));
852 switch(do_prompt(ua, _("Select daemon type to set debug level"), NULL)) {
853 case 0: /* Director */
857 store = get_storage_resource(ua, cmd);
859 do_storage_setdebug(ua, store, level);
863 client = select_client_resource(ua);
865 do_client_setdebug(ua, client, level);
869 do_all_setdebug(ua, level);
880 * Delete Pool records (should purge Media with it).
882 * delete pool=<pool-name>
883 * delete media pool=<pool-name> volume=<name>
885 static int deletecmd(UAContext *ua, char *cmd)
887 static char *keywords[] = {
897 "In general it is not a good idea to delete either a\n"
898 "Pool or Media since in both cases, you may delete Media\n"
899 "that contain data.\n\n"));
901 switch (find_arg_keyword(ua, keywords)) {
911 switch (do_keyword_prompt(ua, _("Choose catalog item to delete"), keywords)) {
919 bsendmsg(ua, _("Nothing done.\n"));
926 * Delete media records from database -- dangerous
928 static int delete_media(UAContext *ua)
933 if (!select_pool_and_media_dbr(ua, &pr, &mr)) {
936 bsendmsg(ua, _("\nThis command will delete volume %s\n"
937 "and all Jobs saved on that volume from the Catalog\n"),
940 if (!get_cmd(ua, _("If you want to continue enter pretty please: "))) {
943 if (strcmp(ua->cmd, _("pretty please")) == 0) {
944 db_delete_media_record(ua->db, &mr);
950 * Delete a pool record from the database -- dangerous
952 static int delete_pool(UAContext *ua)
956 memset(&pr, 0, sizeof(pr));
958 if (!get_pool_dbr(ua, &pr)) {
961 if (!get_cmd(ua, _("If you want to continue enter pretty please: "))) {
964 if (strcmp(ua->cmd, _("pretty please")) == 0) {
965 db_delete_pool_record(ua->db, &pr);
974 * label storage=xxx volume=vvv
976 static int labelcmd(UAContext *ua, char *cmd)
980 char dev_name[MAX_NAME_LENGTH];
986 static char *keyword[] = {
993 store = get_storage_resource(ua, cmd);
998 i = find_arg_keyword(ua, keyword);
999 if (i >=0 && ua->argv[i]) {
1000 strcpy(ua->cmd, ua->argv[i]);
1005 if (!get_cmd(ua, _("Enter new Volume name: "))) {
1009 if (strchr(ua->cmd, '|')) {
1010 bsendmsg(ua, _("Illegal character | in a volume name.\n"));
1013 if (strlen(ua->cmd) >= MAX_NAME_LENGTH) {
1014 bsendmsg(ua, _("Volume name too long.\n"));
1018 memset(&mr, 0, sizeof(mr));
1019 strcpy(mr.VolumeName, ua->cmd);
1020 if (db_get_media_record(ua->db, &mr)) {
1021 bsendmsg(ua, _("Media record for Volume %s already exists.\n"),
1025 strcpy(mr.MediaType, store->media_type);
1027 memset(&pr, 0, sizeof(pr));
1028 if (!select_pool_dbr(ua, &pr)) {
1031 mr.PoolId = pr.PoolId;
1032 strcpy(mr.VolStatus, "Append");
1033 mr.Recycle = pr.Recycle;
1034 mr.VolRetention = pr.VolumeRetention;
1036 ua->jcr->store = store;
1037 bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"),
1038 store->hdr.name, store->address, store->SDport);
1039 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1040 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1043 sd = ua->jcr->store_bsock;
1044 strcpy(dev_name, store->dev_name);
1045 bash_spaces(dev_name);
1046 bash_spaces(mr.VolumeName);
1047 bash_spaces(mr.MediaType);
1048 bash_spaces(pr.Name);
1049 bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s"),
1050 dev_name, mr.VolumeName, pr.Name, mr.MediaType);
1051 bsendmsg(ua, "Sending label command ...\n");
1052 while (bget_msg(sd, 0) > 0) {
1053 bsendmsg(ua, "%s", sd->msg);
1054 if (strncmp(sd->msg, "3000 OK label.", 14) == 0) {
1058 ua->jcr->store_bsock = NULL;
1059 unbash_spaces(dev_name);
1060 unbash_spaces(mr.VolumeName);
1061 unbash_spaces(mr.MediaType);
1062 unbash_spaces(pr.Name);
1064 if (db_create_media_record(ua->db, &mr)) {
1065 bsendmsg(ua, _("Media record for Volume=%s successfully created.\n"),
1067 if (ua->automount) {
1068 bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name);
1069 bash_spaces(dev_name);
1070 bnet_fsend(sd, "mount %s", dev_name);
1071 unbash_spaces(dev_name);
1072 while (bnet_recv(sd) > 0) {
1073 bsendmsg(ua, "%s", sd->msg);
1075 * 3001 OK mount. Device=xxx or
1076 * 3001 Mounted Volume vvvv
1078 if (strncmp(sd->msg, "3001 ", 5) == 0) {
1080 /***** ****FIXME***** find job waiting for
1081 ***** mount, and change to waiting for SD
1087 bsendmsg(ua, "%s", db_strerror(ua->db));
1091 bsendmsg(ua, _("Do not forget to mount the drive!!!\n"));
1093 bnet_sig(sd, BNET_TERMINATE);
1098 static void do_mount_cmd(int mount, UAContext *ua, char *cmd)
1102 char dev_name[MAX_NAME_LENGTH];
1108 Dmsg1(20, "mount: %s\n", ua->UA_sock->msg);
1110 store = get_storage_resource(ua, cmd);
1115 Dmsg2(20, "Found storage, MediaType=%s DevName=%s\n",
1116 store->media_type, store->dev_name);
1118 ua->jcr->store = store;
1119 if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) {
1120 bsendmsg(ua, _("Failed to connect to Storage daemon.\n"));
1123 sd = ua->jcr->store_bsock;
1124 strcpy(dev_name, store->dev_name);
1125 bash_spaces(dev_name);
1127 bnet_fsend(sd, "mount %s", dev_name);
1129 bnet_fsend(sd, "unmount %s", dev_name);
1131 while (bnet_recv(sd) > 0) {
1132 bsendmsg(ua, "%s", sd->msg);
1133 if (strncmp(sd->msg, "3001 OK mount.", 14) == 0) {
1134 /***** ****FIXME**** fix JobStatus */
1137 bnet_sig(sd, BNET_TERMINATE);
1139 ua->jcr->store_bsock = NULL;
1143 * mount [storage | device] <name>
1145 static int mountcmd(UAContext *ua, char *cmd)
1147 do_mount_cmd(1, ua, cmd); /* mount */
1153 * unmount [storage | device] <name>
1155 static int unmountcmd(UAContext *ua, char *cmd)
1157 do_mount_cmd(0, ua, cmd); /* unmount */
1164 * use catalog=<name>
1166 static int usecmd(UAContext *ua, char *cmd)
1168 CAT *oldcatalog, *catalog;
1171 close_db(ua); /* close any previously open db */
1172 oldcatalog = ua->catalog;
1174 if (!(catalog = get_catalog_resource(ua))) {
1175 ua->catalog = oldcatalog;
1177 ua->catalog = catalog;
1180 bsendmsg(ua, _("Using Catalog name=%s DB=%s\n"),
1181 ua->catalog->hdr.name, ua->catalog->db_name);
1186 int quitcmd(UAContext *ua, char *cmd)
1192 static int helpcmd(UAContext *ua, char *cmd)
1197 bnet_fsend(ua->UA_sock, _(" Command Description\n ======= ===========\n"));
1198 for (i=0; i<comsize; i++) {
1199 bnet_fsend(ua->UA_sock, _(" %-10s %s\n"), _(commands[i].key), _(commands[i].help));
1201 bnet_fsend(ua->UA_sock, "\n");
1205 static int versioncmd(UAContext *ua, char *cmd)
1207 bsendmsg(ua, "%s Version: " VERSION " (" DATE ")\n", my_name);
1212 /* A bit brain damaged in that if the user has not done
1213 * a "use catalog xxx" command, we simply find the first
1214 * catalog resource and open it.
1216 int open_db(UAContext *ua)
1223 ua->catalog = (CAT *)GetNextRes(R_CATALOG, NULL);
1226 bnet_fsend(ua->UA_sock, _("Could not find a Catalog resource\n"));
1229 bnet_fsend(ua->UA_sock, _("Using default Catalog name=%s DB=%s\n"),
1230 ua->catalog->hdr.name, ua->catalog->db_name);
1234 Dmsg0(50, "Open database\n");
1235 ua->db = db_init_database(ua->catalog->db_name, ua->catalog->db_user,
1236 ua->catalog->db_password);
1237 if (!db_open_database(ua->db)) {
1238 bnet_fsend(ua->UA_sock, _("Could not open DB %s: ERR=%s"),
1239 ua->catalog->db_name, db_strerror(ua->db));
1243 ua->jcr->db = ua->db;
1244 Dmsg1(50, "DB %s opened\n", ua->catalog->db_name);
1248 void close_db(UAContext *ua)
1251 db_close_database(ua->db);