(cd scripts; \
chmod 755 startmysql stopmysql bacula startit stopit btraceback; \
chmod 755 mtx-changer bconsole gconsole devel_bacula; \
- chmod 755 dvd-freespace dvd-writepart)
+ chmod 755 dvd-handler)
(cd src/cats; \
chmod 755 create_bacula_database update_bacula_tables make_bacula_tables; \
General:
+Changes to 1.39.5
+30Jan06
+- Continue implementing migration.
+- Implement support for removable filesystems in SD.
+- Ensure that btraceback scripts can be read by anyone.
+- Replace dvd-freespace and dvd-writepart by dvd-handler.
+- Correct bug where canceling restore before the FD contacts
+ the SD causes the drive to be left in read mode.
+- Move ofline_or_rewind into DEVICE::close().
+- Eliminate close_device.
+- Convert several dev subroutines to methods (e.g. bsf,
+ eod, ...)
+- Eliminate force_close_device().
+- Implement Device Type directive in Device resource that
+ can have values File, Tape, Fifo, DVD, or Prog.
+- Add has_cap() method to Device.
Changes to 1.39.4
17Jan06
- Add patch from bug #527 to allow RedHat user to specify
$(INSTALL_SCRIPT) dvd-handler $(DESTDIR)$(scriptdir)/dvd-handler
$(INSTALL_DATA) btraceback.gdb $(DESTDIR)$(scriptdir)/btraceback.gdb
$(INSTALL_DATA) btraceback.dbx $(DESTDIR)$(scriptdir)/btraceback.dbx
+ chmod 0644 $(DESTDIR)$(scriptdir)/btraceback.gdb \
+ $(DESTDIR)$(scriptdir)/btraceback.dbx
$(INSTALL_SCRIPT) btraceback $(DESTDIR)$(sbindir)/btraceback
gzip <bacula.man >bacula.8.gz
$(INSTALL_DATA) bacula.8.gz $(DESTDIR)$(mandir)/bacula.8.gz
* Version $Id$
*/
/*
- Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+ Copyright (C) 2000-2006 Kern Sibbald
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.
+ modify it under the terms of the GNU General Public License
+ version 2 as amended with additional clauses defined in the
+ file LICENSE in the main source directory.
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.
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ the file LICENSE for additional details.
*/
/* find.c */
bool db_find_job_start_time(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM **stime);
-int db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr);
+bool db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr);
int db_find_next_volume(JCR *jcr, B_DB *mdb, int index, bool InChanger, MEDIA_DBR *mr);
bool db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, int &JobLevel);
* VERIFY_CATALOG we want the JobId of the last INIT.
* For VERIFY_VOLUME_TO_CATALOG, we want the JobId of the last Job.
*
- * Returns: 1 on success
- * 0 on failure
+ * Returns: true on success
+ * false on failure
*/
-int
+bool
db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr)
{
SQL_ROW row;
L_VERIFY_INIT, jr->Name,
edit_int64(jr->ClientId, ed1));
} else if (jr->JobLevel == L_VERIFY_VOLUME_TO_CATALOG ||
- jr->JobLevel == L_VERIFY_DISK_TO_CATALOG) {
+ jr->JobLevel == L_VERIFY_DISK_TO_CATALOG ||
+ jr->JobType == JT_MIGRATE) {
if (Name) {
Mmsg(mdb->cmd,
"SELECT JobId FROM Job WHERE Type='B' AND JobStatus='T' AND "
} else {
Mmsg1(&mdb->errmsg, _("Unknown Job level=%c\n"), jr->JobLevel);
db_unlock(mdb);
- return 0;
+ return false;
}
Dmsg1(100, "Query: %s\n", mdb->cmd);
if (!QUERY_DB(jcr, mdb, mdb->cmd)) {
db_unlock(mdb);
- return 0;
+ return false;
}
if ((row = sql_fetch_row(mdb)) == NULL) {
Mmsg1(&mdb->errmsg, _("No Job found for: %s.\n"), mdb->cmd);
sql_free_result(mdb);
db_unlock(mdb);
- return 0;
+ return false;
}
jr->JobId = str_to_int64(row[0]);
if (jr->JobId <= 0) {
Mmsg1(&mdb->errmsg, _("No Job found for: %s\n"), mdb->cmd);
db_unlock(mdb);
- return 0;
+ return false;
}
db_unlock(mdb);
- return 1;
+ return true;
}
/*
}
Dmsg0(150, "Storage daemon connection OK\n");
+ if (!bnet_fsend(jcr->store_bsock, "run")) {
+ return false;
+ }
+
set_jcr_job_status(jcr, JS_WaitFD);
if (!connect_to_file_daemon(jcr, 10, FDConnectTimeout, 1)) {
return false;
}
}
- bnet_fsend(fd, storaddr, store->address, store->SDDport,
- tls_need);
+ bnet_fsend(fd, storaddr, store->address, store->SDDport, tls_need);
if (!response(jcr, fd, OKstore, "Storage", DISPLAY_ERROR)) {
return false;
}
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
/* Responses received from File daemon */
static char OKinc[] = "2000 OK include\n";
static char OKjob[] = "2000 OK Job";
-static char OKbootstrap[] = "2000 OK bootstrap\n";
static char OKlevel[] = "2000 OK level\n";
static char OKRunBefore[] = "2000 OK RunBefore\n";
static char OKRunAfter[] = "2000 OK RunAfter\n";
/*
- * Send bootstrap file if any to the File daemon.
- * This is used for restore and verify VolumeToCatalog
+ * Send bootstrap file if any to the socket given (FD or SD).
+ * This is used for restore, verify VolumeToCatalog, and
+ * for migration.
*/
-bool send_bootstrap_file(JCR *jcr)
+bool send_bootstrap_file(JCR *jcr, BSOCK *sock)
{
FILE *bs;
char buf[1000];
- BSOCK *fd = jcr->file_bsock;
const char *bootstrap = "bootstrap\n";
Dmsg1(400, "send_bootstrap_file: %s\n", jcr->RestoreBootstrap);
if (!jcr->RestoreBootstrap) {
- return 1;
+ return true;
}
bs = fopen(jcr->RestoreBootstrap, "r");
if (!bs) {
Jmsg(jcr, M_FATAL, 0, _("Could not open bootstrap file %s: ERR=%s\n"),
jcr->RestoreBootstrap, be.strerror());
set_jcr_job_status(jcr, JS_ErrorTerminated);
- return 0;
+ return false;
}
- bnet_fsend(fd, bootstrap);
+ bnet_fsend(sock, bootstrap);
while (fgets(buf, sizeof(buf), bs)) {
- bnet_fsend(fd, "%s", buf);
+ bnet_fsend(sock, "%s", buf);
}
- bnet_sig(fd, BNET_EOD);
+ bnet_sig(sock, BNET_EOD);
fclose(bs);
if (jcr->unlink_bsr) {
unlink(jcr->RestoreBootstrap);
jcr->unlink_bsr = false;
}
- if (!response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
- set_jcr_job_status(jcr, JS_ErrorTerminated);
- return 0;
- }
- return 1;
+ return true;
}
/*
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
return false;
}
if ((n = bget_dirmsg(bs)) >= 0) {
- Dmsg0(900, bs->msg);
if (strcmp(bs->msg, resp) == 0) {
return true;
}
- Dmsg1(900, "Bad response: ERR=%s", bs->msg);
if (prtmsg == DISPLAY_ERROR) {
Jmsg(jcr, M_FATAL, 0, _("Bad response to %s command: wanted %s, got %s\n"),
cmd, resp, bs->msg);
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
return true;
default:
-
/* Cancel File daemon */
if (jcr->file_bsock) {
ua->jcr->client = jcr->client;
* Basic tasks done here:
* Open DB and create records for this job.
* Open Message Channel with Storage daemon to tell him a job will be starting.
- * Open connection with File daemon and pass him commands
+ * Open connection with Storage daemon and pass him commands
* to do the backup.
- * When the File daemon finishes the job, update the DB.
+ * When the Storage daemon finishes the job, update the DB.
*
* Version $Id$
*/
/*
- Copyright (C) 2004-2005 Kern Sibbald
+ Copyright (C) 2004-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
#include "dird.h"
#include "ua.h"
+static char OKbootstrap[] = "3000 OK bootstrap\n";
+
/*
* Called here before the job is run to do the job
* specific setup.
/*
* Get the Pool record -- first apply any level defined pools
*/
- switch (jcr->JobLevel) {
+ switch (jcr->target_jr.JobLevel) {
case L_FULL:
if (jcr->full_pool) {
jcr->pool = jcr->full_pool;
int stat;
const char *Type;
char ed1[100];
+ BSOCK *sd;
switch(jcr->JobType) {
case JT_MIGRATE:
if (!connect_to_storage_daemon(jcr, 10, SDConnectTimeout, 1)) {
return false;
}
+ sd = jcr->store_bsock;
/*
* Now start a job with the Storage daemon
*/
- if (!start_storage_daemon_job(jcr, jcr->storage, jcr->storage)) {
+ if (!start_storage_daemon_job(jcr, jcr->storage, NULL)) {
+ return false;
+ }
+ Dmsg0(150, "Storage daemon connection OK\n");
+
+ if (!send_bootstrap_file(jcr, sd) ||
+ !response(jcr, sd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
return false;
}
+
+
/*
* Now start a Storage daemon message thread
*/
if (!start_storage_daemon_message_thread(jcr)) {
return false;
}
- Dmsg0(150, "Storage daemon connection OK\n");
+
+ if (!bnet_fsend(sd, "run")) {
+ return false;
+ }
/* Pickup Job termination data */
set_jcr_job_status(jcr, JS_Running);
void mac_cleanup(JCR *jcr, int TermCode)
{
char sdt[50], edt[50];
- char ec1[30], ec2[30], ec3[30], ec4[30], ec5[30], compress[50];
- char term_code[100], fd_term_msg[100], sd_term_msg[100];
+ char ec3[30], ec4[30], ec5[30], compress[50];
+ char term_code[100], sd_term_msg[100];
const char *term_msg;
int msg_type;
MEDIA_DBR mr;
switch (jcr->JobStatus) {
case JS_Terminated:
if (jcr->Errors || jcr->SDErrors) {
- term_msg = _("Backup OK -- with warnings");
+ term_msg = _("%s OK -- with warnings");
} else {
- term_msg = _("Backup OK");
+ term_msg = _("%s OK");
}
break;
case JS_FatalError:
case JS_ErrorTerminated:
- term_msg = _("*** Backup Error ***");
+ term_msg = _("*** %s Error ***");
msg_type = M_ERROR; /* Generate error message */
if (jcr->store_bsock) {
bnet_sig(jcr->store_bsock, BNET_TERMINATE);
}
break;
case JS_Canceled:
- term_msg = _("Backup Canceled");
+ term_msg = _("%s Canceled");
if (jcr->store_bsock) {
bnet_sig(jcr->store_bsock, BNET_TERMINATE);
if (jcr->SD_msg_chan) {
}
break;
default:
- term_msg = term_code;
- sprintf(term_code, _("Inappropriate term code: %c\n"), jcr->JobStatus);
+ term_msg = _("Inappropriate %s term code");
break;
}
+ bsnprintf(term_code, sizeof(term_code), term_msg, Type);
bstrftimes(sdt, sizeof(sdt), jcr->jr.StartTime);
bstrftimes(edt, sizeof(edt), jcr->jr.EndTime);
RunTime = jcr->jr.EndTime - jcr->jr.StartTime;
bsnprintf(compress, sizeof(compress), "%.1f %%", (float)compression);
}
}
- jobstatus_to_ascii(jcr->FDJobStatus, fd_term_msg, sizeof(fd_term_msg));
jobstatus_to_ascii(jcr->SDJobStatus, sd_term_msg, sizeof(sd_term_msg));
// bmicrosleep(15, 0); /* for debugging SIGHUP */
" Pool: \"%s\"\n"
" Start time: %s\n"
" End time: %s\n"
-" FD Files Written: %s\n"
" SD Files Written: %s\n"
-" FD Bytes Written: %s\n"
" SD Bytes Written: %s\n"
" Rate: %.1f KB/s\n"
" Software Compression: %s\n"
" Volume Session Id: %d\n"
" Volume Session Time: %d\n"
" Last Volume Bytes: %s\n"
-" Non-fatal FD errors: %d\n"
" SD Errors: %d\n"
-" FD termination status: %s\n"
" SD termination status: %s\n"
" Termination: %s\n\n"),
VERSION,
jcr->pool->hdr.name,
sdt,
edt,
- edit_uint64_with_commas(jcr->jr.JobFiles, ec1),
edit_uint64_with_commas(jcr->SDJobFiles, ec4),
- edit_uint64_with_commas(jcr->jr.JobBytes, ec2),
edit_uint64_with_commas(jcr->SDJobBytes, ec5),
(float)kbps,
compress,
jcr->VolSessionId,
jcr->VolSessionTime,
edit_uint64_with_commas(mr.VolBytes, ec3),
- jcr->Errors,
jcr->SDErrors,
- fd_term_msg,
sd_term_msg,
- term_msg);
+ term_code);
Dmsg0(100, "Leave mac_cleanup()\n");
}
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
break;
}
}
- if (ok) {
- ok = bnet_fsend(sd, "run");
- Dmsg1(100, ">stored: %s\n", sd->msg);
- }
return ok;
}
int max_retry_time, int verbose);
extern bool send_include_list(JCR *jcr);
extern bool send_exclude_list(JCR *jcr);
-extern bool send_bootstrap_file(JCR *jcr);
+extern bool send_bootstrap_file(JCR *jcr, BSOCK *sock);
extern bool send_level_command(JCR *jcr);
extern int get_attributes_and_put_in_catalog(JCR *jcr);
extern int get_attributes_and_compare_to_catalog(JCR *jcr, JobId_t JobId);
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
/* Responses received from File daemon */
static char OKrestore[] = "2000 OK restore\n";
static char OKstore[] = "2000 OK storage\n";
+static char OKbootstrap[] = "2000 OK bootstrap\n";
/*
* Do a restore of the specified files
}
Dmsg0(50, "Storage daemon connection OK\n");
+ if (!bnet_fsend(jcr->store_bsock, "run")) {
+ return false;
+ }
+
/*
* Start conversation with File daemon
*/
/*
* Send the bootstrap file -- what Volumes/files to restore
*/
- if (!send_bootstrap_file(jcr)) {
+ if (!send_bootstrap_file(jcr, fd) ||
+ !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
restore_cleanup(jcr, JS_ErrorTerminated);
return false;
}
/*
* Update Slots corresponding to Volumes in autochanger
*/
-int update_slots(UAContext *ua)
+void update_slots(UAContext *ua)
{
STORE *store;
vol_list_t *vl, *vol_list = NULL;
if (!open_db(ua)) {
- return 1;
+ return;
}
store = get_storage_resource(ua, true/*arg is storage*/);
if (!store) {
- return 1;
+ return;
}
set_storage(ua->jcr, store);
drive = get_storage_drive(ua, store);
Dmsg1(100, "max_slots=%d\n", max_slots);
if (max_slots <= 0) {
bsendmsg(ua, _("No slots in changer to scan.\n"));
- return 1;
+ return;
}
slot_list = (char *)malloc(max_slots+1);
if (!get_user_slot_list(ua, slot_list, max_slots)) {
free(slot_list);
- return 1;
+ return;
}
vol_list = get_vol_list_from_SD(ua, scan);
free(slot_list);
close_sd_bsock(ua);
- return 1;
+ return;
}
* run [job=]<job-name> level=<level-name>
*
* For Restore Jobs
- * run <job-name> jobid=nn
+ * run <job-name>
*
* Returns: 0 on error
* JobId if OK
char *where, *fileset_name, *client_name, *bootstrap;
const char *replace;
char *when, *verify_job_name, *catalog_name;
+ char *migration_job_name;
char *since = NULL;
char *verify_list;
bool cloned = false;
bool kw_ok;
JOB *job = NULL;
JOB *verify_job = NULL;
+ JOB *migration_job = NULL;
STORE *store = NULL;
CLIENT *client = NULL;
FILESET *fileset = NULL;
"since", /* 18 since */
"cloned", /* 19 cloned */
"verifylist", /* 20 verify output list */
+ "migrationjob", /* 21 migration job name */
NULL};
#define YES_POS 14
bootstrap = NULL;
replace = NULL;
verify_job_name = NULL;
+ migration_job_name = NULL;
catalog_name = NULL;
verify_list = NULL;
verify_list = ua->argv[i];
kw_ok = true;
break;
+ case 21: /* Migration Job */
+ if (migration_job_name) {
+ bsendmsg(ua, _("Migration Job specified twice.\n"));
+ return 0;
+ }
+ migration_job_name = ua->argv[i];
+ kw_ok = true;
+ break;
+
default:
break;
verify_job = job->verify_job;
}
+ if (migration_job_name) {
+ migration_job = (JOB *)GetResWithName(R_JOB, migration_job_name);
+ if (!migration_job) {
+ bsendmsg(ua, _("Migration Job \"%s\" not found.\n"), migration_job_name);
+ migration_job = select_job_resource(ua);
+ }
+ } else {
+ migration_job = job->verify_job;
+ }
+
+
/*
* Create JCR to run job. NOTE!!! after this point, free_jcr()
* before returning.
set_jcr_defaults(jcr, job);
jcr->verify_job = verify_job;
+ jcr->migration_job = migration_job;
set_storage(jcr, store);
jcr->client = client;
jcr->fileset = fileset;
jcr->JobPriority);
}
break;
+ case JT_MIGRATE:
+ jcr->JobLevel = L_FULL; /* default level */
+ bsendmsg(ua, _("Run Restore job\n"
+ "JobName: %s\n"
+ "Bootstrap: %s\n"
+ "Where: %s\n"
+ "Replace: %s\n"
+ "FileSet: %s\n"
+ "Client: %s\n"
+ "Storage: %s\n"
+ "Migration Job: %s\n"
+ "When: %s\n"
+ "Catalog: %s\n"
+ "Priority: %d\n"),
+ job->hdr.name,
+ NPRT(jcr->RestoreBootstrap),
+ jcr->where?jcr->where:NPRT(job->RestoreWhere),
+ replace,
+ jcr->fileset->hdr.name,
+ jcr->client->hdr.name,
+ jcr->store->hdr.name,
+ jcr->migration_job->hdr.name,
+ bstrutime(dt, sizeof(dt), jcr->sched_time),
+ jcr->catalog->hdr.name,
+ jcr->JobPriority);
+ break;
default:
bsendmsg(ua, _("Unknown Job Type=%d\n"), jcr->JobType);
goto bail_out;
/* Imported functions */
void set_pooldbr_from_poolres(POOL_DBR *pr, POOL *pool, e_pool_op op);
-int update_slots(UAContext *ua);
+void update_slots(UAContext *ua);
+
/* Forward referenced functions */
POOLMEM *query;
char ed1[130];
bool done = false;
+ int i;
const char *kw[] = {
_("VolStatus"), /* 0 */
_("VolRetention"), /* 1 */
_("AllFromPool"), /* 9 */
NULL };
- for (int i=0; kw[i]; i++) {
+ for (i=0; kw[i]; i++) {
int j;
POOL_DBR pr;
if ((j=find_arg_with_value(ua, kw[i])) > 0) {
}
for ( ; !done; ) {
- if (!select_media_dbr(ua, &mr)) {
- return 0;
- }
bsendmsg(ua, _("Updating Volume \"%s\"\n"), mr.VolumeName);
start_prompt(ua, _("Parameters to modify:\n"));
add_prompt(ua, _("Volume Status"));
add_prompt(ua, _("Volume from Pool"));
add_prompt(ua, _("All Volumes from Pool"));
add_prompt(ua, _("Done"));
- switch (do_prompt(ua, "", _("Select parameter to modify"), NULL, 0)) {
+ i = do_prompt(ua, "", _("Select parameter to modify"), NULL, 0);
+ /* For All Volumes from Pool we don't need a Volume record */
+ if (i != 12) {
+ if (!select_media_dbr(ua, &mr)) { /* Get Volume record */
+ return 0;
+ }
+ }
+ switch (i) {
case 0: /* Volume Status */
/* Modify Volume Status */
bsendmsg(ua, _("Current Volume status is: %s\n"), mr.VolStatus);
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
/* Responses received from File daemon */
static char OKverify[] = "2000 OK verify\n";
static char OKstore[] = "2000 OK storage\n";
+static char OKbootstrap[] = "2000 OK bootstrap\n";
/* Forward referenced functions */
static void prt_fname(JCR *jcr);
return false;
}
Dmsg0(50, "Storage daemon connection OK\n");
+
+ if (!bnet_fsend(jcr->store_bsock, "run")) {
+ return false;
+ }
}
/*
* OK, now connect to the File daemon
/*
* Send the bootstrap file -- what Volumes/files to restore
*/
- if (!send_bootstrap_file(jcr)) {
+ if (!send_bootstrap_file(jcr, fd) ||
+ !response(jcr, fd, OKbootstrap, "Bootstrap", DISPLAY_ERROR)) {
return false;
}
Director {
Name = rufus-dir
DIRport = 8101
- address = rufus
+ address = localhost
Password = UA_password
}
BSOCK *ua; /* User agent */
JOB *job; /* Job resource */
JOB *verify_job; /* Job resource of verify target job */
+ JOB *migration_job; /* Job resource of migration target job */
alist *storage; /* Storage possibilities */
STORE *store; /* Storage daemon selected */
CLIENT *client; /* Client resource */
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
*
* tape label label code = token
*/
-struct s_kw tapelabels[] = {
+static s_kw tapelabels[] = {
{"bacula", B_BACULA_LABEL},
{"ansi", B_ANSI_LABEL},
{"ibm", B_IBM_LABEL},
askdir.c authenticate.c \
block.c butil.c dev.c \
device.c dircmd.c dvd.c ebcdic.c fd_cmds.c job.c \
- label.c match_bsr.c mount.c parse_bsr.c \
+ label.c mac.c match_bsr.c mount.c parse_bsr.c \
pythonsd.c read.c read_record.c record.c \
- reserve.c \
+ reserve.c scan.c \
spool.c status.c stored_conf.c wait.c
SVROBJS = stored.o ansi_label.o \
autochanger.o acquire.o append.o \
askdir.o authenticate.o \
block.o butil.o dev.o \
device.o dircmd.o dvd.o ebcdic.c fd_cmds.o job.o \
- label.o match_bsr.o mount.o parse_bsr.o \
+ label.o mac.o match_bsr.o mount.o parse_bsr.o \
pythonsd.o read.o read_record.o record.o \
- reserve.o \
+ reserve.o scan.o \
spool.o status.o stored_conf.o wait.o
# btape
TAPEOBJS = btape.o block.o butil.o dev.o device.o label.o \
ansi_label.o dvd.o ebcdic.o \
autochanger.o acquire.o mount.o record.o read_record.o \
- stored_conf.o match_bsr.o parse_bsr.o spool.o wait.o
+ stored_conf.o match_bsr.o parse_bsr.o scan.o spool.o wait.o
# bls
BLSOBJS = bls.o block.o butil.o device.o dev.o label.o match_bsr.o \
ansi_label.o dvd.o ebcdic.o \
autochanger.o acquire.o mount.o parse_bsr.o record.o \
- read_record.o stored_conf.o spool.o wait.o
+ read_record.o scan.o stored_conf.o spool.o wait.o
# bextract
BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \
ansi_label.o dvd.o ebcdic.o \
autochanger.o acquire.o mount.o match_bsr.o parse_bsr.o butil.o \
pythonsd.o \
- read_record.o stored_conf.o spool.o wait.o
+ read_record.o scan.o stored_conf.o spool.o wait.o
# bscan
SCNOBJS = bscan.o block.o device.o dev.o label.o \
ansi_label.o dvd.o ebcdic.o \
autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \
- butil.o read_record.o stored_conf.o spool.o wait.o
+ butil.o read_record.o scan.o stored_conf.o spool.o wait.o
# bcopy
COPYOBJS = bcopy.o block.o device.o dev.o label.o \
ansi_label.o dvd.o ebcdic.o \
autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \
- butil.o read_record.o stored_conf.o spool.o wait.o
+ butil.o read_record.o scan.o stored_conf.o spool.o wait.o
* Version $Id$
*/
/*
- Copyright (C) 2002-2005 Kern Sibbald
+ Copyright (C) 2002-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
if (dcr->reserved_device) {
lock_device(dev);
dev->reserved_device--;
+ /* If we set read mode in reserving, remove it */
+ if (dev->can_read()) {
+ dev->clear_read();
+ }
Dmsg1(100, "Dec reserve=%d\n", dev->reserved_device);
dcr->reserved_device = false;
if (dev->num_writers < 0) {
default_path:
tape_previously_mounted = true;
- /* If the device requires mount, close it, so the device can be ejected.
- * FIXME: This should perhaps be done for all devices. */
+ /*
+ * If the device requires mount, close it, so the device can be ejected.
+ */
if (dev->requires_mount()) {
- force_close_device(dev);
+ dev->close();
}
/* Call autochanger only once unless ask_sysop called */
/* If no writers, close if file or !CAP_ALWAYS_OPEN */
if (dev->num_writers == 0 && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
- offline_or_rewind_dev(dev);
- close_device(dev);
+ dev->close();
}
/* Fire off Alert command and include any output */
/* Create Job status for end of session label */
set_jcr_job_status(jcr, ok?JS_Terminated:JS_ErrorTerminated);
- Dmsg1(200, "Write session label JobStatus=%d\n", jcr->JobStatus);
- if ((!ok || job_canceled(jcr)) && dev->VolCatInfo.VolCatName[0] == 0) {
- Pmsg0(000, _("NULL Volume name. This shouldn't happen!!!\n"));
- }
+ Dmsg1(200, "Write EOS label JobStatus=%c\n", jcr->JobStatus);
/*
* If !OK, check if we can still write. This may not be the case
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
}
if (dev->is_dvd()) {
- unmount_dev(dev, 0);
+ unmount_dvd(dev, 0);
}
/*
int rtn_stat = -1; /* error status */
POOLMEM *changer;
+ if (!dev->is_autochanger()) {
+ return 0;
+ }
slot = dcr->VolCatInfo.InChanger ? dcr->VolCatInfo.Slot : 0;
/*
* Handle autoloaders here. If we cannot autoload it, we
dcr->VolCatInfo.Slot = slot; /* slot to be loaded */
changer = edit_device_codes(dcr, changer,
dcr->device->changer_command, "load");
- offline_or_rewind_dev(dev);
- force_close_device(dev);
+ dev->close();
status = run_program(changer, timeout, NULL);
if (status == 0) {
Jmsg(jcr, M_INFO, 0, _("3305 Autochanger \"load slot %d, drive %d\", status is OK.\n"),
dcr->VolCatInfo.Slot = loaded;
changer = edit_device_codes(dcr, changer,
dcr->device->changer_command, "unload");
- offline_or_rewind_dev(dev);
- force_close_device(dev);
+ dev->close();
int stat = run_program(changer, timeout, NULL);
dcr->VolCatInfo.Slot = slot;
if (stat != 0) {
changer_cmd = edit_device_codes(dcr, changer_cmd,
dcr->device->changer_command, "unload");
Dmsg1(200, "Run program=%s\n", changer_cmd);
- offline_or_rewind_dev(dev);
- force_close_device(dev);
+ dev->close();
int stat = run_program(changer_cmd, timeout, NULL);
dcr->VolCatInfo.Slot = save_slot;
dcr->dev = save_dev;
*
*/
/*
- Copyright (C) 2001-2005 Kern Sibbald
+ Copyright (C) 2001-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
*/
if (dev->is_tape() && dev_cap(dev, CAP_BSR)) {
/* Now back up over what we wrote and read the last block */
- if (!bsf_dev(dev, 1)) {
+ if (!dev->bsf(1)) {
berrno be;
ok = false;
Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"),
be.strerror(dev->dev_errno));
}
- if (ok && dev_cap(dev, CAP_TWOEOF) && !bsf_dev(dev, 1)) {
+ if (ok && dev->has_cap(CAP_TWOEOF) && !dev->bsf(1)) {
berrno be;
ok = false;
Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"),
DEVICE *dev = dcr->dev;
Dmsg0(20, "Enter dir_ask_sysop_to_mount_volume\n");
/* Close device so user can use autochanger if desired */
- if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
- offline_dev(dev);
- }
- force_close_device(dev);
+ dev->close();
fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
dcr->VolumeName, dev->print_name());
getchar();
*
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
*/
static void eomcmd()
{
- if (!eod_dev(dev)) {
+ if (!dev->eod()) {
Pmsg1(0, "%s", strerror_dev(dev));
return;
} else {
num = 1;
}
- if (!bsf_dev(dev, num)) {
+ if (!dev->bsf(num)) {
Pmsg1(0, _("Bad status from bsf. ERR=%s\n"), strerror_dev(dev));
} else {
Pmsg2(0, _("Backspaced %d file%s.\n"), num, num==1?"":"s");
if (dev_cap(dev, CAP_TWOEOF)) {
weofcmd();
}
- if (!bsf_dev(dev, 1)) {
+ if (!dev->bsf(1)) {
Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror_dev(dev));
goto bail_out;
}
if (dev_cap(dev, CAP_TWOEOF)) {
- if (!bsf_dev(dev, 1)) {
+ if (!dev->bsf(1)) {
Pmsg1(0, _("Backspace file failed! ERR=%s\n"), strerror_dev(dev));
goto bail_out;
}
if (dev_cap(dev, CAP_TWOEOF)) {
weofcmd();
}
- force_close_device(dev); /* release device */
+ dev->close(); /* release device */
if (!open_the_device()) {
return -1;
}
Dmsg1(100, "Results from loaded query=%s\n", results);
if (loaded) {
dcr->VolCatInfo.Slot = loaded;
- offline_or_rewind_dev(dev);
/* We are going to load a new tape, so close the device */
- force_close_device(dev);
+ dev->close();
Pmsg2(-1, _("3302 Issuing autochanger \"unload %d %d\" command.\n"),
loaded, dev->drive_index);
changer = edit_device_codes(dcr, changer,
changer = edit_device_codes(dcr, changer,
dcr->device->changer_command, "load");
Dmsg1(100, "Changer=%s\n", changer);
- force_close_device(dev);
+ dev->close();
status = run_program(changer, timeout, results);
if (status == 0) {
Pmsg2(-1, _("3303 Autochanger \"load %d %d\" status is OK.\n"),
/* Multiple Volume tape */
/* Close device so user can use autochanger if desired */
if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
- offline_dev(dev);
+ dev->offline();
}
autochanger = autoload_device(dcr, 1, NULL);
if (!autochanger) {
- force_close_device(dev);
+ dev->close();
get_cmd(_("Mount first tape. Press enter when ready: "));
}
free_restore_volume_list(jcr);
set_volume_name("TestVolume1", 1);
jcr->bsr = NULL;
create_restore_volume_list(jcr);
- close_device(dev);
- dev->state &= ~(ST_READ|ST_APPEND);
+ dev->close();
dev->num_writers = 0;
if (!acquire_device_for_read(dcr)) {
Pmsg1(-1, "%s", dev->errmsg);
/* Multiple Volume tape */
/* Close device so user can use autochanger if desired */
if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
- offline_dev(dev);
+ dev->offline();
}
free_restore_volume_list(jcr);
create_restore_volume_list(jcr);
autochanger = autoload_device(dcr, 1, NULL);
if (!autochanger) {
- force_close_device(dev);
+ dev->close();
get_cmd(_("Mount second tape. Press enter when ready: "));
}
if (dcr->VolumeName[0] == 0) {
return dir_ask_sysop_to_create_appendable_volume(dcr);
}
- /* Close device so user can use autochanger if desired */
- if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
- offline_dev(dev);
- }
- force_close_device(dev);
+ dev->close();
Pmsg1(-1, "%s", dev->errmsg); /* print reason */
if (dcr->VolumeName[0] == 0 || strcmp(dcr->VolumeName, "TestVolume2") == 0) {
fprintf(stderr, _("Mount second Volume on device %s and press return when ready: "),
}
/* Close device so user can use autochanger if desired */
if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
- offline_dev(dev);
+ dev->offline();
}
autochanger = autoload_device(dcr, 1, NULL);
if (!autochanger) {
- force_close_device(dev);
+ dev->close();
fprintf(stderr, _("Mount blank Volume on device %s and press return when ready: "),
dev->print_name());
getchar();
set_volume_name("TestVolume2", 2);
jcr->bsr = NULL;
create_restore_volume_list(jcr);
- close_device(dev);
- dev->clear_read();
+ dev->close();
if (!acquire_device_for_read(dcr)) {
Pmsg2(0, _("Cannot open Dev=%s, Vol=%s\n"), dev->print_name(), dcr->VolumeName);
return false;
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
init_dev(JCR *jcr, DEVRES *device)
{
struct stat statp;
- bool tape, fifo;
int errstat;
DCR *dcr = NULL;
DEVICE *dev;
- /* Check that device is available */
- if (stat(device->device_name, &statp) < 0) {
- berrno be;
- Jmsg2(jcr, M_ERROR, 0, _("Unable to stat device %s: ERR=%s\n"),
- device->device_name, be.strerror());
- return NULL;
- }
-
- tape = false;
- fifo = false;
- if (S_ISDIR(statp.st_mode)) {
- tape = false;
- } else if (S_ISCHR(statp.st_mode)) {
- tape = true;
- } else if (S_ISFIFO(statp.st_mode)) {
- fifo = true;
- } else if (!(device->cap_bits & CAP_REQMOUNT)) {
- Jmsg2(jcr, M_ERROR, 0, _("%s is an unknown device type. Must be tape or directory\n"
- " or have RequiresMount=yes for DVD. st_mode=%x\n"),
- device->device_name, statp.st_mode);
- return NULL;
- }
-
- dev = (DEVICE *)get_memory(sizeof(DEVICE));
+ /* If no device type specified, try to guess */
+ if (!device->dev_type) {
+ /* Check that device is available */
+ if (stat(device->device_name, &statp) < 0) {
+ berrno be;
+ Jmsg2(jcr, M_ERROR, 0, _("Unable to stat device %s: ERR=%s\n"),
+ device->device_name, be.strerror());
+ return NULL;
+ }
+ if (S_ISDIR(statp.st_mode)) {
+ device->dev_type = B_FILE_DEV;
+ } else if (S_ISCHR(statp.st_mode)) {
+ device->dev_type = B_TAPE_DEV;
+ } else if (S_ISFIFO(statp.st_mode)) {
+ device->dev_type = B_FILE_DEV;
+ } else if (!(device->cap_bits & CAP_REQMOUNT)) {
+ Jmsg2(jcr, M_ERROR, 0, _("%s is an unknown device type. Must be tape or directory\n"
+ " or have RequiresMount=yes for DVD. st_mode=%x\n"),
+ device->device_name, statp.st_mode);
+ return NULL;
+ } else {
+ device->dev_type = B_DVD_DEV;
+ }
+ }
+
+ dev = (DEVICE *)malloc(sizeof(DEVICE));
memset(dev, 0, sizeof(DEVICE));
dev->state = ST_MALLOC;
dev->max_spool_size = device->max_spool_size;
dev->drive_index = device->drive_index;
dev->autoselect = device->autoselect;
- if (tape) { /* No parts on tapes */
+ dev->dev_type = device->dev_type;
+ if (dev->is_tape()) { /* No parts on tapes */
dev->max_part_size = 0;
- }
- else {
+ } else {
dev->max_part_size = device->max_part_size;
}
/* Sanity check */
}
dev->device = device;
- if (tape) {
- dev->state |= ST_TAPE;
- } else if (fifo) {
- dev->state |= ST_FIFO;
+ if (dev->is_fifo()) {
dev->capabilities |= CAP_STREAM; /* set stream device */
- } else {
- dev->state |= ST_FILE;
}
/* If the device requires mount :
* - Check that the mount point is available
* - Check that (un)mount commands are defined
*/
- if (dev->is_file() && dev->requires_mount()) {
- if (stat(device->mount_point, &statp) < 0) {
+ if ((dev->is_file() || dev->is_dvd()) && dev->requires_mount()) {
+ if (!device->mount_point || stat(device->mount_point, &statp) < 0) {
berrno be;
dev->dev_errno = errno;
Jmsg2(jcr, M_ERROR, 0, _("Unable to stat mount point %s: ERR=%s\n"),
device->mount_point, be.strerror());
return NULL;
}
+ }
+ if (dev->is_dvd()) {
if (!device->mount_command || !device->unmount_command) {
Jmsg0(jcr, M_ERROR_TERM, 0, _("Mount and unmount commands must defined for a device which requires mount.\n"));
}
if (!device->write_part_command) {
Jmsg0(jcr, M_ERROR_TERM, 0, _("Write part command must be defined for a device which requires mount.\n"));
}
- dev->state |= ST_DVD;
}
if (dev->max_block_size > 1000000) {
int
DEVICE::open(DCR *dcr, int omode)
{
+ int preserve = 0;
if (is_open()) {
if (openmode == omode) {
return fd;
::close(fd); /* use system close so correct mode will be used on open */
clear_opened();
Dmsg0(100, "Close fd for mode change.\n");
+ preserve = state & (ST_LABEL|ST_APPEND|ST_READ);
}
}
if (dcr) {
bstrncpy(VolCatInfo.VolCatName, dcr->VolumeName, sizeof(VolCatInfo.VolCatName));
}
- Dmsg4(29, "open dev: tape=%d dev_name=%s vol=%s mode=%s\n", is_tape(),
+ Dmsg4(29, "open dev: type=%d dev_name=%s vol=%s mode=%s\n", dev_type,
print_name(), VolCatInfo.VolCatName, mode_to_str(omode));
state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
label_type = B_BACULA_LABEL;
open_dvd_device(dcr, omode);
} else {
Dmsg1(100, "call open_file_device mode=%s\n", mode_to_str(omode));
- open_file_device(omode);
+ open_file_device(dcr, omode);
+ }
+ state |= preserve; /* reset any important state info */
+ if (preserve) {
+ Dmsg1(000, "preserve=0x%x\n", preserve);
}
return fd;
}
mode = O_CREAT | O_RDWR | O_BINARY;
break;
case OPEN_READ_WRITE:
- if (is_dvd() || is_file()) {
- mode = O_CREAT | O_RDWR | O_BINARY;
- } else {
- mode = O_RDWR | O_BINARY;
- }
+ mode = O_RDWR | O_BINARY;
break;
case OPEN_READ_ONLY:
mode = O_RDONLY | O_BINARY;
/*
* Open a file device
*/
-void DEVICE::open_file_device(int omode)
+void DEVICE::open_file_device(DCR *dcr, int omode)
{
POOL_MEM archive_name(PM_FNAME);
/*
* Handle opening of File Archive (not a tape)
*/
- Dmsg3(29, "Enter: open_file_dev: %s dev=%s mode=%s\n", is_dvd()?"DVD":"disk",
- archive_name.c_str(), mode_to_str(omode));
if (VolCatInfo.VolCatName[0] == 0) {
Mmsg(errmsg, _("Could not open file device %s. No Volume name given.\n"),
pm_strcat(archive_name, "/");
}
pm_strcat(archive_name, VolCatInfo.VolCatName);
+
+ mount(1); /* do mount if required */
- Dmsg3(29, "open dev: %s dev=%s mode=%s\n", is_dvd()?"DVD":"disk",
- archive_name.c_str(), mode_to_str(omode));
openmode = omode;
- Dmsg2(100, "openmode=%d %s\n", openmode, mode_to_str(openmode));
-
set_mode(omode);
/* If creating file, give 0640 permissions */
- Dmsg3(29, "mode=%s open(%s, 0x%x, 0640)\n", mode_to_str(omode),
+ Dmsg3(29, "open disk: mode=%s open(%s, 0x%x, 0640)\n", mode_to_str(omode),
archive_name.c_str(), mode);
/* Use system open() */
if ((fd = ::open(archive_name.c_str(), mode, 0640)) < 0) {
dev_errno = 0;
update_pos_dev(this); /* update position */
}
- Dmsg5(29, "open dev: %s fd=%d opened, part=%d/%d, part_size=%u\n",
- is_dvd()?"DVD":"disk", fd, part, num_parts,
- part_size);
+ Dmsg4(29, "open dev: disk fd=%d opened, part=%d/%d, part_size=%u\n",
+ fd, part, num_parts, part_size);
}
/*
- * Open a DVD device. N.B. at this point, dcr->VolCatInfo.VolCatName (NB:??? I think it's VolCatInfo.VolCatName that is right)
+ * Open a DVD device. N.B. at this point, dcr->VolCatInfo.VolCatName
+ * (NB:??? I think it's VolCatInfo.VolCatName that is right)
* has the desired Volume name, but there is NO assurance that
* any other field of VolCatInfo is correct.
*/
dcr->dev->num_parts = dcr->VolCatInfo.VolCatParts;
}
- if (mount_dev(this, 1)) {
+ if (mount_dvd(this, 1)) {
if ((num_parts == 0) && (!truncating)) {
/* If we can mount the device, and we are not truncating the DVD, we usually want to abort. */
/* There is one exception, if there is only one 0-sized file on the DVD, with the right volume name,
- * we continue (it's the method used by truncate_dvd_dev to truncate a volume). */
+ * we continue (it's the method used by truncate_dvd to truncate a volume). */
if (!check_can_write_on_non_blank_dvd(dcr)) {
Mmsg(errmsg, _("The media in the device %s is not empty, please blank it before writing anything to it.\n"), print_name());
Emsg0(M_FATAL, 0, errmsg);
- unmount_dev(this, 1); /* Unmount the device, so the operator can change it. */
+ unmount_dvd(this, 1); /* Unmount the device, so the operator can change it. */
clear_opened();
return;
}
}
- }
- else {
+ } else {
/* We cannot mount the device */
if (num_parts == 0) {
/* Run free space, check there is a media. */
* Returns: true on succes
* false on error
*/
-bool
-eod_dev(DEVICE *dev)
+bool DEVICE::eod()
{
struct mtop mt_com;
struct mtget mt_stat;
bool ok = true;
off_t pos;
- if (dev->fd < 0) {
- dev->dev_errno = EBADF;
- Mmsg1(dev->errmsg, _("Bad call to eod_dev. Device %s not open\n"),
- dev->print_name());
+ if (fd < 0) {
+ dev_errno = EBADF;
+ Mmsg1(errmsg, _("Bad call to eod_dev. Device %s not open\n"), print_name());
return false;
}
#if defined (__digital__) && defined (__unix__)
- return dev->fsf(dev->VolCatInfo.VolCatFiles);
+ return fsf(VolCatInfo.VolCatFiles);
#endif
Dmsg0(29, "eod_dev\n");
- if (dev->at_eot()) {
+ if (at_eot()) {
return true;
}
- dev->state &= ~(ST_EOF); /* remove EOF flags */
- dev->block_num = dev->file = 0;
- dev->file_size = 0;
- dev->file_addr = 0;
- if (dev->state & (ST_FIFO | ST_PROG)) {
+ state &= ~(ST_EOF); /* remove EOF flags */
+ block_num = file = 0;
+ file_size = 0;
+ file_addr = 0;
+ if (is_fifo() || is_prog()) {
return true;
}
- if (!dev->is_tape()) {
- pos = lseek_dev(dev, (off_t)0, SEEK_END);
+ if (!is_tape()) {
+ pos = lseek_dev(this, (off_t)0, SEEK_END);
// Dmsg1(100, "====== Seek to %lld\n", pos);
if (pos >= 0) {
- update_pos_dev(dev);
- dev->state |= ST_EOT;
+ update_pos_dev(this);
+ state |= ST_EOT;
return true;
}
- dev->dev_errno = errno;
+ dev_errno = errno;
berrno be;
- Mmsg2(dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
+ Mmsg2(errmsg, _("lseek_dev error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
return false;
}
#ifdef MTEOM
- if (dev_cap(dev, CAP_FASTFSF) && !dev_cap(dev, CAP_EOM)) {
+ if (has_cap(CAP_FASTFSF) && !has_cap(CAP_EOM)) {
Dmsg0(100,"Using FAST FSF for EOM\n");
/* If unknown position, rewind */
- if (!dev_get_os_pos(dev, &mt_stat)) {
- if (!dev->rewind(NULL)) {
+ if (!dev_get_os_pos(this, &mt_stat)) {
+ if (!rewind(NULL)) {
return false;
}
}
}
}
- if (dev_cap(dev, CAP_MTIOCGET) && (dev_cap(dev, CAP_FASTFSF) || dev_cap(dev, CAP_EOM))) {
- if (dev_cap(dev, CAP_EOM)) {
+ if (has_cap(CAP_MTIOCGET) && (has_cap(CAP_FASTFSF) || has_cap(CAP_EOM))) {
+ if (has_cap(CAP_EOM)) {
Dmsg0(100,"Using EOM for EOM\n");
mt_com.mt_op = MTEOM;
mt_com.mt_count = 1;
}
- if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ if (ioctl(fd, MTIOCTOP, (char *)&mt_com) < 0) {
berrno be;
- clrerror_dev(dev, mt_com.mt_op);
+ clrerror_dev(this, mt_com.mt_op);
Dmsg1(50, "ioctl error: %s\n", be.strerror());
- update_pos_dev(dev);
- Mmsg2(dev->errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
+ update_pos_dev(this);
+ Mmsg2(errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
return false;
}
- if (!dev_get_os_pos(dev, &mt_stat)) {
+ if (!dev_get_os_pos(this, &mt_stat)) {
berrno be;
- clrerror_dev(dev, -1);
- Mmsg2(dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
+ clrerror_dev(this, -1);
+ Mmsg2(errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
return false;
}
Dmsg2(100, "EOD file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
- dev->set_ateof();
- dev->file = mt_stat.mt_fileno;
+ set_ateof();
+ file = mt_stat.mt_fileno;
} else {
#else
{
/*
* Rewind then use FSF until EOT reached
*/
- if (!dev->rewind(NULL)) {
+ if (!rewind(NULL)) {
return false;
}
/*
* Move file by file to the end of the tape
*/
int file_num;
- for (file_num=dev->file; !dev->at_eot(); file_num++) {
+ for (file_num=file; !at_eot(); file_num++) {
Dmsg0(200, "eod_dev: doing fsf 1\n");
- if (!dev->fsf(1)) {
+ if (!fsf(1)) {
Dmsg0(200, "fsf error.\n");
return false;
}
/*
* Avoid infinite loop by ensuring we advance.
*/
- if (file_num == (int)dev->file) {
+ if (file_num == (int)file) {
struct mtget mt_stat;
Dmsg1(100, "fsf did not advance from file %d\n", file_num);
- dev->set_ateof();
- if (dev_get_os_pos(dev, &mt_stat)) {
- Dmsg2(100, "Adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno);
- dev->file = mt_stat.mt_fileno;
+ set_ateof();
+ if (dev_get_os_pos(this, &mt_stat)) {
+ Dmsg2(100, "Adjust file from %d to %d\n", file , mt_stat.mt_fileno);
+ file = mt_stat.mt_fileno;
}
break;
}
* MTEOM, so we must backup so that appending overwrites
* the second EOF.
*/
- if (dev_cap(dev, CAP_BSFATEOM)) {
+ if (has_cap(CAP_BSFATEOM)) {
struct mtget mt_stat;
/* Backup over EOF */
- ok = bsf_dev(dev, 1);
+ ok = bsf(1);
/* If BSF worked and fileno is known (not -1), set file */
- if (dev_get_os_pos(dev, &mt_stat)) {
- Dmsg2(100, "BSFATEOF adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno);
- dev->file = mt_stat.mt_fileno;
+ if (dev_get_os_pos(this, &mt_stat)) {
+ Dmsg2(100, "BSFATEOF adjust file from %d to %d\n", file , mt_stat.mt_fileno);
+ file = mt_stat.mt_fileno;
} else {
- dev->file++; /* wing it -- not correct on all OSes */
+ file++; /* wing it -- not correct on all OSes */
}
} else {
- update_pos_dev(dev); /* update position */
+ update_pos_dev(this); /* update position */
}
- Dmsg1(200, "EOD dev->file=%d\n", dev->file);
+ Dmsg1(200, "EOD dev->file=%d\n", file);
return ok;
}
Pmsg0(-20, " IM_REP_EN");
}
#endif /* !SunOS && !OSF */
- if (dev_cap(dev, CAP_MTIOCGET)) {
+ if (dev->has_cap(CAP_MTIOCGET)) {
Pmsg2(-20, _(" file=%d block=%d\n"), mt_stat.mt_fileno, mt_stat.mt_blkno);
} else {
Pmsg2(-20, _(" file=%d block=%d\n"), -1, -1);
* Returns: true on success
* false on failure
*/
-bool offline_dev(DEVICE *dev)
+bool DEVICE::offline()
{
struct mtop mt_com;
- if (!dev || dev->fd < 0 || !dev->is_tape()) {
+ if (!is_tape()) {
return true; /* device not open */
}
- dev->state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */
- dev->block_num = dev->file = 0;
- dev->file_size = 0;
- dev->file_addr = 0;
- dev->part = 0;
+ state &= ~(ST_APPEND|ST_READ|ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */
+ block_num = file = 0;
+ file_size = 0;
+ file_addr = 0;
+ part = 0;
#ifdef MTUNLOCK
mt_com.mt_op = MTUNLOCK;
mt_com.mt_count = 1;
- ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+ ioctl(fd, MTIOCTOP, (char *)&mt_com);
#endif
mt_com.mt_op = MTOFFL;
mt_com.mt_count = 1;
- if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
+ if (ioctl(fd, MTIOCTOP, (char *)&mt_com) < 0) {
berrno be;
- dev->dev_errno = errno;
- Mmsg2(dev->errmsg, _("ioctl MTOFFL error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
+ dev_errno = errno;
+ Mmsg2(errmsg, _("ioctl MTOFFL error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
return false;
}
- Dmsg1(100, "Offlined device %s\n", dev->print_name());
+ Dmsg1(100, "Offlined device %s\n", print_name());
return true;
}
-bool offline_or_rewind_dev(DEVICE *dev)
+bool DEVICE::offline_or_rewind()
{
- if (dev->fd < 0) {
+ if (fd < 0) {
return false;
}
- if (dev_cap(dev, CAP_OFFLINEUNMOUNT)) {
- return offline_dev(dev);
+ if (has_cap(CAP_OFFLINEUNMOUNT)) {
+ return offline();
} else {
/*
* Note, this rewind probably should not be here (it wasn't
* such as backspacing after writing and EOF. If it is not
* done, all future references to the drive get and I/O error.
*/
- clrerror_dev(dev, MTREW);
- return dev->rewind(NULL);
+ clrerror_dev(this, MTREW);
+ return rewind(NULL);
}
}
* the SCSI driver will ensure that we do not
* forward space past the end of the medium.
*/
- if (dev_cap(this, CAP_FSF) && dev_cap(this, CAP_MTIOCGET) && dev_cap(this, CAP_FASTFSF)) {
+ if (has_cap(CAP_FSF) && has_cap(CAP_MTIOCGET) && has_cap(CAP_FASTFSF)) {
mt_com.mt_op = MTFSF;
mt_com.mt_count = num;
stat = ioctl(fd, MTIOCTOP, (char *)&mt_com);
* is the only way we can be sure that we don't read
* two consecutive EOF marks, which means End of Data.
*/
- } else if (dev_cap(this, CAP_FSF)) {
+ } else if (has_cap(CAP_FSF)) {
POOLMEM *rbuf;
int rbuf_len;
Dmsg0(200, "FSF has cap_fsf\n");
* Returns: false on failure
* true on success
*/
-bool
-bsf_dev(DEVICE *dev, int num)
+bool DEVICE::bsf(int num)
{
struct mtop mt_com;
int stat;
- if (dev->fd < 0) {
- dev->dev_errno = EBADF;
- Mmsg0(dev->errmsg, _("Bad call to bsf_dev. Device not open\n"));
- Emsg0(M_FATAL, 0, dev->errmsg);
+ if (fd < 0) {
+ dev_errno = EBADF;
+ Mmsg0(errmsg, _("Bad call to bsf. Device not open\n"));
+ Emsg0(M_FATAL, 0, errmsg);
return false;
}
- if (!dev->is_tape()) {
- Mmsg1(dev->errmsg, _("Device %s cannot BSF because it is not a tape.\n"),
- dev->print_name());
+ if (!is_tape()) {
+ Mmsg1(errmsg, _("Device %s cannot BSF because it is not a tape.\n"),
+ print_name());
return false;
}
- Dmsg0(29, "bsf_dev\n");
- dev->state &= ~(ST_EOT|ST_EOF);
- dev->file -= num;
- dev->file_addr = 0;
- dev->file_size = 0;
+ Dmsg0(29, "bsf\n");
+ state &= ~(ST_EOT|ST_EOF);
+ file -= num;
+ file_addr = 0;
+ file_size = 0;
mt_com.mt_op = MTBSF;
mt_com.mt_count = num;
- stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+ stat = ioctl(fd, MTIOCTOP, (char *)&mt_com);
if (stat < 0) {
berrno be;
- clrerror_dev(dev, MTBSF);
- Mmsg2(dev->errmsg, _("ioctl MTBSF error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
+ clrerror_dev(this, MTBSF);
+ Mmsg2(errmsg, _("ioctl MTBSF error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
}
- update_pos_dev(dev);
+ update_pos_dev(this);
return stat == 0;
}
if (!is_tape()) {
return false;
}
- if (!dev_cap(this, CAP_FSR)) {
+ if (!has_cap(CAP_FSR)) {
Mmsg1(errmsg, _("ioctl MTFSR not permitted on %s.\n"), print_name());
return false;
}
return false;
}
- if (!dev_cap(dev, CAP_BSR)) {
+ if (!dev->has_cap(CAP_BSR)) {
Mmsg1(dev->errmsg, _("ioctl MTBSR not permitted on %s.\n"), dev->print_name());
return false;
}
}
if (block < dev->block_num) {
Dmsg2(100, "wanted_blk=%d at_blk=%d\n", block, dev->block_num);
- Dmsg0(100, "bsf_dev 1\n");
- bsf_dev(dev, 1);
+ Dmsg0(100, "bsf 1\n");
+ dev->bsf(1);
Dmsg0(100, "fsf_dev 1\n");
dev->fsf(1);
Dmsg2(100, "wanted_blk=%d at_blk=%d\n", block, dev->block_num);
}
- if (dev_cap(dev, CAP_POSITIONBLOCKS) && block > dev->block_num) {
+ if (dev->has_cap(CAP_POSITIONBLOCKS) && block > dev->block_num) {
/* Ignore errors as Bacula can read to the correct block */
Dmsg1(100, "fsr %d\n", block-dev->block_num);
return dev->fsr(block-dev->block_num);
return 1;
}
-static void do_close(DEVICE *dev)
+/*
+ * Close the device
+ */
+void DEVICE::close()
{
-
- Dmsg1(100, "really close_dev %s\n", dev->print_name());
- if (dev->fd >= 0) {
- ::close(dev->fd);
+ Dmsg1(100, "close_dev %s\n", print_name());
+ if (has_cap(CAP_OFFLINEUNMOUNT)) {
+ offline();
+ }
+ if (fd >= 0) {
+ ::close(fd);
+ } else {
+ return; /* already closed */
}
- if (!unmount_dev(dev, 1)) {
- Dmsg1(0, "Cannot unmount device %s.\n", dev->print_name());
+ if (is_dvd() && !unmount_dvd(this, 1)) {
+ Dmsg1(0, "Cannot unmount device %s.\n", print_name());
}
/* Remove the last part file if it is empty */
- if (dev->num_parts > 0) {
+ if (num_parts > 0) {
struct stat statp;
POOL_MEM archive_name(PM_FNAME);
- dev->part = dev->num_parts;
- Dmsg1(100, "Call make_dvd_filename. Vol=%s\n", dev->VolCatInfo.VolCatName);
- make_spooled_dvd_filename(dev, archive_name);
+ part = num_parts;
+ Dmsg1(100, "Call make_dvd_filename. Vol=%s\n", VolCatInfo.VolCatName);
+ make_spooled_dvd_filename(this, archive_name);
/* Check that the part file is empty */
if ((stat(archive_name.c_str(), &statp) == 0) && (statp.st_size == 0)) {
Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
}
/* Clean up device packet so it can be reused */
- dev->clear_opened();
- dev->state &= ~(ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF);
- dev->label_type = B_BACULA_LABEL;
- dev->file = dev->block_num = 0;
- dev->file_size = 0;
- dev->file_addr = 0;
- dev->part = 0;
- dev->num_parts = 0;
- dev->part_size = 0;
- dev->part_start = 0;
- dev->EndFile = dev->EndBlock = 0;
- memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
- free_volume(dev);
- memset(&dev->VolHdr, 0, sizeof(dev->VolHdr));
- if (dev->tid) {
- stop_thread_timer(dev->tid);
- dev->tid = 0;
- }
- dev->openmode = 0;
+ clear_opened();
+ state &= ~(ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF);
+ label_type = B_BACULA_LABEL;
+ file = block_num = 0;
+ file_size = 0;
+ file_addr = 0;
+ part = 0;
+ num_parts = 0;
+ part_size = 0;
+ part_start = 0;
+ EndFile = EndBlock = 0;
+ memset(&VolCatInfo, 0, sizeof(VolCatInfo));
+ free_volume(this);
+ memset(&VolHdr, 0, sizeof(VolHdr));
+ if (tid) {
+ stop_thread_timer(tid);
+ tid = 0;
+ }
+ openmode = 0;
}
-/*
- * Close the device
- */
-void DEVICE::close()
-{
- do_close(this);
-}
-bool truncate_dev(DCR *dcr) /* We need the DCR for DVD-writing */
+bool DEVICE::truncate(DCR *dcr) /* We need the DCR for DVD-writing */
{
- DEVICE *dev = dcr->dev;
-
- Dmsg1(100, "truncate_dev %s\n", dev->print_name());
- if (dev->is_tape()) {
+ Dmsg1(100, "truncate_dev %s\n", print_name());
+ if (is_tape()) {
return true; /* we don't really truncate tapes */
/* maybe we should rewind and write and eof ???? */
}
- if (dev->is_dvd()) {
- return truncate_dvd_dev(dcr);
+ if (is_dvd()) {
+ return truncate_dvd(dcr);
}
- if (ftruncate(dev->fd, 0) != 0) {
+ if (ftruncate(fd, 0) != 0) {
berrno be;
- Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
- dev->print_name(), be.strerror());
+ Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"),
+ print_name(), be.strerror());
+ return false;
+ }
+ return true;
+}
+
+/* Mount the device.
+ * If timeout, wait until the mount command returns 0.
+ * If !timeout, try to mount the device only once.
+ */
+bool DEVICE::mount(int timeout)
+{
+ Dmsg0(90, "Enter mount\n");
+ if (is_mounted()) {
+ return true;
+ } else if (requires_mount()) {
+ return do_mount(1, timeout);
+ }
+ return true;
+}
+
+/* Unmount the device
+ * If timeout, wait until the unmount command returns 0.
+ * If !timeout, try to unmount the device only once.
+ */
+bool DEVICE::unmount(int timeout)
+{
+ Dmsg0(90, "Enter unmount_dvd\n");
+ if (is_mounted()) {
+ return do_mount(0, timeout);
+ }
+ return true;
+}
+
+/* (Un)mount the device */
+bool DEVICE::do_mount(int mount, int dotimeout)
+{
+ POOL_MEM ocmd(PM_FNAME);
+ POOLMEM *results;
+ char *icmd;
+ int status, timeout;
+
+ sm_check(__FILE__, __LINE__, false);
+ if (mount) {
+ if (is_mounted()) {
+ Dmsg0(200, "======= mount=1\n");
+ return true;
+ }
+ icmd = device->mount_command;
+ } else {
+ if (!is_mounted()) {
+ Dmsg0(200, "======= mount=0\n");
+ return true;
+ }
+ icmd = device->unmount_command;
+ }
+
+ edit_mount_codes(ocmd, icmd);
+
+ Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!is_mounted());
+
+ if (dotimeout) {
+ /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
+ timeout = 1;
+ } else {
+ timeout = 0;
+ }
+ results = get_memory(2000);
+ results[0] = 0;
+ /* If busy retry each second */
+ while ((status = run_program_full_output(ocmd.c_str(),
+ max_open_wait/2, results)) != 0) {
+ /* Doesn't work with internationalisation (This is not a problem) */
+ if (fnmatch("*is already mounted on", results, 0) == 0) {
+ break;
+ }
+ if (timeout-- > 0) {
+ /* Sometimes the device cannot be mounted because it is already mounted.
+ * Try to unmount it, then remount it */
+ if (mount) {
+ Dmsg1(400, "Trying to unmount the device %s...\n", print_name());
+ do_mount(0, 0);
+ }
+ bmicrosleep(1, 0);
+ continue;
+ }
+ Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", print_name(), results);
+ Mmsg(errmsg, _("Device %s cannot be mounted. ERR=%s\n"),
+ print_name(), results);
+ /*
+ * Now, just to be sure it is not mounted, try to read the
+ * filesystem.
+ */
+ DIR* dp;
+ struct dirent *entry, *result;
+ int name_max;
+ int count;
+
+ name_max = pathconf(".", _PC_NAME_MAX);
+ if (name_max < 1024) {
+ name_max = 1024;
+ }
+
+ if (!(dp = opendir(device->mount_point))) {
+ berrno be;
+ dev_errno = errno;
+ Dmsg3(29, "do_mount: failed to open dir %s (dev=%s), ERR=%s\n",
+ device->mount_point, print_name(), be.strerror());
+ goto get_out;
+ }
+
+ entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
+ count = 0;
+ while (1) {
+ if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
+ dev_errno = EIO;
+ Dmsg2(129, "do_mount: failed to find suitable file in dir %s (dev=%s)\n",
+ device->mount_point, print_name());
+ break;
+ }
+ if ((strcmp(result->d_name, ".")) && (strcmp(result->d_name, "..")) && (strcmp(result->d_name, ".keep"))) {
+ count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
+ break;
+ } else {
+ Dmsg2(129, "do_mount: ignoring %s in %s\n", result->d_name, device->mount_point);
+ }
+ }
+ free(entry);
+ closedir(dp);
+
+ Dmsg1(29, "do_mount: got %d files in the mount point (not counting ., .. and .keep)\n", count);
+
+ if (count > 0) {
+ mount = 1; /* If we got more than ., .. and .keep */
+ break; /* there must be something mounted */
+ }
+get_out:
+ set_mounted(false);
+ sm_check(__FILE__, __LINE__, false);
+ free_pool_memory(results);
+ Dmsg0(200, "============ mount=0\n");
return false;
}
+
+ set_mounted(mount); /* set/clear mounted flag */
+ free_pool_memory(results);
+ Dmsg1(200, "============ mount=%d\n", mount);
return true;
}
+/*
+ * Edit codes into (Un)MountCommand, Write(First)PartCommand
+ * %% = %
+ * %a = archive device name
+ * %e = erase (set if cannot mount and first part)
+ * %n = part number
+ * %m = mount point
+ * %v = last part name
+ *
+ * omsg = edited output message
+ * imsg = input string containing edit codes (%x)
+ *
+ */
+void DEVICE::edit_mount_codes(POOL_MEM &omsg, const char *imsg)
+{
+ const char *p;
+ const char *str;
+ char add[20];
+
+ POOL_MEM archive_name(PM_FNAME);
+
+ omsg.c_str()[0] = 0;
+ Dmsg1(800, "edit_mount_codes: %s\n", imsg);
+ for (p=imsg; *p; p++) {
+ if (*p == '%') {
+ switch (*++p) {
+ case '%':
+ str = "%";
+ break;
+ case 'a':
+ str = dev_name;
+ break;
+ case 'e':
+ if (num_parts == 0) {
+ str = "1";
+ } else {
+ str = "0";
+ }
+ break;
+ case 'n':
+ bsnprintf(add, sizeof(add), "%d", part);
+ str = add;
+ break;
+ case 'm':
+ str = device->mount_point;
+ break;
+ case 'v':
+ make_spooled_dvd_filename(this, archive_name);
+ str = archive_name.c_str();
+ break;
+ default:
+ add[0] = '%';
+ add[1] = *p;
+ add[2] = 0;
+ str = add;
+ break;
+ }
+ } else {
+ add[0] = *p;
+ add[1] = 0;
+ str = add;
+ }
+ Dmsg1(1900, "add_str %s\n", str);
+ pm_strcat(omsg, (char *)str);
+ Dmsg1(1800, "omsg=%s\n", omsg.c_str());
+ }
+}
+
+
/* Return the resource name for the device */
const char *DEVICE::name() const
{
return;
}
Dmsg1(29, "term_dev: %s\n", dev->print_name());
- do_close(dev);
+ dev->close();
if (dev->dev_name) {
free_memory(dev->dev_name);
dev->dev_name = NULL;
dev->attached_dcrs = NULL;
}
if (dev->state & ST_MALLOC) {
- free_pool_memory((POOLMEM *)dev);
+ free((char *)dev);
}
}
}
mt_com.mt_op = MTSETDRVBUFFER;
mt_com.mt_count = MT_ST_CLEARBOOLEANS;
- if (!dev_cap(dev, CAP_TWOEOF)) {
+ if (!dev->has_cap(CAP_TWOEOF)) {
mt_com.mt_count |= MT_ST_TWO_FM;
}
- if (dev_cap(dev, CAP_EOM)) {
+ if (dev->has_cap(CAP_EOM)) {
mt_com.mt_count |= MT_ST_FAST_MTEOM;
}
if (ioctl(dev->fd, MTIOCTOP, (char *)&mt_com) < 0) {
static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat)
{
- return dev_cap(dev, CAP_MTIOCGET) &&
+ return dev->has_cap(CAP_MTIOCGET) &&
ioctl(dev->fd, MTIOCGET, (char *)mt_stat) == 0 &&
mt_stat->mt_fileno >= 0;
}
OPEN_WRITE_ONLY
};
+/* Device types */
+enum {
+ B_FILE_DEV = 1,
+ B_TAPE_DEV,
+ B_DVD_DEV,
+ B_FIFO_DEV,
+ B_PROG_DEV
+};
+
/* Generic status bits returned from status_dev() */
#define BMT_TAPE (1<<0) /* is tape device */
#define BMT_EOF (1<<1) /* just read EOF */
/* Device state bits */
#define ST_XXXXXX (1<<0) /* was ST_OPENED */
-#define ST_TAPE (1<<1) /* is a tape device */
-#define ST_FILE (1<<2) /* is a file device */
-#define ST_FIFO (1<<3) /* is a fifo device */
-#define ST_DVD (1<<4) /* is a DVD device */
-#define ST_PROG (1<<5) /* is a program device */
+#define ST_XXXXX (1<<1) /* was ST_TAPE */
+#define ST_XXXX (1<<2) /* was ST_FILE */
+#define ST_XXX (1<<3) /* was ST_FIFO */
+#define ST_XX (1<<4) /* was ST_DVD */
+#define ST_X (1<<5) /* was ST_PROG */
+
#define ST_LABEL (1<<6) /* label found */
#define ST_MALLOC (1<<7) /* dev packet malloc'ed in init_dev() */
#define ST_APPEND (1<<8) /* ready for Bacula append */
int dev_errno; /* Our own errno */
int mode; /* read/write modes */
int openmode; /* parameter passed to open_dev (useful to reopen the device) */
+ int dev_type; /* device type */
bool autoselect; /* Autoselect in autochanger */
int label_type; /* Bacula/ANSI/IBM label types */
uint32_t drive_index; /* Autochanger drive index (base 0) */
int num_wait;
/* Methods */
+ int has_cap(int cap) const { return capabilities & cap; }
int is_autochanger() const { return capabilities & CAP_AUTOCHANGER; }
int requires_mount() const { return capabilities & CAP_REQMOUNT; }
- int is_tape() const { return state & ST_TAPE; }
- int is_file() const { return state & ST_FILE; }
- int is_fifo() const { return state & ST_FIFO; }
- int is_dvd() const { return state & ST_DVD; }
+ int is_removable() const { return capabilities & CAP_REM; }
+ int is_tape() const { return dev_type == B_TAPE_DEV; }
+ int is_file() const { return dev_type == B_FILE_DEV; }
+ int is_fifo() const { return dev_type == B_FIFO_DEV; }
+ int is_dvd() const { return dev_type == B_DVD_DEV; }
+ int is_prog() const { return dev_type == B_PROG_DEV; }
int is_open() const { return fd >= 0; }
int is_offline() const { return state & ST_OFFLINE; }
int is_labeled() const { return state & ST_LABEL; }
dev_blocked == BST_WAITING_FOR_SYSOP ||
dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP); };
bool weof() { return !weof_dev(this, 1); };
- bool fsr(int num); /* in dev.c */
- bool fsf(int num); /* in dev.c */
const char *strerror() const;
const char *archive_name() const;
const char *name() const;
void set_eof() { state |= ST_EOF; };
void set_append() { state |= ST_APPEND; };
void set_labeled() { state |= ST_LABEL; };
- void set_read() { state |= ST_READ; };
+ inline void set_read() { state |= ST_READ; };
void set_offline() { state |= ST_OFFLINE; };
void set_mounted() { state |= ST_MOUNTED; };
void set_media() { state |= ST_MEDIA; };
void clear_short_block() { state &= ~ST_SHORT; };
void clear_freespace_ok() { state &= ~ST_FREESPACE_OK; }
- void block(int why); /* in dev.c */
- void unblock(); /* in dev.c */
- void close(); /* in dev.c */
+ void block(int why); /* in dev.c */
+ void unblock(); /* in dev.c */
+ void close(); /* in dev.c */
+ bool truncate(DCR *dcr); /* in dev.c */
int open(DCR *dcr, int mode); /* in dev.c */
- bool rewind(DCR *dcr); /* in dev.c */
-
+ bool rewind(DCR *dcr); /* in dev.c */
+ bool mount(int timeout); /* in dev.c */
+ bool unmount(int timeout); /* in dev.c */
+ void edit_mount_codes(POOL_MEM &omsg, const char *imsg); /* in dev.c */
+ bool offline_or_rewind(); /* in dev.c */
+ bool offline(); /* in dev.c */
+ bool bsf(int count); /* in dev.c */
+ bool eod(); /* in dev.c */
+ bool fsr(int num); /* in dev.c */
+ bool fsf(int num); /* in dev.c */
+ bool scan_dir_for_volume(DCR *dcr); /* in scan.c */
void set_blocked(int block) { dev_blocked = block; };
int get_blocked() const { return dev_blocked; };
bool is_blocked() const { return dev_blocked != BST_NOT_BLOCKED; };
private:
- void set_mode(int omode); /* in dev.c */
+ bool do_mount(int mount, int timeout); /* in dev.c */
+ void set_mode(int omode); /* in dev.c */
void open_tape_device(DCR *dcr, int omode); /* in dev.c */
- void open_file_device(int omode); /* in dev.c */
- void open_dvd_device(DCR *dcr, int omode); /* in dev.c */
- void set_blocking(); /* in dev.c */
+ void open_file_device(DCR *dcr, int omode); /* in dev.c */
+ void open_dvd_device(DCR *dcr, int omode); /* in dev.c */
+ void set_blocking(); /* in dev.c */
};
/* If polling, ignore the error */
/* If DVD, also ignore the error, very often you cannot open the device
* (when there is no DVD, or when the one inserted is a wrong one) */
- if ((!dev->poll) && (!dev->is_dvd())) {
+ if (!dev->poll && !dev->is_dvd() && !dev->is_removable()) {
Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device %s: ERR=%s\n"),
dev->print_name(), strerror_dev(dev));
Pmsg2(000, _("Unable to open archive %s: ERR=%s\n"),
return true;
}
-/*
- * Release any Volume attached to this device
- * then close the device.
- */
-void close_device(DEVICE *dev)
-{
- free_volume(dev);
- dev->close();
-}
-
-/*
- */
-void force_close_device(DEVICE *dev)
-{
- if (!dev || dev->fd < 0) {
- return;
- }
- Dmsg1(29, "Force close_dev %s\n", dev->print_name());
- free_volume(dev);
- dev->close();
-}
void dev_lock(DEVICE *dev)
*
*/
/*
- Copyright (C) 2001-2005 Kern Sibbald
+ Copyright (C) 2001-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
static bool cancel_cmd(JCR *cjcr);
static bool mount_cmd(JCR *jcr);
static bool unmount_cmd(JCR *jcr);
+static bool bootstrap_cmd(JCR *jcr);
static bool changer_cmd(JCR *sjcr);
static bool do_label(JCR *jcr, int relabel);
static DCR *find_device(JCR *jcr, POOL_MEM &dev_name, int drive);
dev = dcr->dev;
P(dev->mutex); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
- Dmsg0(400, "Can relabel. Device is not open\n");
+ Dmsg1(400, "Can %slabel. Device is not open\n", relabel?"re":"");
label_volume_if_ok(dcr, oldname, newname, poolname, slot, relabel);
- force_close_device(dev);
+ dev->close();
/* Under certain "safe" conditions, we can steal the lock */
} else if (dev->can_steal_lock()) {
Dmsg0(400, "Can relabel. can_steal_lock\n");
bsteal_lock_t hold;
DEVICE *dev = dcr->dev;
int label_status;
+ int mode;
steal_device_lock(dev, &hold, BST_WRITING_LABEL);
Dmsg1(100, "Stole device %s lock, writing label.\n", dev->print_name());
- /* Note, try_autoload_device() opens the device */
if (!try_autoload_device(dcr->jcr, slot, newname)) {
goto bail_out; /* error */
}
+ /* Ensure that the device is open -- autoload_device() closes it */
+ if (dev->is_tape()) {
+ mode = OPEN_READ_WRITE;
+ } else {
+ mode = CREATE_READ_WRITE;
+ }
+ if (dev->open(dcr, mode) < 0) {
+ bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"),
+ dev->print_name(), dev->strerror());
+ return;
+ }
+
/* See what we have for a Volume */
label_status = read_dev_volume_label(dcr);
break;
}
}
- foreach_res(changer, R_AUTOCHANGER) {
- /* Find resource, and make sure we were able to open it */
- if (fnmatch(devname.c_str(), changer->hdr.name, 0) == 0) {
- /* Try each device in this AutoChanger */
- foreach_alist(device, changer->device) {
- Dmsg1(100, "Try changer device %s\n", device->hdr.name);
- if (!device->dev) {
- device->dev = init_dev(jcr, device);
- }
- if (!device->dev) {
- Dmsg1(100, "Device %s could not be opened. Skipped\n", devname.c_str());
- Jmsg(jcr, M_WARNING, 0, _("\n"
- " Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
- device->hdr.name, devname.c_str());
- continue;
- }
- if (!device->dev->autoselect) {
- Dmsg1(100, "Device %s not autoselect skipped.\n", devname.c_str());
- continue; /* device is not available */
- }
- if (drive < 0 || drive == (int)device->dev->drive_index) {
- Dmsg1(20, "Found changer device %s\n", device->hdr.name);
- found = true;
- break;
+ if (!found) {
+ foreach_res(changer, R_AUTOCHANGER) {
+ /* Find resource, and make sure we were able to open it */
+ if (fnmatch(devname.c_str(), changer->hdr.name, 0) == 0) {
+ /* Try each device in this AutoChanger */
+ foreach_alist(device, changer->device) {
+ Dmsg1(100, "Try changer device %s\n", device->hdr.name);
+ if (!device->dev) {
+ device->dev = init_dev(jcr, device);
+ }
+ if (!device->dev) {
+ Dmsg1(100, "Device %s could not be opened. Skipped\n", devname.c_str());
+ Jmsg(jcr, M_WARNING, 0, _("\n"
+ " Device \"%s\" in changer \"%s\" requested by DIR could not be opened or does not exist.\n"),
+ device->hdr.name, devname.c_str());
+ continue;
+ }
+ if (!device->dev->autoselect) {
+ Dmsg1(100, "Device %s not autoselect skipped.\n", devname.c_str());
+ continue; /* device is not available */
+ }
+ if (drive < 0 || drive == (int)device->dev->drive_index) {
+ Dmsg1(20, "Found changer device %s\n", device->hdr.name);
+ found = true;
+ break;
+ }
+ Dmsg3(100, "Device %s drive wrong: want=%d got=%d skipping\n",
+ devname.c_str(), drive, (int)device->dev->drive_index);
}
- Dmsg3(100, "Device %s drive wrong: want=%d got=%d skipping\n",
- devname.c_str(), drive, (int)device->dev->drive_index);
+ break; /* we found it but could not open a device */
}
- break; /* we found it but could not open a device */
}
}
if (found) {
- Dmsg1(100, "Found changer device %s\n", device->hdr.name);
+ Dmsg1(100, "Found device %s\n", device->hdr.name);
dcr = new_dcr(jcr, device->dev);
dcr->device = device;
jcr->dcr = dcr;
dev->print_name());
}
} else if (dev->is_dvd()) {
- if (mount_dev(dev, 1)) {
+ if (mount_dvd(dev, 1)) {
bnet_fsend(dir, _("3002 Device %s is mounted.\n"),
dev->print_name());
} else {
Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting,
dev->dev_blocked);
if (!unload_autochanger(jcr->dcr, -1)) {
- offline_or_rewind_dev(dev);
- force_close_device(dev);
+ dev->close();
}
dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP;
bnet_fsend(dir, _("3001 Device %s unmounted.\n"),
dev->dev_blocked = BST_UNMOUNTED;
dev->no_wait_id = 0;
if (!unload_autochanger(jcr->dcr, -1)) {
- offline_or_rewind_dev(dev);
- force_close_device(dev);
+ dev->close();
}
bnet_fsend(dir, _("3002 Device %s unmounted.\n"),
dev->print_name());
}
+static bool bootstrap_cmd(JCR *jcr)
+{
+ return get_bootstrap_file(jcr, jcr->dir_bsock);
+}
/*
* Autochanger command from Director
P(dev->mutex); /* Use P to avoid indefinite block */
if (!dev->is_open()) {
read_volume_label(jcr, dev, Slot);
- force_close_device(dev);
+ dev->close();
/* Under certain "safe" conditions, we can steal the lock */
} else if (dev->can_steal_lock()) {
read_volume_label(jcr, dev, Slot);
return true;
}
+
/*
* Read the tape label
*
{
DCR *dcr = jcr->dcr;
BSOCK *dir = jcr->dir_bsock;
- DEVICE *dev = dcr->dev;
bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName));
dcr->VolCatInfo.Slot = slot;
if (autoload_device(dcr, 0, dir) < 0) { /* autoload if possible */
return false;
}
-
- /* Ensure that the device is open -- autoload_device() closes it */
- if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
- bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"),
- dev->print_name(), dev->strerror());
- return false;
- }
return true;
}
* Version $Id$
*/
/*
- Copyright (C) 2005 Kern Sibbald
+ Copyright (C) 2005-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
#include "stored.h"
/* Forward referenced functions */
-static void edit_device_codes_dev(DEVICE *dev, POOL_MEM &omsg, const char *imsg);
-static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout);
+static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout);
static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
/*
* If timeout, wait until the mount command returns 0.
* If !timeout, try to mount the device only once.
*/
-bool mount_dev(DEVICE* dev, int timeout)
+bool mount_dvd(DEVICE* dev, int timeout)
{
- Dmsg0(90, "Enter mount_dev\n");
+ Dmsg0(90, "Enter mount_dvd\n");
if (dev->is_mounted()) {
return true;
} else if (dev->requires_mount()) {
- return do_mount_dev(dev, 1, timeout);
+ return do_mount_dvd(dev, 1, timeout);
}
return true;
}
* If timeout, wait until the unmount command returns 0.
* If !timeout, try to unmount the device only once.
*/
-bool unmount_dev(DEVICE *dev, int timeout)
+bool unmount_dvd(DEVICE *dev, int timeout)
{
- Dmsg0(90, "Enter unmount_dev\n");
+ if (!dev->is_dvd()) {
+ return true;
+ }
+ Dmsg0(90, "Enter unmount_dvd\n");
if (dev->is_mounted()) {
- return do_mount_dev(dev, 0, timeout);
+ return do_mount_dvd(dev, 0, timeout);
}
return true;
}
/* (Un)mount the device */
-static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout)
+static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout)
{
POOL_MEM ocmd(PM_FNAME);
POOLMEM *results;
icmd = dev->device->unmount_command;
}
- edit_device_codes_dev(dev, ocmd, icmd);
+ dev->edit_mount_codes(ocmd, icmd);
- Dmsg2(200, "do_mount_dev: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
+ Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
if (dotimeout) {
/* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
* Try to unmount it, then remount it */
if (mount) {
Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
- do_mount_dev(dev, 0, 0);
+ do_mount_dvd(dev, 0, 0);
}
bmicrosleep(1, 0);
continue;
DIR* dp;
struct dirent *entry, *result;
int name_max;
- int count = 0;
+ int count;
name_max = pathconf(".", _PC_NAME_MAX);
if (name_max < 1024) {
if (!(dp = opendir(dev->device->mount_point))) {
berrno be;
dev->dev_errno = errno;
- Dmsg3(29, "open_mounted_dev: failed to open dir %s (dev=%s), ERR=%s\n",
+ Dmsg3(29, "do_mount_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
dev->device->mount_point, dev->print_name(), be.strerror());
goto get_out;
}
entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
+ count = 0;
while (1) {
if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
dev->dev_errno = EIO;
- Dmsg2(129, "open_mounted_dev: failed to find suitable file in dir %s (dev=%s)\n",
+ Dmsg2(129, "do_mount_dvd: failed to find suitable file in dir %s (dev=%s)\n",
dev->device->mount_point, dev->print_name());
break;
}
- if ((strcmp(result->d_name, ".")) && (strcmp(result->d_name, "..")) && (strcmp(result->d_name, ".keep"))) {
+ if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
+ strcmp(result->d_name, ".keep")) {
count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
+ break;
}
else {
- Dmsg2(129, "open_mounted_dev: ignoring %s in %s\n",
+ Dmsg2(129, "do_mount_dvd: ignoring %s in %s\n",
result->d_name, dev->device->mount_point);
}
}
free(entry);
closedir(dp);
- Dmsg1(29, "open_mounted_dev: got %d files in the mount point (not counting ., .. and .keep)\n", count);
+ Dmsg1(29, "do_mount_dvd: got %d files in the mount point (not counting ., .. and .keep)\n", count);
if (count > 0) {
mount = 1; /* If we got more than ., .. and .keep */
char ed1[50];
/* The device must be mounted in order to dvd-freespace to work */
- mount_dev(dev, 1);
+ mount_dvd(dev, 1);
sm_check(__FILE__, __LINE__, false);
icmd = dev->device->free_space_command;
return;
}
- edit_device_codes_dev(dev, ocmd, icmd);
+ dev->edit_mount_codes(ocmd, icmd);
Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
* Write a part (Vol, Vol.1, ...) from the spool to the DVD
* This routine does not update the part number, so normally, you
* should call open_next_part()
- * It is also called from truncate_dvd_dev to "blank" the medium, as
+ * It is also called from truncate_dvd to "blank" the medium, as
* well as from block.c when the DVD is full to write the last part.
*/
bool dvd_write_part(DCR *dcr)
Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
icmd = dev->device->write_part_command;
- edit_device_codes_dev(dev, ocmd, icmd);
+ dev->edit_mount_codes(ocmd, icmd);
/*
* original line follows
/* growisofs umounted the device, so remount it (it will update the free space) */
dev->clear_mounted();
- mount_dev(dev, 1);
+ mount_dvd(dev, 1);
Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
sm_check(__FILE__, __LINE__, false);
return ok;
}
-bool truncate_dvd_dev(DCR *dcr) {
+bool truncate_dvd(DCR *dcr) {
DEVICE* dev = dcr->dev;
/* Set num_parts to zero (on disk) */
dcr->VolCatInfo.VolCatParts = 0;
dev->VolCatInfo.VolCatParts = 0;
- Dmsg0(100, "truncate_dvd_dev: Opening first part (1)...\n");
+ Dmsg0(100, "truncate_dvd: Opening first part (1)...\n");
dev->truncating = true;
if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
- Dmsg0(100, "truncate_dvd_dev: Error while opening first part (1).\n");
+ Dmsg0(100, "truncate_dvd: Error while opening first part (1).\n");
dev->truncating = false;
return false;
}
dev->truncating = false;
- Dmsg0(100, "truncate_dvd_dev: Truncating...\n");
+ Dmsg0(100, "truncate_dvd: Truncating...\n");
/* If necessary, truncate it. */
if (ftruncate(dev->fd, 0) != 0) {
dev->fd = -1;
dev->clear_opened();
- Dmsg0(100, "truncate_dvd_dev: Opening first part (2)...\n");
+ Dmsg0(100, "truncate_dvd: Opening first part (2)...\n");
if (!dvd_write_part(dcr)) {
- Dmsg0(100, "truncate_dvd_dev: Error while writing to DVD.\n");
+ Dmsg0(100, "truncate_dvd: Error while writing to DVD.\n");
return false;
}
dev->VolCatInfo.VolCatParts = 0;
if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
- Dmsg0(100, "truncate_dvd_dev: Error while opening first part (2).\n");
+ Dmsg0(100, "truncate_dvd: Error while opening first part (2).\n");
return false;
}
Dmsg2(129, "check_can_write_on_non_blank_dvd: failed to find suitable file in dir %s (dev=%s)\n",
dev->device->mount_point, dev->print_name());
break;
- }
- else {
+ } else {
Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
result->d_name, dev->VolCatInfo.VolCatName);
if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
}
Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %d\n",
filename.c_str(), filestat.st_size);
- matched = (filestat.st_size == 0);
+ matched = filestat.st_size == 0;
}
}
count++;
Dmsg2(29, "check_can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
if (count != 3) {
- /* There is more than 3 files (., .., and the volume file) */
+ /* There are more than 3 files (., .., and the volume file) */
return false;
}
return matched;
}
-
-/*
- * Edit codes into (Un)MountCommand, Write(First)PartCommand
- * %% = %
- * %a = archive device name
- * %e = erase (set if cannot mount and first part)
- * %n = part number
- * %m = mount point
- * %v = last part name
- *
- * omsg = edited output message
- * imsg = input string containing edit codes (%x)
- *
- */
-static void edit_device_codes_dev(DEVICE* dev, POOL_MEM &omsg, const char *imsg)
-{
- const char *p;
- const char *str;
- char add[20];
-
- POOL_MEM archive_name(PM_FNAME);
-
- omsg.c_str()[0] = 0;
- Dmsg1(800, "edit_device_codes: %s\n", imsg);
- for (p=imsg; *p; p++) {
- if (*p == '%') {
- switch (*++p) {
- case '%':
- str = "%";
- break;
- case 'a':
- str = dev->dev_name;
- break;
- case 'e':
- if (dev->num_parts == 0) {
- str = "1";
- } else {
- str = "0";
- }
- break;
- case 'n':
- bsnprintf(add, sizeof(add), "%d", dev->part);
- str = add;
- break;
- case 'm':
- str = dev->device->mount_point;
- break;
- case 'v':
- make_spooled_dvd_filename(dev, archive_name);
- str = archive_name.c_str();
- break;
- default:
- add[0] = '%';
- add[1] = *p;
- add[2] = 0;
- str = add;
- break;
- }
- } else {
- add[0] = *p;
- add[1] = 0;
- str = add;
- }
- Dmsg1(1900, "add_str %s\n", str);
- pm_strcat(omsg, (char *)str);
- Dmsg1(1800, "omsg=%s\n", omsg.c_str());
- }
-}
*
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
static bool read_open_session(JCR *jcr);
static bool read_data_cmd(JCR *jcr);
static bool read_close_session(JCR *jcr);
+static bool bootstrap_cmd(JCR *jcr);
/* Exported function */
-bool bootstrap_cmd(JCR *jcr);
+bool get_bootstrap_file(JCR *jcr, BSOCK *bs);
struct s_cmds {
const char *cmd;
/* Information sent to the Director */
static char Job_start[] = "3010 Job %s start\n";
-static char Job_end[] =
+char Job_end[] =
"3099 Job %s end JobStatus=%d JobFiles=%d JobBytes=%s\n";
/*
return true;
}
-bool bootstrap_cmd(JCR *jcr)
+static bool bootstrap_cmd(JCR *jcr)
+{
+ return get_bootstrap_file(jcr, jcr->file_bsock);
+}
+
+bool get_bootstrap_file(JCR *jcr, BSOCK *sock)
{
- BSOCK *fd = jcr->file_bsock;
POOLMEM *fname = get_pool_memory(PM_FNAME);
FILE *bs;
bool ok = false;
jcr->RestoreBootstrap, strerror(errno));
goto bail_out;
}
- while (bnet_recv(fd) >= 0) {
- Dmsg1(400, "stored<filed: bootstrap file %s", fd->msg);
- fputs(fd->msg, bs);
+ while (bnet_recv(sock) >= 0) {
+ Dmsg1(400, "stored<filed: bootstrap file %s", sock->msg);
+ fputs(sock->msg, bs);
}
fclose(bs);
jcr->bsr = parse_bsr(jcr, jcr->RestoreBootstrap);
free_pool_memory(jcr->RestoreBootstrap);
jcr->RestoreBootstrap = NULL;
if (!ok) {
- bnet_fsend(fd, ERROR_bootstrap);
+ bnet_fsend(sock, ERROR_bootstrap);
return false;
}
- return bnet_fsend(fd, OK_bootstrap);
+ return bnet_fsend(sock, OK_bootstrap);
}
*
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
/* Imported functions */
extern uint32_t newVolSessionId();
+extern bool do_mac(JCR *jcr);
/* Requests from the Director daemon */
static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
case JT_COPY:
case JT_ARCHIVE:
jcr->authenticated = true;
- run_job(jcr);
+ do_mac(jcr);
return false;
}
Dmsg1(100, "<dird: %s\n", dir->msg);
if (ok) {
unbash_spaces(dev_name);
-// LockRes();
foreach_res(device, R_DEVICE) {
/* Find resource, and make sure we were able to open it */
if (fnmatch(dev_name.c_str(), device->hdr.name, 0) == 0) {
if (!device->dev) {
break;
}
-// UnlockRes();
ok = dir_update_device(jcr, device->dev);
if (ok) {
ok = bnet_fsend(dir, OK_query);
foreach_res(changer, R_AUTOCHANGER) {
/* Find resource, and make sure we were able to open it */
if (fnmatch(dev_name.c_str(), changer->hdr.name, 0) == 0) {
-// UnlockRes();
if (!changer->device || changer->device->size() == 0) {
continue; /* no devices */
}
}
}
/* If we get here, the device/autochanger was not found */
-// UnlockRes();
unbash_spaces(dir->msg);
pm_strcpy(jcr->errmsg, dir->msg);
bnet_fsend(dir, NO_device, dev_name.c_str());
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
dev->VolHdr.VolumeName[0]?dev->VolHdr.VolumeName:"*NULL*");
if (!dev->is_open()) {
- Emsg0(M_ABORT, 0, _("BAD call to read_dev_volume_label\n"));
+ if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
+ return VOL_IO_ERROR;
+ }
}
if (dev->is_labeled()) { /* did we already read label? */
/* Compare Volume Names allow special wild card */
* after the label will be destroyed,
* in fact, we write the label 5 times !!!!
*
- * This routine expects that open_device() was previously called.
- *
* This routine should be used only when labeling a blank tape.
*/
bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName)
empty_block(dcr->block);
if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
- goto bail_out;
+ /* If device is not tape, attempt to create it */
+ if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
+ goto bail_out;
+ }
}
Dmsg1(150, "Label type=%d\n", dev->label_type);
if (!dev->rewind(dcr)) {
dev->print_name(), strerror_dev(dev));
}
if (recycle) {
- if (!truncate_dev(dcr)) {
+ if (!dev->truncate(dcr)) {
Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device %s: ERR=%s\n"),
dev->print_name(), strerror_dev(dev));
}
* Version $Id$
*/
/*
- Copyright (C) 2002-2005 Kern Sibbald
+ Copyright (C) 2002-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
#include "stored.h" /* pull in Storage Deamon headers */
static void mark_volume_not_inchanger(DCR *dcr);
+static int try_autolabel(DCR *dcr);
+
+enum {
+ try_next_vol = 1,
+ try_read_vol,
+ try_error,
+ try_default
+};
/*
* If release is set, we rewind the current volume,
DEVICE *dev = dcr->dev;
JCR *jcr = dcr->jcr;
DEV_BLOCK *block = dcr->block;
+ int mode;
Dmsg1(150, "Enter mount_next_volume(release=%d)\n", release);
* and read the label. If there is no tape in the drive,
* we will err, recurse and ask the operator the next time.
*/
- if (!release && dev->is_tape() && dev_cap(dev, CAP_AUTOMOUNT)) {
+ if (!release && dev->is_tape() && dev->has_cap(CAP_AUTOMOUNT)) {
Dmsg0(150, "(1)Ask=0\n");
ask = false; /* don't ask SYSOP this time */
}
/* Don't ask if not removable */
- if (!dev_cap(dev, CAP_REM)) {
+ if (!dev->is_removable()) {
Dmsg0(150, "(2)Ask=0\n");
ask = false;
}
}
Dmsg1(150, "want vol=%s\n", dcr->VolumeName);
- if (dev->poll && dev_cap(dev, CAP_CLOSEONPOLL)) {
- force_close_device(dev);
+ if (dev->poll && dev->has_cap(CAP_CLOSEONPOLL)) {
+ dev->close();
}
/* Ensure the device is open */
- if (!open_device(dcr)) {
+ if (dev_cap(dev, CAP_STREAM)) {
+ mode = OPEN_WRITE_ONLY;
+ } else {
+ mode = OPEN_READ_WRITE;
+ }
+ while (dev->open(dcr, mode) < 0) {
+ Dmsg0(000, "open_device failed\n");
+ if (dev->is_file() && dev->is_removable()) {
+ Dmsg0(000, "call scan_dir_for_vol\n");
+ if (dev->scan_dir_for_volume(dcr)) {
+ break; /* got a valid volume */
+ }
+ }
+ if (try_autolabel(dcr) == try_read_vol) {
+ break; /* created a new volume label */
+ }
/* If DVD, ignore the error, very often you cannot open the device
* (when there is no DVD, or when the one inserted is a wrong one) */
- if ((dev->poll) || (dev->is_dvd())) {
+ if (dev->poll || dev->is_dvd() || dev->is_removable()) {
goto mount_next_vol;
} else {
return false;
* If we are writing to a stream device, ASSUME the volume label
* is correct.
*/
- if (dev_cap(dev, CAP_STREAM)) {
+ if (dev->has_cap(CAP_STREAM)) {
vol_label_status = VOL_OK;
create_volume_label(dev, dcr->VolumeName, "Default");
dev->VolHdr.LabelType = PRE_LABEL;
VOLUME_CAT_INFO VolCatInfo, devVolCatInfo;
/* If not removable, Volume is broken */
- if (!dev_cap(dev, CAP_REM)) {
+ if (!dev->is_removable()) {
Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
dcr->VolumeName, dev->print_name());
mark_volume_in_error(dcr);
/* If polling and got a previous bad name, ignore it */
if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolumeName) == 0) {
ask = true;
- Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n",
- dcr->VolumeName);
+ Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n", dcr->VolumeName);
goto mount_next_vol;
}
/*
}
/* Fall through wanted */
case VOL_NO_LABEL:
- /*
- * If permitted, we label the device, make sure we can do
- * it by checking that the VolCatBytes is zero => not labeled,
- * once the Volume is labeled we don't want to label another
- * blank tape with the same name. For disk, we go ahead and
- * label it anyway, because the OS insures that there is only
- * one Volume with that name.
- * As noted above, at this point dcr->VolCatInfo has what
- * the Director wants and dev->VolCatInfo has info on the
- * previous tape (or nothing).
- */
- if (dev_cap(dev, CAP_LABEL) && (dcr->VolCatInfo.VolCatBytes == 0 ||
- (!dev->is_tape() && strcmp(dcr->VolCatInfo.VolCatStatus,
- "Recycle") == 0))) {
- Dmsg0(150, "Create volume label\n");
- /* Create a new Volume label and write it to the device */
- if (!write_new_volume_label_to_dev(dcr, dcr->VolumeName,
- dcr->pool_name)) {
- Dmsg0(150, "!write_vol_label\n");
- mark_volume_in_error(dcr);
- goto mount_next_vol;
- }
- Dmsg0(150, "dir_update_vol_info. Set Append\n");
- /* Copy Director's info into the device info */
- memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
- if (!dir_update_volume_info(dcr, true)) { /* indicate tape labeled */
- return false;
- }
- Jmsg(jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
- dcr->VolumeName, dev->print_name());
- goto read_volume; /* read label we just wrote */
- }
- if (!dev_cap(dev, CAP_LABEL) && dcr->VolCatInfo.VolCatBytes == 0) {
- Jmsg(jcr, M_INFO, 0, _("Warning device %s not configured to autolabel Volumes.\n"),
- dev->print_name());
- }
- /* If not removable, Volume is broken */
- if (!dev_cap(dev, CAP_REM)) {
- Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
- dcr->VolumeName, dev->print_name());
- mark_volume_in_error(dcr);
+ switch (try_autolabel(dcr)) {
+ case try_next_vol:
goto mount_next_vol;
+ case try_read_vol:
+ goto read_volume;
+ case try_error:
+ return false;
+ case try_default:
+ break;
}
+
/* NOTE! Fall-through wanted. */
case VOL_NO_MEDIA:
default:
ask = true;
/* Needed, so the medium can be changed */
if (dev->requires_mount()) {
- close_device(dev);
+ dev->close();
}
goto mount_next_vol;
}
Dmsg0(200, "Device previously written, moving to end of data\n");
Jmsg(jcr, M_INFO, 0, _("Volume \"%s\" previously written, moving to end of data.\n"),
dcr->VolumeName);
- if (!eod_dev(dev)) {
+ if (!dev->eod()) {
Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data on device %s: ERR=%s\n"),
dev->print_name(), strerror_dev(dev));
mark_volume_in_error(dcr);
return true;
}
+/*
+ * If permitted, we label the device, make sure we can do
+ * it by checking that the VolCatBytes is zero => not labeled,
+ * once the Volume is labeled we don't want to label another
+ * blank tape with the same name. For disk, we go ahead and
+ * label it anyway, because the OS insures that there is only
+ * one Volume with that name.
+ * As noted above, at this point dcr->VolCatInfo has what
+ * the Director wants and dev->VolCatInfo has info on the
+ * previous tape (or nothing).
+ */
+static int try_autolabel(DCR *dcr)
+{
+ DEVICE *dev = dcr->dev;
+ if (dev->has_cap(CAP_LABEL) && (dcr->VolCatInfo.VolCatBytes == 0 ||
+ (!dev->is_tape() && strcmp(dcr->VolCatInfo.VolCatStatus,
+ "Recycle") == 0))) {
+ Dmsg0(150, "Create volume label\n");
+ /* Create a new Volume label and write it to the device */
+ if (!write_new_volume_label_to_dev(dcr, dcr->VolumeName,
+ dcr->pool_name)) {
+ Dmsg0(150, "!write_vol_label\n");
+ mark_volume_in_error(dcr);
+ return try_next_vol;
+ }
+ Dmsg0(150, "dir_update_vol_info. Set Append\n");
+ /* Copy Director's info into the device info */
+ memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
+ if (!dir_update_volume_info(dcr, true)) { /* indicate tape labeled */
+ return try_error;
+ }
+ Jmsg(dcr->jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
+ dcr->VolumeName, dev->print_name());
+ return try_read_vol; /* read label we just wrote */
+ }
+ if (!dev->has_cap(CAP_LABEL) && dcr->VolCatInfo.VolCatBytes == 0) {
+ Jmsg(dcr->jcr, M_INFO, 0, _("Warning device %s not configured to autolabel Volumes.\n"),
+ dev->print_name());
+ }
+ /* If not removable, Volume is broken */
+ if (!dev->is_removable()) {
+ Jmsg(dcr->jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"),
+ dcr->VolumeName, dev->print_name());
+ mark_volume_in_error(dcr);
+ return try_next_vol;
+ }
+ return try_default;
+}
/*
dcr->VolumeName[0] = 0;
if (dev->is_open() && (!dev->is_tape() || !dev_cap(dev, CAP_ALWAYSOPEN))) {
- offline_or_rewind_dev(dev);
- close_device(dev);
+ dev->close();
}
/* If we have not closed the device, then at least rewind the tape */
if (dev->is_open()) {
- offline_or_rewind_dev(dev);
+ dev->offline_or_rewind();
}
Dmsg0(190, "release_volume\n");
}
* End Of Tape -- mount next Volume (if another specified)
*/
if (jcr->NumVolumes > 1 && jcr->CurVolume < jcr->NumVolumes) {
- close_device(dev);
- dev->clear_read();
+ dev->close();
if (!acquire_device_for_read(dcr)) {
Jmsg2(jcr, M_FATAL, 0, _("Cannot open Dev=%s, Vol=%s\n"), dev->print_name(),
dcr->VolumeName);
bool update_pos_dev(DEVICE *dev);
bool rewind_dev(DEVICE *dev);
bool load_dev(DEVICE *dev);
-bool offline_dev(DEVICE *dev);
int flush_dev(DEVICE *dev);
int weof_dev(DEVICE *dev, int num);
int write_block(DEVICE *dev);
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);
-bool offline_or_rewind_dev(DEVICE *dev);
bool reposition_dev(DEVICE *dev, uint32_t file, uint32_t block);
void init_device_wait_timers(DCR *dcr);
void init_jcr_device_wait_timers(JCR *jcr);
int dvd_open_next_part(DCR *dcr);
bool dvd_write_part(DCR *dcr);
bool dvd_close_job(DCR *dcr);
-bool mount_dev(DEVICE* dev, int timeout);
-bool unmount_dev(DEVICE* dev, int timeout);
+bool mount_dvd(DEVICE* dev, int timeout);
+bool unmount_dvd(DEVICE* dev, int timeout);
void update_free_space_dev(DEVICE *dev);
void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name);
void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name);
-bool truncate_dvd_dev(DCR *dcr);
+bool truncate_dvd(DCR *dcr);
bool check_can_write_on_non_blank_dvd(DCR *dcr);
/* From device.c */
bool open_device(DCR *dcr);
-void close_device(DEVICE *dev);
-void force_close_device(DEVICE *dev);
bool first_open_device(DCR *dcr);
bool fixup_device_block_write_error(DCR *dcr);
void _lock_device(const char *file, int line, DEVICE *dev);
/* From fd_cmds.c */
void run_job(JCR *jcr);
-bool bootstrap_cmd(JCR *jcr);
+bool get_bootstrap_file(JCR *jcr, BSOCK *bsock);
/* From job.c */
void stored_free_jcr(JCR *jcr);
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
/* Forward referenced subroutines */
+static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass);
+
/* We build the current resource here statically,
* then move it to dynamic memory */
{"name", store_name, ITEM(res_dev.hdr.name), 0, ITEM_REQUIRED, 0},
{"description", store_str, ITEM(res_dir.hdr.desc), 0, 0, 0},
{"mediatype", store_strname,ITEM(res_dev.media_type), 0, ITEM_REQUIRED, 0},
+ {"devicetype", store_devtype,ITEM(res_dev.dev_type), 0, 0, 0},
{"archivedevice", store_strname,ITEM(res_dev.device_name), 0, ITEM_REQUIRED, 0},
{"hardwareendoffile", store_yesno, ITEM(res_dev.cap_bits), CAP_EOF, ITEM_DEFAULT, 1},
{"hardwareendofmedium", store_yesno, ITEM(res_dev.cap_bits), CAP_EOM, ITEM_DEFAULT, 1},
{NULL, NULL, 0}
};
+/*
+ * Device types
+ *
+ * device type device code = token
+ */
+struct s_kw {
+ const char *name;
+ int token;
+};
+static s_kw dev_types[] = {
+ {"file", B_FILE_DEV},
+ {"tape", B_TAPE_DEV},
+ {"dvd", B_DVD_DEV},
+ {"fifo", B_FIFO_DEV},
+ {NULL, 0}
+};
+
+
+/*
+ * Store Device Type (File, FIFO, Tape, DVD)
+ *
+ */
+static void store_devtype(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+ int token, i;
+
+ token = lex_get_token(lc, T_NAME);
+ /* Store the label pass 2 so that type is defined */
+ for (i=0; dev_types[i].name; i++) {
+ if (strcasecmp(lc->str, dev_types[i].name) == 0) {
+ *(int *)(item->value) = dev_types[i].token;
+ i = 0;
+ break;
+ }
+ }
+ if (i != 0) {
+ scan_err1(lc, _("Expected a Device Type keyword, got: %s"), lc->str);
+ }
+ scan_to_eol(lc);
+ set_bit(index, res_all.hdr.item_present);
+}
/* Dump contents of resource */
* Version $Id$
*/
/*
- Copyright (C) 2000-2005 Kern Sibbald
+ Copyright (C) 2000-2006 Kern Sibbald
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
utime_t heartbeat_interval; /* Interval to send hb to FD */
int tls_enable; /* Enable TLS */
int tls_require; /* Require TLS */
- int tls_verify_peer; /* TLS Verify Client Certificate */
+ int tls_verify_peer; /* TLS Verify Client Certificate */
char *tls_ca_certfile; /* TLS CA Certificate File */
char *tls_ca_certdir; /* TLS CA Certificate Directory */
char *tls_certfile; /* TLS Server Certificate File */
char *changer_command; /* Changer command -- external program */
char *alert_command; /* Alert command -- external program */
char *spool_directory; /* Spool file directory */
+ int dev_type; /* device type */
int label_type; /* label type */
int autoselect; /* Automatically select from AutoChanger */
uint32_t drive_index; /* Autochanger drive index */
*/
#undef VERSION
-#define VERSION "1.39.4"
-#define BDATE "14 January 2006"
-#define LSMDATE "14Jan06"
+#define VERSION "1.39.5"
+#define BDATE "30 January 2006"
+#define LSMDATE "30Jan06"
/* Debug flags */
#undef DEBUG