From 38a904747f731644cd1a10befd09847e52e5e2af Mon Sep 17 00:00:00 2001 From: Kern Sibbald Date: Sat, 8 Jan 2005 14:44:25 +0000 Subject: [PATCH] Integrate Nicolas' patch for direct DVD support. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@1796 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/Makefile.in | 2 +- bacula/autoconf/config.h.in | 6 +- bacula/autoconf/configure.in | 6 + bacula/kernstodo | 1 - bacula/scripts/.cvsignore | 2 + bacula/scripts/Makefile.in | 18 +- bacula/src/c | 2 +- bacula/src/cats/cats.h | 1 + bacula/src/cats/make_mysql_tables.in | 1 + bacula/src/cats/make_postgresql_tables.in | 2 + bacula/src/cats/make_sqlite_tables.in | 1 + bacula/src/cats/sql_create.c | 8 +- bacula/src/cats/sql_find.c | 5 +- bacula/src/cats/sql_get.c | 5 +- bacula/src/cats/sql_list.c | 4 +- bacula/src/cats/sql_update.c | 8 +- bacula/src/cats/update_mysql_tables.in | 16 +- bacula/src/cats/update_postgresql_tables.in | 32 +- bacula/src/cats/update_sqlite_tables.in | 21 +- bacula/src/dird/catreq.c | 53 +- bacula/src/dird/dird_conf.c | 167 ++-- bacula/src/dird/dird_conf.h | 314 +++---- bacula/src/dird/fd_cmds.c | 164 ++-- bacula/src/dird/inc_conf.c | 14 +- bacula/src/dird/job.c | 3 +- bacula/src/dird/msgchan.c | 22 +- bacula/src/dird/python.c | 3 +- bacula/src/dird/run_conf.c | 125 +-- bacula/src/dird/scheduler.c | 23 +- bacula/src/filed/backup.c | 2 +- bacula/src/filed/job.c | 64 +- bacula/src/filed/protos.h | 2 +- bacula/src/filed/restore.c | 74 +- bacula/src/findlib/find.c | 26 +- bacula/src/findlib/find.h | 138 +-- bacula/src/findlib/find_one.c | 2 +- bacula/src/findlib/fstype.c | 2 +- bacula/src/findlib/protos.h | 2 +- bacula/src/jcr.h | 6 +- bacula/src/lib/bpipe.c | 59 ++ bacula/src/lib/protos.h | 1 + bacula/src/stored/acquire.c | 87 +- bacula/src/stored/append.c | 59 +- bacula/src/stored/askdir.c | 76 +- bacula/src/stored/block.c | 143 ++- bacula/src/stored/dev.c | 952 ++++++++++++++++++-- bacula/src/stored/dev.h | 296 +++--- bacula/src/stored/dircmd.c | 146 +-- bacula/src/stored/job.c | 27 +- bacula/src/stored/label.c | 135 ++- bacula/src/stored/mount.c | 84 +- bacula/src/stored/protos.h | 8 +- bacula/src/stored/python.c | 1 - bacula/src/stored/read.c | 6 +- bacula/src/stored/status.c | 53 +- bacula/src/stored/stored.h | 13 +- bacula/src/stored/stored_conf.c | 72 +- bacula/src/stored/stored_conf.h | 82 +- bacula/src/tools/fstype.c | 13 +- bacula/src/version.h | 6 +- 60 files changed, 2409 insertions(+), 1257 deletions(-) diff --git a/bacula/Makefile.in b/bacula/Makefile.in index ec47e0473a..3f805b3ad0 100755 --- a/bacula/Makefile.in +++ b/bacula/Makefile.in @@ -181,7 +181,7 @@ clean: @(cd platforms; echo "==>Entering directory `pwd`"; ${MAKE} $@ || exit 1) @$(RMF) *~ 1 2 3 core core.* config.guess console.log console.sum @$(RMF) examples/1 examples/2 examples/devices/1 examples/devices/2 - @$(RMF) autom4te.cache + @$(RMF) -r autom4te.cache # clean for distribution diff --git a/bacula/autoconf/config.h.in b/bacula/autoconf/config.h.in index adac090114..8d3797e6b4 100644 --- a/bacula/autoconf/config.h.in +++ b/bacula/autoconf/config.h.in @@ -594,9 +594,9 @@ /* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. - STACK_DIRECTION > 0 => grows toward higher addresses - STACK_DIRECTION < 0 => grows toward lower addresses - STACK_DIRECTION = 0 => direction of growth unknown */ + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ #undef STACK_DIRECTION /* Define to 1 if the `S_IS*' macros in do not work properly. */ diff --git a/bacula/autoconf/configure.in b/bacula/autoconf/configure.in index c30b359f3e..a3e70fa4a4 100644 --- a/bacula/autoconf/configure.in +++ b/bacula/autoconf/configure.in @@ -62,6 +62,10 @@ AC_PATH_PROG(AR, ar, ar) dnl AC_PATH_PROG(RANLIB, ranlib, ranlib) AC_PATH_PROG(OPENSSL, openssl, none) AC_PATH_PROG(MTX, mtx, mtx) +AC_PATH_PROG(MKISOFS, mkisofs, mkisofs) +AC_PATH_PROG(PYTHON, python, python) +AC_PATH_PROG(GROWISOFS, growisofs, growisofs) +AC_PATH_PROG(DVDRWMEDIAINFO, dvd+rw-mediainfo, dvd+rw-mediainfo) AC_PATH_PROG(PKGCONFIG, pkg-config, pkg-config) AC_PATH_PROG(WXCONFIG, wx-config, wx-config) AC_PATH_PROG(CDRECORD, cdrecord, cdrecord) @@ -1952,6 +1956,8 @@ AC_OUTPUT([autoconf/Make.common \ scripts/bacula.desktop.gnome2.xsu \ scripts/gnome-console.console_apps \ scripts/mtx-changer \ + scripts/dvd-writepart \ + scripts/dvd-freespace \ scripts/bacula-tray-monitor.desktop \ scripts/logwatch/Makefile \ scripts/logwatch/logfile.bacula.conf \ diff --git a/bacula/kernstodo b/bacula/kernstodo index 6fbfb3aec2..706e61127d 100644 --- a/bacula/kernstodo +++ b/bacula/kernstodo @@ -30,7 +30,6 @@ Suggestions for Preben: - Optimized bootstrap. For 1.37: -- Look at Preben's fstype error handling code. - Look at Preben's acl.c error handling code. - See multiple-store.txt for Multiple Storage implementation design. diff --git a/bacula/scripts/.cvsignore b/bacula/scripts/.cvsignore index 38362e56b4..c9cb41e404 100644 --- a/bacula/scripts/.cvsignore +++ b/bacula/scripts/.cvsignore @@ -9,6 +9,8 @@ bconsole devel_bacula gconsole mtx-changer +dvd-writepart +dvd-freespace Makefile bacula btraceback diff --git a/bacula/scripts/Makefile.in b/bacula/scripts/Makefile.in index 10f97167f7..c08fc344b3 100755 --- a/bacula/scripts/Makefile.in +++ b/bacula/scripts/Makefile.in @@ -42,6 +42,16 @@ install: installdirs $(MV) -f ${DESTDIR}${scriptdir}/mtx-changer ${DESTDIR}${scriptdir}/mtx-changer.old; \ fi $(INSTALL_SCRIPT) mtx-changer $(DESTDIR)$(scriptdir)/mtx-changer + @if test -f ${DESTDIR}${scriptdir}/dvd-writepart; then \ + echo " ==> Saving existing dvd-writepart to dvd-writepart.old"; \ + $(MV) -f ${DESTDIR}${scriptdir}/dvd-writepart ${DESTDIR}${scriptdir}/dvd-writepart.old; \ + fi + $(INSTALL_SCRIPT) dvd-writepart $(DESTDIR)$(scriptdir)/dvd-writepart + @if test -f ${DESTDIR}${scriptdir}/dvd-freespace; then \ + echo " ==> Saving existing dvd-freespace to dvd-freespace.old"; \ + $(MV) -f ${DESTDIR}${scriptdir}/dvd-freespace ${DESTDIR}${scriptdir}/dvd-freespace.old; \ + fi + $(INSTALL_SCRIPT) dvd-freespace $(DESTDIR)$(scriptdir)/dvd-freespace $(INSTALL_DATA) btraceback.gdb $(DESTDIR)$(scriptdir)/btraceback.gdb $(INSTALL_DATA) btraceback.dbx $(DESTDIR)$(scriptdir)/btraceback.dbx $(INSTALL_SCRIPT) btraceback $(DESTDIR)$(sbindir)/btraceback @@ -54,6 +64,8 @@ uninstall: (cd $(DESTDIR)$(scriptdir); $(RMF) bacula) (cd $(DESTDIR)$(scriptdir); $(RMF) fd) (cd $(DESTDIR)$(scriptdir); $(RMF) mtx-changer) + (cd $(DESTDIR)$(scriptdir); $(RMF) dvd-writepart) + (cd $(DESTDIR)$(scriptdir); $(RMF) dvd-freespace) (cd $(DESTDIR)$(scriptdir); $(RMF) btraceback.gdb) (cd $(DESTDIR)$(scriptdir); $(RMF) btraceback.dbx) (cd $(DESTDIR)$(sbindir); $(RMF) btraceback) @@ -62,12 +74,12 @@ Makefile: Makefile.in cd $(topdir) \ && CONFIG_FILES=$(thisdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status chmod 755 startmysql stopmysql bacula startit stopit btraceback - chmod 755 mtx-changer bconsole gconsole + chmod 755 mtx-changer dvd-writepart dvd-freespace bconsole gconsole Makefiles: $(SHELL) config.status chmod 755 startmysql stopmysql bacula startit stopit btraceback - chmod 755 mtx-changer bconsole gconsole + chmod 755 mtx-changer dvd-writepart dvd-freespace bconsole gconsole clean: @$(RMF) *~ 1 2 3 @@ -76,7 +88,7 @@ clean: distclean: clean @$(RMF) startmysql stopmysql bacula fd startit stopit btraceback @$(RMF) bconsole gconsole logrotate bacula.desktop - @$(RMF) bacula.desktop.gnome1 bacula.desktop.gnome2 mtx-changer + @$(RMF) bacula.desktop.gnome1 bacula.desktop.gnome2 mtx-changer dvd-writepart dvd-freespace @$(RMF) gnome-console.console_apps bacula.desktop.gnome2.xsu @$(RMF) bacula.desktop.gnome2.consolehelper bacula.desktop.gnome1.xsu @$(RMF) bacula.desktop.gnome1.consolehelper diff --git a/bacula/src/c b/bacula/src/c index 5c8d1e7c4b..fd4a244c20 100644 --- a/bacula/src/c +++ b/bacula/src/c @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2005 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h index 3a5d3756de..28c6a41de1 100644 --- a/bacula/src/cats/cats.h +++ b/bacula/src/cats/cats.h @@ -535,6 +535,7 @@ struct MEDIA_DBR { uint32_t VolWrites; /* Number of writes */ uint32_t VolReads; /* Number of reads */ uint64_t VolBytes; /* Number of bytes written */ + uint32_t VolParts; /* Number of parts written */ uint64_t MaxVolBytes; /* Max bytes to write to Volume */ uint64_t VolCapacityBytes; /* capacity estimate */ uint64_t VolReadTime; /* time spent reading volume */ diff --git a/bacula/src/cats/make_mysql_tables.in b/bacula/src/cats/make_mysql_tables.in index 3f292ea447..8dc2781780 100644 --- a/bacula/src/cats/make_mysql_tables.in +++ b/bacula/src/cats/make_mysql_tables.in @@ -111,6 +111,7 @@ CREATE TABLE Media ( VolBlocks INTEGER UNSIGNED NOT NULL DEFAULT 0, VolMounts INTEGER UNSIGNED NOT NULL DEFAULT 0, VolBytes BIGINT UNSIGNED NOT NULL DEFAULT 0, + VolParts INTEGER UNSIGNED NOT NULL DEFAULT 0, VolErrors INTEGER UNSIGNED NOT NULL DEFAULT 0, VolWrites INTEGER UNSIGNED NOT NULL DEFAULT 0, VolCapacityBytes BIGINT UNSIGNED NOT NULL, diff --git a/bacula/src/cats/make_postgresql_tables.in b/bacula/src/cats/make_postgresql_tables.in index b067f1548b..25941db867 100644 --- a/bacula/src/cats/make_postgresql_tables.in +++ b/bacula/src/cats/make_postgresql_tables.in @@ -122,6 +122,8 @@ create table media default 0, volbytes bigint not null default 0, + volparts integer not null + default 0, volerrors integer not null default 0, volwrites integer not null diff --git a/bacula/src/cats/make_sqlite_tables.in b/bacula/src/cats/make_sqlite_tables.in index a780f9dc50..9288ca7575 100644 --- a/bacula/src/cats/make_sqlite_tables.in +++ b/bacula/src/cats/make_sqlite_tables.in @@ -111,6 +111,7 @@ CREATE TABLE Media ( VolBlocks INTEGER UNSIGNED DEFAULT 0, VolMounts INTEGER UNSIGNED DEFAULT 0, VolBytes BIGINT UNSIGNED DEFAULT 0, + VolParts INTEGER UNSIGNED DEFAULT 0, VolErrors INTEGER UNSIGNED DEFAULT 0, VolWrites INTEGER UNSIGNED DEFAULT 0, VolCapacityBytes BIGINT UNSIGNED DEFAULT 0, diff --git a/bacula/src/cats/sql_create.c b/bacula/src/cats/sql_create.c index 147538484a..6dffada302 100644 --- a/bacula/src/cats/sql_create.c +++ b/bacula/src/cats/sql_create.c @@ -242,9 +242,9 @@ db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) Mmsg(mdb->cmd, "INSERT INTO Media (VolumeName,MediaType,PoolId,MaxVolBytes,VolCapacityBytes," "Recycle,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," -"VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime," +"VolStatus,Slot,VolBytes,InChanger,VolReadTime,VolWriteTime,VolParts," "EndFile,EndBlock) " -"VALUES ('%s','%s',%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,0,0)", +"VALUES ('%s','%s',%u,%s,%s,%d,%s,%s,%u,%u,'%s',%d,%s,%d,%s,%s,%d,0,0)", mr->VolumeName, mr->MediaType, mr->PoolId, edit_uint64(mr->MaxVolBytes,ed1), @@ -259,7 +259,9 @@ db_create_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) edit_uint64(mr->VolBytes, ed5), mr->InChanger, edit_uint64(mr->VolReadTime, ed6), - edit_uint64(mr->VolWriteTime, ed7)); + edit_uint64(mr->VolWriteTime, ed7), + mr->VolParts + ); Dmsg1(500, "Create Volume: %s\n", mdb->cmd); diff --git a/bacula/src/cats/sql_find.c b/bacula/src/cats/sql_find.c index dd10220aa1..cb53f6b3d6 100644 --- a/bacula/src/cats/sql_find.c +++ b/bacula/src/cats/sql_find.c @@ -268,7 +268,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks," "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes," "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot," - "FirstWritten,LastWritten,VolStatus,InChanger " + "FirstWritten,LastWritten,VolStatus,InChanger,VolParts " "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus IN ('Full'," "'Recycle','Purged','Used','Append') " "ORDER BY LastWritten LIMIT 1", mr->PoolId, mr->MediaType); @@ -289,7 +289,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks," "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes," "VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles,Recycle,Slot," - "FirstWritten,LastWritten,VolStatus,InChanger " + "FirstWritten,LastWritten,VolStatus,InChanger,VolParts " "FROM Media WHERE PoolId=%u AND MediaType='%s' AND VolStatus='%s' " "%s " "%s LIMIT %d", @@ -344,6 +344,7 @@ db_find_next_volume(JCR *jcr, B_DB *mdb, int item, bool InChanger, MEDIA_DBR *mr mr->LastWritten = (time_t)str_to_utime(mr->cLastWritten); bstrncpy(mr->VolStatus, row[19], sizeof(mr->VolStatus)); mr->InChanger = str_to_int64(row[20]); + mr->VolParts = str_to_int64(row[21]); sql_free_result(mdb); db_unlock(mdb); diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c index e53ecfa4db..958e86503c 100644 --- a/bacula/src/cats/sql_get.c +++ b/bacula/src/cats/sql_get.c @@ -810,13 +810,13 @@ int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks," "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes," "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," - "Recycle,Slot,FirstWritten,LastWritten,InChanger,EndFile,EndBlock " + "Recycle,Slot,FirstWritten,LastWritten,InChanger,EndFile,EndBlock,VolParts " "FROM Media WHERE MediaId=%d", mr->MediaId); } else { /* find by name */ Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,VolJobs,VolFiles,VolBlocks," "VolBytes,VolMounts,VolErrors,VolWrites,MaxVolBytes,VolCapacityBytes," "MediaType,VolStatus,PoolId,VolRetention,VolUseDuration,MaxVolJobs,MaxVolFiles," - "Recycle,Slot,FirstWritten,LastWritten,InChanger,EndFile,EndBlock " + "Recycle,Slot,FirstWritten,LastWritten,InChanger,EndFile,EndBlock,VolParts " "FROM Media WHERE VolumeName='%s'", mr->VolumeName); } @@ -860,6 +860,7 @@ int db_get_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) mr->InChanger = str_to_uint64(row[22]); mr->EndFile = str_to_uint64(row[23]); mr->EndBlock = str_to_uint64(row[24]); + mr->VolParts = str_to_int64(row[25]); stat = mr->MediaId; } } else { diff --git a/bacula/src/cats/sql_list.c b/bacula/src/cats/sql_list.c index ec69cda044..287d780935 100644 --- a/bacula/src/cats/sql_list.c +++ b/bacula/src/cats/sql_list.c @@ -141,7 +141,7 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, "VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites," "VolCapacityBytes,VolStatus,Recycle,VolRetention," "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger," - "EndFile,EndBlock " + "EndFile,EndBlock,VolParts " "FROM Media WHERE Media.VolumeName='%s'", mdbr->VolumeName); } else { Mmsg(mdb->cmd, "SELECT MediaId,VolumeName,Slot,PoolId," @@ -149,7 +149,7 @@ db_list_media_records(JCR *jcr, B_DB *mdb, MEDIA_DBR *mdbr, "VolFiles,VolBlocks,VolMounts,VolBytes,VolErrors,VolWrites," "VolCapacityBytes,VolStatus,Recycle,VolRetention," "VolUseDuration,MaxVolJobs,MaxVolFiles,MaxVolBytes,InChanger," - "EndFile,EndBlock " + "EndFile,EndBlock,VolParts " "FROM Media WHERE Media.PoolId=%u ORDER BY MediaId", mdbr->PoolId); } } else { diff --git a/bacula/src/cats/sql_update.c b/bacula/src/cats/sql_update.c index 86f65d6c39..3785fda5e7 100644 --- a/bacula/src/cats/sql_update.c +++ b/bacula/src/cats/sql_update.c @@ -261,7 +261,7 @@ db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) time_t ttime; struct tm tm; int stat; - char ed1[30], ed2[30], ed3[30], ed4[30]; + char ed1[30], ed2[30], ed3[30], ed4[30], ed5[30]; Dmsg1(100, "update_media: FirstWritten=%d\n", mr->FirstWritten); @@ -298,7 +298,7 @@ db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u," "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u," "VolWrites=%u,MaxVolBytes=%s,LastWritten='%s',VolStatus='%s'," - "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s " + "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%s " " WHERE VolumeName='%s'", mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1), mr->VolMounts, mr->VolErrors, mr->VolWrites, @@ -306,12 +306,13 @@ db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) mr->VolStatus, mr->Slot, mr->InChanger, edit_uint64(mr->VolReadTime, ed3), edit_uint64(mr->VolWriteTime, ed4), + edit_uint64(mr->VolParts, ed5), mr->VolumeName); } else { Mmsg(mdb->cmd, "UPDATE Media SET VolJobs=%u," "VolFiles=%u,VolBlocks=%u,VolBytes=%s,VolMounts=%u,VolErrors=%u," "VolWrites=%u,MaxVolBytes=%s,VolStatus='%s'," - "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s " + "Slot=%d,InChanger=%d,VolReadTime=%s,VolWriteTime=%s,VolParts=%s " " WHERE VolumeName='%s'", mr->VolJobs, mr->VolFiles, mr->VolBlocks, edit_uint64(mr->VolBytes, ed1), mr->VolMounts, mr->VolErrors, mr->VolWrites, @@ -319,6 +320,7 @@ db_update_media_record(JCR *jcr, B_DB *mdb, MEDIA_DBR *mr) mr->VolStatus, mr->Slot, mr->InChanger, edit_uint64(mr->VolReadTime, ed3), edit_uint64(mr->VolWriteTime, ed4), + edit_uint64(mr->VolParts, ed5), mr->VolumeName); } diff --git a/bacula/src/cats/update_mysql_tables.in b/bacula/src/cats/update_mysql_tables.in index 64797d65f2..f47f2137c5 100755 --- a/bacula/src/cats/update_mysql_tables.in +++ b/bacula/src/cats/update_mysql_tables.in @@ -12,21 +12,7 @@ bindir=@SQL_BINDIR@ if $bindir/mysql $* -f <InChanger, edit_uint64(mr->VolReadTime, ed4), edit_uint64(mr->VolWriteTime, ed5), - mr->EndFile, mr->EndBlock); + mr->EndFile, mr->EndBlock, + mr->VolParts); unbash_spaces(mr->VolumeName); Dmsg2(200, "Vol Info for %s: %s", jcr->Job, sd->msg); return stat; @@ -111,7 +113,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) if (ok) { send_volume_info_to_storage_daemon(jcr, bs, &mr); } else { - bnet_fsend(bs, "1901 No Media.\n"); + bnet_fsend(bs, "1901 No Media.\n"); } /* @@ -138,18 +140,18 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) * and Media Type matches and Pool allows any volume. */ if (mr.PoolId != jcr->PoolId) { - reason = "not in Pool"; + reason = "not in Pool"; } else if (strcmp(mr.MediaType, jcr->store->media_type) != 0) { - reason = "not correct MediaType"; + reason = "not correct MediaType"; } else { /* * ****FIXME*** * This test (accept_any_volume) is turned off - * because it doesn't properly check if the volume + * because it doesn't properly check if the volume * really is out of sequence! * * } else if (!jcr->pool->accept_any_volume) { - * reason = "Volume not in sequence"; + * reason = "Volume not in sequence"; */ /* @@ -166,12 +168,12 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) send_volume_info_to_storage_daemon(jcr, bs, &mr); } else { /* Not suitable volume */ - bnet_fsend(bs, "1998 Volume \"%s\" status is %s, %s.\n", mr.VolumeName, + bnet_fsend(bs, "1998 Volume \"%s\" status is %s, %s.\n", mr.VolumeName, mr.VolStatus, reason); } } else { - bnet_fsend(bs, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName); + bnet_fsend(bs, "1997 Volume \"%s\" not in catalog.\n", mr.VolumeName); } @@ -184,7 +186,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) &sdmr.VolFiles, &sdmr.VolBlocks, &sdmr.VolBytes, &sdmr.VolMounts, &sdmr.VolErrors, &sdmr.VolWrites, &sdmr.MaxVolBytes, &sdmr.LastWritten, &sdmr.VolStatus, &sdmr.Slot, &label, &sdmr.InChanger, &sdmr.VolReadTime, - &sdmr.VolWriteTime) == 17) { + &sdmr.VolWriteTime, &sdmr.VolParts) == 18) { db_lock(jcr->db); Dmsg3(300, "Update media %s oldStat=%s newStat=%s\n", sdmr.VolumeName, @@ -192,9 +194,9 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) bstrncpy(mr.VolumeName, sdmr.VolumeName, sizeof(mr.VolumeName)); /* copy Volume name */ unbash_spaces(mr.VolumeName); if (!db_get_media_record(jcr, jcr->db, &mr)) { - Jmsg(jcr, M_ERROR, 0, _("Unable to get Media record for Volume %s: ERR=%s\n"), + Jmsg(jcr, M_ERROR, 0, _("Unable to get Media record for Volume %s: ERR=%s\n"), mr.VolumeName, db_strerror(jcr->db)); - bnet_fsend(bs, "1991 Catalog Request failed: %s", db_strerror(jcr->db)); + bnet_fsend(bs, "1991 Catalog Request failed: %s", db_strerror(jcr->db)); db_unlock(jcr->db); return; } @@ -211,7 +213,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) * Insanity check for VolFiles get set to a smaller value */ if (sdmr.VolFiles < mr.VolFiles) { - Jmsg(jcr, M_ERROR, 0, _("ERROR!! Volume Files at %u being set to %u. This is probably wrong.\n"), + Jmsg(jcr, M_ERROR, 0, _("ERROR!! Volume Files at %u being set to %u. This is probably wrong.\n"), mr.VolFiles, sdmr.VolFiles); } } @@ -229,6 +231,7 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) mr.InChanger = sdmr.InChanger; mr.VolReadTime = sdmr.VolReadTime; mr.VolWriteTime = sdmr.VolWriteTime; + mr.VolParts = sdmr.VolParts; bstrncpy(mr.VolStatus, sdmr.VolStatus, sizeof(mr.VolStatus)); Dmsg2(300, "db_update_media_record. Stat=%s Vol=%s\n", mr.VolStatus, mr.VolumeName); @@ -241,10 +244,10 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) } else if (db_update_media_record(jcr, jcr->db, &mr)) { send_volume_info_to_storage_daemon(jcr, bs, &mr); } else { - Jmsg(jcr, M_ERROR, 0, _("Catalog error updating Media record. %s"), + Jmsg(jcr, M_ERROR, 0, _("Catalog error updating Media record. %s"), db_strerror(jcr->db)); - bnet_fsend(bs, "1992 Update Media error\n"); - Dmsg0(190, "send error\n"); + bnet_fsend(bs, "1992 Update Media error\n"); + Dmsg0(190, "send error\n"); } db_unlock(jcr->db); @@ -260,11 +263,11 @@ void catalog_request(JCR *jcr, BSOCK *bs, char *msg) Dmsg6(300, "create_jobmedia JobId=%d MediaId=%d SF=%d EF=%d FI=%d LI=%d\n", jm.JobId, jm.MediaId, jm.StartFile, jm.EndFile, jm.FirstIndex, jm.LastIndex); if (!db_create_jobmedia_record(jcr, jcr->db, &jm)) { - Jmsg(jcr, M_ERROR, 0, _("Catalog error creating JobMedia record. %s"), + Jmsg(jcr, M_ERROR, 0, _("Catalog error creating JobMedia record. %s"), db_strerror(jcr->db)); - bnet_fsend(bs, "1991 Update JobMedia error\n"); + bnet_fsend(bs, "1991 Update JobMedia error\n"); } else { - Dmsg0(300, "JobMedia record created\n"); + Dmsg0(300, "JobMedia record created\n"); bnet_fsend(bs, OK_create); } @@ -343,7 +346,7 @@ void catalog_update(JCR *jcr, BSOCK *bs, char *msg) Dmsg1(120, "dirddb, &ar)) { - Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db)); + Jmsg1(jcr, M_FATAL, 0, _("Attribute create error. %s"), db_strerror(jcr->db)); } /* Save values for SIG update */ jcr->FileId = ar.FileId; @@ -351,7 +354,7 @@ void catalog_update(JCR *jcr, BSOCK *bs, char *msg) } else if (Stream == STREAM_MD5_SIGNATURE || Stream == STREAM_SHA1_SIGNATURE) { fname = p; if (jcr->FileIndex != FileIndex) { - Jmsg(jcr, M_WARNING, 0, "Got MD5/SHA1 but not same File as attributes\n"); + Jmsg(jcr, M_WARNING, 0, "Got MD5/SHA1 but not same File as attributes\n"); } else { /* Update signature in catalog */ char SIGbuf[50]; /* 24 bytes should be enough */ @@ -364,9 +367,9 @@ void catalog_update(JCR *jcr, BSOCK *bs, char *msg) type = SHA1_SIG; } bin_to_base64(SIGbuf, fname, len); - Dmsg3(190, "SIGlen=%d SIG=%s type=%d\n", strlen(SIGbuf), SIGbuf, Stream); + Dmsg3(190, "SIGlen=%d SIG=%s type=%d\n", strlen(SIGbuf), SIGbuf, Stream); if (!db_add_SIG_to_file_record(jcr, jcr->db, jcr->FileId, SIGbuf, type)) { - Jmsg(jcr, M_ERROR, 0, _("Catalog error updating MD5/SHA1. %s"), + Jmsg(jcr, M_ERROR, 0, _("Catalog error updating MD5/SHA1. %s"), db_strerror(jcr->db)); } } diff --git a/bacula/src/dird/dird_conf.c b/bacula/src/dird/dird_conf.c index 336f413d74..430d0a6bec 100644 --- a/bacula/src/dird/dird_conf.c +++ b/bacula/src/dird/dird_conf.c @@ -22,7 +22,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -241,6 +241,7 @@ RES_ITEM job_items[] = { {"rescheduleinterval", store_time, ITEM(res_job.RescheduleInterval), 0, ITEM_DEFAULT, 60 * 30}, {"rescheduletimes", store_pint, ITEM(res_job.RescheduleTimes), 0, 0, 0}, {"priority", store_pint, ITEM(res_job.Priority), 0, ITEM_DEFAULT, 10}, + {"writepartafterjob", store_yesno, ITEM(res_job.write_part_after_job), 1, ITEM_DEFAULT, 0}, {NULL, NULL, NULL, 0, 0, 0} }; @@ -442,10 +443,10 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm edit_uint64(res->res_dir.FDConnectTimeout, ed1), edit_uint64(res->res_dir.SDConnectTimeout, ed2)); if (res->res_dir.query_file) { - sendit(sock, " query_file=%s\n", res->res_dir.query_file); + sendit(sock, " query_file=%s\n", res->res_dir.query_file); } if (res->res_dir.messages) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_MSGS, (RES *)res->res_dir.messages, sendit, sock); } break; @@ -455,17 +456,17 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm break; case R_COUNTER: if (res->res_counter.WrapCounter) { - sendit(sock, "Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n", + sendit(sock, "Counter: name=%s min=%d max=%d cur=%d wrapcntr=%s\n", res->res_counter.hdr.name, res->res_counter.MinValue, res->res_counter.MaxValue, res->res_counter.CurrentValue, res->res_counter.WrapCounter->hdr.name); } else { - sendit(sock, "Counter: name=%s min=%d max=%d\n", + sendit(sock, "Counter: name=%s min=%d max=%d\n", res->res_counter.hdr.name, res->res_counter.MinValue, res->res_counter.MaxValue); } if (res->res_counter.Catalog) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_CATALOG, (RES *)res->res_counter.Catalog, sendit, sock); } break; @@ -479,7 +480,7 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm edit_utime(res->res_client.FileRetention, ed2, sizeof(ed2)), res->res_client.AutoPrune); if (res->res_client.catalog) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_CATALOG, (RES *)res->res_client.catalog, sendit, sock); } break; @@ -500,72 +501,72 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm case R_JOB: case R_JOBDEFS: sendit(sock, "%s: name=%s JobType=%d level=%s Priority=%d MaxJobs=%u\n", - type == R_JOB ? "Job" : "JobDefs", + type == R_JOB ? "Job" : "JobDefs", res->res_job.hdr.name, res->res_job.JobType, level_to_str(res->res_job.JobLevel), res->res_job.Priority, res->res_job.MaxConcurrentJobs); - sendit(sock, " Resched=%d Times=%d Interval=%s Spool=%d\n", + sendit(sock, " Resched=%d Times=%d Interval=%s Spool=%d WritePartAfterJob=%d\n", res->res_job.RescheduleOnError, res->res_job.RescheduleTimes, edit_uint64_with_commas(res->res_job.RescheduleInterval, ed1), - res->res_job.spool_data); + res->res_job.spool_data, res->res_job.write_part_after_job); if (res->res_job.client) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_CLIENT, (RES *)res->res_job.client, sendit, sock); } if (res->res_job.fileset) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_FILESET, (RES *)res->res_job.fileset, sendit, sock); } if (res->res_job.schedule) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_SCHEDULE, (RES *)res->res_job.schedule, sendit, sock); } if (res->res_job.RestoreWhere) { - sendit(sock, " --> Where=%s\n", NPRT(res->res_job.RestoreWhere)); + sendit(sock, " --> Where=%s\n", NPRT(res->res_job.RestoreWhere)); } if (res->res_job.RestoreBootstrap) { - sendit(sock, " --> Bootstrap=%s\n", NPRT(res->res_job.RestoreBootstrap)); + sendit(sock, " --> Bootstrap=%s\n", NPRT(res->res_job.RestoreBootstrap)); } if (res->res_job.RunBeforeJob) { - sendit(sock, " --> RunBefore=%s\n", NPRT(res->res_job.RunBeforeJob)); + sendit(sock, " --> RunBefore=%s\n", NPRT(res->res_job.RunBeforeJob)); } if (res->res_job.RunAfterJob) { - sendit(sock, " --> RunAfter=%s\n", NPRT(res->res_job.RunAfterJob)); + sendit(sock, " --> RunAfter=%s\n", NPRT(res->res_job.RunAfterJob)); } if (res->res_job.RunAfterFailedJob) { - sendit(sock, " --> RunAfterFailed=%s\n", NPRT(res->res_job.RunAfterFailedJob)); + sendit(sock, " --> RunAfterFailed=%s\n", NPRT(res->res_job.RunAfterFailedJob)); } if (res->res_job.WriteBootstrap) { - sendit(sock, " --> WriteBootstrap=%s\n", NPRT(res->res_job.WriteBootstrap)); + sendit(sock, " --> WriteBootstrap=%s\n", NPRT(res->res_job.WriteBootstrap)); } if (res->res_job.storage[0]) { - sendit(sock, " --> "); + sendit(sock, " --> "); /* ***FIXME*** */ // dump_resource(-R_STORAGE, (RES *)res->res_job.storage, sendit, sock); } if (res->res_job.pool) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_POOL, (RES *)res->res_job.pool, sendit, sock); } if (res->res_job.full_pool) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_POOL, (RES *)res->res_job.full_pool, sendit, sock); } if (res->res_job.inc_pool) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_POOL, (RES *)res->res_job.inc_pool, sendit, sock); } if (res->res_job.dif_pool) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_POOL, (RES *)res->res_job.dif_pool, sendit, sock); } if (res->res_job.verify_job) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-type, (RES *)res->res_job.verify_job, sendit, sock); } break; if (res->res_job.messages) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_MSGS, (RES *)res->res_job.messages, sendit, sock); } break; @@ -577,54 +578,54 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm INCEXE *incexe = res->res_fs.include_items[i]; for (j=0; jnum_opts; j++) { FOPTS *fo = incexe->opts_list[j]; - sendit(sock, " O %s\n", fo->opts); + sendit(sock, " O %s\n", fo->opts); for (k=0; kregex.size(); k++) { - sendit(sock, " R %s\n", fo->regex.get(k)); + sendit(sock, " R %s\n", fo->regex.get(k)); } for (k=0; kregexdir.size(); k++) { - sendit(sock, " RD %s\n", fo->regexdir.get(k)); + sendit(sock, " RD %s\n", fo->regexdir.get(k)); } for (k=0; kregexfile.size(); k++) { - sendit(sock, " RF %s\n", fo->regexfile.get(k)); + sendit(sock, " RF %s\n", fo->regexfile.get(k)); } for (k=0; kwild.size(); k++) { - sendit(sock, " W %s\n", fo->wild.get(k)); + sendit(sock, " W %s\n", fo->wild.get(k)); } for (k=0; kwilddir.size(); k++) { - sendit(sock, " WD %s\n", fo->wilddir.get(k)); + sendit(sock, " WD %s\n", fo->wilddir.get(k)); } for (k=0; kwildfile.size(); k++) { - sendit(sock, " WF %s\n", fo->wildfile.get(k)); + sendit(sock, " WF %s\n", fo->wildfile.get(k)); } for (k=0; kbase.size(); k++) { - sendit(sock, " B %s\n", fo->base.get(k)); + sendit(sock, " B %s\n", fo->base.get(k)); } for (k=0; kfstype.size(); k++) { - sendit(sock, " X %s\n", fo->fstype.get(k)); + sendit(sock, " X %s\n", fo->fstype.get(k)); } if (fo->reader) { - sendit(sock, " D %s\n", fo->reader); + sendit(sock, " D %s\n", fo->reader); } if (fo->writer) { - sendit(sock, " T %s\n", fo->writer); + sendit(sock, " T %s\n", fo->writer); } - sendit(sock, " N\n"); + sendit(sock, " N\n"); } for (j=0; jname_list.size(); j++) { - sendit(sock, " I %s\n", incexe->name_list.get(j)); + sendit(sock, " I %s\n", incexe->name_list.get(j)); } if (incexe->name_list.size()) { - sendit(sock, " N\n"); + sendit(sock, " N\n"); } } for (i=0; ires_fs.num_excludes; i++) { INCEXE *incexe = res->res_fs.exclude_items[i]; for (j=0; jname_list.size(); j++) { - sendit(sock, " E %s\n", incexe->name_list.get(j)); + sendit(sock, " E %s\n", incexe->name_list.get(j)); } if (incexe->name_list.size()) { - sendit(sock, " N\n"); + sendit(sock, " N\n"); } } break; @@ -634,77 +635,77 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm int i; RUN *run = res->res_sch.run; char buf[1000], num[30]; - sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name); + sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name); if (!run) { break; } next_run: - sendit(sock, " --> Run Level=%s\n", level_to_str(run->level)); - bstrncpy(buf, " hour=", sizeof(buf)); + sendit(sock, " --> Run Level=%s\n", level_to_str(run->level)); + bstrncpy(buf, " hour=", sizeof(buf)); for (i=0; i<24; i++) { if (bit_is_set(i, run->hour)) { - bsnprintf(num, sizeof(num), "%d ", i); + bsnprintf(num, sizeof(num), "%d ", i); bstrncat(buf, num, sizeof(buf)); } } - bstrncat(buf, "\n", sizeof(buf)); + bstrncat(buf, "\n", sizeof(buf)); sendit(sock, buf); - bstrncpy(buf, " mday=", sizeof(buf)); + bstrncpy(buf, " mday=", sizeof(buf)); for (i=0; i<31; i++) { if (bit_is_set(i, run->mday)) { - bsnprintf(num, sizeof(num), "%d ", i); + bsnprintf(num, sizeof(num), "%d ", i); bstrncat(buf, num, sizeof(buf)); } } - bstrncat(buf, "\n", sizeof(buf)); + bstrncat(buf, "\n", sizeof(buf)); sendit(sock, buf); - bstrncpy(buf, " month=", sizeof(buf)); + bstrncpy(buf, " month=", sizeof(buf)); for (i=0; i<12; i++) { if (bit_is_set(i, run->month)) { - bsnprintf(num, sizeof(num), "%d ", i); + bsnprintf(num, sizeof(num), "%d ", i); bstrncat(buf, num, sizeof(buf)); } } - bstrncat(buf, "\n", sizeof(buf)); + bstrncat(buf, "\n", sizeof(buf)); sendit(sock, buf); - bstrncpy(buf, " wday=", sizeof(buf)); + bstrncpy(buf, " wday=", sizeof(buf)); for (i=0; i<7; i++) { if (bit_is_set(i, run->wday)) { - bsnprintf(num, sizeof(num), "%d ", i); + bsnprintf(num, sizeof(num), "%d ", i); bstrncat(buf, num, sizeof(buf)); } } - bstrncat(buf, "\n", sizeof(buf)); + bstrncat(buf, "\n", sizeof(buf)); sendit(sock, buf); - bstrncpy(buf, " wom=", sizeof(buf)); + bstrncpy(buf, " wom=", sizeof(buf)); for (i=0; i<5; i++) { if (bit_is_set(i, run->wom)) { - bsnprintf(num, sizeof(num), "%d ", i); + bsnprintf(num, sizeof(num), "%d ", i); bstrncat(buf, num, sizeof(buf)); } } - bstrncat(buf, "\n", sizeof(buf)); + bstrncat(buf, "\n", sizeof(buf)); sendit(sock, buf); - bstrncpy(buf, " woy=", sizeof(buf)); + bstrncpy(buf, " woy=", sizeof(buf)); for (i=0; i<54; i++) { if (bit_is_set(i, run->woy)) { - bsnprintf(num, sizeof(num), "%d ", i); + bsnprintf(num, sizeof(num), "%d ", i); bstrncat(buf, num, sizeof(buf)); } } - bstrncat(buf, "\n", sizeof(buf)); + bstrncat(buf, "\n", sizeof(buf)); sendit(sock, buf); - sendit(sock, " mins=%d\n", run->minute); + sendit(sock, " mins=%d\n", run->minute); if (run->pool) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_POOL, (RES *)run->pool, sendit, sock); } if (run->storage) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_STORAGE, (RES *)run->storage, sendit, sock); } if (run->msgs) { - sendit(sock, " --> "); + sendit(sock, " --> "); dump_resource(-R_MSGS, (RES *)run->msgs, sendit, sock); } /* If another Run record is chained in, go print it */ @@ -713,7 +714,7 @@ next_run: goto next_run; } } else { - sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name); + sendit(sock, "Schedule: name=%s\n", res->res_sch.hdr.name); } break; case R_POOL: @@ -739,9 +740,9 @@ next_run: case R_MSGS: sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name); if (res->res_msgs.mail_cmd) - sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd); + sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd); if (res->res_msgs.operator_cmd) - sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd); + sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd); break; default: sendit(sock, "Unknown resource type %d in dump_resource.\n", type); @@ -996,13 +997,13 @@ void save_resource(int type, RES_ITEM *items, int pass) for (i=0; items[i].name; i++) { if (items[i].flags & ITEM_REQUIRED) { if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { - Emsg2(M_ERROR_TERM, 0, "%s item is required in %s resource, but not found.\n", + Emsg2(M_ERROR_TERM, 0, "%s item is required in %s resource, but not found.\n", items[i].name, resources[rindex]); } } /* If this triggers, take a look at lib/parse_conf.h */ if (i >= MAX_RES_ITEMS) { - Emsg1(M_ERROR_TERM, 0, "Too many items in %s resource\n", resources[rindex]); + Emsg1(M_ERROR_TERM, 0, "Too many items in %s resource\n", resources[rindex]); } } } @@ -1027,14 +1028,14 @@ void save_resource(int type, RES_ITEM *items, int pass) /* Resources containing another resource */ case R_DIRECTOR: if ((res = (URES *)GetResWithName(R_DIRECTOR, res_all.res_dir.hdr.name)) == NULL) { - Emsg1(M_ERROR_TERM, 0, "Cannot find Director resource %s\n", res_all.res_dir.hdr.name); + Emsg1(M_ERROR_TERM, 0, "Cannot find Director resource %s\n", res_all.res_dir.hdr.name); } res->res_dir.messages = res_all.res_dir.messages; break; case R_JOB: case R_JOBDEFS: if ((res = (URES *)GetResWithName(type, res_all.res_dir.hdr.name)) == NULL) { - Emsg1(M_ERROR_TERM, 0, "Cannot find Job resource %s\n", + Emsg1(M_ERROR_TERM, 0, "Cannot find Job resource %s\n", res_all.res_dir.hdr.name); } res->res_job.messages = res_all.res_job.messages; @@ -1053,7 +1054,7 @@ void save_resource(int type, RES_ITEM *items, int pass) break; case R_COUNTER: if ((res = (URES *)GetResWithName(R_COUNTER, res_all.res_counter.hdr.name)) == NULL) { - Emsg1(M_ERROR_TERM, 0, "Cannot find Counter resource %s\n", res_all.res_counter.hdr.name); + Emsg1(M_ERROR_TERM, 0, "Cannot find Counter resource %s\n", res_all.res_counter.hdr.name); } res->res_counter.Catalog = res_all.res_counter.Catalog; res->res_counter.WrapCounter = res_all.res_counter.WrapCounter; @@ -1061,24 +1062,24 @@ void save_resource(int type, RES_ITEM *items, int pass) case R_CLIENT: if ((res = (URES *)GetResWithName(R_CLIENT, res_all.res_client.hdr.name)) == NULL) { - Emsg1(M_ERROR_TERM, 0, "Cannot find Client resource %s\n", res_all.res_client.hdr.name); + Emsg1(M_ERROR_TERM, 0, "Cannot find Client resource %s\n", res_all.res_client.hdr.name); } res->res_client.catalog = res_all.res_client.catalog; break; case R_SCHEDULE: /* * Schedule is a bit different in that it contains a RUN record - * chain which isn't a "named" resource. This chain was linked + * chain which isn't a "named" resource. This chain was linked * in by run_conf.c during pass 2, so here we jam the pointer * into the Schedule resource. */ if ((res = (URES *)GetResWithName(R_SCHEDULE, res_all.res_client.hdr.name)) == NULL) { - Emsg1(M_ERROR_TERM, 0, "Cannot find Schedule resource %s\n", res_all.res_client.hdr.name); + Emsg1(M_ERROR_TERM, 0, "Cannot find Schedule resource %s\n", res_all.res_client.hdr.name); } res->res_sch.run = res_all.res_sch.run; break; default: - Emsg1(M_ERROR, 0, "Unknown resource type %d in save_resource.\n", type); + Emsg1(M_ERROR, 0, "Unknown resource type %d in save_resource.\n", type); error = 1; break; } @@ -1146,7 +1147,7 @@ void save_resource(int type, RES_ITEM *items, int pass) memcpy(res, &res_all, size); if (!res_head[rindex]) { res_head[rindex] = (RES *)res; /* store first entry */ - Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type), + Dmsg3(900, "Inserting first %s res: %s index=%d\n", res_to_str(type), res->res_dir.hdr.name, rindex); } else { RES *next; @@ -1154,12 +1155,12 @@ void save_resource(int type, RES_ITEM *items, int pass) for (next=res_head[rindex]; next->next; next=next->next) { if (strcmp(next->name, res->res_dir.hdr.name) == 0) { Emsg2(M_ERROR_TERM, 0, - _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), + _("Attempt to define second %s resource named \"%s\" is not permitted.\n"), resources[rindex].name, res->res_dir.hdr.name); } } next->next = (RES *)res; - Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(type), + Dmsg4(900, "Inserting %s res: %s index=%d pass=%d\n", res_to_str(type), res->res_dir.hdr.name, rindex, pass); } } @@ -1245,10 +1246,10 @@ void store_acl(LEX *lc, RES_ITEM *item, int index, int pass) if (pass == 1) { if (((alist **)item->value)[item->code] == NULL) { ((alist **)item->value)[item->code] = New(alist(10, owned_by_alist)); - Dmsg1(900, "Defined new ACL alist at %d\n", item->code); + Dmsg1(900, "Defined new ACL alist at %d\n", item->code); } ((alist **)item->value)[item->code]->append(bstrdup(lc->str)); - Dmsg2(900, "Appended to %d %s\n", item->code, lc->str); + Dmsg2(900, "Appended to %d %s\n", item->code, lc->str); } token = lex_get_token(lc, T_ALL); if (token == T_COMMA) { diff --git a/bacula/src/dird/dird_conf.h b/bacula/src/dird/dird_conf.h index 779fe50335..084257de23 100644 --- a/bacula/src/dird/dird_conf.h +++ b/bacula/src/dird/dird_conf.h @@ -6,7 +6,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -44,7 +44,7 @@ enum { R_CONSOLE, R_JOBDEFS, R_FIRST = R_DIRECTOR, - R_LAST = R_JOBDEFS /* keep this updated */ + R_LAST = R_JOBDEFS /* keep this updated */ }; @@ -68,9 +68,9 @@ struct s_kw { /* Job Level keyword structure */ struct s_jl { - const char *level_name; /* level keyword */ - int level; /* level */ - int job_type; /* JobType permitting this level */ + const char *level_name; /* level keyword */ + int level; /* level */ + int job_type; /* JobType permitting this level */ }; /* Job Type keyword structure */ @@ -92,20 +92,20 @@ struct RUN; * */ struct DIRRES { - RES hdr; + RES hdr; dlist *DIRaddrs; - char *password; /* Password for UA access */ - int enable_ssl; /* Use SSL for UA */ - char *query_file; /* SQL query file */ - char *working_directory; /* WorkingDirectory */ + char *password; /* Password for UA access */ + int enable_ssl; /* Use SSL for UA */ + char *query_file; /* SQL query file */ + char *working_directory; /* WorkingDirectory */ const char *scripts_directory; /* ScriptsDirectory */ - char *pid_directory; /* PidDirectory */ - char *subsys_directory; /* SubsysDirectory */ - int require_ssl; /* Require SSL for all connections */ - MSGS *messages; /* Daemon message handler */ - uint32_t MaxConcurrentJobs; /* Max concurrent jobs for whole director */ - utime_t FDConnectTimeout; /* timeout for connect in seconds */ - utime_t SDConnectTimeout; /* timeout in seconds */ + char *pid_directory; /* PidDirectory */ + char *subsys_directory; /* SubsysDirectory */ + int require_ssl; /* Require SSL for all connections */ + MSGS *messages; /* Daemon message handler */ + uint32_t MaxConcurrentJobs; /* Max concurrent jobs for whole director */ + utime_t FDConnectTimeout; /* timeout for connect in seconds */ + utime_t SDConnectTimeout; /* timeout in seconds */ }; @@ -122,17 +122,17 @@ enum { Command_ACL, FileSet_ACL, Catalog_ACL, - Num_ACL /* keep last */ + Num_ACL /* keep last */ }; /* * Console Resource */ struct CONRES { - RES hdr; - char *password; /* UA server password */ - int enable_ssl; /* Use SSL */ - alist *ACL_lists[Num_ACL]; /* pointers to ACLs */ + RES hdr; + char *password; /* UA server password */ + int enable_ssl; /* Use SSL */ + alist *ACL_lists[Num_ACL]; /* pointers to ACLs */ }; @@ -141,15 +141,15 @@ struct CONRES { * */ struct CAT { - RES hdr; + RES hdr; - int db_port; /* Port -- not yet implemented */ - char *db_address; /* host name for remote access */ - char *db_socket; /* Socket for local access */ + int db_port; /* Port -- not yet implemented */ + char *db_address; /* host name for remote access */ + char *db_socket; /* Socket for local access */ char *db_password; char *db_user; char *db_name; - int mult_db_connections; /* set if multiple connections wanted */ + int mult_db_connections; /* set if multiple connections wanted */ }; @@ -158,18 +158,18 @@ struct CAT { * */ struct CLIENT { - RES hdr; + RES hdr; - int FDport; /* Where File daemon listens */ - int AutoPrune; /* Do automatic pruning? */ - utime_t FileRetention; /* file retention period in seconds */ - utime_t JobRetention; /* job retention period in seconds */ + int FDport; /* Where File daemon listens */ + int AutoPrune; /* Do automatic pruning? */ + utime_t FileRetention; /* file retention period in seconds */ + utime_t JobRetention; /* job retention period in seconds */ char *address; char *password; - CAT *catalog; /* Catalog resource */ - uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ - uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ - int enable_ssl; /* Use SSL */ + CAT *catalog; /* Catalog resource */ + uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ + uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ + int enable_ssl; /* Use SSL */ }; /* @@ -177,97 +177,98 @@ struct CLIENT { * */ struct STORE { - RES hdr; + RES hdr; - int SDport; /* port where Directors connect */ - int SDDport; /* data port for File daemon */ + int SDport; /* port where Directors connect */ + int SDDport; /* data port for File daemon */ char *address; char *password; char *media_type; char *dev_name; - int autochanger; /* set if autochanger */ - uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ - uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ - int enable_ssl; /* Use SSL */ + int autochanger; /* set if autochanger */ + uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ + uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ + int enable_ssl; /* Use SSL */ }; -#define MAX_STORE 2 /* Max storage directives in Job */ +#define MAX_STORE 2 /* Max storage directives in Job */ /* * Job Resource */ struct JOB { - RES hdr; - - int JobType; /* job type (backup, verify, restore */ - int JobLevel; /* default backup/verify level */ - int Priority; /* Job priority */ - int RestoreJobId; /* What -- JobId to restore */ - char *RestoreWhere; /* Where on disk to restore -- directory */ - char *RestoreBootstrap; /* Bootstrap file */ - char *RunBeforeJob; /* Run program before Job */ - char *RunAfterJob; /* Run program after Job */ - char *RunAfterFailedJob; /* Run program after Job that errs */ - char *ClientRunBeforeJob; /* Run client program before Job */ - char *ClientRunAfterJob; /* Run client program after Job */ - char *WriteBootstrap; /* Where to write bootstrap Job updates */ - int replace; /* How (overwrite, ..) */ - utime_t MaxRunTime; /* max run time in seconds */ - utime_t MaxWaitTime; /* max blocking time in seconds */ - utime_t MaxStartDelay; /* max start delay in seconds */ - int PrefixLinks; /* prefix soft links with Where path */ - int PruneJobs; /* Force pruning of Jobs */ - int PruneFiles; /* Force pruning of Files */ - int PruneVolumes; /* Force pruning of Volumes */ - int SpoolAttributes; /* Set to spool attributes in SD */ - int spool_data; /* Set to spool data in SD */ - int rerun_failed_levels; /* Upgrade to rerun failed levels */ - uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ - int RescheduleOnError; /* Set to reschedule on error */ - int RescheduleTimes; /* Number of times to reschedule job */ - utime_t RescheduleInterval; /* Reschedule interval */ - utime_t JobRetention; /* job retention period in seconds */ - - MSGS *messages; /* How and where to send messages */ - SCHED *schedule; /* When -- Automatic schedule */ - CLIENT *client; /* Who to backup */ - FILESET *fileset; /* What to backup -- Fileset */ + RES hdr; + + int JobType; /* job type (backup, verify, restore */ + int JobLevel; /* default backup/verify level */ + int Priority; /* Job priority */ + int RestoreJobId; /* What -- JobId to restore */ + char *RestoreWhere; /* Where on disk to restore -- directory */ + char *RestoreBootstrap; /* Bootstrap file */ + char *RunBeforeJob; /* Run program before Job */ + char *RunAfterJob; /* Run program after Job */ + char *RunAfterFailedJob; /* Run program after Job that errs */ + char *ClientRunBeforeJob; /* Run client program before Job */ + char *ClientRunAfterJob; /* Run client program after Job */ + char *WriteBootstrap; /* Where to write bootstrap Job updates */ + int replace; /* How (overwrite, ..) */ + utime_t MaxRunTime; /* max run time in seconds */ + utime_t MaxWaitTime; /* max blocking time in seconds */ + utime_t MaxStartDelay; /* max start delay in seconds */ + int PrefixLinks; /* prefix soft links with Where path */ + int PruneJobs; /* Force pruning of Jobs */ + int PruneFiles; /* Force pruning of Files */ + int PruneVolumes; /* Force pruning of Volumes */ + int SpoolAttributes; /* Set to spool attributes in SD */ + int spool_data; /* Set to spool data in SD */ + int rerun_failed_levels; /* Upgrade to rerun failed levels */ + uint32_t MaxConcurrentJobs; /* Maximume concurrent jobs */ + int RescheduleOnError; /* Set to reschedule on error */ + int RescheduleTimes; /* Number of times to reschedule job */ + utime_t RescheduleInterval; /* Reschedule interval */ + utime_t JobRetention; /* job retention period in seconds */ + bool write_part_after_job; /* Set to write part after job in SD */ + + MSGS *messages; /* How and where to send messages */ + SCHED *schedule; /* When -- Automatic schedule */ + CLIENT *client; /* Who to backup */ + FILESET *fileset; /* What to backup -- Fileset */ alist *storage[MAX_STORE]; /* Where is device -- Storage daemon */ - POOL *pool; /* Where is media -- Media Pool */ - POOL *full_pool; /* Pool for Full backups */ - POOL *inc_pool; /* Pool for Incremental backups */ - POOL *dif_pool; /* Pool for Differental backups */ - JOB *verify_job; /* Job name to verify */ - JOB *jobdefs; /* Job defaults */ - uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ + POOL *pool; /* Where is media -- Media Pool */ + POOL *full_pool; /* Pool for Full backups */ + POOL *inc_pool; /* Pool for Incremental backups */ + POOL *dif_pool; /* Pool for Differental backups */ + JOB *verify_job; /* Job name to verify */ + JOB *jobdefs; /* Job defaults */ + uint32_t NumConcurrentJobs; /* number of concurrent jobs running */ }; -#undef MAX_FOPTS +#undef MAX_FOPTS #define MAX_FOPTS 34 /* File options structure */ struct FOPTS { - char opts[MAX_FOPTS]; /* options string */ - alist regex; /* regex string(s) */ - alist regexdir; /* regex string(s) for directories */ - alist regexfile; /* regex string(s) for files */ - alist wild; /* wild card strings */ - alist wilddir; /* wild card strings for directories */ - alist wildfile; /* wild card strings for files */ - alist base; /* list of base names */ - alist fstype; /* file system type limitation */ - char *reader; /* reader program */ - char *writer; /* writer program */ + char opts[MAX_FOPTS]; /* options string */ + alist regex; /* regex string(s) */ + alist regexdir; /* regex string(s) for directories */ + alist regexfile; /* regex string(s) for files */ + alist wild; /* wild card strings */ + alist wilddir; /* wild card strings for directories */ + alist wildfile; /* wild card strings for files */ + alist base; /* list of base names */ + alist fstype; /* file system type limitation */ + char *reader; /* reader program */ + char *writer; /* writer program */ }; /* This is either an include item or an exclude item */ struct INCEXE { - FOPTS *current_opts; /* points to current options structure */ - FOPTS **opts_list; /* options list */ - int num_opts; /* number of options items */ - alist name_list; /* filename list -- holds char * */ + FOPTS *current_opts; /* points to current options structure */ + FOPTS **opts_list; /* options list */ + int num_opts; /* number of options items */ + alist name_list; /* filename list -- holds char * */ }; /* @@ -275,16 +276,16 @@ struct INCEXE { * */ struct FILESET { - RES hdr; + RES hdr; - bool new_include; /* Set if new include used */ - INCEXE **include_items; /* array of incexe structures */ - int num_includes; /* number in array */ + bool new_include; /* Set if new include used */ + INCEXE **include_items; /* array of incexe structures */ + int num_includes; /* number in array */ INCEXE **exclude_items; int num_excludes; - bool have_MD5; /* set if MD5 initialized */ - struct MD5Context md5c; /* MD5 of include/exclude */ - char MD5[30]; /* base 64 representation of MD5 */ + bool have_MD5; /* set if MD5 initialized */ + struct MD5Context md5c; /* MD5 of include/exclude */ + char MD5[30]; /* base 64 representation of MD5 */ int ignore_fs_changes; /* Don't force Full if FS changed */ }; @@ -294,7 +295,7 @@ struct FILESET { * */ struct SCHED { - RES hdr; + RES hdr; RUN *run; }; @@ -303,14 +304,14 @@ struct SCHED { * Counter Resource */ struct COUNTER { - RES hdr; - - int32_t MinValue; /* Minimum value */ - int32_t MaxValue; /* Maximum value */ - int32_t CurrentValue; /* Current value */ - COUNTER *WrapCounter; /* Wrap counter name */ - CAT *Catalog; /* Where to store */ - bool created; /* Created in DB */ + RES hdr; + + int32_t MinValue; /* Minimum value */ + int32_t MaxValue; /* Maximum value */ + int32_t CurrentValue; /* Current value */ + COUNTER *WrapCounter; /* Wrap counter name */ + CAT *Catalog; /* Where to store */ + bool created; /* Created in DB */ }; /* @@ -318,26 +319,26 @@ struct COUNTER { * */ struct POOL { - RES hdr; - - char *pool_type; /* Pool type */ - char *label_format; /* Label format string */ - char *cleaning_prefix; /* Cleaning label prefix */ - int use_catalog; /* maintain catalog for media */ - int catalog_files; /* maintain file entries in catalog */ - int use_volume_once; /* write on volume only once */ - int accept_any_volume; /* accept any volume */ - int purge_oldest_volume; /* purge oldest volume */ - int recycle_oldest_volume; /* attempt to recycle oldest volume */ - int recycle_current_volume; /* attempt recycle of current volume */ - uint32_t max_volumes; /* max number of volumes */ - utime_t VolRetention; /* volume retention period in seconds */ - utime_t VolUseDuration; /* duration volume can be used */ - uint32_t MaxVolJobs; /* Maximum jobs on the Volume */ - uint32_t MaxVolFiles; /* Maximum files on the Volume */ - uint64_t MaxVolBytes; /* Maximum bytes on the Volume */ - int AutoPrune; /* default for pool auto prune */ - int Recycle; /* default for media recycle yes/no */ + RES hdr; + + char *pool_type; /* Pool type */ + char *label_format; /* Label format string */ + char *cleaning_prefix; /* Cleaning label prefix */ + int use_catalog; /* maintain catalog for media */ + int catalog_files; /* maintain file entries in catalog */ + int use_volume_once; /* write on volume only once */ + int accept_any_volume; /* accept any volume */ + int purge_oldest_volume; /* purge oldest volume */ + int recycle_oldest_volume; /* attempt to recycle oldest volume */ + int recycle_current_volume; /* attempt recycle of current volume */ + uint32_t max_volumes; /* max number of volumes */ + utime_t VolRetention; /* volume retention period in seconds */ + utime_t VolUseDuration; /* duration volume can be used */ + uint32_t MaxVolJobs; /* Maximum jobs on the Volume */ + uint32_t MaxVolFiles; /* Maximum files on the Volume */ + uint64_t MaxVolBytes; /* Maximum bytes on the Volume */ + int AutoPrune; /* default for pool auto prune */ + int Recycle; /* default for media recycle yes/no */ }; @@ -349,37 +350,40 @@ union URES { CONRES res_con; CLIENT res_client; STORE res_store; - CAT res_cat; - JOB res_job; + CAT res_cat; + JOB res_job; FILESET res_fs; SCHED res_sch; POOL res_pool; MSGS res_msgs; COUNTER res_counter; - RES hdr; + RES hdr; }; /* Run structure contained in Schedule Resource */ struct RUN { - RUN *next; /* points to next run record */ - int level; /* level override */ - int Priority; /* priority override */ + RUN *next; /* points to next run record */ + int level; /* level override */ + int Priority; /* priority override */ int job_type; - bool spool_data; /* Data spooling override */ - bool spool_data_set; /* Data spooling override given */ - POOL *pool; /* Pool override */ - POOL *full_pool; /* Pool override */ - POOL *inc_pool; /* Pool override */ - POOL *dif_pool; /* Pool override */ - STORE *storage; /* Storage override */ - MSGS *msgs; /* Messages override */ + bool spool_data; /* Data spooling override */ + bool spool_data_set; /* Data spooling override given */ + bool write_part_after_job; /* Write part after job override */ + bool write_part_after_job_set; /* Write part after job override given */ + + POOL *pool; /* Pool override */ + POOL *full_pool; /* Pool override */ + POOL *inc_pool; /* Pool override */ + POOL *dif_pool; /* Pool override */ + STORE *storage; /* Storage override */ + MSGS *msgs; /* Messages override */ char *since; int level_no; - int minute; /* minute to run job */ - time_t last_run; /* last time run */ - time_t next_run; /* next time to run */ + int minute; /* minute to run job */ + time_t last_run; /* last time run */ + time_t next_run; /* next time to run */ char hour[nbytes_for_bits(24)]; /* bit set for each hour */ char mday[nbytes_for_bits(31)]; /* bit set for each day of month */ char month[nbytes_for_bits(12)]; /* bit set for each month */ diff --git a/bacula/src/dird/fd_cmds.c b/bacula/src/dird/fd_cmds.c index 1c9e389502..e4be6d4c36 100644 --- a/bacula/src/dird/fd_cmds.c +++ b/bacula/src/dird/fd_cmds.c @@ -13,7 +13,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -78,7 +78,7 @@ int connect_to_file_daemon(JCR *jcr, int retry_interval, int max_retry_time, if (!jcr->file_bsock) { fd = bnet_connect(jcr, retry_interval, max_retry_time, - _("File daemon"), jcr->client->address, + _("File daemon"), jcr->client->address, NULL, jcr->client->FDport, verbose); if (fd == NULL) { set_jcr_job_status(jcr, JS_ErrorTerminated); @@ -109,7 +109,7 @@ int connect_to_file_daemon(JCR *jcr, int retry_interval, int max_retry_time, if (bget_dirmsg(fd) > 0) { Dmsg1(110, "msg); if (strncmp(fd->msg, OKjob, strlen(OKjob)) != 0) { - Jmsg(jcr, M_FATAL, 0, _("File daemon \"%s\" rejected Job command: %s\n"), + Jmsg(jcr, M_FATAL, 0, _("File daemon \"%s\" rejected Job command: %s\n"), jcr->client->hdr.name, fd->msg); set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; @@ -122,7 +122,7 @@ int connect_to_file_daemon(JCR *jcr, int retry_interval, int max_retry_time, cr.JobRetention = jcr->client->JobRetention; bstrncpy(cr.Uname, fd->msg+strlen(OKjob)+1, sizeof(cr.Uname)); if (!db_update_client_record(jcr, jcr->db, &cr)) { - Jmsg(jcr, M_WARNING, 0, _("Error updating Client record. ERR=%s\n"), + Jmsg(jcr, M_WARNING, 0, _("Error updating Client record. ERR=%s\n"), db_strerror(jcr->db)); } } @@ -160,24 +160,24 @@ void get_level_since_time(JCR *jcr, char *since, int since_len) jcr->jr.JobId = 0; /* flag for db_find_job_start time */ if (!db_find_job_start_time(jcr, jcr->db, &jcr->jr, &jcr->stime)) { /* No job found, so upgrade this one to Full */ - Jmsg(jcr, M_INFO, 0, "%s", db_strerror(jcr->db)); - Jmsg(jcr, M_INFO, 0, _("No prior or suitable Full backup found. Doing FULL backup.\n")); - bsnprintf(since, since_len, " (upgraded from %s)", + Jmsg(jcr, M_INFO, 0, "%s", db_strerror(jcr->db)); + Jmsg(jcr, M_INFO, 0, _("No prior or suitable Full backup found. Doing FULL backup.\n")); + bsnprintf(since, since_len, " (upgraded from %s)", level_to_str(jcr->JobLevel)); jcr->JobLevel = jcr->jr.JobLevel = L_FULL; } else { if (jcr->job->rerun_failed_levels) { if (db_find_failed_job_since(jcr, jcr->db, &jcr->jr, jcr->stime, JobLevel)) { - Jmsg(jcr, M_INFO, 0, _("Prior failed job found. Upgrading to %s.\n"), + Jmsg(jcr, M_INFO, 0, _("Prior failed job found. Upgrading to %s.\n"), level_to_str(JobLevel)); - bsnprintf(since, since_len, " (upgraded from %s)", + bsnprintf(since, since_len, " (upgraded from %s)", level_to_str(jcr->JobLevel)); jcr->JobLevel = jcr->jr.JobLevel = JobLevel; jcr->jr.JobId = jcr->JobId; break; } } - bstrncpy(since, ", since=", since_len); + bstrncpy(since, ", since=", since_len); bstrncat(since, jcr->stime, since_len); } jcr->jr.JobId = jcr->JobId; @@ -213,7 +213,7 @@ int send_level_command(JCR *jcr) stime = str_to_utime(jcr->stime); bnet_fsend(fd, levelcmd, "since_utime ", edit_uint64(stime, ed1), 0); while (bget_dirmsg(fd) >= 0) { /* allow him to poll us to sync clocks */ - Jmsg(jcr, M_INFO, 0, "%s\n", fd->msg); + Jmsg(jcr, M_INFO, 0, "%s\n", fd->msg); } break; case L_SINCE: @@ -265,80 +265,80 @@ static int send_list(JCR *jcr, int list) for (int j=0; jname_list.size(); j++) { p = (char *)ie->name_list.get(j); switch (*p) { - case '|': + case '|': p++; /* skip over the | */ - fd->msg = edit_job_codes(jcr, fd->msg, p, ""); - bpipe = open_bpipe(fd->msg, 0, "r"); + fd->msg = edit_job_codes(jcr, fd->msg, p, ""); + bpipe = open_bpipe(fd->msg, 0, "r"); if (!bpipe) { berrno be; - Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"), p, be.strerror()); goto bail_out; } /* Copy File options */ if (ie->num_opts) { bstrncpy(buf, ie->opts_list[0]->opts, sizeof(buf)); - bstrncat(buf, " ", sizeof(buf)); + bstrncat(buf, " ", sizeof(buf)); } else { - bstrncpy(buf, "0 ", sizeof(buf)); + bstrncpy(buf, "0 ", sizeof(buf)); } - Dmsg1(500, "Opts=%s\n", buf); + Dmsg1(500, "Opts=%s\n", buf); optlen = strlen(buf); while (fgets(buf+optlen, sizeof(buf)-optlen, bpipe->rfd)) { - fd->msglen = Mmsg(fd->msg, "%s", buf); - Dmsg2(500, "Inc/exc len=%d: %s", fd->msglen, fd->msg); + fd->msglen = Mmsg(fd->msg, "%s", buf); + Dmsg2(500, "Inc/exc len=%d: %s", fd->msglen, fd->msg); if (!bnet_send(fd)) { - Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); + Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); goto bail_out; } } if ((stat=close_bpipe(bpipe)) != 0) { berrno be; - Jmsg(jcr, M_FATAL, 0, _("Error running program %p: ERR=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Error running program %p: ERR=%s\n"), p, be.strerror(stat)); goto bail_out; } break; - case '<': + case '<': p++; /* skip over < */ - if ((ffd = fopen(p, "r")) == NULL) { - Jmsg(jcr, M_FATAL, 0, _("Cannot open %s file: %s. ERR=%s\n"), - list==INC_LIST?"included":"excluded", p, strerror(errno)); + if ((ffd = fopen(p, "r")) == NULL) { + Jmsg(jcr, M_FATAL, 0, _("Cannot open %s file: %s. ERR=%s\n"), + list==INC_LIST?"included":"excluded", p, strerror(errno)); goto bail_out; } /* Copy File options */ if (ie->num_opts) { bstrncpy(buf, ie->opts_list[0]->opts, sizeof(buf)); - bstrncat(buf, " ", sizeof(buf)); + bstrncat(buf, " ", sizeof(buf)); } else { - bstrncpy(buf, "0 ", sizeof(buf)); + bstrncpy(buf, "0 ", sizeof(buf)); } - Dmsg1(500, "Opts=%s\n", buf); + Dmsg1(500, "Opts=%s\n", buf); optlen = strlen(buf); while (fgets(buf+optlen, sizeof(buf)-optlen, ffd)) { - fd->msglen = Mmsg(fd->msg, "%s", buf); + fd->msglen = Mmsg(fd->msg, "%s", buf); if (!bnet_send(fd)) { - Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); + Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); goto bail_out; } } fclose(ffd); break; - case '\\': - p++; /* skip over \ */ + case '\\': + p++; /* skip over \ */ /* Note, fall through wanted */ default: if (ie->num_opts) { - Dmsg2(500, "numopts=%d opts=%s\n", ie->num_opts, NPRT(ie->opts_list[0]->opts)); + Dmsg2(500, "numopts=%d opts=%s\n", ie->num_opts, NPRT(ie->opts_list[0]->opts)); pm_strcpy(fd->msg, ie->opts_list[0]->opts); - pm_strcat(fd->msg, " "); + pm_strcat(fd->msg, " "); } else { - pm_strcpy(fd->msg, "0 "); + pm_strcpy(fd->msg, "0 "); } fd->msglen = pm_strcat(fd->msg, p); - Dmsg1(500, "Inc/Exc name=%s\n", fd->msg); + Dmsg1(500, "Inc/Exc name=%s\n", fd->msg); if (!bnet_send(fd)) { - Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); + Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); goto bail_out; } break; @@ -389,113 +389,113 @@ static int send_fileset(JCR *jcr) if (include) { ie = fileset->include_items[i]; - bnet_fsend(fd, "I\n"); + bnet_fsend(fd, "I\n"); } else { ie = fileset->exclude_items[i]; - bnet_fsend(fd, "E\n"); + bnet_fsend(fd, "E\n"); } for (j=0; jnum_opts; j++) { FOPTS *fo = ie->opts_list[j]; - bnet_fsend(fd, "O %s\n", fo->opts); + bnet_fsend(fd, "O %s\n", fo->opts); for (k=0; kregex.size(); k++) { - bnet_fsend(fd, "R %s\n", fo->regex.get(k)); + bnet_fsend(fd, "R %s\n", fo->regex.get(k)); } for (k=0; kregexdir.size(); k++) { - bnet_fsend(fd, "RD %s\n", fo->regexdir.get(k)); + bnet_fsend(fd, "RD %s\n", fo->regexdir.get(k)); } for (k=0; kregexfile.size(); k++) { - bnet_fsend(fd, "RF %s\n", fo->regexfile.get(k)); + bnet_fsend(fd, "RF %s\n", fo->regexfile.get(k)); } for (k=0; kwild.size(); k++) { - bnet_fsend(fd, "W %s\n", fo->wild.get(k)); + bnet_fsend(fd, "W %s\n", fo->wild.get(k)); } for (k=0; kwilddir.size(); k++) { - bnet_fsend(fd, "WD %s\n", fo->wilddir.get(k)); + bnet_fsend(fd, "WD %s\n", fo->wilddir.get(k)); } for (k=0; kwildfile.size(); k++) { - bnet_fsend(fd, "WF %s\n", fo->wildfile.get(k)); + bnet_fsend(fd, "WF %s\n", fo->wildfile.get(k)); } for (k=0; kbase.size(); k++) { - bnet_fsend(fd, "B %s\n", fo->base.get(k)); + bnet_fsend(fd, "B %s\n", fo->base.get(k)); } for (k=0; kfstype.size(); k++) { - bnet_fsend(fd, "X %s\n", fo->fstype.get(k)); + bnet_fsend(fd, "X %s\n", fo->fstype.get(k)); } if (fo->reader) { - bnet_fsend(fd, "D %s\n", fo->reader); + bnet_fsend(fd, "D %s\n", fo->reader); } if (fo->writer) { - bnet_fsend(fd, "T %s\n", fo->writer); + bnet_fsend(fd, "T %s\n", fo->writer); } - bnet_fsend(fd, "N\n"); + bnet_fsend(fd, "N\n"); } for (j=0; jname_list.size(); j++) { p = (char *)ie->name_list.get(j); switch (*p) { - case '|': + case '|': p++; /* skip over the | */ - fd->msg = edit_job_codes(jcr, fd->msg, p, ""); - bpipe = open_bpipe(fd->msg, 0, "r"); + fd->msg = edit_job_codes(jcr, fd->msg, p, ""); + bpipe = open_bpipe(fd->msg, 0, "r"); if (!bpipe) { berrno be; - Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Cannot run program: %s. ERR=%s\n"), p, be.strerror()); goto bail_out; } - bstrncpy(buf, "F ", sizeof(buf)); - Dmsg1(500, "Opts=%s\n", buf); + bstrncpy(buf, "F ", sizeof(buf)); + Dmsg1(500, "Opts=%s\n", buf); optlen = strlen(buf); while (fgets(buf+optlen, sizeof(buf)-optlen, bpipe->rfd)) { - fd->msglen = Mmsg(fd->msg, "%s", buf); - Dmsg2(500, "Inc/exc len=%d: %s", fd->msglen, fd->msg); + fd->msglen = Mmsg(fd->msg, "%s", buf); + Dmsg2(500, "Inc/exc len=%d: %s", fd->msglen, fd->msg); if (!bnet_send(fd)) { - Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); + Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); goto bail_out; } } if ((stat=close_bpipe(bpipe)) != 0) { berrno be; - Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. ERR=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Error running program: %s. ERR=%s\n"), p, be.strerror(stat)); goto bail_out; } break; - case '<': + case '<': p++; /* skip over < */ - if ((ffd = fopen(p, "r")) == NULL) { + if ((ffd = fopen(p, "r")) == NULL) { berrno be; - Jmsg(jcr, M_FATAL, 0, _("Cannot open included file: %s. ERR=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Cannot open included file: %s. ERR=%s\n"), p, be.strerror()); goto bail_out; } - bstrncpy(buf, "F ", sizeof(buf)); - Dmsg1(500, "Opts=%s\n", buf); + bstrncpy(buf, "F ", sizeof(buf)); + Dmsg1(500, "Opts=%s\n", buf); optlen = strlen(buf); while (fgets(buf+optlen, sizeof(buf)-optlen, ffd)) { - fd->msglen = Mmsg(fd->msg, "%s", buf); + fd->msglen = Mmsg(fd->msg, "%s", buf); if (!bnet_send(fd)) { - Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); + Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); goto bail_out; } } fclose(ffd); break; - case '\\': - p++; /* skip over \ */ + case '\\': + p++; /* skip over \ */ /* Note, fall through wanted */ default: - pm_strcpy(fd->msg, "F "); + pm_strcpy(fd->msg, "F "); fd->msglen = pm_strcat(fd->msg, p); - Dmsg1(500, "Inc/Exc name=%s\n", fd->msg); + Dmsg1(500, "Inc/Exc name=%s\n", fd->msg); if (!bnet_send(fd)) { - Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); + Jmsg(jcr, M_FATAL, 0, _(">filed: write error on socket\n")); goto bail_out; } break; } } - bnet_fsend(fd, "N\n"); + bnet_fsend(fd, "N\n"); } if (!include) { /* If we just did excludes */ break; /* all done */ @@ -645,7 +645,7 @@ int get_attributes_and_put_in_catalog(JCR *jcr) jcr->fname = check_pool_memory_size(jcr->fname, fd->msglen); if ((len = sscanf(fd->msg, "%ld %d %s", &file_index, &stream, Opts_SIG)) != 3) { - Jmsg(jcr, M_FATAL, 0, _("msglen, fd->msg); set_jcr_job_status(jcr, JS_ErrorTerminated); return 0; @@ -677,27 +677,27 @@ int get_attributes_and_put_in_catalog(JCR *jcr) ar.PathId = 0; ar.FilenameId = 0; - Dmsg2(111, "dirdfname); - Dmsg1(120, "dirdfname); + Dmsg1(120, "dirddb, &ar)) { - Jmsg1(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); + Jmsg1(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); set_jcr_job_status(jcr, JS_Error); continue; } jcr->FileId = ar.FileId; } else if (stream == STREAM_MD5_SIGNATURE || stream == STREAM_SHA1_SIGNATURE) { if (jcr->FileIndex != (uint32_t)file_index) { - Jmsg2(jcr, M_ERROR, 0, _("MD5/SHA1 index %d not same as attributes %d\n"), + Jmsg2(jcr, M_ERROR, 0, _("MD5/SHA1 index %d not same as attributes %d\n"), file_index, jcr->FileIndex); set_jcr_job_status(jcr, JS_Error); continue; } db_escape_string(SIG, Opts_SIG, strlen(Opts_SIG)); - Dmsg2(120, "SIGlen=%d SIG=%s\n", strlen(SIG), SIG); + Dmsg2(120, "SIGlen=%d SIG=%s\n", strlen(SIG), SIG); if (!db_add_SIG_to_file_record(jcr, jcr->db, jcr->FileId, SIG, stream==STREAM_MD5_SIGNATURE?MD5_SIG:SHA1_SIG)) { - Jmsg1(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); + Jmsg1(jcr, M_ERROR, 0, "%s", db_strerror(jcr->db)); set_jcr_job_status(jcr, JS_Error); } } diff --git a/bacula/src/dird/inc_conf.c b/bacula/src/dird/inc_conf.c index d1ec4bb8ca..6f30607143 100644 --- a/bacula/src/dird/inc_conf.c +++ b/bacula/src/dird/inc_conf.c @@ -7,7 +7,7 @@ * Version $Id$ */ /* - Copyright (C) 2003-2004 Kern Sibbald + Copyright (C) 2003-2005 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 @@ -497,15 +497,15 @@ static void store_regex(LEX *lc, RES_ITEM *item, int index, int pass) } regfree(&preg); if (item->code == 1) { - type = "regexdir"; + type = "regexdir"; res_incexe.current_opts->regexdir.append(bstrdup(lc->str)); newsize = res_incexe.current_opts->regexdir.size(); } else if (item->code == 2) { - type = "regexfile"; + type = "regexfile"; res_incexe.current_opts->regexfile.append(bstrdup(lc->str)); newsize = res_incexe.current_opts->regexfile.size(); } else { - type = "regex"; + type = "regex"; res_incexe.current_opts->regex.append(bstrdup(lc->str)); newsize = res_incexe.current_opts->regex.size(); } @@ -583,15 +583,15 @@ static void store_wild(LEX *lc, RES_ITEM *item, int index, int pass) case T_UNQUOTED_STRING: case T_QUOTED_STRING: if (item->code == 1) { - type = "wilddir"; + type = "wilddir"; res_incexe.current_opts->wilddir.append(bstrdup(lc->str)); newsize = res_incexe.current_opts->wilddir.size(); } else if (item->code == 2) { - type = "wildfile"; + type = "wildfile"; res_incexe.current_opts->wildfile.append(bstrdup(lc->str)); newsize = res_incexe.current_opts->wildfile.size(); } else { - type = "wild"; + type = "wild"; res_incexe.current_opts->wild.append(bstrdup(lc->str)); newsize = res_incexe.current_opts->wild.size(); } diff --git a/bacula/src/dird/job.c b/bacula/src/dird/job.c index 44d14fec75..de88b1e914 100644 --- a/bacula/src/dird/job.c +++ b/bacula/src/dird/job.c @@ -7,7 +7,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald + Copyright (C) 2000-2005 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 @@ -786,6 +786,7 @@ void set_jcr_defaults(JCR *jcr, JOB *job) jcr->fileset = job->fileset; jcr->messages = job->messages; jcr->spool_data = job->spool_data; + jcr->write_part_after_job = job->write_part_after_job; if (jcr->RestoreBootstrap) { free(jcr->RestoreBootstrap); jcr->RestoreBootstrap = NULL; diff --git a/bacula/src/dird/msgchan.c b/bacula/src/dird/msgchan.c index f5c8ee2ff0..b34e29e4c0 100644 --- a/bacula/src/dird/msgchan.c +++ b/bacula/src/dird/msgchan.c @@ -16,7 +16,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald + Copyright (C) 2000-2005 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 @@ -40,7 +40,7 @@ /* Commands sent to Storage daemon */ static char jobcmd[] = "JobId=%d job=%s job_name=%s client_name=%s " -"type=%d level=%d FileSet=%s NoAttr=%d SpoolAttr=%d FileSetMD5=%s SpoolData=%d"; +"type=%d level=%d FileSet=%s NoAttr=%d SpoolAttr=%d FileSetMD5=%s SpoolData=%d WritePartAfterJob=%d"; static char use_device[] = "use device=%s media_type=%s pool_name=%s pool_type=%s\n"; /* Response from Storage daemon */ @@ -74,7 +74,7 @@ bool connect_to_storage_daemon(JCR *jcr, int retry_interval, Dmsg2(200, "bnet_connect to Storage daemon %s:%d\n", store->address, store->SDport); sd = bnet_connect(jcr, retry_interval, max_retry_time, - _("Storage daemon"), store->address, + _("Storage daemon"), store->address, NULL, store->SDport, verbose); if (sd == NULL) { return false; @@ -113,7 +113,7 @@ int start_storage_daemon_job(JCR *jcr) bnet_fsend(sd, jobcmd, jcr->JobId, jcr->Job, jcr->job->hdr.name, jcr->client->hdr.name, jcr->JobType, jcr->JobLevel, jcr->fileset->hdr.name, !jcr->pool->catalog_files, - jcr->job->SpoolAttributes, jcr->fileset->MD5, jcr->spool_data); + jcr->job->SpoolAttributes, jcr->fileset->MD5, jcr->spool_data, jcr->write_part_after_job); Dmsg1(200, "Jobcmd=%s\n", sd->msg); unbash_spaces(jcr->job->hdr.name); unbash_spaces(jcr->client->hdr.name); @@ -122,12 +122,12 @@ int start_storage_daemon_job(JCR *jcr) Dmsg1(110, "msg); if (sscanf(sd->msg, OKjob, &jcr->VolSessionId, &jcr->VolSessionTime, &auth_key) != 3) { - Dmsg1(100, "BadJob=%s\n", sd->msg); - Jmsg(jcr, M_FATAL, 0, _("Storage daemon rejected Job command: %s\n"), sd->msg); + Dmsg1(100, "BadJob=%s\n", sd->msg); + Jmsg(jcr, M_FATAL, 0, _("Storage daemon rejected Job command: %s\n"), sd->msg); return 0; } else { jcr->sd_auth_key = bstrdup(auth_key); - Dmsg1(150, "sd_auth_key=%s\n", jcr->sd_auth_key); + Dmsg1(150, "sd_auth_key=%s\n", jcr->sd_auth_key); } } else { Jmsg(jcr, M_FATAL, 0, _("stored: %s", sd->msg); - status = response(jcr, sd, OK_device, "Use Device", NO_DISPLAY); + Dmsg1(110, ">stored: %s", sd->msg); + status = response(jcr, sd, OK_device, "Use Device", NO_DISPLAY); if (!status) { pm_strcpy(pool_type, sd->msg); /* save message */ - Jmsg(jcr, M_FATAL, 0, _("\n" - " Storage daemon didn't accept Device \"%s\" because:\n %s"), + Jmsg(jcr, M_FATAL, 0, _("\n" + " Storage daemon didn't accept Device \"%s\" because:\n %s"), device_name.c_str(), pool_type.c_str()/* sd->msg */); } } diff --git a/bacula/src/dird/python.c b/bacula/src/dird/python.c index 882e1ae236..50e71cd605 100644 --- a/bacula/src/dird/python.c +++ b/bacula/src/dird/python.c @@ -9,8 +9,7 @@ */ /* - - Copyright (C) 2004 Kern Sibbald + Copyright (C) 2000-2005 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 diff --git a/bacula/src/dird/run_conf.c b/bacula/src/dird/run_conf.c index cd3092a262..23f5956dc2 100644 --- a/bacula/src/dird/run_conf.c +++ b/bacula/src/dird/run_conf.c @@ -8,7 +8,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -139,15 +139,16 @@ static void set_defaults() /* Keywords (RHS) permitted in Run records */ static struct s_kw RunFields[] = { - {"pool", 'P'}, - {"fullpool", 'f'}, - {"incrementalpool", 'i'}, - {"differentialpool", 'd'}, - {"level", 'L'}, - {"storage", 'S'}, - {"messages", 'M'}, - {"priority", 'p'}, - {"spooldata", 's'}, + {"pool", 'P'}, + {"fullpool", 'f'}, + {"incrementalpool", 'i'}, + {"differentialpool", 'd'}, + {"level", 'L'}, + {"storage", 'S'}, + {"messages", 'M'}, + {"priority", 'p'}, + {"spooldata", 's'}, + {"writepartafterjob", 'W'}, {NULL, 0} }; @@ -189,23 +190,35 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) if (strcasecmp(lc->str, RunFields[i].name) == 0) { found = true; if (lex_get_token(lc, T_ALL) != T_EQUALS) { - scan_err1(lc, "Expected an equals, got: %s", lc->str); + scan_err1(lc, "Expected an equals, got: %s", lc->str); /* NOT REACHED */ } switch (RunFields[i].token) { - case 's': /* Data spooling */ + case 's': /* Data spooling */ token = lex_get_token(lc, T_NAME); - if (strcasecmp(lc->str, "yes") == 0) { + if (strcasecmp(lc->str, "yes") == 0) { lrun.spool_data = true; lrun.spool_data_set = true; - } else if (strcasecmp(lc->str, "no") == 0) { + } else if (strcasecmp(lc->str, "no") == 0) { lrun.spool_data = false; lrun.spool_data_set = true; } else { - scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str); + scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str); } break; - case 'L': /* level */ + case 'W': /* Write part after job */ + token = lex_get_token(lc, T_NAME); + if (strcasecmp(lc->str, "yes") == 0) { + lrun.write_part_after_job = true; + lrun.write_part_after_job_set = true; + } else if (strcasecmp(lc->str, "no") == 0) { + lrun.write_part_after_job = false; + lrun.write_part_after_job_set = true; + } else { + scan_err1(lc, _("Expect a YES or NO, got: %s"), lc->str); + } + break; + case 'L': /* level */ token = lex_get_token(lc, T_NAME); for (j=0; joblevels[j].level_name; j++) { if (strcasecmp(lc->str, joblevels[j].level_name) == 0) { @@ -216,62 +229,62 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) } } if (j != 0) { - scan_err1(lc, _("Job level field: %s not found in run record"), lc->str); + scan_err1(lc, _("Job level field: %s not found in run record"), lc->str); /* NOT REACHED */ } break; - case 'p': /* Priority */ + case 'p': /* Priority */ token = lex_get_token(lc, T_PINT32); if (pass == 2) { lrun.Priority = lc->pint32_val; } break; - case 'P': /* Pool */ - case 'f': /* FullPool */ - case 'i': /* IncPool */ - case 'd': /* DifPool */ + case 'P': /* Pool */ + case 'f': /* FullPool */ + case 'i': /* IncPool */ + case 'd': /* DifPool */ token = lex_get_token(lc, T_NAME); if (pass == 2) { res = GetResWithName(R_POOL, lc->str); if (res == NULL) { - scan_err1(lc, "Could not find specified Pool Resource: %s", + scan_err1(lc, "Could not find specified Pool Resource: %s", lc->str); /* NOT REACHED */ } switch(RunFields[i].token) { - case 'P': + case 'P': lrun.pool = (POOL *)res; break; - case 'f': + case 'f': lrun.full_pool = (POOL *)res; break; - case 'i': + case 'i': lrun.inc_pool = (POOL *)res; break; - case 'd': + case 'd': lrun.dif_pool = (POOL *)res; break; } } break; - case 'S': /* storage */ + case 'S': /* storage */ token = lex_get_token(lc, T_NAME); if (pass == 2) { res = GetResWithName(R_STORAGE, lc->str); if (res == NULL) { - scan_err1(lc, "Could not find specified Storage Resource: %s", + scan_err1(lc, "Could not find specified Storage Resource: %s", lc->str); /* NOT REACHED */ } lrun.storage = (STORE *)res; } break; - case 'M': /* messages */ + case 'M': /* messages */ token = lex_get_token(lc, T_NAME); if (pass == 2) { res = GetResWithName(R_MSGS, lc->str); if (res == NULL) { - scan_err1(lc, "Could not find specified Messages Resource: %s", + scan_err1(lc, "Could not find specified Messages Resource: %s", lc->str); /* NOT REACHED */ } @@ -279,7 +292,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) } break; default: - scan_err1(lc, "Expected a keyword name, got: %s", lc->str); + scan_err1(lc, "Expected a keyword name, got: %s", lc->str); /* NOT REACHED */ break; } /* end switch */ @@ -314,24 +327,24 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) state = s_mday; code = atoi(lc->str) - 1; if (code < 0 || code > 30) { - scan_err0(lc, _("Day number out of range (1-31)")); + scan_err0(lc, _("Day number out of range (1-31)")); } break; case T_NAME: /* this handles drop through from keyword */ case T_UNQUOTED_STRING: - if (strchr(lc->str, (int)'-')) { + if (strchr(lc->str, (int)'-')) { state = s_range; break; } - if (strchr(lc->str, (int)':')) { + if (strchr(lc->str, (int)':')) { state = s_time; break; } - if (lc->str_len == 3 && (lc->str[0] == 'w' || lc->str[0] == 'W') && + if (lc->str_len == 3 && (lc->str[0] == 'w' || lc->str[0] == 'W') && is_an_integer(lc->str+1)) { code = atoi(lc->str+1); if (code < 0 || code > 53) { - scan_err0(lc, _("Week number out of range (0-53)")); + scan_err0(lc, _("Week number out of range (0-53)")); } state = s_woy; /* week of year */ break; @@ -346,14 +359,14 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) } } if (i != 0) { - scan_err1(lc, _("Job type field: %s in run record not found"), lc->str); + scan_err1(lc, _("Job type field: %s in run record not found"), lc->str); /* NOT REACHED */ } break; case T_COMMA: continue; default: - scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str); + scan_err2(lc, _("Unexpected token: %d:%s"), token, lc->str); /* NOT REACHED */ break; } @@ -397,27 +410,27 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) break; case s_time: /* time */ if (!have_at) { - scan_err0(lc, _("Time must be preceded by keyword AT.")); + scan_err0(lc, _("Time must be preceded by keyword AT.")); /* NOT REACHED */ } if (!have_hour) { clear_bits(0, 23, lrun.hour); } - p = strchr(lc->str, ':'); + p = strchr(lc->str, ':'); if (!p) { - scan_err0(lc, _("Time logic error.\n")); + scan_err0(lc, _("Time logic error.\n")); /* NOT REACHED */ } *p++ = 0; /* separate two halves */ code = atoi(lc->str); len = strlen(p); - if (len > 2 && p[len-1] == 'm') { - if (p[len-2] == 'a') { + if (len > 2 && p[len-1] == 'm') { + if (p[len-2] == 'a') { pm = 0; - } else if (p[len-2] == 'p') { + } else if (p[len-2] == 'p') { pm = 1; } else { - scan_err0(lc, _("Bad time specification.")); + scan_err0(lc, _("Bad time specification.")); /* NOT REACHED */ } } else { @@ -428,7 +441,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) code += 12; } if (code < 0 || code > 23 || code2 < 0 || code2 > 59) { - scan_err0(lc, _("Bad time specification.")); + scan_err0(lc, _("Bad time specification.")); /* NOT REACHED */ } /****FIXME**** convert to UTC */ @@ -440,9 +453,9 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) have_at = true; break; case s_range: - p = strchr(lc->str, '-'); + p = strchr(lc->str, '-'); if (!p) { - scan_err0(lc, _("Range logic error.\n")); + scan_err0(lc, _("Range logic error.\n")); } *p++ = 0; /* separate two halves */ @@ -451,7 +464,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) code = atoi(lc->str) - 1; code2 = atoi(p) - 1; if (code < 0 || code > 30 || code2 < 0 || code2 > 30) { - scan_err0(lc, _("Bad day range specification.")); + scan_err0(lc, _("Bad day range specification.")); } if (!have_mday) { clear_bits(0, 30, lrun.mday); @@ -467,13 +480,13 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) } /* Check for week of year range */ if (strlen(lc->str) == 3 && strlen(p) == 3 && - (lc->str[0] == 'w' || lc->str[0] == 'W') && - (p[0] == 'w' || p[0] == 'W') && + (lc->str[0] == 'w' || lc->str[0] == 'W') && + (p[0] == 'w' || p[0] == 'W') && is_an_integer(lc->str+1) && is_an_integer(p+1)) { code = atoi(lc->str+1); code2 = atoi(p+1); if (code < 0 || code > 53 || code2 < 0 || code2 > 53) { - scan_err0(lc, _("Week number out of range (0-53)")); + scan_err0(lc, _("Week number out of range (0-53)")); } if (!have_woy) { clear_bits(0, 53, lrun.woy); @@ -498,7 +511,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) } } if (i != 0 || (state != s_month && state != s_wday && state != s_wom)) { - scan_err0(lc, _("Invalid month, week or position day range")); + scan_err0(lc, _("Invalid month, week or position day range")); /* NOT REACHED */ } @@ -513,7 +526,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) } } if (i != 0 || state != state2 || code == code2) { - scan_err0(lc, _("Invalid month, weekday or position range")); + scan_err0(lc, _("Invalid month, weekday or position range")); /* NOT REACHED */ } if (state == s_wday) { @@ -572,7 +585,7 @@ void store_run(LEX *lc, RES_ITEM *item, int index, int pass) set_bits(0, 11, lrun.month); break; default: - scan_err0(lc, _("Unexpected run state\n")); + scan_err0(lc, _("Unexpected run state\n")); /* NOT REACHED */ break; } diff --git a/bacula/src/dird/scheduler.c b/bacula/src/dird/scheduler.c index abe5668a86..3cbcee5000 100644 --- a/bacula/src/dird/scheduler.c +++ b/bacula/src/dird/scheduler.c @@ -10,7 +10,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald + Copyright (C) 2000-2005 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 @@ -82,9 +82,9 @@ JCR *wait_for_next_job(char *one_shot_job_to_run) if (one_shot_job_to_run) { /* one shot */ job = (JOB *)GetResWithName(R_JOB, one_shot_job_to_run); if (!job) { - Emsg1(M_ABORT, 0, _("Job %s not found\n"), one_shot_job_to_run); + Emsg1(M_ABORT, 0, _("Job %s not found\n"), one_shot_job_to_run); } - Dmsg1(5, "Found one_shot_job_to_run %s\n", one_shot_job_to_run); + Dmsg1(5, "Found one_shot_job_to_run %s\n", one_shot_job_to_run); jcr = new_jcr(sizeof(JCR), dird_free_jcr); set_jcr_defaults(jcr, job); return jcr; @@ -168,6 +168,9 @@ JCR *wait_for_next_job(char *one_shot_job_to_run) if (run->spool_data_set) { jcr->spool_data = run->spool_data; } + if (run->write_part_after_job_set) { + jcr->write_part_after_job = run->write_part_after_job; + } Dmsg0(200, "Leave wait_for_next_job()\n"); return jcr; } @@ -246,10 +249,10 @@ static void find_runs() * Find runs scheduled between now and the next hour. */ #ifdef xxxx - Dmsg0(000, "\n"); - Dmsg6(000, "run h=%d m=%d md=%d wd=%d wom=%d woy=%d\n", + Dmsg0(000, "\n"); + Dmsg6(000, "run h=%d m=%d md=%d wd=%d wom=%d woy=%d\n", hour, month, mday, wday, wom, woy); - Dmsg6(000, "bitset bsh=%d bsm=%d bsmd=%d bswd=%d bswom=%d bswoy=%d\n", + Dmsg6(000, "bitset bsh=%d bsm=%d bsmd=%d bswd=%d bswom=%d bswoy=%d\n", bit_is_set(hour, run->hour), bit_is_set(month, run->month), bit_is_set(mday, run->mday), @@ -257,9 +260,9 @@ static void find_runs() bit_is_set(wom, run->wom), bit_is_set(woy, run->woy)); - Dmsg6(000, "nh_run h=%d m=%d md=%d wd=%d wom=%d woy=%d\n", + Dmsg6(000, "nh_run h=%d m=%d md=%d wd=%d wom=%d woy=%d\n", nh_hour, nh_month, nh_mday, nh_wday, nh_wom, nh_woy); - Dmsg6(000, "nh_bitset bsh=%d bsm=%d bsmd=%d bswd=%d bswom=%d bswoy=%d\n", + Dmsg6(000, "nh_bitset bsh=%d bsm=%d bsmd=%d bswd=%d bswom=%d bswoy=%d\n", bit_is_set(nh_hour, run->hour), bit_is_set(nh_month, run->month), bit_is_set(nh_mday, run->mday), @@ -282,7 +285,7 @@ static void find_runs() bit_is_set(nh_wom, run->wom) && bit_is_set(nh_woy, run->woy); - Dmsg2(200, "run_now=%d run_nh=%d\n", run_now, run_nh); + Dmsg2(200, "run_now=%d run_nh=%d\n", run_now, run_nh); /* find time (time_t) job is to be run */ localtime_r(&now, &tm); /* reset tm structure */ @@ -344,7 +347,7 @@ static void add_job(JOB *job, RUN *run, time_t now, time_t runtime) if (ji->runtime > je->runtime || (ji->runtime == je->runtime && ji->Priority > je->Priority)) { jobs_to_run->insert_before(je, ji); - dump_job(je, "Inserted job"); + dump_job(je, "Inserted job"); inserted = true; break; } diff --git a/bacula/src/filed/backup.c b/bacula/src/filed/backup.c index 23a2a79c12..9405ec0d24 100644 --- a/bacula/src/filed/backup.c +++ b/bacula/src/filed/backup.c @@ -8,7 +8,7 @@ * */ /* - Copyright (C) 2000-2004 Kern Sibbald + Copyright (C) 2000-2005 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 diff --git a/bacula/src/filed/job.c b/bacula/src/filed/job.c index e7fb78c341..0c40531ad6 100644 --- a/bacula/src/filed/job.c +++ b/bacula/src/filed/job.c @@ -7,7 +7,7 @@ * */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -724,7 +724,7 @@ static void add_fileset(JCR *jcr, const char *item) if (code != '\0') { ++item; } - int subcode = ' '; /* A space is always a valid subcode */ + int subcode = ' '; /* A space is always a valid subcode */ if (item[0] != '\0' && item[0] != ' ') { subcode = item[0]; ++item; @@ -862,21 +862,21 @@ static bool term_fileset(JCR *jcr) for (k=0; kregex.size(); k++) { Dmsg1(400, "R %s\n", (char *)fo->regex.get(k)); } - for (k=0; kregexdir.size(); k++) { - Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k)); - } - for (k=0; kregexfile.size(); k++) { - Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k)); - } - for (k=0; kwild.size(); k++) { - Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); - } - for (k=0; kwilddir.size(); k++) { - Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k)); - } - for (k=0; kwildfile.size(); k++) { - Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k)); - } + for (k=0; kregexdir.size(); k++) { + Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k)); + } + for (k=0; kregexfile.size(); k++) { + Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k)); + } + for (k=0; kwild.size(); k++) { + Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); + } + for (k=0; kwilddir.size(); k++) { + Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k)); + } + for (k=0; kwildfile.size(); k++) { + Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k)); + } for (k=0; kbase.size(); k++) { Dmsg1(400, "B %s\n", (char *)fo->base.get(k)); } @@ -902,21 +902,21 @@ static bool term_fileset(JCR *jcr) for (k=0; kregex.size(); k++) { Dmsg1(400, "R %s\n", (char *)fo->regex.get(k)); } - for (k=0; kregexdir.size(); k++) { - Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k)); - } - for (k=0; kregexfile.size(); k++) { - Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k)); - } - for (k=0; kwild.size(); k++) { - Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); - } - for (k=0; kwilddir.size(); k++) { - Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k)); - } - for (k=0; kwildfile.size(); k++) { - Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k)); - } + for (k=0; kregexdir.size(); k++) { + Dmsg1(400, "RD %s\n", (char *)fo->regexdir.get(k)); + } + for (k=0; kregexfile.size(); k++) { + Dmsg1(400, "RF %s\n", (char *)fo->regexfile.get(k)); + } + for (k=0; kwild.size(); k++) { + Dmsg1(400, "W %s\n", (char *)fo->wild.get(k)); + } + for (k=0; kwilddir.size(); k++) { + Dmsg1(400, "WD %s\n", (char *)fo->wilddir.get(k)); + } + for (k=0; kwildfile.size(); k++) { + Dmsg1(400, "WF %s\n", (char *)fo->wildfile.get(k)); + } for (k=0; kbase.size(); k++) { Dmsg1(400, "B %s\n", (char *)fo->base.get(k)); } diff --git a/bacula/src/filed/protos.h b/bacula/src/filed/protos.h index 6d30c93dfc..bac523bde4 100644 --- a/bacula/src/filed/protos.h +++ b/bacula/src/filed/protos.h @@ -3,7 +3,7 @@ */ /* - Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c index 5c1d65fed9..ada10e9cae 100644 --- a/bacula/src/filed/restore.c +++ b/bacula/src/filed/restore.c @@ -7,7 +7,7 @@ * */ /* - Copyright (C) 2000-2004 Kern Sibbald + Copyright (C) 2000-2005 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 @@ -152,15 +152,15 @@ void do_restore(JCR *jcr) * 3. Repeat step 1 * * NOTE: We keep track of two bacula file descriptors: - * 1. bfd for file data. + * 1. bfd for file data. * This fd is opened for non empty files when an attribute stream is * encountered and closed when we find the next attribute stream. - * 2. alt_bfd for alternate data streams + * 2. alt_bfd for alternate data streams * This fd is opened every time we encounter a new alternate data * stream for the current file. When we find any other stream, we * close it again. - * The expected size of the stream, alt_len, should be set when - * opening the fd. + * The expected size of the stream, alt_len, should be set when + * opening the fd. */ binit(&bfd); binit(&altbfd); @@ -173,18 +173,18 @@ void do_restore(JCR *jcr) /* First we expect a Stream Record Header */ if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index, &stream, &size) != 5) { - Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg); + Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg); goto bail_out; } Dmsg2(30, "Got hdr: FilInx=%d Stream=%d.\n", file_index, stream); /* * Now we expect the Stream Data */ if (bget_msg(sd) < 0) { - Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd)); + Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), bnet_strerror(sd)); goto bail_out; } if (size != (uint32_t)sd->msglen) { - Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size); + Jmsg2(jcr, M_FATAL, 0, _("Actual data size %d not same as header %d\n"), sd->msglen, size); goto bail_out; } Dmsg1(30, "Got stream data, len=%d\n", sd->msglen); @@ -202,20 +202,20 @@ void do_restore(JCR *jcr) switch (stream) { case STREAM_UNIX_ATTRIBUTES: case STREAM_UNIX_ATTRIBUTES_EX: - Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract); + Dmsg1(30, "Stream=Unix Attributes. extract=%d\n", extract); /* * If extracting, it was from previous stream, so * close the output file. */ if (extract) { if (size > 0 && !is_bopen(&bfd)) { - Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n")); + Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n")); } set_attributes(jcr, attr, &bfd); extract = false; - Dmsg0(30, "Stop extracting.\n"); + Dmsg0(30, "Stop extracting.\n"); } else if (is_bopen(&bfd)) { - Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n")); + Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n")); bclose(&bfd); } @@ -226,20 +226,20 @@ void do_restore(JCR *jcr) goto bail_out; } if (file_index != attr->file_index) { - Jmsg(jcr, M_FATAL, 0, _("Record header file index %ld not equal record index %ld\n"), + Jmsg(jcr, M_FATAL, 0, _("Record header file index %ld not equal record index %ld\n"), file_index, attr->file_index); - Dmsg0(100, "File index error\n"); + Dmsg0(100, "File index error\n"); goto bail_out; } - Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", attr->fname, + Dmsg3(200, "File %s\nattrib=%s\nattribsEx=%s\n", attr->fname, attr->attr, attr->attrEx); attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI); if (!is_stream_supported(attr->data_stream)) { if (!non_support_data++) { - Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"), + Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"), stream_to_ascii(attr->data_stream)); } continue; @@ -251,7 +251,7 @@ void do_restore(JCR *jcr) * Now determine if we are extracting or not. */ jcr->num_files_examined++; - Dmsg1(30, "Outfile=%s\n", attr->ofname); + Dmsg1(30, "Outfile=%s\n", attr->ofname); extract = false; stat = create_file(jcr, attr, &bfd, jcr->replace); switch (stat) { @@ -316,12 +316,12 @@ void do_restore(JCR *jcr) if (extract) { if (prev_stream != stream) { if (bopen_rsrc(&altbfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) { - Jmsg(jcr, M_ERROR, 0, _(" Cannot open resource fork for %s\n"), jcr->last_fname); + Jmsg(jcr, M_ERROR, 0, _(" Cannot open resource fork for %s\n"), jcr->last_fname); extract = false; continue; } alt_size = rsrc_len; - Dmsg0(30, "Restoring resource fork\n"); + Dmsg0(30, "Restoring resource fork\n"); } flags = 0; if (extract_data(jcr, &altbfd, sd->msg, sd->msglen, &alt_addr, flags) < 0) { @@ -337,13 +337,13 @@ void do_restore(JCR *jcr) case STREAM_HFSPLUS_ATTRIBUTES: #ifdef HAVE_DARWIN_OS - Dmsg0(30, "Restoring Finder Info\n"); + Dmsg0(30, "Restoring Finder Info\n"); if (sd->msglen != 32) { - Jmsg(jcr, M_ERROR, 0, _(" Invalid length of Finder Info (got %d, not 32)\n"), sd->msglen); + Jmsg(jcr, M_ERROR, 0, _(" Invalid length of Finder Info (got %d, not 32)\n"), sd->msglen); continue; } if (setattrlist(jcr->last_fname, &attrList, sd->msg, sd->msglen, 0) != 0) { - Jmsg(jcr, M_ERROR, 0, _(" Could not set Finder Info on %s\n"), jcr->last_fname); + Jmsg(jcr, M_ERROR, 0, _(" Could not set Finder Info on %s\n"), jcr->last_fname); continue; } #else @@ -357,7 +357,7 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL: /* Recover Acess ACL from stream and check it */ acl = acl_from_text(sd->msg); if (acl_valid(acl) != 0) { - Jmsg1(jcr, M_WARNING, 0, "Failure in the ACL of %s! FD is not able to restore it!\n", jcr->last_fname); + Jmsg1(jcr, M_WARNING, 0, "Failure in the ACL of %s! FD is not able to restore it!\n", jcr->last_fname); acl_free(acl); } @@ -365,14 +365,14 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL: if (attr->type == FT_DIREND) { /* Directory */ if (acl_set_file(jcr->last_fname, ACL_TYPE_ACCESS, acl) != 0) { - Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname); + Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname); } /* File or Link */ } else if (acl_set_file(jcr->last_fname, ACL_TYPE_ACCESS, acl) != 0) { - Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore ACL of file: %s! Maybe system does not support ACLs!\n", jcr->last_fname); + Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore ACL of file: %s! Maybe system does not support ACLs!\n", jcr->last_fname); } acl_free(acl); - Dmsg1(200, "ACL of file: %s successfully restored!\n", jcr->last_fname); + Dmsg1(200, "ACL of file: %s successfully restored!\n", jcr->last_fname); break; #else non_support_acl++; @@ -383,7 +383,7 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL: /* Recover Default ACL from stream and check it */ acl = acl_from_text(sd->msg); if (acl_valid(acl) != 0) { - Jmsg1(jcr, M_WARNING, 0, "Failure in the Default ACL of %s! FD is not able to restore it!\n", jcr->last_fname); + Jmsg1(jcr, M_WARNING, 0, "Failure in the Default ACL of %s! FD is not able to restore it!\n", jcr->last_fname); acl_free(acl); } @@ -391,11 +391,11 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL: if (attr->type == FT_DIREND) { /* Directory */ if (acl_set_file(jcr->last_fname, ACL_TYPE_DEFAULT, acl) != 0) { - Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore Default ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname); + Jmsg1(jcr, M_WARNING, 0, "Error! Can't restore Default ACL of directory: %s! Maybe system does not support ACLs!\n", jcr->last_fname); } } acl_free(acl); - Dmsg1(200, "Default ACL of file: %s successfully restored!\n", jcr->last_fname); + Dmsg1(200, "Default ACL of file: %s successfully restored!\n", jcr->last_fname); break; #else non_support_acl++; @@ -410,7 +410,7 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL: case STREAM_PROGRAM_NAMES: case STREAM_PROGRAM_DATA: if (!non_support_progname) { - Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n"); + Pmsg0(000, "Got Program Name or Data Stream. Ignored.\n"); non_support_progname++; } break; @@ -418,18 +418,18 @@ case STREAM_UNIX_ATTRIBUTES_ACCESS_ACL: default: /* If extracting, wierd stream (not 1 or 2), close output file anyway */ if (extract) { - Dmsg1(30, "Found wierd stream %d\n", stream); + Dmsg1(30, "Found wierd stream %d\n", stream); if (size > 0 && !is_bopen(&bfd)) { - Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n")); + Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should be open\n")); } set_attributes(jcr, attr, &bfd); extract = false; } else if (is_bopen(&bfd)) { - Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n")); + Jmsg0(jcr, M_ERROR, 0, _("Logic error: output file should not be open\n")); bclose(&bfd); } - Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), stream); - Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg); + Jmsg(jcr, M_ERROR, 0, _("Unknown stream=%d ignored. This shouldn't happen!\n"), stream); + Dmsg2(0, "None of above!!! stream=%d data=%s\n", stream,sd->msg); break; } /* end switch(stream) */ @@ -536,7 +536,7 @@ int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen, if (blseek(bfd, (off_t)*addr, SEEK_SET) < 0) { berrno be; be.set_errno(bfd->berrno); - Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"), + Jmsg3(jcr, M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"), edit_uint64(*addr, ec1), jcr->last_fname, be.strerror()); return -1; } @@ -553,7 +553,7 @@ int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen, Dmsg2(100, "Comp_len=%d msglen=%d\n", compress_len, wsize); if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len, (const Byte *)wbuf, (uLong)rsize)) != Z_OK) { - Jmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"), + Jmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"), jcr->last_fname, zlib_strerror(stat)); return -1; } diff --git a/bacula/src/findlib/find.c b/bacula/src/findlib/find.c index 1d5f1009fc..13bf2c47a4 100644 --- a/bacula/src/findlib/find.c +++ b/bacula/src/findlib/find.c @@ -10,7 +10,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -140,7 +140,7 @@ find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt), void bstrncat(ff->VerifyOpts, fo->VerifyOpts, sizeof(ff->VerifyOpts)); } for (j=0; jname_list.size(); j++) { - Dmsg1(100, "F %s\n", (char *)incexe->name_list.get(j)); + Dmsg1(100, "F %s\n", (char *)incexe->name_list.get(j)); char *fname = (char *)incexe->name_list.get(j); if (find_one_file(jcr, ff, our_callback, his_pkt, fname, (dev_t)-1, 1) == 0) { return 0; /* error return */ @@ -154,7 +154,7 @@ find_files(JCR *jcr, FF_PKT *ff, int callback(FF_PKT *ff_pkt, void *hpkt), void while (!job_canceled(jcr) && (inc = get_next_included_file(ff, inc))) { /* Copy options for this file */ bstrncat(ff->VerifyOpts, inc->VerifyOpts, sizeof(ff->VerifyOpts)); - Dmsg1(100, "find_files: file=%s\n", inc->fname); + Dmsg1(100, "find_files: file=%s\n", inc->fname); if (!file_is_excluded(ff, inc->fname)) { if (find_one_file(jcr, ff, callback, his_pkt, inc->fname, (dev_t)-1, 1) ==0) { return 0; /* error return */ @@ -184,9 +184,9 @@ static bool accept_file(FF_PKT *ff) for (k=0; kwilddir.size(); k++) { if (fnmatch((char *)fo->wilddir.get(k), ff->fname, fnmode|ic) == 0) { if (ff->flags & FO_EXCLUDE) { - Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k), + Dmsg2(100, "Exclude wilddir: %s file=%s\n", (char *)fo->wilddir.get(k), ff->fname); - return false; /* reject file */ + return false; /* reject file */ } return true; /* accept file */ } @@ -195,9 +195,9 @@ static bool accept_file(FF_PKT *ff) for (k=0; kwildfile.size(); k++) { if (fnmatch((char *)fo->wildfile.get(k), ff->fname, fnmode|ic) == 0) { if (ff->flags & FO_EXCLUDE) { - Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k), + Dmsg2(100, "Exclude wildfile: %s file=%s\n", (char *)fo->wildfile.get(k), ff->fname); - return false; /* reject file */ + return false; /* reject file */ } return true; /* accept file */ } @@ -206,7 +206,7 @@ static bool accept_file(FF_PKT *ff) for (k=0; kwild.size(); k++) { if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) { if (ff->flags & FO_EXCLUDE) { - Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k), + Dmsg2(100, "Exclude wild: %s file=%s\n", (char *)fo->wild.get(k), ff->fname); return false; /* reject file */ } @@ -220,7 +220,7 @@ static bool accept_file(FF_PKT *ff) regmatch_t pmatch[nmatch]; if (regexec((regex_t *)fo->regexdir.get(k), ff->fname, nmatch, pmatch, 0) == 0) { if (ff->flags & FO_EXCLUDE) { - return false; /* reject file */ + return false; /* reject file */ } return true; /* accept file */ } @@ -231,7 +231,7 @@ static bool accept_file(FF_PKT *ff) regmatch_t pmatch[nmatch]; if (regexec((regex_t *)fo->regexfile.get(k), ff->fname, nmatch, pmatch, 0) == 0) { if (ff->flags & FO_EXCLUDE) { - return false; /* reject file */ + return false; /* reject file */ } return true; /* accept file */ } @@ -257,7 +257,7 @@ static bool accept_file(FF_PKT *ff) ic = (fo->flags & FO_IGNORECASE) ? FNM_CASEFOLD : 0; for (k=0; kwild.size(); k++) { if (fnmatch((char *)fo->wild.get(k), ff->fname, fnmode|ic) == 0) { - Dmsg1(100, "Reject wild1: %s\n", ff->fname); + Dmsg1(100, "Reject wild1: %s\n", ff->fname); return false; /* reject file */ } } @@ -266,7 +266,7 @@ static bool accept_file(FF_PKT *ff) ? FNM_CASEFOLD : 0; for (j=0; jname_list.size(); j++) { if (fnmatch((char *)incexe->name_list.get(j), ff->fname, fnmode|ic) == 0) { - Dmsg1(100, "Reject wild2: %s\n", ff->fname); + Dmsg1(100, "Reject wild2: %s\n", ff->fname); return false; /* reject file */ } } @@ -307,7 +307,7 @@ static int our_callback(FF_PKT *ff, void *hpkt) if (accept_file(ff)) { return ff->callback(ff, hpkt); } else { - Dmsg1(100, "Skip file %s\n", ff->fname); + Dmsg1(100, "Skip file %s\n", ff->fname); return -1; /* ignore this file */ } diff --git a/bacula/src/findlib/find.h b/bacula/src/findlib/find.h index 16d1a393a9..cf35bd589a 100755 --- a/bacula/src/findlib/find.h +++ b/bacula/src/findlib/find.h @@ -1,10 +1,10 @@ /* * File types as returned by find_files() * - * Kern Sibbald MIM + * Kern Sibbald MMI */ /* - Copyright (C) 2000-2004 Kern Sibbald + Copyright (C) 2001-2005 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 @@ -63,41 +63,41 @@ int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); * Status codes returned by create_file() */ enum { - CF_SKIP = 1, /* skip file (not newer or something) */ - CF_ERROR, /* error creating file */ - CF_EXTRACT, /* file created, data to extract */ - CF_CREATED /* file created, no data to extract */ + CF_SKIP = 1, /* skip file (not newer or something) */ + CF_ERROR, /* error creating file */ + CF_EXTRACT, /* file created, data to extract */ + CF_CREATED /* file created, no data to extract */ }; /* Options saved int "options" of the include/exclude lists. * They are directly jammed ito "flag" of ff packet */ -#define FO_MD5 (1<<1) /* Do MD5 checksum */ -#define FO_GZIP (1<<2) /* Do Zlib compression */ -#define FO_NO_RECURSION (1<<3) /* no recursion in directories */ -#define FO_MULTIFS (1<<4) /* multiple file systems */ -#define FO_SPARSE (1<<5) /* do sparse file checking */ -#define FO_IF_NEWER (1<<6) /* replace if newer */ -#define FO_NOREPLACE (1<<7) /* never replace */ -#define FO_READFIFO (1<<8) /* read data from fifo */ -#define FO_SHA1 (1<<9) /* Do SHA1 checksum */ -#define FO_PORTABLE (1<<10) /* Use portable data format -- no BackupWrite */ -#define FO_MTIMEONLY (1<<11) /* Use mtime rather than mtime & ctime */ -#define FO_KEEPATIME (1<<12) /* Reset access time */ -#define FO_EXCLUDE (1<<13) /* Exclude file */ -#define FO_ACL (1<<14) /* Backup ACLs */ +#define FO_MD5 (1<<1) /* Do MD5 checksum */ +#define FO_GZIP (1<<2) /* Do Zlib compression */ +#define FO_NO_RECURSION (1<<3) /* no recursion in directories */ +#define FO_MULTIFS (1<<4) /* multiple file systems */ +#define FO_SPARSE (1<<5) /* do sparse file checking */ +#define FO_IF_NEWER (1<<6) /* replace if newer */ +#define FO_NOREPLACE (1<<7) /* never replace */ +#define FO_READFIFO (1<<8) /* read data from fifo */ +#define FO_SHA1 (1<<9) /* Do SHA1 checksum */ +#define FO_PORTABLE (1<<10) /* Use portable data format -- no BackupWrite */ +#define FO_MTIMEONLY (1<<11) /* Use mtime rather than mtime & ctime */ +#define FO_KEEPATIME (1<<12) /* Reset access time */ +#define FO_EXCLUDE (1<<13) /* Exclude file */ +#define FO_ACL (1<<14) /* Backup ACLs */ #define FO_NO_HARDLINK (1<<15) /* don't handle hard links */ -#define FO_IGNORECASE (1<<16) /* Ignore file name case */ -#define FO_HFSPLUS (1<<17) /* Resource forks and Finder Info */ +#define FO_IGNORECASE (1<<16) /* Ignore file name case */ +#define FO_HFSPLUS (1<<17) /* Resource forks and Finder Info */ struct s_included_file { struct s_included_file *next; - uint32_t options; /* backup options */ - int level; /* compression level */ - int len; /* length of fname */ - int pattern; /* set if wild card pattern */ - char VerifyOpts[20]; /* Options for verify */ + uint32_t options; /* backup options */ + int level; /* compression level */ + int len; /* length of fname */ + int pattern; /* set if wild card pattern */ + char VerifyOpts[20]; /* Options for verify */ char fname[1]; }; @@ -112,7 +112,7 @@ struct s_excluded_file { * of the structure are passed by the Director to the * File daemon and recompiled back into this structure */ -#undef MAX_FOPTS +#undef MAX_FOPTS #define MAX_FOPTS 30 enum { @@ -124,27 +124,27 @@ enum { /* File options structure */ struct findFOPTS { - uint32_t flags; /* options in bits */ - int GZIP_level; /* GZIP level */ - char VerifyOpts[MAX_FOPTS]; /* verify options */ - alist regex; /* regex string(s) */ - alist regexdir; /* regex string(s) for directories */ - alist regexfile; /* regex string(s) for files */ - alist wild; /* wild card strings */ - alist wilddir; /* wild card strings for directories */ - alist wildfile; /* wild card strings for files */ - alist base; /* list of base names */ - alist fstype; /* file system type limitation */ - char *reader; /* reader program */ - char *writer; /* writer program */ + uint32_t flags; /* options in bits */ + int GZIP_level; /* GZIP level */ + char VerifyOpts[MAX_FOPTS]; /* verify options */ + alist regex; /* regex string(s) */ + alist regexdir; /* regex string(s) for directories */ + alist regexfile; /* regex string(s) for files */ + alist wild; /* wild card strings */ + alist wilddir; /* wild card strings for directories */ + alist wildfile; /* wild card strings for files */ + alist base; /* list of base names */ + alist fstype; /* file system type limitation */ + char *reader; /* reader program */ + char *writer; /* writer program */ }; /* This is either an include item or an exclude item */ struct findINCEXE { - findFOPTS *current_opts; /* points to current options structure */ - alist opts_list; /* options list */ - alist name_list; /* filename list -- holds char * */ + findFOPTS *current_opts; /* points to current options structure */ + alist opts_list; /* options list */ + alist name_list; /* filename list -- holds char * */ }; /* @@ -153,16 +153,16 @@ struct findINCEXE { */ struct findFILESET { int state; - findINCEXE *incexe; /* current item */ + findINCEXE *incexe; /* current item */ alist include_list; alist exclude_list; }; #ifdef HAVE_DARWIN_OS struct HFSPLUS_INFO { - unsigned long length; /* Mandatory field */ - char fndrinfo[32]; /* Finder Info */ - off_t rsrclength; /* Size of resource fork */ + unsigned long length; /* Mandatory field */ + char fndrinfo[32]; /* Finder Info */ + off_t rsrclength; /* Size of resource fork */ }; #endif @@ -171,20 +171,20 @@ struct HFSPLUS_INFO { * first argument to the find_files callback subroutine. */ struct FF_PKT { - char *fname; /* filename */ - char *link; /* link if file linked */ - POOLMEM *sys_fname; /* system filename */ - struct stat statp; /* stat packet */ - int32_t FileIndex; /* FileIndex of this file */ - int32_t LinkFI; /* FileIndex of main hard linked file */ - struct f_link *linked; /* Set if this file is hard linked */ - int type; /* FT_ type from above */ - int ff_errno; /* errno */ - BFILE bfd; /* Bacula file descriptor */ - time_t save_time; /* start of incremental time */ - bool dereference; /* follow links (not implemented) */ - bool null_output_device; /* using null output device */ - bool incremental; /* incremental save */ + char *fname; /* filename */ + char *link; /* link if file linked */ + POOLMEM *sys_fname; /* system filename */ + struct stat statp; /* stat packet */ + int32_t FileIndex; /* FileIndex of this file */ + int32_t LinkFI; /* FileIndex of main hard linked file */ + struct f_link *linked; /* Set if this file is hard linked */ + int type; /* FT_ type from above */ + int ff_errno; /* errno */ + BFILE bfd; /* Bacula file descriptor */ + time_t save_time; /* start of incremental time */ + bool dereference; /* follow links (not implemented) */ + bool null_output_device; /* using null output device */ + bool incremental; /* incremental save */ char VerifyOpts[20]; struct s_included_file *included_files_list; struct s_excluded_file *excluded_files_list; @@ -193,18 +193,18 @@ struct FF_PKT { int (*callback)(FF_PKT *, void *); /* User's callback */ /* Values set by accept_file while processing Options */ - uint32_t flags; /* backup options */ - int GZIP_level; /* compression level */ - char *reader; /* reader program */ - char *writer; /* writer program */ - alist fstypes; /* allowed file system types */ + uint32_t flags; /* backup options */ + int GZIP_level; /* compression level */ + char *reader; /* reader program */ + char *writer; /* writer program */ + alist fstypes; /* allowed file system types */ /* List of all hard linked files found */ - struct f_link *linklist; /* hard linked files */ + struct f_link *linklist; /* hard linked files */ /* Darwin specific things. So as not to clutter every bclose() * with an #ifdef, we always include rsrc_bfd */ - BFILE rsrc_bfd; /* fd for resource forks */ + BFILE rsrc_bfd; /* fd for resource forks */ #ifdef HAVE_DARWIN_OS struct HFSPLUS_INFO hfsinfo; /* Finder Info and resource fork size */ #endif diff --git a/bacula/src/findlib/find_one.c b/bacula/src/findlib/find_one.c index 354811db87..d3516d37fe 100755 --- a/bacula/src/findlib/find_one.c +++ b/bacula/src/findlib/find_one.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-20054 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 diff --git a/bacula/src/findlib/fstype.c b/bacula/src/findlib/fstype.c index 1ab43f0a4c..a23d9aaa65 100644 --- a/bacula/src/findlib/fstype.c +++ b/bacula/src/findlib/fstype.c @@ -7,7 +7,7 @@ */ /* - Copyright (C) Kern Sibbald + Copyright (C) 2005 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 diff --git a/bacula/src/findlib/protos.h b/bacula/src/findlib/protos.h index e269c39e1e..16867ba6a3 100644 --- a/bacula/src/findlib/protos.h +++ b/bacula/src/findlib/protos.h @@ -4,7 +4,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 diff --git a/bacula/src/jcr.h b/bacula/src/jcr.h index d534be3ab0..38a9cd7b5a 100644 --- a/bacula/src/jcr.h +++ b/bacula/src/jcr.h @@ -10,7 +10,7 @@ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -185,6 +185,7 @@ struct JCR { bool acquired_resource_locks; /* set if resource locks acquired */ bool term_wait_inited; /* Set when cond var inited */ bool fn_printed; /* printed filename */ + bool write_part_after_job; /* Write part after job in SD */ #endif /* DIRECTOR_DAEMON */ @@ -239,7 +240,8 @@ struct JCR { bool spool_data; /* set to spool data */ int CurVol; /* Current Volume count */ DIRRES* director; /* Director resource */ - + bool write_part_after_job; /* Set to write part after job */ + uint32_t FileId; /* Last file id inserted */ /* Parmaters for Open Read Session */ diff --git a/bacula/src/lib/bpipe.c b/bacula/src/lib/bpipe.c index f7a340034b..4350de4c05 100644 --- a/bacula/src/lib/bpipe.c +++ b/bacula/src/lib/bpipe.c @@ -282,6 +282,65 @@ int run_program(char *prog, int wait, POOLMEM *results) return stat1; } +/* + * Run an external program. Optionally wait a specified number + * of seconds. Program killed if wait exceeded (it is done by the + * watchdog, as fgets is a blocking function). + * Return the full output from the program (not only the first line). + * + * Contrary to my normal calling conventions, this program + * + * Returns: 0 on success + * non-zero on error == berrno status + * + */ +int run_program_full_output(char *prog, int wait, POOLMEM *results) +{ + BPIPE *bpipe; + int stat1, stat2; + char *mode; + POOLMEM* tmp; + + if (results == NULL) { + return run_program(prog, wait, NULL); + } + + tmp = get_pool_memory(PM_MESSAGE); + + mode = (char *)"r"; + bpipe = open_bpipe(prog, wait, mode); + if (!bpipe) { + return ENOENT; + } + + results[0] = 0; + + while (1) { + fgets(tmp, sizeof_pool_memory(tmp), bpipe->rfd); + Dmsg1(200, "Run program fgets=%s", tmp); + pm_strcat(results, tmp); + if (feof(bpipe->rfd)) { + stat1 = 0; + Dmsg1(100, "Run program fgets stat=%d\n", stat1); + break; + } else { + stat1 = ferror(bpipe->rfd); + } + if (stat1 < 0) { + Dmsg2(100, "Run program fgets stat=%d ERR=%s\n", stat1, strerror(errno)); + break; + } else if (stat1 != 0) { + Dmsg1(100, "Run program fgets stat=%d\n", stat1); + } + } + + stat2 = close_bpipe(bpipe); + stat1 = stat2 != 0 ? stat2 : stat1; + + Dmsg1(100, "Run program returning %d\n", stat); + free_pool_memory(tmp); + return stat1; +} /* * Build argc and argv from a string diff --git a/bacula/src/lib/protos.h b/bacula/src/lib/protos.h index 199abd8f03..d1cc5cc99b 100644 --- a/bacula/src/lib/protos.h +++ b/bacula/src/lib/protos.h @@ -209,6 +209,7 @@ char * encode_mode (mode_t mode, char *buf); int do_shell_expansion (char *name, int name_len); void jobstatus_to_ascii (int JobStatus, char *msg, int maxlen); int run_program (char *prog, int wait, POOLMEM *results); +int run_program_full_output (char *prog, int wait, POOLMEM *results); const char * job_type_to_str (int type); const char * job_status_to_str (int stat); const char * job_level_to_str (int level); diff --git a/bacula/src/stored/acquire.c b/bacula/src/stored/acquire.c index cd6e846d17..67a40872d8 100644 --- a/bacula/src/stored/acquire.c +++ b/bacula/src/stored/acquire.c @@ -6,7 +6,7 @@ * Version $Id$ */ /* - Copyright (C) 2002-2004 Kern Sibbald and John Walker + Copyright (C) 2002-2005 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 @@ -93,7 +93,8 @@ DCR *acquire_device_for_read(JCR *jcr) int i; DCR *dcr = jcr->dcr; DEVICE *dev; - + int vol_label_status; + /* Called for each volume */ if (!dcr) { dcr = new_dcr(jcr, jcr->device->dev); @@ -131,10 +132,18 @@ DCR *acquire_device_for_read(JCR *jcr) } bstrncpy(dcr->VolumeName, vol->VolumeName, sizeof(dcr->VolumeName)); + /* Volume info is always needed because of VolParts */ + Dmsg0(200, "dir_get_volume_info\n"); + if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) { + Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg); + } + + dcr->dev->num_parts = dcr->VolCatInfo.VolCatParts; + for (i=0; i<5; i++) { dcr->dev->state &= ~ST_LABEL; /* force reread of label */ if (job_canceled(jcr)) { - Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId); + Mmsg1(dev->errmsg, _("Job %d canceled.\n"), jcr->JobId); goto get_out; /* error return */ } /* @@ -143,23 +152,39 @@ DCR *acquire_device_for_read(JCR *jcr) * If it is a tape, it checks the volume name */ for ( ; !(dev->state & ST_OPENED); ) { - Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName); + Dmsg1(120, "bstored: open vol=%s\n", dcr->VolumeName); if (open_dev(dev, dcr->VolumeName, OPEN_READ_ONLY) < 0) { if (dev->dev_errno == EIO) { /* no tape loaded */ goto default_path; } - Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"), + + /* If we have a device that requires mount, + * we need to try to open the label, so the info can be reported + * if a wrong volume has been mounted. */ + if (dev_cap(dev, CAP_REQMOUNT) && (dcr->VolCatInfo.VolCatParts > 0)) { + break; + } + + Jmsg(jcr, M_FATAL, 0, _("Open device %s volume %s failed, ERR=%s\n"), dev_name(dev), dcr->VolumeName, strerror_dev(dev)); goto get_out; } - Dmsg1(129, "open_dev %s OK\n", dev_name(dev)); + Dmsg1(129, "open_dev %s OK\n", dev_name(dev)); + } + + if (dev_cap(dev, CAP_REQMOUNT)) { + vol_label_status = read_dev_volume_label_guess(dcr, 0); + } + else { + vol_label_status = read_dev_volume_label(dcr); } + /****FIXME***** do not reread label if ioctl() says we are * correctly possitioned. Possibly have way user can turn * this optimization (to be implemented) off. */ Dmsg0(200, "calling read-vol-label\n"); - switch (read_dev_volume_label(dcr)) { + switch (vol_label_status) { case VOL_OK: vol_ok = true; memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo)); @@ -171,7 +196,7 @@ DCR *acquire_device_for_read(JCR *jcr) * error messages when nothing is mounted. */ if (tape_previously_mounted) { - Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); + Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); } goto default_path; case VOL_NAME_ERROR: @@ -181,17 +206,20 @@ DCR *acquire_device_for_read(JCR *jcr) } /* Fall through */ default: - Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); + Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); default_path: tape_previously_mounted = true; - Dmsg0(200, "dir_get_volume_info\n"); - if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_READ)) { - Jmsg1(jcr, M_WARNING, 0, "%s", jcr->errmsg); + + /* If the device requires mount, close it, so the device can be ejected. + * FIXME: This should perhaps be done for all devices. */ + if (dev_cap(dev, CAP_REQMOUNT)) { + force_close_dev(dev); } + /* Call autochanger only once unless ask_sysop called */ if (try_autochanger) { int stat; - Dmsg2(200, "calling autoload Vol=%s Slot=%d\n", + Dmsg2(200, "calling autoload Vol=%s Slot=%d\n", dcr->VolumeName, dcr->VolCatInfo.Slot); stat = autoload_device(dcr, 0, NULL); if (stat > 0) { @@ -199,8 +227,9 @@ default_path: continue; } } + /* Mount a specific volume and no other */ - Dmsg0(200, "calling dir_ask_sysop\n"); + Dmsg0(200, "calling dir_ask_sysop\n"); if (!dir_ask_sysop_to_mount_volume(dcr)) { goto get_out; /* error return */ } @@ -277,7 +306,7 @@ DCR *acquire_device_for_append(JCR *jcr) if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) && !(dir_find_next_appendable_volume(dcr) && strcmp(dev->VolHdr.VolName, dcr->VolumeName) == 0)) { /* wrong tape mounted */ - Dmsg0(190, "Wrong tape mounted.\n"); + Dmsg0(190, "Wrong tape mounted.\n"); if (dev->num_writers != 0) { DEVICE *d = ((DEVRES *)dev->device)->dev; uint32_t open_vols = 0; @@ -301,12 +330,12 @@ DCR *acquire_device_for_append(JCR *jcr) block_device(dev, BST_DOING_ACQUIRE); unlock_device(dev); } else { - Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev)); + Jmsg(jcr, M_FATAL, 0, _("Device %s is busy writing on another Volume.\n"), dev_name(dev)); goto get_out; } } /* Wrong tape mounted, release it, then fall through to get correct one */ - Dmsg0(190, "Wrong tape mounted, release and try mount.\n"); + Dmsg0(190, "Wrong tape mounted, release and try mount.\n"); release = true; do_mount = true; } else { @@ -315,11 +344,11 @@ DCR *acquire_device_for_append(JCR *jcr) * we do not need to do mount_next_write_volume(), unless * we need to recycle the tape. */ - recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0; - Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle); + recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0; + Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle); if (recycle && dev->num_writers != 0) { - Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\"" - " because it is in use by another job.\n")); + Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\"" + " because it is in use by another job.\n")); goto get_out; } if (dev->num_writers == 0) { @@ -330,7 +359,7 @@ DCR *acquire_device_for_append(JCR *jcr) /* Not already in append mode, so mount the device */ Dmsg0(190, "Not in append mode, try mount.\n"); if (dev_state(dev, ST_READ)) { - Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev)); + Jmsg(jcr, M_FATAL, 0, _("Device %s is busy reading.\n"), dev_name(dev)); goto get_out; } ASSERT(dev->num_writers == 0); @@ -344,8 +373,8 @@ DCR *acquire_device_for_append(JCR *jcr) P(mutex); /* re-lock */ if (!mounted) { if (!job_canceled(jcr)) { - /* Reduce "noise" -- don't print if job canceled */ - Jmsg(jcr, M_FATAL, 0, _("Could not ready device \"%s\" for append.\n"), + /* Reduce "noise" -- don't print if job canceled */ + Jmsg(jcr, M_FATAL, 0, _("Could not ready device \"%s\" for append.\n"), dev_name(dev)); } goto get_out; @@ -398,9 +427,9 @@ bool release_device(JCR *jcr) dev->num_writers--; Dmsg1(100, "There are %d writers in release_device\n", dev->num_writers); if (dev_state(dev, ST_LABEL)) { - Dmsg0(100, "dir_create_jobmedia_record. Release\n"); + Dmsg0(100, "dir_create_jobmedia_record. Release\n"); if (!dir_create_jobmedia_record(dcr)) { - Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), dcr->VolCatInfo.VolCatName, jcr->Job); } /* If no more writers, write an EOF */ @@ -410,7 +439,7 @@ bool release_device(JCR *jcr) dev->VolCatInfo.VolCatFiles = dev->file; /* set number of files */ dev->VolCatInfo.VolCatJobs++; /* increment number of jobs */ /* Note! do volume update before close, which zaps VolCatInfo */ - Dmsg0(100, "dir_update_vol_info. Release0\n"); + Dmsg0(100, "dir_update_vol_info. Release0\n"); dir_update_volume_info(dcr, false); /* send Volume info to Director */ } @@ -435,7 +464,7 @@ bool release_device(JCR *jcr) bpipe = open_bpipe(alert, 0, "r"); if (bpipe) { while (fgets(line, sizeof(line), bpipe->rfd)) { - Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line); + Jmsg(jcr, M_ALERT, 0, _("Alert: %s"), line); } status = close_bpipe(bpipe); } else { @@ -443,7 +472,7 @@ bool release_device(JCR *jcr) } if (status != 0) { berrno be; - Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"), + Jmsg(jcr, M_ALERT, 0, _("3997 Bad alert command: %s: ERR=%s.\n"), alert, be.strerror(status)); } diff --git a/bacula/src/stored/append.c b/bacula/src/stored/append.c index 97edb1b97c..c188c4d409 100644 --- a/bacula/src/stored/append.c +++ b/bacula/src/stored/append.c @@ -5,7 +5,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -136,7 +136,7 @@ bool do_append_data(JCR *jcr) if (n == BNET_SIGNAL && ds->msglen == BNET_EOD) { break; /* end of data */ } - Jmsg1(jcr, M_FATAL, 0, _("Error reading data header from FD. ERR=%s\n"), + Jmsg1(jcr, M_FATAL, 0, _("Error reading data header from FD. ERR=%s\n"), bnet_strerror(ds)); ok = false; break; @@ -158,7 +158,7 @@ bool do_append_data(JCR *jcr) p++; } if (!B_ISSPACE(*p) || !B_ISDIGIT(*(p+1))) { - Jmsg1(jcr, M_FATAL, 0, _("Malformed data header from FD: %s\n"), ds->msg); + Jmsg1(jcr, M_FATAL, 0, _("Malformed data header from FD: %s\n"), ds->msg); ok = false; break; } @@ -168,7 +168,7 @@ bool do_append_data(JCR *jcr) if (!(file_index > 0 && (file_index == last_file_index || file_index == last_file_index + 1))) { - Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n")); + Jmsg0(jcr, M_FATAL, 0, _("File index from FD not positive or sequential\n")); ok = false; break; } @@ -188,28 +188,28 @@ bool do_append_data(JCR *jcr) rec.data_len = ds->msglen; rec.data = ds->msg; /* use message buffer */ - Dmsg4(850, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n", + Dmsg4(850, "before writ_rec FI=%d SessId=%d Strm=%s len=%d\n", rec.FileIndex, rec.VolSessionId, stream_to_ascii(rec.Stream,rec.FileIndex), rec.data_len); while (!write_record_to_block(dcr->block, &rec)) { - Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len, + Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec.data_len, rec.remainder); if (!write_block_to_device(dcr)) { - Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n", + Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n", dev_name(dev), strerror_dev(dev)); - Jmsg(jcr, M_FATAL, 0, _("Fatal device error: ERR=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Fatal device error: ERR=%s\n"), strerror_dev(dev)); ok = false; break; } } if (!ok) { - Dmsg0(400, "Not OK\n"); + Dmsg0(400, "Not OK\n"); break; } jcr->JobBytes += rec.data_len; /* increment bytes this job */ - Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n", + Dmsg4(850, "write_record FI=%s SessId=%d Strm=%s len=%d\n", FI_to_ascii(rec.FileIndex), rec.VolSessionId, stream_to_ascii(rec.Stream, rec.FileIndex), rec.data_len); @@ -220,10 +220,10 @@ bool do_append_data(JCR *jcr) if (are_attributes_spooled(jcr)) { jcr->dir_bsock->spool = true; } - Dmsg0(850, "Send attributes to dir.\n"); + Dmsg0(850, "Send attributes to dir.\n"); if (!dir_update_file_attributes(dcr, &rec)) { jcr->dir_bsock->spool = false; - Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"), bnet_strerror(jcr->dir_bsock)); ok = false; break; @@ -231,12 +231,12 @@ bool do_append_data(JCR *jcr) jcr->dir_bsock->spool = false; } } - Dmsg0(350, "Enter bnet_get\n"); + Dmsg0(350, "Enter bnet_get\n"); } Dmsg1(350, "End read loop with FD. Stat=%d\n", n); if (is_bnet_error(ds)) { - Dmsg1(350, "Network read error from FD. ERR=%s\n", bnet_strerror(ds)); - Jmsg1(jcr, M_FATAL, 0, _("Network error on data channel. ERR=%s\n"), + Dmsg1(350, "Network read error from FD. ERR=%s\n", bnet_strerror(ds)); + Jmsg1(jcr, M_FATAL, 0, _("Network error on data channel. ERR=%s\n"), bnet_strerror(ds)); ok = false; break; @@ -257,18 +257,18 @@ bool do_append_data(JCR *jcr) */ if (ok || dev_can_write(dev)) { if (!write_session_label(dcr, EOS_LABEL)) { - Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"), + Jmsg1(jcr, M_FATAL, 0, _("Error writting end session label. ERR=%s\n"), strerror_dev(dev)); set_jcr_job_status(jcr, JS_ErrorTerminated); ok = false; } if (dev->VolCatInfo.VolCatName[0] == 0) { - Dmsg0(000, "NULL Volume name. This shouldn't happen!!!\n"); + Dmsg0(000, "NULL Volume name. This shouldn't happen!!!\n"); } Dmsg0(90, "back from write_end_session_label()\n"); /* Flush out final partial block of this session */ if (!write_block_to_device(dcr)) { - Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n")); + Dmsg0(100, _("Set ok=FALSE after write_block_to_device.\n")); set_jcr_job_status(jcr, JS_ErrorTerminated); ok = false; } @@ -282,6 +282,29 @@ bool do_append_data(JCR *jcr) } else { commit_data_spool(jcr); } + + /* If the device is nor a tape, nor a fifo, and WritePartAfterJob + * is set to yes, open the next part, so, in case of a device + * that requires mount, it will be written to the device. + */ + if (!(dcr->dev->state & (ST_TAPE|ST_FIFO)) && (jcr->write_part_after_job) && (dcr->dev->part_size > 0)) { + Dmsg0(100, "Writing last part because write_part_after_job is set.\n"); + if (dcr->dev->part < dcr->dev->num_parts) { + Jmsg3(dcr->jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"), + dev->part, dev->num_parts, dev_name(dev)); + dcr->dev->dev_errno = EIO; + ok = false; + } + + if (ok && (open_next_part(dcr->dev) < 0)) { + Jmsg2(jcr, M_FATAL, 0, _("Unable to open device next part %s. ERR=%s\n"), + dev_name(dcr->dev), strerror_dev(dcr->dev)); + dcr->dev->dev_errno = EIO; + ok = false; + } + + dcr->dev->VolCatInfo.VolCatParts = dcr->dev->num_parts; + } Dmsg1(200, "calling release device JobStatus=%d\n", jcr->JobStatus); /* Release the device */ diff --git a/bacula/src/stored/askdir.c b/bacula/src/stored/askdir.c index b77c5e1e25..645993c72c 100644 --- a/bacula/src/stored/askdir.c +++ b/bacula/src/stored/askdir.c @@ -7,7 +7,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -35,7 +35,8 @@ static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n"; static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s" " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u" " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%d VolStatus=%s" - " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s\n"; + " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s" + " VolParts=%u\n"; static char Create_job_media[] = "CatReq Job=%s CreateJobMedia" " FirstIndex=%u LastIndex=%u StartFile=%u EndFile=%u" " StartBlock=%u EndBlock=%u\n"; @@ -48,7 +49,7 @@ static char OK_media[] = "1000 OK VolName=%127s VolJobs=%u VolFiles=%u" " VolBlocks=%u VolBytes=%" lld " VolMounts=%u VolErrors=%u VolWrites=%u" " MaxVolBytes=%" lld " VolCapacityBytes=%" lld " VolStatus=%20s" " Slot=%d MaxVolJobs=%u MaxVolFiles=%u InChanger=%d" - " VolReadTime=%" lld " VolWriteTime=%" lld " EndFile=%u EndBlock=%u"; + " VolReadTime=%" lld " VolWriteTime=%" lld " EndFile=%u EndBlock=%u VolParts=%u"; static char OK_create[] = "1000 OK CreateJobMedia\n"; @@ -97,8 +98,8 @@ static bool do_get_volume_info(DCR *dcr) &vol.VolCatCapacityBytes, vol.VolCatStatus, &vol.Slot, &vol.VolCatMaxJobs, &vol.VolCatMaxFiles, &InChanger, &vol.VolReadTime, &vol.VolWriteTime, - &vol.EndFile, &vol.EndBlock); - if (n != 19) { + &vol.EndFile, &vol.EndBlock, &vol.VolCatParts); + if (n != 20) { Dmsg2(100, "Bad response from Dir fields=%d: %s\n", n, dir->msg); Mmsg(jcr->errmsg, _("Error getting Volume info: %s\n"), dir->msg); return false; @@ -162,7 +163,7 @@ bool dir_find_next_appendable_volume(DCR *dcr) for (int vol_index=1; vol_index < 3; vol_index++) { bnet_fsend(dir, Find_media, jcr->Job, vol_index); if (do_get_volume_info(dcr)) { - Dmsg2(300, "JobId=%d got possible Vol=%s\n", jcr->JobId, dcr->VolumeName); + Dmsg2(300, "JobId=%d got possible Vol=%s\n", jcr->JobId, dcr->VolumeName); bool found = false; /* * Walk through all jobs and see if the volume is @@ -176,10 +177,10 @@ bool dir_find_next_appendable_volume(DCR *dcr) free_locked_jcr(njcr); continue; /* us */ } - Dmsg2(300, "Compare to JobId=%d using Vol=%s\n", njcr->JobId, njcr->dcr->VolumeName); + Dmsg2(300, "Compare to JobId=%d using Vol=%s\n", njcr->JobId, njcr->dcr->VolumeName); if (njcr->dcr && strcmp(dcr->VolumeName, njcr->dcr->VolumeName) == 0) { found = true; - Dmsg1(400, "Vol in use by JobId=%u\n", njcr->JobId); + Dmsg1(400, "Vol in use by JobId=%u\n", njcr->JobId); free_locked_jcr(njcr); break; } @@ -187,11 +188,11 @@ bool dir_find_next_appendable_volume(DCR *dcr) } unlock_jcr_chain(); if (!found) { - Dmsg0(400, "dir_find_next_appendable_volume return true\n"); + Dmsg0(400, "dir_find_next_appendable_volume return true\n"); return true; /* Got good Volume */ } } else { - Dmsg0(200, "No volume info, return false\n"); + Dmsg0(200, "No volume info, return false\n"); return false; } } @@ -242,7 +243,8 @@ bool dir_update_volume_info(DCR *dcr, bool label) LastWritten, vol->VolCatStatus, vol->Slot, label, InChanger, /* bool in structure */ edit_uint64(vol->VolReadTime, ed3), - edit_uint64(vol->VolWriteTime, ed4) ); + edit_uint64(vol->VolWriteTime, ed4), + vol->VolCatParts ); Dmsg1(300, "update_volume_info(): %s", dir->msg); unbash_spaces(vol->VolCatName); @@ -347,9 +349,9 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) for ( ;; ) { if (job_canceled(jcr)) { Mmsg(dev->errmsg, - _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"), + _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"), jcr->Job, dcr->dev_name); - Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg); + Jmsg(jcr, M_INFO, 0, "%s", dev->errmsg); return false; } /* First pass, we *know* there are no appendable volumes, so no need to call */ @@ -365,7 +367,7 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) if (!unmounted && ((dcr->VolumeName[0] && !dev_cap(dev, CAP_REM) && dev_cap(dev, CAP_LABEL)) || (dcr->VolumeName[0] && dcr->VolCatInfo.Slot))) { - Dmsg0(400, "Return 1 from mount without wait.\n"); + Dmsg0(400, "Return 1 from mount without wait.\n"); return true; } jstat = JS_WaitMount; @@ -374,7 +376,7 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) "Please mount Volume \"%s\" on Storage Device \"%s\" for Job %s\n" "Use \"mount\" command to release Job.\n"), dcr->VolumeName, dcr->dev_name, jcr->Job); - Dmsg3(400, "Mount %s on %s for Job %s\n", + Dmsg3(400, "Mount %s on %s for Job %s\n", dcr->VolumeName, dcr->dev_name, jcr->Job); } } else { @@ -399,30 +401,30 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr) stat = wait_for_sysop(dcr); if (dev->poll) { - Dmsg1(400, "Poll timeout in create append vol on device %s\n", dev_name(dev)); + Dmsg1(400, "Poll timeout in create append vol on device %s\n", dev_name(dev)); continue; } if (stat == ETIMEDOUT) { if (!double_dev_wait_time(dev)) { - Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device \"%s\" for Job %s\n"), + Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device \"%s\" for Job %s\n"), dev_name(dev), jcr->Job); - Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg); - Dmsg1(400, "Gave up waiting on device %s\n", dev_name(dev)); + Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg); + Dmsg1(400, "Gave up waiting on device %s\n", dev_name(dev)); return false; /* exceeded maximum waits */ } continue; } if (stat == EINVAL) { berrno be; - Mmsg2(dev->errmsg, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), + Mmsg2(dev->errmsg, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat, be.strerror(stat)); - Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg); + Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg); return false; } if (stat != 0) { berrno be; - Jmsg(jcr, M_WARNING, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat, + Jmsg(jcr, M_WARNING, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat, be.strerror(stat)); } Dmsg1(400, "Someone woke me for device %s\n", dev_name(dev)); @@ -481,16 +483,16 @@ bool dir_ask_sysop_to_mount_volume(DCR *dcr) ASSERT(dev->dev_blocked); for ( ;; ) { if (job_canceled(jcr)) { - Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"), + Mmsg(dev->errmsg, _("Job %s canceled while waiting for mount on Storage Device \"%s\".\n"), jcr->Job, dcr->dev_name); return false; } if (!dev->poll) { - msg = _("Please mount"); - Jmsg(jcr, M_MOUNT, 0, _("%s Volume \"%s\" on Storage Device \"%s\" for Job %s\n"), + msg = _("Please mount"); + Jmsg(jcr, M_MOUNT, 0, _("%s Volume \"%s\" on Storage Device \"%s\" for Job %s\n"), msg, dcr->VolumeName, dcr->dev_name, jcr->Job); - Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n", + Dmsg3(400, "Mount \"%s\" on device \"%s\" for Job %s\n", dcr->VolumeName, dcr->dev_name, jcr->Job); } @@ -499,31 +501,31 @@ bool dir_ask_sysop_to_mount_volume(DCR *dcr) stat = wait_for_sysop(dcr); ; /* wait on device */ if (dev->poll) { - Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev_name(dev)); - Dmsg1(400, "Blocked=%s\n", edit_blocked_reason(dev)); + Dmsg1(400, "Poll timeout in mount vol on device %s\n", dev_name(dev)); + Dmsg1(400, "Blocked=%s\n", edit_blocked_reason(dev)); return true; } if (stat == ETIMEDOUT) { if (!double_dev_wait_time(dev)) { - Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device \"%s\" for Job %s\n"), + Mmsg(dev->errmsg, _("Max time exceeded waiting to mount Storage Device \"%s\" for Job %s\n"), dev_name(dev), jcr->Job); - Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg); - Dmsg1(400, "Gave up waiting on device %s\n", dev_name(dev)); + Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg); + Dmsg1(400, "Gave up waiting on device %s\n", dev_name(dev)); return false; /* exceeded maximum waits */ } continue; } if (stat == EINVAL) { berrno be; - Mmsg2(dev->errmsg, _("pthread error in mount_volume stat=%d ERR=%s\n"), + Mmsg2(dev->errmsg, _("pthread error in mount_volume stat=%d ERR=%s\n"), stat, be.strerror(stat)); - Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg); + Jmsg(jcr, M_FATAL, 0, "%s", dev->errmsg); return false; } if (stat != 0) { berrno be; - Jmsg(jcr, M_FATAL, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat, + Jmsg(jcr, M_FATAL, 0, _("pthread error in mount_next_volume stat=%d ERR=%s\n"), stat, be.strerror(stat)); } Dmsg1(400, "Someone woke me for device %s\n", dev_name(dev)); @@ -600,7 +602,7 @@ static int wait_for_sysop(DCR *dcr) /* send heartbeats */ if (jcr->file_bsock) { bnet_sig(jcr->file_bsock, BNET_HEARTBEAT); - Dmsg0(400, "Send heartbeat to FD.\n"); + Dmsg0(400, "Send heartbeat to FD.\n"); } if (jcr->dir_bsock) { bnet_sig(jcr->dir_bsock, BNET_HEARTBEAT); @@ -619,13 +621,13 @@ static int wait_for_sysop(DCR *dcr) break; /* on error return */ } if (dev->rem_wait_sec <= 0) { /* on exceeding wait time return */ - Dmsg0(400, "Exceed wait time.\n"); + Dmsg0(400, "Exceed wait time.\n"); break; } if (!unmounted && dev->vol_poll_interval && (now - first_start >= dev->vol_poll_interval)) { - Dmsg1(400, "In wait blocked=%s\n", edit_blocked_reason(dev)); + Dmsg1(400, "In wait blocked=%s\n", edit_blocked_reason(dev)); dev->poll = true; /* returning a poll event */ break; } diff --git a/bacula/src/stored/block.c b/bacula/src/stored/block.c index 4ad745f3fa..8fb8a26815 100644 --- a/bacula/src/stored/block.c +++ b/bacula/src/stored/block.c @@ -9,7 +9,7 @@ * */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -234,10 +234,10 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) block->bufp = block->buf + bhl; if (strncmp(Id, BLKHDR1_ID, BLKHDR_ID_LENGTH) != 0) { dev->dev_errno = EIO; - Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"), + Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"), dev->file, dev->block_num, BLKHDR1_ID, Id); if (block->read_errors == 0 || verbose >= 2) { - Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); + Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } block->read_errors++; return false; @@ -250,10 +250,10 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) block->bufp = block->buf + bhl; if (strncmp(Id, BLKHDR2_ID, BLKHDR_ID_LENGTH) != 0) { dev->dev_errno = EIO; - Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"), + Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"), dev->file, dev->block_num, BLKHDR2_ID, Id); if (block->read_errors == 0 || verbose >= 2) { - Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); + Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } block->read_errors++; return false; @@ -263,7 +263,7 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) Mmsg4(dev->errmsg, _("Volume data error at %u:%u! Wanted ID: \"%s\", got \"%s\". Buffer discarded.\n"), dev->file, dev->block_num, BLKHDR2_ID, Id); if (block->read_errors == 0 || verbose >= 2) { - Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); + Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } block->read_errors++; unser_uint32(block->VolSessionId); @@ -277,7 +277,7 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) Mmsg3(dev->errmsg, _("Volume data error at %u:%u! Block length %u is insane (too large), probably due to a bad archive.\n"), dev->file, dev->block_num, block_len); if (block->read_errors == 0 || verbose >= 2) { - Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); + Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } block->read_errors++; return false; @@ -300,10 +300,10 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block) block_len-BLKHDR_CS_LENGTH); if (BlockCheckSum != CheckSum) { dev->dev_errno = EIO; - Mmsg5(dev->errmsg, _("Volume data error at %u:%u! Block checksum mismatch in block %u: calc=%x blk=%x\n"), + Mmsg5(dev->errmsg, _("Volume data error at %u:%u! Block checksum mismatch in block %u: calc=%x blk=%x\n"), dev->file, dev->block_num, (unsigned)BlockNumber, BlockCheckSum, CheckSum); if (block->read_errors == 0 || verbose >= 2) { - Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); + Jmsg(jcr, M_ERROR, 0, "%s", dev->errmsg); } block->read_errors++; if (!forge_on) { @@ -350,7 +350,7 @@ bool write_block_to_device(DCR *dcr) /* Create a jobmedia record for this job */ if (!dir_create_jobmedia_record(dcr)) { dev->dev_errno = EIO; - Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), dcr->VolCatInfo.VolCatName, jcr->Job); set_new_volume_parameters(dcr); stat = false; @@ -476,7 +476,7 @@ bool write_block_to_dev(DCR *dcr) dev->file_size = 0; /* reset file size */ if (dev_state(dev, ST_TAPE) && weof_dev(dev, 1) != 0) { /* write eof */ - Dmsg0(190, "WEOF error in max file size.\n"); + Dmsg0(190, "WEOF error in max file size.\n"); terminate_writing_volume(dcr); dev->dev_errno = ENOSPC; return false; @@ -484,9 +484,9 @@ bool write_block_to_dev(DCR *dcr) /* Create a JobMedia record so restore can seek */ if (!dir_create_jobmedia_record(dcr)) { - Dmsg0(190, "Error from create_job_media.\n"); + Dmsg0(190, "Error from create_job_media.\n"); dev->dev_errno = EIO; - Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), + Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"), dcr->VolCatInfo.VolCatName, jcr->Job); terminate_writing_volume(dcr); dev->dev_errno = EIO; @@ -494,7 +494,7 @@ bool write_block_to_dev(DCR *dcr) } dev->VolCatInfo.VolCatFiles = dev->file; if (!dir_update_volume_info(dcr, false)) { - Dmsg0(190, "Error from update_vol_info.\n"); + Dmsg0(190, "Error from update_vol_info.\n"); terminate_writing_volume(dcr); dev->dev_errno = EIO; return false; @@ -516,6 +516,60 @@ bool write_block_to_dev(DCR *dcr) /* Set new file/block parameters for current dcr */ set_new_file_parameters(dcr); } + + /* Limit maximum part size to value specified by user (not applicable to tapes/fifos) */ + if (!(dev->state & (ST_TAPE|ST_FIFO)) && + (dev->max_part_size > 0) && + ((dev->part_size + block->binbuf) >= dev->max_part_size)) { + if (dev->part < dev->num_parts) { + Jmsg3(dcr->jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"), + dev->part, dev->num_parts, dev_name(dev)); + dev->dev_errno = EIO; + return false; + } + + if (open_next_part(dev) < 0) { + Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device next part %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + dev->dev_errno = EIO; + return false; + } + + dev->VolCatInfo.VolCatParts = dev->num_parts; + + if (!dir_update_volume_info(dcr, false)) { + Dmsg0(190, "Error from update_vol_info.\n"); + dev->dev_errno = EIO; + return false; + } + } + + if (dev->free_space_errno < 0) { /* Error while getting free space */ + char ed1[50]; + char ed2[50]; + Dmsg1(10, "Cannot get free space on the device ERR=%s.\n", dev->errmsg); + Jmsg(jcr, M_FATAL, 0, _("End of Volume \"%s\" at %u:%u on device %s (part_size=%s, free_space=%s, free_space_errno=%d, errmsg=%s).\n"), + dev->VolCatInfo.VolCatName, + dev->file, dev->block_num, dev->dev_name, + edit_uint64_with_commas(dev->part_size, ed1), edit_uint64_with_commas(dev->free_space, ed2), + dev->free_space_errno, dev->errmsg); + dev->dev_errno = -dev->free_space_errno; + return false; + } + + if (((dev->free_space_errno > 0) && ((dev->part_size + block->binbuf) >= dev->free_space))) { + char ed1[50]; + char ed2[50]; + Dmsg0(10, "==== Just enough free space on the device to write the current part...\n"); + Jmsg(jcr, M_INFO, 0, _("End of Volume \"%s\" at %u:%u on device %s (part_size=%s, free_space=%s, free_space_errno=%d).\n"), + dev->VolCatInfo.VolCatName, + dev->file, dev->block_num, dev->dev_name, + edit_uint64_with_commas(dev->part_size, ed1), edit_uint64_with_commas(dev->free_space, ed2), + dev->free_space_errno); + terminate_writing_volume(dcr); + dev->dev_errno = ENOSPC; + return false; + } dev->VolCatInfo.VolCatWrites++; Dmsg1(300, "Write block of %u bytes\n", wlen); @@ -548,14 +602,14 @@ bool write_block_to_dev(DCR *dcr) dev->dev_errno = ENOSPC; /* out of space */ } if (dev->dev_errno != ENOSPC) { - Jmsg4(jcr, M_ERROR, 0, _("Write error at %u:%u on device %s. ERR=%s.\n"), + Jmsg4(jcr, M_ERROR, 0, _("Write error at %u:%u on device %s. ERR=%s.\n"), dev->file, dev->block_num, dev->dev_name, be.strerror()); } } else { dev->dev_errno = ENOSPC; /* out of space */ } if (dev->dev_errno == ENOSPC) { - Jmsg(jcr, M_INFO, 0, _("End of Volume \"%s\" at %u:%u on device %s. Write of %u bytes got %d.\n"), + Jmsg(jcr, M_INFO, 0, _("End of Volume \"%s\" at %u:%u on device %s. Write of %u bytes got %d.\n"), dev->VolCatInfo.VolCatName, dev->file, dev->block_num, dev->dev_name, wlen, stat); } @@ -580,19 +634,19 @@ bool write_block_to_dev(DCR *dcr) /* Now back up over what we wrote and read the last block */ if (!bsf_dev(dev, 1)) { ok = false; - Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); + Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); } if (ok && dev_cap(dev, CAP_TWOEOF) && !bsf_dev(dev, 1)) { ok = false; - Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); + Jmsg(jcr, M_ERROR, 0, _("Backspace file at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); } /* Backspace over record */ if (ok && !bsr_dev(dev, 1)) { ok = false; - Jmsg(jcr, M_ERROR, 0, _("Backspace record at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); + Jmsg(jcr, M_ERROR, 0, _("Backspace record at EOT failed. ERR=%s\n"), strerror(dev->dev_errno)); /* * On FreeBSD systems, if the user got here, it is likely that his/her - * tape drive is "frozen". The correct thing to do is a + * tape drive is "frozen". The correct thing to do is a * rewind(), but if we do that, higher levels in cleaning up, will * most likely write the EOS record over the beginning of the * tape. The rewind *is* done later in mount.c when another @@ -605,10 +659,10 @@ bool write_block_to_dev(DCR *dcr) /* Note, this can destroy dev->errmsg */ dcr->block = lblock; if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) { - Jmsg(jcr, M_ERROR, 0, _("Re-read last block at EOT failed. ERR=%s"), dev->errmsg); + Jmsg(jcr, M_ERROR, 0, _("Re-read last block at EOT failed. ERR=%s"), dev->errmsg); } else { if (lblock->BlockNumber+1 == block->BlockNumber) { - Jmsg(jcr, M_INFO, 0, _("Re-read of last block succeeded.\n")); + Jmsg(jcr, M_INFO, 0, _("Re-read of last block succeeded.\n")); } else { Jmsg(jcr, M_ERROR, 0, _( "Re-read of last block failed. Last block=%u Current block=%u.\n"), @@ -650,6 +704,7 @@ bool write_block_to_dev(DCR *dcr) dcr->WroteVol = true; dev->file_addr += wlen; /* update file address */ dev->file_size += wlen; + dev->part_size += wlen; Dmsg2(300, "write_block: wrote block %d bytes=%d\n", dev->block_num, wlen); empty_block(block); @@ -675,11 +730,16 @@ static bool terminate_writing_volume(DCR *dcr) if (weof_dev(dev, 1) != 0) { /* end the tape */ dev->VolCatInfo.VolCatErrors++; Jmsg(dcr->jcr, M_ERROR, 0, "Error writing final EOF to tape. This tape may not be readable.\n" - "%s", dev->errmsg); + "%s", dev->errmsg); ok = false; Dmsg0(100, "WEOF error.\n"); } dev->VolCatInfo.VolCatFiles = dev->file; + + if (dev_cap(dev, CAP_REQMOUNT)) { /* Write the current (and last) part. */ + open_next_part(dev); + } + if (!dir_update_volume_info(dcr, false)) { ok = false; } @@ -743,7 +803,7 @@ bool read_block_from_dev(DCR *dcr, bool check_block_numbers) JCR *jcr = dcr->jcr; DEVICE *dev = dcr->dev; DEV_BLOCK *block = dcr->block; - + if (dev_state(dev, ST_EOT)) { return false; } @@ -759,6 +819,27 @@ reread: block->read_len = 0; return false; } + + /*Dmsg1(200, "dev.c 111->file_size=%u\n",(unsigned int)dev->file_size); + Dmsg1(200, "dev.c lseek=%u\n",(unsigned int)lseek(dev->fd, 0, SEEK_CUR)); + Dmsg1(200, "dev.c dev->part_start=%u\n",(unsigned int)dev->part_start); + Dmsg1(200, "dev.c dev->file_size-dev->part_start=%u\n",(unsigned int)dev->file_size-dev->part_start); + Dmsg1(200, "dev.c dev->part_size=%u\n", (unsigned int)dev->part_size); + Dmsg1(200, "dev.c dev->part=%u\n", (unsigned int)dev->part); + Dmsg1(200, "dev.c dev->VolCatInfo.VolCatParts=%u\n", (unsigned int)dev->VolCatInfo.VolCatParts); + Dmsg3(200, "dev.c Tests : %d %d %d\n", (dev->VolCatInfo.VolCatParts > 0), ((dev->file_size-dev->part_start) == dev->part_size), (dev->part <= dev->VolCatInfo.VolCatParts));*/ + /* Check for part file end */ + if ((dev->num_parts > 0) && + ((dev->file_size-dev->part_start) == dev->part_size) && + (dev->part < dev->num_parts)) { + if (open_next_part(dev) < 0) { + Jmsg2(dcr->jcr, M_FATAL, 0, _("Unable to open device next part %s. ERR=%s\n"), + dev_name(dev), strerror_dev(dev)); + dev->dev_errno = EIO; + return false; + } + } + retry = 0; do { // uint32_t *bp = (uint32_t *)block->buf; @@ -836,17 +917,17 @@ reread: Pmsg1(000, "%s", dev->errmsg); /* Attempt to reposition to re-read the block */ if (dev->state & ST_TAPE) { - Dmsg0(200, "BSR for reread; block too big for buffer.\n"); + Dmsg0(200, "BSR for reread; block too big for buffer.\n"); if (!bsr_dev(dev, 1)) { - Jmsg(jcr, M_ERROR, 0, "%s", strerror_dev(dev)); + Jmsg(jcr, M_ERROR, 0, "%s", strerror_dev(dev)); block->read_len = 0; return false; } } else { - Dmsg0(200, "Seek to beginning of block for reread.\n"); - off_t pos = lseek(dev->fd, (off_t)0, SEEK_CUR); /* get curr pos */ + Dmsg0(200, "Seek to beginning of block for reread.\n"); + off_t pos = lseek_dev(dev, (off_t)0, SEEK_CUR); /* get curr pos */ pos -= block->read_len; - lseek(dev->fd, pos, SEEK_SET); + lseek_dev(dev, pos, SEEK_SET); dev->file_addr = pos; } Mmsg1(dev->errmsg, _("Setting block buffer size to %u bytes.\n"), block->block_len); @@ -910,9 +991,9 @@ reread: */ Dmsg0(200, "At end of read block\n"); if (block->read_len > block->block_len && !(dev->state & ST_TAPE)) { - off_t pos = lseek(dev->fd, (off_t)0, SEEK_CUR); /* get curr pos */ + off_t pos = lseek_dev(dev, (off_t)0, SEEK_CUR); /* get curr pos */ pos -= (block->read_len - block->block_len); - lseek(dev->fd, pos, SEEK_SET); + lseek_dev(dev, pos, SEEK_SET); Dmsg2(200, "Did lseek blk_size=%d rdlen=%d\n", block->block_len, block->read_len); dev->file_addr = pos; diff --git a/bacula/src/stored/dev.c b/bacula/src/stored/dev.c index b8967bfb29..1aa389c542 100644 --- a/bacula/src/stored/dev.c +++ b/bacula/src/stored/dev.c @@ -29,7 +29,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -82,6 +82,12 @@ /* Forward referenced functions */ void set_os_device_parameters(DEVICE *dev); +int mount_dev(DEVICE* dev, int timeout); +int unmount_dev(DEVICE* dev, int timeout); +int write_part(DEVICE *dev); +char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg); +void get_filename(DEVICE *dev, char *VolName, POOL_MEM& archive_name); +void update_free_space_dev(DEVICE* dev); /* * Allocate and initialize the DEVICE structure @@ -109,9 +115,34 @@ init_dev(DEVICE *dev, DEVRES *device) dev->dev_errno = errno; } Emsg2(M_FATAL, 0, "Unable to stat device %s : %s\n", device->device_name, - be.strerror()); + be.strerror()); return NULL; } + + /* If the device requires mount : + * - Check that the mount point is available + * - Check that (un)mount commands are defined + */ + if (device->cap_bits & CAP_REQMOUNT) { + if (stat(device->mount_point, &statp) < 0) { + berrno be; + if (dev) { + dev->dev_errno = errno; + } + Emsg2(M_FATAL, 0, "Unable to stat mount point %s : %s\n", device->mount_point, + be.strerror()); + return NULL; + } + if (!device->mount_command || !device->unmount_command) { + Emsg0(M_FATAL, 0, "Mount and unmount commands must defined for a device which requires mount.\n"); + return NULL; + } + if (!device->write_part_command) { + Emsg0(M_FATAL, 0, "Write part command must be defined for a device which requires mount.\n"); + return NULL; + } + } + tape = false; fifo = false; if (S_ISDIR(statp.st_mode)) { @@ -151,6 +182,12 @@ init_dev(DEVICE *dev, DEVRES *device) dev->vol_poll_interval = device->vol_poll_interval; dev->max_spool_size = device->max_spool_size; dev->drive_index = device->drive_index; + if (tape) { /* No parts on tapes */ + dev->max_part_size = 0; + } + else { + dev->max_part_size = device->max_part_size; + } /* Sanity check */ if (dev->vol_poll_interval && dev->vol_poll_interval < 60) { dev->vol_poll_interval = 60; @@ -213,10 +250,48 @@ init_dev(DEVICE *dev, DEVRES *device) dev->fd = -1; dev->attached_dcrs = New(dlist(dcr, &dcr->dev_link)); Dmsg2(29, "init_dev: tape=%d dev_name=%s\n", dev_is_tape(dev), dev->dev_name); - + return dev; } +/* + * Write the current volume/part filename to archive_name. + */ + +void get_filename(DEVICE *dev, char *VolName, POOL_MEM& archive_name) { + char partnumber[20]; + + if (dev_cap(dev, CAP_REQMOUNT)) { + /* If we try to open the last part, just open it from disk, + * otherwise, open it from the spooling directory */ + if (dev->part < dev->num_parts) { + pm_strcpy(archive_name, dev->device->mount_point); + } + else { + /* Use the working directory if spool directory is not defined */ + if (dev->device->spool_directory) { + pm_strcpy(archive_name, dev->device->spool_directory); + } else { + pm_strcpy(archive_name, working_directory); + } + } + } + else { + pm_strcpy(archive_name, dev->dev_name); + } + + if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') { + pm_strcat(archive_name, "/"); + } + pm_strcat(archive_name, VolName); + /* if part != 0, append .# to the filename (where # is the part number) */ + if (dev->part != 0) { + pm_strcat(archive_name, "."); + bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part); + pm_strcat(archive_name, partnumber); + } +} + /* Open the device with the operating system and * initialize buffer pointers. * @@ -229,8 +304,6 @@ init_dev(DEVICE *dev, DEVRES *device) int open_dev(DEVICE *dev, char *VolName, int mode) { - POOLMEM *archive_name; - if (dev->state & ST_OPENED) { /* * *****FIXME***** how to handle two threads wanting @@ -254,8 +327,8 @@ open_dev(DEVICE *dev, char *VolName, int mode) Dmsg3(29, "open_dev: tape=%d dev_name=%s vol=%s\n", dev_is_tape(dev), dev->dev_name, dev->VolCatInfo.VolCatName); dev->state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF); - dev->file_size = 0; if (dev->state & (ST_TAPE|ST_FIFO)) { + dev->file_size = 0; int timeout; Dmsg0(29, "open_dev: device is tape\n"); if (mode == OPEN_READ_WRITE) { @@ -265,7 +338,7 @@ open_dev(DEVICE *dev, char *VolName, int mode) } else if (mode == OPEN_WRITE_ONLY) { dev->mode = O_WRONLY | O_BINARY; } else { - Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); + Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); } timeout = dev->max_open_wait; errno = 0; @@ -280,12 +353,12 @@ open_dev(DEVICE *dev, char *VolName, int mode) continue; } if (errno == EBUSY && timeout-- > 0) { - Dmsg2(100, "Device %s busy. ERR=%s\n", dev->dev_name, be.strerror()); + Dmsg2(100, "Device %s busy. ERR=%s\n", dev->dev_name, be.strerror()); bmicrosleep(1, 0); continue; } dev->dev_errno = errno; - Mmsg2(&dev->errmsg, _("stored: unable to open device %s: ERR=%s\n"), + Mmsg2(&dev->errmsg, _("stored: unable to open device %s: ERR=%s\n"), dev->dev_name, be.strerror()); /* Stop any open timer we set */ if (dev->tid) { @@ -309,21 +382,49 @@ open_dev(DEVICE *dev, char *VolName, int mode) } Dmsg1(29, "open_dev: tape %d opened\n", dev->fd); } else { + POOL_MEM archive_name(PM_FNAME); + struct stat filestat; /* * Handle opening of File Archive (not a tape) - */ + */ + if (dev->part == 0) { + dev->file_size = 0; + } + dev->part_size = 0; + + /* if num_parts has not been set, but VolCatInfo is available, copy + * it from the VolCatInfo.VolCatParts */ + if (dev->num_parts < dev->VolCatInfo.VolCatParts) { + dev->num_parts = dev->VolCatInfo.VolCatParts; + } + if (VolName == NULL || *VolName == 0) { - Mmsg(dev->errmsg, _("Could not open file device %s. No Volume name given.\n"), + Mmsg(dev->errmsg, _("Could not open file device %s. No Volume name given.\n"), dev->dev_name); return -1; } - archive_name = get_pool_memory(PM_FNAME); - pm_strcpy(archive_name, dev->dev_name); - if (archive_name[strlen(archive_name)] != '/') { - pm_strcat(archive_name, "/"); + get_filename(dev, VolName, archive_name); + + if (dev_cap(dev, CAP_REQMOUNT) && (dev->num_parts > 0)) { + if (mount_dev(dev, 1) < 0) { + Mmsg(dev->errmsg, _("Could not mount device %s.\n"), + dev->dev_name); + Emsg0(M_FATAL, 0, dev->errmsg); + dev->fd = -1; + return dev->fd; + } } - pm_strcat(archive_name, VolName); - Dmsg1(29, "open_dev: device is disk %s\n", archive_name); + + Dmsg2(29, "open_dev: device is disk %s (mode:%d)\n", archive_name.c_str(), mode); + dev->openmode = mode; + + /* If we are not trying to access the last part, set mode to OPEN_READ_ONLY, + * as writing would be an error. + */ + if (dev->part < dev->num_parts) { + mode = OPEN_READ_ONLY; + } + if (mode == OPEN_READ_WRITE) { dev->mode = O_CREAT | O_RDWR | O_BINARY; } else if (mode == OPEN_READ_ONLY) { @@ -331,26 +432,503 @@ open_dev(DEVICE *dev, char *VolName, int mode) } else if (mode == OPEN_WRITE_ONLY) { dev->mode = O_WRONLY | O_BINARY; } else { - Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); + Emsg0(M_ABORT, 0, _("Illegal mode given to open_dev.\n")); } /* If creating file, give 0640 permissions */ - if ((dev->fd = open(archive_name, dev->mode, 0640)) < 0) { + if ((dev->fd = open(archive_name.c_str(), dev->mode, 0640)) < 0) { berrno be; dev->dev_errno = errno; - Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name, be.strerror()); + Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), be.strerror()); Emsg0(M_FATAL, 0, dev->errmsg); } else { dev->dev_errno = 0; dev->state |= ST_OPENED; dev->use_count = 1; update_pos_dev(dev); /* update position */ + if (fstat(dev->fd, &filestat) < 0) { + berrno be; + dev->dev_errno = errno; + Mmsg2(&dev->errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), be.strerror()); + Emsg0(M_FATAL, 0, dev->errmsg); + } + else { + dev->part_size = filestat.st_size; + } + } + Dmsg4(29, "open_dev: disk fd=%d opened, part=%d/%d, part_size=%u\n", dev->fd, dev->part, dev->num_parts, dev->part_size); + if ((dev->mode != OPEN_READ_ONLY) && ((dev->free_space_errno == 0) || (dev->num_parts == dev->part))) { + update_free_space_dev(dev); } - Dmsg1(29, "open_dev: disk fd=%d opened\n", dev->fd); - free_pool_memory(archive_name); } return dev->fd; } +/* (Un)mount the device */ +int do_mount_dev(DEVICE* dev, int mount, int dotimeout) { + POOL_MEM ocmd(PM_FNAME); + POOLMEM* results; + results = get_pool_memory(PM_MESSAGE); + char* icmd; + int status, timeout; + + if (mount) { + icmd = dev->device->mount_command; + } + else { + icmd = dev->device->unmount_command; + } + + edit_device_codes_dev(dev, ocmd.c_str(), icmd); + + Dmsg2(29, "do_mount_dev: cmd=%s state=%d\n", ocmd.c_str(), dev->state & ST_MOUNTED); + + if (dotimeout) { + /* Try at most 5 times to (un)mount the device. This should perhaps be configurable. */ + timeout = 5; + } + else { + timeout = 0; + } + /* If busy retry each second */ + while ((status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results)) != 0) { + if (--timeout > 0) { + Dmsg2(40, "Device %s cannot be (un)mounted. Retrying... ERR=%s\n", dev->dev_name, results); + /* Sometimes the device cannot be mounted because it is already mounted. + * Try to unmount it, then remount it */ + if (mount) { + Dmsg1(40, "Trying to unmount the device %s...\n", dev->dev_name); + do_mount_dev(dev, 0, 0); + } + bmicrosleep(1, 0); + continue; + } + free_pool_memory(results); + Dmsg2(40, "Device %s cannot be mounted. ERR=%s\n", dev->dev_name, results); + return -1; + } + + if (mount) { + dev->state |= ST_MOUNTED; + } + else { + dev->state &= ~ST_MOUNTED; + } + free_pool_memory(results); + + Dmsg1(29, "do_mount_dev: end_state=%d\n", dev->state & ST_MOUNTED); + return 0; +} + +/* Only for devices that requires mount. + * Try to find the volume name of the loaded device, and open the + * first part of this volume. + * + * Returns 0 if read_dev_volume_label can now read the label, + * -1 if an error occured, and read_dev_volume_label_guess must abort with an IO_ERROR. + * + * To guess the device name, it lists all the files on the DVD, and searches for a + * file which has a minimum size (500 bytes). If this file has a numeric extension, + * like part files, try to open the file which has no extension (e.g. the first + * part file). + * So, if the DVD does not contains a Bacula volume, a random file is opened, + * and no valid label could be read from this file. + */ +int open_guess_name_dev(DEVICE *dev) { + Dmsg1(29, "open_guess_name_dev: dev=%s\n", dev->dev_name); + POOL_MEM guessedname(PM_FNAME); + DIR* dp; + struct dirent *entry, *result; + struct stat statp; + int index; + int name_max; + + if (!dev_cap(dev, CAP_REQMOUNT)) { + Dmsg1(100, "open_guess_name_dev: device does not require mount, returning 0. dev=%s\n", dev->dev_name); + return 0; + } + +#ifndef HAVE_DIRENT_H + Dmsg0(29, "open_guess_name_dev: readdir not available, cannot guess volume name\n"); + return 0; +#endif + + update_free_space_dev(dev); + + if (mount_dev(dev, 1) < 0) { + /* If the device cannot be mounted, check if it is writable */ + if (dev->free_space_errno >= 0) { + Dmsg1(100, "open_guess_name_dev: device cannot be mounted, but it seems to be writable, returning 0. dev=%s\n", dev->dev_name); + return 0; + } + else { + Dmsg1(100, "open_guess_name_dev: device cannot be mounted, and is not writable, returning 0. dev=%s\n", dev->dev_name); + /* read_dev_volume_label_guess must now check dev->free_space_errno to understand that the media is not writable. */ + return 0; + } + } + + name_max = pathconf(".", _PC_NAME_MAX); + if (name_max < 1024) { + name_max = 1024; + } + + if (!(dp = opendir(dev->device->mount_point))) { + berrno be; + dev->dev_errno = errno; + Dmsg3(29, "open_guess_name_dev: failed to open dir %s (dev=%s), ERR=%s\n", dev->device->mount_point, dev->dev_name, be.strerror()); + return -1; + } + + entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 100); + while (1) { + if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) { + dev->dev_errno = ENOENT; + Dmsg2(29, "open_guess_name_dev: failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->dev_name); + closedir(dp); + return -1; + } + + ASSERT(name_max+1 > (int)sizeof(struct dirent) + (int)NAMELEN(entry)); + + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) { + continue; + } + + pm_strcpy(guessedname, dev->device->mount_point); + if (guessedname.c_str()[strlen(guessedname.c_str())-1] != '/') { + pm_strcat(guessedname, "/"); + } + pm_strcat(guessedname, entry->d_name); + + if (stat(guessedname.c_str(), &statp) < 0) { + berrno be; + Dmsg3(29, "open_guess_name_dev: failed to stat %s (dev=%s), ERR=%s\n", + guessedname.c_str(), dev->dev_name, be.strerror()); + continue; + } + + if (!S_ISREG(statp.st_mode) || (statp.st_size < 500)) { + Dmsg2(100, "open_guess_name_dev: %s is not a regular file, or less than 500 bytes (dev=%s)\n", + guessedname.c_str(), dev->dev_name); + continue; + } + + /* Ok, we found a good file, remove the part extension if possible. */ + for (index = strlen(guessedname.c_str())-1; index >= 0; index--) { + if ((guessedname.c_str()[index] == '/') || + (guessedname.c_str()[index] < '0') || + (guessedname.c_str()[index] > '9')) { + break; + } + if (guessedname.c_str()[index] == '.') { + guessedname.c_str()[index] = '\0'; + break; + } + } + + if ((stat(guessedname.c_str(), &statp) < 0) || (statp.st_size < 500)) { + /* The file with extension truncated does not exists or is too small, so use it with its extension. */ + berrno be; + Dmsg3(100, "open_guess_name_dev: failed to stat %s (dev=%s), using the file with its extension, ERR=%s\n", + guessedname.c_str(), dev->dev_name, be.strerror()); + pm_strcpy(guessedname, dev->device->mount_point); + if (guessedname.c_str()[strlen(guessedname.c_str())-1] != '/') { + pm_strcat(guessedname, "/"); + } + pm_strcat(guessedname, entry->d_name); + continue; + } + break; + } + + closedir(dp); + + if (dev->fd >= 0) { + close(dev->fd); + } + + if ((dev->fd = open(guessedname.c_str(), O_RDONLY | O_BINARY)) < 0) { + berrno be; + dev->dev_errno = errno; + Dmsg3(29, "open_guess_name_dev: failed to open %s (dev=%s), ERR=%s\n", + guessedname.c_str(), dev->dev_name, be.strerror()); + if (open_first_part(dev) < 0) { + berrno be; + dev->dev_errno = errno; + Mmsg1(&dev->errmsg, _("Could not open_first_part, ERR=%s\n"), be.strerror()); + Emsg0(M_FATAL, 0, dev->errmsg); + } + return -1; + } + dev->part_start = 0; + dev->part_size = statp.st_size; + dev->part = 0; + dev->state |= ST_OPENED; + dev->use_count = 1; + + Dmsg2(29, "open_guess_name_dev: %s opened (dev=%s)\n", guessedname.c_str(), dev->dev_name); + + return 0; +} + +/* Mount the device. + * If timeout, wait until the mount command returns 0. + * If !timeout, try to mount the device only once. + */ +int mount_dev(DEVICE* dev, int timeout) { + if (dev->state & ST_MOUNTED) { + Dmsg0(100, "mount_dev: Device already mounted\n"); + return 0; + } + else { + return do_mount_dev(dev, 1, timeout); + } +} + +/* Unmount the device + * If timeout, wait until the unmount command returns 0. + * If !timeout, try to unmount the device only once. + */ +int unmount_dev(DEVICE* dev, int timeout) { + if (dev->state & ST_MOUNTED) { + return do_mount_dev(dev, 0, timeout); + } + else { + Dmsg0(100, "mount_dev: Device already unmounted\n"); + return 0; + } +} + +/* Update the free space on the device */ +void update_free_space_dev(DEVICE* dev) { + POOL_MEM ocmd(PM_FNAME); + POOLMEM* results; + char* icmd; + int timeout; + char* statstr; + long long int free; + + icmd = dev->device->free_space_command; + + if (!icmd) { + dev->free_space = 0; + dev->free_space_errno = 0; + Dmsg2(29, "update_free_space_dev: free_space=%d, free_space_errno=%d (!icmd)\n", dev->free_space, dev->free_space_errno); + return; + } + + edit_device_codes_dev(dev, ocmd.c_str(), icmd); + + Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str()); + + results = get_pool_memory(PM_MESSAGE); + + /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */ + timeout = 3; + + while (1) { + if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) { + Dmsg1(100, "Free space program run : %s\n", results); + /* We also need negatives values, so we can't use dev->free_space, which is unsigned */ + free = strtoll(results, &statstr, 10); + if (results != statstr) { /* Something parsed */ + if (free >= 0) { + dev->free_space = free; + dev->free_space_errno = 1; + Mmsg0(dev->errmsg, ""); + break; + } + else { + dev->free_space_errno = free; + dev->free_space = 0; + if (*statstr == '\n') { + statstr++; + } + if (statstr[strlen(statstr)-1] == '\n') { + statstr[strlen(statstr)-1] = 0; + } + Mmsg1(dev->errmsg, "Error while getting free space (%s)", statstr); + } + } + else { + dev->free_space = 0; + dev->free_space_errno = -EPIPE; + Mmsg1(dev->errmsg, "Error while getting free space (output=%s)", results); + } + } + else { + dev->free_space = 0; + dev->free_space_errno = -EPIPE; + Mmsg1(dev->errmsg, "Cannot run free space command (%s)", results); + } + + if (--timeout > 0) { + Dmsg4(40, "Cannot get free space on device %s. free_space=%lld, free_space_errno=%d ERR=%s\n", dev->dev_name, + dev->free_space, dev->free_space_errno, dev->errmsg); + bmicrosleep(1, 0); + continue; + } + + dev->dev_errno = -dev->free_space_errno; + Dmsg4(40, "Cannot get free space on device %s. free_space=%lld, free_space_errno=%d ERR=%s\n", + dev->dev_name, dev->free_space, dev->free_space_errno, dev->errmsg); + free_pool_memory(results); + return; + } + + free_pool_memory(results); + + Dmsg2(29, "update_free_space_dev: free_space=%lld, free_space_errno=%d\n", dev->free_space, dev->free_space_errno); +} + +int write_part(DEVICE *dev) { + Dmsg1(29, "write_part: device is %s\n", dev->dev_name); + + if (unmount_dev(dev, 1) < 0) { + Dmsg0(29, "write_part: unable to unmount the device\n"); + } + + POOL_MEM ocmd(PM_FNAME); + POOLMEM *results; + results = get_pool_memory(PM_MESSAGE); + char* icmd; + int status; + int timeout; + + icmd = dev->device->write_part_command; + + edit_device_codes_dev(dev, ocmd.c_str(), icmd); + + /* Wait at most the time a maximum size part is written in DVD 0.5x speed + * FIXME: Minimum speed should be in device configuration + */ + timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2)); + + Dmsg2(29, "write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout); + + status = run_program_full_output(ocmd.c_str(), timeout, results); + if (status != 0) { + Mmsg1(dev->errmsg, "Error while writing current part to the DVD: %s", results); + dev->dev_errno = EIO; + free_pool_memory(results); + return -1; + } + else { + Dmsg1(29, "write_part: command output=%s\n", results); + POOL_MEM archive_name(PM_FNAME); + get_filename(dev, dev->VolCatInfo.VolCatName, archive_name); + unlink(archive_name.c_str()); + free_pool_memory(results); + return 0; + } +} + +/* Open the next part file. + * - Close the fd + * - Increment part number + * - Reopen the device + */ +int open_next_part(DEVICE *dev) { + int state; + + Dmsg3(29, "open_next_part %s %s %d\n", dev->dev_name, dev->VolCatInfo.VolCatName, dev->openmode); + /* When appending, do not open a new part if the current is empty */ + if ((dev->state & ST_APPEND) && (dev->part == dev->num_parts) && (dev->part_size == 0)) { + Dmsg0(29, "open_next_part exited immediatly (dev->part_size == 0).\n"); + return dev->fd; + } + + if (dev->fd >= 0) { + close(dev->fd); + } + + dev->fd = -1; + + state = dev->state; + dev->state &= ~ST_OPENED; + + if ((dev_cap(dev, CAP_REQMOUNT)) && (dev->part == dev->num_parts) && (dev->state & ST_APPEND)) { + if (write_part(dev) < 0) { + return -1; + } + } + + dev->part_start += dev->part_size; + dev->part++; + + if ((dev->num_parts < dev->part) && (dev->state & ST_APPEND)) { + dev->num_parts = dev->part; + + /* Check that the next part file does not exists. + * If it does, move it away... */ + POOL_MEM archive_name(PM_FNAME); + POOL_MEM archive_bkp_name(PM_FNAME); + struct stat buf; + + get_filename(dev, dev->VolCatInfo.VolCatName, archive_name); + + /* Check if the next part exists. */ + if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) { + Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str()); + pm_strcpy(archive_bkp_name, archive_name.c_str()); + pm_strcat(archive_bkp_name, ".bak"); + unlink(archive_bkp_name.c_str()); + + /* First try to rename it */ + if (rename(archive_name.c_str(), archive_bkp_name.c_str()) < 0) { + berrno be; + Dmsg3(29, "open_next_part can't rename %s to %s, ERR=%s\n", + archive_name.c_str(), archive_bkp_name.c_str(), be.strerror()); + /* Then try to unlink it */ + if (unlink(archive_name.c_str()) < 0) { + berrno be; + dev->dev_errno = errno; + Mmsg2(&dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), + archive_name.c_str(), be.strerror()); + Emsg0(M_FATAL, 0, dev->errmsg); + return -1; + } + } + } + } + + if (open_dev(dev, dev->VolCatInfo.VolCatName, dev->openmode) < 0) { + return -1; + } + else { + dev->state = state; + return dev->fd; + } +} + +/* Open the first part file. + * - Close the fd + * - Reopen the device + */ +int open_first_part(DEVICE *dev) { + int state; + + Dmsg3(29, "open_first_part %s %s %d\n", dev->dev_name, dev->VolCatInfo.VolCatName, dev->openmode); + if (dev->fd >= 0) { + close(dev->fd); + } + + dev->fd = -1; + state = dev->state; + dev->state &= ~ST_OPENED; + + dev->part_start = 0; + dev->part = 0; + + if (open_dev(dev, dev->VolCatInfo.VolCatName, dev->openmode)) { + dev->state = state; + return dev->fd; + } + else { + return 0; + } +} + #ifdef debug_tracing #undef rewind_dev bool _rewind_dev(char *file, int line, DEVICE *dev) @@ -360,6 +938,108 @@ bool _rewind_dev(char *file, int line, DEVICE *dev) } #endif +/* Protected version of lseek, which opens the right part if necessary */ +off_t lseek_dev(DEVICE *dev, off_t offset, int whence) { + int pos, openmode; + + if (dev->num_parts == 0) { /* If there is only one part, simply call lseek. */ + return lseek(dev->fd, offset, whence); + } + + switch(whence) { + case SEEK_SET: + Dmsg1(100, "lseek_dev SEEK_SET called %d\n", offset); + if ((uint64_t)offset >= dev->part_start) { + if ((uint64_t)(offset - dev->part_start) < dev->part_size) { + /* We are staying in the current part, just seek */ + if ((pos = lseek(dev->fd, (off_t)(offset-dev->part_start), SEEK_SET)) < 0) { + return pos; + } + else { + return pos + dev->part_start; + } + } + else { + /* Load next part, and start again */ + if (open_next_part(dev) < 0) { + Dmsg0(100, "lseek_dev failed while trying to open the next part\n"); + return -1; + } + return lseek_dev(dev, offset, SEEK_SET); + } + } + else { + /* pos < dev->part_start : + * We need to access a previous part, + * so just load the first one, and seek again + * until the right one is loaded */ + if (open_first_part(dev) < 0) { + Dmsg0(100, "lseek_dev failed while trying to open the first part\n"); + return -1; + } + return lseek_dev(dev, offset, SEEK_SET); + } + break; + case SEEK_CUR: + Dmsg1(100, "lseek_dev SEEK_CUR called %d\n", offset); + if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) { + return pos; + } + pos += dev->part_start; + if (offset == 0) { + return pos; + } + else { /* Not used in Bacula, but should work */ + return lseek_dev(dev, pos, SEEK_SET); + } + break; + case SEEK_END: + Dmsg1(100, "lseek_dev SEEK_END called %d\n", offset); + if (offset > 0) { /* Not used by bacula */ + Dmsg1(100, "lseek_dev SEEK_END called with an invalid offset %d\n", offset); + errno = EINVAL; + return -1; + } + + if (dev->part == dev->num_parts) { /* The right part is already loaded */ + if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) { + return pos; + } + else { + return pos + dev->part_start; + } + } + else { + /* Load the first part, then load the next until we reach the last one. + * This is the only way to be sure we compute the right file address. */ + /* Save previous openmode, and open all but last part read-only (useful for DVDs) */ + openmode = dev->openmode; + dev->openmode = OPEN_READ_ONLY; + + /* Works because num_parts > 0. */ + if (open_first_part(dev) < 0) { + Dmsg0(100, "lseek_dev failed while trying to open the first part\n"); + return -1; + } + while (dev->part < (dev->num_parts-1)) { + if (open_next_part(dev) < 0) { + Dmsg0(100, "lseek_dev failed while trying to open the next part\n"); + return -1; + } + } + dev->openmode = openmode; + if (open_next_part(dev) < 0) { + Dmsg0(100, "lseek_dev failed while trying to open the next part\n"); + return -1; + } + return lseek_dev(dev, 0, SEEK_END); + } + break; + default: + errno = EINVAL; + return -1; + } +} /* * Rewind the device. @@ -395,24 +1075,24 @@ bool rewind_dev(DEVICE *dev) berrno be; clrerror_dev(dev, MTREW); if (i == dev->max_rewind_wait) { - Dmsg1(200, "Rewind error, %s. retrying ...\n", be.strerror()); + Dmsg1(200, "Rewind error, %s. retrying ...\n", be.strerror()); } if (dev->dev_errno == EIO && i > 0) { - Dmsg0(200, "Sleeping 5 seconds.\n"); + Dmsg0(200, "Sleeping 5 seconds.\n"); bmicrosleep(5, 0); continue; } - Mmsg2(&dev->errmsg, _("Rewind error on %s. ERR=%s.\n"), + Mmsg2(&dev->errmsg, _("Rewind error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); return false; } break; } - } else if (dev->state & ST_FILE) { - if (lseek(dev->fd, (off_t)0, SEEK_SET) < 0) { + } else if (dev->state & ST_FILE) { + if (lseek_dev(dev, (off_t)0, SEEK_SET) < 0) { berrno be; dev->dev_errno = errno; - Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"), + Mmsg2(&dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); return false; } @@ -445,7 +1125,7 @@ eod_dev(DEVICE *dev) return 1; } if (!(dev->state & ST_TAPE)) { - pos = lseek(dev->fd, (off_t)0, SEEK_END); + pos = lseek_dev(dev, (off_t)0, SEEK_END); // Dmsg1(100, "====== Seek to %lld\n", pos); if (pos >= 0) { update_pos_dev(dev); @@ -454,7 +1134,7 @@ eod_dev(DEVICE *dev) } dev->dev_errno = errno; berrno be; - Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"), + Mmsg2(&dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); return 0; } @@ -481,7 +1161,7 @@ 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)) { - Dmsg0(100,"Using EOM for EOM\n"); + Dmsg0(100,"Using EOM for EOM\n"); mt_com.mt_op = MTEOM; mt_com.mt_count = 1; } @@ -489,9 +1169,9 @@ eod_dev(DEVICE *dev) if ((stat=ioctl(dev->fd, MTIOCTOP, (char *)&mt_com)) < 0) { berrno be; clrerror_dev(dev, mt_com.mt_op); - Dmsg1(50, "ioctl error: %s\n", be.strerror()); + Dmsg1(50, "ioctl error: %s\n", be.strerror()); update_pos_dev(dev); - Mmsg2(&dev->errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"), + Mmsg2(&dev->errmsg, _("ioctl MTEOM error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); return 0; } @@ -499,7 +1179,7 @@ eod_dev(DEVICE *dev) if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) { berrno be; clrerror_dev(dev, -1); - Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), + Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); return 0; } @@ -521,9 +1201,9 @@ eod_dev(DEVICE *dev) */ int file_num; for (file_num=dev->file; !(dev->state & ST_EOT); file_num++) { - Dmsg0(200, "eod_dev: doing fsf 1\n"); + Dmsg0(200, "eod_dev: doing fsf 1\n"); if (!fsf_dev(dev, 1)) { - Dmsg0(200, "fsf_dev error.\n"); + Dmsg0(200, "fsf_dev error.\n"); return 0; } /* @@ -532,10 +1212,10 @@ eod_dev(DEVICE *dev) */ if (file_num == (int)dev->file) { struct mtget mt_stat; - Dmsg1(100, "fsf_dev did not advance from file %d\n", file_num); + Dmsg1(100, "fsf_dev did not advance from file %d\n", file_num); if (dev_cap(dev, CAP_MTIOCGET) && ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno >= 0) { - Dmsg2(100, "Adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno); + Dmsg2(100, "Adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno); dev->file = mt_stat.mt_fileno; } stat = 0; @@ -554,7 +1234,7 @@ eod_dev(DEVICE *dev) stat = bsf_dev(dev, 1); /* If BSF worked and fileno is known (not -1), set file */ if (dev_cap(dev, CAP_MTIOCGET) && ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno >= 0) { - Dmsg2(100, "BSFATEOF adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno); + Dmsg2(100, "BSFATEOF adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno); dev->file = mt_stat.mt_fileno; } else { dev->file++; /* wing it -- not correct on all OSes */ @@ -589,12 +1269,12 @@ bool update_pos_dev(DEVICE *dev) if (dev->state & ST_FILE) { dev->file = 0; dev->file_addr = 0; - pos = lseek(dev->fd, (off_t)0, SEEK_CUR); + pos = lseek_dev(dev, (off_t)0, SEEK_CUR); if (pos < 0) { berrno be; dev->dev_errno = errno; - Pmsg1(000, "Seek error: ERR=%s\n", be.strerror()); - Mmsg2(&dev->errmsg, _("lseek error on %s. ERR=%s.\n"), + Pmsg1(000, "Seek error: ERR=%s\n", be.strerror()); + Mmsg2(&dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); ok = false; } else { @@ -634,7 +1314,7 @@ uint32_t status_dev(DEVICE *dev) if (ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) { berrno be; dev->dev_errno = errno; - Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), + Mmsg2(&dev->errmsg, _("ioctl MTIOCGET error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); return 0; } @@ -643,45 +1323,45 @@ uint32_t status_dev(DEVICE *dev) #if defined(HAVE_LINUX_OS) if (GMT_EOF(mt_stat.mt_gstat)) { stat |= BMT_EOF; - Dmsg0(-20, " EOF"); + Dmsg0(-20, " EOF"); } if (GMT_BOT(mt_stat.mt_gstat)) { stat |= BMT_BOT; - Dmsg0(-20, " BOT"); + Dmsg0(-20, " BOT"); } if (GMT_EOT(mt_stat.mt_gstat)) { stat |= BMT_EOT; - Dmsg0(-20, " EOT"); + Dmsg0(-20, " EOT"); } if (GMT_SM(mt_stat.mt_gstat)) { stat |= BMT_SM; - Dmsg0(-20, " SM"); + Dmsg0(-20, " SM"); } if (GMT_EOD(mt_stat.mt_gstat)) { stat |= BMT_EOD; - Dmsg0(-20, " EOD"); + Dmsg0(-20, " EOD"); } if (GMT_WR_PROT(mt_stat.mt_gstat)) { stat |= BMT_WR_PROT; - Dmsg0(-20, " WR_PROT"); + Dmsg0(-20, " WR_PROT"); } if (GMT_ONLINE(mt_stat.mt_gstat)) { stat |= BMT_ONLINE; - Dmsg0(-20, " ONLINE"); + Dmsg0(-20, " ONLINE"); } if (GMT_DR_OPEN(mt_stat.mt_gstat)) { stat |= BMT_DR_OPEN; - Dmsg0(-20, " DR_OPEN"); + Dmsg0(-20, " DR_OPEN"); } if (GMT_IM_REP_EN(mt_stat.mt_gstat)) { stat |= BMT_IM_REP_EN; - Dmsg0(-20, " IM_REP_EN"); + Dmsg0(-20, " IM_REP_EN"); } #endif /* !SunOS && !OSF */ if (dev_cap(dev, CAP_MTIOCGET)) { - Dmsg2(-20, " file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno); + Dmsg2(-20, " file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno); } else { - Dmsg2(-20, " file=%d block=%d\n", -1, -1); + Dmsg2(-20, " file=%d block=%d\n", -1, -1); } } else { stat |= BMT_ONLINE | BMT_BOT; @@ -758,6 +1438,7 @@ bool offline_dev(DEVICE *dev) dev->block_num = dev->file = 0; dev->file_size = 0; dev->file_addr = 0; + dev->part = 0; #ifdef MTUNLOCK mt_com.mt_op = MTUNLOCK; mt_com.mt_count = 1; @@ -843,11 +1524,11 @@ fsf_dev(DEVICE *dev, int num) if (stat < 0 || ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) < 0) { berrno be; dev->state |= ST_EOT; - Dmsg0(200, "Set ST_EOT\n"); + Dmsg0(200, "Set ST_EOT\n"); clrerror_dev(dev, MTFSF); - Mmsg2(dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), + Mmsg2(dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); - Dmsg1(200, "%s", dev->errmsg); + Dmsg1(200, "%s", dev->errmsg); return false; } Dmsg2(200, "fsf file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno); @@ -877,7 +1558,7 @@ fsf_dev(DEVICE *dev, int num) mt_com.mt_op = MTFSF; mt_com.mt_count = 1; while (num-- && !(dev->state & ST_EOT)) { - Dmsg0(100, "Doing read before fsf\n"); + Dmsg0(100, "Doing read before fsf\n"); if ((stat = read(dev->fd, (char *)rbuf, rbuf_len)) < 0) { if (errno == ENOMEM) { /* tape record exceeds buf len */ stat = rbuf_len; /* This is OK */ @@ -885,21 +1566,21 @@ fsf_dev(DEVICE *dev, int num) berrno be; dev->state |= ST_EOT; clrerror_dev(dev, -1); - Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev->dev_errno, + Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev->dev_errno, be.strerror()); - Mmsg2(dev->errmsg, _("read error on %s. ERR=%s.\n"), + Mmsg2(dev->errmsg, _("read error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); - Dmsg1(100, "%s", dev->errmsg); + Dmsg1(100, "%s", dev->errmsg); break; } } if (stat == 0) { /* EOF */ update_pos_dev(dev); - Dmsg1(100, "End of File mark from read. File=%d\n", dev->file+1); + Dmsg1(100, "End of File mark from read. File=%d\n", dev->file+1); /* Two reads of zero means end of tape */ if (dev->state & ST_EOF) { dev->state |= ST_EOT; - Dmsg0(100, "Set ST_EOT\n"); + Dmsg0(100, "Set ST_EOT\n"); break; } else { dev->state |= ST_EOF; @@ -912,17 +1593,17 @@ fsf_dev(DEVICE *dev, int num) dev->state &= ~(ST_EOF|ST_EOT); } - Dmsg0(100, "Doing MTFSF\n"); + Dmsg0(100, "Doing MTFSF\n"); stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com); if (stat < 0) { /* error => EOT */ berrno be; dev->state |= ST_EOT; - Dmsg0(100, "Set ST_EOT\n"); + Dmsg0(100, "Set ST_EOT\n"); clrerror_dev(dev, MTFSF); - Mmsg2(&dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), + Mmsg2(&dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); - Dmsg0(100, "Got < 0 for MTFSF\n"); - Dmsg1(100, "%s", dev->errmsg); + Dmsg0(100, "Got < 0 for MTFSF\n"); + Dmsg1(100, "%s", dev->errmsg); } else { dev->state |= ST_EOF; /* just read EOF */ dev->file++; @@ -942,7 +1623,7 @@ fsf_dev(DEVICE *dev, int num) } if (dev->state & ST_EOT) { dev->dev_errno = 0; - Mmsg1(dev->errmsg, _("Device %s at End of Tape.\n"), dev->dev_name); + Mmsg1(dev->errmsg, _("Device %s at End of Tape.\n"), dev->dev_name); stat = -1; } else { stat = 0; @@ -1039,7 +1720,7 @@ fsr_dev(DEVICE *dev, int num) clrerror_dev(dev, MTFSR); Dmsg1(100, "FSF fail: ERR=%s\n", be.strerror()); if (dev_cap(dev, CAP_MTIOCGET) && ioctl(dev->fd, MTIOCGET, (char *)&mt_stat) == 0 && mt_stat.mt_fileno >= 0) { - Dmsg4(100, "Adjust from %d:%d to %d:%d\n", dev->file, + Dmsg4(100, "Adjust from %d:%d to %d:%d\n", dev->file, dev->block_num, mt_stat.mt_fileno, mt_stat.mt_blkno); dev->file = mt_stat.mt_fileno; dev->block_num = mt_stat.mt_blkno; @@ -1121,11 +1802,11 @@ reposition_dev(DEVICE *dev, uint32_t file, uint32_t block) if (!(dev_state(dev, ST_TAPE))) { off_t pos = (((off_t)file)<<32) + block; - Dmsg1(100, "===== lseek to %d\n", (int)pos); - if (lseek(dev->fd, pos, SEEK_SET) == (off_t)-1) { + Dmsg1(100, "===== lseek_dev to %d\n", (int)pos); + if (lseek_dev(dev, pos, SEEK_SET) == (off_t)-1) { berrno be; dev->dev_errno = errno; - Mmsg2(dev->errmsg, _("lseek error on %s. ERR=%s.\n"), + Mmsg2(dev->errmsg, _("lseek_dev error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); return false; } @@ -1145,7 +1826,7 @@ reposition_dev(DEVICE *dev, uint32_t file, uint32_t block) if (file > dev->file) { Dmsg1(100, "fsf %d\n", file-dev->file); if (!fsf_dev(dev, file-dev->file)) { - Dmsg1(100, "fsf failed! ERR=%s\n", strerror_dev(dev)); + Dmsg1(100, "fsf failed! ERR=%s\n", strerror_dev(dev)); return false; } Dmsg2(100, "wanted_file=%d at_file=%d\n", file, dev->file); @@ -1178,7 +1859,8 @@ weof_dev(DEVICE *dev, int num) { struct mtop mt_com; int stat; - + Dmsg0(29, "weof_dev\n"); + if (dev->fd < 0) { dev->dev_errno = EBADF; Mmsg0(dev->errmsg, _("Bad call to weof_dev. Archive drive not open\n")); @@ -1191,7 +1873,6 @@ weof_dev(DEVICE *dev, int num) return 0; } dev->state &= ~(ST_EOT | ST_EOF); /* remove EOF/EOT flags */ - Dmsg0(29, "weof_dev\n"); mt_com.mt_op = MTWEOF; mt_com.mt_count = num; stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com); @@ -1203,7 +1884,7 @@ weof_dev(DEVICE *dev, int num) berrno be; clrerror_dev(dev, MTWEOF); if (stat == -1) { - Mmsg2(dev->errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"), + Mmsg2(dev->errmsg, _("ioctl MTWEOF error on %s. ERR=%s.\n"), dev->dev_name, be.strerror()); } } @@ -1244,41 +1925,41 @@ clrerror_dev(DEVICE *dev, int func) if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */ switch (func) { case -1: - Emsg0(M_ABORT, 0, "Got ENOTTY on read/write!\n"); + Emsg0(M_ABORT, 0, "Got ENOTTY on read/write!\n"); break; case MTWEOF: - msg = "WTWEOF"; + msg = "WTWEOF"; dev->capabilities &= ~CAP_EOF; /* turn off feature */ break; #ifdef MTEOM case MTEOM: - msg = "WTEOM"; + msg = "WTEOM"; dev->capabilities &= ~CAP_EOM; /* turn off feature */ break; #endif case MTFSF: - msg = "MTFSF"; + msg = "MTFSF"; dev->capabilities &= ~CAP_FSF; /* turn off feature */ break; case MTBSF: - msg = "MTBSF"; + msg = "MTBSF"; dev->capabilities &= ~CAP_BSF; /* turn off feature */ break; case MTFSR: - msg = "MTFSR"; + msg = "MTFSR"; dev->capabilities &= ~CAP_FSR; /* turn off feature */ break; case MTBSR: - msg = "MTBSR"; + msg = "MTBSR"; dev->capabilities &= ~CAP_BSR; /* turn off feature */ break; default: - msg = "Unknown"; + msg = "Unknown"; break; } if (msg != NULL) { dev->dev_errno = ENOSYS; - Mmsg1(&dev->errmsg, _("This device does not support %s.\n"), msg); + Mmsg1(&dev->errmsg, _("This device does not support %s.\n"), msg); Emsg0(M_ERROR, 0, dev->errmsg); } } @@ -1337,12 +2018,33 @@ static void do_close(DEVICE *dev) if (dev->fd >= 0) { close(dev->fd); } + if (dev_cap(dev, CAP_REQMOUNT)) { + if (unmount_dev(dev, 1) < 0) { + Dmsg1(0, "Cannot unmount device %s.\n", dev->dev_name); + } + } + + /* Remove the last part file if it is empty */ + if ((dev->state & ST_APPEND) && (dev->num_parts > 0)) { + struct stat statp; + POOL_MEM archive_name(PM_FNAME); + dev->part = dev->num_parts; + get_filename(dev, dev->VolCatInfo.VolCatName, archive_name); + /* Check that the part file is empty */ + if ((stat(archive_name.c_str(), &statp) == 0) && (statp.st_size == 0)) { + unlink(archive_name.c_str()); + } + } + /* Clean up device packet so it can be reused */ dev->fd = -1; dev->state &= ~(ST_OPENED|ST_LABEL|ST_READ|ST_APPEND|ST_EOT|ST_WEOT|ST_EOF); dev->file = dev->block_num = 0; dev->file_size = 0; dev->file_addr = 0; + dev->part = 0; + dev->part_size = 0; + dev->part_start = 0; dev->EndFile = dev->EndBlock = 0; memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo)); memset(&dev->VolHdr, 0, sizeof(dev->VolHdr)); @@ -1364,7 +2066,11 @@ close_dev(DEVICE *dev) Emsg0(M_FATAL, 0, dev->errmsg); return; } - if (dev->fd >= 0 && dev->use_count == 1) { + /*if (dev->fd >= 0 && dev->use_count == 1) {*/ + /* No need to check if dev->fd >= 0: it is checked again + * in do_close, and do_close MUST be called for volumes + * splitted in parts, even if dev->fd == -1. */ + if (dev->use_count == 1) { do_close(dev); } else if (dev->use_count > 0) { dev->use_count--; @@ -1395,10 +2101,22 @@ void force_close_dev(DEVICE *dev) bool truncate_dev(DEVICE *dev) { + Dmsg1(100, "truncate_dev %s\n", dev->dev_name); if (dev->state & ST_TAPE) { return true; /* we don't really truncate tapes */ /* maybe we should rewind and write and eof ???? */ } + + /* If there is more than one part, open the first one, and then truncate it. */ + if (dev->num_parts > 0) { + dev->num_parts = 0; + dev->VolCatInfo.VolCatParts = 0; + if (open_first_part(dev) < 0) { + berrno be; + Mmsg1(&dev->errmsg, "Unable to truncate device, because I'm unable to open the first part. ERR=%s\n", be.strerror()); + } + } + if (ftruncate(dev->fd, 0) != 0) { berrno be; Mmsg1(&dev->errmsg, _("Unable to truncate device. ERR=%s\n"), be.strerror()); @@ -1596,3 +2314,63 @@ void set_os_device_parameters(DEVICE *dev) return; #endif } + +/* + * Edit codes into (Un)MountCommand, Write(First)PartCommand + * %% = % + * %a = archive device name + * %m = mount point + * %v = last part name + * + * omsg = edited output message + * imsg = input string containing edit codes (%x) + * + */ +char *edit_device_codes_dev(DEVICE* dev, char *omsg, const char *imsg) +{ + const char *p; + const char *str; + char add[20]; + + POOL_MEM archive_name(PM_FNAME); + get_filename(dev, dev->VolCatInfo.VolCatName, archive_name); + + *omsg = 0; + Dmsg1(800, "edit_device_codes: %s\n", imsg); + for (p=imsg; *p; p++) { + if (*p == '%') { + switch (*++p) { + case '%': + str = "%"; + break; + case 'n': + bsnprintf(add, sizeof(add), "%d", dev->part); + str = add; + break; + case 'a': + str = dev->dev_name; + break; + case 'm': + str = dev->device->mount_point; + break; + case 'v': + 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(900, "add_str %s\n", str); + pm_strcat(&omsg, (char *)str); + Dmsg1(800, "omsg=%s\n", omsg); + } + return omsg; +} diff --git a/bacula/src/stored/dev.h b/bacula/src/stored/dev.h index bca2c42694..181398c630 100644 --- a/bacula/src/stored/dev.h +++ b/bacula/src/stored/dev.h @@ -8,7 +8,7 @@ * */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -31,13 +31,13 @@ #ifndef __DEV_H #define __DEV_H 1 -#undef DCR /* used by Bacula */ +#undef DCR /* used by Bacula */ /* #define NEW_LOCK 1 */ -#define new_lock_device(dev) _new_lock_device(__FILE__, __LINE__, (dev)) +#define new_lock_device(dev) _new_lock_device(__FILE__, __LINE__, (dev)) #define new_lock_device_state(dev,state) _new_lock_device(__FILE__, __LINE__, (dev), (state)) -#define new_unlock_device(dev) _new_unlock_device(__FILE__, __LINE__, (dev)) +#define new_unlock_device(dev) _new_unlock_device(__FILE__, __LINE__, (dev)) #define lock_device(d) _lock_device(__FILE__, __LINE__, (d)) #define unlock_device(d) _unlock_device(__FILE__, __LINE__, (d)) @@ -54,109 +54,112 @@ enum { }; /* Generic status bits returned from status_dev() */ -#define BMT_TAPE (1<<0) /* is tape device */ -#define BMT_EOF (1<<1) /* just read EOF */ -#define BMT_BOT (1<<2) /* at beginning of tape */ -#define BMT_EOT (1<<3) /* end of tape reached */ -#define BMT_SM (1<<4) /* DDS setmark */ -#define BMT_EOD (1<<5) /* DDS at end of data */ -#define BMT_WR_PROT (1<<6) /* tape write protected */ -#define BMT_ONLINE (1<<7) /* tape online */ -#define BMT_DR_OPEN (1<<8) /* tape door open */ -#define BMT_IM_REP_EN (1<<9) /* immediate report enabled */ +#define BMT_TAPE (1<<0) /* is tape device */ +#define BMT_EOF (1<<1) /* just read EOF */ +#define BMT_BOT (1<<2) /* at beginning of tape */ +#define BMT_EOT (1<<3) /* end of tape reached */ +#define BMT_SM (1<<4) /* DDS setmark */ +#define BMT_EOD (1<<5) /* DDS at end of data */ +#define BMT_WR_PROT (1<<6) /* tape write protected */ +#define BMT_ONLINE (1<<7) /* tape online */ +#define BMT_DR_OPEN (1<<8) /* tape door open */ +#define BMT_IM_REP_EN (1<<9) /* immediate report enabled */ /* Test capabilities */ #define dev_cap(dev, cap) ((dev)->capabilities & (cap)) /* Bits for device capabilities */ -#define CAP_EOF (1<<0) /* has MTWEOF */ -#define CAP_BSR (1<<1) /* has MTBSR */ -#define CAP_BSF (1<<2) /* has MTBSF */ -#define CAP_FSR (1<<3) /* has MTFSR */ -#define CAP_FSF (1<<4) /* has MTFSF */ -#define CAP_EOM (1<<5) /* has MTEOM */ -#define CAP_REM (1<<6) /* is removable media */ -#define CAP_RACCESS (1<<7) /* is random access device */ -#define CAP_AUTOMOUNT (1<<8) /* Read device at start to see what is there */ -#define CAP_LABEL (1<<9) /* Label blank tapes */ -#define CAP_ANONVOLS (1<<10) /* Mount without knowing volume name */ -#define CAP_ALWAYSOPEN (1<<11) /* always keep device open */ +#define CAP_EOF (1<<0) /* has MTWEOF */ +#define CAP_BSR (1<<1) /* has MTBSR */ +#define CAP_BSF (1<<2) /* has MTBSF */ +#define CAP_FSR (1<<3) /* has MTFSR */ +#define CAP_FSF (1<<4) /* has MTFSF */ +#define CAP_EOM (1<<5) /* has MTEOM */ +#define CAP_REM (1<<6) /* is removable media */ +#define CAP_RACCESS (1<<7) /* is random access device */ +#define CAP_AUTOMOUNT (1<<8) /* Read device at start to see what is there */ +#define CAP_LABEL (1<<9) /* Label blank tapes */ +#define CAP_ANONVOLS (1<<10) /* Mount without knowing volume name */ +#define CAP_ALWAYSOPEN (1<<11) /* always keep device open */ #define CAP_AUTOCHANGER (1<<12) /* AutoChanger */ #define CAP_OFFLINEUNMOUNT (1<<13) /* Offline before unmount */ -#define CAP_STREAM (1<<14) /* Stream device */ -#define CAP_BSFATEOM (1<<15) /* Backspace file at EOM */ -#define CAP_FASTFSF (1<<16) /* Fast forward space file */ -#define CAP_TWOEOF (1<<17) /* Write two eofs for EOM */ +#define CAP_STREAM (1<<14) /* Stream device */ +#define CAP_BSFATEOM (1<<15) /* Backspace file at EOM */ +#define CAP_FASTFSF (1<<16) /* Fast forward space file */ +#define CAP_TWOEOF (1<<17) /* Write two eofs for EOM */ #define CAP_CLOSEONPOLL (1<<18) /* Close device on polling */ #define CAP_POSITIONBLOCKS (1<<19) /* Use block positioning */ -#define CAP_MTIOCGET (1<<20) /* Basic support for fileno and blkno */ +#define CAP_MTIOCGET (1<<20) /* Basic support for fileno and blkno */ +#define CAP_REQMOUNT (1<<21) /* Require mount to read files back (typically: DVD) */ /* Test state */ #define dev_state(dev, st_state) ((dev)->state & (st_state)) /* Device state bits */ -#define ST_OPENED (1<<0) /* set when device 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_PROG (1<<4) /* is a program device */ -#define ST_LABEL (1<<5) /* label found */ +#define ST_OPENED (1<<0) /* set when device 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_PROG (1<<4) /* is a program device */ +#define ST_LABEL (1<<5) /* label found */ #define ST_MALLOC (1<<6) /* dev packet malloc'ed in init_dev() */ -#define ST_APPEND (1<<7) /* ready for Bacula append */ -#define ST_READ (1<<8) /* ready for Bacula read */ -#define ST_EOT (1<<9) /* at end of tape */ -#define ST_WEOT (1<<10) /* Got EOT on write */ -#define ST_EOF (1<<11) /* Read EOF i.e. zero bytes */ -#define ST_NEXTVOL (1<<12) /* Start writing on next volume */ -#define ST_SHORT (1<<13) /* Short block read */ +#define ST_APPEND (1<<7) /* ready for Bacula append */ +#define ST_READ (1<<8) /* ready for Bacula read */ +#define ST_EOT (1<<9) /* at end of tape */ +#define ST_WEOT (1<<10) /* Got EOT on write */ +#define ST_EOF (1<<11) /* Read EOF i.e. zero bytes */ +#define ST_NEXTVOL (1<<12) /* Start writing on next volume */ +#define ST_SHORT (1<<13) /* Short block read */ +#define ST_MOUNTED (1<<14) /* the device is mounted to the mount point */ /* dev_blocked states (mutually exclusive) */ enum { - BST_NOT_BLOCKED = 0, /* not blocked */ - BST_UNMOUNTED, /* User unmounted device */ - BST_WAITING_FOR_SYSOP, /* Waiting for operator to mount tape */ - BST_DOING_ACQUIRE, /* Opening/validating/moving tape */ - BST_WRITING_LABEL, /* Labeling a tape */ + BST_NOT_BLOCKED = 0, /* not blocked */ + BST_UNMOUNTED, /* User unmounted device */ + BST_WAITING_FOR_SYSOP, /* Waiting for operator to mount tape */ + BST_DOING_ACQUIRE, /* Opening/validating/moving tape */ + BST_WRITING_LABEL, /* Labeling a tape */ BST_UNMOUNTED_WAITING_FOR_SYSOP, /* Closed by user during mount request */ - BST_MOUNT /* Mount request */ + BST_MOUNT /* Mount request */ }; /* Volume Catalog Information structure definition */ struct VOLUME_CAT_INFO { /* Media info for the current Volume */ - uint32_t VolCatJobs; /* number of jobs on this Volume */ - uint32_t VolCatFiles; /* Number of files */ - uint32_t VolCatBlocks; /* Number of blocks */ - uint64_t VolCatBytes; /* Number of bytes written */ - uint32_t VolCatMounts; /* Number of mounts this volume */ - uint32_t VolCatErrors; /* Number of errors this volume */ - uint32_t VolCatWrites; /* Number of writes this volume */ - uint32_t VolCatReads; /* Number of reads this volume */ - uint64_t VolCatRBytes; /* Number of bytes read */ - uint32_t VolCatRecycles; /* Number of recycles this volume */ - uint32_t EndFile; /* Last file number */ - uint32_t EndBlock; /* Last block number */ - int32_t Slot; /* Slot in changer */ - bool InChanger; /* Set if vol in current magazine */ - uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */ - uint32_t VolCatMaxFiles; /* Maximum files to write to volume */ - uint64_t VolCatMaxBytes; /* Max bytes to write to volume */ + uint32_t VolCatJobs; /* number of jobs on this Volume */ + uint32_t VolCatFiles; /* Number of files */ + uint32_t VolCatBlocks; /* Number of blocks */ + uint64_t VolCatBytes; /* Number of bytes written */ + uint32_t VolCatParts; /* Number of parts written */ + uint32_t VolCatMounts; /* Number of mounts this volume */ + uint32_t VolCatErrors; /* Number of errors this volume */ + uint32_t VolCatWrites; /* Number of writes this volume */ + uint32_t VolCatReads; /* Number of reads this volume */ + uint64_t VolCatRBytes; /* Number of bytes read */ + uint32_t VolCatRecycles; /* Number of recycles this volume */ + uint32_t EndFile; /* Last file number */ + uint32_t EndBlock; /* Last block number */ + int32_t Slot; /* Slot in changer */ + bool InChanger; /* Set if vol in current magazine */ + uint32_t VolCatMaxJobs; /* Maximum Jobs to write to volume */ + uint32_t VolCatMaxFiles; /* Maximum files to write to volume */ + uint64_t VolCatMaxBytes; /* Max bytes to write to volume */ uint64_t VolCatCapacityBytes; /* capacity estimate */ - uint64_t VolReadTime; /* time spent reading */ - uint64_t VolWriteTime; /* time spent writing this Volume */ - char VolCatStatus[20]; /* Volume status */ + uint64_t VolReadTime; /* time spent reading */ + uint64_t VolWriteTime; /* time spent writing this Volume */ + char VolCatStatus[20]; /* Volume status */ char VolCatName[MAX_NAME_LENGTH]; /* Desired volume to mount */ }; typedef struct s_steal_lock { - pthread_t no_wait_id; /* id of no wait thread */ - int dev_blocked; /* state */ - int dev_prev_blocked; /* previous blocked state */ + pthread_t no_wait_id; /* id of no wait thread */ + int dev_blocked; /* state */ + int dev_prev_blocked; /* previous blocked state */ } bsteal_lock_t; -struct DEVRES; /* Device resource defined in stored_conf.h */ +struct DEVRES; /* Device resource defined in stored_conf.h */ /* * Device structure definition. There is one of these for @@ -165,58 +168,71 @@ struct DEVRES; /* Device resource defined in stored_conf. */ struct DEVICE { public: - DEVICE *next; /* pointer to next open device */ - DEVICE *prev; /* pointer to prev open device */ - JCR *attached_jcrs; /* attached JCR list */ - dlist *attached_dcrs; /* attached DCR list */ - pthread_mutex_t mutex; /* access control */ + DEVICE *next; /* pointer to next open device */ + DEVICE *prev; /* pointer to prev open device */ + JCR *attached_jcrs; /* attached JCR list */ + dlist *attached_dcrs; /* attached DCR list */ + pthread_mutex_t mutex; /* access control */ pthread_mutex_t spool_mutex; /* mutex for updating spool_size */ - pthread_cond_t wait; /* thread wait variable */ + pthread_cond_t wait; /* thread wait variable */ pthread_cond_t wait_next_vol; /* wait for tape to be mounted */ - pthread_t no_wait_id; /* this thread must not wait */ - int dev_blocked; /* set if we must wait (i.e. change tape) */ - int dev_prev_blocked; /* previous blocked state */ - int num_waiting; /* number of threads waiting */ - int num_writers; /* number of writing threads */ + pthread_t no_wait_id; /* this thread must not wait */ + int dev_blocked; /* set if we must wait (i.e. change tape) */ + int dev_prev_blocked; /* previous blocked state */ + int num_waiting; /* number of threads waiting */ + int num_writers; /* number of writing threads */ /* New access control in process of being implemented */ - brwlock_t lock; /* New mutual exclusion lock */ + brwlock_t lock; /* New mutual exclusion lock */ - int use_count; /* usage count on this device */ - int fd; /* file descriptor */ - int capabilities; /* capabilities mask */ - int state; /* state mask */ - int dev_errno; /* Our own errno */ - int mode; /* read/write modes */ - uint32_t drive_index; /* Autochanger drive index */ - POOLMEM *dev_name; /* device name */ - char *errmsg; /* nicely edited error message */ - uint32_t block_num; /* current block number base 0 */ - uint32_t file; /* current file number base 0 */ - uint64_t file_addr; /* Current file read/write address */ - uint64_t file_size; /* Current file size */ - uint32_t EndBlock; /* last block written */ - uint32_t EndFile; /* last file written */ - uint32_t min_block_size; /* min block size */ - uint32_t max_block_size; /* max block size */ - uint64_t max_volume_size; /* max bytes to put on one volume */ - uint64_t max_file_size; /* max file size to put in one file on volume */ - uint64_t volume_capacity; /* advisory capacity */ - uint64_t max_spool_size; /* maximum spool file size */ - uint64_t spool_size; /* curren spool size */ - uint32_t max_rewind_wait; /* max secs to allow for rewind */ - uint32_t max_open_wait; /* max secs to allow for open */ - uint32_t max_open_vols; /* max simultaneous open volumes */ - utime_t vol_poll_interval; /* interval between polling Vol mount */ - DEVRES *device; /* pointer to Device Resource */ - btimer_t *tid; /* timer id */ + int use_count; /* usage count on this device */ + int fd; /* file descriptor */ + int capabilities; /* capabilities mask */ + int state; /* state mask */ + int dev_errno; /* Our own errno */ + int mode; /* read/write modes */ + int openmode; /* parameter passed to open_dev (useful to reopen the device) */ + uint32_t drive_index; /* Autochanger drive index */ + POOLMEM *dev_name; /* device name */ + char *errmsg; /* nicely edited error message */ + uint32_t block_num; /* current block number base 0 */ + uint32_t file; /* current file number base 0 */ + uint64_t file_addr; /* Current file read/write address */ + uint64_t file_size; /* Current file size */ + uint32_t EndBlock; /* last block written */ + uint32_t EndFile; /* last file written */ + uint32_t min_block_size; /* min block size */ + uint32_t max_block_size; /* max block size */ + uint64_t max_volume_size; /* max bytes to put on one volume */ + uint64_t max_file_size; /* max file size to put in one file on volume */ + uint64_t volume_capacity; /* advisory capacity */ + uint64_t max_spool_size; /* maximum spool file size */ + uint64_t spool_size; /* current spool size */ + uint32_t max_rewind_wait; /* max secs to allow for rewind */ + uint32_t max_open_wait; /* max secs to allow for open */ + uint32_t max_open_vols; /* max simultaneous open volumes */ + + uint64_t max_part_size; /* max part size */ + uint64_t part_size; /* current part size */ + uint32_t part; /* current part number */ + uint64_t part_start; /* current part start address (relative to the whole volume) */ + uint32_t num_parts; /* number of parts (total) */ + uint64_t free_space; /* current free space on medium (without the current part) */ + int free_space_errno; /* indicates: + * - free_space_errno == 0: ignore free_space. + * - free_space_errno < 0: an error occured. + * - free_space_errno > 0: free_space is valid. */ + + utime_t vol_poll_interval; /* interval between polling Vol mount */ + DEVRES *device; /* pointer to Device Resource */ + btimer_t *tid; /* timer id */ - VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */ - VOLUME_LABEL VolHdr; /* Actual volume label */ + VOLUME_CAT_INFO VolCatInfo; /* Volume Catalog Information */ + VOLUME_LABEL VolHdr; /* Actual volume label */ /* Device wait times ***FIXME*** look at durations */ char BadVolName[MAX_NAME_LENGTH]; /* Last wrong Volume mounted */ - bool poll; /* set to poll Volume */ + bool poll; /* set to poll Volume */ int min_wait; int max_wait; int max_num_wait; @@ -233,33 +249,33 @@ public: */ class DCR { public: - dlink dev_link; /* link to attach to dev */ - JCR *jcr; /* pointer to JCR */ - DEVICE *dev; /* pointer to device */ - DEV_BLOCK *block; /* pointer to block */ - DEV_RECORD *rec; /* pointer to record */ - int spool_fd; /* fd if spooling */ - bool spool_data; /* set to spool data */ - bool spooling; /* set when actually spooling */ - bool dev_locked; /* set if dev already locked */ - bool NewVol; /* set if new Volume mounted */ - bool WroteVol; /* set if Volume written */ - bool NewFile; /* set when EOF written */ - uint32_t VolFirstIndex; /* First file index this Volume */ - uint32_t VolLastIndex; /* Last file index this Volume */ - uint32_t FileIndex; /* Current File Index */ - uint32_t EndFile; /* End file written */ - uint32_t StartFile; /* Start write file */ - uint32_t StartBlock; /* Start write block */ - uint32_t EndBlock; /* Ending block written */ - int64_t spool_size; /* Current spool size */ - int64_t max_spool_size; /* Max job spool size */ + dlink dev_link; /* link to attach to dev */ + JCR *jcr; /* pointer to JCR */ + DEVICE *dev; /* pointer to device */ + DEV_BLOCK *block; /* pointer to block */ + DEV_RECORD *rec; /* pointer to record */ + int spool_fd; /* fd if spooling */ + bool spool_data; /* set to spool data */ + bool spooling; /* set when actually spooling */ + bool dev_locked; /* set if dev already locked */ + bool NewVol; /* set if new Volume mounted */ + bool WroteVol; /* set if Volume written */ + bool NewFile; /* set when EOF written */ + uint32_t VolFirstIndex; /* First file index this Volume */ + uint32_t VolLastIndex; /* Last file index this Volume */ + uint32_t FileIndex; /* Current File Index */ + uint32_t EndFile; /* End file written */ + uint32_t StartFile; /* Start write file */ + uint32_t StartBlock; /* Start write block */ + uint32_t EndBlock; /* Ending block written */ + int64_t spool_size; /* Current spool size */ + int64_t max_spool_size; /* Max job spool size */ char VolumeName[MAX_NAME_LENGTH]; /* Volume name */ char pool_name[MAX_NAME_LENGTH]; /* pool name */ char pool_type[MAX_NAME_LENGTH]; /* pool type */ char media_type[MAX_NAME_LENGTH]; /* media type */ char dev_name[MAX_NAME_LENGTH]; /* dev name */ - VOLUME_CAT_INFO VolCatInfo; /* Catalog info for desired volume */ + VOLUME_CAT_INFO VolCatInfo; /* Catalog info for desired volume */ }; @@ -268,7 +284,7 @@ public: * dependent. Arrgggg! */ #ifndef MTEOM -#ifdef MTSEOD +#ifdef MTSEOD #define MTEOM MTSEOD #endif #ifdef MTEOD diff --git a/bacula/src/stored/dircmd.c b/bacula/src/stored/dircmd.c index de9904b31a..12c67cb156 100644 --- a/bacula/src/stored/dircmd.c +++ b/bacula/src/stored/dircmd.c @@ -19,7 +19,7 @@ * */ /* - Copyright (C) 2001-2004 Kern Sibbald and John Walker + Copyright (C) 2001-2005 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 @@ -188,14 +188,14 @@ void *handle_connection_request(void *arg) for (i=0; cmds[i].cmd; i++) { if (strncmp(cmds[i].cmd, bs->msg, strlen(cmds[i].cmd)) == 0) { if ((!cmds[i].monitoraccess) && (jcr->director->monitor)) { - Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd); + Dmsg1(100, "Command %s illegal.\n", cmds[i].cmd); bnet_fsend(bs, illegal_cmd); bnet_sig(bs, BNET_EOD); break; } if (!cmds[i].func(jcr)) { /* do command */ quit = true; /* error, get out */ - Dmsg1(190, "Command %s requsts quit\n", cmds[i].cmd); + Dmsg1(190, "Command %s requsts quit\n", cmds[i].cmd); } found = true; /* indicate command found */ break; @@ -245,7 +245,7 @@ static bool cancel_cmd(JCR *cjcr) if (sscanf(dir->msg, "cancel Job=%127s", Job) == 1) { if (!(jcr=get_jcr_by_full_name(Job))) { - bnet_fsend(dir, _("3992 Job %s not found.\n"), Job); + bnet_fsend(dir, _("3992 Job %s not found.\n"), Job); } else { P(jcr->mutex); oldStatus = jcr->JobStatus; @@ -264,7 +264,7 @@ static bool cancel_cmd(JCR *cjcr) jcr->dcr->dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP)) { pthread_cond_signal(&jcr->dcr->dev->wait_next_vol); } - bnet_fsend(dir, _("3000 Job %s marked to be canceled.\n"), jcr->Job); + bnet_fsend(dir, _("3000 Job %s marked to be canceled.\n"), jcr->Job); free_jcr(jcr); } } else { @@ -325,7 +325,7 @@ static bool do_label(JCR *jcr, int relabel) if (!(dev->state & ST_OPENED)) { label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel); force_close_dev(dev); - /* Under certain "safe" conditions, we can steal the lock */ + /* Under certain "safe" conditions, we can steal the lock */ } else if (dev->dev_blocked && (dev->dev_blocked == BST_UNMOUNTED || dev->dev_blocked == BST_WAITING_FOR_SYSOP || @@ -333,10 +333,10 @@ static bool do_label(JCR *jcr, int relabel) label_volume_if_ok(jcr, dev, oldname, newname, poolname, slot, relabel); } else if (dev_state(dev, ST_READ) || dev->num_writers) { if (dev_state(dev, ST_READ)) { - bnet_fsend(dir, _("3911 Device %s is busy with 1 reader.\n"), + bnet_fsend(dir, _("3911 Device %s is busy with 1 reader.\n"), dev_name(dev)); } else { - bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"), + bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"), dev_name(dev), dev->num_writers); } } else { /* device not being used */ @@ -344,7 +344,7 @@ static bool do_label(JCR *jcr, int relabel) } V(dev->mutex); } else { - bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); + bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); } } else { /* NB dir->msg gets clobbered in bnet_fsend, so save command */ @@ -383,6 +383,14 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, /* See what we have for a Volume */ label_status = read_dev_volume_label(dcr); + + if (dev_cap(dev, CAP_REQMOUNT)) { + label_status = read_dev_volume_label_guess(dcr, 1); + } + else { + label_status = read_dev_volume_label(dcr); + } + switch(label_status) { case VOL_NAME_ERROR: case VOL_VERSION_ERROR: @@ -390,20 +398,20 @@ static void label_volume_if_ok(JCR *jcr, DEVICE *dev, char *oldname, case VOL_OK: if (!relabel) { bnet_fsend(dir, _( - "3911 Cannot label Volume because it is already labeled: \"%s\"\n"), + "3911 Cannot label Volume because it is already labeled: \"%s\"\n"), dev->VolHdr.VolName); break; } /* Relabel request. If oldname matches, continue */ if (strcmp(oldname, dev->VolHdr.VolName) != 0) { - bnet_fsend(dir, _("Wrong volume mounted.\n")); + bnet_fsend(dir, _("Wrong volume mounted.\n")); break; } /* Fall through wanted! */ case VOL_IO_ERROR: case VOL_NO_LABEL: if (!write_new_volume_label_to_dev(dcr, newname, poolname)) { - bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev)); + bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), strerror_dev(dev)); break; } bstrncpy(dcr->VolumeName, newname, sizeof(dcr->VolumeName)); @@ -468,7 +476,7 @@ static DEVICE *find_device(JCR *jcr, POOL_MEM &dname) foreach_res(device, R_DEVICE) { /* Find resource, and make sure we were able to open it */ if (strcmp(device->hdr.name, dname.c_str()) == 0 && device->dev) { - Dmsg1(20, "Found device %s\n", device->hdr.name); + Dmsg1(20, "Found device %s\n", device->hdr.name); jcr->device = device; found = true; break; @@ -506,9 +514,9 @@ static bool mount_cmd(JCR *jcr) switch (dev->dev_blocked) { /* device blocked? */ case BST_WAITING_FOR_SYSOP: /* Someone is waiting, wake him */ - Dmsg0(100, "Waiting for mount. Attempting to wake thread\n"); + Dmsg0(100, "Waiting for mount. Attempting to wake thread\n"); dev->dev_blocked = BST_MOUNT; - bnet_fsend(dir, "3001 OK mount. Device=%s\n", dev_name(dev)); + bnet_fsend(dir, "3001 OK mount. Device=%s\n", dev_name(dev)); pthread_cond_signal(&dev->wait_next_vol); break; @@ -517,79 +525,79 @@ static bool mount_cmd(JCR *jcr) case BST_UNMOUNTED: /* We freed the device, so reopen it and wake any waiting threads */ if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) { - bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), + bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), strerror_dev(dev)); break; } read_dev_volume_label(dcr); if (dev->dev_blocked == BST_UNMOUNTED) { /* We blocked the device, so unblock it */ - Dmsg0(100, "Unmounted. Unblocking device\n"); + Dmsg0(100, "Unmounted. Unblocking device\n"); read_label(dcr); /* this should not be necessary */ unblock_device(dev); } else { - Dmsg0(100, "Unmounted waiting for mount. Attempting to wake thread\n"); + Dmsg0(100, "Unmounted waiting for mount. Attempting to wake thread\n"); dev->dev_blocked = BST_MOUNT; } if (dev_state(dev, ST_LABEL)) { - bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"), + bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"), dev_name(dev), dev->VolHdr.VolName); } else { - bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" - "If this is not a blank tape, try unmounting and remounting the Volume.\n"), + bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" + "If this is not a blank tape, try unmounting and remounting the Volume.\n"), dev_name(dev)); } pthread_cond_signal(&dev->wait_next_vol); break; case BST_DOING_ACQUIRE: - bnet_fsend(dir, _("3001 Device %s is mounted; doing acquire.\n"), + bnet_fsend(dir, _("3001 Device %s is mounted; doing acquire.\n"), dev_name(dev)); break; case BST_WRITING_LABEL: - bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), dev_name(dev)); + bnet_fsend(dir, _("3903 Device %s is being labeled.\n"), dev_name(dev)); break; case BST_NOT_BLOCKED: if (dev_state(dev, ST_OPENED)) { if (dev_state(dev, ST_LABEL)) { - bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"), + bnet_fsend(dir, _("3001 Device %s is mounted with Volume \"%s\"\n"), dev_name(dev), dev->VolHdr.VolName); } else { - bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" - "If this is not a blank tape, try unmounting and remounting the Volume.\n"), + bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" + "If this is not a blank tape, try unmounting and remounting the Volume.\n"), dev_name(dev)); } } else { if (!dev_is_tape(dev)) { - bnet_fsend(dir, _("3906 cannot mount non-tape.\n")); + bnet_fsend(dir, _("3906 cannot mount non-tape.\n")); break; } if (open_dev(dev, NULL, OPEN_READ_WRITE) < 0) { - bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), + bnet_fsend(dir, _("3901 open device failed: ERR=%s\n"), strerror_dev(dev)); break; } read_label(dcr); if (dev_state(dev, ST_LABEL)) { - bnet_fsend(dir, _("3001 Device %s is already mounted with Volume \"%s\"\n"), + bnet_fsend(dir, _("3001 Device %s is already mounted with Volume \"%s\"\n"), dev_name(dev), dev->VolHdr.VolName); } else { - bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" - "If this is not a blank tape, try unmounting and remounting the Volume.\n"), + bnet_fsend(dir, _("3905 Device %s open but no Bacula volume is mounted.\n" + "If this is not a blank tape, try unmounting and remounting the Volume.\n"), dev_name(dev)); } } break; default: - bnet_fsend(dir, _("3905 Bizarre wait state %d\n"), dev->dev_blocked); + bnet_fsend(dir, _("3905 Bizarre wait state %d\n"), dev->dev_blocked); break; } V(dev->mutex); } else { - bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); + bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); } } else { pm_strcpy(jcr->errmsg, dir->msg); @@ -613,36 +621,36 @@ static bool unmount_cmd(JCR *jcr) if (dev) { P(dev->mutex); /* Use P to avoid indefinite block */ if (!(dev->state & ST_OPENED)) { - Dmsg0(90, "Device already unmounted\n"); - bnet_fsend(dir, _("3901 Device \"%s\" is already unmounted.\n"), dev_name(dev)); + Dmsg0(90, "Device already unmounted\n"); + bnet_fsend(dir, _("3901 Device \"%s\" is already unmounted.\n"), dev_name(dev)); } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP) { - Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting, + Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting, dev->dev_blocked); open_dev(dev, NULL, 0); /* fake open for close */ offline_or_rewind_dev(dev); force_close_dev(dev); dev->dev_blocked = BST_UNMOUNTED_WAITING_FOR_SYSOP; - bnet_fsend(dir, _("3001 Device \"%s\" unmounted.\n"), dev_name(dev)); + bnet_fsend(dir, _("3001 Device \"%s\" unmounted.\n"), dev_name(dev)); } else if (dev->dev_blocked == BST_DOING_ACQUIRE) { - bnet_fsend(dir, _("3902 Device \"%s\" is busy in acquire.\n"), dev_name(dev)); + bnet_fsend(dir, _("3902 Device \"%s\" is busy in acquire.\n"), dev_name(dev)); } else if (dev->dev_blocked == BST_WRITING_LABEL) { - bnet_fsend(dir, _("3903 Device \"%s\" is being labeled.\n"), dev_name(dev)); + bnet_fsend(dir, _("3903 Device \"%s\" is being labeled.\n"), dev_name(dev)); } else if (dev_state(dev, ST_READ) || dev->num_writers) { if (dev_state(dev, ST_READ)) { - Dmsg0(90, "Device in read mode\n"); - bnet_fsend(dir, _("3904 Device \"%s\" is busy reading.\n"), dev_name(dev)); + Dmsg0(90, "Device in read mode\n"); + bnet_fsend(dir, _("3904 Device \"%s\" is busy reading.\n"), dev_name(dev)); } else { - Dmsg1(90, "Device busy with %d writers\n", dev->num_writers); - bnet_fsend(dir, _("3905 Device %s is busy with %d writer(s).\n"), + Dmsg1(90, "Device busy with %d writers\n", dev->num_writers); + bnet_fsend(dir, _("3905 Device %s is busy with %d writer(s).\n"), dev_name(dev), dev->num_writers); } } else { /* device not being used */ - Dmsg0(90, "Device not in use, unmounting\n"); + Dmsg0(90, "Device not in use, unmounting\n"); /* On FreeBSD, I am having ASSERT() failures in block_device() * and I can only imagine that the thread id that we are * leaving in no_wait_id is being re-used. So here, @@ -654,11 +662,11 @@ static bool unmount_cmd(JCR *jcr) open_dev(dev, NULL, 0); /* fake open for close */ offline_or_rewind_dev(dev); force_close_dev(dev); - bnet_fsend(dir, _("3002 Device %s unmounted.\n"), dev_name(dev)); + bnet_fsend(dir, _("3002 Device %s unmounted.\n"), dev_name(dev)); } V(dev->mutex); } else { - bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); + bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); } } else { /* NB dir->msg gets clobbered in bnet_fsend, so save command */ @@ -687,39 +695,39 @@ static bool release_cmd(JCR *jcr) if (dev) { P(dev->mutex); /* Use P to avoid indefinite block */ if (!(dev->state & ST_OPENED)) { - Dmsg0(90, "Device already released\n"); - bnet_fsend(dir, _("3911 Device %s already released.\n"), dev_name(dev)); + Dmsg0(90, "Device already released\n"); + bnet_fsend(dir, _("3911 Device %s already released.\n"), dev_name(dev)); } else if (dev->dev_blocked == BST_WAITING_FOR_SYSOP || dev->dev_blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP) { - Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting, + Dmsg2(90, "%d waiter dev_block=%d. doing unmount\n", dev->num_waiting, dev->dev_blocked); - bnet_fsend(dir, _("3912 Device %s waiting for mount.\n"), dev_name(dev)); + bnet_fsend(dir, _("3912 Device %s waiting for mount.\n"), dev_name(dev)); } else if (dev->dev_blocked == BST_DOING_ACQUIRE) { - bnet_fsend(dir, _("3913 Device %s is busy in acquire.\n"), dev_name(dev)); + bnet_fsend(dir, _("3913 Device %s is busy in acquire.\n"), dev_name(dev)); } else if (dev->dev_blocked == BST_WRITING_LABEL) { - bnet_fsend(dir, _("3914 Device %s is being labeled.\n"), dev_name(dev)); + bnet_fsend(dir, _("3914 Device %s is being labeled.\n"), dev_name(dev)); } else if (dev_state(dev, ST_READ) || dev->num_writers) { if (dev_state(dev, ST_READ)) { - Dmsg0(90, "Device in read mode\n"); - bnet_fsend(dir, _("3915 Device %s is busy with 1 reader.\n"), dev_name(dev)); + Dmsg0(90, "Device in read mode\n"); + bnet_fsend(dir, _("3915 Device %s is busy with 1 reader.\n"), dev_name(dev)); } else { - Dmsg1(90, "Device busy with %d writers\n", dev->num_writers); - bnet_fsend(dir, _("3916 Device %s is busy with %d writer(s).\n"), + Dmsg1(90, "Device busy with %d writers\n", dev->num_writers); + bnet_fsend(dir, _("3916 Device %s is busy with %d writer(s).\n"), dev_name(dev), dev->num_writers); } } else { /* device not being used */ - Dmsg0(90, "Device not in use, unmounting\n"); + Dmsg0(90, "Device not in use, unmounting\n"); release_volume(jcr->dcr); - bnet_fsend(dir, _("3012 Device %s released.\n"), dev_name(dev)); + bnet_fsend(dir, _("3012 Device %s released.\n"), dev_name(dev)); } V(dev->mutex); } else { - bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); + bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); } } else { /* NB dir->msg gets clobbered in bnet_fsend, so save command */ @@ -748,10 +756,10 @@ static bool autochanger_cmd(JCR *jcr) if (dev) { P(dev->mutex); /* Use P to avoid indefinite block */ if (!dev_is_tape(dev)) { - bnet_fsend(dir, _("3995 Device %s is not an autochanger.\n"), dev_name(dev)); + bnet_fsend(dir, _("3995 Device %s is not an autochanger.\n"), dev_name(dev)); } else if (!(dev->state & ST_OPENED)) { autochanger_list(dcr, dir); - /* Under certain "safe" conditions, we can steal the lock */ + /* Under certain "safe" conditions, we can steal the lock */ } else if (dev->dev_blocked && (dev->dev_blocked == BST_UNMOUNTED || dev->dev_blocked == BST_WAITING_FOR_SYSOP || @@ -759,9 +767,9 @@ static bool autochanger_cmd(JCR *jcr) autochanger_list(dcr, dir); } else if (dev_state(dev, ST_READ) || dev->num_writers) { if (dev_state(dev, ST_READ)) { - bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"), dev_name(dev)); + bnet_fsend(dir, _("3901 Device %s is busy with 1 reader.\n"), dev_name(dev)); } else { - bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"), + bnet_fsend(dir, _("3902 Device %s is busy with %d writer(s).\n"), dev_name(dev), dev->num_writers); } } else { /* device not being used */ @@ -769,7 +777,7 @@ static bool autochanger_cmd(JCR *jcr) } V(dev->mutex); } else { - bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); + bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); } } else { /* error on scanf */ pm_strcpy(jcr->errmsg, dir->msg); @@ -797,7 +805,7 @@ static bool readlabel_cmd(JCR *jcr) if (!dev_state(dev, ST_OPENED)) { read_volume_label(jcr, dev, Slot); force_close_dev(dev); - /* Under certain "safe" conditions, we can steal the lock */ + /* Under certain "safe" conditions, we can steal the lock */ } else if (dev->dev_blocked && (dev->dev_blocked == BST_UNMOUNTED || dev->dev_blocked == BST_WAITING_FOR_SYSOP || @@ -805,10 +813,10 @@ static bool readlabel_cmd(JCR *jcr) read_volume_label(jcr, dev, Slot); } else if (dev_state(dev, ST_READ) || dev->num_writers) { if (dev_state(dev, ST_READ)) { - bnet_fsend(dir, _("3911 Device %s is busy with 1 reader.\n"), + bnet_fsend(dir, _("3911 Device %s is busy with 1 reader.\n"), dev_name(dev)); } else { - bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"), + bnet_fsend(dir, _("3912 Device %s is busy with %d writer(s).\n"), dev_name(dev), dev->num_writers); } } else { /* device not being used */ @@ -816,7 +824,7 @@ static bool readlabel_cmd(JCR *jcr) } V(dev->mutex); } else { - bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); + bnet_fsend(dir, _("3999 Device \"%s\" not found\n"), dname.c_str()); } } else { pm_strcpy(jcr->errmsg, dir->msg); @@ -878,7 +886,7 @@ static bool try_autoload_device(JCR *jcr, int slot, const char *VolName) /* Ensure that the device is open -- autoload_device() closes it */ for ( ; !(dev->state & ST_OPENED); ) { if (open_dev(dev, dcr->VolumeName, OPEN_READ_WRITE) < 0) { - bnet_fsend(dir, _("3910 Unable to open device %s. ERR=%s\n"), + bnet_fsend(dir, _("3910 Unable to open device %s. ERR=%s\n"), dev_name(dev), strerror_dev(dev)); return false; } diff --git a/bacula/src/stored/job.c b/bacula/src/stored/job.c index 4381db297d..1be408cfeb 100644 --- a/bacula/src/stored/job.c +++ b/bacula/src/stored/job.c @@ -7,7 +7,7 @@ * */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -40,8 +40,8 @@ static bool use_device_cmd(JCR *jcr); /* Requests from the Director daemon */ static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s " - "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s " - "SpoolData=%d"; + "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s " + "SpoolData=%d WritePartAfterJob=%d"; static char use_device[] = "use device=%127s media_type=%127s pool_name=%127s pool_type=%127s\n"; static char use_devices[] = "use devices=%127s media_type=%127s pool_name=%127s pool_type=%127s\n"; @@ -68,7 +68,7 @@ bool job_cmd(JCR *jcr) char auth_key[100]; BSOCK *dir = jcr->dir_bsock; POOL_MEM job_name, client_name, job, fileset_name, fileset_md5; - int JobType, level, spool_attributes, no_attributes, spool_data; + int JobType, level, spool_attributes, no_attributes, spool_data, write_part_after_job; struct timeval tv; struct timezone tz; struct timespec timeout; @@ -81,7 +81,7 @@ bool job_cmd(JCR *jcr) if (sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(), client_name.c_str(), &JobType, &level, fileset_name.c_str(), &no_attributes, - &spool_attributes, fileset_md5.c_str(), &spool_data) != 11) { + &spool_attributes, fileset_md5.c_str(), &spool_data, &write_part_after_job) != 12) { pm_strcpy(jcr->errmsg, dir->msg); bnet_fsend(dir, BAD_job, jcr->errmsg); Emsg1(M_FATAL, 0, _("Bad Job Command from Director: %s\n"), jcr->errmsg); @@ -116,6 +116,7 @@ bool job_cmd(JCR *jcr) jcr->no_attributes = no_attributes; jcr->spool_attributes = spool_attributes; jcr->spool_data = spool_data; + jcr->write_part_after_job = write_part_after_job; jcr->fileset_md5 = get_pool_memory(PM_NAME); pm_strcpy(jcr->fileset_md5, fileset_md5); @@ -247,7 +248,7 @@ static bool use_device_cmd(JCR *jcr) while (!quit) { bool ok; if (bnet_recv(dir) <= 0) { - Jmsg0(jcr, M_FATAL, 0, _("No Device from Director\n")); + Jmsg0(jcr, M_FATAL, 0, _("No Device from Director\n")); return false; } @@ -283,13 +284,13 @@ static bool use_device_cmd(JCR *jcr) if (!dcr) { return false; } - Dmsg1(120, "Found device %s\n", device->hdr.name); + Dmsg1(120, "Found device %s\n", device->hdr.name); bstrncpy(dcr->pool_name, pool_name, name_len); bstrncpy(dcr->pool_type, pool_type, name_len); bstrncpy(dcr->media_type, media_type, name_len); bstrncpy(dcr->dev_name, dev_name, name_len); jcr->device = device; - Dmsg1(220, "Got: %s", dir->msg); + Dmsg1(220, "Got: %s", dir->msg); return bnet_fsend(dir, OK_device); } } @@ -297,19 +298,19 @@ static bool use_device_cmd(JCR *jcr) if (verbose) { unbash_spaces(dir->msg); pm_strcpy(jcr->errmsg, dir->msg); - Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg); + Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg); } - Jmsg(jcr, M_FATAL, 0, _("\n" - " Device \"%s\" with MediaType \"%s\" requested by Dir not found in SD Device resources.\n"), + Jmsg(jcr, M_FATAL, 0, _("\n" + " Device \"%s\" with MediaType \"%s\" requested by Dir not found in SD Device resources.\n"), dev_name.c_str(), media_type.c_str()); bnet_fsend(dir, NO_device, dev_name.c_str()); } else { unbash_spaces(dir->msg); pm_strcpy(jcr->errmsg, dir->msg); if (verbose) { - Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg); + Jmsg(jcr, M_INFO, 0, _("Failed command: %s\n"), jcr->errmsg); } - Jmsg(jcr, M_FATAL, 0, _("Bad Use Device command: %s\n"), jcr->errmsg); + Jmsg(jcr, M_FATAL, 0, _("Bad Use Device command: %s\n"), jcr->errmsg); bnet_fsend(dir, BAD_use, jcr->errmsg); } } diff --git a/bacula/src/stored/label.c b/bacula/src/stored/label.c index d822b6b4fd..9b5e03aba2 100644 --- a/bacula/src/stored/label.c +++ b/bacula/src/stored/label.c @@ -8,7 +8,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -71,14 +71,14 @@ int read_dev_volume_label(DCR *dcr) if (dev_state(dev, ST_LABEL)) { /* did we already read label? */ /* Compare Volume Names allow special wild card */ if (VolName && *VolName && *VolName != '*' && strcmp(dev->VolHdr.VolName, VolName) != 0) { - Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"), + Mmsg(jcr->errmsg, _("Wrong Volume mounted on device %s: Wanted %s have %s\n"), dev_name(dev), VolName, dev->VolHdr.VolName); /* * Cancel Job if too many label errors * => we are in a loop */ if (!dev->poll && jcr->label_errors++ > 100) { - Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg); + Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg); } return VOL_NAME_ERROR; } @@ -95,14 +95,14 @@ int read_dev_volume_label(DCR *dcr) return VOL_NO_MEDIA; } bstrncpy(dev->VolHdr.Id, "**error**", sizeof(dev->VolHdr.Id)); - + /* Read the Volume label block */ record = new_record(); empty_block(block); Dmsg0(90, "Big if statement in read_volume_label\n"); if (!read_block_from_dev(dcr, NO_BLOCK_NUMBER_CHECK)) { Mmsg(jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula " - "labeled Volume, because: ERR=%s"), NPRT(VolName), dev_name(dev), + "labeled Volume, because: ERR=%s"), NPRT(VolName), dev_name(dev), strerror_dev(dev)); Dmsg1(30, "%s", jcr->errmsg); } else if (!read_record_from_block(block, record)) { @@ -123,7 +123,7 @@ int read_dev_volume_label(DCR *dcr) free_record(record); if (forge_on || jcr->ignore_label_errors) { dev->state |= ST_LABEL; /* set has Bacula label */ - Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg); + Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg); return VOL_OK; } empty_block(block); @@ -170,7 +170,7 @@ int read_dev_volume_label(DCR *dcr) * => we are in a loop */ if (!dev->poll && jcr->label_errors++ > 100) { - Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg); + Jmsg(jcr, M_FATAL, 0, "Too many tries: %s", jcr->errmsg); } return VOL_NAME_ERROR; } @@ -183,6 +183,95 @@ int read_dev_volume_label(DCR *dcr) return VOL_OK; } +/* Read the volume label by guessing the volume name. (only for mounted devices) + * write is true if we are reading the label before writing to the device. + * + * If the volume name cannot be guessed : + * Writing : returns the label of the current file (on the harddisk). + * Reading : returns an error + */ +int read_dev_volume_label_guess(DCR *dcr, bool write) { + int vol_label_status; + Dmsg3(100, "Enter read_dev_volume_label_guess device=%s vol=%s dev_Vol=%s\n", + dev_name(dcr->dev), dcr->VolumeName, dcr->dev->VolHdr.VolName); + + if (!dev_cap(dcr->dev, CAP_REQMOUNT)) { + Dmsg0(100, "Leave read_dev_volume_label_guess !CAP_REQMOUNT\n"); + return read_dev_volume_label(dcr); + } + + if (!write && (dcr->VolCatInfo.VolCatParts == 0)) { + Dmsg0(100, "Leave read_dev_volume_label_guess !writing, and VolCatParts == 0\n"); + return read_dev_volume_label(dcr); + } + + /* For mounted devices, tries to guess the volume name, and read the label if possible. + */ + if (open_guess_name_dev(dcr->dev) < 0) { + if ((!write) || (dcr->VolCatInfo.VolCatParts > 0)) { + Mmsg2(dcr->jcr->errmsg, _("Requested Volume \"%s\" on %s is not a Bacula labeled Volume."), + dev_name(dcr->dev), dcr->VolumeName); + Dmsg0(100, "Leave read_dev_volume_label_guess VOL_IO_ERROR (!open_guess_name_dev)\n"); + return VOL_NO_LABEL; + } + + if (write && (dcr->dev->free_space_errno < 0)) { + Dmsg0(100, "Leave read_dev_volume_label_guess !free_space VOL_NO_MEDIA\n"); + Mmsg2(dcr->jcr->errmsg, _("free_space error on %s. The current medium is probably not writable. ERR=%s.\n"), + dcr->dev->dev_name, dcr->dev->errmsg); + return VOL_NO_MEDIA; + } + + /* If we can't guess the name, and we are writing, just reopen the right file with open_first_part. */ + if (open_first_part(dcr->dev) < 0) { + berrno be; + Mmsg2(dcr->jcr->errmsg, _("open_first_part error on %s. ERR=%s.\n"), + dcr->dev->dev_name, be.strerror()); + Dmsg0(100, "Leave read_dev_volume_label_guess VOL_IO_ERROR (!open_guess_name_dev && !open_first_part)\n"); + return VOL_IO_ERROR; + } + + Dmsg0(100, "Leave read_dev_volume_label_guess !open_guess_name_dev\n"); + return read_dev_volume_label(dcr); + } + else { + if (write && (dcr->dev->free_space_errno < 0)) { + Dmsg0(100, "Leave read_dev_volume_label_guess !free_space VOL_NO_MEDIA\n"); + Mmsg2(dcr->jcr->errmsg, _("free_space error on %s. The current medium is probably not writable. ERR=%s.\n"), + dcr->dev->dev_name, dcr->dev->errmsg); + return VOL_NO_MEDIA; + } + + vol_label_status = read_dev_volume_label(dcr); + + if ((!write) || (dcr->VolCatInfo.VolCatParts > 0)) { + Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && (!write || dcr->VolCatInfo.VolCatParts > 0))\n"); + return vol_label_status; + } + + if (open_first_part(dcr->dev) < 0) { + berrno be; + Mmsg2(dcr->jcr->errmsg, _("open_first_part error on %s. ERR=%s.\n"), + dcr->dev->dev_name, be.strerror()); + Dmsg0(100, "Leave read_dev_volume_label_guess VOL_IO_ERROR (open_guess_name_dev && !open_first_part)\n"); + return VOL_IO_ERROR; + } + + /* When writing, if the guessed volume name is no the right volume name, + * report the error, otherwise, just continue with the right file. + */ + if (vol_label_status != VOL_NAME_ERROR) { + Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && !VOL_NAME_ERROR)\n"); + dcr->dev->state &= ~ST_LABEL; + return read_dev_volume_label(dcr); + } + else { + Dmsg0(100, "Leave read_dev_volume_label_guess (open_guess_name_dev && VOL_NAME_ERROR)\n"); + return vol_label_status; + } + } +} + /* unser_volume_label * * Unserialize the Volume label into the device Volume_Label @@ -546,9 +635,9 @@ bool write_session_label(DCR *dcr, int label) if (!can_write_record_to_block(block, rec)) { Dmsg0(100, "Cannot write session label to block.\n"); if (!write_block_to_device(dcr)) { - Dmsg0(90, "Got session label write_block_to_dev error.\n"); + Dmsg0(90, "Got session label write_block_to_dev error.\n"); /* ****FIXME***** errno is not set here */ - Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"), + Jmsg(jcr, M_FATAL, 0, _("Error writing Session label to %s: %s\n"), dev_vol_name(dev), strerror(errno)); free_record(rec); return false; @@ -562,7 +651,7 @@ bool write_session_label(DCR *dcr, int label) } Dmsg6(20, "Write sesson_label record JobId=%d FI=%s SessId=%d Strm=%s len=%d " - "remainder=%d\n", jcr->JobId, + "remainder=%d\n", jcr->JobId, FI_to_ascii(rec->FileIndex), rec->VolSessionId, stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len, rec->remainder); @@ -586,25 +675,25 @@ void dump_volume_label(DEVICE *dev) File = dev->file; switch (dev->VolHdr.LabelType) { case PRE_LABEL: - LabelType = "PRE_LABEL"; + LabelType = "PRE_LABEL"; break; case VOL_LABEL: - LabelType = "VOL_LABEL"; + LabelType = "VOL_LABEL"; break; case EOM_LABEL: - LabelType = "EOM_LABEL"; + LabelType = "EOM_LABEL"; break; case SOS_LABEL: - LabelType = "SOS_LABEL"; + LabelType = "SOS_LABEL"; break; case EOS_LABEL: - LabelType = "EOS_LABEL"; + LabelType = "EOS_LABEL"; break; case EOT_LABEL: goto bail_out; default: LabelType = buf; - sprintf(buf, "Unknown %d", dev->VolHdr.LabelType); + sprintf(buf, "Unknown %d", dev->VolHdr.LabelType); break; } @@ -804,14 +893,14 @@ void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose) dump_session_label(rec, type); break; case EOM_LABEL: - Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n", + Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n", type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); break; case EOT_LABEL: - Pmsg0(-1, _("End of physical tape.\n")); + Pmsg0(-1, _("End of physical tape.\n")); break; default: - Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n", + Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n", type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); break; } @@ -820,17 +909,17 @@ void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose) switch (rec->FileIndex) { case SOS_LABEL: unser_session_label(&label, rec); - Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n", + Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n", type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, label.JobLevel, label.JobType); break; case EOS_LABEL: char ed1[30], ed2[30]; unser_session_label(&label, rec); - Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n", + Pmsg6(-1, "%s Record: SessId=%d SessTime=%d JobId=%d Level=%c Type=%c\n", type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, label.JobLevel, label.JobType); - Pmsg4(-1, " Files=%s Bytes=%s Errors=%d Status=%c\n", + Pmsg4(-1, " Files=%s Bytes=%s Errors=%d Status=%c\n", edit_uint64_with_commas(label.JobFiles, ed1), edit_uint64_with_commas(label.JobBytes, ed2), label.JobErrors, (char)label.JobStatus); @@ -839,7 +928,7 @@ void dump_label_record(DEVICE *dev, DEV_RECORD *rec, int verbose) case PRE_LABEL: case VOL_LABEL: default: - Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n", + Pmsg5(-1, "%s Record: SessId=%d SessTime=%d JobId=%d DataLen=%d\n", type, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len); break; case EOT_LABEL: diff --git a/bacula/src/stored/mount.c b/bacula/src/stored/mount.c index 1b0cd6b52d..4b58a57aab 100644 --- a/bacula/src/stored/mount.c +++ b/bacula/src/stored/mount.c @@ -8,7 +8,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -69,7 +69,7 @@ mount_next_vol: /* Last ditch effort before giving up, force operator to respond */ dcr->VolCatInfo.Slot = 0; if (!dir_ask_sysop_to_mount_volume(dcr)) { - Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"), + Jmsg(jcr, M_FATAL, 0, _("Too many errors trying to mount device %s.\n"), dev_name(dev)); return false; } @@ -100,8 +100,10 @@ mount_next_vol: if (job_canceled(jcr)) { return false; } - Dmsg2(100, "After find_next_append. Vol=%s Slot=%d\n", - dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.Slot); + Dmsg3(100, "After find_next_append. Vol=%s Slot=%d Parts=%d\n", + dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.Slot, dcr->VolCatInfo.VolCatParts); + + dev->num_parts = dcr->VolCatInfo.VolCatParts; /* * Get next volume and ready it for append @@ -154,13 +156,24 @@ mount_next_vol: } /* Ensure the device is open */ - if (!open_device(dcr)) { - if (dev->poll) { - goto mount_next_vol; - } else { - return false; + /* If we have a device that requires mount, we first want to guess + * which device is loaded, so we continue (if the wrong device is + * loaded, open_device would fail). */ + if (!dev_cap(dev, CAP_REQMOUNT)) { + if (!open_device(dcr)) { + if (dev->poll) { + goto mount_next_vol; + } + else { + return false; + } } } + else { + /* Just copy the VolCatName in the device resource (usually done by open_dev). + * It is necessary so we can open the real files later. */ + bstrncpy(dcr->dev->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatName, sizeof(dcr->dev->VolCatInfo.VolCatName)); + } /* * Now make sure we have the right tape mounted @@ -174,7 +187,10 @@ read_volume: vol_label_status = VOL_OK; create_volume_label(dev, dcr->VolumeName, "Default"); dev->VolHdr.LabelType = PRE_LABEL; - } else { + } else if (dev_cap(dev, CAP_REQMOUNT)) { + vol_label_status = read_dev_volume_label_guess(dcr, 1); + } + else { vol_label_status = read_dev_volume_label(dcr); } if (job_canceled(jcr)) { @@ -198,7 +214,7 @@ read_volume: /* If not removable, Volume is broken */ if (!dev_cap(dev, CAP_REM)) { - Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"), + Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"), dcr->VolumeName, dev_name(dev)); mark_volume_in_error(dcr); goto mount_next_vol; @@ -208,7 +224,7 @@ read_volume: /* If polling and got a previous bad name, ignore it */ if (dev->poll && strcmp(dev->BadVolName, dev->VolHdr.VolName) == 0) { ask = true; - Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n", + Dmsg1(200, "Vol Name error supress due to poll. Name=%s\n", dcr->VolumeName); goto mount_next_vol; } @@ -223,9 +239,9 @@ read_volume: bstrncpy(dcr->VolumeName, dev->VolHdr.VolName, sizeof(dcr->VolumeName)); if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE)) { bstrncpy(dev->BadVolName, dev->VolHdr.VolName, sizeof(dev->BadVolName)); - Jmsg(jcr, M_WARNING, 0, _("Director wanted Volume \"%s\".\n" - " Current Volume \"%s\" not acceptable because:\n" - " %s"), + Jmsg(jcr, M_WARNING, 0, _("Director wanted Volume \"%s\".\n" + " Current Volume \"%s\" not acceptable because:\n" + " %s"), VolCatInfo.VolCatName, dev->VolHdr.VolName, jcr->dir_bsock->msg); /* Restore desired volume name, note device info out of sync */ @@ -255,27 +271,27 @@ read_volume: */ if (dev_cap(dev, CAP_LABEL) && (dcr->VolCatInfo.VolCatBytes == 0 || (!dev_is_tape(dev) && strcmp(dcr->VolCatInfo.VolCatStatus, - "Recycle") == 0))) { - Dmsg0(100, "Create volume label\n"); + "Recycle") == 0))) { + Dmsg0(100, "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(100, "!write_vol_label\n"); + Dmsg0(100, "!write_vol_label\n"); goto mount_next_vol; } - Dmsg0(100, "dir_update_vol_info. Set Append\n"); - /* Copy Director's info into the device info */ + Dmsg0(100, "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"), + Jmsg(jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"), dcr->VolumeName, dev_name(dev)); goto read_volume; /* read label we just wrote */ } /* If not removable, Volume is broken */ if (!dev_cap(dev, CAP_REM)) { - Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"), + Jmsg(jcr, M_WARNING, 0, _("Volume \"%s\" not on device %s.\n"), dcr->VolumeName, dev_name(dev)); mark_volume_in_error(dcr); goto mount_next_vol; @@ -285,11 +301,15 @@ read_volume: default: /* Send error message */ if (!dev->poll) { - Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); + Jmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg); } else { - Dmsg1(200, "Msg suppressed by poll: %s\n", jcr->errmsg); + Dmsg1(200, "Msg suppressed by poll: %s\n", jcr->errmsg); } ask = true; + /* Needed, so the medium can be changed */ + if (dev_cap(dev, CAP_REQMOUNT)) { + close_dev(dev); + } goto mount_next_vol; } @@ -320,7 +340,7 @@ read_volume: Jmsg(jcr, M_INFO, 0, _("Volume \"%s\" previously written, moving to end of data.\n"), dcr->VolumeName); if (!eod_dev(dev)) { - Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data on device \"%s\". ERR=%s\n"), + Jmsg(jcr, M_ERROR, 0, _("Unable to position to end of data on device \"%s\". ERR=%s\n"), dev_name(dev), strerror_dev(dev)); mark_volume_in_error(dcr); goto mount_next_vol; @@ -332,10 +352,10 @@ read_volume: * that the database says we should be. */ if (dev->VolCatInfo.VolCatFiles == dev_file(dev)) { - Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\" at file=%d.\n"), + Jmsg(jcr, M_INFO, 0, _("Ready to append to end of Volume \"%s\" at file=%d.\n"), dcr->VolumeName, dev_file(dev)); } else { - Jmsg(jcr, M_ERROR, 0, _("I canot write on Volume \"%s\" because:\n" + Jmsg(jcr, M_ERROR, 0, _("I canot write on Volume \"%s\" because:\n" "The number of files mismatch! Volume=%u Catalog=%u\n"), dcr->VolumeName, dev_file(dev), dev->VolCatInfo.VolCatFiles); mark_volume_in_error(dcr); @@ -379,21 +399,21 @@ static bool rewrite_volume_label(DCR *dcr, bool recycle) */ if (!dev_cap(dev, CAP_STREAM)) { if (!rewind_dev(dev)) { - Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device \"%s\". ERR=%s\n"), + Jmsg2(jcr, M_WARNING, 0, _("Rewind error on device \"%s\". ERR=%s\n"), dev_name(dev), strerror_dev(dev)); } if (recycle) { if (!truncate_dev(dev)) { - Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device \"%s\". ERR=%s\n"), + Jmsg2(jcr, M_WARNING, 0, _("Truncate error on device \"%s\". ERR=%s\n"), dev_name(dev), strerror_dev(dev)); } } /* Attempt write to check write permission */ Dmsg0(200, "Attempt to write to device.\n"); if (!write_block_to_dev(dcr)) { - Jmsg2(jcr, M_ERROR, 0, _("Unable to write device \"%s\". ERR=%s\n"), + Jmsg2(jcr, M_ERROR, 0, _("Unable to write device \"%s\". ERR=%s\n"), dev_name(dev), strerror_dev(dev)); - Dmsg0(200, "===ERROR write block to dev\n"); + Dmsg0(200, "===ERROR write block to dev\n"); return false; } } @@ -463,7 +483,7 @@ bool mount_next_read_volume(DCR *dcr) close_dev(dev); dev->state &= ~ST_READ; if (!acquire_device_for_read(jcr)) { - Jmsg2(jcr, M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), + Jmsg2(jcr, M_FATAL, 0, "Cannot open Dev=%s, Vol=%s\n", dev_name(dev), dcr->VolumeName); return false; } diff --git a/bacula/src/stored/protos.h b/bacula/src/stored/protos.h index 29cb049158..dc3e1eda07 100644 --- a/bacula/src/stored/protos.h +++ b/bacula/src/stored/protos.h @@ -5,7 +5,7 @@ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -85,6 +85,10 @@ void display_tape_error_status(JCR *jcr, DEVICE *dev); /* From dev.c */ DEVICE *init_dev(DEVICE *dev, DEVRES *device); int open_dev(DEVICE *dev, char *VolName, int mode); +off_t lseek_dev(DEVICE *dev, off_t offset, int whence); +int open_first_part(DEVICE *dev); +int open_next_part(DEVICE *dev); +int open_guess_name_dev(DEVICE *dev); void close_dev(DEVICE *dev); void force_close_dev(DEVICE *dev); bool truncate_dev(DEVICE *dev); @@ -113,7 +117,6 @@ bool reposition_dev(DEVICE *dev, uint32_t file, uint32_t block); void init_dev_wait_timers(DEVICE *dev); bool double_dev_wait_time(DEVICE *dev); - /* Get info about device */ char * dev_name(DEVICE *dev); char * dev_vol_name(DEVICE *dev); @@ -153,6 +156,7 @@ void handle_filed_connection(BSOCK *fd, char *job_name); /* From label.c */ int read_dev_volume_label(DCR *dcr); +int read_dev_volume_label_guess(DCR *dcr, bool write); void create_session_label(DCR *dcr, DEV_RECORD *rec, int label); void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName); bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName); diff --git a/bacula/src/stored/python.c b/bacula/src/stored/python.c index e2ff88acb3..9a93f48fed 100644 --- a/bacula/src/stored/python.c +++ b/bacula/src/stored/python.c @@ -9,7 +9,6 @@ */ /* - Copyright (C) 2005 Kern Sibbald This program is free software; you can redistribute it and/or diff --git a/bacula/src/stored/read.c b/bacula/src/stored/read.c index c91aca9120..6bceb324b1 100644 --- a/bacula/src/stored/read.c +++ b/bacula/src/stored/read.c @@ -6,7 +6,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -117,7 +117,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) bnet_strerror(fd)); return false; } else { - Dmsg1(30, ">filed: Hdr=%s\n", fd->msg); + Dmsg1(31, ">filed: Hdr=%s\n", fd->msg); } @@ -125,7 +125,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec) save_msg = fd->msg; /* save fd message pointer */ fd->msg = rec->data; /* pass data directly to bnet_send */ fd->msglen = rec->data_len; - Dmsg1(30, ">filed: send %d bytes data.\n", fd->msglen); + Dmsg1(31, ">filed: send %d bytes data.\n", fd->msglen); if (!bnet_send(fd)) { Pmsg1(000, "Error sending to FD. ERR=%s\n", bnet_strerror(fd)); Jmsg1(jcr, M_FATAL, 0, _("Error sending to File daemon. ERR=%s\n"), diff --git a/bacula/src/stored/status.c b/bacula/src/stored/status.c index 878376b79c..a9c0bf9146 100644 --- a/bacula/src/stored/status.c +++ b/bacula/src/stored/status.c @@ -7,7 +7,7 @@ * */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -71,7 +71,7 @@ bool status_cmd(JCR *jcr) HOST_OS, DISTNAME, DISTVER); bstrftime_nc(dt, sizeof(dt), daemon_start_time); bnet_fsend(user, _("Daemon started %s, %d Job%s run since started.\n"), dt, num_jobs_run, - num_jobs_run == 1 ? "" : "s"); + num_jobs_run == 1 ? "" : "s"); if (debug_level > 0) { char b1[35], b2[35], b3[35], b4[35]; bnet_fsend(user, _(" Heap: bytes=%s max_bytes=%s bufs=%s max_bufs=%s\n"), @@ -100,10 +100,10 @@ bool status_cmd(JCR *jcr) for (dev=device->dev; dev; dev=dev->next) { if (dev_state(dev, ST_OPENED)) { if (dev_state(dev, ST_LABEL)) { - bnet_fsend(user, _("Device \"%s\" is mounted with Volume \"%s\"\n"), + bnet_fsend(user, _("Device \"%s\" is mounted with Volume \"%s\"\n"), dev_name(dev), dev->VolHdr.VolName); } else { - bnet_fsend(user, _("Device \"%s\" open but no Bacula volume is mounted.\n"), dev_name(dev)); + bnet_fsend(user, _("Device \"%s\" open but no Bacula volume is mounted.\n"), dev_name(dev)); } send_blocked_status(jcr, dev); if (dev_state(dev, ST_APPEND)) { @@ -112,7 +112,7 @@ bool status_cmd(JCR *jcr) bpb = 1; } bpb = dev->VolCatInfo.VolCatBytes / bpb; - bnet_fsend(user, _(" Total Bytes=%s Blocks=%s Bytes/block=%s\n"), + bnet_fsend(user, _(" Total Bytes=%s Blocks=%s Bytes/block=%s\n"), edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, b1), edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2), edit_uint64_with_commas(bpb, b3)); @@ -126,17 +126,17 @@ bool status_cmd(JCR *jcr) } else { bpb = 0; } - bnet_fsend(user, _(" Total Bytes Read=%s Blocks Read=%s Bytes/block=%s\n"), + bnet_fsend(user, _(" Total Bytes Read=%s Blocks Read=%s Bytes/block=%s\n"), edit_uint64_with_commas(dev->VolCatInfo.VolCatRBytes, b1), edit_uint64_with_commas(dev->VolCatInfo.VolCatReads, b2), edit_uint64_with_commas(bpb, b3)); } - bnet_fsend(user, _(" Positioned at File=%s Block=%s\n"), + bnet_fsend(user, _(" Positioned at File=%s Block=%s\n"), edit_uint64_with_commas(dev->file, b1), edit_uint64_with_commas(dev->block_num, b2)); } else { - bnet_fsend(user, _("Device \"%s\" is not open.\n"), dev_name(dev)); + bnet_fsend(user, _("Device \"%s\" is not open.\n"), dev_name(dev)); send_blocked_status(jcr, dev); } } @@ -170,10 +170,10 @@ static void send_blocked_status(JCR *jcr, DEVICE *dev) break; case BST_WAITING_FOR_SYSOP: if (jcr->JobStatus == JS_WaitMount) { - bnet_fsend(user, _(" Device is BLOCKED waiting for mount of volume \"%s\".\n"), + bnet_fsend(user, _(" Device is BLOCKED waiting for mount of volume \"%s\".\n"), dcr->VolumeName); } else { - bnet_fsend(user, _(" Device is BLOCKED waiting for appendable media.\n")); + bnet_fsend(user, _(" Device is BLOCKED waiting for appendable media.\n")); } break; case BST_DOING_ACQUIRE: @@ -213,6 +213,7 @@ static void send_blocked_status(JCR *jcr, DEVICE *dev) bnet_fsend(user, "%sEOF ", dev->state & ST_EOF ? "" : "!"); bnet_fsend(user, "%sNEXTVOL ", dev->state & ST_NEXTVOL ? "" : "!"); bnet_fsend(user, "%sSHORT ", dev->state & ST_SHORT ? "" : "!"); + bnet_fsend(user, "%sMOUNTED ", dev->state & ST_MOUNTED ? "" : "!"); bnet_fsend(user, "\n"); bnet_fsend(user, _("Device parameters:\n")); @@ -235,7 +236,7 @@ static void list_running_jobs(BSOCK *user) lock_jcr_chain(); foreach_jcr(jcr) { if (jcr->JobStatus == JS_WaitFD) { - bnet_fsend(user, _("%s Job %s waiting for Client connection.\n"), + bnet_fsend(user, _("%s Job %s waiting for Client connection.\n"), job_type_to_str(jcr->JobType), jcr->Job); } if (jcr->device) { @@ -243,35 +244,35 @@ static void list_running_jobs(BSOCK *user) /* There are three periods after the Job name */ char *p; for (int i=0; i<3; i++) { - if ((p=strrchr(JobName, '.')) != NULL) { + if ((p=strrchr(JobName, '.')) != NULL) { *p = 0; } } - bnet_fsend(user, _("%s %s job %s JobId=%d Volume=\"%s\" device=\"%s\"\n"), + bnet_fsend(user, _("%s %s job %s JobId=%d Volume=\"%s\" device=\"%s\"\n"), job_level_to_str(jcr->JobLevel), job_type_to_str(jcr->JobType), JobName, jcr->JobId, - jcr->dcr?jcr->dcr->VolumeName:"*none*", - jcr->device?jcr->device->device_name:"none"); + jcr->dcr?jcr->dcr->VolumeName:"*none*", + jcr->device?jcr->device->device_name:"none"); sec = time(NULL) - jcr->run_time; if (sec <= 0) { sec = 1; } bps = jcr->JobBytes / sec; - bnet_fsend(user, _(" Files=%s Bytes=%s Bytes/sec=%s\n"), + bnet_fsend(user, _(" Files=%s Bytes=%s Bytes/sec=%s\n"), edit_uint64_with_commas(jcr->JobFiles, b1), edit_uint64_with_commas(jcr->JobBytes, b2), edit_uint64_with_commas(bps, b3)); found = true; #ifdef DEBUG if (jcr->file_bsock) { - bnet_fsend(user, " FDReadSeqNo=%s in_msg=%u out_msg=%d fd=%d\n", + bnet_fsend(user, " FDReadSeqNo=%s in_msg=%u out_msg=%d fd=%d\n", edit_uint64_with_commas(jcr->file_bsock->read_seqno, b1), jcr->file_bsock->in_msg_no, jcr->file_bsock->out_msg_no, jcr->file_bsock->fd); } else { - bnet_fsend(user, " FDSocket closed\n"); + bnet_fsend(user, " FDSocket closed\n"); } #endif } @@ -312,7 +313,7 @@ static void list_terminated_jobs(void *arg) switch (je->JobType) { case JT_ADMIN: case JT_RESTORE: - bstrncpy(level, " ", sizeof(level)); + bstrncpy(level, " ", sizeof(level)); break; default: bstrncpy(level, level_to_str(je->JobLevel), sizeof(level)); @@ -321,30 +322,30 @@ static void list_terminated_jobs(void *arg) } switch (je->JobStatus) { case JS_Created: - termstat = "Created"; + termstat = "Created"; break; case JS_FatalError: case JS_ErrorTerminated: - termstat = "Error"; + termstat = "Error"; break; case JS_Differences: - termstat = "Diffs"; + termstat = "Diffs"; break; case JS_Canceled: - termstat = "Cancel"; + termstat = "Cancel"; break; case JS_Terminated: - termstat = "OK"; + termstat = "OK"; break; default: - termstat = "Other"; + termstat = "Other"; break; } bstrncpy(JobName, je->Job, sizeof(JobName)); /* There are three periods after the Job name */ char *p; for (int i=0; i<3; i++) { - if ((p=strrchr(JobName, '.')) != NULL) { + if ((p=strrchr(JobName, '.')) != NULL) { *p = 0; } } diff --git a/bacula/src/stored/stored.h b/bacula/src/stored/stored.h index 2933237cc0..cfd68b0e83 100644 --- a/bacula/src/stored/stored.h +++ b/bacula/src/stored/stored.h @@ -4,7 +4,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -47,7 +47,7 @@ #include "jcr.h" #include "protos.h" #ifdef HAVE_LIBZ -#include /* compression headers */ +#include /* compression headers */ #else #define uLongf uint32_t #endif @@ -56,9 +56,16 @@ #else #include "lib/fnmatch.h" #endif +#ifdef HAVE_DIRENT_H +#include +#define NAMELEN(dirent) (strlen((dirent)->d_name)) +#endif +#ifndef HAVE_READDIR_R +int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); +#endif extern STORES *me; /* "Global" daemon resource */ -extern bool forge_on; /* proceed inspite of I/O errors */ +extern bool forge_on; /* proceed inspite of I/O errors */ #ifdef debug_tracing extern int _rewind_dev(char *file, int line, DEVICE *dev); diff --git a/bacula/src/stored/stored_conf.c b/bacula/src/stored/stored_conf.c index 9f8edaa23d..00c7b2df58 100644 --- a/bacula/src/stored/stored_conf.c +++ b/bacula/src/stored/stored_conf.c @@ -7,7 +7,7 @@ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -122,6 +122,13 @@ static RES_ITEM dev_items[] = { {"maximumspoolsize", store_size, ITEM(res_dev.max_spool_size), 0, 0, 0}, {"maximumjobspoolsize", store_size, ITEM(res_dev.max_job_spool_size), 0, 0, 0}, {"driveindex", store_pint, ITEM(res_dev.drive_index), 0, 0, 0}, + {"maximumpartsize", store_size, ITEM(res_dev.max_part_size), 0, ITEM_DEFAULT, 0}, + {"requiresmount", store_yesno, ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0}, + {"mountpoint", store_strname,ITEM(res_dev.mount_point), 0, 0, 0}, + {"mountcommand", store_strname,ITEM(res_dev.mount_command), 0, 0, 0}, + {"unmountcommand", store_strname,ITEM(res_dev.unmount_command), 0, 0, 0}, + {"writepartcommand", store_strname,ITEM(res_dev.write_part_command), 0, 0, 0}, + {"freespacecommand", store_strname,ITEM(res_dev.free_space_command), 0, 0, 0}, {NULL, NULL, 0, 0, 0, 0} }; @@ -172,11 +179,11 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm get_first_port_host_order(res->res_store.sddaddrs), edit_utime(res->res_store.heartbeat_interval, buf, sizeof(buf))); foreach_dlist(p, res->res_store.sdaddrs) { - sendit(sock, " SDaddr=%s SDport=%d\n", + sendit(sock, " SDaddr=%s SDport=%d\n", p->get_address(buf, sizeof(buf)), p->get_port_host_order()); } foreach_dlist(p, res->res_store.sddaddrs) { - sendit(sock, " SDDaddr=%s SDDport=%d\n", + sendit(sock, " SDDaddr=%s SDDport=%d\n", p->get_address(buf, sizeof(buf)), p->get_port_host_order()); } break; @@ -197,40 +204,40 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm res->res_dev.max_spool_size, res->res_dev.max_job_spool_size); strcpy(buf, " "); if (res->res_dev.cap_bits & CAP_EOF) { - bstrncat(buf, "CAP_EOF ", sizeof(buf)); + bstrncat(buf, "CAP_EOF ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_BSR) { - bstrncat(buf, "CAP_BSR ", sizeof(buf)); + bstrncat(buf, "CAP_BSR ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_BSF) { - bstrncat(buf, "CAP_BSF ", sizeof(buf)); + bstrncat(buf, "CAP_BSF ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_FSR) { - bstrncat(buf, "CAP_FSR ", sizeof(buf)); + bstrncat(buf, "CAP_FSR ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_FSF) { - bstrncat(buf, "CAP_FSF ", sizeof(buf)); + bstrncat(buf, "CAP_FSF ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_EOM) { - bstrncat(buf, "CAP_EOM ", sizeof(buf)); + bstrncat(buf, "CAP_EOM ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_REM) { - bstrncat(buf, "CAP_REM ", sizeof(buf)); + bstrncat(buf, "CAP_REM ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_RACCESS) { - bstrncat(buf, "CAP_RACCESS ", sizeof(buf)); + bstrncat(buf, "CAP_RACCESS ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_AUTOMOUNT) { - bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf)); + bstrncat(buf, "CAP_AUTOMOUNT ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_LABEL) { - bstrncat(buf, "CAP_LABEL ", sizeof(buf)); + bstrncat(buf, "CAP_LABEL ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_ANONVOLS) { - bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf)); + bstrncat(buf, "CAP_ANONVOLS ", sizeof(buf)); } if (res->res_dev.cap_bits & CAP_ALWAYSOPEN) { - bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf)); + bstrncat(buf, "CAP_ALWAYSOPEN ", sizeof(buf)); } bstrncat(buf, "\n", sizeof(buf)); sendit(sock, buf); @@ -238,9 +245,9 @@ void dump_resource(int type, RES *reshdr, void sendit(void *sock, const char *fm case R_MSGS: sendit(sock, "Messages: name=%s\n", res->res_msgs.hdr.name); if (res->res_msgs.mail_cmd) - sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd); + sendit(sock, " mailcmd=%s\n", res->res_msgs.mail_cmd); if (res->res_msgs.operator_cmd) - sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd); + sendit(sock, " opcmd=%s\n", res->res_msgs.operator_cmd); break; default: sendit(sock, _("Warning: unknown resource type %d\n"), type); @@ -320,6 +327,21 @@ void free_resource(RES *sres, int type) if (res->res_dev.spool_directory) { free(res->res_dev.spool_directory); } + if (res->res_dev.mount_point) { + free(res->res_dev.mount_point); + } + if (res->res_dev.mount_command) { + free(res->res_dev.mount_command); + } + if (res->res_dev.unmount_command) { + free(res->res_dev.unmount_command); + } + if (res->res_dev.write_part_command) { + free(res->res_dev.write_part_command); + } + if (res->res_dev.free_space_command) { + free(res->res_dev.free_space_command); + } break; case R_MSGS: if (res->res_msgs.mail_cmd) { @@ -332,7 +354,7 @@ void free_resource(RES *sres, int type) res = NULL; break; default: - Dmsg1(0, "Unknown resource type %d\n", type); + Dmsg1(0, "Unknown resource type %d\n", type); break; } /* Common stuff again -- free the resource, recurse to next one */ @@ -361,13 +383,13 @@ void save_resource(int type, RES_ITEM *items, int pass) for (i=0; items[i].name; i++) { if (items[i].flags & ITEM_REQUIRED) { if (!bit_is_set(i, res_all.res_dir.hdr.item_present)) { - Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"), + Emsg2(M_ERROR_TERM, 0, _("\"%s\" item is required in \"%s\" resource, but not found.\n"), items[i].name, resources[rindex]); } } /* If this triggers, take a look at lib/parse_conf.h */ if (i >= MAX_RES_ITEMS) { - Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]); + Emsg1(M_ERROR_TERM, 0, _("Too many items in \"%s\" resource\n"), resources[rindex]); } } @@ -387,12 +409,12 @@ void save_resource(int type, RES_ITEM *items, int pass) /* Resources containing a resource */ case R_STORAGE: if ((res = (URES *)GetResWithName(R_STORAGE, res_all.res_dir.hdr.name)) == NULL) { - Emsg1(M_ERROR_TERM, 0, "Cannot find Storage resource \"%s\"\n", res_all.res_dir.hdr.name); + Emsg1(M_ERROR_TERM, 0, "Cannot find Storage resource \"%s\"\n", res_all.res_dir.hdr.name); } res->res_store.messages = res_all.res_store.messages; break; default: - printf("Unknown resource type %d\n", type); + printf("Unknown resource type %d\n", type); error = 1; break; } @@ -424,7 +446,7 @@ void save_resource(int type, RES_ITEM *items, int pass) size = sizeof(MSGS); break; default: - printf("Unknown resource type %d\n", type); + printf("Unknown resource type %d\n", type); error = 1; size = 1; break; @@ -441,12 +463,12 @@ void save_resource(int type, RES_ITEM *items, int pass) for (next=res_head[rindex]; next->next; next=next->next) { if (strcmp(next->name, res->res_dir.hdr.name) == 0) { Emsg2(M_ERROR_TERM, 0, - _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"), + _("Attempt to define second \"%s\" resource named \"%s\" is not permitted.\n"), resources[rindex].name, res->res_dir.hdr.name); } } next->next = (RES *)res; - Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), + Dmsg2(90, "Inserting %s res: %s\n", res_to_str(type), res->res_dir.hdr.name); } } diff --git a/bacula/src/stored/stored_conf.h b/bacula/src/stored/stored_conf.h index 7274d34787..4e68d83d69 100644 --- a/bacula/src/stored/stored_conf.h +++ b/bacula/src/stored/stored_conf.h @@ -4,7 +4,7 @@ * Version $Id$ */ /* - Copyright (C) 2000-2004 Kern Sibbald and John Walker + Copyright (C) 2000-2005 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 @@ -29,7 +29,7 @@ enum { R_DEVICE, R_MSGS, R_FIRST = R_DIRECTOR, - R_LAST = R_MSGS /* keep this updated */ + R_LAST = R_MSGS /* keep this updated */ }; enum { @@ -43,59 +43,67 @@ enum { /* Definition of the contents of each Resource */ struct DIRRES { - RES hdr; + RES hdr; - char *password; /* Director password */ - char *address; /* Director IP address or zero */ - int enable_ssl; /* Use SSL with this Director */ - int monitor; /* Have only access to status and .status functions */ + char *password; /* Director password */ + char *address; /* Director IP address or zero */ + int enable_ssl; /* Use SSL with this Director */ + int monitor; /* Have only access to status and .status functions */ }; /* Storage daemon "global" definitions */ struct s_res_store { - RES hdr; + RES hdr; dlist *sdaddrs; dlist *sddaddrs; - char *working_directory; /* working directory for checkpoints */ + char *working_directory; /* working directory for checkpoints */ char *pid_directory; char *subsys_directory; - int require_ssl; /* Require SSL on all connections */ + int require_ssl; /* Require SSL on all connections */ uint32_t max_concurrent_jobs; /* maximum concurrent jobs to run */ - MSGS *messages; /* Daemon message handler */ - utime_t heartbeat_interval; /* Interval to send hb to FD */ + MSGS *messages; /* Daemon message handler */ + utime_t heartbeat_interval; /* Interval to send hb to FD */ }; typedef struct s_res_store STORES; /* Device specific definitions */ struct DEVRES { - RES hdr; + RES hdr; - char *media_type; /* User assigned media type */ - char *device_name; /* Archive device name */ - char *changer_name; /* Changer device name */ - char *changer_command; /* Changer command -- external program */ - char *alert_command; /* Alert command -- external program */ - char *spool_directory; /* Spool file directory */ - uint32_t drive_index; /* Autochanger drive index */ - uint32_t cap_bits; /* Capabilities of this device */ - uint32_t max_changer_wait; /* Changer timeout */ - uint32_t max_rewind_wait; /* maximum secs to wait for rewind */ - uint32_t max_open_wait; /* maximum secs to wait for open */ - uint32_t max_open_vols; /* maximum simultaneous open volumes */ - uint32_t min_block_size; /* min block size */ - uint32_t max_block_size; /* max block size */ - uint32_t max_volume_jobs; /* max jobs to put on one volume */ + char *media_type; /* User assigned media type */ + char *device_name; /* Archive device name */ + char *changer_name; /* Changer device name */ + char *changer_command; /* Changer command -- external program */ + char *alert_command; /* Alert command -- external program */ + char *spool_directory; /* Spool file directory */ + uint32_t drive_index; /* Autochanger drive index */ + uint32_t cap_bits; /* Capabilities of this device */ + uint32_t max_changer_wait; /* Changer timeout */ + uint32_t max_rewind_wait; /* maximum secs to wait for rewind */ + uint32_t max_open_wait; /* maximum secs to wait for open */ + uint32_t max_open_vols; /* maximum simultaneous open volumes */ + uint32_t min_block_size; /* min block size */ + uint32_t max_block_size; /* max block size */ + uint32_t max_volume_jobs; /* max jobs to put on one volume */ uint32_t max_network_buffer_size; /* max network buf size */ - utime_t vol_poll_interval; /* interval between polling volume during mount */ - int64_t max_volume_files; /* max files to put on one volume */ - int64_t max_volume_size; /* max bytes to put on one volume */ - int64_t max_file_size; /* max file size in bytes */ - int64_t volume_capacity; /* advisory capacity */ - int64_t max_spool_size; /* Max spool size for all jobs */ - int64_t max_job_spool_size; /* Max spool size for any single job */ - DEVICE *dev; /* Pointer to phyical dev -- set at runtime */ + utime_t vol_poll_interval; /* interval between polling volume during mount */ + int64_t max_volume_files; /* max files to put on one volume */ + int64_t max_volume_size; /* max bytes to put on one volume */ + int64_t max_file_size; /* max file size in bytes */ + int64_t volume_capacity; /* advisory capacity */ + int64_t max_spool_size; /* Max spool size for all jobs */ + int64_t max_job_spool_size; /* Max spool size for any single job */ + + int64_t max_part_size; /* Max part size */ + char *mount_point; /* Mount point for require mount devices */ + char *mount_command; /* Mount command */ + char *unmount_command; /* Unmount command */ + char *write_part_command; /* Write part command */ + char *free_space_command; /* Free space command */ + + DEVICE *dev; /* Pointer to phyical dev -- set at runtime */ }; union URES { @@ -103,5 +111,5 @@ union URES { STORES res_store; DEVRES res_dev; MSGS res_msgs; - RES hdr; + RES hdr; }; diff --git a/bacula/src/tools/fstype.c b/bacula/src/tools/fstype.c index 458f776767..32abe6fa40 100644 --- a/bacula/src/tools/fstype.c +++ b/bacula/src/tools/fstype.c @@ -50,17 +50,17 @@ static void usage() int main (int argc, char *const *argv) { - POOLMEM *fs; int verbose = 0; int status = 0; int ch, i; + char fs[1000]; while ((ch = getopt(argc, argv, "v?")) != -1) { switch (ch) { - case 'v': + case 'v': verbose = 1; break; - case '?': + case '?': default: usage(); @@ -74,15 +74,14 @@ main (int argc, char *const *argv) } for (i = 0; i < argc; --argc, ++argv) { - if ((fs = fstype(*argv)) != NULL) { + if (fstype(*argv, fs, sizeof(fs))) { if (verbose) { - printf("%s: %s\n", *argv, fs); + printf("%s: %s\n", *argv, fs); } else { puts(fs); } - free(fs); } else { - fprintf(stderr, "%s: unknown\n", *argv); + fprintf(stderr, "%s: unknown\n", *argv); status = 1; } } diff --git a/bacula/src/version.h b/bacula/src/version.h index beaab4303c..f44707ce51 100644 --- a/bacula/src/version.h +++ b/bacula/src/version.h @@ -1,8 +1,8 @@ /* */ #undef VERSION -#define VERSION "1.37.1" -#define BDATE "07 January 2005" -#define LSMDATE "07Jan05" +#define VERSION "1.37.2" +#define BDATE "08 January 2005" +#define LSMDATE "08Jan05" /* Debug flags */ #undef DEBUG -- 2.39.5