From ffc5ea462dedafd258de0e4e325eaa51618723fc Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Mon, 30 Jan 2006 14:24:17 +0000 Subject: [PATCH] - 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. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@2775 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/Makefile.in | 2 +- bacula/kes-1.39 | 16 + bacula/scripts/Makefile.in | 2 + bacula/src/cats/protos.h | 19 +- bacula/src/cats/sql_find.c | 19 +- bacula/src/dird/backup.c | 7 +- bacula/src/dird/fd_cmds.c | 27 +- bacula/src/dird/getmsg.c | 4 +- bacula/src/dird/job.c | 3 +- bacula/src/dird/mac.c | 54 +- bacula/src/dird/msgchan.c | 6 +- bacula/src/dird/protos.h | 2 +- bacula/src/dird/restore.c | 10 +- bacula/src/dird/ua_label.c | 12 +- bacula/src/dird/ua_run.c | 53 +- bacula/src/dird/ua_update.c | 18 +- bacula/src/dird/verify.c | 10 +- .../gnome2-console/test-gnome-console.conf | 2 +- bacula/src/jcr.h | 1 + bacula/src/lib/parse_conf.c | 4 +- bacula/src/stored/Makefile.in | 18 +- bacula/src/stored/acquire.c | 16 +- bacula/src/stored/append.c | 5 +- bacula/src/stored/askdir.c | 4 +- bacula/src/stored/autochanger.c | 12 +- bacula/src/stored/block.c | 6 +- bacula/src/stored/bscan.c | 5 +- bacula/src/stored/btape.c | 41 +- bacula/src/stored/dev.c | 626 ++++++++++++------ bacula/src/stored/dev.h | 65 +- bacula/src/stored/device.c | 23 +- bacula/src/stored/dircmd.c | 102 +-- bacula/src/stored/dvd.c | 142 ++-- bacula/src/stored/fd_cmds.c | 25 +- bacula/src/stored/job.c | 9 +- bacula/src/stored/label.c | 15 +- bacula/src/stored/mount.c | 155 +++-- bacula/src/stored/protos.h | 12 +- bacula/src/stored/read.c | 2 +- bacula/src/stored/stored_conf.c | 46 +- bacula/src/stored/stored_conf.h | 5 +- bacula/src/version.h | 6 +- 42 files changed, 958 insertions(+), 653 deletions(-) diff --git a/bacula/Makefile.in b/bacula/Makefile.in index 71d0b70c99..64042e8390 100755 --- a/bacula/Makefile.in +++ b/bacula/Makefile.in @@ -168,7 +168,7 @@ Makefiles: (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; \ diff --git a/bacula/kes-1.39 b/bacula/kes-1.39 index b3ae87b2bb..18fa97fcbf 100644 --- a/bacula/kes-1.39 +++ b/bacula/kes-1.39 @@ -3,6 +3,22 @@ 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 diff --git a/bacula/scripts/Makefile.in b/bacula/scripts/Makefile.in index 03027516c2..d440b3c48a 100755 --- a/bacula/scripts/Makefile.in +++ b/bacula/scripts/Makefile.in @@ -50,6 +50,8 @@ install: installdirs $(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.8.gz $(INSTALL_DATA) bacula.8.gz $(DESTDIR)$(mandir)/bacula.8.gz diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h index 580d3c387b..6841dffdcf 100644 --- a/bacula/src/cats/protos.h +++ b/bacula/src/cats/protos.h @@ -6,22 +6,17 @@ * 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. */ @@ -65,7 +60,7 @@ int db_delete_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr); /* 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); diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index 33ae9b0ac3..cac8a58cc3 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -188,10 +188,10 @@ db_find_failed_job_since(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *stime, int & * 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; @@ -207,7 +207,8 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr) 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 " @@ -221,18 +222,18 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr) } 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]); @@ -242,11 +243,11 @@ db_find_last_jobid(JCR *jcr, B_DB *mdb, const char *Name, JOB_DBR *jr) 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; } /* diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c index cbc95c61e7..225ffe5fcc 100644 --- a/bacula/src/dird/backup.c +++ b/bacula/src/dird/backup.c @@ -186,6 +186,10 @@ bool do_backup(JCR *jcr) } 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; @@ -223,8 +227,7 @@ bool do_backup(JCR *jcr) } } - 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; } diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index 5855adf4e3..dfc4cc11db 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -13,7 +13,7 @@ * 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 @@ -43,7 +43,6 @@ static char runafter[] = "RunAfterJob %s\n"; /* 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"; @@ -422,19 +421,19 @@ bool send_exclude_list(JCR *jcr) /* - * 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) { @@ -442,23 +441,19 @@ bool send_bootstrap_file(JCR *jcr) 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; } /* diff --git a/bacula/src/dird/getmsg.c b/bacula/src/dird/getmsg.c index 8150cb8972..bd5dea6157 100644 --- a/bacula/src/dird/getmsg.c +++ b/bacula/src/dird/getmsg.c @@ -21,7 +21,7 @@ * 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 @@ -304,11 +304,9 @@ bool response(JCR *jcr, BSOCK *bs, char *resp, const char *cmd, e_prtmsg prtmsg) 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); diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 6c12e089ce..dfd3b1e1f3 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -7,7 +7,7 @@ * 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 @@ -379,7 +379,6 @@ bool cancel_job(UAContext *ua, JCR *jcr) return true; default: - /* Cancel File daemon */ if (jcr->file_bsock) { ua->jcr->client = jcr->client; diff --git a/bacula/src/dird/mac.c b/bacula/src/dird/mac.c index ecbe8aa013..eb1d7835e1 100644 --- a/bacula/src/dird/mac.c +++ b/bacula/src/dird/mac.c @@ -8,14 +8,14 @@ * 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 @@ -33,6 +33,8 @@ #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. @@ -98,7 +100,7 @@ bool do_mac_init(JCR *jcr) /* * 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; @@ -171,6 +173,7 @@ bool do_mac(JCR *jcr) int stat; const char *Type; char ed1[100]; + BSOCK *sd; switch(jcr->JobType) { case JT_MIGRATE: @@ -213,19 +216,31 @@ bool do_mac(JCR *jcr) 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); @@ -252,8 +267,8 @@ bool do_mac(JCR *jcr) 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; @@ -359,14 +374,14 @@ void mac_cleanup(JCR *jcr, int TermCode) 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); @@ -376,7 +391,7 @@ void mac_cleanup(JCR *jcr, int TermCode) } 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) { @@ -385,10 +400,10 @@ void mac_cleanup(JCR *jcr, int TermCode) } 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; @@ -420,7 +435,6 @@ void mac_cleanup(JCR *jcr, int TermCode) 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 */ @@ -434,9 +448,7 @@ void mac_cleanup(JCR *jcr, int TermCode) " 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" @@ -444,9 +456,7 @@ void mac_cleanup(JCR *jcr, int TermCode) " 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, @@ -460,9 +470,7 @@ void mac_cleanup(JCR *jcr, int TermCode) 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, @@ -470,11 +478,9 @@ void mac_cleanup(JCR *jcr, int TermCode) 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"); } diff --git a/bacula/src/dird/msgchan.c b/bacula/src/dird/msgchan.c index a0b2e0a1bf..04ac72bfee 100644 --- a/bacula/src/dird/msgchan.c +++ b/bacula/src/dird/msgchan.c @@ -16,7 +16,7 @@ * 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 @@ -250,10 +250,6 @@ bool start_storage_daemon_job(JCR *jcr, alist *rstore, alist *wstore) break; } } - if (ok) { - ok = bnet_fsend(sd, "run"); - Dmsg1(100, ">stored: %s\n", sd->msg); - } return ok; } diff --git a/bacula/src/dird/protos.h b/bacula/src/dird/protos.h index 4417a800a7..d65fa46a00 100644 --- a/bacula/src/dird/protos.h +++ b/bacula/src/dird/protos.h @@ -71,7 +71,7 @@ extern int connect_to_file_daemon(JCR *jcr, int retry_interval, 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); diff --git a/bacula/src/dird/restore.c b/bacula/src/dird/restore.c index 3e5cc366fa..ff7b18c99c 100644 --- a/bacula/src/dird/restore.c +++ b/bacula/src/dird/restore.c @@ -18,7 +18,7 @@ * 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 @@ -43,6 +43,7 @@ static char storaddr[] = "storage address=%s port=%d ssl=0\n"; /* 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 @@ -107,6 +108,10 @@ bool do_restore(JCR *jcr) } Dmsg0(50, "Storage daemon connection OK\n"); + if (!bnet_fsend(jcr->store_bsock, "run")) { + return false; + } + /* * Start conversation with File daemon */ @@ -137,7 +142,8 @@ bool do_restore(JCR *jcr) /* * 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; } diff --git a/bacula/src/dird/ua_label.c b/bacula/src/dird/ua_label.c index 7b9778ef8d..dce647bbb8 100644 --- a/bacula/src/dird/ua_label.c +++ b/bacula/src/dird/ua_label.c @@ -147,7 +147,7 @@ bail_out: /* * 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; @@ -159,11 +159,11 @@ int update_slots(UAContext *ua) 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); @@ -174,12 +174,12 @@ int update_slots(UAContext *ua) 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); @@ -273,7 +273,7 @@ bail_out: free(slot_list); close_sd_bsock(ua); - return 1; + return; } diff --git a/bacula/src/dird/ua_run.c b/bacula/src/dird/ua_run.c index e544817cf0..470cd5bd96 100644 --- a/bacula/src/dird/ua_run.c +++ b/bacula/src/dird/ua_run.c @@ -34,7 +34,7 @@ extern struct s_kw ReplaceOptions[]; * run [job=] level= * * For Restore Jobs - * run jobid=nn + * run * * Returns: 0 on error * JobId if OK @@ -47,6 +47,7 @@ int run_cmd(UAContext *ua, const char *cmd) 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; @@ -55,6 +56,7 @@ int run_cmd(UAContext *ua, const char *cmd) bool kw_ok; JOB *job = NULL; JOB *verify_job = NULL; + JOB *migration_job = NULL; STORE *store = NULL; CLIENT *client = NULL; FILESET *fileset = NULL; @@ -81,6 +83,7 @@ int run_cmd(UAContext *ua, const char *cmd) "since", /* 18 since */ "cloned", /* 19 cloned */ "verifylist", /* 20 verify output list */ + "migrationjob", /* 21 migration job name */ NULL}; #define YES_POS 14 @@ -101,6 +104,7 @@ int run_cmd(UAContext *ua, const char *cmd) bootstrap = NULL; replace = NULL; verify_job_name = NULL; + migration_job_name = NULL; catalog_name = NULL; verify_list = NULL; @@ -254,6 +258,15 @@ int run_cmd(UAContext *ua, const char *cmd) 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; @@ -401,6 +414,17 @@ int run_cmd(UAContext *ua, const char *cmd) 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. @@ -409,6 +433,7 @@ int run_cmd(UAContext *ua, const char *cmd) 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; @@ -638,6 +663,32 @@ try_again: 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; diff --git a/bacula/src/dird/ua_update.c b/bacula/src/dird/ua_update.c index a95057209a..22e3e3a098 100644 --- a/bacula/src/dird/ua_update.c +++ b/bacula/src/dird/ua_update.c @@ -30,7 +30,8 @@ extern char *list_pool; /* in sql_cmds.c */ /* 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 */ @@ -340,6 +341,7 @@ static int update_volume(UAContext *ua) POOLMEM *query; char ed1[130]; bool done = false; + int i; const char *kw[] = { _("VolStatus"), /* 0 */ _("VolRetention"), /* 1 */ @@ -353,7 +355,7 @@ static int update_volume(UAContext *ua) _("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) { @@ -403,9 +405,6 @@ static int update_volume(UAContext *ua) } 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")); @@ -422,7 +421,14 @@ static int update_volume(UAContext *ua) 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); diff --git a/bacula/src/dird/verify.c b/bacula/src/dird/verify.c index 8081532727..97be8d8095 100644 --- a/bacula/src/dird/verify.c +++ b/bacula/src/dird/verify.c @@ -14,7 +14,7 @@ * 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 @@ -43,6 +43,7 @@ static char storaddr[] = "storage address=%s port=%d ssl=0\n"; /* 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); @@ -208,6 +209,10 @@ bool do_verify(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 @@ -258,7 +263,8 @@ bool do_verify(JCR *jcr) /* * 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; } diff --git a/bacula/src/gnome2-console/test-gnome-console.conf b/bacula/src/gnome2-console/test-gnome-console.conf index b2725a1f9f..fa5f9bcd4e 100644 --- a/bacula/src/gnome2-console/test-gnome-console.conf +++ b/bacula/src/gnome2-console/test-gnome-console.conf @@ -5,6 +5,6 @@ Director { Name = rufus-dir DIRport = 8101 - address = rufus + address = localhost Password = UA_password } diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index 869bde86a7..bc6700de2c 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -165,6 +165,7 @@ public: 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 */ diff --git a/bacula/src/lib/parse_conf.c b/bacula/src/lib/parse_conf.c index 41307bd07b..aaa75baf1f 100755 --- a/bacula/src/lib/parse_conf.c +++ b/bacula/src/lib/parse_conf.c @@ -33,7 +33,7 @@ * 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 @@ -136,7 +136,7 @@ struct s_kw { * * 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}, diff --git a/bacula/src/stored/Makefile.in b/bacula/src/stored/Makefile.in index 3851a1681d..e094287545 100644 --- a/bacula/src/stored/Makefile.in +++ b/bacula/src/stored/Makefile.in @@ -28,18 +28,18 @@ SVRSRCS = stored.c ansi_label.c \ 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 @@ -50,32 +50,32 @@ TAPESRCS = btape.c block.c butil.c dev.c device.c label.c \ 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 diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index 44002603b1..fa69e3b4fa 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -6,7 +6,7 @@ * 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 @@ -86,6 +86,10 @@ void free_dcr(DCR *dcr) 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) { @@ -227,10 +231,11 @@ DCR *acquire_device_for_read(DCR *dcr) 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 */ @@ -481,8 +486,7 @@ bool release_device(DCR *dcr) /* 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 */ diff --git a/bacula/src/stored/append.c b/bacula/src/stored/append.c index 1e5153e019..cfa936df02 100644 --- a/bacula/src/stored/append.c +++ b/bacula/src/stored/append.c @@ -251,10 +251,7 @@ bool do_append_data(JCR *jcr) /* 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 diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c index b5b4c106b3..93984bcc98 100644 --- a/bacula/src/stored/askdir.c +++ b/bacula/src/stored/askdir.c @@ -7,7 +7,7 @@ * 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 @@ -510,7 +510,7 @@ bool dir_ask_sysop_to_mount_volume(DCR *dcr) } if (dev->is_dvd()) { - unmount_dev(dev, 0); + unmount_dvd(dev, 0); } /* diff --git a/bacula/src/stored/autochanger.c b/bacula/src/stored/autochanger.c index bd08996814..821c856c2c 100644 --- a/bacula/src/stored/autochanger.c +++ b/bacula/src/stored/autochanger.c @@ -104,6 +104,9 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) 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 @@ -151,8 +154,7 @@ int autoload_device(DCR *dcr, int writing, BSOCK *dir) 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"), @@ -297,8 +299,7 @@ bool unload_autochanger(DCR *dcr, int loaded) 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) { @@ -373,8 +374,7 @@ static bool unload_other_drive(DCR *dcr, int slot) 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; diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index 5f3f2feb04..a7e7fe1cf4 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -9,7 +9,7 @@ * */ /* - 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 @@ -613,13 +613,13 @@ static void reread_last_block(DCR *dcr) */ 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"), diff --git a/bacula/src/stored/bscan.c b/bacula/src/stored/bscan.c index 099736b338..a74f27554d 100644 --- a/bacula/src/stored/bscan.c +++ b/bacula/src/stored/bscan.c @@ -1255,10 +1255,7 @@ bool dir_ask_sysop_to_mount_volume(DCR *dcr) 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(); diff --git a/bacula/src/stored/btape.c b/bacula/src/stored/btape.c index e6ef6ec914..aca4acc047 100644 --- a/bacula/src/stored/btape.c +++ b/bacula/src/stored/btape.c @@ -14,7 +14,7 @@ * */ /* - 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 @@ -483,7 +483,7 @@ static void weofcmd() */ static void eomcmd() { - if (!eod_dev(dev)) { + if (!dev->eod()) { Pmsg1(0, "%s", strerror_dev(dev)); return; } else { @@ -513,7 +513,7 @@ static void bsfcmd() 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"); @@ -699,12 +699,12 @@ static int re_read_block_test() 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; } @@ -1053,7 +1053,7 @@ static int append_test() if (dev_cap(dev, CAP_TWOEOF)) { weofcmd(); } - force_close_device(dev); /* release device */ + dev->close(); /* release device */ if (!open_the_device()) { return -1; } @@ -1147,9 +1147,8 @@ try_again: 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, @@ -1174,7 +1173,7 @@ try_again: 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"), @@ -2103,11 +2102,11 @@ static void do_unfill() /* 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); @@ -2115,8 +2114,7 @@ static void do_unfill() 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); @@ -2167,7 +2165,7 @@ static void do_unfill() /* 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); @@ -2176,7 +2174,7 @@ static void do_unfill() 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: ")); } @@ -2677,11 +2675,7 @@ bool dir_ask_sysop_to_mount_volume(DCR *dcr) 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: "), @@ -2706,11 +2700,11 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) } /* 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(); @@ -2753,8 +2747,7 @@ static bool my_mount_next_read_volume(DCR *dcr) 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; diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index acb79b1d2b..8e1e224f1e 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -29,7 +29,7 @@ * 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 @@ -99,36 +99,37 @@ DEVICE * 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; @@ -151,10 +152,10 @@ init_dev(JCR *jcr, DEVRES *device) 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 */ @@ -163,34 +164,30 @@ init_dev(JCR *jcr, DEVRES *device) } 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) { @@ -260,6 +257,7 @@ init_dev(JCR *jcr, DEVRES *device) int DEVICE::open(DCR *dcr, int omode) { + int preserve = 0; if (is_open()) { if (openmode == omode) { return fd; @@ -267,13 +265,14 @@ DEVICE::open(DCR *dcr, int omode) ::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; @@ -284,7 +283,11 @@ DEVICE::open(DCR *dcr, int omode) 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; } @@ -296,11 +299,7 @@ void DEVICE::set_mode(int new_mode) 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; @@ -404,15 +403,13 @@ void DEVICE::set_blocking() /* * 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"), @@ -426,15 +423,13 @@ void DEVICE::open_file_device(int omode) 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) { @@ -448,13 +443,13 @@ void DEVICE::open_file_device(int omode) 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. */ @@ -491,21 +486,20 @@ void DEVICE::open_dvd_device(DCR *dcr, int omode) 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. */ @@ -753,56 +747,54 @@ void DEVICE::set_ateot() * 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; } } @@ -817,33 +809,33 @@ eod_dev(DEVICE *dev) } } - 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 { @@ -851,29 +843,29 @@ eod_dev(DEVICE *dev) /* * 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; } @@ -884,21 +876,21 @@ eod_dev(DEVICE *dev) * 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; } @@ -1013,7 +1005,7 @@ uint32_t status_dev(DEVICE *dev) 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); @@ -1075,44 +1067,44 @@ bool load_dev(DEVICE *dev) * 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 @@ -1121,8 +1113,8 @@ bool offline_or_rewind_dev(DEVICE *dev) * 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); } } @@ -1165,7 +1157,7 @@ bool DEVICE::fsf(int num) * 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); @@ -1191,7 +1183,7 @@ bool DEVICE::fsf(int num) * 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"); @@ -1291,39 +1283,38 @@ bool DEVICE::fsf(int num) * 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; } @@ -1348,7 +1339,7 @@ bool DEVICE::fsr(int num) 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; } @@ -1406,7 +1397,7 @@ bsr_dev(DEVICE *dev, int num) 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; } @@ -1475,13 +1466,13 @@ reposition_dev(DEVICE *dev, uint32_t file, uint32_t block) } 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); @@ -1679,25 +1670,32 @@ int flush_dev(DEVICE *dev) 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()); @@ -1706,59 +1704,263 @@ static void do_close(DEVICE *dev) } /* 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 { @@ -1796,7 +1998,7 @@ term_dev(DEVICE *dev) 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; @@ -1819,7 +2021,7 @@ term_dev(DEVICE *dev) dev->attached_dcrs = NULL; } if (dev->state & ST_MALLOC) { - free_pool_memory((POOLMEM *)dev); + free((char *)dev); } } @@ -1896,10 +2098,10 @@ void set_os_device_parameters(DEVICE *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) { @@ -1957,7 +2159,7 @@ void set_os_device_parameters(DEVICE *dev) 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; } diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index 5d953e6045..76e8cdfb48 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -58,6 +58,15 @@ enum { 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 */ @@ -104,11 +113,12 @@ enum { /* 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 */ @@ -204,6 +214,7 @@ public: 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) */ @@ -259,12 +270,15 @@ public: 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; } @@ -295,8 +309,6 @@ public: 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; @@ -307,7 +319,7 @@ public: 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; }; @@ -329,12 +341,22 @@ public: 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; }; @@ -342,11 +364,12 @@ public: 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 */ }; diff --git a/bacula/src/stored/device.c b/bacula/src/stored/device.c index c7407d5d24..a5b3dae44e 100644 --- a/bacula/src/stored/device.c +++ b/bacula/src/stored/device.c @@ -291,7 +291,7 @@ bool open_device(DCR *dcr) /* 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"), @@ -302,27 +302,6 @@ bool open_device(DCR *dcr) 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) diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index 2481b21b99..e6d4b289ed 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -20,7 +20,7 @@ * */ /* - 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 @@ -71,6 +71,7 @@ static bool setdebug_cmd(JCR *jcr); 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); @@ -344,9 +345,9 @@ static bool do_label(JCR *jcr, int relabel) 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"); @@ -390,15 +391,27 @@ static void label_volume_if_ok(DCR *dcr, char *oldname, 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); @@ -515,40 +528,42 @@ static DCR *find_device(JCR *jcr, POOL_MEM &devname, int drive) 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; @@ -657,7 +672,7 @@ static bool mount_cmd(JCR *jcr) 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 { @@ -715,8 +730,7 @@ static bool unmount_cmd(JCR *jcr) 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"), @@ -743,8 +757,7 @@ static bool unmount_cmd(JCR *jcr) 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()); @@ -828,6 +841,10 @@ static bool release_cmd(JCR *jcr) } +static bool bootstrap_cmd(JCR *jcr) +{ + return get_bootstrap_file(jcr, jcr->dir_bsock); +} /* * Autochanger command from Director @@ -902,7 +919,7 @@ static bool readlabel_cmd(JCR *jcr) 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); @@ -925,6 +942,7 @@ static bool readlabel_cmd(JCR *jcr) return true; } + /* * Read the tape label * @@ -965,7 +983,6 @@ static bool try_autoload_device(JCR *jcr, int slot, const char *VolName) { DCR *dcr = jcr->dcr; BSOCK *dir = jcr->dir_bsock; - DEVICE *dev = dcr->dev; bstrncpy(dcr->VolumeName, VolName, sizeof(dcr->VolumeName)); dcr->VolCatInfo.Slot = slot; @@ -973,13 +990,6 @@ static bool try_autoload_device(JCR *jcr, int slot, const char *VolName) 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; } diff --git a/bacula/src/stored/dvd.c b/bacula/src/stored/dvd.c index 417cf5fcec..f68ac089d0 100644 --- a/bacula/src/stored/dvd.c +++ b/bacula/src/stored/dvd.c @@ -8,7 +8,7 @@ * 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 @@ -26,8 +26,7 @@ #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); /* @@ -73,13 +72,13 @@ 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; } @@ -88,17 +87,20 @@ bool mount_dev(DEVICE* dev, int timeout) * 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; @@ -120,9 +122,9 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) 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. */ @@ -144,7 +146,7 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) * 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; @@ -159,7 +161,7 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) DIR* dp; struct dirent *entry, *result; int name_max; - int count = 0; + int count; name_max = pathconf(".", _PC_NAME_MAX); if (name_max < 1024) { @@ -169,31 +171,34 @@ static bool do_mount_dev(DEVICE* dev, int mount, int dotimeout) 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 */ @@ -228,7 +233,7 @@ void update_free_space_dev(DEVICE* dev) 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; @@ -243,7 +248,7 @@ void update_free_space_dev(DEVICE* dev) 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()); @@ -298,7 +303,7 @@ void update_free_space_dev(DEVICE* dev) * 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) @@ -342,7 +347,7 @@ 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 @@ -390,7 +395,7 @@ bool dvd_write_part(DCR *dcr) /* 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); @@ -708,7 +713,7 @@ bool dvd_close_job(DCR *dcr) return ok; } -bool truncate_dvd_dev(DCR *dcr) { +bool truncate_dvd(DCR *dcr) { DEVICE* dev = dcr->dev; /* Set num_parts to zero (on disk) */ @@ -716,17 +721,17 @@ bool truncate_dvd_dev(DCR *dcr) { 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) { @@ -740,10 +745,10 @@ bool truncate_dvd_dev(DCR *dcr) { 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; } @@ -753,7 +758,7 @@ bool truncate_dvd_dev(DCR *dcr) { 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; } @@ -792,8 +797,7 @@ bool check_can_write_on_non_blank_dvd(DCR *dcr) { 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) { @@ -813,7 +817,7 @@ bool check_can_write_on_non_blank_dvd(DCR *dcr) { } 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++; @@ -824,77 +828,9 @@ bool check_can_write_on_non_blank_dvd(DCR *dcr) { 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()); - } -} diff --git a/bacula/src/stored/fd_cmds.c b/bacula/src/stored/fd_cmds.c index 8c798a436d..aca7e3c0d4 100644 --- a/bacula/src/stored/fd_cmds.c +++ b/bacula/src/stored/fd_cmds.c @@ -13,7 +13,7 @@ * */ /* - 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 @@ -53,9 +53,10 @@ static bool append_end_session(JCR *jcr); 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; @@ -93,7 +94,7 @@ static char ERROR_bootstrap[] = "3904 Error bootstrap\n"; /* 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"; /* @@ -309,9 +310,13 @@ static bool read_open_session(JCR *jcr) 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; @@ -330,9 +335,9 @@ bool bootstrap_cmd(JCR *jcr) jcr->RestoreBootstrap, strerror(errno)); goto bail_out; } - while (bnet_recv(fd) >= 0) { - Dmsg1(400, "storedmsg); - fputs(fd->msg, bs); + while (bnet_recv(sock) >= 0) { + Dmsg1(400, "storedmsg); + fputs(sock->msg, bs); } fclose(bs); jcr->bsr = parse_bsr(jcr, jcr->RestoreBootstrap); @@ -350,10 +355,10 @@ bail_out: 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); } diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c index 1176ef45f8..c00c7d37ea 100644 --- a/bacula/src/stored/job.c +++ b/bacula/src/stored/job.c @@ -7,7 +7,7 @@ * */ /* - 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 @@ -29,6 +29,7 @@ extern uint32_t VolSessionTime; /* 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 " @@ -141,7 +142,7 @@ bool run_cmd(JCR *jcr) case JT_COPY: case JT_ARCHIVE: jcr->authenticated = true; - run_job(jcr); + do_mac(jcr); return false; } @@ -247,7 +248,6 @@ bool query_cmd(JCR *jcr) Dmsg1(100, "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) { @@ -257,7 +257,6 @@ bool query_cmd(JCR *jcr) if (!device->dev) { break; } -// UnlockRes(); ok = dir_update_device(jcr, device->dev); if (ok) { ok = bnet_fsend(dir, OK_query); @@ -270,7 +269,6 @@ bool query_cmd(JCR *jcr) 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 */ } @@ -284,7 +282,6 @@ bool query_cmd(JCR *jcr) } } /* 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()); diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index ee0d4fbd74..72340278f8 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -8,7 +8,7 @@ * 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 @@ -71,7 +71,9 @@ int read_dev_volume_label(DCR *dcr) 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 */ @@ -287,8 +289,6 @@ bool write_volume_label_to_block(DCR *dcr) * 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) @@ -300,7 +300,10 @@ bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *Po 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)) { @@ -401,7 +404,7 @@ bool rewrite_volume_label(DCR *dcr, bool recycle) 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)); } diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index 28ce910ab8..d88181a9c2 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -8,7 +8,7 @@ * 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 @@ -26,6 +26,14 @@ #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, @@ -47,6 +55,7 @@ bool mount_next_write_volume(DCR *dcr, bool release) 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); @@ -123,12 +132,12 @@ mount_next_vol: * 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; } @@ -144,15 +153,30 @@ mount_next_vol: } 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; @@ -167,7 +191,7 @@ read_volume: * 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; @@ -194,7 +218,7 @@ read_volume: 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); @@ -205,8 +229,7 @@ read_volume: /* 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; } /* @@ -254,49 +277,17 @@ read_volume: } /* 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: @@ -309,7 +300,7 @@ read_volume: ask = true; /* Needed, so the medium can be changed */ if (dev->requires_mount()) { - close_device(dev); + dev->close(); } goto mount_next_vol; } @@ -341,7 +332,7 @@ read_volume: 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); @@ -407,6 +398,54 @@ read_volume: 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; +} /* @@ -470,13 +509,12 @@ void release_volume(DCR *dcr) 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"); } @@ -494,8 +532,7 @@ bool mount_next_read_volume(DCR *dcr) * 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); diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index c5b458fd2a..384cfb7ef7 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -91,7 +91,6 @@ void clrerror_dev(DEVICE *dev, int func); 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); @@ -103,7 +102,6 @@ bool bsr_dev(DEVICE *dev, int num); void attach_jcr_to_device(DEVICE *dev, JCR *jcr); void detach_jcr_from_device(DEVICE *dev, JCR *jcr); JCR *next_attached_jcr(DEVICE *dev, JCR *jcr); -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); @@ -118,18 +116,16 @@ uint32_t dev_file(DEVICE *dev); 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); @@ -150,7 +146,7 @@ void *handle_connection_request(void *arg); /* 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); diff --git a/bacula/src/stored/read.c b/bacula/src/stored/read.c index 2eb3518665..633cea29fa 100644 --- a/bacula/src/stored/read.c +++ b/bacula/src/stored/read.c @@ -6,7 +6,7 @@ * 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 diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 2f00de4b58..f6f2e8ed3d 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -6,7 +6,7 @@ * 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 @@ -34,6 +34,8 @@ RES **res_head = sres_head; /* 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 */ @@ -95,6 +97,7 @@ static RES_ITEM dev_items[] = { {"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}, @@ -174,7 +177,48 @@ RES_TABLE resources[] = { {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 */ diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index c025dbbff1..6cc91f3eea 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -4,7 +4,7 @@ * 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 @@ -75,7 +75,7 @@ public: 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 */ @@ -107,6 +107,7 @@ public: 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 */ diff --git a/bacula/src/version.h b/bacula/src/version.h index c21e46b520..03ae06a43f 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -3,9 +3,9 @@ */ #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 -- 2.39.5