From: Kern Sibbald Date: Fri, 4 Apr 2003 20:18:26 +0000 (+0000) Subject: relabel command, first cut label barcodes X-Git-Tag: Release-1.30~48 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=2c3a8837ac375953ac7f353a9cd93eddcd1e2978;p=bacula%2Fbacula relabel command, first cut label barcodes git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@419 91ce42f0-d328-0410-95d8-f526ca767f89 --- diff --git a/bacula/ReleaseNotes b/bacula/ReleaseNotes index eb5cfdefc4..b5e8ae3ddd 100644 --- a/bacula/ReleaseNotes +++ b/bacula/ReleaseNotes @@ -1,19 +1,20 @@ Release Notes for Bacula 1.30 - Bacula code: Total files = 231 Total lines = 65,064 (*.h *.c *.in) + Bacula code: Total files = 233 Total lines = 65,765 (*.h *.c *.in) Major Changes this Release: -- The Windows Client now uses Cygwin 1.3.20 and should be much more reliable. +- The Windows Client now uses Cygwin 1.3.20 and should be much + more reliable. - Implemented save/restore of chflags for FreeBSD systems. - Support for FreeBSD tape drives. - Support for SHA1 signatures in addition to MD5 (more secure). +- The btape "test" command is much more comprehensive and automatically + tries different options. Other Changes this Release: - Added "BSF at EOM = yes/no" for supporting FreeBSD tape drives. - The | and < options are now available for Excludes. - Multiple Directors in the GNOME Console now work (thanks Lutz Kttler). -- The btape "test" command is much more comprehensive and automatically - tries different options. - Installation on Cygwin systems is now supported. - GNOME Console has font support thanks to Phil Stracchino. - Solaris 2.6 now supported. @@ -23,7 +24,10 @@ Other Changes this Release: - Partial support for AIX systems. - Cycle through tapes with "RecycleOldestVolume=yes" (dangerous). - Support for Win95 systems (I hope). -- Console program now supported on Win32 systems. +- Console program now supported on Win32 systems as well as + several other utility programs. +- Full listing of most catalog records (llist command). +- Relabel Purged tapes with the relabel command. Items to note: diff --git a/bacula/kernstodo b/bacula/kernstodo index 1125308619..4dca20a714 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -20,14 +20,12 @@ Testing to do: (painful) - multiple simultaneous Volumes For 1.30 release: -- Pool requested twice in "relabel" command. - Must delete old volume from catalog. -- Make non-zero status from RunJobBefore/After error the job. +- Add IP address to authentication failures. Implement M_SECURITY + message class. - Remove kern and kelvin from mysql_grant... - Install grant_mysql... - Look at Python for a Bacula scripting language -- www.python.org - add #define ENABLE_NLS for Gnome compile on SuSE. -- Need define of int_least16_t in sha1.h for SuSE. - Figure out how to use ssh to protect Bacula communications. - Fix "access not allowed" for backup of files on WinXP. - Issue message to mount a new tape before the rewind. @@ -914,3 +912,5 @@ rufus-dir: Volume used once. Marking Volume "File0003" as Used. that no longer exist on the machine -- so that we maintain say backups for 30 days, but if the file is deleted, we maintain the last copy for 1 year. -- answer Volume retention. +- Make non-zero status from RunJobBefore/After error the job. +- Need define of int_least16_t in sha1.h for SuSE. diff --git a/bacula/src/cats/sql_delete.c b/bacula/src/cats/sql_delete.c index 244b0b3411..e5961e9ab2 100644 --- a/bacula/src/cats/sql_delete.c +++ b/bacula/src/cats/sql_delete.c @@ -190,14 +190,20 @@ static int do_media_purge(B_DB *mdb, MEDIA_DBR *mr) */ int db_delete_media_record(void *jcr, B_DB *mdb, MEDIA_DBR *mr) { + db_lock(mdb); if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) { + db_unlock(mdb); return 0; } - /* Delete associated records */ - do_media_purge(mdb, mr); + /* Do purge if not already purged */ + if (strcmp(mr->VolStatus, "Purged") != 0) { + /* Delete associated records */ + do_media_purge(mdb, mr); + } Mmsg(&mdb->cmd, "DELETE FROM Media WHERE MediaId=%d", mr->MediaId); db_sql_query(mdb, mdb->cmd, NULL, (void *)NULL); + db_unlock(mdb); return 1; } @@ -209,18 +215,22 @@ int db_delete_media_record(void *jcr, B_DB *mdb, MEDIA_DBR *mr) */ int db_purge_media_record(void *jcr, B_DB *mdb, MEDIA_DBR *mr) { + db_lock(mdb); if (mr->MediaId == 0 && !db_get_media_record(jcr, mdb, mr)) { + db_unlock(mdb); return 0; } /* Delete associated records */ - do_media_purge(mdb, mr); + do_media_purge(mdb, mr); /* Note, always purge */ /* Mark Volume as purged */ strcpy(mr->VolStatus, "Purged"); if (!db_update_media_record(jcr, mdb, mr)) { + db_unlock(mdb); return 0; } + db_unlock(mdb); return 1; } diff --git a/bacula/src/dird/Makefile.in b/bacula/src/dird/Makefile.in index 3eebd8b51b..5ec19ed3e2 100644 --- a/bacula/src/dird/Makefile.in +++ b/bacula/src/dird/Makefile.in @@ -31,7 +31,7 @@ SVRSRCS = dird.c authenticate.c autoprune.c \ scheduler.c sql_cmds.c \ ua_cmds.c ua_dotcmds.c \ ua_db_query.c ua_retention.c \ - ua_input.c ua_output.c ua_prune.c \ + ua_input.c ua_label.c ua_output.c ua_prune.c \ ua_purge.c ua_restore.c ua_run.c \ ua_select.c ua_server.c \ ua_status.c verify.c @@ -44,7 +44,7 @@ SVROBJS = dird.o authenticate.o autoprune.o \ scheduler.o sql_cmds.o \ ua_cmds.o ua_dotcmds.o \ ua_db_query.o ua_retention.o \ - ua_input.o ua_output.o ua_prune.o \ + ua_input.o ua_label.o ua_output.o ua_prune.o \ ua_purge.o ua_restore.o ua_run.o \ ua_select.o ua_server.o \ ua_status.o verify.o diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 451e650258..77fecf0115 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -176,18 +176,18 @@ static void *job_thread(void *arg) sm_check(__FILE__, __LINE__, True); if (!acquire_resource_locks(jcr)) { - set_jcr_job_status(jcr, JS_Cancelled); + set_jcr_job_status(jcr, JS_Canceled); } Dmsg0(200, "=====Start Job=========\n"); jcr->start_time = time(NULL); /* set the real start time */ - Dmsg2(200, "jcr->JobStatus=%d %c\n", jcr->JobStatus, (char)jcr->JobStatus); - if (job_cancelled(jcr)) { + + if (job_canceled(jcr)) { update_job_end_record(jcr); } else if (jcr->job->MaxStartDelay != 0 && jcr->job->MaxStartDelay < (utime_t)(jcr->start_time - jcr->sched_time)) { - Jmsg(jcr, M_FATAL, 0, _("Job cancelled because max start delay time exceeded.\n")); - set_jcr_job_status(jcr, JS_Cancelled); + Jmsg(jcr, M_FATAL, 0, _("Job canceled because max start delay time exceeded.\n")); + set_jcr_job_status(jcr, JS_Canceled); update_job_end_record(jcr); } else { @@ -200,6 +200,14 @@ static void *job_thread(void *arg) before = edit_run_codes(jcr, before, jcr->job->RunBeforeJob); status = run_program(before, 0, NULL); + if (status != 0) { + Jmsg(jcr, M_FATAL, 0, _("RunBeforeJob returned non-zero status=%d\n"), + status); + set_jcr_job_status(jcr, JS_FatalError); + update_job_end_record(jcr); + free_pool_memory(before); + goto bail_out; + } free_pool_memory(before); } switch (jcr->JobType) { @@ -236,9 +244,16 @@ static void *job_thread(void *arg) after = edit_run_codes(jcr, after, jcr->job->RunAfterJob); status = run_program(after, 0, NULL); + if (status != 0) { + Jmsg(jcr, M_FATAL, 0, _("RunAfterJob returned non-zero status=%d\n"), + status); + set_jcr_job_status(jcr, JS_FatalError); + update_job_end_record(jcr); + } free_pool_memory(after); } } +bail_out: release_resource_locks(jcr); Dmsg0(50, "Before free jcr\n"); free_jcr(jcr); diff --git a/bacula/src/dird/ua_cmds.c b/bacula/src/dird/ua_cmds.c index 0b81d81bd9..ca6b080872 100644 --- a/bacula/src/dird/ua_cmds.c +++ b/bacula/src/dird/ua_cmds.c @@ -58,6 +58,8 @@ extern int retentioncmd(UAContext *ua, char *cmd); extern int prunecmd(UAContext *ua, char *cmd); extern int purgecmd(UAContext *ua, char *cmd); extern int restorecmd(UAContext *ua, char *cmd); +extern int labelcmd(UAContext *ua, char *cmd); +extern int relabelcmd(UAContext *ua, char *cmd); /* Forward referenced functions */ static int addcmd(UAContext *ua, char *cmd), createcmd(UAContext *ua, char *cmd), cancelcmd(UAContext *ua, char *cmd); @@ -65,15 +67,14 @@ static int setdebugcmd(UAContext *ua, char *cmd); static int helpcmd(UAContext *ua, char *cmd); static int deletecmd(UAContext *ua, char *cmd); static int usecmd(UAContext *ua, char *cmd), unmountcmd(UAContext *ua, char *cmd); -static int labelcmd(UAContext *ua, char *cmd), mountcmd(UAContext *ua, char *cmd), updatecmd(UAContext *ua, char *cmd); -static int relabelcmd(UAContext *ua, char *cmd), mountcmd(UAContext *ua, char *cmd), updatecmd(UAContext *ua, char *cmd); static int versioncmd(UAContext *ua, char *cmd), automountcmd(UAContext *ua, char *cmd); static int timecmd(UAContext *ua, char *cmd); static int update_volume(UAContext *ua); static int update_pool(UAContext *ua); static int delete_volume(UAContext *ua); static int delete_pool(UAContext *ua); -static int do_label(UAContext *ua, char *cmd, int relabel); +static int mountcmd(UAContext *ua, char *cmd); +static int updatecmd(UAContext *ua, char *cmd); int quitcmd(UAContext *ua, char *cmd); @@ -1110,7 +1111,7 @@ static int setdebugcmd(UAContext *ua, char *cmd) if (strcasecmp(ua->argk[i], _("client")) == 0) { client = NULL; if (ua->argv[i]) { - client = (CLIENT *) GetResWithName(R_CLIENT, ua->argv[i]); + client = (CLIENT *)GetResWithName(R_CLIENT, ua->argv[i]); if (client) { do_client_setdebug(ua, client, level); return 1; @@ -1121,7 +1122,18 @@ static int setdebugcmd(UAContext *ua, char *cmd) do_client_setdebug(ua, client, level); return 1; } + } + if (strcasecmp(ua->argk[i], _("store")) == 0 || + strcasecmp(ua->argk[i], _("storage")) == 0) { + store = NULL; + if (ua->argv[i]) { + store = (STORE *)GetResWithName(R_STORAGE, ua->argv[i]); + if (store) { + do_storage_setdebug(ua, store, level); + return 1; + } + } store = get_storage_resource(ua, cmd); if (store) { do_storage_setdebug(ua, store, level); @@ -1270,199 +1282,6 @@ static int delete_pool(UAContext *ua) } -/* - * Label a tape - * - * label storage=xxx volume=vvv - */ -static int labelcmd(UAContext *ua, char *cmd) -{ - return do_label(ua, cmd, 0); /* standard label */ -} - -static int relabelcmd(UAContext *ua, char *cmd) -{ - return do_label(ua, cmd, 1); /* relabel tape */ -} - - -/* - * Common routine for both label and relabel - */ -static int do_label(UAContext *ua, char *cmd, int relabel) -{ - STORE *store; - BSOCK *sd; - char dev_name[MAX_NAME_LENGTH]; - MEDIA_DBR mr, omr; - POOL_DBR pr; - int ok = FALSE; - int mounted = FALSE; - int i; - int slot = 0; - static char *name_keyword[] = { - "name", - NULL}; - - static char *vol_keyword[] = { - "volume", - NULL}; - - - if (!open_db(ua)) { - return 1; - } - store = get_storage_resource(ua, cmd); - if (!store) { - return 1; - } - - /* If relabel get name of Volume to relabel */ - if (relabel) { - i = find_arg_keyword(ua, vol_keyword); - if (i >= 0 && ua->argv[i]) { - memset(&omr, 0, sizeof(omr)); - bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName)); - if (!db_get_media_record(ua->jcr, ua->db, &omr)) { - bsendmsg(ua, "%s", db_strerror(ua->db)); - goto getVol; - } - goto gotVol; - } -getVol: - if (!select_pool_and_media_dbr(ua, &pr, &omr)) { - return 1; - } - -gotVol: - if (strcmp(omr.VolStatus, "Purged") != 0) { - bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be purged before relabeling.\n"), - omr.VolumeName, omr.VolStatus); - return 1; - } - } - - i = find_arg_keyword(ua, name_keyword); - if (i >=0 && ua->argv[i]) { - strcpy(ua->cmd, ua->argv[i]); - goto gotName; - } - -getName: - if (!get_cmd(ua, _("Enter new Volume name: "))) { - return 1; - } -gotName: - /* ****FIXME*** be much more restrictive in the name */ - if (strpbrk(ua->cmd, "`~!@#$%^&*()[]{}|\\;'\"<>?,/")) { - bsendmsg(ua, _("Illegal character | in a volume name.\n")); - goto getName; - } - if (strlen(ua->cmd) >= MAX_NAME_LENGTH) { - bsendmsg(ua, _("Volume name too long.\n")); - goto getVol; - } - if (strlen(ua->cmd) == 0) { - bsendmsg(ua, _("Volume name must be at least one character long.\n")); - goto getName; - } - - memset(&mr, 0, sizeof(mr)); - strcpy(mr.VolumeName, ua->cmd); - if (db_get_media_record(ua->jcr, ua->db, &mr)) { - bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), - mr.VolumeName); - goto getName; - } - - /* Do some more checking on slot ****FIXME**** */ - if (store->autochanger) { - if (!get_cmd(ua, _("Enter slot (0 for none): "))) { - return 1; - } - slot = atoi(ua->cmd); - } - strcpy(mr.MediaType, store->media_type); - mr.Slot = slot; - - memset(&pr, 0, sizeof(pr)); - if (!select_pool_dbr(ua, &pr)) { - return 1; - } - - ua->jcr->store = store; - bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), - store->hdr.name, store->address, store->SDport); - if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) { - bsendmsg(ua, _("Failed to connect to Storage daemon.\n")); - return 1; - } - sd = ua->jcr->store_bsock; - strcpy(dev_name, store->dev_name); - bash_spaces(dev_name); - bash_spaces(mr.VolumeName); - bash_spaces(mr.MediaType); - bash_spaces(pr.Name); - if (relabel) { - bash_spaces(omr.VolumeName); - bnet_fsend(sd, _("relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d"), - dev_name, omr.VolumeName, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot); - bsendmsg(ua, _("Sending relabel command ...\n")); - } else { - bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d"), - dev_name, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot); - bsendmsg(ua, _("Sending label command ...\n")); - } - while (bget_msg(sd, 0) >= 0) { - bsendmsg(ua, "%s", sd->msg); - if (strncmp(sd->msg, "3000 OK label.", 14) == 0) { - ok = TRUE; - } else { - bsendmsg(ua, _("Label command failed.\n")); - } - } - ua->jcr->store_bsock = NULL; - unbash_spaces(dev_name); - unbash_spaces(mr.VolumeName); - unbash_spaces(mr.MediaType); - unbash_spaces(pr.Name); - mr.LabelDate = time(NULL); - if (ok) { - set_pool_dbr_defaults_in_media_dbr(&mr, &pr); - if (db_create_media_record(ua->jcr, ua->db, &mr)) { - bsendmsg(ua, _("Media record for Volume \"%s\" successfully created.\n"), - mr.VolumeName); - if (ua->automount) { - bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name); - bash_spaces(dev_name); - bnet_fsend(sd, "mount %s", dev_name); - unbash_spaces(dev_name); - while (bnet_recv(sd) >= 0) { - bsendmsg(ua, "%s", sd->msg); - /* Here we can get - * 3001 OK mount. Device=xxx or - * 3001 Mounted Volume vvvv - */ - if (strncmp(sd->msg, "3001 ", 5) == 0) { - mounted = TRUE; - /***** ****FIXME***** find job waiting for - ***** mount, and change to waiting for SD - */ - } - } - } - } else { - bsendmsg(ua, "%s", db_strerror(ua->db)); - } - } - if (!mounted) { - bsendmsg(ua, _("Do not forget to mount the drive!!!\n")); - } - bnet_sig(sd, BNET_TERMINATE); - bnet_close(sd); - return 1; -} - static void do_mount_cmd(int mount, UAContext *ua, char *cmd) { STORE *store; diff --git a/bacula/src/dird/ua_label.c b/bacula/src/dird/ua_label.c new file mode 100644 index 0000000000..871d141a37 --- /dev/null +++ b/bacula/src/dird/ua_label.c @@ -0,0 +1,299 @@ +/* + * + * Bacula Director -- Tape labeling commands + * + * Kern Sibbald, April MMIII + * + * Version $Id$ + */ + +/* + Copyright (C) 2000-2003 Kern Sibbald and John Walker + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" +#include "dird.h" + +/* Imported subroutines */ + +/* Imported variables */ + + +/* Imported functions */ + +/* Forward referenced functions */ +static int do_label(UAContext *ua, char *cmd, int relabel); +static void label_from_barcodes(UAContext *ua); + +/* + * Label a tape + * + * label storage=xxx volume=vvv + */ +int labelcmd(UAContext *ua, char *cmd) +{ + return do_label(ua, cmd, 0); /* standard label */ +} + +int relabelcmd(UAContext *ua, char *cmd) +{ + return do_label(ua, cmd, 1); /* relabel tape */ +} + + +/* + * Common routine for both label and relabel + */ +static int do_label(UAContext *ua, char *cmd, int relabel) +{ + STORE *store; + BSOCK *sd; + char dev_name[MAX_NAME_LENGTH]; + MEDIA_DBR mr, omr; + POOL_DBR pr; + int ok = FALSE; + int mounted = FALSE; + int i; + int slot = 0; + static char *name_keyword[] = { + "name", + NULL}; + static char *vol_keyword[] = { + "volume", + NULL}; + static char *barcode_keyword[] = { + "barcode", + "barcodes", + NULL}; + + + memset(&pr, 0, sizeof(pr)); + if (!open_db(ua)) { + return 1; + } + store = get_storage_resource(ua, cmd); + if (!store) { + return 1; + } + ua->jcr->store = store; + + if (!relabel && find_arg_keyword(ua, barcode_keyword) >= 0) { + label_from_barcodes(ua); + return 1; + } + + /* If relabel get name of Volume to relabel */ + if (relabel) { + /* Check for volume=OldVolume */ + i = find_arg_keyword(ua, vol_keyword); + if (i >= 0 && ua->argv[i]) { + memset(&omr, 0, sizeof(omr)); + bstrncpy(omr.VolumeName, ua->argv[i], sizeof(omr.VolumeName)); + if (db_get_media_record(ua->jcr, ua->db, &omr)) { + goto checkVol; + } + bsendmsg(ua, "%s", db_strerror(ua->db)); + } + /* No keyword or Vol not found, ask user to select */ + if (!select_pool_and_media_dbr(ua, &pr, &omr)) { + return 1; + } + + /* Require Volume to be Purged */ +checkVol: + if (strcmp(omr.VolStatus, "Purged") != 0) { + bsendmsg(ua, _("Volume \"%s\" has VolStatus %s. It must be purged before relabeling.\n"), + omr.VolumeName, omr.VolStatus); + return 1; + } + } + + /* Check for name=NewVolume */ + i = find_arg_keyword(ua, name_keyword); + if (i >=0 && ua->argv[i]) { + strcpy(ua->cmd, ua->argv[i]); + goto checkName; + } + + /* Get a new Volume name */ + for ( ;; ) { + if (!get_cmd(ua, _("Enter new Volume name: "))) { + return 1; + } +checkName: + /* Restrict the characters permitted in the Volume name */ + if (strpbrk(ua->cmd, "`~!@#$%^&*()[]{}|\\;'\"<>?,/")) { + bsendmsg(ua, _("Illegal character | in a volume name.\n")); + continue; + } + if (strlen(ua->cmd) >= MAX_NAME_LENGTH) { + bsendmsg(ua, _("Volume name too long.\n")); + continue; + } + if (strlen(ua->cmd) == 0) { + bsendmsg(ua, _("Volume name must be at least one character long.\n")); + continue; + } + + memset(&mr, 0, sizeof(mr)); + strcpy(mr.VolumeName, ua->cmd); + if (db_get_media_record(ua->jcr, ua->db, &mr)) { + bsendmsg(ua, _("Media record for new Volume \"%s\" already exists.\n"), + mr.VolumeName); + continue; + } + break; /* Got it */ + } + + /* Do some more checking on slot ****FIXME**** */ + if (store->autochanger) { + for ( ;; ) { + if (!get_cmd(ua, _("Enter slot (0 for none): "))) { + return 1; + } + slot = atoi(ua->cmd); + if (slot >= 0) { /* OK */ + break; + } + bsendmsg(ua, _("Slot numbers must be positive.\n")); + } + } + strcpy(mr.MediaType, store->media_type); + mr.Slot = slot; + + /* Must select Pool if not already done */ + if (pr.PoolId == 0) { + memset(&pr, 0, sizeof(pr)); + if (!select_pool_dbr(ua, &pr)) { + return 1; + } + } + + bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), + store->hdr.name, store->address, store->SDport); + if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) { + bsendmsg(ua, _("Failed to connect to Storage daemon.\n")); + return 1; + } + sd = ua->jcr->store_bsock; + strcpy(dev_name, store->dev_name); + bash_spaces(dev_name); + bash_spaces(mr.VolumeName); + bash_spaces(mr.MediaType); + bash_spaces(pr.Name); + if (relabel) { + bash_spaces(omr.VolumeName); + bnet_fsend(sd, _("relabel %s OldName=%s NewName=%s PoolName=%s MediaType=%s Slot=%d"), + dev_name, omr.VolumeName, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot); + bsendmsg(ua, _("Sending relabel command ...\n")); + } else { + bnet_fsend(sd, _("label %s VolumeName=%s PoolName=%s MediaType=%s Slot=%d"), + dev_name, mr.VolumeName, pr.Name, mr.MediaType, mr.Slot); + bsendmsg(ua, _("Sending label command ...\n")); + } + while (bget_msg(sd, 0) >= 0) { + bsendmsg(ua, "%s", sd->msg); + if (strncmp(sd->msg, "3000 OK label.", 14) == 0) { + ok = TRUE; + } else { + bsendmsg(ua, _("Label command failed.\n")); + } + } + ua->jcr->store_bsock = NULL; + unbash_spaces(dev_name); + unbash_spaces(mr.VolumeName); + unbash_spaces(mr.MediaType); + unbash_spaces(pr.Name); + mr.LabelDate = time(NULL); + if (ok) { + set_pool_dbr_defaults_in_media_dbr(&mr, &pr); + if (db_create_media_record(ua->jcr, ua->db, &mr)) { + bsendmsg(ua, _("Media record for Volume \"%s\" successfully created.\n"), + mr.VolumeName); + if (ua->automount) { + bsendmsg(ua, _("Requesting mount %s ...\n"), dev_name); + bash_spaces(dev_name); + bnet_fsend(sd, "mount %s", dev_name); + unbash_spaces(dev_name); + while (bnet_recv(sd) >= 0) { + bsendmsg(ua, "%s", sd->msg); + /* Here we can get + * 3001 OK mount. Device=xxx or + * 3001 Mounted Volume vvvv + */ + if (strncmp(sd->msg, "3001 ", 5) == 0) { + mounted = TRUE; + /***** ****FIXME***** find job waiting for + ***** mount, and change to waiting for SD + */ + } + } + } + } else { + bsendmsg(ua, "%s", db_strerror(ua->db)); + } + if (!db_delete_media_record(ua->jcr, ua->db, &omr)) { + bsendmsg(ua, _("Delete of Volume \"%s\" failed. ERR=%s"), + omr.VolumeName, db_strerror(ua->db)); + } else { + bsendmsg(ua, _("Volume \"%s\" deleted from catalog.\n")); + } + } + if (!mounted) { + bsendmsg(ua, _("Do not forget to mount the drive!!!\n")); + } + bnet_sig(sd, BNET_TERMINATE); + bnet_close(sd); + ua->jcr->store_bsock = NULL; + + return 1; +} + +static void label_from_barcodes(UAContext *ua) +{ + STORE *store = ua->jcr->store; + BSOCK *sd; + POOL_DBR pr; + char dev_name[MAX_NAME_LENGTH]; + + bsendmsg(ua, _("Connecting to Storage daemon %s at %s:%d ...\n"), + store->hdr.name, store->address, store->SDport); + if (!connect_to_storage_daemon(ua->jcr, 10, SDConnectTimeout, 1)) { + bsendmsg(ua, _("Failed to connect to Storage daemon.\n")); + return; + } + + strcpy(dev_name, store->dev_name); + bash_spaces(dev_name); + sd = ua->jcr->store_bsock; + bnet_fsend(sd, _("autochanger list %s \n"), dev_name); + while (bget_msg(sd, 0) >= 0) { + bsendmsg(ua, "%s", sd->msg); + } + bnet_sig(sd, BNET_TERMINATE); + bnet_close(sd); + ua->jcr->store_bsock = NULL; + + memset(&pr, 0, sizeof(pr)); + if (!select_pool_dbr(ua, &pr)) { + return; + } + + return; +} diff --git a/bacula/src/dird/ua_select.c b/bacula/src/dird/ua_select.c index 824602a6e8..c6ccc313a2 100644 --- a/bacula/src/dird/ua_select.c +++ b/bacula/src/dird/ua_select.c @@ -660,7 +660,6 @@ int do_prompt(UAContext *ua, char *msg, char *prompt, int max_prompt) /* * We scan what the user has entered looking for - * * device= ???? does this work ???? * storage= * job= @@ -676,10 +675,6 @@ STORE *get_storage_resource(UAContext *ua, char *cmd) JCR *jcr; int i; - if (ua->argc == 1) { - return select_storage_resource(ua); - } - device_name = NULL; store_name = NULL; diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index c96dabbd1c..5df133ccdc 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -61,6 +61,7 @@ #define JS_FatalError 'f' /* Fatal error */ #define JS_Differences 'D' /* Verify differences */ #define JS_Cancelled 'A' /* cancelled by user */ +#define JS_Canceled 'A' /* canceled by user */ #define JS_WaitFD 'F' /* waiting on File daemon */ #define JS_WaitSD 'S' /* waiting on the Storage daemon */ #define JS_WaitMedia 'm' /* waiting for new media */ @@ -71,10 +72,16 @@ #define JS_WaitMaxJobs 'd' /* Waiting for maximum jobs */ #define job_cancelled(jcr) \ - (jcr->JobStatus == JS_Cancelled || \ + (jcr->JobStatus == JS_Canceled || \ jcr->JobStatus == JS_ErrorTerminated || \ jcr->JobStatus == JS_FatalError) +#define job_canceled(jcr) \ + (jcr->JobStatus == JS_Canceled || \ + jcr->JobStatus == JS_ErrorTerminated || \ + jcr->JobStatus == JS_FatalError) + + typedef void (JCR_free_HANDLER)(struct s_jcr *jcr); /* Job Control Record (JCR) */ diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index 8cbc821fba..9d4a53a02c 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -18,12 +18,14 @@ first_rule: all dummy: # bacula-sd -SVRSRCS = stored.c acquire.c append.c askdir.c authenticate.c \ +SVRSRCS = stored.c autochanger.c acquire.c append.c \ + askdir.c authenticate.c \ block.c dev.c \ device.c dircmd.c fd_cmds.c fdmsg.c job.c \ label.c match_bsr.c parse_bsr.c \ read.c record.c stored_conf.c mount.c -SVROBJS = stored.o acquire.o append.o askdir.o authenticate.o \ +SVROBJS = stored.o autochanger.o acquire.o append.o \ + askdir.o authenticate.o \ block.o dev.o \ device.o dircmd.o fd_cmds.o fdmsg.o job.o \ label.o match_bsr.o mount.o parse_bsr.o \ @@ -34,27 +36,27 @@ TAPESRCS = btape.c block.c butil.c dev.c device.c label.c \ acquire.c mount.c record.c read_record.c \ stored_conf.c match_bsr.c parse_bsr.o TAPEOBJS = btape.o block.o butil.o dev.o device.o label.o \ - acquire.o mount.o record.o read_record.o \ + autochanger.o acquire.o mount.o record.o read_record.o \ stored_conf.o match_bsr.o parse_bsr.o # bls BLSOBJS = bls.o block.o butil.o device.o dev.o label.o match_bsr.o \ - acquire.o mount.o parse_bsr.o record.o \ + autochanger.o acquire.o mount.o parse_bsr.o record.o \ read_record.o stored_conf.o # bextract BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \ - acquire.o mount.o match_bsr.o parse_bsr.o butil.o \ + autochanger.o acquire.o mount.o match_bsr.o parse_bsr.o butil.o \ read_record.o stored_conf.o # bscan SCNOBJS = bscan.o block.o device.o dev.o label.o \ - acquire.o mount.o record.o match_bsr.o parse_bsr.o \ + autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \ butil.o read_record.o stored_conf.o # bcopy COPYOBJS = bcopy.o block.o device.o dev.o label.o \ - acquire.o mount.o record.o match_bsr.o parse_bsr.o \ + autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \ butil.o read_record.o stored_conf.o diff --git a/bacula/src/stored/autochanger.c b/bacula/src/stored/autochanger.c new file mode 100644 index 0000000000..76d1e00e35 --- /dev/null +++ b/bacula/src/stored/autochanger.c @@ -0,0 +1,263 @@ +/* + * + * Routines for handling the autochanger. + * + * Kern Sibbald, August MMII + * + * Version $Id$ + */ +/* + Copyright (C) 2000-2003 Kern Sibbald and John Walker + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public + License along with this program; if not, write to the Free + Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, + MA 02111-1307, USA. + + */ + +#include "bacula.h" /* pull in global headers */ +#include "stored.h" /* pull in Storage Deamon headers */ + +/* Forward referenced functions */ +static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd); + + +/* + * Called here to do an autoload using the autochanger, if + * configured, and if a Slot has been defined for this Volume. + * On success this routine loads the indicated tape, but the + * label is not read, so it must be verified. + * + * Note if dir is not NULL, it is the console requesting the + * autoload for labeling, so we respond directly to the + * dir bsock. + * + * Returns: 1 on success + * 0 on failure + */ +int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir) +{ + int slot = jcr->VolCatInfo.Slot; + int rtn_stat = 0; + + /* + * Handle autoloaders here. If we cannot autoload it, we + * will return FALSE to ask the sysop. + */ + if (writing && dev_cap(dev, CAP_AUTOCHANGER) && slot <= 0) { + if (dir) { + return 0; /* For user, bail out right now */ + } + if (dir_find_next_appendable_volume(jcr)) { + slot = jcr->VolCatInfo.Slot; + } + } + Dmsg1(100, "Want changer slot=%d\n", slot); + + if (slot > 0 && jcr->device->changer_name && jcr->device->changer_command) { + uint32_t timeout = jcr->device->max_changer_wait; + POOLMEM *changer, *results; + int status, loaded; + + results = get_pool_memory(PM_MESSAGE); + changer = get_pool_memory(PM_FNAME); + + /* Find out what is loaded, zero means device is unloaded */ + changer = edit_device_codes(jcr, changer, jcr->device->changer_command, + "loaded"); + status = run_program(changer, timeout, results); + Dmsg3(100, "run_prog: %s stat=%d result=%s\n", changer, status, results); + if (status == 0) { + loaded = atoi(results); + } else { + loaded = -1; /* force unload */ + } + Dmsg1(100, "loaded=%s\n", results); + + /* If bad status or tape we want is not loaded, load it. */ + if (status != 0 || loaded != slot) { + if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) { + offline_dev(dev); + } + /* We are going to load a new tape, so close the device */ + force_close_dev(dev); + if (loaded != 0) { /* must unload drive */ + Dmsg0(100, "Doing changer unload.\n"); + if (dir) { + bnet_fsend(dir, _("3902 Issuing autochanger \"unload\" command.\n")); + } else { + Jmsg(jcr, M_INFO, 0, _("Issuing autochanger \"unload\" command.\n")); + } + changer = edit_device_codes(jcr, changer, + jcr->device->changer_command, "unload"); + status = run_program(changer, timeout, NULL); + Dmsg1(100, "unload status=%d\n", status); + } + /* + * Load the desired cassette + */ + Dmsg1(100, "Doing changer load slot %d\n", slot); + if (dir) { + bnet_fsend(dir, _("3903 Issuing autochanger \"load slot %d\" command.\n"), + slot); + } else { + Jmsg(jcr, M_INFO, 0, _("Issuing autochanger \"load slot %d\" command.\n"), + slot); + } + changer = edit_device_codes(jcr, changer, + jcr->device->changer_command, "load"); + status = run_program(changer, timeout, NULL); + if (status == 0) { + Jmsg(jcr, M_INFO, 0, _("Autochanger \"load slot\" status is OK.\n")); + } else { + Jmsg(jcr, M_INFO, 0, _("Bad autochanger \"load slot\" status = %d.\n"), + status); + } + Dmsg2(100, "load slot %d status=%d\n", slot, status); + } + free_pool_memory(changer); + free_pool_memory(results); + Dmsg1(100, "After changer, status=%d\n", status); + if (status == 0) { /* did we succeed? */ + rtn_stat = 1; /* tape loaded by changer */ + } + } + return rtn_stat; +} + +int autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir) +{ + uint32_t timeout = jcr->device->max_changer_wait; + POOLMEM *changer; + BPIPE *bpipe; + int len = sizeof_pool_memory(dir->msg) - 1; + + if (!dev_cap(dev, CAP_AUTOCHANGER) || !jcr->device->changer_name || + !jcr->device->changer_command) { + bnet_fsend(dir, _("Not a changer device.\n")); + return 0; + } + + changer = get_pool_memory(PM_FNAME); + if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) { + offline_dev(dev); + } + /* We are going to load a new tape, so close the device */ + force_close_dev(dev); + + /* First unload any tape */ + bnet_fsend(dir, _("3902 Issuing autochanger \"unload\" command.\n")); + changer = edit_device_codes(jcr, changer, jcr->device->changer_command, "unload"); + run_program(changer, timeout, NULL); + + /* Now list slots occupied */ + changer = edit_device_codes(jcr, changer, jcr->device->changer_command, "list"); + bnet_fsend(dir, _("3903 Issuing autochanger \"list\" command.\n")); + bpipe = open_bpipe(changer, timeout, "r"); + if (!bpipe) { + bnet_fsend(dir, _("Open bpipe failed.\n")); + goto bail_out; + } + /* Get output from changer */ + while (fgets(dir->msg, len, bpipe->rfd)) { + dir->msglen = strlen(dir->msg); + bnet_send(dir); + } + bnet_sig(dir, BNET_EOD); + close_bpipe(bpipe); + +bail_out: + free_pool_memory(changer); + return 1; +} + + + +/* + * Edit codes into ChangerCommand + * %% = % + * %a = archive device name + * %c = changer device name + * %f = Client's name + * %j = Job name + * %o = command + * %s = Slot base 0 + * %S = Slot base 1 + * %v = Volume name + * + * + * omsg = edited output message + * imsg = input string containing edit codes (%x) + * cmd = command string (load, unload, ...) + * + */ +static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) +{ + char *p; + const char *str; + char add[20]; + + *omsg = 0; + Dmsg1(200, "edit_device_codes: %s\n", imsg); + for (p=imsg; *p; p++) { + if (*p == '%') { + switch (*++p) { + case '%': + str = "%"; + break; + case 'a': + str = jcr->device->dev->dev_name; + break; + case 'c': + str = NPRT(jcr->device->changer_name); + break; + case 'o': + str = NPRT(cmd); + break; + case 's': + sprintf(add, "%d", jcr->VolCatInfo.Slot - 1); + str = add; + break; + case 'S': + sprintf(add, "%d", jcr->VolCatInfo.Slot); + str = add; + break; + case 'j': /* Job name */ + str = jcr->Job; + break; + case 'v': + str = NPRT(jcr->VolumeName); + break; + case 'f': + str = NPRT(jcr->client_name); + break; + + default: + add[0] = '%'; + add[1] = *p; + add[2] = 0; + str = add; + break; + } + } else { + add[0] = *p; + add[1] = 0; + str = add; + } + Dmsg1(200, "add_str %s\n", str); + pm_strcat(&omsg, (char *)str); + Dmsg1(200, "omsg=%s\n", omsg); + } + return omsg; +} diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index 016bd440aa..fdabb03f56 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -68,6 +68,7 @@ static int cancel_cmd(JCR *cjcr); static int mount_cmd(JCR *jcr); static int unmount_cmd(JCR *jcr); static int status_cmd(JCR *sjcr); +static int autochanger_cmd(JCR *sjcr); static int do_label(JCR *jcr, int relabel); static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, char *newname, char *poolname, @@ -91,6 +92,7 @@ static struct s_cmds cmds[] = { {"mount", mount_cmd}, {"unmount", unmount_cmd}, {"status", status_cmd}, + {"autochanger", autochanger_cmd}, {NULL, NULL} /* list terminator */ }; @@ -801,3 +803,69 @@ static void send_blocked_status(JCR *jcr, DEVICE *dev) break; } } + +/* + * Autochanger command from Director + */ +static int autochanger_cmd(JCR *jcr) +{ + char *devname; + BSOCK *dir = jcr->dir_bsock; + DEVRES *device; + DEVICE *dev; + int found = 0; + + devname = (char *)get_memory(dir->msglen); + if (sscanf(dir->msg, "autochanger list %s ", devname) == 1) { + unbash_spaces(devname); + device = NULL; + LockRes(); + while ((device=(DEVRES *)GetNextRes(R_DEVICE, (RES *)device))) { + /* Find resource, and make sure we were able to open it */ + if (strcmp(device->hdr.name, devname) == 0 && device->dev) { + Dmsg1(20, "Found device %s\n", device->hdr.name); + found = 1; + break; + } + } + UnlockRes(); + if (found) { + jcr->device = device; + dev = device->dev; + P(dev->mutex); /* Use P to avoid indefinite block */ + if (!(dev->state & ST_OPENED)) { + if (open_dev(dev, NULL, READ_WRITE) < 0) { + bnet_fsend(dir, _("3994 Connot open device: %s\n"), strerror_dev(dev)); + } else { + autochanger_list(jcr, dev, dir); + force_close_dev(dev); + } + /* Under certain "safe" conditions, we can steal the lock */ + } else if (dev->dev_blocked && + (dev->dev_blocked == BST_UNMOUNTED || + dev->dev_blocked == BST_WAITING_FOR_SYSOP || + dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP)) { + autochanger_list(jcr, dev, dir); + } else if (dev->state & ST_READ || dev->num_writers) { + if (dev->state & ST_READ) { + bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"), + dev_name(dev)); + } else { + bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"), + dev_name(dev), dev->num_writers); + } + } else { /* device not being used */ + autochanger_list(jcr, dev, dir); + } + V(dev->mutex); + } else { + bnet_fsend(dir, _("3999 Device %s not found\n"), devname); + } + } else { + strcpy(devname, dir->msg); + bnet_fsend(dir, _("3907 Error scanning autocharger list command: %s\n"), devname); + } + free_memory(devname); + bnet_sig(dir, BNET_EOD); + return 1; +} diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index abedacf060..dc0f5179ad 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -31,7 +31,6 @@ #include "stored.h" /* pull in Storage Deamon headers */ /* Forward referenced functions */ -static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd); /* @@ -378,186 +377,3 @@ int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) Dmsg0(90, "End of Device reached.\n"); return 0; } - -/* - * Called here to do an autoload using the autochanger, if - * configured, and if a Slot has been defined for this Volume. - * On success this routine loads the indicated tape, but the - * label is not read, so it must be verified. - * - * Note if dir is not NULL, it is the console requesting the - * autoload for labeling, so we respond directly to the - * dir bsock. - * - * Returns: 1 on success - * 0 on failure - */ -int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir) -{ - int slot = jcr->VolCatInfo.Slot; - int rtn_stat = 0; - - /* - * Handle autoloaders here. If we cannot autoload it, we - * will return FALSE to ask the sysop. - */ - if (writing && dev_cap(dev, CAP_AUTOCHANGER) && slot <= 0) { - if (dir) { - return 0; /* For user, bail out right now */ - } - if (dir_find_next_appendable_volume(jcr)) { - slot = jcr->VolCatInfo.Slot; - } - } - Dmsg1(100, "Want changer slot=%d\n", slot); - - if (slot > 0 && jcr->device->changer_name && jcr->device->changer_command) { - uint32_t timeout = jcr->device->max_changer_wait; - POOLMEM *changer, *results; - int status, loaded; - - results = get_pool_memory(PM_MESSAGE); - changer = get_pool_memory(PM_FNAME); - - /* Find out what is loaded, zero means device is unloaded */ - changer = edit_device_codes(jcr, changer, jcr->device->changer_command, - "loaded"); - status = run_program(changer, timeout, results); - Dmsg3(100, "run_prog: %s stat=%d result=%s\n", changer, status, results); - if (status == 0) { - loaded = atoi(results); - } else { - loaded = -1; /* force unload */ - } - Dmsg1(100, "loaded=%s\n", results); - - /* If bad status or tape we want is not loaded, load it. */ - if (status != 0 || loaded != slot) { - if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) { - offline_dev(dev); - } - /* We are going to load a new tape, so close the device */ - force_close_dev(dev); - if (loaded != 0) { /* must unload drive */ - Dmsg0(100, "Doing changer unload.\n"); - if (dir) { - bnet_fsend(dir, _("3902 Issuing autochanger \"unload\" command.\n")); - } else { - Jmsg(jcr, M_INFO, 0, _("Issuing autochanger \"unload\" command.\n")); - } - changer = edit_device_codes(jcr, changer, - jcr->device->changer_command, "unload"); - status = run_program(changer, timeout, NULL); - Dmsg1(100, "unload status=%d\n", status); - } - /* - * Load the desired cassette - */ - Dmsg1(100, "Doing changer load slot %d\n", slot); - if (dir) { - bnet_fsend(dir, _("3903 Issuing autochanger \"load slot %d\" command.\n"), - slot); - } else { - Jmsg(jcr, M_INFO, 0, _("Issuing autochanger \"load slot %d\" command.\n"), - slot); - } - changer = edit_device_codes(jcr, changer, - jcr->device->changer_command, "load"); - status = run_program(changer, timeout, NULL); - if (status == 0) { - Jmsg(jcr, M_INFO, 0, _("Autochanger \"load slot\" status is OK.\n")); - } else { - Jmsg(jcr, M_INFO, 0, _("Bad autochanger \"load slot\" status = %d.\n"), - status); - } - Dmsg2(100, "load slot %d status=%d\n", slot, status); - } - free_pool_memory(changer); - free_pool_memory(results); - Dmsg1(100, "After changer, status=%d\n", status); - if (status == 0) { /* did we succeed? */ - rtn_stat = 1; /* tape loaded by changer */ - } - } - return rtn_stat; -} - - - -/* - * Edit codes into ChangerCommand - * %% = % - * %a = archive device name - * %c = changer device name - * %f = Client's name - * %j = Job name - * %o = command - * %s = Slot base 0 - * %S = Slot base 1 - * %v = Volume name - * - * - * omsg = edited output message - * imsg = input string containing edit codes (%x) - * cmd = command string (load, unload, ...) - * - */ -static char *edit_device_codes(JCR *jcr, char *omsg, char *imsg, char *cmd) -{ - char *p; - const char *str; - char add[20]; - - *omsg = 0; - Dmsg1(200, "edit_device_codes: %s\n", imsg); - for (p=imsg; *p; p++) { - if (*p == '%') { - switch (*++p) { - case '%': - str = "%"; - break; - case 'a': - str = jcr->device->dev->dev_name; - break; - case 'c': - str = NPRT(jcr->device->changer_name); - break; - case 'o': - str = NPRT(cmd); - break; - case 's': - sprintf(add, "%d", jcr->VolCatInfo.Slot - 1); - str = add; - break; - case 'S': - sprintf(add, "%d", jcr->VolCatInfo.Slot); - str = add; - break; - case 'j': /* Job name */ - str = jcr->Job; - break; - case 'v': - str = NPRT(jcr->VolumeName); - break; - case 'f': - str = NPRT(jcr->client_name); - break; - - default: - add[0] = '%'; - add[1] = *p; - add[2] = 0; - str = add; - break; - } - } else { - add[0] = *p; - add[1] = 0; - str = add; - } - Dmsg1(200, "add_str %s\n", str); - pm_strcat(&omsg, (char *)str); - Dmsg1(200, "omsg=%s\n", omsg); - } - return omsg; -} diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index a75a16055f..693ce620c5 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -28,82 +28,82 @@ uint32_t new_VolSessionId(); /* From acquire.c */ -DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -int release_device(JCR *jcr, DEVICE *dev); +DEVICE *acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int release_device(JCR *jcr, DEVICE *dev); /* From askdir.c */ -int dir_get_volume_info(JCR *jcr, int writing); -int dir_find_next_appendable_volume(JCR *jcr); -int dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel); -int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev); -int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev); -int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec); -int dir_send_job_status(JCR *jcr); -int dir_create_jobmedia_record(JCR *jcr); +int dir_get_volume_info(JCR *jcr, int writing); +int dir_find_next_appendable_volume(JCR *jcr); +int dir_update_volume_info(JCR *jcr, VOLUME_CAT_INFO *vol, int relabel); +int dir_ask_sysop_to_mount_next_volume(JCR *jcr, DEVICE *dev); +int dir_ask_sysop_to_mount_volume(JCR *jcr, DEVICE *dev); +int dir_update_file_attributes(JCR *jcr, DEV_RECORD *rec); +int dir_send_job_status(JCR *jcr); +int dir_create_jobmedia_record(JCR *jcr); /* authenticate.c */ -int authenticate_director(JCR *jcr); -int authenticate_filed(JCR *jcr); +int authenticate_director(JCR *jcr); +int authenticate_filed(JCR *jcr); /* From block.c */ -void dump_block(DEV_BLOCK *b, char *msg); +void dump_block(DEV_BLOCK *b, char *msg); DEV_BLOCK *new_block(DEVICE *dev); -void init_block_write(DEV_BLOCK *block); -void empty_block(DEV_BLOCK *block); -void free_block(DEV_BLOCK *block); -int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -int read_block_from_device(DEVICE *dev, DEV_BLOCK *block); -int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block); +void init_block_write(DEV_BLOCK *block); +void empty_block(DEV_BLOCK *block); +void free_block(DEV_BLOCK *block); +int write_block_to_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int write_block_to_dev(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int read_block_from_device(DEVICE *dev, DEV_BLOCK *block); +int read_block_from_dev(DEVICE *dev, DEV_BLOCK *block); /* From butil.c -- utilities for SD tool programs */ -void print_ls_output(char *fname, char *link, int type, struct stat *statp); +void print_ls_output(char *fname, char *link, int type, struct stat *statp); JCR *setup_jcr(char *name, char *device, BSR *bsr, char *VolumeName); DEVICE *setup_to_access_device(JCR *jcr, int read_access); -void display_error_status(DEVICE *dev); +void display_error_status(DEVICE *dev); DEVRES *find_device_res(char *device_name, int read_access); /* From dev.c */ -DEVICE *init_dev(DEVICE *dev, DEVRES *device); -int open_dev(DEVICE *dev, char *VolName, int mode); -void close_dev(DEVICE *dev); -void force_close_dev(DEVICE *dev); -int truncate_dev(DEVICE *dev); -void term_dev(DEVICE *dev); -char * strerror_dev(DEVICE *dev); -void clrerror_dev(DEVICE *dev, int func); -int update_pos_dev(DEVICE *dev); -int rewind_dev(DEVICE *dev); -int load_dev(DEVICE *dev); -int offline_dev(DEVICE *dev); -int flush_dev(DEVICE *dev); -int weof_dev(DEVICE *dev, int num); -int write_block(DEVICE *dev); -int write_dev(DEVICE *dev, char *buf, size_t len); -int read_dev(DEVICE *dev, char *buf, size_t len); -int status_dev(DEVICE *dev, uint32_t *status); -int eod_dev(DEVICE *dev); -int fsf_dev(DEVICE *dev, int num); -int fsr_dev(DEVICE *dev, int num); -int bsf_dev(DEVICE *dev, int num); -int bsr_dev(DEVICE *dev, int num); -void attach_jcr_to_device(DEVICE *dev, JCR *jcr); -void detach_jcr_from_device(DEVICE *dev, JCR *jcr); -JCR *next_attached_jcr(DEVICE *dev, JCR *jcr); +DEVICE *init_dev(DEVICE *dev, DEVRES *device); +int open_dev(DEVICE *dev, char *VolName, int mode); +void close_dev(DEVICE *dev); +void force_close_dev(DEVICE *dev); +int truncate_dev(DEVICE *dev); +void term_dev(DEVICE *dev); +char * strerror_dev(DEVICE *dev); +void clrerror_dev(DEVICE *dev, int func); +int update_pos_dev(DEVICE *dev); +int rewind_dev(DEVICE *dev); +int load_dev(DEVICE *dev); +int offline_dev(DEVICE *dev); +int flush_dev(DEVICE *dev); +int weof_dev(DEVICE *dev, int num); +int write_block(DEVICE *dev); +int write_dev(DEVICE *dev, char *buf, size_t len); +int read_dev(DEVICE *dev, char *buf, size_t len); +int status_dev(DEVICE *dev, uint32_t *status); +int eod_dev(DEVICE *dev); +int fsf_dev(DEVICE *dev, int num); +int fsr_dev(DEVICE *dev, int num); +int bsf_dev(DEVICE *dev, int num); +int bsr_dev(DEVICE *dev, int num); +void attach_jcr_to_device(DEVICE *dev, JCR *jcr); +void detach_jcr_from_device(DEVICE *dev, JCR *jcr); +JCR *next_attached_jcr(DEVICE *dev, JCR *jcr); /* Get info about device */ -char * dev_name(DEVICE *dev); -char * dev_vol_name(DEVICE *dev); +char * dev_name(DEVICE *dev); +char * dev_vol_name(DEVICE *dev); uint32_t dev_block(DEVICE *dev); uint32_t dev_file(DEVICE *dev); -int dev_is_tape(DEVICE *dev); +int dev_is_tape(DEVICE *dev); /* From device.c */ -int open_device(DEVICE *dev); -int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +int open_device(DEVICE *dev); +int fixup_device_block_write_error(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); void _lock_device(char *file, int line, DEVICE *dev); void _unlock_device(char *file, int line, DEVICE *dev); void _block_device(char *file, int line, DEVICE *dev, int state); @@ -119,40 +119,43 @@ void new_steal_device_lock(DEVICE *dev, brwsteal_t *hold, int state); void new_return_device_lock(DEVICE *dev, brwsteal_t *hold); /* From dircmd.c */ -void *connection_request(void *arg); +void *connection_request(void *arg); /* From fd_cmds.c */ -void run_job(JCR *jcr); +void run_job(JCR *jcr); /* From fdmsg.c */ -int bget_msg(BSOCK *sock); +int bget_msg(BSOCK *sock); /* From job.c */ -void stored_free_jcr(JCR *jcr); -void connection_from_filed(void *arg); -void handle_filed_connection(BSOCK *fd, char *job_name); +void stored_free_jcr(JCR *jcr); +void connection_from_filed(void *arg); +void handle_filed_connection(BSOCK *fd, char *job_name); /* From label.c */ -int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -void create_session_label(JCR *jcr, DEV_RECORD *rec, int label); -void create_volume_label(DEVICE *dev, char *VolName); -int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName); -int write_session_label(JCR *jcr, DEV_BLOCK *block, int label); -int write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -void dump_volume_label(DEVICE *dev); -void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose); -int unser_volume_label(DEVICE *dev, DEV_RECORD *rec); -int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec); +int read_dev_volume_label(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +void create_session_label(JCR *jcr, DEV_RECORD *rec, int label); +void create_volume_label(DEVICE *dev, char *VolName); +int write_volume_label_to_dev(JCR *jcr, DEVRES *device, char *VolName, char *PoolName); +int write_session_label(JCR *jcr, DEV_BLOCK *block, int label); +int write_volume_label_to_block(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); +void dump_volume_label(DEVICE *dev); +void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose); +int unser_volume_label(DEVICE *dev, DEV_RECORD *rec); +int unser_session_label(SESSION_LABEL *label, DEV_RECORD *rec); /* From match_bsr.c */ int match_bsr(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec, - SESSION_LABEL *sesrec); + SESSION_LABEL *sesrec); /* From mount.c */ -int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release); -int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); -int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir); +int mount_next_write_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, int release); +int mount_next_read_volume(JCR *jcr, DEVICE *dev, DEV_BLOCK *block); + +/* From autochanger.c */ +int autoload_device(JCR *jcr, DEVICE *dev, int writing, BSOCK *dir); +int autochanger_list(JCR *jcr, DEVICE *dev, BSOCK *dir); /* From parse_bsr.c */ @@ -167,11 +170,11 @@ extern void create_vol_list(JCR *jcr); /* From record.c */ char *FI_to_ascii(int fi); char *stream_to_ascii(int stream, int fi); -int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); -int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); -int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); +int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); +int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec); +int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec); DEV_RECORD *new_record(); -void free_record(DEV_RECORD *rec); +void free_record(DEV_RECORD *rec); /* From read_record.c */ int read_records(JCR *jcr, DEVICE *dev,