]> git.sur5r.net Git - bacula/bacula/commitdiff
Merge branch 'master' into basejobv3
authorEric Bollengier <eric@eb.homelinux.org>
Fri, 14 Aug 2009 12:37:44 +0000 (14:37 +0200)
committerEric Bollengier <eric@eb.homelinux.org>
Fri, 14 Aug 2009 12:37:44 +0000 (14:37 +0200)
Conflicts:
bacula/src/filed/backup.c

73 files changed:
bacula/.gitignore
bacula/platforms/redhat/bacula.spec
bacula/src/cats/bvfs.c
bacula/src/cats/bvfs.h
bacula/src/cats/cats.h
bacula/src/dird/dird_conf.c
bacula/src/dird/restore.c
bacula/src/dird/ua_dotcmds.c
bacula/src/dird/ua_label.c
bacula/src/filed/acl.c
bacula/src/filed/backup.c
bacula/src/filed/filed.h
bacula/src/filed/protos.h
bacula/src/filed/restore.c
bacula/src/filed/xattr.c
bacula/src/filed/xattr.h
bacula/src/findlib/Makefile.in
bacula/src/jcr.h
bacula/src/lib/bnet.c
bacula/src/lib/bsock.h
bacula/src/lib/jcr.c
bacula/src/lib/lockmgr.c
bacula/src/lib/lockmgr.h
bacula/src/lib/protos.h
bacula/src/lib/rwlock.c
bacula/src/lib/signal.c
bacula/src/qt-console/bat.pro.in
bacula/src/qt-console/images/W.png [new file with mode: 0644]
bacula/src/qt-console/images/runit.png [new file with mode: 0644]
bacula/src/qt-console/job/job.cpp
bacula/src/qt-console/job/job.h
bacula/src/qt-console/job/job.ui
bacula/src/qt-console/main.qrc
bacula/src/qt-console/mediainfo/mediainfo.cpp
bacula/src/qt-console/run/run.cpp
bacula/src/qt-console/run/run.h
bacula/src/qt-console/run/run.ui
bacula/src/qt-console/storage/content.cpp [new file with mode: 0644]
bacula/src/qt-console/storage/content.h [new file with mode: 0644]
bacula/src/qt-console/storage/content.ui [new file with mode: 0644]
bacula/src/qt-console/storage/storage.cpp
bacula/src/qt-console/storage/storage.h
bacula/src/stored/acquire.c
bacula/src/stored/append.c
bacula/src/stored/askdir.c
bacula/src/stored/block.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/lock.c
bacula/src/stored/protos.h
bacula/src/stored/reserve.c
bacula/src/stored/spool.c
bacula/src/stored/stored.h
bacula/src/stored/stored_conf.c
bacula/src/stored/stored_conf.h
bacula/src/stored/wait.c
bacula/src/tools/bvfs_test.c
bacula/src/version.h
bacula/technotes
regress/.gitignore
regress/DartTestfile.txt.in
regress/all-disk-tests
regress/scripts/bacula-dir-tape.conf.in
regress/scripts/bacula-sd-2disk-drive.conf.in
regress/scripts/functions
regress/tests/acl-xattr-test [new file with mode: 0755]
regress/tests/backup-acl-test [deleted file]
regress/tests/big-virtual-changer-test [new file with mode: 0755]
regress/tests/regexwhere-test
regress/tests/strip-test
regress/tests/virtual-backup-test
regress/tests/virtual-backup2-test
regress/tests/virtual-changer-test

index b2be2e915507d7a6552e69c7c1adfc9072675ebb..5d0f544b58ccfef7183762f387926a9fceb36bec 100644 (file)
@@ -507,6 +507,7 @@ src/tools/bbatch
 src/tools/bregtest
 src/tools/grow
 src/tools/.libs
+src/tools/bvfs_test
 
 # src/tray-monitor/
 src/tray-monitor/tray-monitor.conf
index 7359b83d4111158287d1746550e646d98bb0aac5..1a6363a198f6433d04d530bbc9fa64117207010a 100644 (file)
@@ -81,7 +81,7 @@
 
 # choose database backend here
 # postgres, mysql, sqlite
-%define build_postgresql 1
+%define build_mysql 1
 
 # Build Service: Determine Distribution
 
@@ -220,7 +220,12 @@ Packager: %{_packager}
 Prefix: %{_prefix}
 
 Source0: http://www.prdownloads.sourceforge.net/bacula/%{name}-%{version}.tar.gz
+# opensuse build service changes the release itself
+%if 0%{?opensuse_bs}
+Source1: Release_Notes-%{version}-1.tar.gz
+%else
 Source1: Release_Notes-%{version}-%{release}.tar.gz
+%endif
 Source2: bacula-2.2.7-postgresql.patch
 
 # define the basic package description
@@ -345,6 +350,7 @@ Source2: bacula-2.2.7-postgresql.patch
 %define scil 1
 %endif
 
+
 # test for a platform definition
 %if !%{rhat} && !%{rhel} && !%{fed} && !%{wb3} && !%{suse} && !%{mdk}
 %{error: You must specify a platform. Please examine the spec file.}
@@ -413,7 +419,29 @@ exit 1
 %define _dist %(grep Mand /etc/mandrake-release)
 %endif
 %{?DISTNAME:%define _dist %{DISTNAME}}
+
+# only set Disribution if not in opensuse build service, as it sets it itself
+%if ! 0%{?opensuse_bs}
+%{?DISTNAME:%define _dist %{DISTNAME}}
 Distribution: %{_dist}
+%endif
+
+%if 0%{?opensuse_bs} &&  %{mysql} && %{suse}
+# needed in opensuse_bs, as rpm is installed during build process
+BuildRequires: libmysqlclient-devel
+BuildRequires: mysql-client
+BuildRequires: mysql
+%endif
+%if 0%{?opensuse_bs} &&  %{suse} && %{postgresql}
+BuildRequires: postgresql
+BuildRequires: postgresql-server
+%endif
+BuildRequires: openssl
+
+%if 0%{?opensuse_bs} && %{suse}
+BuildRequires: pwdutils
+BuildRequires: sysconfig
+%endif
 
 # should we turn on python support
 %define python 0
@@ -474,10 +502,13 @@ BuildRequires: glibc-static-devel
 BuildRequires: libtermcap-devel
 %endif
 %if !%{rh7} && !%{su9} && !%{su10} && !%{su102} && !%{su103} && !%{su110} && !%{su111} && !%{mdk} && !%{fc3} && !%{fc4} && !%{fc5} && !%{fc6} && !%{fc7} && !%{fc8} && !%{fc9}
-BuildRequires: libtermcap-devel
+#BuildRequires: libtermcap-devel
 %endif
 
-%if %{sqlite}
+%if %{sqlite} && %{su10}
+BuildRequires: sqlite2-devel
+%endif
+%if %{sqlite} && ! %{su10}
 BuildRequires: sqlite-devel
 %endif
 
@@ -671,15 +702,18 @@ Group: System Environment/Daemons
 This package installs the Bacula pdf and html documentation.
 
 # Must explicitly enable debug pkg on SuSE
+# but not in opensuse_bs
+%if ! 0%{?opensuse_bs}
 %if %{suse}
 %debug_package
 export LDFLAGS="${LDFLAGS} -L/usr/lib/termcap"
 %endif
+%endif
 
 %prep
 %setup
 %setup -T -D -b 1
-%setup -T -D -b 2
+#%setup -T -D -b 2
 
 %build
 
@@ -691,18 +725,18 @@ patch -p3 src/cats/postgresql.c < %SOURCE5
 
 # patch the make_sqlite_tables script for installation bindir
 #patch src/cats/make_sqlite_tables.in src/cats/make_sqlite_tables.in.patch
-patch src/cats/make_sqlite3_tables.in src/cats/make_sqlite3_tables.in.patch
+#patch src/cats/make_sqlite3_tables.in src/cats/make_sqlite3_tables.in.patch
 
 # patch the create_sqlite_database script for installation bindir
 #patch src/cats/create_sqlite_database.in src/cats/create_sqlite_database.in.patch
-patch src/cats/create_sqlite3_database.in src/cats/create_sqlite3_database.in.patch
+#patch src/cats/create_sqlite3_database.in src/cats/create_sqlite3_database.in.patch
 
 # patch the make_catalog_backup script for installation bindir
-patch src/cats/make_catalog_backup.in src/cats/make_catalog_backup.in.patch
+#patch src/cats/make_catalog_backup.in src/cats/make_catalog_backup.in.patch
 
 # patch the update_sqlite_tables script for installation bindir
 #patch src/cats/update_sqlite_tables.in src/cats/update_sqlite_tables.in.patch
-patch src/cats/update_sqlite3_tables.in src/cats/update_sqlite3_tables.in.patch
+#patch src/cats/update_sqlite3_tables.in src/cats/update_sqlite3_tables.in.patch
 
 # patch the bacula-dir init script to remove sqlite service
 %if %{sqlite} && %{su9}
@@ -762,8 +796,12 @@ export LDFLAGS="${LDFLAGS} -L/usr/lib64/python%{pyver}"
         --with-mysql \
 %endif
 %if %{sqlite}
+%if %{su9} || %{su10}
+        --with-sqlite \
+%else
         --with-sqlite3 \
 %endif
+%endif # sqlite?
 %if %{postgresql}
         --with-postgresql \
 %endif
@@ -831,6 +869,7 @@ rm -f $RPM_BUILD_ROOT%{script_dir}/gconsole
 
 # fixme - make installs the mysql scripts for sqlite build
 %if %{sqlite}
+rm -f $RPM_BUILD_ROOT%{script_dir}/startmysql
 rm -f $RPM_BUILD_ROOT%{script_dir}/stopmysql
 rm -f $RPM_BUILD_ROOT%{script_dir}/grant_mysql_privileges
 %endif
@@ -901,7 +940,12 @@ rm -f $RPM_BUILD_ROOT%{_sbindir}/bacula
 
 %clean
 [ "$RPM_BUILD_ROOT" != "/" ] && rm -rf "$RPM_BUILD_ROOT"
+%if 0%{?opensuse_bs}
+rm -f $RPM_BUILD_DIR/Release_Notes-%{version}-1.txt
+%else
 rm -f $RPM_BUILD_DIR/Release_Notes-%{version}-%{release}.txt
+%endif
+
 
 %if %{mysql}
 # MySQL specific files
@@ -918,6 +962,17 @@ rm -f $RPM_BUILD_DIR/Release_Notes-%{version}-%{release}.txt
 %endif
 
 %if %{sqlite}
+%if  %{su9} ||  %{su10}
+# use sqlite2 on SLE_10 and SLES9
+%files sqlite
+%defattr(-,root,root)
+%attr(-, root, %{daemon_group}) %{script_dir}/create_sqlite_database
+%attr(-, root, %{daemon_group}) %{script_dir}/drop_sqlite_database
+%attr(-, root, %{daemon_group}) %{script_dir}/grant_sqlite_privileges
+%attr(-, root, %{daemon_group}) %{script_dir}/make_sqlite_tables
+%attr(-, root, %{daemon_group}) %{script_dir}/drop_sqlite_tables
+%attr(-, root, %{daemon_group}) %{script_dir}/update_sqlite_tables
+%else
 %files sqlite
 %defattr(-,root,root)
 %attr(-, root, %{daemon_group}) %{script_dir}/create_sqlite3_database
@@ -926,8 +981,11 @@ rm -f $RPM_BUILD_DIR/Release_Notes-%{version}-%{release}.txt
 %attr(-, root, %{daemon_group}) %{script_dir}/make_sqlite3_tables
 %attr(-, root, %{daemon_group}) %{script_dir}/drop_sqlite3_tables
 %attr(-, root, %{daemon_group}) %{script_dir}/update_sqlite3_tables
+%endif # sqlite?
 %endif
 
+
+
 %if %{postgresql}
 %files postgresql
 %defattr(-,root,root)
@@ -937,9 +995,17 @@ rm -f $RPM_BUILD_DIR/Release_Notes-%{version}-%{release}.txt
 %attr(-, root, %{daemon_group}) %{script_dir}/drop_postgresql_tables
 %attr(-, root, %{daemon_group}) %{script_dir}/update_postgresql_tables
 %attr(-, root, %{daemon_group}) %{script_dir}/grant_postgresql_privileges
+# The rest is DB backend independent
 %endif
+# opensuse_bs: directories not owned by any package
+/etc/bacula
+/etc/log.d
+/etc/log.d/conf
+/etc/log.d/conf/logfiles
+/etc/log.d/conf/services
+/etc/log.d/scripts
+/etc/log.d/scripts/services
 
-# The rest is DB backend independent
 %if ! %{client_only}
 %attr(-, root, %{daemon_group}) %dir %{script_dir}
 %attr(-, root, %{daemon_group}) %{script_dir}/bacula
@@ -1110,10 +1176,15 @@ fi
 %if %{postgresql}
 %post postgresql
 %endif
-
 %if ! %{client_only}
 # add our links
 if [ "$1" -ge 1 ] ; then
+%if %{suse} && %{mysql}
+  /sbin/chkconfig --add mysql
+%endif
+%if %{suse} && %{postgresql}
+  /sbin/chkconfig --add postgresql
+%endif
   /sbin/chkconfig --add bacula-dir
   /sbin/chkconfig --add bacula-fd
   /sbin/chkconfig --add bacula-sd
@@ -1121,6 +1192,10 @@ fi
 %endif
 
 %if %{mysql}
+
+#check, if mysql can be called successfully at all
+if mysql 2>/dev/null bacula -e 'select * from Version;' ; then
+
 # test for an existing database
 # note: this ASSUMES no password has been set for bacula database
 DB_VER=`mysql 2>/dev/null bacula -e 'select * from Version;'|tail -n 1`
@@ -1144,6 +1219,7 @@ elif [ "$DB_VER" -lt "11" ]; then
     %{script_dir}/update_mysql_tables
     echo "If bacula works correctly you can remove the backup file %{working_dir}/bacula_backup.sql.bz2"
 
+fi
 fi
 %endif
 
@@ -1172,6 +1248,9 @@ fi
 %endif
 
 %if %{postgresql}
+# check if psql can be called successfully at all
+if echo 'select * from Version;' | psql bacula 2>/dev/null; then
+
 # test for an existing database
 # note: this ASSUMES no password has been set for bacula database
 DB_VER=`echo 'select * from Version;' | psql bacula 2>/dev/null | tail -3 | head -1`
@@ -1195,6 +1274,7 @@ elif [ "$DB_VER" -lt "11" ]; then
     %{script_dir}/update_postgresql_tables
     echo "If bacula works correctly you can remove the backup file %{working_dir}/bacula_backup.sql.bz2"
         
+fi
 fi
 %endif
 
@@ -1204,26 +1284,21 @@ if [ -d %{sysconf_dir} ]; then
    for string in XXX_REPLACE_WITH_DIRECTOR_PASSWORD_XXX XXX_REPLACE_WITH_CLIENT_PASSWORD_XXX XXX_REPLACE_WITH_STORAGE_PASSWORD_XXX XXX_REPLACE_WITH_DIRECTOR_MONITOR_PASSWORD_XXX XXX_REPLACE_WITH_CLIENT_MONITOR_PASSWORD_XXX XXX_REPLACE_WITH_STORAGE_MONITOR_PASSWORD_XXX; do
       pass=`openssl rand -base64 33`
       for file in *.conf; do
-         need_password=`grep ${string} $file 2>/dev/null`
-         if [ -n "$need_password" ]; then
-            sed "s@${string}@${pass}@g" $file > $file.new
-            cp -f $file.new $file; rm -f $file.new
-         fi
+         sed "s@${string}@${pass}@g" $file > $file.new
+         cp -f $file.new $file; rm -f $file.new
       done
    done
 # put actual hostname in conf file
    host=`hostname`
    string="XXX_HOSTNAME_XXX"
    for file in *.conf; do
-      need_host=`grep ${string} $file 2>/dev/null`
-      if [ -n "$need_host" ]; then
-         sed "s@${string}@${host}@g" $file >$file.new
-         cp -f $file.new $file; rm -f $file.new
-      fi
+      sed "s@${string}@${host}@g" $file >$file.new
+      cp -f $file.new $file; rm -f $file.new
    done
 fi
-/sbin/ldconfig
 %endif
+/sbin/ldconfig
+exit 0 # always exit successfull, as otherwise opensuse build service complains
 
 %if %{mysql}
 %preun mysql
@@ -1245,6 +1320,18 @@ fi
 /sbin/ldconfig
 %endif
 
+# added: run ldconfig in postun
+%if %{mysql}
+%postun mysql
+%endif
+%if %{sqlite}
+%postun sqlite
+%endif
+%if %{postgresql}
+%postun postgresql
+%endif
+/sbin/ldconfig
+
 %files client
 %defattr(-,root,root)
 %attr(-, root, %{daemon_group}) %dir %{script_dir}
@@ -1272,7 +1359,8 @@ fi
 %{_libdir}/libbacfind.*
 %{_libdir}/libbacpy.*
 /usr/share/doc/*
-
+#opensuse_bs: directories not owned by any package
+/etc/bacula
 
 %pre client
 # create the daemon group and user
@@ -1308,27 +1396,21 @@ if [ -d %{sysconf_dir} ]; then
    for string in XXX_REPLACE_WITH_DIRECTOR_PASSWORD_XXX XXX_REPLACE_WITH_CLIENT_PASSWORD_XXX XXX_REPLACE_WITH_STORAGE_PASSWORD_XXX XXX_REPLACE_WITH_DIRECTOR_MONITOR_PASSWORD_XXX XXX_REPLACE_WITH_CLIENT_MONITOR_PASSWORD_XXX XXX_REPLACE_WITH_STORAGE_MONITOR_PASSWORD_XXX; do
       pass=`openssl rand -base64 33`
       for file in *.conf; do
-         need_password=`grep ${string} $file 2>/dev/null`
-         if [ -n "$need_password" ]; then
-            sed "s@${string}@${pass}@g" $file > $file.new
-            cp -f $file.new $file; rm -f $file.new
-         fi
+         sed "s@${string}@${pass}@g" $file > $file.new
+         cp -f $file.new $file; rm -f $file.new
       done
    done
 # put actual hostname in conf file
    host=`hostname`
    string="XXX_HOSTNAME_XXX"
    for file in *.conf; do
-      need_host=`grep ${string} $file 2>/dev/null`
-      if [ -n "$need_host" ]; then
-         sed "s@${string}@${host}@g" $file >$file.new
-         cp -f $file.new $file; rm -f $file.new
-      fi
+      sed "s@${string}@${host}@g" $file >$file.new
+      cp -f $file.new $file; rm -f $file.new
    done
 fi
 
 /sbin/ldconfig
-
+exit 0
 %preun client
 # delete our link
 if [ $1 = 0 ]; then
@@ -1342,6 +1424,8 @@ fi
 %files updatedb
 %defattr(-,root,%{daemon_group})
 %{script_dir}/updatedb/*
+#oensuse_bs: directories not owned by any package
+%{script_dir}/updatedb
 
 %pre updatedb
 # create the daemon group
index 94e2e0c8a0171a9b710931f1efbc85f76acf108e..c27ab50fceedfe5ace7d25a88e1294c912dceec7 100644 (file)
@@ -438,6 +438,7 @@ void bvfs_update_cache(JCR *jcr, B_DB *mdb)
    Dmsg1(dbglevel, "Affected row(s) = %d\n", nb);
 
    db_end_transaction(jcr, mdb);
+   free_pool_memory(jobids);
 }
 
 /*
@@ -472,7 +473,7 @@ void Bvfs::update_cache()
 }
 
 /* Change the current directory, returns true if the path exists */
-bool Bvfs::ch_dir(char *path)
+bool Bvfs::ch_dir(const char *path)
 {
    pm_strcpy(db->path, path);
    db->pnl = strlen(db->path);
@@ -483,7 +484,7 @@ bool Bvfs::ch_dir(char *path)
 /* 
  * Get all file versions for a specified client
  */
-void Bvfs::get_all_file_versions(DBId_t pathid, DBId_t fnid, char *client)
+void Bvfs::get_all_file_versions(DBId_t pathid, DBId_t fnid, const char *client)
 {
    Dmsg3(dbglevel, "get_all_file_versions(%lld, %lld, %s)\n", (uint64_t)pathid,
          (uint64_t)fnid, client);
@@ -678,8 +679,8 @@ bool Bvfs::ls_files()
 "SELECT File.FilenameId, listfiles.Name, File.JobId, File.LStat, listfiles.id "
 "FROM File, ( "
        "SELECT Filename.Name as Name, max(File.FileId) as id "
-        "FROM File, Filename "
-       "WHERE File.FilenameId = Filename.FilenameId "
+         "FROM File, Filename "
+        "WHERE File.FilenameId = Filename.FilenameId "
           "AND Filename.Name != '' "
           "AND File.PathId = %s "
           "AND File.JobId IN (%s) "
index bc6d43656712cfa5a620908b8b980a4ddc4e5027..9abe7c485e7caf1f1ac24193006d8ba5097faf76 100644 (file)
@@ -106,12 +106,12 @@ public:
    /* 
     * Returns true if the directory exists
     */
-   bool ch_dir(char *path);
+   bool ch_dir(const char *path);
 
    bool ls_files();             /* Returns true if we have more files to read */
    bool ls_dirs();              /* Returns true if we have more dir to read */
    void ls_special_dirs();      /* get . and .. */
-   void get_all_file_versions(DBId_t pathid, DBId_t fnid, char *client);
+   void get_all_file_versions(DBId_t pathid, DBId_t fnid, const char *client);
 
    void update_cache();
 
index 5f889c93f1c5957ea150a72ae06131eadda067fd..283e4dc20a539cc8ff58c182f30386087809ddf8 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
index 2daba3b6873619d634b28a413042a726d1f88e93..69472202759b9f68fab768a9fa59b2e2e400de20 100644 (file)
@@ -949,7 +949,7 @@ next_run:
       sendit(sock, _("      MaxVolJobs=%d MaxVolFiles=%d MaxVolBytes=%s\n"),
               res->res_pool.MaxVolJobs, 
               res->res_pool.MaxVolFiles,
-              edit_uint64(res->res_pool.MaxVolFiles, ed1));
+              edit_uint64(res->res_pool.MaxVolBytes, ed1));
       sendit(sock, _("      MigTime=%s MigHiBytes=%s MigLoBytes=%s\n"),
               edit_utime(res->res_pool.MigrationTime, ed1, sizeof(ed1)),
               edit_uint64(res->res_pool.MigrationHighBytes, ed2),
index 82f798021a09fedfa87534a50d9c41635778a82f..e852edfe4c5b1436ce82c5b9c5d52c3897010aa3 100644 (file)
@@ -231,7 +231,7 @@ static bool check_for_new_storage(JCR *jcr, struct bootstrap_info &info)
 static bool send_bootstrap_file(JCR *jcr, BSOCK *sock,
                                 struct bootstrap_info &info)
 {
-   uint64_t pos;
+   boffset_t pos;
    const char *bootstrap = "bootstrap\n";
    UAContext *ua = info.ua;
    FILE *bs = info.bs;
@@ -241,17 +241,17 @@ static bool send_bootstrap_file(JCR *jcr, BSOCK *sock,
       return false;
    }
    sock->fsend(bootstrap);
-   pos = ftell(bs);
+   pos = ftello(bs);
    while(fgets(ua->cmd, UA_CMD_SIZE, bs)) {
       if (check_for_new_storage(jcr, info)) {
          /* Otherwise, we need to contact another storage daemon.
           * Reset bs to the beginning of the current segment. 
           */
-         fseek(bs, pos, SEEK_SET);
+         fseeko(bs, pos, SEEK_SET);
          break;
       }
       sock->fsend("%s", ua->cmd);
-      pos = ftell(bs);
+      pos = ftello(bs);
    }
    sock->signal(BNET_EOD);
    return true;
index 462d8ed27a3dbafceb513990983a9b6a2e1f8183..363d12fd8f453e03a4fd69bdfe049faedce8d843 100644 (file)
@@ -40,6 +40,8 @@
 
 #include "bacula.h"
 #include "dird.h"
+#include "cats/bvfs.h"
+#include "findlib/find.h"
 
 /* Imported variables */
 
@@ -64,6 +66,10 @@ static bool backupscmd(UAContext *ua, const char *cmd);
 static bool levelscmd(UAContext *ua, const char *cmd);
 static bool getmsgscmd(UAContext *ua, const char *cmd);
 
+static bool dot_lsdirs(UAContext *ua, const char *cmd);
+static bool dot_lsfiles(UAContext *ua, const char *cmd);
+static bool dot_update(UAContext *ua, const char *cmd);
+
 static bool api_cmd(UAContext *ua, const char *cmd);
 static bool sql_cmd(UAContext *ua, const char *cmd);
 static bool dot_quit_cmd(UAContext *ua, const char *cmd);
@@ -88,6 +94,9 @@ static struct cmdstruct commands[] = { /* help */  /* can be used in runscript *
  { NT_(".sql"),        sql_cmd,          NULL,       false},
  { NT_(".status"),     dot_status_cmd,   NULL,       false},
  { NT_(".storage"),    storagecmd,       NULL,       true},
+ { NT_(".lsdirs"),     dot_lsdirs,       NULL,       true},
+ { NT_(".lsfiles"),    dot_lsfiles,      NULL,       true},
+ { NT_(".update"),     dot_update,       NULL,       true},
  { NT_(".types"),      typescmd,         NULL,       false} 
              };
 #define comsize ((int)(sizeof(commands)/sizeof(struct cmdstruct)))
@@ -145,6 +154,167 @@ bool do_a_dot_command(UAContext *ua)
    return ok;
 }
 
+static bool dot_update(UAContext *ua, const char *cmd)
+{
+   if (!open_client_db(ua)) {
+      return 1;
+   }
+
+   int pos = find_arg_with_value(ua, "jobid");
+   if (pos != -1) {             /* find jobid arg */
+      if (is_a_number_list(ua->argv[pos])) {
+         bvfs_update_path_hierarchy_cache(ua->jcr, ua->db, ua->argv[pos]);
+      }
+   } else {
+      /* update cache for all jobids */
+      bvfs_update_cache(ua->jcr, ua->db);
+   }
+   return true;
+}
+
+static int bvfs_result_handler(void *ctx, int fields, char **row)
+{
+   UAContext *ua = (UAContext *)ctx;
+   struct stat statp;
+   int32_t LinkFI;
+   char empty[] = "A A A A A A A A A A A A A A";
+
+   memset(&statp, 0, sizeof(struct stat));
+   decode_stat((row[BVFS_LStat] && row[BVFS_LStat][0])?row[BVFS_LStat]:empty,
+               &statp, &LinkFI);
+
+   if (fields == BVFS_DIR_RECORD) {
+      char *path = bvfs_basename_dir(row[BVFS_Name]);
+      ua->send_msg("%s\t%s\t\%s\n", row[BVFS_Id], row[BVFS_JobId], path);
+   } else if (fields == BVFS_FILE_RECORD) {
+      ua->send_msg("%s\t%s\t\%s\n", row[BVFS_Id], row[BVFS_JobId], row[BVFS_Name]);
+   }
+
+   return 0;
+}
+
+static bool bvfs_parse_arg(UAContext *ua, 
+                           DBId_t *pathid, char **path, char **jobid,
+                           int *limit, int *offset)
+{
+   *pathid=0;
+   *limit=2000;
+   *offset=0;
+   *path=NULL;
+   *jobid=NULL;
+
+   for (int i=1; i<ua->argc; i++) {
+      if (strcasecmp(ua->argk[i], NT_("pathid")) == 0) {
+         if (is_a_number(ua->argv[i])) {
+            *pathid = str_to_int64(ua->argv[i]);
+         }
+      }
+      if (strcasecmp(ua->argk[i], NT_("path")) == 0) {
+         *path = ua->argv[i];
+      }
+      
+      if (strcasecmp(ua->argk[i], NT_("jobid")) == 0) {
+         if (is_a_number_list(ua->argv[i])) {
+            *jobid = ua->argv[i];
+         }
+      }
+
+      if (strcasecmp(ua->argk[i], NT_("limit")) == 0) {
+         if (is_a_number(ua->argv[i])) {
+            *limit = str_to_int64(ua->argv[i]);
+         }
+      }
+
+      if (strcasecmp(ua->argk[i], NT_("offset")) == 0) {
+         if (is_a_number(ua->argv[i])) {
+            *offset = str_to_int64(ua->argv[i]);
+         }
+      }
+   }
+
+   if (!((pathid || path) && jobid)) {
+      return false;
+   }
+
+   if (!open_client_db(ua)) {
+      return false;
+   }
+
+   return true;
+}
+
+/* 
+ * .lsfiles jobid=1,2,3,4 pathid=10
+ * .lsfiles jobid=1,2,3,4 path=/
+ */
+static bool dot_lsfiles(UAContext *ua, const char *cmd)
+{
+   DBId_t pathid=0;
+   int limit=2000, offset=0;
+   char *path=NULL, *jobid=NULL;
+
+   if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
+                       &limit, &offset))
+   {
+      ua->error_msg("Can't find jobid, pathid or path argument\n");
+      return true;              /* not enough param */
+   }
+
+   Bvfs fs(ua->jcr, ua->db);
+   fs.set_jobids(jobid);   
+   fs.set_handler(bvfs_result_handler, ua);
+   fs.set_limit(limit);
+
+   if (pathid) {
+      fs.ch_dir(pathid);
+   } else {
+      fs.ch_dir(path);
+   }
+
+   fs.set_offset(offset);
+
+   fs.ls_files();
+
+   return true;
+}
+
+/* 
+ * .lsdirs jobid=1,2,3,4 pathid=10
+ * .lsdirs jobid=1,2,3,4 path=/
+ * .lsdirs jobid=1,2,3,4 path=
+ */
+static bool dot_lsdirs(UAContext *ua, const char *cmd)
+{
+   DBId_t pathid=0;
+   int limit=2000, offset=0;
+   char *path=NULL, *jobid=NULL;
+
+   if (!bvfs_parse_arg(ua, &pathid, &path, &jobid,
+                       &limit, &offset))
+   {
+      ua->error_msg("Can't find jobid, pathid or path argument\n");
+      return true;              /* not enough param */
+   }
+
+   Bvfs fs(ua->jcr, ua->db);
+   fs.set_jobids(jobid);   
+   fs.set_limit(limit);
+   fs.set_handler(bvfs_result_handler, ua);
+
+   if (pathid) {
+      fs.ch_dir(pathid);
+   } else {
+      fs.ch_dir(path);
+   }
+
+   fs.set_offset(offset);
+
+   fs.ls_special_dirs();
+   fs.ls_dirs();
+
+   return true;
+}
+
 static bool dot_quit_cmd(UAContext *ua, const char *cmd)
 {
    quit_cmd(ua, cmd);
index b464be19c986d2431d10cf76f4aae26ef0e96d96..6d7e9fe90e86289738d947ae51ae592b0dfcc909 100644 (file)
@@ -1026,13 +1026,18 @@ void status_slots(UAContext *ua, STORE *store_r)
    POOL_DBR pr;
    vol_list_t *vl, *vol_list = NULL;
    MEDIA_DBR mr;
+   char ed1[50], ed2[50], ed3[50];
    char *slot_list;
    int max_slots;
    int drive;
    int i=1;
    /* output format */
-   const char *slot_api_empty_format="%i|||||\n";
-   const char *slot_api_full_format="%i|%i|%s|%s|%s|%s|\n";
+   const char *slot_api_empty_format="%i||||||||\n";
+
+   /* Slot|RealSlot|Volume|Bytes|Status|MediaType|Pool|LastW|Expire */
+   const char *slot_api_full_format="%i|%i|%s|%s|%s|%s|%s|%s|%s\n";
+
+   /* Slot | Volume | Status | MediaType | Pool */
    const char *slot_hformat=" %4i%c| %16s | %9s | %20s | %18s |\n";
 
    if (!open_client_db(ua)) {
@@ -1084,12 +1089,13 @@ void status_slots(UAContext *ua, STORE *store_r)
 
       if (!vl->VolName) {
          Dmsg1(100, "No VolName for Slot=%d.\n", vl->Slot);
-         if (!ua->api) {
+         if (ua->api) {
+            ua->send_msg(slot_api_empty_format, vl->Slot);
+
+         } else {
             ua->send_msg(slot_hformat,
                          vl->Slot, '*',
                          "?", "?", "?", "?");
-         } else {
-            ua->send_msg(slot_api_empty_format, vl->Slot);
          }
          continue;
       }
@@ -1097,11 +1103,12 @@ void status_slots(UAContext *ua, STORE *store_r)
       /* Hope that slots are ordered */
       for (; i < vl->Slot; i++) {
          if (slot_list[i]) {
-            if (!ua->api) {
+            if (ua->api) {
+               ua->send_msg(slot_api_empty_format, i);
+
+            } else {
                ua->send_msg(slot_hformat,
                             i, ' ', "", "", "", "");
-            } else {
-               ua->send_msg(slot_api_empty_format, i);
             }       
             slot_list[i]=0;
          }
@@ -1117,23 +1124,31 @@ void status_slots(UAContext *ua, STORE *store_r)
             strcpy(pr.Name, "?");
          }
 
-         if (!ua->api) {
+         if (ua->api) {
+            ua->send_msg(slot_api_full_format,
+                         vl->Slot, mr.Slot, mr.VolumeName, 
+                         edit_uint64(mr.VolBytes, ed1), 
+                         mr.VolStatus, mr.MediaType, pr.Name, 
+                         edit_uint64(mr.LastWritten, ed2),
+                         edit_uint64(mr.LastWritten+mr.VolRetention, ed3));
+         } else {
             /* Print information */
             ua->send_msg(slot_hformat,
                          vl->Slot, ((vl->Slot==mr.Slot)?' ':'*'),
                          mr.VolumeName, mr.VolStatus, mr.MediaType, pr.Name);
-         } else {
-            ua->send_msg(slot_api_full_format,
-                         vl->Slot, mr.Slot, mr.VolumeName, mr.VolStatus, 
-                         mr.MediaType, pr.Name);
          }
 
          db_unlock(ua->db);
          continue;
       } else {                  /* TODO: get information from catalog  */
-         ua->send_msg(slot_hformat,
-                      vl->Slot, '*',
-                      mr.VolumeName, "?", "?", "?");
+         if (ua->api) {
+            ua->send_msg(slot_api_empty_format, vl->Slot);
+
+         } else {
+            ua->send_msg(slot_hformat,
+                         vl->Slot, '*',
+                         mr.VolumeName, "?", "?", "?");
+         }
       }
       db_unlock(ua->db);
    }
@@ -1143,10 +1158,11 @@ void status_slots(UAContext *ua, STORE *store_r)
    for (; i <= max_slots; i++) {
       if (slot_list[i]) {
          if (!ua->api) {
+            ua->send_msg(slot_api_empty_format, i);
+
+         } else {
             ua->send_msg(slot_hformat,
                          i, ' ', "", "", "", "");
-         } else {
-            ua->send_msg(slot_api_empty_format, i);
          } 
          slot_list[i]=0;
       }
index feae14bc7b3070e985f958ba749b5f0b7e4baa9f..ca8313a2e3b3ae12aaa6b01a5557a38c50f26a54 100644 (file)
@@ -44,9 +44,6 @@
  * Its also interesting to see what the exact format of acl text is on
  * certain platforms and if they use they same encoding we might allow
  * different platform streams to be decoded on an other similar platform.
- * As we implement the decoding/restoring process as a big switch based
- * on the stream number being passed in extending the switching code is
- * easy.
  *
  *   Original written by Preben 'Peppe' Guldberg, December MMIV
  *   Major rewrite by Marco van Wieringen, November MMVIII
   
 #include "bacula.h"
 #include "filed.h"
+#include "acl.h"
   
 #if !defined(HAVE_ACL)
 /*
  * Entry points when compiled without support for ACLs or on an unsupported platform.
  */
-bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
-   return false;
+   return bacl_exit_fatal;
 }
 
-bool parse_acl_stream(JCR *jcr, int stream)
+bacl_exit_code parse_acl_stream(JCR *jcr, int stream)
 {
-   return false;
+   return bacl_exit_fatal;
 }
 #else
 /*
  * Send an ACL stream to the SD.
  */
-static bool send_acl_stream(JCR *jcr, int stream)
+static bacl_exit_code send_acl_stream(JCR *jcr, int stream)
 {
    BSOCK *sd = jcr->store_bsock;
    POOLMEM *msgsave;
 #ifdef FD_NO_SEND_TEST
-   return true;
+   return bacl_exit_ok;
 #endif
 
    /*
     * Sanity check
     */
    if (jcr->acl_data_len <= 0)
-      return true;
+      return bacl_exit_ok;
 
    /*
     * Send header
@@ -94,8 +92,7 @@ static bool send_acl_stream(JCR *jcr, int stream)
    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
             sd->bstrerror());
-
-      return false;
+      return bacl_exit_fatal;
    }
 
    /*
@@ -110,8 +107,7 @@ static bool send_acl_stream(JCR *jcr, int stream)
       sd->msglen = 0;
       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
             sd->bstrerror());
-
-      return false;
+      return bacl_exit_fatal;
    }
 
    jcr->JobBytes += sd->msglen;
@@ -119,47 +115,54 @@ static bool send_acl_stream(JCR *jcr, int stream)
    if (!sd->signal(BNET_EOD)) {
       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
             sd->bstrerror());
-
-      return false;
+      return bacl_exit_fatal;
    }
 
    Dmsg1(200, "ACL of file: %s successfully backed up!\n", jcr->last_fname);
-
-   return true;
+   return bacl_exit_ok;
 }
 
 #if defined(HAVE_AIX_OS)
 
 #include <sys/access.h>
 
-static bool aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+/*
+ * Define the supported ACL streams for this OS
+ */
+static int os_access_acl_streams[1] = { STREAM_ACL_AIX_TEXT };
+static int os_default_acl_streams[1] = { -1 };
+
+static bacl_exit_code aix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    char *acl_text;
 
    if ((acl_text = acl_get(jcr->last_fname)) != NULL) {
       jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
       actuallyfree(acl_text);
-
       return send_acl_stream(jcr, STREAM_ACL_AIX_TEXT);
    }
-
-   return false;
+   return bacl_exit_error;
 }
 
-static bool aix_parse_acl_stream(JCR *jcr, int stream)
+static bacl_exit_code aix_parse_acl_streams(JCR *jcr, int stream)
 {
    if (acl_put(jcr->last_fname, jcr->acl_data, 0) != 0) {
-      return false;
+      return bacl_exit_error;
    }
-
-   return true;
+   return bacl_exit_ok;
 }
 
-#elif defined(HAVE_DARWIN_OS) \
-   || defined(HAVE_FREEBSD_OS) \
-   || defined(HAVE_IRIX_OS) \
-   || defined(HAVE_OSF1_OS) \
-   || defined(HAVE_LINUX_OS)
+/*
+ * For this OS setup the build and parse function pointer to the OS specific functions.
+ */
+static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = aix_build_acl_streams;
+static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = aix_parse_acl_streams;
+
+#elif defined(HAVE_DARWIN_OS) || \
+      defined(HAVE_FREEBSD_OS) || \
+      defined(HAVE_IRIX_OS) || \
+      defined(HAVE_OSF1_OS) || \
+      defined(HAVE_LINUX_OS)
 
 #include <sys/types.h>
 
@@ -222,13 +225,12 @@ static acl_type_t bac_to_os_acltype(bacl_type acltype)
 #endif
    default:
       /*
-       * This should never happen, as the per os version function only tries acl
+       * This should never happen, as the per OS version function only tries acl
        * types supported on a certain platform.
        */
       ostype = (acl_type_t)ACL_TYPE_NONE;
       break;
    }
-
    return ostype;
 }
 
@@ -247,7 +249,8 @@ static bool acl_is_trivial(acl_t acl)
    */
    acl_entry_t ace;
    acl_tag_t tag;
-#if defined(HAVE_FREEBSD_OS) || defined(HAVE_LINUX_OS)
+#if defined(HAVE_FREEBSD_OS) || \
+    defined(HAVE_LINUX_OS)
    int entry_available;
 
    entry_available = acl_get_entry(acl, ACL_FIRST_ENTRY, &ace);
@@ -257,8 +260,7 @@ static bool acl_is_trivial(acl_t acl)
        * If we fail to get the tagtype we call the acl non-trivial.
        */
       if (acl_get_tag_type(ace, &tag) < 0)
-         return false;
-
+         return true;
       /*
        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
        */
@@ -266,10 +268,8 @@ static bool acl_is_trivial(acl_t acl)
           tag != ACL_GROUP_OBJ &&
           tag != ACL_OTHER)
          return false;
-
       entry_available = acl_get_entry(acl, ACL_NEXT_ENTRY, &ace);
    }
-
    return true;
 #elif defined(HAVE_IRIX_OS)
    int n;
@@ -286,7 +286,6 @@ static bool acl_is_trivial(acl_t acl)
           tag != ACL_OTHER_OBJ)
          return false;
    }
-
    return true;
 #elif defined(HAVE_OSF1_OS)
    int count;
@@ -296,7 +295,6 @@ static bool acl_is_trivial(acl_t acl)
 
    while (count > 0) {
       tag = ace->entry->acl_type;
-
       /*
        * Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
        */
@@ -304,18 +302,15 @@ static bool acl_is_trivial(acl_t acl)
           tag != ACL_GROUP_OBJ &&
           tag != ACL_OTHER)
          return false;
-
       /*
        * On Tru64, perm can also contain non-standard bits such as
        * PERM_INSERT, PERM_DELETE, PERM_MODIFY, PERM_LOOKUP, ...
        */
       if ((ace->entry->acl_perm & ~(ACL_READ | ACL_WRITE | ACL_EXECUTE)))
          return false;
-
       ace = ace->next;
       count--;
    }
-
    return true;
 #endif
 }
@@ -324,12 +319,12 @@ static bool acl_is_trivial(acl_t acl)
 /*
  * Generic wrapper around acl_get_file call.
  */
-static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
+static bacl_exit_code generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
 {
    acl_t acl;
-   int len;
    acl_type_t ostype;
    char *acl_text;
+   berrno be;
 
    ostype = bac_to_os_acltype(acltype);
    acl = acl_get_file(jcr->last_fname, ostype);
@@ -349,8 +344,9 @@ static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
        */
       if (acl->acl_cnt <= 0) {
          pm_strcpy(jcr->acl_data, "");
+         jcr->acl_data_len = 0;
          acl_free(acl);
-         return 0;
+         return bacl_exit_ok;
       }
 #endif
 
@@ -364,29 +360,28 @@ static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
           * So we don't send an ACL stream to the SD.
           */
          pm_strcpy(jcr->acl_data, "");
+         jcr->acl_data_len = 0;
          acl_free(acl);
-         return 0;
+         return bacl_exit_ok;
       }
 #endif
 
       if ((acl_text = acl_to_text(acl, NULL)) != NULL) {
-         len = pm_strcpy(jcr->acl_data, acl_text);
+         jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
          acl_free(acl);
          acl_free(acl_text);
-
-         return len;
+         return bacl_exit_ok;
       }
 
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("acl_to_text error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("acl_to_text error on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg2(100, "acl_to_text error file=%s ERR=%s\n",  
-         jcr->last_fname, be.bstrerror());
+            jcr->last_fname, be.bstrerror());
 
       pm_strcpy(jcr->acl_data, "");
+      jcr->acl_data_len = 0;
       acl_free(acl);
-
-      return 0;                       /* non-fatal error */
+      return bacl_exit_error;
    }
 
    /*
@@ -398,32 +393,38 @@ static int generic_get_acl_from_os(JCR *jcr, bacl_type acltype)
       case BACL_ENOTSUP:
          break;                       /* not supported */
 #endif
+      case ENOENT:
+         pm_strcpy(jcr->acl_data, "");
+         jcr->acl_data_len = 0;
+         return bacl_exit_ok;
       default:
-         berrno be;
          /* Some real error */
-         Jmsg2(jcr, M_ERROR, 0, _("acl_get_file error on file \"%s\": ERR=%s\n"),
-            jcr->last_fname, be.bstrerror());
+         Mmsg2(jcr->errmsg, _("acl_get_file error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
          Dmsg2(100, "acl_get_file error file=%s ERR=%s\n",  
-            jcr->last_fname, be.bstrerror());
+               jcr->last_fname, be.bstrerror());
 
          pm_strcpy(jcr->acl_data, "");
-         return 0;                    /* non-fatal error */
+         jcr->acl_data_len = 0;
+         return bacl_exit_error;
       }
    }
    /*
     * Not supported, just pretend there is nothing to see
     */
    pm_strcpy(jcr->acl_data, "");
-   return 0;
+   jcr->acl_data_len = 0;
+   return bacl_exit_ok;
 }
 
 /*
  * Generic wrapper around acl_set_file call.
  */
-static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
+static bacl_exit_code generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
 {
    acl_t acl;
    acl_type_t ostype;
+   berrno be;
 
    /*
     * If we get empty default ACLs, clear ACLs now
@@ -431,40 +432,39 @@ static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
    ostype = bac_to_os_acltype(acltype);
    if (ostype == ACL_TYPE_DEFAULT && strlen(jcr->acl_data) == 0) {
       if (acl_delete_def_file(jcr->last_fname) == 0) {
-         return true;
+         return bacl_exit_ok;
+      }
+      switch (errno) {
+      case ENOENT:
+         return bacl_exit_ok;
+      default:
+         Mmsg2(jcr->errmsg, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         return bacl_exit_error;
       }
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("acl_delete_def_file error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
-
-      return false;
    }
 
    acl = acl_from_text(jcr->acl_data);
    if (acl == NULL) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("acl_from_text error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("acl_from_text error on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg3(100, "acl_from_text error acl=%s file=%s ERR=%s\n",  
          jcr->acl_data, jcr->last_fname, be.bstrerror());
-
-      return false;
+      return bacl_exit_error;
    }
 
+#ifndef HAVE_FREEBSD_OS
    /*
     * FreeBSD always fails acl_valid() - at least on valid input...
     * As it does the right thing, given valid input, just ignore acl_valid().
     */
-#ifndef HAVE_FREEBSD_OS
    if (acl_valid(acl) != 0) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("ac_valid error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("acl_valid error on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg3(100, "acl_valid error acl=%s file=%s ERR=%s\n",  
          jcr->acl_data, jcr->last_fname, be.bstrerror());
       acl_free(acl);
-
-      return false;
+      return bacl_exit_error;
    }
 #endif
 
@@ -475,25 +475,34 @@ static bool generic_set_acl_on_os(JCR *jcr, bacl_type acltype)
     * don't save acls of symlinks (which cannot have acls anyhow)
     */
    if (acl_set_file(jcr->last_fname, ostype, acl) != 0 && jcr->last_type != FT_LNK) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("acl_set_file error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
-      Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",  
-         jcr->acl_data, jcr->last_fname, be.bstrerror());
-      acl_free(acl);
-
-      return false;
+      switch (errno) {
+      case ENOENT:
+         acl_free(acl);
+         return bacl_exit_ok;
+      default:
+         Mmsg2(jcr->errmsg, _("acl_set_file error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg3(100, "acl_set_file error acl=%s file=%s ERR=%s\n",
+               jcr->acl_data, jcr->last_fname, be.bstrerror());
+         acl_free(acl);
+         return bacl_exit_error;
+      }
    }
    acl_free(acl);
-
-   return true;
+   return bacl_exit_ok;
 }
 
 /*
  * OS specific functions for handling different types of acl streams.
  */
 #if defined(HAVE_DARWIN_OS)
-static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+/*
+ * Define the supported ACL streams for this OS
+ */
+static int os_access_acl_streams[1] = { STREAM_ACL_DARWIN_ACCESS_ACL };
+static int os_default_acl_streams[1] = { -1 };
+
+static bacl_exit_code darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
 #if defined(ACL_TYPE_EXTENDED)
    /*
@@ -505,189 +514,145 @@ static bool darwin_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
     *
     * Read access ACLs for files, dirs and links
     */
-   if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED)) < 0)
-      return false;
+   if (generic_get_acl_from_os(jcr, BACL_TYPE_EXTENDED) == bacl_exit_fatal)
+      return bacl_exit_fatal;
 #else
    /*
     * Read access ACLs for files, dirs and links
     */
-   if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
-      return false;
+   if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
+      return bacl_exit_fatal;
 #endif
 
    if (jcr->acl_data_len > 0) {
-      if (!send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL))
-         return false;
+      return send_acl_stream(jcr, STREAM_ACL_DARWIN_ACCESS_ACL);
    }
-
-   return true;
+   return bacl_exit_ok;
 }
 
-static bool darwin_parse_acl_stream(JCR *jcr, int stream)
+static bacl_exit_code darwin_parse_acl_streams(JCR *jcr, int stream)
 {
-   switch (stream) {
-   case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_ACL_DARWIN_ACCESS_ACL:
+#if defined(ACL_TYPE_EXTENDED)
+      return generic_set_acl_on_os(jcr, BACL_TYPE_EXTENDED);
+#else
       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
-   }
-
-   return false;
+#endif
 }
-#elif defined(HAVE_FREEBSD_OS)
-static bool freebsd_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
-   /*
-    * Read access ACLs for files, dirs and links
-    */
-   if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
-      return false;
-
-   if (jcr->acl_data_len > 0) {
-      if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_ACCESS_ACL))
-         return false;
-   }
-
-   /*
-    * Directories can have default ACLs too
-    */
-   if (ff_pkt->type == FT_DIREND) {
-      if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
-         return false;
 
-      if (jcr->acl_data_len > 0) {
-         if (!send_acl_stream(jcr, STREAM_ACL_FREEBSD_DEFAULT_ACL))
-            return false;
-      }
-   }
-
-   return true;
-}
+/*
+ * For this OS setup the build and parse function pointer to the OS specific functions.
+ */
+static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = darwin_build_acl_streams;
+static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = darwin_parse_acl_streams;
 
-static bool freebsd_parse_acl_stream(JCR *jcr, int stream)
-{
-   switch (stream) {
-   case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_ACL_FREEBSD_ACCESS_ACL:
-      return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
-   case STREAM_UNIX_DEFAULT_ACL:
-   case STREAM_ACL_FREEBSD_DEFAULT_ACL:
-      return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
-   }
+#elif defined(HAVE_FREEBSD_OS) || \
+      defined(HAVE_IRIX_OS) || \
+      defined(HAVE_LINUX_OS)
 
-   return false;
-}
+/*
+ * Define the supported ACL streams for these OSes
+ */
+#if defined(HAVE_FREEBSD_OS)
+static int os_access_acl_streams[1] = { STREAM_ACL_FREEBSD_ACCESS_ACL };
+static int os_default_acl_streams[1] = { STREAM_ACL_FREEBSD_DEFAULT_ACL };
 #elif defined(HAVE_IRIX_OS)
-static bool irix_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+static int os_access_acl_streams[1] = { STREAM_ACL_IRIX_ACCESS_ACL };
+static int os_default_acl_streams[1] = { STREAM_ACL_IRIX_DEFAULT_ACL };
+#elif defined(HAVE_LINUX_OS)
+static int os_access_acl_streams[1] = { STREAM_ACL_LINUX_ACCESS_ACL };
+static int os_default_acl_streams[1] = { STREAM_ACL_LINUX_DEFAULT_ACL };
+#endif
+
+static bacl_exit_code generic_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    /*
     * Read access ACLs for files, dirs and links
     */
-   if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
-      return false;
+   if (generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS) == bacl_exit_fatal)
+      return bacl_exit_fatal;
 
    if (jcr->acl_data_len > 0) {
-      if (!send_acl_stream(jcr, STREAM_ACL_IRIX_ACCESS_ACL))
-         return false;
+      if (send_acl_stream(jcr, os_access_acl_streams[0]) == bacl_exit_fatal)
+         return bacl_exit_fatal;
    }
 
    /*
     * Directories can have default ACLs too
     */
    if (ff_pkt->type == FT_DIREND) {
-      if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
-         return false;
-
+      if (generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT) == bacl_exit_fatal)
+         return bacl_exit_fatal;
       if (jcr->acl_data_len > 0) {
-         if (!send_acl_stream(jcr, STREAM_ACL_IRIX_DEFAULT_ACL))
-            return false;
+         if (send_acl_stream(jcr, os_default_acl_streams[0]) == bacl_exit_fatal)
+            return bacl_exit_fatal;
       }
    }
-
-   return true;
+   return bacl_exit_ok;
 }
 
-static bool irix_parse_acl_stream(JCR *jcr, int stream)
+static bacl_exit_code generic_parse_acl_streams(JCR *jcr, int stream)
 {
+   unsigned int cnt;
+
    switch (stream) {
    case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_ACL_IRIX_ACCESS_ACL:
       return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
    case STREAM_UNIX_DEFAULT_ACL:
-   case STREAM_ACL_IRIX_DEFAULT_ACL:
       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
-   }
-
-   return false;
-}
-#elif defined(HAVE_LINUX_OS)
-static bool linux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
-   /*
-    * Read access ACLs for files, dirs and links
-    */
-   if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
-      return false;
-
-   if (jcr->acl_data_len > 0) {
-      if (!send_acl_stream(jcr, STREAM_ACL_LINUX_ACCESS_ACL))
-         return false;
-   }
-
-   /*
-    * Directories can have default ACLs too
-    */
-   if (ff_pkt->type == FT_DIREND) {
-      if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
-         return false;
-
-      if (jcr->acl_data_len > 0) {
-         if (!send_acl_stream(jcr, STREAM_ACL_LINUX_DEFAULT_ACL))
-            return false;
+   default:
+      /*
+       * See what type of acl it is.
+       */
+      for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
+         if (os_access_acl_streams[cnt] == stream) {
+            return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
+         }
       }
+      for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
+         if (os_default_acl_streams[cnt] == stream) {
+            return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
+         }
+      }
+      break;
    }
-
-   return true;
+   return bacl_exit_error;
 }
 
-static bool linux_parse_acl_stream(JCR *jcr, int stream)
-{
-   switch (stream) {
-   case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_ACL_LINUX_ACCESS_ACL:
-      return generic_set_acl_on_os(jcr, BACL_TYPE_ACCESS);
-   case STREAM_UNIX_DEFAULT_ACL:
-   case STREAM_ACL_LINUX_DEFAULT_ACL:
-      return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT);
-   }
+/*
+ * For this OSes setup the build and parse function pointer to the OS specific functions.
+ */
+static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_build_acl_streams;
+static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = generic_parse_acl_streams;
 
-   return false;
-}
 #elif defined(HAVE_OSF1_OS)
-static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+
+/*
+ * Define the supported ACL streams for this OS
+ */
+static int os_access_acl_streams[1] = { STREAM_ACL_TRU64_ACCESS_ACL };
+static int os_default_acl_streams[2] = { STREAM_ACL_TRU64_DEFAULT_ACL, STREAM_ACL_TRU64_DEFAULT_DIR_ACL };
+
+static bacl_exit_code tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    /*
     * Read access ACLs for files, dirs and links
     */
    if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_ACCESS)) < 0)
-      return false;
-
+      return bacl_exit_error;
    if (jcr->acl_data_len > 0) {
       if (!send_acl_stream(jcr, STREAM_ACL_TRU64_ACCESS_ACL))
-         return false;
+         return bacl_exit_error;
    }
-
    /*
     * Directories can have default ACLs too
     */
    if (ff_pkt->type == FT_DIREND) {
       if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT)) < 0)
-         return false;
-
+         return bacl_exit_error;
       if (jcr->acl_data_len > 0) {
          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_ACL))
-            return false;
+            return bacl_exit_error;
       }
-
       /*
        * Tru64 has next to BACL_TYPE_DEFAULT also BACL_TYPE_DEFAULT_DIR acls.
        * This is an inherited acl for all subdirs.
@@ -695,18 +660,16 @@ static bool tru64_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
        * Section 21.5 Default ACLs 
        */
       if ((jcr->acl_data_len = generic_get_acl_from_os(jcr, BACL_TYPE_DEFAULT_DIR)) < 0)
-         return false;
-
+         return bacl_exit_error;
       if (jcr->acl_data_len > 0) {
          if (!send_acl_stream(jcr, STREAM_ACL_TRU64_DEFAULT_DIR_ACL))
-            return false;
+            return bacl_exit_error;
       }
    }
-
-   return true;
+   return bacl_exit_ok;
 }
 
-static bool tru64_parse_acl_stream(JCR *jcr, int stream)
+static bacl_exit_code tru64_parse_acl_streams(JCR *jcr, int stream)
 {
    switch (stream) {
    case STREAM_UNIX_ACCESS_ACL:
@@ -718,6 +681,13 @@ static bool tru64_parse_acl_stream(JCR *jcr, int stream)
    case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
       return generic_set_acl_on_os(jcr, BACL_TYPE_DEFAULT_DIR);
 }
+
+/*
+ * For this OS setup the build and parse function pointer to the OS specific functions.
+ */
+static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = tru64_build_acl_streams;
+static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = tru64_parse_acl_streams;
+
 #endif
 
 #elif defined(HAVE_HPUX_OS)
@@ -729,6 +699,12 @@ static bool tru64_parse_acl_stream(JCR *jcr, int stream)
 
 #include <acllib.h>
 
+/*
+ * Define the supported ACL streams for this OS
+ */
+static int os_access_acl_streams[1] = { STREAM_ACL_HPUX_ACL_ENTRY };
+static int os_default_acl_streams[1] = { -1 };
+
 /*
  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
  * There is no need to store those acls as we already store the stat bits too.
@@ -740,7 +716,6 @@ static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
 
    for (n = 0; n < count; n++) {
       ace = entries[n];
-
       /*
        * See if this acl just is the stat mode in acl form.
        */
@@ -749,46 +724,50 @@ static bool acl_is_trivial(int count, struct acl_entry *entries, struct stat sb)
             (ace.uid == ACL_NSUSER && ace.gid == ACL_NSGROUP)))
          return false;
    }
-
    return true;
 }
 
 /*
  * OS specific functions for handling different types of acl streams.
  */
-static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+static bacl_exit_code hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    int n;
    struct acl_entry acls[NACLENTRIES];
    char *acl_text;
+   berrno be;
 
    if ((n = getacl(jcr->last_fname, 0, acls)) < 0) {
-      switch(errno) {
+      switch (errno) {
 #if defined(BACL_ENOTSUP)
       case BACL_ENOTSUP:
          /*
           * Not supported, just pretend there is nothing to see
           */
          pm_strcpy(jcr->acl_data, "");
-         return true;
+         jcr->acl_data_len = 0;
+         return bacl_exit_ok;
 #endif
+      case ENOENT:
+         pm_strcpy(jcr->acl_data, "");
+         jcr->acl_data_len = 0;
+         return bacl_exit_ok;
       default:
-         berrno be;
-         Jmsg2(jcr, M_ERROR, 0, _("getacl error on file \"%s\": ERR=%s\n"),
-            jcr->last_fname, be.bstrerror());
+         Mmsg2(jcr->errmsg, _("getacl error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
          Dmsg2(100, "getacl error file=%s ERR=%s\n",  
-            jcr->last_fname, be.bstrerror());
+               jcr->last_fname, be.bstrerror());
 
          pm_strcpy(jcr->acl_data, "");
-         return false;
+         jcr->acl_data_len = 0;
+         return bacl_exit_error;
       }
    }
-
    if (n == 0) {
       pm_strcpy(jcr->acl_data, "");
-      return true;
+      jcr->acl_data_len = 0;
+      return bacl_exit_ok;
    }
-
    if ((n = getacl(jcr->last_fname, n, acls)) > 0) {
       if (acl_is_trivial(n, acls, ff_pkt->statp)) {
          /*
@@ -796,51 +775,45 @@ static bool hpux_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
           * So we don't send an ACL stream to the SD.
           */
          pm_strcpy(jcr->acl_data, "");
-         return true;
+         jcr->acl_data_len = 0;
+         return bacl_exit_ok;
       }
-
       if ((acl_text = acltostr(n, acls, FORM_SHORT)) != NULL) {
          jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
          actuallyfree(acl_text);
 
          return send_acl_stream(jcr, STREAM_ACL_HPUX_ACL_ENTRY);
       }
-
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("acltostr error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("acltostr error on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg3(100, "acltostr error acl=%s file=%s ERR=%s\n",  
-         jcr->acl_data, jcr->last_fname, be.bstrerror());
-
-      return false;
+            jcr->acl_data, jcr->last_fname, be.bstrerror());
+      return bacl_exit_error;
    }
-
-   return false;
+   return bacl_exit_error;
 }
 
-static bool hpux_parse_acl_stream(JCR *jcr, int stream)
+static bacl_exit_code hpux_parse_acl_streams(JCR *jcr, int stream)
 {
    int n, stat;
    struct acl_entry acls[NACLENTRIES];
+   berrno be;
 
    n = strtoacl(jcr->acl_data, 0, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP);
    if (n <= 0) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
-         jcr->acl_data, jcr->last_fname, be.bstrerror());
-
-      return false;
+            jcr->acl_data, jcr->last_fname, be.bstrerror());
+      return bacl_exit_error;
    }
    if (strtoacl(jcr->acl_data, n, NACLENTRIES, acls, ACL_FILEOWNER, ACL_FILEGROUP) != n) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("strtoacl error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("strtoacl error on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg3(100, "strtoacl error acl=%s file=%s ERR=%s\n",  
-         jcr->acl_data, jcr->last_fname, be.bstrerror());
+            jcr->acl_data, jcr->last_fname, be.bstrerror());
 
-      return false;
+      return bacl_exit_error;
    }
    /*
     * Restore the ACLs, but don't complain about links which really should
@@ -849,18 +822,26 @@ static bool hpux_parse_acl_stream(JCR *jcr, int stream)
     * don't save acls of symlinks (which cannot have acls anyhow)
     */
    if (setacl(jcr->last_fname, n, acls) != 0 && jcr->last_type != FT_LNK) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("setacl error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
-      Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",  
-         jcr->acl_data, jcr->last_fname, be.bstrerror());
-
-      return false;
+      switch (errno) {
+      case ENOENT:
+         return bacl_exit_ok;
+      default:
+         Mmsg2(jcr->errmsg, _("setacl error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg3(100, "setacl error acl=%s file=%s ERR=%s\n",
+               jcr->acl_data, jcr->last_fname, be.bstrerror());
+         return bacl_exit_error;
+      }
    }
-
-   return true;
+   return bacl_exit_ok;
 }
 
+/*
+ * For this OS setup the build and parse function pointer to the OS specific functions.
+ */
+static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = hpux_build_acl_streams;
+static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = hpux_parse_acl_streams;
+
 #elif defined(HAVE_SUN_OS)
 #ifdef HAVE_SYS_ACL_H
 #include <sys/acl.h>
@@ -876,7 +857,7 @@ static bool hpux_parse_acl_stream(JCR *jcr, int stream)
  * and versions of Solaris we need to expose some data to be able
  * to determine the type of acl used to stuff it into the correct
  * data stream. I know this is far from portable, but maybe the
- * propper interface is exposed later on and we can get ride of
+ * proper interface is exposed later on and we can get ride of
  * this kludge. Newer versions of Solaris include sys/acl_impl.h
  * which has implementation details of acls, if thats included we
  * don't have to define it ourself.
@@ -896,18 +877,24 @@ int acl_type(acl_t *);
 char *acl_strerror(int);
 }
 
+/*
+ * Define the supported ACL streams for this OS
+ */
+static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT, STREAM_ACL_SOLARIS_ACE };
+static int os_default_acl_streams[1] = { -1 };
+
 /*
  * As the new libsec interface with acl_totext and acl_fromtext also handles
  * the old format from acltotext we can use the new functions even
  * for acls retrieved and stored in the database with older fd versions. If the
  * new interface is not defined (Solaris 9 and older we fall back to the old code)
  */
-static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    int acl_enabled, flags;
    acl_t *aclp;
    char *acl_text;
-   bool stream_status = false;
+   bacl_exit_code stream_status = bacl_exit_error;
    berrno be;
 
    /*
@@ -917,15 +904,19 @@ static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
    switch (acl_enabled) {
    case 0:
       pm_strcpy(jcr->acl_data, "");
-
-      return true;
+      jcr->acl_data_len = 0;
+      return bacl_exit_ok;
    case -1:
-      Jmsg2(jcr, M_ERROR, 0, _("pathconf error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
-      Dmsg2(100, "pathconf error file=%s ERR=%s\n",  
-         jcr->last_fname, be.bstrerror());
-
-      return false;
+      switch (errno) {
+      case ENOENT:
+         return bacl_exit_ok;
+      default:
+         Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg2(100, "pathconf error file=%s ERR=%s\n",  
+               jcr->last_fname, be.bstrerror());
+         return bacl_exit_error;
+      }
    default:
       break;
    }
@@ -934,12 +925,16 @@ static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
     * Get ACL info: don't bother allocating space if there is only a trivial ACL.
     */
    if (acl_get(jcr->last_fname, ACL_NO_TRIVIAL, &aclp) != 0) {
-      Jmsg2(jcr, M_ERROR, 0, _("acl_get error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, acl_strerror(errno));
-      Dmsg2(100, "acl_get error file=%s ERR=%s\n",  
-         jcr->last_fname, acl_strerror(errno));
-
-      return false;
+      switch (errno) {
+      case ENOENT:
+         return bacl_exit_ok;
+      default:
+         Mmsg2(jcr->errmsg, _("acl_get error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, acl_strerror(errno));
+         Dmsg2(100, "acl_get error file=%s ERR=%s\n",  
+               jcr->last_fname, acl_strerror(errno));
+         return bacl_exit_error;
+      }
    }
 
    if (!aclp) {
@@ -948,7 +943,8 @@ static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
        * So we don't send an ACL stream to the SD.
        */
       pm_strcpy(jcr->acl_data, "");
-      return true;
+      jcr->acl_data_len = 0;
+      return bacl_exit_ok;
    }
 
 #if defined(ACL_SID_FMT)
@@ -977,11 +973,10 @@ static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 
       acl_free(aclp);
    }
-
    return stream_status;
 }
 
-static bool solaris_parse_acl_stream(JCR *jcr, int stream)
+static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
 {
    acl_t *aclp;
    int acl_enabled, error;
@@ -997,17 +992,20 @@ static bool solaris_parse_acl_stream(JCR *jcr, int stream)
       acl_enabled = pathconf(jcr->last_fname, _PC_ACL_ENABLED);
       switch (acl_enabled) {
       case 0:
-         Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
-            jcr->last_fname);
-
-         return false;
+         Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without acl support\n"),
+               jcr->last_fname);
+         return bacl_exit_error;
       case -1:
-         Jmsg2(jcr, M_ERROR, 0, _("pathconf error on file \"%s\": ERR=%s\n"),
-            jcr->last_fname, be.bstrerror());
-         Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",  
-            jcr->acl_data, jcr->last_fname, be.bstrerror());
-
-         return false;
+         switch (errno) {
+         case ENOENT:
+            return bacl_exit_ok;
+         default:
+            Mmsg2(jcr->errmsg, _("pathconf error on file \"%s\": ERR=%s\n"),
+                  jcr->last_fname, be.bstrerror());
+            Dmsg3(100, "pathconf error acl=%s file=%s ERR=%s\n",  
+                  jcr->acl_data, jcr->last_fname, be.bstrerror());
+            return bacl_exit_error;
+         }
       default:
          /*
           * On a filesystem with ACL support make sure this particilar ACL type can be restored.
@@ -1018,9 +1016,9 @@ static bool solaris_parse_acl_stream(JCR *jcr, int stream)
              * An aclent can be restored on filesystems with _ACL_ACLENT_ENABLED or _ACL_ACE_ENABLED support.
              */
             if ((acl_enabled & (_ACL_ACLENT_ENABLED | _ACL_ACE_ENABLED)) == 0) {
-               Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
-                  jcr->last_fname);
-               return false;
+               Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without aclent acl support\n"),
+                     jcr->last_fname);
+               return bacl_exit_error;
             }
             break;
          case STREAM_ACL_SOLARIS_ACE:
@@ -1028,9 +1026,9 @@ static bool solaris_parse_acl_stream(JCR *jcr, int stream)
              * An ace can only be restored on a filesystem with _ACL_ACE_ENABLED support.
              */
             if ((acl_enabled & _ACL_ACE_ENABLED) == 0) {
-               Jmsg1(jcr, M_ERROR, 0, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
-                  jcr->last_fname);
-               return false;
+               Mmsg1(jcr->errmsg, _("Trying to restore acl on file \"%s\" on filesystem without ace acl support\n"),
+                     jcr->last_fname);
+               return bacl_exit_error;
             }
             break;
          default:
@@ -1043,11 +1041,11 @@ static bool solaris_parse_acl_stream(JCR *jcr, int stream)
       }
 
       if ((error = acl_fromtext(jcr->acl_data, &aclp)) != 0) {
-         Jmsg2(jcr, M_ERROR, 0, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
-            jcr->last_fname, acl_strerror(error));
+         Mmsg2(jcr->errmsg, _("acl_fromtext error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, acl_strerror(error));
          Dmsg3(100, "acl_fromtext error acl=%s file=%s ERR=%s\n",  
-            jcr->acl_data, jcr->last_fname, acl_strerror(error));
-         return false;
+               jcr->acl_data, jcr->last_fname, acl_strerror(error));
+         return bacl_exit_error;
       }
 
       /*
@@ -1056,16 +1054,16 @@ static bool solaris_parse_acl_stream(JCR *jcr, int stream)
       switch (stream) {
       case STREAM_ACL_SOLARIS_ACLENT:
          if (acl_type(aclp) != ACLENT_T) {
-            Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
-               jcr->last_fname);
-            return false;
+            Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
+                  jcr->last_fname);
+            return bacl_exit_error;
          }
          break;
       case STREAM_ACL_SOLARIS_ACE:
          if (acl_type(aclp) != ACE_T) {
-            Jmsg1(jcr, M_ERROR, 0, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
-               jcr->last_fname);
-            return false;
+            Mmsg1(jcr->errmsg, _("wrong encoding of acl type in acl stream on file \"%s\"\n"),
+                  jcr->last_fname);
+            return bacl_exit_error;
          }
          break;
       default:
@@ -1082,24 +1080,35 @@ static bool solaris_parse_acl_stream(JCR *jcr, int stream)
        * don't save acls of symlinks (which cannot have acls anyhow)
        */
       if ((error = acl_set(jcr->last_fname, aclp)) == -1 && jcr->last_type != FT_LNK) {
-         Jmsg2(jcr, M_ERROR, 0, _("acl_set error on file \"%s\": ERR=%s\n"),
-            jcr->last_fname, acl_strerror(error));
-         Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",  
-            jcr->acl_data, jcr->last_fname, acl_strerror(error));
-
-         acl_free(aclp);
-         return false;
+         switch (errno) {
+         case ENOENT:
+            acl_free(aclp);
+            return bacl_exit_ok;
+         default:
+            Mmsg2(jcr->errmsg, _("acl_set error on file \"%s\": ERR=%s\n"),
+                  jcr->last_fname, acl_strerror(error));
+            Dmsg3(100, "acl_set error acl=%s file=%s ERR=%s\n",  
+                  jcr->acl_data, jcr->last_fname, acl_strerror(error));
+            acl_free(aclp);
+            return bacl_exit_error;
+         }
       }
 
       acl_free(aclp);
-      return true;
+      return bacl_exit_ok;
    default:
-      return false;
+      return bacl_exit_error;
    } /* end switch (stream) */
 }
 
 #else /* HAVE_EXTENDED_ACL */
 
+/*
+ * Define the supported ACL streams for this OS
+ */
+static int os_access_acl_streams[2] = { STREAM_ACL_SOLARIS_ACLENT };
+static int os_default_acl_streams[1] = { -1 };
+
 /*
  * See if an acl is a trivial one (e.g. just the stat bits encoded as acl.)
  * There is no need to store those acls as we already store the stat bits too.
@@ -1118,22 +1127,22 @@ static bool acl_is_trivial(int count, aclent_t *entries)
             ace->a_type == CLASS_OBJ))
         return false;
    }
-
    return true;
 }
 
 /*
  * OS specific functions for handling different types of acl streams.
  */
-static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    int n;
    aclent_t *acls;
    char *acl_text;
+   berrno be;
 
    n = acl(jcr->last_fname, GETACLCNT, 0, NULL);
    if (n < MIN_ACL_ENTRIES)
-      return false;
+      return bacl_exit_error;
 
    acls = (aclent_t *)malloc(n * sizeof(aclent_t));
    if (acl(jcr->last_fname, GETACL, n, acls) == n) {
@@ -1144,42 +1153,40 @@ static bool solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
           */
          free(acls);
          pm_strcpy(jcr->acl_data, "");
-         return true;
+         jcr->acl_data_len = 0;
+         return bacl_exit_ok;
       }
 
       if ((acl_text = acltotext(acls, n)) != NULL) {
          jcr->acl_data_len = pm_strcpy(jcr->acl_data, acl_text);
          actuallyfree(acl_text);
          free(acls);
-
          return send_acl_stream(jcr, STREAM_ACL_SOLARIS_ACLENT);
       }
 
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("acltotext error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("acltotext error on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg3(100, "acltotext error acl=%s file=%s ERR=%s\n",  
-         jcr->acl_data, jcr->last_fname, be.bstrerror());
+            jcr->acl_data, jcr->last_fname, be.bstrerror());
    }
 
    free(acls);
-   return false;
+   return bacl_exit_error;
 }
 
-static bool solaris_parse_acl_stream(JCR *jcr, int stream)
+static bacl_exit_code solaris_parse_acl_streams(JCR *jcr, int stream)
 {
    int n;
    aclent_t *acls;
+   berrno be;
 
    acls = aclfromtext(jcr->acl_data, &n);
    if (!acls) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("aclfromtext error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("aclfromtext error on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg3(100, "aclfromtext error acl=%s file=%s ERR=%s\n",  
-         jcr->acl_data, jcr->last_fname, be.bstrerror());
-
-      return false;
+            jcr->acl_data, jcr->last_fname, be.bstrerror());
+      return bacl_exit_error;
    }
 
    /*
@@ -1187,21 +1194,30 @@ static bool solaris_parse_acl_stream(JCR *jcr, int stream)
     * not have attributes, and the file it is linked to may not yet be restored.
     */
    if (acl(jcr->last_fname, SETACL, n, acls) == -1 && jcr->last_type != FT_LNK) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
-      Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",  
-         jcr->acl_data, jcr->last_fname, be.bstrerror());
-      actuallyfree(acls);
-
-      return false;
+      switch (errno) {
+      case ENOENT:
+         actuallyfree(acls);
+         return bacl_exit_ok;
+      default:
+         Mmsg2(jcr->errmsg, _("acl(SETACL) error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg3(100, "acl(SETACL) error acl=%s file=%s ERR=%s\n",
+               jcr->acl_data, jcr->last_fname, be.bstrerror());
+         actuallyfree(acls);
+         return bacl_exit_error;
+      }
    }
-
    actuallyfree(acls);
-   return true;
+   return bacl_exit_ok;
 }
-
 #endif /* HAVE_EXTENDED_ACL */
+
+/*
+ * For this OS setup the build and parse function pointer to the OS specific functions.
+ */
+static bacl_exit_code (*os_build_acl_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_acl_streams;
+static bacl_exit_code (*os_parse_acl_streams)(JCR *jcr, int stream) = solaris_parse_acl_streams;
+
 #endif /* HAVE_SUN_OS */
 
 /*
@@ -1211,96 +1227,55 @@ static bool solaris_parse_acl_stream(JCR *jcr, int stream)
 /*
  * Read and send an ACL for the last encountered file.
  */
-bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
+bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    /*
-    * Call the appropriate function, the ifdefs make sure the proper code is compiled.
+    * Call the appropriate function.
     */
-#if defined(HAVE_AIX_OS)
-   return aix_build_acl_streams(jcr, ff_pkt);
-#elif defined(HAVE_DARWIN_OS)
-   return darwin_build_acl_streams(jcr, ff_pkt);
-#elif defined(HAVE_FREEBSD_OS)
-   return freebsd_build_acl_streams(jcr, ff_pkt);
-#elif defined(HAVE_HPUX_OS)
-   return hpux_build_acl_streams(jcr, ff_pkt);
-#elif defined(HAVE_IRIX_OS)
-   return irix_build_acl_streams(jcr, ff_pkt);
-#elif defined(HAVE_LINUX_OS)
-   return linux_build_acl_streams(jcr, ff_pkt);
-#elif defined(HAVE_OSF1_OS)
-   return tru64_build_acl_streams(jcr, ff_pkt);
-#elif defined(HAVE_SUN_OS)
-   return solaris_build_acl_streams(jcr, ff_pkt);
-#endif
+   if (os_build_acl_streams) {
+      return (*os_build_acl_streams)(jcr, ff_pkt);
+   }
+   return bacl_exit_error;
 }
 
-bool parse_acl_stream(JCR *jcr, int stream)
+bacl_exit_code parse_acl_streams(JCR *jcr, int stream)
 {
-   /*
-    * Based on the stream being passed in dispatch to the right function
-    * for parsing and restoring a specific acl. The platform determines
-    * which streams are recognized and parsed and which are handled by
-    * the default case and ignored. The old STREAM_UNIX_ACCESS_ACL and
-    * STREAM_UNIX_DEFAULT_ACL is handled as a legacy stream by each function.
-    * As only one of the platform defines is true per compile we never end
-    * up with duplicate switch values.
-    */
+   unsigned int cnt;
+
    switch (stream) {
-#if defined(HAVE_AIX_OS)
-   case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_UNIX_DEFAULT_ACL:
-   case STREAM_ACL_AIX_TEXT:
-      return aix_parse_acl_stream(jcr, stream);
-#elif defined(HAVE_DARWIN_OS)
-   case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_ACL_DARWIN_ACCESS_ACL:
-      return darwin_parse_acl_stream(jcr, stream);
-#elif defined(HAVE_FREEBSD_OS)
    case STREAM_UNIX_ACCESS_ACL:
    case STREAM_UNIX_DEFAULT_ACL:
-   case STREAM_ACL_FREEBSD_DEFAULT_ACL:
-   case STREAM_ACL_FREEBSD_ACCESS_ACL:
-      return freebsd_parse_acl_stream(jcr, stream);
-#elif defined(HAVE_HPUX_OS)
-   case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_ACL_HPUX_ACL_ENTRY:
-      return hpux_parse_acl_stream(jcr, stream);
-#elif defined(HAVE_IRIX_OS)
-   case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_UNIX_DEFAULT_ACL:
-   case STREAM_ACL_IRIX_DEFAULT_ACL:
-   case STREAM_ACL_IRIX_ACCESS_ACL:
-      return irix_parse_acl_stream(jcr, stream);
-#elif defined(HAVE_LINUX_OS)
-   case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_UNIX_DEFAULT_ACL:
-   case STREAM_ACL_LINUX_DEFAULT_ACL:
-   case STREAM_ACL_LINUX_ACCESS_ACL:
-      return linux_parse_acl_stream(jcr, stream);
-#elif defined(HAVE_OSF1_OS)
-   case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_UNIX_DEFAULT_ACL:
-   case STREAM_ACL_TRU64_DEFAULT_ACL:
-   case STREAM_ACL_TRU64_ACCESS_ACL:
-   case STREAM_ACL_TRU64_DEFAULT_DIR_ACL:
-      return tru64_parse_acl_stream(jcr, stream);
-#elif defined(HAVE_SUN_OS)
-   case STREAM_UNIX_ACCESS_ACL:
-   case STREAM_ACL_SOLARIS_ACLENT:
-#if defined(HAVE_EXTENDED_ACL)
-   case STREAM_ACL_SOLARIS_ACE:
-#endif
-      return solaris_parse_acl_stream(jcr, stream);
-#endif
-   default:
       /*
-       * Issue a warning and discard the message. But pretend the restore was ok.
+       * Handle legacy ACL streams.
        */
-      Qmsg2(jcr, M_WARNING, 0,
-         _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
-         jcr->last_fname, stream);
-      return true;
-   } /* end switch (stream) */
+      if (os_parse_acl_streams) {
+         return (*os_parse_acl_streams)(jcr, stream);
+      }
+      break;
+   default:
+      if (os_parse_acl_streams) {
+         /*
+          * Walk the os_access_acl_streams array with the supported Access ACL streams for this OS.
+          */
+         for (cnt = 0; cnt < sizeof(os_access_acl_streams) / sizeof(int); cnt++) {
+            if (os_access_acl_streams[cnt] == stream) {
+               return (*os_parse_acl_streams)(jcr, stream);
+            }
+         }
+         /*
+          * Walk the os_default_acl_streams array with the supported Default ACL streams for this OS.
+          */
+         for (cnt = 0; cnt < sizeof(os_default_acl_streams) / sizeof(int); cnt++) {
+            if (os_default_acl_streams[cnt] == stream) {
+               return (*os_parse_acl_streams)(jcr, stream);
+            }
+         }
+      }
+      break;
+   }
+   Qmsg2(jcr, M_WARNING, 0,
+      _("Can't restore ACLs of %s - incompatible acl stream encountered - %d\n"),
+      jcr->last_fname, stream);
+   return bacl_exit_error;
 }
 #endif
index 1721199ea0495b861bc5db36110de9aecef8ea5e..e92f880b4f7d7102f47ffd6629c70fbcfc3a51b6 100644 (file)
@@ -142,9 +142,11 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
 
    if (have_acl) {
       jcr->acl_data = get_pool_memory(PM_MESSAGE);
+      jcr->total_acl_errors = 0;
    }
    if (have_xattr) {
       jcr->xattr_data = get_pool_memory(PM_MESSAGE);
+      jcr->total_xattr_errors = 0;
    }
 
    /* Subroutine save_file() is called for each file */
@@ -153,6 +155,15 @@ bool blast_data_to_storage_daemon(JCR *jcr, char *addr)
       set_jcr_job_status(jcr, JS_ErrorTerminated);
    }
 
+   if (jcr->total_acl_errors > 0) {
+      Jmsg(jcr, M_ERROR, 0, _("Encountered %ld acl errors while doing backup\n"),
+           jcr->total_acl_errors);
+   }
+   if (jcr->total_xattr_errors > 0) {
+      Jmsg(jcr, M_ERROR, 0, _("Encountered %ld xattr errors while doing backup\n"),
+           jcr->total_xattr_errors);
+   }
+
    accurate_finish(jcr);              /* send deleted or base file list to SD */
 
    stop_heartbeat_monitor(jcr);
@@ -600,8 +611,22 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
     */
    if (have_acl) {
       if (ff_pkt->flags & FO_ACL && ff_pkt->type != FT_LNK && !ff_pkt->cmd_plugin) {
-         if (!build_acl_streams(jcr, ff_pkt))
+         switch (build_acl_streams(jcr, ff_pkt)) {
+         case bacl_exit_fatal:
             goto bail_out;
+         case bacl_exit_error:
+            /*
+             * Non-fatal errors, count them and when the number is under ACL_REPORT_ERR_MAX_PER_JOB
+             * print the error message set by the lower level routine in jcr->errmsg.
+             */
+            if (jcr->total_acl_errors < ACL_REPORT_ERR_MAX_PER_JOB) {
+               Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
+            }
+            jcr->total_acl_errors++;
+            break;
+         case bacl_exit_ok:
+            break;
+         }
       }
    }
 
@@ -610,8 +635,22 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
     */
    if (have_xattr) {
       if (ff_pkt->flags & FO_XATTR && !ff_pkt->cmd_plugin) {
-         if (!build_xattr_streams(jcr, ff_pkt))
+         switch (build_xattr_streams(jcr, ff_pkt)) {
+         case bxattr_exit_fatal:
             goto bail_out;
+         case bxattr_exit_error:
+            /*
+             * Non-fatal errors, count them and when the number is under XATTR_REPORT_ERR_MAX_PER_JOB
+             * print the error message set by the lower level routine in jcr->errmsg.
+             */
+            if (jcr->total_xattr_errors < XATTR_REPORT_ERR_MAX_PER_JOB) {
+               Jmsg(jcr, M_ERROR, 0, "%s", jcr->errmsg);
+            }
+            jcr->total_xattr_errors++;
+            break;
+         case bxattr_exit_ok:
+            break;
+         }
       }
    }
 
index 3c3649be307f0c90a952f0af782dfcfdb9367076..b82aef08600ac2b9ab23d29fab8ddde554b34c56 100644 (file)
  *   Version $Id$
  */
 
+/*
+ * Number of acl errors to report per job.
+ */
+#define ACL_REPORT_ERR_MAX_PER_JOB     25
+
+/*
+ * Number of xattr errors to report per job.
+ */
+#define XATTR_REPORT_ERR_MAX_PER_JOB   25
+
+/*
+ * Return codes from acl subroutines.
+ */
+typedef enum {
+   bacl_exit_fatal = -1,
+   bacl_exit_error = 0,
+   bacl_exit_ok = 1
+} bacl_exit_code;
+
+/*
+ * Return codes from xattr subroutines.
+ */
+typedef enum {
+   bxattr_exit_fatal = -1,
+   bxattr_exit_error = 0,
+   bxattr_exit_ok = 1
+} bxattr_exit_code;
 
 #define FILE_DAEMON 1
 #include "lib/htable.h"
@@ -40,7 +67,6 @@
 #include "fd_plugins.h"
 #include "findlib/find.h"
 #include "jcr.h"
-#include "acl.h"
 #include "protos.h"                   /* file daemon prototypes */
 #include "lib/runscript.h"
 #include "lib/breg.h"
index eb480062838894bc5601596b2d4a19d06debd51a..9ac0afbeeb2f1d9f54a54572bf771f5686893b4a 100644 (file)
@@ -47,8 +47,8 @@ void start_dir_heartbeat(JCR *jcr);
 void stop_dir_heartbeat(JCR *jcr);
 
 /* From acl.c */
-bool build_acl_streams(JCR *jcr, FF_PKT *ff_pkt);
-bool parse_acl_stream(JCR *jcr, int stream);
+bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt);
+bacl_exit_code parse_acl_streams(JCR *jcr, int stream);
 
 /* from accurate.c */
 bool accurate_finish(JCR *jcr);
@@ -62,5 +62,5 @@ void strip_path(FF_PKT *ff_pkt);
 void unstrip_path(FF_PKT *ff_pkt);
 
 /* from xattr.c */
-bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt);
-bool parse_xattr_stream(JCR *jcr, int stream);
+bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt);
+bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream);
index e24abdf3f54a8aa30b43bd1470c5b4ab6d3ebd2a..c1dc3b735264a6baf83297535803989a5008f326 100644 (file)
@@ -252,9 +252,11 @@ void do_restore(JCR *jcr)
    attr = rctx.attr = new_attr(jcr);
    if (have_acl) {
       jcr->acl_data = get_pool_memory(PM_MESSAGE);
+      jcr->total_acl_errors = 0;
    }
    if (have_xattr) {
       jcr->xattr_data = get_pool_memory(PM_MESSAGE);
+      jcr->total_xattr_errors = 0;
    }
 
    while (bget_msg(sd) >= 0 && !job_canceled(jcr)) {
@@ -610,8 +612,21 @@ void do_restore(JCR *jcr)
          if (have_acl) {
             pm_memcpy(jcr->acl_data, sd->msg, sd->msglen);
             jcr->acl_data_len = sd->msglen;
-            if (!parse_acl_stream(jcr, rctx.stream)) {
-               Qmsg1(jcr, M_WARNING, 0, _("Can't restore ACLs of %s\n"), jcr->last_fname);
+            switch (parse_acl_streams(jcr, rctx.stream)) {
+            case bacl_exit_fatal:
+               goto bail_out;
+            case bacl_exit_error:
+               /*
+                * Non-fatal errors, count them and when the number is under ACL_REPORT_ERR_MAX_PER_JOB
+                * print the error message set by the lower level routine in jcr->errmsg.
+                */
+               if (jcr->total_acl_errors < ACL_REPORT_ERR_MAX_PER_JOB) {
+                  Qmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+               }
+               jcr->total_acl_errors++;
+               break;
+            case bacl_exit_ok:
+               break;
             }
          } else {
             non_support_acl++;
@@ -636,8 +651,21 @@ void do_restore(JCR *jcr)
          if (have_xattr) {
             pm_memcpy(jcr->xattr_data, sd->msg, sd->msglen);
             jcr->xattr_data_len = sd->msglen;
-            if (!parse_xattr_stream(jcr, rctx.stream)) {
-               Qmsg1(jcr, M_WARNING, 0, _("Can't restore Extended Attributes of %s\n"), jcr->last_fname);
+            switch (parse_xattr_streams(jcr, rctx.stream)) {
+            case bxattr_exit_fatal:
+               goto bail_out;
+            case bxattr_exit_error:
+               /*
+                * Non-fatal errors, count them and when the number is under XATTR_REPORT_ERR_MAX_PER_JOB
+                * print the error message set by the lower level routine in jcr->errmsg.
+                */
+               if (jcr->total_xattr_errors < XATTR_REPORT_ERR_MAX_PER_JOB) {
+                  Qmsg(jcr, M_WARNING, 0, "%s", jcr->errmsg);
+               }
+               jcr->total_xattr_errors++;
+               break;
+            case bxattr_exit_ok:
+               break;
             }
          } else {
             non_support_xattr++;
@@ -751,6 +779,14 @@ ok_out:
    free_attr(rctx.attr);
    Dmsg2(10, "End Do Restore. Files=%d Bytes=%s\n", jcr->JobFiles,
       edit_uint64(jcr->JobBytes, ec1));
+   if (jcr->total_acl_errors > 0) {
+      Jmsg(jcr, M_ERROR, 0, _("Encountered %ld acl errors while doing restore\n"),
+           jcr->total_acl_errors);
+   }
+   if (jcr->total_xattr_errors > 0) {
+      Jmsg(jcr, M_ERROR, 0, _("Encountered %ld xattr errors while doing restore\n"),
+           jcr->total_xattr_errors);
+   }
    if (non_support_data > 1 || non_support_attr > 1) {
       Jmsg(jcr, M_ERROR, 0, _("%d non-supported data streams and %d non-supported attrib streams ignored.\n"),
          non_support_data, non_support_attr);
index 99f9bbb63b89b930f2df263a6d2fb6dd640c7eda..c444d62093acbc9348067dcfbbd2b55aa0a22f21 100644 (file)
 /*
  * Entry points when compiled without support for XATTRs or on an unsupported platform.
  */
-bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
+bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
-   return false;
+   return bxattr_exit_fatal;
 }
 
-bool parse_xattr_stream(JCR *jcr, int stream)
+bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
 {
-   return false;
+   return bxattr_exit_fatal;
 }
 #else
 /*
  * Send a XATTR stream to the SD.
  */
-static bool send_xattr_stream(JCR *jcr, int stream)
+static bxattr_exit_code send_xattr_stream(JCR *jcr, int stream)
 {
    BSOCK *sd = jcr->store_bsock;
    POOLMEM *msgsave;
 #ifdef FD_NO_SEND_TEST
-   return true;
+   return bxattr_exit_ok;
 #endif
 
    /*
     * Sanity check
     */
    if (jcr->xattr_data_len <= 0)
-      return true;
+      return bxattr_exit_ok;
 
    /*
     * Send header
@@ -84,7 +84,7 @@ static bool send_xattr_stream(JCR *jcr, int stream)
    if (!sd->fsend("%ld %d 0", jcr->JobFiles, stream)) {
       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
             sd->bstrerror());
-      return false;
+      return bxattr_exit_fatal;
    }
 
    /*
@@ -99,7 +99,7 @@ static bool send_xattr_stream(JCR *jcr, int stream)
       sd->msglen = 0;
       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
             sd->bstrerror());
-      return false;
+      return bxattr_exit_fatal;
    }
 
    jcr->JobBytes += sd->msglen;
@@ -107,26 +107,38 @@ static bool send_xattr_stream(JCR *jcr, int stream)
    if (!sd->signal(BNET_EOD)) {
       Jmsg1(jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"),
             sd->bstrerror());
-      return false;
+      return bxattr_exit_fatal;
    }
    Dmsg1(200, "XATTR of file: %s successfully backed up!\n", jcr->last_fname);
-
-   return true;
+   return bxattr_exit_ok;
 }
 
 /*
  * This is a supported OS, See what kind of interface we should use.
  * Start with the generic interface used by most OS-es.
  */
-#if defined(HAVE_DARWIN_OS) \
-   || defined(HAVE_FREEBSD_OS) \
-   || defined(HAVE_LINUX_OS) \
-   || defined(HAVE_NETBSD_OS)
+#if defined(HAVE_DARWIN_OS) || \
+    defined(HAVE_FREEBSD_OS) || \
+    defined(HAVE_LINUX_OS) || \
+    defined(HAVE_NETBSD_OS)
        
 #ifdef HAVE_SYS_XATTR_H
 #include <sys/xattr.h>
 #endif
 
+/*
+ * Define the supported XATTR streams for this OS
+ */
+#if defined(HAVE_DARWIN_OS)
+static int os_default_xattr_streams[1] = { STREAM_XATTR_DARWIN };
+#elif defined(HAVE_FREEBSD_OS)
+static int os_default_xattr_streams[1] = { STREAM_XATTR_FREEBSD };
+#elif defined(HAVE_LINUX_OS)
+static int os_default_xattr_streams[1] = { STREAM_XATTR_LINUX };
+#elif defined(HAVE_NETBSD_OS)
+static int os_default_xattr_streams[1] = { STREAM_XATTR_NETBSD };
+#endif
+
 /*
  * OSX doesn't have llistxattr, lgetxattr and lsetxattr but has
  * listxattr, getxattr and setxattr with an extra options argument
@@ -226,32 +238,37 @@ static uint32_t serialize_xattr_stream(JCR *jcr, uint32_t expected_serialize_len
 
    ser_end(jcr->xattr_data, expected_serialize_len + 10);
    jcr->xattr_data_len = ser_length(jcr->xattr_data);
-
    return jcr->xattr_data_len;
 }
 
-static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
+static bxattr_exit_code generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
    int count = 0;
    int32_t xattr_list_len,
            xattr_value_len;
    uint32_t expected_serialize_len = 0;
    char *xattr_list, *bp;
-   xattr_t *xattr_value_list, *current_xattr;
+   xattr_t *xattr_value_list = NULL, *current_xattr;
+   bxattr_exit_code retval = bxattr_exit_error;
+   berrno be;
 
    /*
     * First get the length of the available list with extended attributes.
     */
    xattr_list_len = llistxattr(jcr->last_fname, NULL, 0);
    if (xattr_list_len < 0) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
-      Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
-         jcr->last_fname, be.bstrerror());
-      return true;                       /* non-fatal return */
+      switch (errno) {
+      case ENOENT:
+         return bxattr_exit_ok;
+      default:
+         Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
+               jcr->last_fname, be.bstrerror());
+         return bxattr_exit_error;
+      }
    } else if (xattr_list_len == 0) {
-      return true;
+      return bxattr_exit_ok;
    }
 
    /*
@@ -265,13 +282,17 @@ static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
     */
    xattr_list_len = llistxattr(jcr->last_fname, xattr_list, xattr_list_len);
    if (xattr_list_len < 0) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("llistxattr error on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
-      Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
-         jcr->last_fname, be.bstrerror());
-      free(xattr_list);
-      return true;                    /* non-fatal return */
+      switch (errno) {
+      case ENOENT:
+         retval = bxattr_exit_ok;
+         goto bail_out;
+      default:
+         Mmsg2(jcr->errmsg, _("llistxattr error on file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg2(100, "llistxattr error file=%s ERR=%s\n",
+               jcr->last_fname, be.bstrerror());
+         goto bail_out;
+      }
    }
    xattr_list[xattr_list_len] = '\0';
 
@@ -296,9 +317,8 @@ static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
    }
 
    if (count == 0) {
-      free(xattr_list);
-
-      return true;
+      retval = bxattr_exit_ok;
+      goto bail_out;
    }
 
    /*
@@ -316,6 +336,11 @@ static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
    bp = xattr_list;
    while ((bp - xattr_list) + 1 < xattr_list_len) {
 #if defined(HAVE_LINUX_OS)
+      /*
+       * On Linux you also get the acls in the extented attribute list.
+       * So we check if we are already backing up acls and if we do we
+       * don't store the extended attribute with the same info.
+       */
       if (ff_pkt->flags & FO_ACL && !strcmp(bp, "system.posix_acl_access")) {
          bp = strchr(bp, '\0') + 1;
          continue;
@@ -342,12 +367,17 @@ static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
        */
       xattr_value_len = lgetxattr(jcr->last_fname, bp, NULL, 0);
       if (xattr_value_len < 0) {
-         berrno be;
-         Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
-            jcr->last_fname, be.bstrerror());
-         Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
-            jcr->last_fname, be.bstrerror());
-         goto bail_out;
+         switch (errno) {
+         case ENOENT:
+            retval = bxattr_exit_ok;
+            goto bail_out;
+         default:
+            Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
+                  jcr->last_fname, be.bstrerror());
+            Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
+                  jcr->last_fname, be.bstrerror());
+            goto bail_out;
+         }
       }
 
       /*
@@ -358,12 +388,17 @@ static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
 
       xattr_value_len = lgetxattr(jcr->last_fname, bp, current_xattr->value, xattr_value_len);
       if (xattr_value_len < 0) {
-         berrno be;
-         Jmsg2(jcr, M_ERROR, 0, _("lgetxattr error on file \"%s\": ERR=%s\n"),
-            jcr->last_fname, be.bstrerror());
-         Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
-            jcr->last_fname, be.bstrerror());
-         goto bail_out;
+         switch (errno) {
+         case ENOENT:
+            retval = bxattr_exit_ok;
+            goto bail_out;
+         default:
+            Mmsg2(jcr->errmsg, _("lgetxattr error on file \"%s\": ERR=%s\n"),
+                  jcr->last_fname, be.bstrerror());
+            Dmsg2(100, "lgetxattr error file=%s ERR=%s\n",
+                  jcr->last_fname, be.bstrerror());
+            goto bail_out;
+         }
       }
 
       /*
@@ -376,8 +411,8 @@ static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
        * Protect ourself against things getting out of hand.
        */
       if (expected_serialize_len >= MAX_XATTR_STREAM) {
-         Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
-            jcr->last_fname, MAX_XATTR_STREAM);
+         Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
+               jcr->last_fname, MAX_XATTR_STREAM);
          goto bail_out;
       }
       
@@ -392,10 +427,10 @@ static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
     * Serialize the datastream.
     */
    if (serialize_xattr_stream(jcr, expected_serialize_len, xattr_value_list) < expected_serialize_len) {
-      Jmsg1(jcr, M_ERROR, 0, _("Failed to serialize extended attributes on file \"%s\"\n"),
-         jcr->last_fname);
+      Mmsg1(jcr->errmsg, _("Failed to serialize extended attributes on file \"%s\"\n"),
+            jcr->last_fname);
       Dmsg1(100, "Failed to serialize extended attributes on file \"%s\"\n",
-         jcr->last_fname);
+            jcr->last_fname);
       goto bail_out;
    }
 
@@ -405,19 +440,22 @@ static bool generic_xattr_build_streams(JCR *jcr, FF_PKT *ff_pkt, int stream)
    /*
     * Send the datastream to the SD.
     */
-   return send_xattr_stream(jcr, stream);
+   return send_xattr_stream(jcr, os_default_xattr_streams[0]);
 
 bail_out:
-   xattr_drop_internal_table(xattr_value_list);
+   if (xattr_value_list) {
+      xattr_drop_internal_table(xattr_value_list);
+   }
    free(xattr_list);
-   return true;                    /* non-fatal return */
+   return retval;
 }
 
-static bool generic_xattr_parse_streams(JCR *jcr)
+static bxattr_exit_code generic_xattr_parse_streams(JCR *jcr, int stream)
 {
    unser_declare;
    xattr_t current_xattr;
-   bool retval = true;                /* default non-fatal */
+   bxattr_exit_code retval = bxattr_exit_ok;
+   berrno be;
 
    /*
     * Parse the stream and perform the setxattr calls on the file.
@@ -433,11 +471,11 @@ static bool generic_xattr_parse_streams(JCR *jcr)
        */
       unser_uint32(current_xattr.magic);
       if (current_xattr.magic != XATTR_MAGIC) {
-         Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
-            jcr->last_fname);
+         Mmsg1(jcr->errmsg, _("Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n"),
+               jcr->last_fname);
          Dmsg1(100, "Illegal xattr stream, no XATTR_MAGIC on file \"%s\"\n",
-            jcr->last_fname);
-         return true;                 /* non-fatal return */
+               jcr->last_fname);
+         return bxattr_exit_error;
       }
 
       /*
@@ -473,12 +511,18 @@ static bool generic_xattr_parse_streams(JCR *jcr)
        * we try to restore the other extended attributes too.
        */
       if (lsetxattr(jcr->last_fname, current_xattr.name, current_xattr.value,
-         current_xattr.value_length, 0) != 0) {
-         berrno be;
-         Jmsg2(jcr, M_ERROR, 0, _("lsetxattr error on file \"%s\": ERR=%s\n"),
-            jcr->last_fname, be.bstrerror());
-         Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
-            jcr->last_fname, be.bstrerror());
+                    current_xattr.value_length, 0) != 0) {
+         switch (errno) {
+         case ENOENT:
+            break;
+         default:
+            Mmsg2(jcr->errmsg, _("lsetxattr error on file \"%s\": ERR=%s\n"),
+                  jcr->last_fname, be.bstrerror());
+            Dmsg2(100, "lsetxattr error file=%s ERR=%s\n",
+                  jcr->last_fname, be.bstrerror());
+            retval = bxattr_exit_error;
+            break;
+         }
       }
 
       /*
@@ -492,79 +536,12 @@ static bool generic_xattr_parse_streams(JCR *jcr)
    return retval;
 }
 
-#if defined(HAVE_DARWIN_OS)
-static bool darwin_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
-   return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_DARWIN);
-}
-
-static bool darwin_parse_xattr_stream(JCR *jcr, int stream)
-{
-   switch (stream) {
-   case STREAM_XATTR_DARWIN:
-      return generic_xattr_parse_streams(jcr);
-   default:
-      Jmsg2(jcr, M_WARNING, 0,
-         _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
-         jcr->last_fname, stream);
-      return true;                    /* non-fatal error */
-   }
-}
-#elif defined(HAVE_FREEBSD_OS)
-static bool freebsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
-   return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_FREEBSD);
-}
-
-static bool freebsd_parse_xattr_stream(JCR *jcr, int stream)
-{
-   switch (stream) {
-   case STREAM_XATTR_FREEBSD:
-      return generic_xattr_parse_streams(jcr);
-   default:
-      Jmsg2(jcr, M_WARNING, 0, 
-         _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
-         jcr->last_fname, stream);
-      return true;                    /* non-fatal error */
-   }
-}
-#elif defined(HAVE_LINUX_OS)
-static bool linux_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
-   return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_LINUX);
-}
-
-static bool linux_parse_xattr_stream(JCR *jcr, int stream)
-{
-   switch (stream) {
-   case STREAM_XATTR_LINUX:
-      return generic_xattr_parse_streams(jcr);
-   default:
-      Jmsg2(jcr, M_WARNING, 0, 
-         _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
-         jcr->last_fname, stream);
-      return true;                    /* non-fatal error */
-   }
-}
-#elif defined(HAVE_NETBSD_OS)
-static bool netbsd_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
-   return generic_xattr_build_streams(jcr, ff_pkt, STREAM_XATTR_NETBSD);
-}
+/*
+ * For all these os-es setup the build and parse function pointer to the generic functions.
+ */
+static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = generic_xattr_build_streams;
+static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = generic_xattr_parse_streams;
 
-static bool netbsd_parse_xattr_stream(JCR *jcr, int stream)
-{
-   switch (stream) {
-   case STREAM_XATTR_NETBSD:
-      return generic_xattr_parse_streams(jcr);
-   default:
-      Jmsg2(jcr, M_WARNING, 0, 
-         _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
-         jcr->last_fname, stream);
-      return true;                    /* non-fatal error */
-   }
-}
-#endif
 #elif defined(HAVE_SUN_OS)
 /*
  * Solaris extended attributes were introduced in Solaris 9
@@ -661,6 +638,15 @@ static bool netbsd_parse_xattr_stream(JCR *jcr, int stream)
 #include <sys/acl.h>
 #endif
 
+/*
+ * Define the supported XATTR streams for this OS
+ */
+#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
+static int os_default_xattr_streams[2] = { STREAM_XATTR_SOLARIS, STREAM_XATTR_SOLARIS_SYS};
+#else
+static int os_default_xattr_streams[1] = { STREAM_XATTR_SOLARIS };
+#endif /* defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED) */
+
 /*
  * This is the count of xattrs saved on a certain file, it gets reset
  * on each new file processed and is used to see if we need to send
@@ -675,15 +661,14 @@ static int toplevel_hidden_dir_xattr_data_len;
  * This code creates a temporary cache with entries for each xattr which has
  * a link count > 1 (which indicates it has one or more hard linked counterpart(s))
  */
-static xattr_link_cache_entry_t *xattr_link_cache_head = NULL,
-                                *xattr_link_cache_tail = NULL;
+static alist *xattr_link_cache = NULL;
 
-static struct xattr_link_cache_entry *find_xattr_link_cache_entry(ino_t inum)
+static xattr_link_cache_entry_t *find_xattr_link_cache_entry(ino_t inum)
 {
    xattr_link_cache_entry_t *ptr;
 
-   for (ptr = xattr_link_cache_head; ptr != NULL; ptr = ptr->next) {
-      if (ptr->inum == inum) {
+   foreach_alist(ptr, xattr_link_cache) {
+      if (ptr && ptr->inum == inum) {
          return ptr;
       }
    }
@@ -694,28 +679,11 @@ static void add_xattr_link_cache_entry(ino_t inum, char *target)
 {
    xattr_link_cache_entry_t *ptr;
 
-   ptr = (xattr_link_cache_entry_t *)malloc(sizeof(struct xattr_link_cache_entry));
-   memset((caddr_t)ptr, 0, sizeof(struct xattr_link_cache_entry));
+   ptr = (xattr_link_cache_entry_t *)malloc(sizeof(xattr_link_cache_entry_t));
+   memset((caddr_t)ptr, 0, sizeof(xattr_link_cache_entry_t));
    ptr->inum = inum;
-   strncpy(ptr->target, target, sizeof(ptr->target));
-   if (xattr_link_cache_head == NULL) {
-      xattr_link_cache_head = ptr;
-   }
-   if (xattr_link_cache_tail != NULL) {
-      xattr_link_cache_tail->next = ptr;
-   }
-}
-
-static void drop_xattr_link_cache(void)
-{
-   xattr_link_cache_entry_t *ptr, *next;
-
-   for (ptr = xattr_link_cache_tail; ptr != NULL; ptr = next) {
-      next = ptr->next;
-      free(ptr);
-   }
-   xattr_link_cache_head = NULL;
-   xattr_link_cache_tail = NULL;
+   bstrncpy(ptr->target, target, sizeof(ptr->target));
+   xattr_link_cache->append(ptr);
 }
 
 #if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
@@ -755,7 +723,7 @@ static bool solaris_has_non_transient_extensible_attributes(int fd)
          fattr = name_to_attr(name);
       } else {
          retval = true;
-         goto cleanup;
+         goto bail_out;
       }
 
       type = nvpair_type(pair);
@@ -767,23 +735,23 @@ static bool solaris_has_non_transient_extensible_attributes(int fd)
          if (value && fattr != F_ARCHIVE &&
                       fattr != F_AV_MODIFIED) {
             retval = true;
-            goto cleanup;
+            goto bail_out;
          }
          break;
       case DATA_TYPE_UINT64_ARRAY:
          if (fattr != F_CRTIME) {
             retval = true;
-            goto cleanup;
+            goto bail_out;
          }
          break;
       case DATA_TYPE_NVLIST:
       default:
          retval = true;
-         goto cleanup;
+         goto bail_out;
       }
    }
 
-cleanup:
+bail_out:
    if (response != NULL) {
       nvlist_free(response);
    }
@@ -813,12 +781,13 @@ static bool acl_is_trivial(int count, aclent_t *entries)
 }
 #endif /* HAVE_ACL && !HAVE_EXTENDED_ACL */
 
-static bool solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
+static bxattr_exit_code solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char **acl_text)
 {
 #ifdef HAVE_ACL
 #ifdef HAVE_EXTENDED_ACL
    int flags;
    acl_t *aclp = NULL;
+   berrno be;
 
    /*
     * See if this attribute has an ACL
@@ -830,12 +799,16 @@ static bool solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char
        */
       if ((fd != -1 && facl_get(fd, ACL_NO_TRIVIAL, &aclp) != 0) ||
            acl_get(attrname, ACL_NO_TRIVIAL, &aclp) != 0) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
-            attrname, jcr->last_fname, be.bstrerror());
-         Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
-            attrname, jcr->last_fname, be.bstrerror());
-         return true;                    /* non-fatal */
+         switch (errno) {
+         case ENOENT:
+            return bxattr_exit_ok;
+         default:
+            Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
+                  attrname, jcr->last_fname, be.bstrerror());
+            Dmsg3(100, "facl_get/acl_get of xattr %s on \"%s\" failed: ERR=%s\n",
+                  attrname, jcr->last_fname, be.bstrerror());
+            return bxattr_exit_error;
+         }
       }
 
       if (aclp != NULL) {
@@ -856,11 +829,11 @@ static bool solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char
    } else {
       *acl_text = NULL;
    }
-
-   return true;
+   return bxattr_exit_ok;
 #else /* HAVE_EXTENDED_ACL */
    int n;
    aclent_t *acls = NULL;
+   berrno be;
 
    /*
     * See if this attribute has an ACL
@@ -875,13 +848,18 @@ static bool solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char
       acls = (aclent_t *)malloc(n * sizeof(aclent_t));
       if ((fd != -1 && facl(fd, GETACL, n, acls) != n) ||
           acl(attrname, GETACL, n, acls) != n) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
-            attrname, jcr->last_fname, be.bstrerror());
-         Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
-            attrname, jcr->last_fname, be.bstrerror());
-         free(acls);
-         return true;                 /* non-fatal */
+         switch (errno) {
+         case ENOENT:
+            free(acls);
+            return bxattr_exit_ok;
+         default:
+            Mmsg3(jcr->errmsg, _("Unable to get acl on xattr %s on file \"%s\": ERR=%s\n"),
+                  attrname, jcr->last_fname, be.bstrerror());
+            Dmsg3(100, "facl/acl of xattr %s on \"%s\" failed: ERR=%s\n",
+                  attrname, jcr->last_fname, be.bstrerror());
+            free(acls);
+            return bxattr_exit_error;
+         }
       }
 
       /*
@@ -889,13 +867,12 @@ static bool solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char
        */
       if (!acl_is_trivial(n, acls)) {
          if ((*acl_text = acltotext(acls, n)) == NULL) {
-            berrno be;
-            Jmsg3(jcr, M_ERROR, 0, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
-               attrname, jcr->last_fname, be.bstrerror());
+            Mmsg3(jcr->errmsg, _("Unable to get acl text on xattr %s on file \"%s\": ERR=%s\n"),
+                  attrname, jcr->last_fname, be.bstrerror());
             Dmsg3(100, "acltotext of xattr %s on \"%s\" failed: ERR=%s\n",
-               attrname, jcr->last_fname, be.bstrerror());
+                  attrname, jcr->last_fname, be.bstrerror());
             free(acls);
-            return true;                 /* non-fatal */
+            return bxattr_exit_error;
          }
       } else {
          *acl_text = NULL;
@@ -905,19 +882,18 @@ static bool solaris_save_xattr_acl(JCR *jcr, int fd, const char *attrname, char
    } else {
       *acl_text = NULL;
    }
-
-   return true;
+   return bxattr_exit_ok;
 #endif /* HAVE_EXTENDED_ACL */
 
 #else /* HAVE_ACL */
-   return false;                         /* fatal return */
+   return bxattr_exit_ok;
 #endif /* HAVE_ACL */
 }
 
 /*
  * Forward declaration for recursive function call.
  */
-static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
+static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent);
 
 /*
  * Save an extended or extensible attribute.
@@ -934,32 +910,38 @@ static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const cha
  * acl_string is an acl text when a non trivial acl is set on the xattr.
  * actual_xattr_data is the content of the xattr file.
  */
-static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
-                                  const char *attrname, bool toplevel_hidden_dir, int stream)
+static bxattr_exit_code solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
+                                         const char *attrname, bool toplevel_hidden_dir, int stream)
 {
    int cnt;
    int attrfd = -1;
    struct stat st;
-   struct xattr_link_cache_entry *xlce;
+   xattr_link_cache_entry_t *xlce;
    char target_attrname[PATH_MAX];
    char link_source[PATH_MAX];
    char *acl_text = NULL;
    char attribs[MAXSTRING];
    char buffer[BUFSIZ];
-   bool retval = true;                /* default is non-fatal */
+   bxattr_exit_code retval = bxattr_exit_error;
+   berrno be;
 
-   snprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
+   bsnprintf(target_attrname, sizeof(target_attrname), "%s%s", xattr_namespace, attrname);
 
    /*
     * Get the stats of the extended or extensible attribute.
     */
    if (fstatat(fd, attrname, &st, AT_SYMLINK_NOFOLLOW) < 0) {
-      berrno be;
-      Jmsg3(jcr, M_ERROR, 0, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
-         target_attrname, jcr->last_fname, be.bstrerror());
-      Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
-         target_attrname, jcr->last_fname, be.bstrerror());
-      goto cleanup;
+      switch (errno) {
+      case ENOENT:
+         retval = bxattr_exit_ok;
+         goto bail_out;
+      default:
+         Mmsg3(jcr->errmsg, _("Unable to get status on xattr %s on file \"%s\": ERR=%s\n"),
+               target_attrname, jcr->last_fname, be.bstrerror());
+         Dmsg3(100, "fstatat of xattr %s on \"%s\" failed: ERR=%s\n",
+               target_attrname, jcr->last_fname, be.bstrerror());
+         goto bail_out;
+      }
    }
 
    /*
@@ -974,15 +956,15 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
       /*
        * Get any acl on the xattr.
        */
-      if (!solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text))
-         goto cleanup;
+      if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
+         goto bail_out;
 
       /*
        * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
        * Encode the stat struct into an ASCII representation.
        */
       encode_stat(attribs, &st, 0, stream);
-      cnt = snprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
+      cnt = bsnprintf(buffer, sizeof(buffer), "%s%c%s%c%s%c",
                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
       break;
 
@@ -990,8 +972,8 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
       /*
        * Get any acl on the xattr.
        */
-      if (!solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text))
-         goto cleanup;
+      if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok)
+         goto bail_out;
 
       /*
        * See if this is the toplevel_hidden_dir being saved.
@@ -1002,21 +984,21 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
           * Encode the stat struct into an ASCII representation and jump out of the function.
           */
          encode_stat(attribs, &st, 0, stream);
-         toplevel_hidden_dir_xattr_data_len = snprintf(toplevel_hidden_dir_xattr_data,
-                                                       sizeof(toplevel_hidden_dir_xattr_data),
-                                                       "%s%c%s%c%s%c",
-                                                       target_attrname, 0, attribs, 0,
-                                                       (acl_text) ? acl_text : "", 0);
-         goto cleanup;
+         toplevel_hidden_dir_xattr_data_len = bsnprintf(toplevel_hidden_dir_xattr_data,
+                                                        sizeof(toplevel_hidden_dir_xattr_data),
+                                                        "%s%c%s%c%s%c",
+                                                        target_attrname, 0, attribs, 0,
+                                                        (acl_text) ? acl_text : "", 0);
+         goto bail_out;
       } else {
          /*
           * The current implementation of xattr on Solaris doesn't support this, but if it ever does we are prepared.
           * Encode the stat struct into an ASCII representation.
           */
          encode_stat(attribs, &st, 0, stream);
-         cnt = snprintf(buffer, sizeof(buffer),
-                        "%s%c%s%c%s%c",
-                        target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
+         cnt = bsnprintf(buffer, sizeof(buffer),
+                         "%s%c%s%c%s%c",
+                         target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
       }
       break;
    case S_IFREG:
@@ -1032,9 +1014,9 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
              * Generate a xattr encoding with the reference to the target in there.
              */
             encode_stat(attribs, &st, st.st_ino, stream);
-            cnt = snprintf(buffer, sizeof(buffer),
-                           "%s%c%s%c%s%c",
-                           target_attrname, 0, attribs, 0, xlce->target, 0);
+            cnt = bsnprintf(buffer, sizeof(buffer),
+                            "%s%c%s%c%s%c",
+                            target_attrname, 0, attribs, 0, xlce->target, 0);
             pm_memcpy(jcr->xattr_data, buffer, cnt);
             jcr->xattr_data_len = cnt;
             retval = send_xattr_stream(jcr, stream);
@@ -1042,7 +1024,7 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
             /*
              * For a hard linked file we are ready now, no need to recursively save the attributes.
              */
-            goto cleanup;
+            goto bail_out;
          }
 
          /*
@@ -1055,15 +1037,15 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
       /*
        * Get any acl on the xattr.
        */
-      if (!solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text)) {
-         goto cleanup;
+      if (solaris_save_xattr_acl(jcr, attrfd, attrname, &acl_text) != bxattr_exit_ok) {
+         goto bail_out;
       }
 
       /*
        * Encode the stat struct into an ASCII representation.
        */
       encode_stat(attribs, &st, 0, stream);
-      cnt = snprintf(buffer, sizeof(buffer),
+      cnt = bsnprintf(buffer, sizeof(buffer),
                      "%s%c%s%c%s%c",
                      target_attrname, 0, attribs, 0, (acl_text) ? acl_text : "", 0);
 
@@ -1071,12 +1053,17 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
        * Open the extended or extensible attribute file.
        */
       if ((attrfd = openat(fd, attrname, O_RDONLY)) < 0) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
-            target_attrname, jcr->last_fname, be.bstrerror());
-         Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
-            target_attrname, jcr->last_fname, be.bstrerror());
-         goto cleanup;
+         switch (errno) {
+         case ENOENT:
+            retval = bxattr_exit_ok;
+            goto bail_out;
+         default:
+            Mmsg3(jcr->errmsg, _("Unable to open xattr %s on \"%s\": ERR=%s\n"),
+                  target_attrname, jcr->last_fname, be.bstrerror());
+            Dmsg3(100, "openat of xattr %s on \"%s\" failed: ERR=%s\n",
+                  target_attrname, jcr->last_fname, be.bstrerror());
+            goto bail_out;
+         }
       }
       break;
 
@@ -1086,21 +1073,26 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
        * Encode the stat struct into an ASCII representation.
        */
       if (readlink(attrname, link_source, sizeof(link_source)) < 0) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
-            target_attrname, jcr->last_fname, be.bstrerror());
-         Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
-            target_attrname, jcr->last_fname, be.bstrerror());
-         goto cleanup;
+         switch (errno) {
+         case ENOENT:
+            retval = bxattr_exit_ok;
+            goto bail_out;
+         default:
+            Mmsg3(jcr->errmsg, _("Unable to read symlin %s on \"%s\": ERR=%s\n"),
+                  target_attrname, jcr->last_fname, be.bstrerror());
+            Dmsg3(100, "readlink of xattr %s on \"%s\" failed: ERR=%s\n",
+                  target_attrname, jcr->last_fname, be.bstrerror());
+            goto bail_out;
+         }
       }
 
       /*
        * Generate a xattr encoding with the reference to the target in there.
        */
       encode_stat(attribs, &st, st.st_ino, stream);
-      cnt = snprintf(buffer, sizeof(buffer),
-                     "%s%c%s%c%s%c",
-                     target_attrname, 0, attribs, 0, link_source, 0);
+      cnt = bsnprintf(buffer, sizeof(buffer),
+                      "%s%c%s%c%s%c",
+                      target_attrname, 0, attribs, 0, link_source, 0);
       pm_memcpy(jcr->xattr_data, buffer, cnt);
       jcr->xattr_data_len = cnt;
       retval = send_xattr_stream(jcr, stream);
@@ -1108,10 +1100,10 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
       /*
        * For a soft linked file we are ready now, no need to recursively save the attributes.
        */
-      goto cleanup;
+      goto bail_out;
 
    default:
-      goto cleanup;
+      goto bail_out;
    }
 
    /*
@@ -1136,9 +1128,9 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
           * Protect ourself against things getting out of hand.
           */
          if (st.st_size >= MAX_XATTR_STREAM) {
-            Jmsg2(jcr, M_ERROR, 0, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
-               jcr->last_fname, MAX_XATTR_STREAM);
-            goto cleanup;
+            Mmsg2(jcr->errmsg, _("Xattr stream on file \"%s\" exceeds maximum size of %d bytes\n"),
+                  jcr->last_fname, MAX_XATTR_STREAM);
+            goto bail_out;
          }
 
          while ((cnt = read(attrfd, buffer, sizeof(buffer))) > 0) {
@@ -1148,11 +1140,11 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
          }
 
          if (cnt < 0) {
-            Jmsg2(jcr, M_ERROR, 0, _("Unable to read content of xattr %s on file \"%s\"\n"),
-               target_attrname, jcr->last_fname);
+            Mmsg2(jcr->errmsg, _("Unable to read content of xattr %s on file \"%s\"\n"),
+                  target_attrname, jcr->last_fname);
             Dmsg2(100, "read of data from xattr %s on \"%s\" failed\n",
-               target_attrname, jcr->last_fname);
-            goto cleanup;
+                  target_attrname, jcr->last_fname);
+            goto bail_out;
          }
       }
       break;
@@ -1177,16 +1169,21 @@ static bool solaris_save_xattr(JCR *jcr, int fd, const char *xattr_namespace,
        * The recursive call could change our working dir so change back to the wanted workdir.
        */
       if (fchdir(fd) < 0) {
-         berrno be;
-         Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
-            jcr->last_fname, be.bstrerror());
-         Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
-            jcr->last_fname, fd, be.bstrerror());
-         goto cleanup;
+         switch (errno) {
+         case ENOENT:
+            retval = bxattr_exit_ok;
+            goto bail_out;
+         default:
+            Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space of file \"%s\": ERR=%s\n"),
+                  jcr->last_fname, be.bstrerror());
+            Dmsg3(100, "Unable to fchdir to xattr space of file \"%s\" using fd %d: ERR=%s\n",
+                  jcr->last_fname, fd, be.bstrerror());
+            goto bail_out;
+         }
       }
    }
 
-cleanup:
+bail_out:
    if (acl_text) {
       free(acl_text);
    }
@@ -1196,14 +1193,15 @@ cleanup:
    return retval;
 }
 
-static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
+static bxattr_exit_code solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const char *attr_parent)
 {
    const char *name;
    int fd, filefd = -1, attrdirfd = -1;
    DIR *dirp;
    struct dirent *dp;
    char current_xattr_namespace[PATH_MAX];
-   bool retval = true;                   /* default non-fatal error */
+   bxattr_exit_code retval = bxattr_exit_error;
+   berrno be;
  
    /*
     * Determine what argument to use. Use attr_parent when set
@@ -1213,26 +1211,31 @@ static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const cha
    if (attr_parent) {
       name = attr_parent;
       if (xattr_namespace) {
-         snprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
-                  xattr_namespace, attr_parent);
+         bsnprintf(current_xattr_namespace, sizeof(current_xattr_namespace), "%s%s/",
+                   xattr_namespace, attr_parent);
       } else {
-         strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
+         bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
       }
    } else {
       name = jcr->last_fname;
-      strncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
+      bstrncpy(current_xattr_namespace, "/", sizeof(current_xattr_namespace));
    }
 
    /*
     * Open the file on which to save the xattrs read-only.
     */
    if ((filefd = open(name, O_RDONLY | O_NONBLOCK)) < 0) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
-      Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
-         jcr->last_fname, be.bstrerror());
-      goto cleanup;
+      switch (errno) {
+      case ENOENT:
+         retval = bxattr_exit_ok;
+         goto bail_out;
+      default:
+         Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
+               jcr->last_fname, be.bstrerror());
+         Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
+               jcr->last_fname, be.bstrerror());
+         goto bail_out;
+      }
    }
 
    /*
@@ -1246,16 +1249,18 @@ static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const cha
           * Which is not problem we just forget about this this xattr.
           * But as this is not an error we return a positive return value.
           */
-         retval = true;
-         break;
+         retval = bxattr_exit_ok;
+         goto bail_out;
+      case ENOENT:
+         retval = bxattr_exit_ok;
+         goto bail_out;
       default:
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
-            name, jcr->last_fname, be.bstrerror());
+         Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
+               name, jcr->last_fname, be.bstrerror());
          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
-            name, jcr->last_fname, be.bstrerror());
+               name, jcr->last_fname, be.bstrerror());
+         goto bail_out;
       }
-      goto cleanup;
    }
 
   /*
@@ -1263,12 +1268,11 @@ static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const cha
    * attributes should be saved.
    */
    if (fchdir(attrdirfd) < 0) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
-         jcr->last_fname, attrdirfd, be.bstrerror());
-      goto cleanup;
+            jcr->last_fname, attrdirfd, be.bstrerror());
+      goto bail_out;
    }
 
    /*
@@ -1278,17 +1282,16 @@ static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const cha
     */
    if (!attr_parent)
       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, ".",
-                            true, STREAM_XATTR_SOLARIS);
+                         true, STREAM_XATTR_SOLARIS);
 
    if ((fd = dup(attrdirfd)) == -1 ||
        (dirp = fdopendir(fd)) == (DIR *)NULL) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("Unable to list the xattr space on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg3(100, "Unable to fdopendir xattr space on file \"%s\" using fd %d: ERR=%s\n",
-         jcr->last_fname, fd, be.bstrerror());
+            jcr->last_fname, fd, be.bstrerror());
 
-      goto cleanup;
+      goto bail_out;
    }
 
    /*
@@ -1340,7 +1343,7 @@ static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const cha
           * Save the xattr.
           */
          solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
-                               false, STREAM_XATTR_SOLARIS_SYS);
+                            false, STREAM_XATTR_SOLARIS_SYS);
          continue;
       }
 #endif /* HAVE_SYS_NVPAIR_H && _PC_SATTR_ENABLED */
@@ -1349,13 +1352,13 @@ static bool solaris_save_xattrs(JCR *jcr, const char *xattr_namespace, const cha
        * Save the xattr.
        */
       solaris_save_xattr(jcr, attrdirfd, current_xattr_namespace, dp->d_name,
-                            false, STREAM_XATTR_SOLARIS);
+                         false, STREAM_XATTR_SOLARIS);
    }
 
    closedir(dirp);
-   retval = true;
+   retval = bxattr_exit_ok;
 
-cleanup:
+bail_out:
    if (attrdirfd != -1)
       close(attrdirfd);
    if (filefd != -1)
@@ -1364,61 +1367,61 @@ cleanup:
 }
 
 #ifdef HAVE_ACL
-static bool solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
+static bxattr_exit_code solaris_restore_xattr_acl(JCR *jcr, int fd, const char *attrname, char *acl_text)
 {
 #ifdef HAVE_EXTENDED_ACL
    int error;
    acl_t *aclp = NULL;
+   berrno be;
 
    if ((error = acl_fromtext(acl_text, &aclp)) != 0) {
-      Jmsg1(jcr, M_ERROR, 0, _("Unable to convert acl from text on file \"%s\"\n"),
-               jcr->last_fname);
-      return true;                    /* non-fatal */
+      Mmsg1(jcr->errmsg, _("Unable to convert acl from text on file \"%s\"\n"),
+            jcr->last_fname);
+      return bxattr_exit_error;
    }
 
    if ((fd != -1 && facl_set(fd, aclp) != 0) ||
         acl_set(attrname, aclp) != 0) {
-      berrno be;
-      Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
-         attrname, jcr->last_fname, be.bstrerror());
+      Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
+            attrname, jcr->last_fname, be.bstrerror());
       Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
-         attrname, jcr->last_fname, be.bstrerror());
-      return true;                    /* non-fatal */
+            attrname, jcr->last_fname, be.bstrerror());
+      return bxattr_exit_error;
    }
 
    if (aclp) {
       acl_free(aclp);
    }
-   return true;
+   return bxattr_exit_ok;
 
 #else /* HAVE_EXTENDED_ACL */
    int n;
    aclent_t *acls = NULL;
+   berrno be;
 
    acls = aclfromtext(acl_text, &n);
    if (!acls) {
       if ((fd != -1 && facl(fd, SETACL, n, acls) != 0) ||
            acl(attrname, SETACL, n, acls) != 0) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
-            attrname, jcr->last_fname, be.bstrerror());
+         Mmsg3(jcr->errmsg, _("Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n"),
+               attrname, jcr->last_fname, be.bstrerror());
          Dmsg3(100, "Unable to restore acl of xattr %s on file \"%s\": ERR=%s\n",
-            attrname, jcr->last_fname, be.bstrerror());
-         return true;                   /* non-fatal */
+               attrname, jcr->last_fname, be.bstrerror());
+         return bxattr_exit_error;
       }
    }
 
    if (acls) {
       free(acls);
    }
-   return true;
+   return bxattr_exit_ok;
 
 #endif /* HAVE_EXTENDED_ACL */
 
 }
 #endif /* HAVE_ACL */
 
-static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
+static bxattr_exit_code solaris_restore_xattrs(JCR *jcr, bool is_extensible)
 {
    int fd, filefd = -1, attrdirfd = -1, attrfd = -1;
    int used_bytes, total_bytes, cnt;
@@ -1429,7 +1432,8 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
    int32_t inum;
    struct stat st;
    struct timeval times[2];
-   bool retval = true;             /* default non-fatal */
+   bxattr_exit_code retval = bxattr_exit_error;
+   berrno be;
 
    /*
     * Parse the xattr stream. First the part that is the same for all xattrs.
@@ -1453,33 +1457,30 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
     * Open the file on which to restore the xattrs read-only.
     */
    if ((filefd = open(jcr->last_fname, O_RDONLY | O_NONBLOCK)) < 0) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("Unable to open file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("Unable to open file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg2(100, "Unable to open file \"%s\": ERR=%s\n",
-         jcr->last_fname, be.bstrerror());
-      goto cleanup;
+            jcr->last_fname, be.bstrerror());
+      goto bail_out;
    }
 
    /*
     * Open the xattr naming space and make it the current working dir.
     */
    if ((attrdirfd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("Unable to open xattr space on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg2(100, "Unable to open xattr space on file \"%s\": ERR=%s\n",
-         jcr->last_fname, be.bstrerror());
-      goto cleanup;
+            jcr->last_fname, be.bstrerror());
+      goto bail_out;
    }
 
    if (fchdir(attrdirfd) < 0) {
-      berrno be;
-      Jmsg2(jcr, M_ERROR, 0, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
-         jcr->last_fname, be.bstrerror());
+      Mmsg2(jcr->errmsg, _("Unable to chdir to xattr space on file \"%s\": ERR=%s\n"),
+            jcr->last_fname, be.bstrerror());
       Dmsg3(100, "Unable to fchdir to xattr space on file \"%s\" using fd %d: ERR=%s\n",
-         jcr->last_fname, attrdirfd, be.bstrerror());
-      goto cleanup;
+            jcr->last_fname, attrdirfd, be.bstrerror());
+      goto bail_out;
    }
 
    /*
@@ -1491,12 +1492,11 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
       *bp = '\0';
 
       if ((fd = open(target_attrname, O_RDONLY | O_NONBLOCK)) < 0) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
-            target_attrname, jcr->last_fname, be.bstrerror());
+         Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
+               target_attrname, jcr->last_fname, be.bstrerror());
          Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
-            target_attrname, jcr->last_fname, be.bstrerror());
-         goto cleanup;
+               target_attrname, jcr->last_fname, be.bstrerror());
+         goto bail_out;
       }
 
       close(filefd);
@@ -1506,12 +1506,11 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
        * Open the xattr naming space.
        */
       if ((fd = openat(filefd, ".", O_RDONLY | O_XATTR)) < 0) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
-            target_attrname, jcr->last_fname, be.bstrerror());
+         Mmsg3(jcr->errmsg, _("Unable to open xattr space %s on file \"%s\": ERR=%s\n"),
+               target_attrname, jcr->last_fname, be.bstrerror());
          Dmsg3(100, "Unable to open xattr space %s on file \"%s\": ERR=%s\n",
-            target_attrname, jcr->last_fname, be.bstrerror());
-         goto cleanup;
+               target_attrname, jcr->last_fname, be.bstrerror());
+         goto bail_out;
       }
 
       close(attrdirfd);
@@ -1521,12 +1520,11 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
        * Make the xattr space our current workingdir.
        */
       if (fchdir(attrdirfd) < 0) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
-            target_attrname, jcr->last_fname, be.bstrerror());
+         Mmsg3(jcr->errmsg, _("Unable to chdir to xattr space %s on file \"%s\": ERR=%s\n"),
+               target_attrname, jcr->last_fname, be.bstrerror());
          Dmsg4(100, "Unable to fchdir to xattr space %s on file \"%s\" using fd %d: ERR=%s\n",
-            target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
-         goto cleanup;
+               target_attrname, jcr->last_fname, attrdirfd, be.bstrerror());
+         goto bail_out;
       }
 
       target_attrname = ++bp;
@@ -1558,12 +1556,11 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
        */
       unlinkat(attrdirfd, target_attrname, 0);
       if (mkfifo(target_attrname, st.st_mode) < 0) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
-            target_attrname, jcr->last_fname, be.bstrerror());
+         Mmsg3(jcr->errmsg, _("Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n"),
+               target_attrname, jcr->last_fname, be.bstrerror());
          Dmsg3(100, "Unable to mkfifo xattr %s on file \"%s\": ERR=%s\n",
-            target_attrname,  jcr->last_fname, be.bstrerror());
-         goto cleanup;
+               target_attrname,  jcr->last_fname, be.bstrerror());
+         goto bail_out;
       }
       break;
    case S_IFCHR:
@@ -1573,12 +1570,11 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
        */
       unlinkat(attrdirfd, target_attrname, 0);
       if (mknod(target_attrname, st.st_mode, st.st_rdev) < 0) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
-            target_attrname, jcr->last_fname, be.bstrerror());
+         Mmsg3(jcr->errmsg, _("Unable to mknod xattr %s on file \"%s\": ERR=%s\n"),
+               target_attrname, jcr->last_fname, be.bstrerror());
          Dmsg3(100, "Unable to mknod xattr %s on file \"%s\": ERR=%s\n",
-            target_attrname,  jcr->last_fname, be.bstrerror());
-         goto cleanup;
+               target_attrname,  jcr->last_fname, be.bstrerror());
+         goto bail_out;
       }
       break;
    case S_IFDIR:
@@ -1589,12 +1585,11 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
       if (strcmp(target_attrname, ".")) {
          unlinkat(attrdirfd, target_attrname, AT_REMOVEDIR);
          if (mkdir(target_attrname, st.st_mode) < 0) {
-            berrno be;
             Jmsg3(jcr, M_WARNING, 0, _("Unable to mkdir xattr %s on file \"%s\": ERR=%s\n"),
                target_attrname, jcr->last_fname, be.bstrerror());
             Dmsg3(100, "Unable to mkdir xattr %s on file \"%s\": ERR=%s\n",
                target_attrname,  jcr->last_fname, be.bstrerror());
-            goto cleanup;
+            goto bail_out;
          }
       }
       break;
@@ -1607,19 +1602,18 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
 
          unlinkat(attrdirfd, target_attrname, 0);
          if (link(linked_target, target_attrname) < 0) {
-            berrno be;
-            Jmsg4(jcr, M_ERROR, 0, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
-               target_attrname, linked_target, jcr->last_fname, be.bstrerror());
+            Mmsg4(jcr->errmsg, _("Unable to link xattr %s to %s on file \"%s\": ERR=%s\n"),
+                  target_attrname, linked_target, jcr->last_fname, be.bstrerror());
             Dmsg4(100, "Unable to link xattr %s to %s on file \"%s\": ERR=%s\n",
-               target_attrname, linked_target, jcr->last_fname, be.bstrerror());
-            goto cleanup;
+                  target_attrname, linked_target, jcr->last_fname, be.bstrerror());
+            goto bail_out;
          }
 
          /*
           * Successfully restored xattr.
           */
-         retval = true;
-         goto cleanup;
+         retval = bxattr_exit_ok;
+         goto bail_out;
       } else {
          if ((bp = strchr(acl_text, '\0')) == (char *)NULL ||
              (used_bytes = (bp - jcr->xattr_data)) >= total_bytes) {
@@ -1637,12 +1631,11 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
          }
 
          if ((attrfd = openat(attrdirfd, target_attrname, O_RDWR | O_CREAT | O_TRUNC, st.st_mode)) < 0) {
-            berrno be;
-            Jmsg3(jcr, M_ERROR, 0, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
-               target_attrname, jcr->last_fname, be.bstrerror());
+            Mmsg3(jcr->errmsg, _("Unable to open xattr %s on file \"%s\": ERR=%s\n"),
+                  target_attrname, jcr->last_fname, be.bstrerror());
             Dmsg3(100, "Unable to open xattr %s on file \"%s\": ERR=%s\n",
-               target_attrname, jcr->last_fname, be.bstrerror());
-            goto cleanup;
+                  target_attrname, jcr->last_fname, be.bstrerror());
+            goto bail_out;
          }
       }
 
@@ -1658,22 +1651,21 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
           * we have available as data of the stream.
           */
          if (cnt != st.st_size) {
-            Jmsg2(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
-               target_attrname, jcr->last_fname);
+            Mmsg2(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n"),
+                  target_attrname, jcr->last_fname);
             Dmsg2(100, "Unable to restore data of xattr %s on file \"%s\": Not all data available in xattr stream\n",
-               target_attrname, jcr->last_fname);
-            goto cleanup;
+                  target_attrname, jcr->last_fname);
+            goto bail_out;
          }
 
          while (cnt > 0) {
             cnt = write(attrfd, data, cnt);
             if (cnt < 0) {
-               berrno be;
-               Jmsg3(jcr, M_ERROR, 0, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
-                  target_attrname, jcr->last_fname, be.bstrerror());
+               Mmsg3(jcr->errmsg, _("Unable to restore data of xattr %s on file \"%s\": ERR=%s\n"),
+                     target_attrname, jcr->last_fname, be.bstrerror());
                Dmsg3(100, "Unable to restore data of xattr %s on file \"%s\": ERR=%s\n",
-                  target_attrname, jcr->last_fname, be.bstrerror());
-               goto cleanup;
+                     target_attrname, jcr->last_fname, be.bstrerror());
+               goto bail_out;
             }
 
             used_bytes += cnt;
@@ -1689,21 +1681,20 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
       linked_target = bp;
 
       if (symlink(linked_target, target_attrname) < 0) {
-         berrno be;
-         Jmsg4(jcr, M_ERROR, 0, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
-            target_attrname, linked_target, jcr->last_fname, be.bstrerror());
+         Mmsg4(jcr->errmsg, _("Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n"),
+               target_attrname, linked_target, jcr->last_fname, be.bstrerror());
          Dmsg4(100, "Unable to symlink xattr %s to %s on file \"%s\": ERR=%s\n",
-            target_attrname, linked_target, jcr->last_fname, be.bstrerror());
-         goto cleanup;
+               target_attrname, linked_target, jcr->last_fname, be.bstrerror());
+         goto bail_out;
       }
 
       /*
        * Successfully restored xattr.
        */
-      retval = true;
-      goto cleanup;
+      retval = bxattr_exit_ok;
+      goto bail_out;
    default:
-      goto cleanup;
+      goto bail_out;
    }
 
    /*
@@ -1717,23 +1708,25 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
              * Gentile way of the system saying this type of xattr layering is not supported.
              * But as this is not an error we return a positive return value.
              */
-            retval = true;
+            retval = bxattr_exit_ok;
+            break;
+         case ENOENT:
+            retval = bxattr_exit_ok;
             break;
          default:
-            berrno be;
-            Jmsg3(jcr, M_ERROR, 0, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
-               target_attrname, jcr->last_fname, be.bstrerror());
+            Mmsg3(jcr->errmsg, _("Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n"),
+                  target_attrname, jcr->last_fname, be.bstrerror());
             Dmsg3(100, "Unable to restore owner of xattr %s on file \"%s\": ERR=%s\n",
-               target_attrname, jcr->last_fname, be.bstrerror());
+                  target_attrname, jcr->last_fname, be.bstrerror());
          }
-         goto cleanup;
+         goto bail_out;
       }
    }
 
 #ifdef HAVE_ACL
    if (acl_text && *acl_text)
-      if (!solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text))
-         goto cleanup;
+      if (solaris_restore_xattr_acl(jcr, attrfd, target_attrname, acl_text) != bxattr_exit_ok)
+         goto bail_out;
 #endif /* HAVE_ACL */
 
    /*
@@ -1746,28 +1739,27 @@ static bool solaris_restore_xattrs(JCR *jcr, bool is_extensible)
       times[1].tv_usec = 0;
 
       if (futimesat(attrdirfd, target_attrname, times) < 0) {
-         berrno be;
-         Jmsg3(jcr, M_ERROR, 0, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
-            target_attrname, jcr->last_fname, be.bstrerror());
+         Mmsg3(jcr->errmsg, _("Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n"),
+               target_attrname, jcr->last_fname, be.bstrerror());
          Dmsg3(100, "Unable to restore filetimes of xattr %s on file \"%s\": ERR=%s\n",
-            target_attrname, jcr->last_fname, be.bstrerror());
-         goto cleanup;
+               target_attrname, jcr->last_fname, be.bstrerror());
+         goto bail_out;
       }
    }
 
    /*
     * Successfully restored xattr.
     */
-   retval = true;
-   goto cleanup;
+   retval = bxattr_exit_ok;
+   goto bail_out;
 
 parse_error:
-   Jmsg1(jcr, M_ERROR, 0, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
-      jcr->last_fname);
+   Mmsg1(jcr->errmsg, _("Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n"),
+         jcr->last_fname);
    Dmsg1(100, "Illegal xattr stream, failed to parse xattr stream on file \"%s\"\n",
-      jcr->last_fname);
+         jcr->last_fname);
 
-cleanup:
+bail_out:
    if (attrfd != -1) {
       close(attrfd);
    }
@@ -1780,11 +1772,37 @@ cleanup:
    return retval;
 }
 
-static bool solaris_extract_xattr(JCR *jcr, int stream)
+static bxattr_exit_code solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
+{
+   char cwd[PATH_MAX];
+   bxattr_exit_code retval = bxattr_exit_ok;
+
+   /*
+    * First see if extended attributes or extensible attributes are present.
+    * If not just pretend things went ok.
+    */
+   if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
+      nr_xattr_saved = 0;
+
+      /*
+       * As we change the cwd in the save function save the current cwd
+       * for restore after return from the solaris_save_xattrs function.
+       */
+      xattr_link_cache = New(alist(10, not_owned_by_alist));
+      getcwd(cwd, sizeof(cwd));
+      retval = solaris_save_xattrs(jcr, NULL, NULL);
+      chdir(cwd);
+      delete xattr_link_cache;
+      xattr_link_cache = NULL;
+   }
+   return retval;
+}
+
+static bxattr_exit_code solaris_parse_xattr_streams(JCR *jcr, int stream)
 {
    char cwd[PATH_MAX];
    bool is_extensible = false;
-   bool retval;
+   bxattr_exit_code retval;
 
    /*
     * First make sure we can restore xattr on the filesystem.
@@ -1798,7 +1816,7 @@ static bool solaris_extract_xattr(JCR *jcr, int stream)
                jcr->last_fname);
          Dmsg1(100, "Unable to restore extensible attributes on file \"%s\", filesystem doesn't support this\n",
             jcr->last_fname);
-         return true;
+         return bxattr_exit_error;
       }
 
       is_extensible = true;
@@ -1811,11 +1829,11 @@ static bool solaris_extract_xattr(JCR *jcr, int stream)
                jcr->last_fname);
          Dmsg1(100, "Unable to restore extended attributes on file \"%s\", filesystem doesn't support this\n",
             jcr->last_fname);
-         return true;
+         return bxattr_exit_error;
       }
       break;
    default:
-      return true;
+      return bxattr_exit_error;
    }
 
    /*
@@ -1828,101 +1846,46 @@ static bool solaris_extract_xattr(JCR *jcr, int stream)
    return retval;
 }
 
-static int solaris_build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
-{
-   char cwd[PATH_MAX];
-   bool retval = true;
-
-   /*
-    * First see if extended attributes or extensible attributes are present.
-    * If not just pretend things went ok.
-    */
-   if (pathconf(jcr->last_fname, _PC_XATTR_EXISTS) > 0) {
-      nr_xattr_saved = 0;
 
-      /*
-       * As we change the cwd in the save function save the current cwd
-       * for restore after return from the solaris_save_xattrs function.
-       */
-      getcwd(cwd, sizeof(cwd));
-      retval = solaris_save_xattrs(jcr, NULL, NULL);
-      chdir(cwd);
-      drop_xattr_link_cache();
-   }
+/*
+ * Function pointers to the build and parse function to use for these xattrs.
+ */
+static bxattr_exit_code (*os_build_xattr_streams)(JCR *jcr, FF_PKT *ff_pkt) = solaris_build_xattr_streams;
+static bxattr_exit_code (*os_parse_xattr_streams)(JCR *jcr, int stream) = solaris_parse_xattr_streams;
 
-   return retval;
-}
+#endif /* defined(HAVE_SUN_OS) */
 
-static bool solaris_parse_xattr_stream(JCR *jcr, int stream)
+/*
+ * Entry points when compiled with support for XATTRs on a supported platform.
+ */
+bxattr_exit_code build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
 {
-   switch (stream) {
-#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
-   case STREAM_XATTR_SOLARIS_SYS:
-#endif
-   case STREAM_XATTR_SOLARIS:
-      return solaris_extract_xattr(jcr, stream);
-   default:
-      Jmsg2(jcr, M_WARNING, 0,
-         _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
-         jcr->last_fname, stream);
-      return true;                    /* non-fatal error */
+   if (os_build_xattr_streams) {
+      return (*os_build_xattr_streams)(jcr, ff_pkt);
    }
+   return bxattr_exit_error;
 }
-#endif
 
-bool build_xattr_streams(JCR *jcr, FF_PKT *ff_pkt)
+bxattr_exit_code parse_xattr_streams(JCR *jcr, int stream)
 {
-#if defined(HAVE_SUN_OS)
-   return solaris_build_xattr_streams(jcr, ff_pkt);
-#elif defined(HAVE_DARWIN_OS)
-   return darwin_build_xattr_streams(jcr, ff_pkt);
-#elif defined(HAVE_FREEBSD_OS)
-   return freebsd_build_xattr_streams(jcr, ff_pkt);
-#elif defined(HAVE_LINUX_OS)
-   return linux_build_xattr_streams(jcr, ff_pkt);
-#elif defined(HAVE_NETBSD_OS)
-   return netbsd_build_xattr_streams(jcr, ff_pkt);
-#endif
-}
+   unsigned int cnt;
 
-bool parse_xattr_stream(JCR *jcr, int stream)
-{
-   /*
-    * Based on the stream being passed in dispatch to the right function
-    * for parsing and restoring a specific xattr. The platform determines
-    * which streams are recognized and parsed and which are handled by
-    * the default case and ignored. As only one of the platform defines
-    * is true per compile we never end up with duplicate switch values.
-    */
-   switch (stream) {
-#if defined(HAVE_SUN_OS)
-#if defined(HAVE_SYS_NVPAIR_H) && defined(_PC_SATTR_ENABLED)
-   case STREAM_XATTR_SOLARIS_SYS:
-#endif
-   case STREAM_XATTR_SOLARIS:
-      return solaris_parse_xattr_stream(jcr, stream);
-#elif defined(HAVE_DARWIN_OS)
-   case STREAM_XATTR_DARWIN:
-      return darwin_parse_xattr_stream(jcr, stream);
-#elif defined(HAVE_FREEBSD_OS)
-   case STREAM_XATTR_FREEBSD:
-      return freebsd_parse_xattr_stream(jcr, stream);
-#elif defined(HAVE_LINUX_OS)
-   case STREAM_XATTR_LINUX:
-      return linux_parse_xattr_stream(jcr, stream);
-#elif defined(HAVE_NETBSD_OS)
-   case STREAM_XATTR_NETBSD:
-      return netbsd_parse_xattr_stream(jcr, stream);
-#endif
-   default:
+   if (os_parse_xattr_streams) {
       /*
-       * Issue a warning and discard the message. But pretend the restore was ok.
+       * See if we can parse this stream, and ifso give it a try.
        */
-      Qmsg2(jcr, M_WARNING, 0,
-         _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
-         jcr->last_fname, stream);
-      return true;
-   } /* end switch (stream) */
+      for (cnt = 0; cnt < sizeof(os_default_xattr_streams) / sizeof(int); cnt++) {
+         if (os_default_xattr_streams[cnt] == stream) {
+            return (*os_parse_xattr_streams)(jcr, stream);
+         }
+      }
+   }
+   /*
+    * Issue a warning and discard the message. But pretend the restore was ok.
+    */
+   Jmsg2(jcr, M_WARNING, 0,
+      _("Can't restore Extended Attributes of %s - incompatible xattr stream encountered - %d\n"),
+      jcr->last_fname, stream);
+   return bxattr_exit_error;
 }
-
 #endif
index 2adec4fb97462e2fcc9c2e2a56c4ada46ab94054..16056165e72aaf11725b3742c62a301eaf36d651 100644 (file)
 /*
  * Internal representation of an extended attribute.
  */
-typedef struct xattr {
+struct xattr_t {
    uint32_t magic;
    uint32_t name_length;
    char *name;
    uint32_t value_length;
    char *value;
-} xattr_t;
+};
 
 /*
  * Internal representation of an extended attribute hardlinked file.
  */
-typedef struct xattr_link_cache_entry {
+struct xattr_link_cache_entry_t {
    uint32_t inum;
    char target[PATH_MAX];
-   struct xattr_link_cache_entry *next;
-} xattr_link_cache_entry_t;
+};
 
 /*
  * Maximum size of the XATTR stream this prevents us from blowing up the filed.
index a4e3a59362d66e8bef1b78dd4e8de9ea53baaf36..62363b6d55416c127e36226451dc7b956bd78156 100644 (file)
@@ -47,7 +47,7 @@ LIBBACFIND_LT_AGE = 0
        @echo "Compiling $<"
        $(NO_ECHO)$(LIBTOOL_COMPILE) $(CXX) $(DEFS) $(DEBUG) -c $(WCFLAGS) $(CPPFLAGS) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $<
 #-------------------------------------------------------------------------
-all: Makefile libbacfind$(DEFAULT_ARCHIVE_TYPE) libbacfind.a ../lib/libbac$(DEFAULT_ARCHIVE_TYPE)
+all: Makefile libbacfind$(DEFAULT_ARCHIVE_TYPE) ../lib/libbac$(DEFAULT_ARCHIVE_TYPE)
        @echo "==== Make of findlib is good ===="
        @echo " "
 
index cbcc8cf1eb2d3c64d9de086ea602ab2fbc3370e8..3c7796f70fb23252ff8a34e7766266fa98dc405e 100644 (file)
@@ -80,6 +80,7 @@
 #define JS_FatalError            'f'  /* Fatal error */
 #define JS_Differences           'D'  /* Verify differences */
 #define JS_Canceled              'A'  /* canceled by user */
+#define JS_Incomplete            'I'  /* Incomplete Job */
 #define JS_WaitFD                'F'  /* waiting on File daemon */
 #define JS_WaitSD                'S'  /* waiting on the Storage daemon */
 #define JS_WaitMedia             'm'  /* waiting for new media */
@@ -111,7 +112,9 @@ enum {
 #define job_canceled(jcr) \
   (jcr->JobStatus == JS_Canceled || \
    jcr->JobStatus == JS_ErrorTerminated || \
-   jcr->JobStatus == JS_FatalError)
+   jcr->JobStatus == JS_FatalError || \
+   jcr->JobStatus == JS_Incomplete \
+  )
 
 #define job_waiting(jcr) \
   (jcr->JobStatus == JS_WaitFD       || \
@@ -181,6 +184,10 @@ public:
    void init_mutex(void) {pthread_mutex_init(&mutex, NULL); };
    void destroy_mutex(void) {pthread_mutex_destroy(&mutex); };
    bool is_job_canceled() {return job_canceled(this); };
+   void set_JobLevel(int32_t JobLevel) { m_JobLevel = JobLevel; };
+   void setJobLevel(int32_t JobLevel) { m_JobLevel = JobLevel; };
+   void set_JobType(int32_t JobType) { m_JobType = JobType; };
+   void setJobType(int32_t JobType) { m_JobType = JobType; };
    int32_t get_JobType() { return m_JobType; };
    int32_t getJobType() { return m_JobType; };
    int32_t get_JobLevel() { return m_JobLevel; };
@@ -191,10 +198,6 @@ public:
    };
    const char *get_OperationName();       /* in lib/jcr.c */
    const char *get_ActionName(bool past); /* in lib/jcr.c */
-   void set_JobLevel(int32_t JobLevel);   /* in lib/jcr.c */
-   void setJobLevel(int32_t JobLevel);    /* in lib/jcr.c */
-   void set_JobType(int32_t JobType);     /* in lib/jcr.c */
-   void setJobType(int32_t JobType);      /* in lib/jcr.c */
    void setJobStatus(int JobStatus);      /* in lib/jcr.c */
    bool JobReads();                       /* in lib/jcr.c */
    
@@ -350,8 +353,10 @@ public:
    POOLMEM *last_fname;               /* last file saved/verified */
    POOLMEM *acl_data;                 /* data with ACLs for backup/restore */
    uint32_t acl_data_len;             /* length of acl data buffer */
+   uint32_t total_acl_errors;         /* numbers of errors encountered for acl backup/restore */
    POOLMEM *xattr_data;               /* data with Extended Attributes for backup/restore */
    uint32_t xattr_data_len;           /* length of xattr_data buffer */
+   uint32_t total_xattr_errors;       /* numbers of errors encountered for xattr backup/restore */
    int32_t last_type;                 /* type of last file saved/verified */
    int incremental;                   /* set if incremental for SINCE */
    utime_t mtime;                     /* begin time for SINCE */
index ee2415db8d8caae6c4e88e01089731923a095278..8f802b15111eaa286f8b88bc474c96734e8db3b7 100644 (file)
@@ -192,7 +192,7 @@ int32_t bnet_recv(BSOCK * bsock)
  */
 bool is_bnet_stop(BSOCK * bsock)
 {
-   return bsock->errors || bsock->is_terminated();
+   return bsock->is_stop();
 }
 
 /*
@@ -200,8 +200,7 @@ bool is_bnet_stop(BSOCK * bsock)
  */
 int is_bnet_error(BSOCK * bsock)
 {
-   errno = bsock->b_errno;
-   return bsock->errors;
+   return bsock->is_error();
 }
 
 /*
index fca01157a40ba3e82dccf1de8969d3e06dfd711c..996ce4973e6a36546f147f5c6cef1a07842e1cd3 100644 (file)
@@ -59,6 +59,7 @@ private:
    char *m_host;                      /* Host name/IP */
    int m_port;                        /* desired port */
    btimer_t *m_tid;                   /* timer id */
+   boffset_t m_data_end;              /* offset of last valid data written */
    volatile bool m_timed_out: 1;      /* timed out in read/write */
    volatile bool m_terminated: 1;     /* set when BNET_TERMINATE arrives */
    bool m_duped: 1;                   /* set if duped BSOCK */
@@ -135,6 +136,7 @@ public:
    bool is_timed_out() { return m_timed_out; };
    bool is_stop() { return errors || is_terminated(); }
    bool is_error() { errno = b_errno; return errors; }
+   void set_data_end() { if (m_spool) m_data_end = ftello(m_spool_fd); };
    void set_spooling() { m_spool = true; };
    void clear_spooling() { m_spool = false; };
    void set_duped() { m_duped = true; };
index f45683ef30203f60bae3a08f22c1e856a950a485..477fde6161b9eca5e75a1ec75a7569dcca82c757 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -270,18 +270,6 @@ const char *JCR::get_ActionName(bool past)
    }
 }
 
-/* Set Job type in JCR and also set appropriate read flag */
-void JCR::set_JobType(int32_t JobType)
-{
-   m_JobType = JobType;
-}
-
-/* Set Job level in JCR and also set appropriate read flag */
-void JCR::set_JobLevel(int32_t JobLevel)
-{
-   m_JobLevel = JobLevel;
-}
-
 bool JCR::JobReads()
 {
    switch (m_JobType) {
@@ -367,9 +355,9 @@ JCR *new_jcr(int size, JCR_free_HANDLER *daemon_free_jcr)
    /* Setup some dummy values */
    bstrncpy(jcr->Job, "*System*", sizeof(jcr->Job));
    jcr->JobId = 0;
-   jcr->set_JobType(JT_SYSTEM);          /* internal job until defined */
-   jcr->set_JobLevel(L_NONE);
-   set_jcr_job_status(jcr, JS_Created);       /* ready to run */
+   jcr->setJobType(JT_SYSTEM);           /* internal job until defined */
+   jcr->setJobLevel(L_NONE);
+   jcr->setJobStatus(JS_Created);        /* ready to run */
    set_jcr_in_tsd(jcr);
    sigtimer.sa_flags = 0;
    sigtimer.sa_handler = timeout_handler;
@@ -653,6 +641,30 @@ JCR *get_jcr_by_id(uint32_t JobId)
    return jcr;
 }
 
+/*
+ * Given a thread id, find the JobId
+ *   Returns: JobId on success
+ *            0 on failure
+ */
+uint32_t get_jobid_from_tid(pthread_t tid)
+{
+   JCR *jcr = NULL;
+   bool found = false;
+
+   foreach_jcr(jcr) {
+      if (pthread_equal(jcr->my_thread_id, tid)) {
+         found = true;
+         break;
+      }
+   }
+   endeach_jcr(jcr);
+   if (found) {
+      return jcr->JobId;
+   }
+   return 0;
+}
+
+
 /*
  * Given a SessionId and SessionTime, find the JCR
  *   Returns: jcr on success
@@ -740,6 +752,7 @@ static int get_status_priority(int JobStatus)
    case JS_ErrorTerminated:
    case JS_FatalError:
    case JS_Canceled:
+   case JS_Incomplete:
       priority = 10;
       break;
    case JS_Error:
index 9cf9649c5039999a62841863f7cf2725e71d488a..f8876e3bbc5f7e2ed0467c590c1147ecca488f35 100644 (file)
@@ -637,13 +637,14 @@ int lmgr_mutex_unlock(pthread_mutex_t *m, const char *file, int line)
 /* TODO: check this
  */
 int lmgr_cond_wait(pthread_cond_t *cond,
-                   pthread_mutex_t *mutex)
+                   pthread_mutex_t *mutex,
+                   const char *file, int line)
 {
    int ret;
    lmgr_thread_t *self = lmgr_get_thread_info();
-   self->do_V(mutex);   
+   self->do_V(mutex, file, line);   
    ret = pthread_cond_wait(cond, mutex);
-   self->pre_P(mutex);
+   self->pre_P(mutex, file, line);
    self->post_P();
    return ret;
 }
@@ -655,10 +656,10 @@ int lmgr_cond_wait(pthread_cond_t *cond,
  * pthread_mutex_lock(m);
  * lmgr_post_lock(m);
  */
-void lmgr_pre_lock(void *m)
+void lmgr_pre_lock(void *m, const char *file, int line)
 {
    lmgr_thread_t *self = lmgr_get_thread_info();
-   self->pre_P(m);
+   self->pre_P(m, file, line);
 }
 
 /*
@@ -673,10 +674,10 @@ void lmgr_post_lock()
 /*
  * Do directly pre_P and post_P (used by trylock)
  */
-void lmgr_do_lock(void *m)
+void lmgr_do_lock(void *m, const char *file, int line)
 {
    lmgr_thread_t *self = lmgr_get_thread_info();
-   self->pre_P(m);
+   self->pre_P(m, file, line);
    self->post_P();
 }
 
index 83d9b3c879bf0ed73fd95c9300b94dc6075515ed..173c90537223ad0c2e0916e48f400715a27c6cb9 100644 (file)
@@ -47,7 +47,8 @@ void lmgr_v(pthread_mutex_t *m);
 
 /* Not yet working */
 int lmgr_cond_wait(pthread_cond_t *cond,
-                   pthread_mutex_t *mutex);
+                   pthread_mutex_t *mutex,
+                   const char *file="*unknown*", int line=0);
 
 /* Replacement of pthread_mutex_lock() */
 int lmgr_mutex_lock(pthread_mutex_t *m, 
@@ -60,10 +61,18 @@ int lmgr_mutex_unlock(pthread_mutex_t *m,
 /* 
  * Use them when you want use your lock yourself (ie rwlock)
  */
-void lmgr_pre_lock(void *m);    /* Call before requesting the lock */
-void lmgr_post_lock();          /* Call after getting it */
-void lmgr_do_lock(void *m);     /* Same as pre+post lock */
-void lmgr_do_unlock(void *m);   /* Call just before releasing the lock */
+
+/* Call before requesting the lock */
+void lmgr_pre_lock(void *m, const char *file="*unknown*", int line=0);
+
+/* Call after getting it */ 
+void lmgr_post_lock();
+
+/* Same as pre+post lock */
+void lmgr_do_lock(void *m, const char *file="*unknown*", int line=0);
+
+/* Call just before releasing the lock */
+void lmgr_do_unlock(void *m); 
 
 /*
  * Each thread have to call this function to put a lmgr_thread_t object
@@ -119,7 +128,7 @@ int lmgr_thread_create(pthread_t *thread,
 # define V(x) lmgr_mutex_unlock(&(x), __FILE__, __LINE__)
 # define pthread_mutex_lock(x)       lmgr_mutex_lock(x, __FILE__, __LINE__)
 # define pthread_mutex_unlock(x)     lmgr_mutex_unlock(x, __FILE__, __LINE__)
-# define pthread_cond_wait(x,y)      lmgr_cond_wait(x,y)
+# define pthread_cond_wait(x,y)      lmgr_cond_wait(x,y, __FILE__, __LINE__)
 # define pthread_create(a, b, c, d)  lmgr_thread_create(a,b,c,d)
 #endif
 
index d2efd2c9fabef2e0eada846fbd14922257d39171..5379ec5e05732f1fe72f360f9a594237e0b770ea 100644 (file)
@@ -191,23 +191,24 @@ bool             is_an_integer           (const char *n);
 bool             is_name_valid           (char *name, POOLMEM **msg);
 
 /* jcr.c (most definitions are in src/jcr.h) */
-void init_last_jobs_list();
-void term_last_jobs_list();
-void lock_last_jobs_list();
-void unlock_last_jobs_list();
-bool read_last_jobs_list(int fd, uint64_t addr);
+void     init_last_jobs_list();
+void     term_last_jobs_list();
+void     lock_last_jobs_list();
+void     unlock_last_jobs_list();
+bool     read_last_jobs_list(int fd, uint64_t addr);
 uint64_t write_last_jobs_list(int fd, uint64_t addr);
-void write_state_file(char *dir, const char *progname, int port);
-void job_end_push(JCR *jcr, void job_end_cb(JCR *jcr,void *), void *ctx);
-void lock_jobs();
-void unlock_jobs();
-JCR *jcr_walk_start();
-JCR *jcr_walk_next(JCR *prev_jcr);
-void jcr_walk_end(JCR *jcr);
+void     write_state_file(char *dir, const char *progname, int port);
+void     job_end_push(JCR *jcr, void job_end_cb(JCR *jcr,void *), void *ctx);
+void     lock_jobs();
+void     unlock_jobs();
+JCR     *jcr_walk_start();
+JCR     *jcr_walk_next(JCR *prev_jcr);
+void     jcr_walk_end(JCR *jcr);
+JCR     *get_jcr_from_tsd();
+void     set_jcr_in_tsd(JCR *jcr);
+void     remove_jcr_from_tsd(JCR *jcr);
 uint32_t get_jobid_from_tsd();             
-JCR *get_jcr_from_tsd();
-void set_jcr_in_tsd(JCR *jcr);
-void remove_jcr_from_tsd(JCR *jcr);
+uint32_t get_jobid_from_tid(pthread_t tid);
 
 
 /* lex.c */
index 908d5c3764d016e26611a31b709b2e6a3f4f254f..e91b9eab373d02f67bfef8faa74d4a18a819e2bc 100644 (file)
@@ -233,7 +233,7 @@ int rwl_writelock(brwlock_t *rwl)
       pthread_mutex_unlock(&rwl->mutex);
       return 0;
    }
-   lmgr_pre_lock(rwl);
+   lmgr_pre_lock(rwl, __FILE__, __LINE__);
    if (rwl->w_active || rwl->r_active > 0) {
       rwl->w_wait++;                  /* indicate that we are waiting */
       pthread_cleanup_push(rwl_write_release, (void *)rwl);
@@ -278,7 +278,7 @@ int rwl_writetrylock(brwlock_t *rwl)
    } else {
       rwl->w_active = 1;              /* we are running */
       rwl->writer_id = pthread_self(); /* save writer thread's id */
-      lmgr_do_lock(rwl);
+      lmgr_do_lock(rwl, __FILE__, __LINE__);
    }
    stat2 = pthread_mutex_unlock(&rwl->mutex);
    return (stat == 0 ? stat2 : stat);
index a8b39936edeafaa3784d8c23ba6819a0006d918c..0e5acea298d5a0cd645a156ff77301f2b8cfcb5c 100644 (file)
@@ -101,10 +101,9 @@ static void dbg_print_bacula()
    /* Print also B_DB and RWLOCK structure 
     * Can add more info about JCR with dbg_jcr_add_hook()
     */
+   dbg_print_lock(fp);
    _dbg_print_jcr(fp);
-
    _dbg_print_plugin(fp);
-   dbg_print_lock(fp);
 
    if (fp != stderr) {
       fclose(fp);
index 45b4d555057b32bf902b0f9a9e644263d8a81578..7e3b8ebacf3e017e53c420d45cd8e42585a6d13c 100644 (file)
@@ -52,7 +52,7 @@ FORMS += medialist/medialist.ui mediaedit/mediaedit.ui joblist/joblist.ui
 FORMS += clients/clients.ui storage/storage.ui fileset/fileset.ui
 FORMS += joblog/joblog.ui jobs/jobs.ui job/job.ui
 FORMS += help/help.ui mediainfo/mediainfo.ui
-FORMS += status/dirstat.ui
+FORMS += status/dirstat.ui storage/content.ui
 FORMS += status/clientstat.ui
 FORMS += status/storstat.ui
 qwt {
@@ -115,6 +115,10 @@ SOURCES += clients/clients.cpp
 HEADERS += storage/storage.h
 SOURCES += storage/storage.cpp
 
+## Storage content
+HEADERS += storage/content.h
+SOURCES += storage/content.cpp
+
 ## Fileset
 HEADERS += fileset/fileset.h
 SOURCES += fileset/fileset.cpp
diff --git a/bacula/src/qt-console/images/W.png b/bacula/src/qt-console/images/W.png
new file mode 100644 (file)
index 0000000..6d7dbad
Binary files /dev/null and b/bacula/src/qt-console/images/W.png differ
diff --git a/bacula/src/qt-console/images/runit.png b/bacula/src/qt-console/images/runit.png
new file mode 100644 (file)
index 0000000..4dd2e8f
Binary files /dev/null and b/bacula/src/qt-console/images/runit.png differ
index ec9ef8d122499a7cda4525cc6d80fec69e2657b4..42d51b21c03854a85287ce6d88b42821b77cc48b 100644 (file)
@@ -30,6 +30,7 @@
 #include "job.h"
 #include "util/fmtwidgetitem.h"
 #include "mediainfo/mediainfo.h"
+#include "run/run.h"
 
 Job::Job(QString &jobId, QTreeWidgetItem *parentTreeWidgetItem)
 {
@@ -45,6 +46,7 @@ Job::Job(QString &jobId, QTreeWidgetItem *parentTreeWidgetItem)
 
    connect(pbRefresh, SIGNAL(clicked()), this, SLOT(populateAll()));
    connect(pbDelete, SIGNAL(clicked()), this, SLOT(deleteJob()));
+   connect(pbRun, SIGNAL(clicked()), this, SLOT(rerun()));
    connect(list_Volume, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(showInfoVolume(QListWidgetItem *)));
 
    populateAll();
@@ -52,6 +54,16 @@ Job::Job(QString &jobId, QTreeWidgetItem *parentTreeWidgetItem)
    setCurrent();
 }
 
+void Job::rerun()
+{
+   new runPage(label_Name->text(),
+               label_Level->text(),
+               label_Pool->text(),
+               QString(""),              // storage
+               label_Client->text(),
+               label_FileSet->text());
+}
+
 void Job::showInfoVolume(QListWidgetItem *item)
 {
    QString s= item->text();
@@ -98,7 +110,7 @@ void Job::getFont()
 
 void Job::populateAll()
 {
-   Pmsg0(0, "populateAll()\n");
+// Pmsg0(50, "populateAll()\n");
    populateText();
    populateForm();
    populateVolumes();
@@ -124,9 +136,9 @@ void Job::populateText()
       if (!results.size()) {
          QMessageBox::warning(this, tr("Bat"),
             tr("There were no results!\n"
-              "It is possible you may need to add \"catalog = all\" "
-              "to the Messages resource for this job.\n"), QMessageBox::Ok);
-        return;
+               "It is possible you may need to add \"catalog = all\" "
+               "to the Messages resource for this job.\n"), QMessageBox::Ok);
+         return;
       } 
 
       QString jobstr("JobId "); /* FIXME: should this be translated ? */
@@ -141,47 +153,47 @@ void Job::populateText()
       QString lastSvc;
       foreach (QString resultline, results) {
          fieldlist = resultline.split("\t");
-        
-        if (fieldlist.size() < 2)
-           continue;
-
-        QString curTime = fieldlist[0].trimmed();
-
-        field = fieldlist[1].trimmed();
-        int colon = field.indexOf(":");
-        if (colon > 0) {
-           /* string is like <service> <jobId xxxx>: ..." 
-            * we split at ':' then remove the jobId xxxx string (always the same) */ 
-           QString curSvc(field.left(colon).replace(jobstr,"").trimmed());
-           if (curSvc == lastSvc  && curTime == lastTime) {
-              curTime.clear();
-              curSvc.clear(); 
-           } else {
-              lastTime = curTime;
-              lastSvc = curSvc;
-           }
-//         htmlbuf += "<td>" + curTime + "</td>";
-           htmlbuf += "\n" + curSvc + " ";
-
-           /* rest of string is marked as pre-formatted (here trimming should
-            * be avoided, to preserve original formatting) */
-           QString msg(field.mid(colon+2));
-           if (msg.startsWith( tr("Error:")) ) { /* FIXME: should really be translated ? */
-              /* error msg, use a specific class */
-              htmlbuf += "</pre><pre class=err>" + msg + "</pre><pre>";
-           } else {
-              htmlbuf += msg ;
-           }
-        } else {
-           /* non standard string, place as-is */
-           if (curTime == lastTime) {
-              curTime.clear();
-           } else {
-              lastTime = curTime;
-           }
-//         htmlbuf += "<td>" + curTime + "</td>";
-           htmlbuf += "\n" + field ;
-        }
+         
+         if (fieldlist.size() < 2)
+            continue;
+
+         QString curTime = fieldlist[0].trimmed();
+
+         field = fieldlist[1].trimmed();
+         int colon = field.indexOf(":");
+         if (colon > 0) {
+            /* string is like <service> <jobId xxxx>: ..." 
+             * we split at ':' then remove the jobId xxxx string (always the same) */ 
+            QString curSvc(field.left(colon).replace(jobstr,"").trimmed());
+            if (curSvc == lastSvc  && curTime == lastTime) {
+               curTime.clear();
+               curSvc.clear(); 
+            } else {
+               lastTime = curTime;
+               lastSvc = curSvc;
+            }
+//          htmlbuf += "<td>" + curTime + "</td>";
+            htmlbuf += "\n" + curSvc + " ";
+
+            /* rest of string is marked as pre-formatted (here trimming should
+             * be avoided, to preserve original formatting) */
+            QString msg(field.mid(colon+2));
+            if (msg.startsWith( tr("Error:")) ) { /* FIXME: should really be translated ? */
+               /* error msg, use a specific class */
+               htmlbuf += "</pre><pre class=err>" + msg + "</pre><pre>";
+            } else {
+               htmlbuf += msg ;
+            }
+         } else {
+            /* non standard string, place as-is */
+            if (curTime == lastTime) {
+               curTime.clear();
+            } else {
+               lastTime = curTime;
+            }
+//          htmlbuf += "<td>" + curTime + "</td>";
+            htmlbuf += "\n" + field ;
+         }
   
       } /* foreach resultline */
 
@@ -202,7 +214,7 @@ void Job::populateText()
  */
 void Job::populateForm()
 {
-   QString stat;
+   QString stat, err;
    char buf[256];
    QString query = 
       "SELECT JobId, Job.Name, Level, Client.Name, Pool.Name, FileSet, SchedTime, StartTime, EndTime, "
@@ -233,9 +245,13 @@ void Job::populateForm()
 
          label_JobBytes->setText(convertBytesSI(fld.next().toULongLong()));
          label_JobFiles->setText(fld.next());
-         label_JobErrors->setText(fld.next());
+         err = fld.next();
+         label_JobErrors->setText(err);
 
          stat=fld.next();
+         if (stat == "T" && err.toInt() > 0) {
+            stat = "W";
+         }
          label_JobStatus->setPixmap(QPixmap(":/images/" + stat + ".png"));
          jobstatus_to_ascii_gui(stat[0].toAscii(), buf, sizeof(buf));
          stat = buf;
@@ -253,7 +269,7 @@ void Job::populateVolumes()
       "SELECT DISTINCT VolumeName, InChanger, Slot "
       "FROM Job JOIN JobMedia USING (JobId) JOIN Media USING (MediaId) "
       "WHERE JobId=" + m_jobId + " ORDER BY VolumeName "; 
-   Pmsg1(000, "Query cmd : %s\n",query.toUtf8().data());
+   if (mainWin->m_sqlDebug) Pmsg1(0, "Query cmd : %s\n",query.toUtf8().data());
          
 
    QStringList results;
index 2b3d04648995c9b427f800ffe749a56946494a89..45dcdb86e2d3276d4350df046aa94c5e5617c1ff 100644 (file)
@@ -43,6 +43,7 @@ public slots:
    void populateAll();
    void deleteJob();
    void showInfoVolume(QListWidgetItem *);
+   void rerun();
 
 private slots:
 
index 4a74afca01b811947523acc622ee6a6da7270172..169c8d26379dc2b3af75c38ad55262bb871b890b 100644 (file)
@@ -87,9 +87,6 @@
        </item>
        <item>
         <widget class="QPushButton" name="pbRun" >
-         <property name="enabled" >
-          <bool>false</bool>
-         </property>
          <property name="sizePolicy" >
           <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
            <horstretch>0</horstretch>
index 0f9d56ea1688f08f1aadb69218a201a1b11cfd82..6ce0b03e4816bf401ae15c9876d48969df0612dc 100644 (file)
@@ -1,64 +1,66 @@
 <RCC>
-  <qresource prefix="/" >
-    <file>images/edit.png</file>
-    <file>images/extern.png</file>
-    <file>images/intern.png</file>
-    <file>images/R.png</file>
-    <file>images/T.png</file>
-    <file>images/f.png</file>
-    <file>images/A.png</file>
-    <file>images/inflag2.png</file>
-    <file>images/inflag0.png</file>
-    <file>images/inflag1.png</file>
-    <file>images/purge.png</file>
-    <file>images/zoom.png</file>
-    <file>images/applications-graphics.png</file>
-    <file>images/bat.png</file>
-    <file>images/bat_icon.png</file>
-    <file>images/browse.png</file>
-    <file>images/cartridge-edit.png</file>
-    <file>images/cartridge.png</file>
-    <file>images/check.png</file>
-    <file>images/connected.png</file>
-    <file>images/copy.png</file>
-    <file>images/cut.png</file>
-    <file>images/disconnected.png</file>
-    <file>images/edit-cut.png</file>
-    <file>images/edit-delete.png</file>
-    <file>images/emblem-system.png</file>
-    <file>images/estimate-job.png</file>
-    <file>images/folder.png</file>
-    <file>images/folderbothchecked.png</file>
-    <file>images/folderchecked.png</file>
-    <file>images/folderunchecked.png</file>
-    <file>images/go-down.png</file>
-    <file>images/go-up.png</file>
-    <file>images/graph1.png</file>
-    <file>images/help-browser.png</file>
-    <file>images/joblog.png</file>
-    <file>images/label.png</file>
-    <file>images/mail-message-new.png</file>
-    <file>images/mail-message-pending.png</file>
-    <file>images/mark.png</file>
-    <file>images/network-server.png</file>
-    <file>images/new.png</file>
-    <file>images/open.png</file>
-    <file>images/package-x-generic.png</file>
-    <file>images/paste.png</file>
-    <file>images/print.png</file>
-    <file>images/restore.png</file>
-    <file>images/run.png</file>
-    <file>images/save.png</file>
-    <file>images/status-console.png</file>
-    <file>images/status.png</file>
-    <file>images/system-file-manager.png</file>
-    <file>images/unchecked.png</file>
-    <file>images/undo.png</file>
-    <file>images/unmark.png</file>
-    <file>images/up.png</file>
-    <file>images/utilities-terminal.png</file>
-    <file>images/view-refresh.png</file>
-    <file>images/weather-severe-alert.png</file>
-    <file>images/go-jump.png</file>
-  </qresource>
+    <qresource prefix="/" >
+        <file>images/A.png</file>
+        <file>images/R.png</file>
+        <file>images/T.png</file>
+        <file>images/W.png</file>
+        <file>images/applications-graphics.png</file>
+        <file>images/bat.png</file>
+        <file>images/bat_icon.png</file>
+        <file>images/browse.png</file>
+        <file>images/cartridge-edit.png</file>
+        <file>images/cartridge.png</file>
+        <file>images/check.png</file>
+        <file>images/connected.png</file>
+        <file>images/copy.png</file>
+        <file>images/cut.png</file>
+        <file>images/disconnected.png</file>
+        <file>images/edit-cut.png</file>
+        <file>images/edit-delete.png</file>
+        <file>images/edit.png</file>
+        <file>images/emblem-system.png</file>
+        <file>images/estimate-job.png</file>
+        <file>images/extern.png</file>
+        <file>images/f.png</file>
+        <file>images/folder.png</file>
+        <file>images/folderbothchecked.png</file>
+        <file>images/folderchecked.png</file>
+        <file>images/folderunchecked.png</file>
+        <file>images/go-down.png</file>
+        <file>images/go-jump.png</file>
+        <file>images/go-up.png</file>
+        <file>images/graph1.png</file>
+        <file>images/help-browser.png</file>
+        <file>images/inflag0.png</file>
+        <file>images/inflag1.png</file>
+        <file>images/inflag2.png</file>
+        <file>images/intern.png</file>
+        <file>images/joblog.png</file>
+        <file>images/label.png</file>
+        <file>images/mail-message-new.png</file>
+        <file>images/mail-message-pending.png</file>
+        <file>images/mark.png</file>
+        <file>images/network-server.png</file>
+        <file>images/new.png</file>
+        <file>images/open.png</file>
+        <file>images/package-x-generic.png</file>
+        <file>images/paste.png</file>
+        <file>images/print.png</file>
+        <file>images/purge.png</file>
+        <file>images/restore.png</file>
+        <file>images/run.png</file>
+        <file>images/runit.png</file>
+        <file>images/save.png</file>
+        <file>images/status-console.png</file>
+        <file>images/status.png</file>
+        <file>images/system-file-manager.png</file>
+        <file>images/unchecked.png</file>
+        <file>images/undo.png</file>
+        <file>images/unmark.png</file>
+        <file>images/up.png</file>
+        <file>images/utilities-terminal.png</file>
+        <file>images/view-refresh.png</file>
+        <file>images/weather-severe-alert.png</file>
+        <file>images/zoom.png</file>
+    </qresource>
 </RCC>
index bedbcbb328290446fc7e90d7c898d5ca45233009..bbb4e7df1ddc7a87cd35c0ff5e2cbd0653b52cfd 100644 (file)
@@ -67,14 +67,14 @@ void MediaInfo::showInfoForJob(QTableWidgetItem * item)
    QTreeWidgetItem* pageSelectorTreeWidgetItem = mainWin->getFromHash(this);
    int row = item->row();
    QString jobid = tableJob->item(row, 0)->text();
-   Job *j=new Job(jobid, pageSelectorTreeWidgetItem);
-   connect(j, SIGNAL(destroyed()), this, SLOT(populateTree()));
+   new Job(jobid, pageSelectorTreeWidgetItem);
+//   connect(j, SIGNAL(destroyed()), this, SLOT(populateTree()));
 }
 
 void MediaInfo::pruneVol()
 {
-   prunePage* prune = new prunePage(m_mediaName, "");
-   connect(prune, SIGNAL(destroyed()), this, SLOT(populateTree()));
+   new prunePage(m_mediaName, "");
+//   connect(prune, SIGNAL(destroyed()), this, SLOT(populateTree()));
 }
 
 // TODO: use same functions as in medialist.cpp
@@ -118,9 +118,8 @@ void MediaInfo::deleteVol()
 
 void MediaInfo::editVol()
 {
-   MediaEdit* edit = new MediaEdit(mainWin->getFromHash(this), 
-                                   m_mediaId);
-   connect(edit, SIGNAL(destroyed()), this, SLOT(populateTree()));
+   new MediaEdit(mainWin->getFromHash(this), m_mediaId);
+//   connect(edit, SIGNAL(destroyed()), this, SLOT(populateTree()));
 }
 
 /*
@@ -138,7 +137,8 @@ void MediaInfo::populateForm()
       "SELECT MediaId, VolumeName, Pool.Name, MediaType, FirstWritten,"
       "LastWritten, VolMounts, VolBytes, Media.Enabled,"
       "Location.Location, VolStatus, RecyclePool.Name, Media.Recycle, "
-      "VolReadTime, VolWriteTime, Media.VolUseDuration, Media.MaxVolJobs, "
+      "VolReadTime/1000000, VolWriteTime/1000000, Media.VolUseDuration, "
+      "Media.MaxVolJobs, "
       "Media.MaxVolFiles, Media.MaxVolBytes, Media.VolRetention,InChanger,Slot "
       "FROM Media JOIN Pool USING (PoolId) LEFT JOIN Pool AS RecyclePool "
       "ON (Media.RecyclePoolId = RecyclePool.PoolId) "
index 0c313e222ccea7110087d59b5370c483aa77b7fc..714aac3f3574926494116048bbbe8e2f5131edb2 100644 (file)
 #include "bat.h"
 #include "run.h"
 
+
+runPage::runPage()
+{
+   init();
+   show();
+}
+
+runPage::runPage(const QString &defJob)
+{
+   init();
+   if (defJob != "")
+      jobCombo->setCurrentIndex(jobCombo->findText(defJob, Qt::MatchExactly));
+   show();
+}
+
+
+runPage::runPage(const QString &defJob, const QString &level, 
+                 const QString &pool, const QString &storage,
+                 const QString &client, const QString &fileset)
+{
+   init();
+   jobCombo->setCurrentIndex(jobCombo->findText(defJob, Qt::MatchExactly));
+   job_name_change(0);
+   filesetCombo->setCurrentIndex(filesetCombo->findText(fileset,
+                                                        Qt::MatchExactly));
+   levelCombo->setCurrentIndex(levelCombo->findText(level, Qt::MatchExactly));
+   clientCombo->setCurrentIndex(clientCombo->findText(client,Qt::MatchExactly));
+   poolCombo->setCurrentIndex(poolCombo->findText(pool, Qt::MatchExactly));
+
+   if (storage != "") {         // TODO: enable storage
+      storageCombo->setCurrentIndex(storageCombo->findText(storage, 
+                                                           Qt::MatchExactly));
+   }
+   show();
+}
+
+
 /*
  * Setup all the combo boxes and display the dialog
  */
-runPage::runPage(const QString &defJob)
+void runPage::init()
 {
    QDateTime dt;
 
@@ -71,11 +108,10 @@ runPage::runPage(const QString &defJob)
    connect(okButton, SIGNAL(pressed()), this, SLOT(okButtonPushed()));
    connect(cancelButton, SIGNAL(pressed()), this, SLOT(cancelButtonPushed()));
 
-   dockPage();
+   // find a way to place the new window at the cursor position
+   // or in the midle of the page
+//   dockPage();
    setCurrent();
-   this->show();
-   if (defJob != "")
-      jobCombo->setCurrentIndex(jobCombo->findText(defJob, Qt::MatchExactly));
 }
 
 void runPage::okButtonPushed()
index e505e6809de2c16904a51069297b8b4948ab0460..85d3e2730b76c827fbac48e5f0da94423279dc80 100644 (file)
@@ -1,3 +1,30 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
+
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation, which is 
+   listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of Kern Sibbald.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
 
 #ifndef _RUN_H_
 #define _RUN_H_
@@ -14,14 +41,24 @@ class runPage : public Pages, public Ui::runForm
    Q_OBJECT 
 
 public:
+   runPage();
+
    runPage(const QString &defJob);
 
+   runPage(const QString &defJob, 
+           const QString &level,
+           const QString &pool,
+           const QString &storage,
+           const QString &client,
+           const QString &fileset);
+
 public slots:
    void okButtonPushed();
    void cancelButtonPushed();
    void job_name_change(int index);
 
 private:
+   void init();
    int m_conn;
 };
 
index 4bd95aecf939cd278378a1b59369c6e4723e0335..0fc3eae802d82b28e22ec1a20e6c653bf311b1f4 100644 (file)
    <rect>
     <x>0</x>
     <y>0</y>
-    <width>734</width>
-    <height>483</height>
+    <width>594</width>
+    <height>415</height>
    </rect>
   </property>
+  <property name="sizePolicy" >
+   <sizepolicy vsizetype="Preferred" hsizetype="Preferred" >
+    <horstretch>0</horstretch>
+    <verstretch>0</verstretch>
+   </sizepolicy>
+  </property>
   <property name="windowTitle" >
-   <string>Form</string>
+   <string>Run job</string>
   </property>
-  <layout class="QGridLayout" >
-   <property name="margin" >
-    <number>9</number>
-   </property>
-   <property name="spacing" >
-    <number>6</number>
-   </property>
-   <item row="1" column="1" >
-    <layout class="QGridLayout" >
-     <property name="margin" >
-      <number>0</number>
+  <layout class="QVBoxLayout" >
+   <item>
+    <widget class="QLabel" name="run" >
+     <property name="maximumSize" >
+      <size>
+       <width>16777215</width>
+       <height>30</height>
+      </size>
      </property>
-     <property name="spacing" >
-      <number>6</number>
+     <property name="font" >
+      <font>
+       <pointsize>11</pointsize>
+      </font>
      </property>
-     <item row="3" column="0" >
-      <widget class="QLabel" name="label_11" >
-       <property name="text" >
-        <string>Level:</string>
-       </property>
-       <property name="buddy" >
-        <cstring>levelCombo</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="5" column="1" >
-      <widget class="QComboBox" name="poolCombo" />
-     </item>
-     <item row="9" column="0" >
-      <widget class="QLabel" name="label_5" >
+     <property name="text" >
+      <string>&lt;h3>Run a Job&lt;/h3></string>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <widget class="Line" name="line" >
+     <property name="sizePolicy" >
+      <sizepolicy vsizetype="Expanding" hsizetype="Minimum" >
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize" >
+      <size>
+       <width>0</width>
+       <height>5</height>
+      </size>
+     </property>
+     <property name="orientation" >
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" >
+     <item>
+      <widget class="QLabel" name="label_12" >
        <property name="text" >
-        <string>Bootstrap:</string>
-       </property>
-       <property name="openExternalLinks" >
-        <bool>true</bool>
-       </property>
-       <property name="buddy" >
-        <cstring>bootstrap</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="4" column="1" >
-      <widget class="QComboBox" name="filesetCombo" />
-     </item>
-     <item row="9" column="1" >
-      <widget class="QLineEdit" name="bootstrap" >
-       <property name="enabled" >
-        <bool>true</bool>
-       </property>
-       <property name="minimumSize" >
-        <size>
-         <width>200</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="readOnly" >
-        <bool>false</bool>
-       </property>
-      </widget>
-     </item>
-     <item row="6" column="1" >
-      <widget class="QComboBox" name="storageCombo" />
-     </item>
-     <item row="8" column="1" >
-      <widget class="QDateTimeEdit" name="dateTimeEdit" >
-       <property name="dateTime" >
-        <datetime>
-         <hour>0</hour>
-         <minute>2</minute>
-         <second>0</second>
-         <year>2000</year>
-         <month>1</month>
-         <day>1</day>
-        </datetime>
-       </property>
-       <property name="displayFormat" >
-        <string>yyyy-mm-dd hh:mm:ss</string>
+        <string/>
        </property>
-       <property name="calendarPopup" >
-        <bool>true</bool>
+       <property name="pixmap" >
+        <pixmap resource="../main.qrc" >:/images/runit.png</pixmap>
        </property>
       </widget>
      </item>
-     <item row="1" column="0" >
-      <widget class="QLabel" name="label_6" >
-       <property name="text" >
-        <string>Job:</string>
-       </property>
-       <property name="buddy" >
-        <cstring>jobCombo</cstring>
-       </property>
+     <item>
+      <widget class="QGroupBox" name="groupBox" >
+       <property name="title" >
+        <string>Job properties</string>
+       </property>
+       <layout class="QGridLayout" >
+        <item row="0" column="0" >
+         <widget class="QLabel" name="label_6" >
+          <property name="text" >
+           <string>Job:</string>
+          </property>
+          <property name="buddy" >
+           <cstring>jobCombo</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1" >
+         <widget class="QComboBox" name="jobCombo" />
+        </item>
+        <item row="0" column="2" colspan="2" >
+         <layout class="QHBoxLayout" >
+          <property name="spacing" >
+           <number>6</number>
+          </property>
+          <property name="leftMargin" >
+           <number>0</number>
+          </property>
+          <property name="topMargin" >
+           <number>0</number>
+          </property>
+          <property name="rightMargin" >
+           <number>0</number>
+          </property>
+          <property name="bottomMargin" >
+           <number>0</number>
+          </property>
+          <item>
+           <widget class="QLabel" name="label_7" >
+            <property name="text" >
+             <string>Type:</string>
+            </property>
+           </widget>
+          </item>
+          <item>
+           <widget class="QLabel" name="typeLabel" >
+            <property name="text" >
+             <string>&lt;h3>Backup&lt;h3/></string>
+            </property>
+           </widget>
+          </item>
+         </layout>
+        </item>
+        <item row="1" column="0" >
+         <widget class="QLabel" name="label_8" >
+          <property name="text" >
+           <string>Client:</string>
+          </property>
+          <property name="buddy" >
+           <cstring>clientCombo</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1" >
+         <widget class="QComboBox" name="clientCombo" />
+        </item>
+        <item row="1" column="2" >
+         <widget class="QLabel" name="label_4" >
+          <property name="text" >
+           <string>Priority:</string>
+          </property>
+          <property name="buddy" >
+           <cstring>prioritySpin</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="3" >
+         <widget class="QSpinBox" name="prioritySpin" >
+          <property name="minimum" >
+           <number>1</number>
+          </property>
+          <property name="maximum" >
+           <number>10000</number>
+          </property>
+          <property name="value" >
+           <number>10</number>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0" >
+         <widget class="QLabel" name="label_11" >
+          <property name="text" >
+           <string>Level:</string>
+          </property>
+          <property name="buddy" >
+           <cstring>levelCombo</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1" >
+         <widget class="QComboBox" name="levelCombo" />
+        </item>
+        <item rowspan="5" row="2" column="3" >
+         <spacer>
+          <property name="orientation" >
+           <enum>Qt::Vertical</enum>
+          </property>
+          <property name="sizeHint" >
+           <size>
+            <width>56</width>
+            <height>151</height>
+           </size>
+          </property>
+         </spacer>
+        </item>
+        <item row="3" column="0" >
+         <widget class="QLabel" name="label_9" >
+          <property name="text" >
+           <string>FileSet:</string>
+          </property>
+          <property name="buddy" >
+           <cstring>filesetCombo</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="1" >
+         <widget class="QComboBox" name="filesetCombo" />
+        </item>
+        <item row="4" column="0" >
+         <widget class="QLabel" name="label_3" >
+          <property name="text" >
+           <string>Pool:</string>
+          </property>
+          <property name="buddy" >
+           <cstring>poolCombo</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="4" column="1" >
+         <widget class="QComboBox" name="poolCombo" />
+        </item>
+        <item row="5" column="0" >
+         <widget class="QLabel" name="label_2" >
+          <property name="text" >
+           <string>Storage:</string>
+          </property>
+          <property name="buddy" >
+           <cstring>storageCombo</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="5" column="1" >
+         <widget class="QComboBox" name="storageCombo" />
+        </item>
+        <item row="6" column="0" >
+         <widget class="QLabel" name="label_10" >
+          <property name="text" >
+           <string>Messages:</string>
+          </property>
+          <property name="buddy" >
+           <cstring>messagesCombo</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="6" column="1" >
+         <widget class="QComboBox" name="messagesCombo" />
+        </item>
+        <item row="7" column="0" >
+         <widget class="QLabel" name="label" >
+          <property name="text" >
+           <string>When:</string>
+          </property>
+          <property name="buddy" >
+           <cstring>dateTimeEdit</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="7" column="1" >
+         <widget class="QDateTimeEdit" name="dateTimeEdit" >
+          <property name="dateTime" >
+           <datetime>
+            <hour>0</hour>
+            <minute>2</minute>
+            <second>0</second>
+            <year>2000</year>
+            <month>1</month>
+            <day>1</day>
+           </datetime>
+          </property>
+          <property name="displayFormat" >
+           <string>yyyy-mm-dd hh:mm:ss</string>
+          </property>
+          <property name="calendarPopup" >
+           <bool>true</bool>
+          </property>
+         </widget>
+        </item>
+        <item row="8" column="0" >
+         <widget class="QLabel" name="label_5" >
+          <property name="text" >
+           <string>Bootstrap:</string>
+          </property>
+          <property name="openExternalLinks" >
+           <bool>true</bool>
+          </property>
+          <property name="buddy" >
+           <cstring>bootstrap</cstring>
+          </property>
+         </widget>
+        </item>
+        <item row="8" column="1" >
+         <widget class="QLineEdit" name="bootstrap" >
+          <property name="enabled" >
+           <bool>true</bool>
+          </property>
+          <property name="minimumSize" >
+           <size>
+            <width>200</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="readOnly" >
+           <bool>false</bool>
+          </property>
+         </widget>
+        </item>
+       </layout>
       </widget>
      </item>
-     <item rowspan="6" row="3" column="3" >
+    </layout>
+   </item>
+   <item>
+    <widget class="Line" name="line_2" >
+     <property name="sizePolicy" >
+      <sizepolicy vsizetype="Expanding" hsizetype="Minimum" >
+       <horstretch>0</horstretch>
+       <verstretch>0</verstretch>
+      </sizepolicy>
+     </property>
+     <property name="minimumSize" >
+      <size>
+       <width>0</width>
+       <height>5</height>
+      </size>
+     </property>
+     <property name="orientation" >
+      <enum>Qt::Horizontal</enum>
+     </property>
+    </widget>
+   </item>
+   <item>
+    <layout class="QHBoxLayout" >
+     <item>
       <spacer>
        <property name="orientation" >
-        <enum>Qt::Vertical</enum>
+        <enum>Qt::Horizontal</enum>
        </property>
        <property name="sizeHint" >
         <size>
-         <width>56</width>
-         <height>151</height>
+         <width>40</width>
+         <height>20</height>
         </size>
        </property>
       </spacer>
      </item>
-     <item row="5" column="0" >
-      <widget class="QLabel" name="label_3" >
-       <property name="text" >
-        <string>Pool:</string>
-       </property>
-       <property name="buddy" >
-        <cstring>poolCombo</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="1" column="2" colspan="2" >
-      <layout class="QHBoxLayout" >
-       <property name="margin" >
-        <number>0</number>
-       </property>
-       <property name="spacing" >
-        <number>6</number>
-       </property>
-       <item>
-        <widget class="QLabel" name="label_7" >
-         <property name="text" >
-          <string>Type:</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QLabel" name="typeLabel" >
-         <property name="text" >
-          <string>&lt;h3>Backup&lt;h3/></string>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </item>
-     <item row="4" column="0" >
-      <widget class="QLabel" name="label_9" >
-       <property name="text" >
-        <string>FileSet:</string>
-       </property>
-       <property name="buddy" >
-        <cstring>filesetCombo</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="7" column="0" >
-      <widget class="QLabel" name="label_10" >
+     <item>
+      <widget class="QPushButton" name="okButton" >
        <property name="text" >
-        <string>Messages:</string>
-       </property>
-       <property name="buddy" >
-        <cstring>messagesCombo</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="0" column="0" colspan="4" >
-      <layout class="QHBoxLayout" >
-       <property name="margin" >
-        <number>0</number>
-       </property>
-       <property name="spacing" >
-        <number>6</number>
-       </property>
-       <item>
-        <spacer>
-         <property name="orientation" >
-          <enum>Qt::Horizontal</enum>
-         </property>
-         <property name="sizeHint" >
-          <size>
-           <width>71</width>
-           <height>21</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item>
-        <widget class="QLabel" name="run" >
-         <property name="maximumSize" >
-          <size>
-           <width>16777215</width>
-           <height>30</height>
-          </size>
-         </property>
-         <property name="text" >
-          <string>&lt;h3>Run a Job&lt;/h3></string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <spacer>
-         <property name="orientation" >
-          <enum>Qt::Horizontal</enum>
-         </property>
-         <property name="sizeHint" >
-          <size>
-           <width>81</width>
-           <height>20</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-      </layout>
-     </item>
-     <item row="1" column="1" >
-      <widget class="QComboBox" name="jobCombo" />
-     </item>
-     <item row="2" column="2" >
-      <widget class="QLabel" name="label_4" >
-       <property name="text" >
-        <string>Priority:</string>
-       </property>
-       <property name="buddy" >
-        <cstring>prioritySpin</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="3" column="1" >
-      <widget class="QComboBox" name="levelCombo" />
-     </item>
-     <item row="2" column="0" >
-      <widget class="QLabel" name="label_8" >
-       <property name="text" >
-        <string>Client:</string>
-       </property>
-       <property name="buddy" >
-        <cstring>clientCombo</cstring>
-       </property>
-      </widget>
-     </item>
-     <item row="10" column="0" colspan="4" >
-      <layout class="QHBoxLayout" >
-       <property name="margin" >
-        <number>0</number>
-       </property>
-       <property name="spacing" >
-        <number>6</number>
-       </property>
-       <item>
-        <spacer>
-         <property name="orientation" >
-          <enum>Qt::Horizontal</enum>
-         </property>
-         <property name="sizeHint" >
-          <size>
-           <width>40</width>
-           <height>20</height>
-          </size>
-         </property>
-        </spacer>
-       </item>
-       <item>
-        <widget class="QPushButton" name="okButton" >
-         <property name="text" >
-          <string>OK</string>
-         </property>
-        </widget>
-       </item>
-       <item>
-        <widget class="QPushButton" name="cancelButton" >
-         <property name="text" >
-          <string>Cancel</string>
-         </property>
-        </widget>
-       </item>
-      </layout>
-     </item>
-     <item row="2" column="3" >
-      <widget class="QSpinBox" name="prioritySpin" >
-       <property name="maximum" >
-        <number>10000</number>
-       </property>
-       <property name="minimum" >
-        <number>1</number>
-       </property>
-       <property name="value" >
-        <number>10</number>
-       </property>
-      </widget>
-     </item>
-     <item row="2" column="1" >
-      <widget class="QComboBox" name="clientCombo" />
-     </item>
-     <item row="6" column="0" >
-      <widget class="QLabel" name="label_2" >
-       <property name="text" >
-        <string>Storage:</string>
-       </property>
-       <property name="buddy" >
-        <cstring>storageCombo</cstring>
+        <string>OK</string>
        </property>
       </widget>
      </item>
-     <item row="7" column="1" >
-      <widget class="QComboBox" name="messagesCombo" />
-     </item>
-     <item row="8" column="0" >
-      <widget class="QLabel" name="label" >
+     <item>
+      <widget class="QPushButton" name="cancelButton" >
        <property name="text" >
-        <string>When:</string>
-       </property>
-       <property name="buddy" >
-        <cstring>dateTimeEdit</cstring>
+        <string>Cancel</string>
        </property>
       </widget>
      </item>
     </layout>
    </item>
-   <item row="1" column="2" >
-    <spacer>
-     <property name="orientation" >
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="sizeHint" >
-      <size>
-       <width>40</width>
-       <height>20</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="1" column="0" >
-    <spacer>
-     <property name="orientation" >
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="sizeHint" >
-      <size>
-       <width>40</width>
-       <height>20</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="2" column="1" >
-    <spacer>
-     <property name="orientation" >
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeType" >
-      <enum>QSizePolicy::Expanding</enum>
-     </property>
-     <property name="sizeHint" >
-      <size>
-       <width>351</width>
-       <height>16</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
-   <item row="0" column="1" >
-    <spacer>
-     <property name="orientation" >
-      <enum>Qt::Vertical</enum>
-     </property>
-     <property name="sizeType" >
-      <enum>QSizePolicy::Expanding</enum>
-     </property>
-     <property name="sizeHint" >
-      <size>
-       <width>351</width>
-       <height>16</height>
-      </size>
-     </property>
-    </spacer>
-   </item>
   </layout>
  </widget>
- <resources/>
+ <resources>
+  <include location="../main.qrc" />
+ </resources>
  <connections/>
 </ui>
diff --git a/bacula/src/qt-console/storage/content.cpp b/bacula/src/qt-console/storage/content.cpp
new file mode 100644 (file)
index 0000000..6b186c2
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
+
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation and included
+   in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of Kern Sibbald.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
+#include "bat.h"
+#include <QAbstractEventDispatcher>
+#include <QMenu>
+#include "content.h"
+#include "label/label.h"
+#include "mount/mount.h"
+#include "util/fmtwidgetitem.h"
+#include "status/storstat.h"
+
+// 
+// TODO: List tray
+//       List drives in autochanger
+//       use user selection to add slot= argument
+// 
+
+Content::Content(QString storage, QTreeWidgetItem *parentWidget)
+{
+   setupUi(this);
+   pgInitialize(storage, parentWidget);
+   QTreeWidgetItem* thisitem = mainWin->getFromHash(this);
+   thisitem->setIcon(0,QIcon(QString::fromUtf8(":images/package-x-generic.png")));
+
+   m_populated = false;
+   m_firstpopulation = true;
+   m_checkcurwidget = true;
+   m_closeable = true;
+   m_currentStorage = storage;
+
+   connect(pbUpdate, SIGNAL(clicked()), this,
+           SLOT(consoleUpdateSlots()));
+
+   connect(pbLabel, SIGNAL(clicked()), this,
+           SLOT(consoleLabelStorage()));
+
+   connect(pbMount, SIGNAL(clicked()), this,
+           SLOT(consoleMountStorage()));
+
+   connect(pbUnmount, SIGNAL(clicked()), this,
+           SLOT(consoleUnMountStorage()));
+
+   connect(pbStatus, SIGNAL(clicked()), this,
+           SLOT(statusStorageWindow()));
+
+   connect(pbRelease, SIGNAL(clicked()), this,
+           SLOT(consoleRelease()));
+
+   dockPage();
+   setCurrent();
+}
+
+void table_get_selection(QTableWidget *table, QString &sel)
+{
+   QTableWidgetItem *item;
+   int current;
+
+   /* The QT selection returns each cell, so you
+    * have x times the same row number...
+    * We take only one instance
+    */
+   int s = table->rowCount();
+   bool *tab = (bool *)malloc(s * sizeof(bool));
+   memset(tab, 0, s); 
+
+   foreach (item, table->selectedItems()) {
+      current = item->row();
+      tab[current]=true;
+   }
+
+   sel += "=";
+
+   for(int i=0; i<s; i++) {
+      if (tab[i]) {
+         sel += table->item(i, 0)->text();
+         sel += ",";
+      }
+   }
+   sel.chop(1);                 // remove trailing , or useless =
+   free(tab);
+}
+
+/* Label Media populating current storage by default */
+void Content::consoleLabelStorage()
+{
+   QString sel;
+   table_get_selection(tableContent, sel);
+   if (sel == "") {
+      new labelPage(m_currentStorage);
+   } else {
+      QString cmd = "label barcodes slots";
+      cmd += sel;
+      cmd += " storage=" + m_currentStorage;
+      consoleCommand(cmd);
+   }
+}
+
+/* Mount currently selected storage */
+void Content::consoleMountStorage()
+{
+   setConsoleCurrent();
+   /* if this storage is an autochanger, lets ask for the slot */
+   new mountDialog(m_console, m_currentStorage);
+}
+
+/* Unmount Currently selected storage */
+void Content::consoleUnMountStorage()
+{
+   QString cmd("umount storage=");
+   cmd += m_currentStorage;
+   consoleCommand(cmd);
+}
+
+void Content::statusStorageWindow()
+{
+   /* if one exists, then just set it current */
+   bool found = false;
+   foreach(Pages *page, mainWin->m_pagehash) {
+      if (mainWin->currentConsole() == page->console()) {
+         if (page->name() == tr("Storage Status %1").arg(m_currentStorage)) {
+            found = true;
+            page->setCurrent();
+         }
+      }
+   }
+   if (!found) {
+      QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
+      new StorStat(m_currentStorage, parentItem);
+   }
+}
+
+/*
+ * The main meat of the class!!  The function that querries the director and 
+ * creates the widgets with appropriate values.
+ */
+void Content::populateContent()
+{
+   char buf[200];
+   time_t t;
+   struct tm tm;
+
+   QStringList results_all;
+   QString cmd("status slots drive=0 storage=\"" + m_currentStorage + "\"");
+   m_console->dir_cmd(cmd, results_all);
+
+   Freeze frz(*tableContent); /* disable updating*/
+   tableContent->clearContents();
+
+   // take only valid records
+   QStringList results = results_all.filter(QRegExp("^[0-9]+\\|"));
+   tableContent->setRowCount(results.size());
+
+   QString resultline;
+   QStringList fieldlist;
+   int row = 0;
+
+   foreach (resultline, results) {
+      fieldlist = resultline.split("|");
+      if (fieldlist.size() < 9)
+         continue; /* some fields missing, ignore row */
+
+      int index=0;
+      QStringListIterator fld(fieldlist);
+      TableItemFormatter slotitem(*tableContent, row);
+
+      /* Slot */
+      slotitem.setNumericFld(index++, fld.next()); 
+
+      /* Real Slot */
+      if (fld.next() != "") {
+
+         /* Volume */
+         slotitem.setTextFld(index++, fld.next());
+         
+         /* Bytes */
+         slotitem.setBytesFld(index++, fld.next());
+         
+         /* Status */
+         slotitem.setVolStatusFld(index++, fld.next());
+         
+         /* MediaType */
+         slotitem.setTextFld(index++, fld.next());
+         
+         /* Pool */
+         slotitem.setTextFld(index++, fld.next());
+         
+         t = fld.next().toInt();
+         if (t > 0) {
+            /* LastW */
+            localtime_r(&t, &tm);
+            strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
+            slotitem.setTextFld(index++, QString(buf));
+            
+            /* Expire */
+            t = fld.next().toInt();
+            localtime_r(&t, &tm);
+            strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tm);
+            slotitem.setTextFld(index++, QString(buf));
+         }
+      }
+      row++;
+   }
+
+
+   tableContent->verticalHeader()->hide();
+   tableContent->sortByColumn(0, Qt::AscendingOrder);
+   tableContent->setSortingEnabled(true);
+   tableContent->resizeColumnsToContents();
+   tableContent->resizeRowsToContents();
+
+   /* make read only */
+   int rcnt = tableContent->rowCount();
+   int ccnt = tableContent->columnCount();
+   for(int r=0; r < rcnt; r++) {
+      for(int c=0; c < ccnt; c++) {
+         QTableWidgetItem* item = tableContent->item(r, c);
+         if (item) {
+            item->setFlags(Qt::ItemFlags(item->flags() & (~Qt::ItemIsEditable)));
+         }
+      }
+   }
+   m_populated = true;
+
+   tableTray->verticalHeader()->hide();
+   tableDrive->verticalHeader()->hide();
+}
+
+/*
+ * Virtual function which is called when this page is visible on the stack
+ */
+void Content::currentStackItem()
+{
+   if(!m_populated) {
+      populateContent();
+   }
+}
+
+void Content::treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *)
+{
+
+}
+
+/* Update Slots */
+void Content::consoleUpdateSlots()
+{
+   QString sel = "";
+   table_get_selection(tableContent, sel);
+   
+   QString cmd("update slots");
+   if (sel != "") {
+      cmd += sel;
+   }
+   cmd += " drive=0 storage=" + m_currentStorage;
+
+   Pmsg1(0, "cmd=%s\n", cmd.toUtf8().data());
+
+   consoleCommand(cmd);
+   populateContent();
+}
+
+/* Release a tape in the drive */
+void Content::consoleRelease()
+{
+   QString cmd("release storage=");
+   cmd += m_currentStorage;
+   consoleCommand(cmd);
+}
diff --git a/bacula/src/qt-console/storage/content.h b/bacula/src/qt-console/storage/content.h
new file mode 100644 (file)
index 0000000..94eb35e
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef _CONTENT_H_
+#define _CONTENT_H_
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2007-2009 Free Software Foundation Europe e.V.
+
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation and included
+   in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of Kern Sibbald.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
+
+#include <QtGui>
+#include "ui_content.h"
+#include "console.h"
+#include "pages.h"
+
+class Content : public Pages, public Ui::ContentForm
+{
+   Q_OBJECT 
+
+public:
+   Content(QString storage, QTreeWidgetItem *parentWidget);
+//   virtual void PgSeltreeWidgetClicked();
+   virtual void currentStackItem();
+
+public slots:
+   void treeItemChanged(QTreeWidgetItem *, QTreeWidgetItem *);
+
+   void consoleRelease();
+   void consoleUpdateSlots();
+   void consoleLabelStorage();
+   void consoleMountStorage();
+   void statusStorageWindow();
+   void consoleUnMountStorage();
+
+private slots:
+   void populateContent();
+
+private:
+   bool m_currentAutoChanger;
+   bool m_populated;
+   bool m_firstpopulation;
+   bool m_checkcurwidget;
+   QString m_currentStorage;
+};
+
+#endif /* _STORAGE_H_ */
diff --git a/bacula/src/qt-console/storage/content.ui b/bacula/src/qt-console/storage/content.ui
new file mode 100644 (file)
index 0000000..db53fe4
--- /dev/null
@@ -0,0 +1,325 @@
+<ui version="4.0" >
+ <class>ContentForm</class>
+ <widget class="QWidget" name="ContentForm" >
+  <property name="geometry" >
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>949</width>
+    <height>695</height>
+   </rect>
+  </property>
+  <property name="windowTitle" >
+   <string>Form</string>
+  </property>
+  <layout class="QHBoxLayout" >
+   <item>
+    <layout class="QVBoxLayout" >
+     <item>
+      <widget class="QGroupBox" name="groupBox" >
+       <property name="sizePolicy" >
+        <sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize" >
+        <size>
+         <width>240</width>
+         <height>110</height>
+        </size>
+       </property>
+       <property name="title" >
+        <string>Actions</string>
+       </property>
+       <layout class="QGridLayout" >
+        <item row="0" column="0" >
+         <widget class="QPushButton" name="pbUpdate" >
+          <property name="text" >
+           <string>Update slots</string>
+          </property>
+          <property name="icon" >
+           <iconset resource="../main.qrc" >:/images/view-refresh.png</iconset>
+          </property>
+         </widget>
+        </item>
+        <item row="0" column="1" >
+         <widget class="QPushButton" name="pbLabel" >
+          <property name="text" >
+           <string>Label</string>
+          </property>
+          <property name="icon" >
+           <iconset resource="../main.qrc" >:/images/label.png</iconset>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="0" >
+         <widget class="QPushButton" name="pbMoveToTray" >
+          <property name="enabled" >
+           <bool>false</bool>
+          </property>
+          <property name="text" >
+           <string>Move to tray</string>
+          </property>
+          <property name="icon" >
+           <iconset resource="../main.qrc" >:/images/extern.png</iconset>
+          </property>
+         </widget>
+        </item>
+        <item row="1" column="1" >
+         <widget class="QPushButton" name="pbEmptyTray" >
+          <property name="enabled" >
+           <bool>false</bool>
+          </property>
+          <property name="text" >
+           <string>Empty tray</string>
+          </property>
+          <property name="icon" >
+           <iconset resource="../main.qrc" >:/images/intern.png</iconset>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="0" >
+         <widget class="QPushButton" name="pbMount" >
+          <property name="text" >
+           <string>Mount</string>
+          </property>
+         </widget>
+        </item>
+        <item row="2" column="1" >
+         <widget class="QPushButton" name="pbUnmount" >
+          <property name="text" >
+           <string>Unmount</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="0" >
+         <widget class="QPushButton" name="pbStatus" >
+          <property name="text" >
+           <string>Status</string>
+          </property>
+         </widget>
+        </item>
+        <item row="3" column="1" >
+         <widget class="QPushButton" name="pbRelease" >
+          <property name="text" >
+           <string>Release</string>
+          </property>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="QGroupBox" name="groupBox_3" >
+       <property name="sizePolicy" >
+        <sizepolicy vsizetype="Expanding" hsizetype="Fixed" >
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="minimumSize" >
+        <size>
+         <width>241</width>
+         <height>221</height>
+        </size>
+       </property>
+       <property name="maximumSize" >
+        <size>
+         <width>241</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="title" >
+        <string>Drives</string>
+       </property>
+       <layout class="QVBoxLayout" >
+        <item>
+         <widget class="QTableWidget" name="tableDrive" >
+          <property name="sizePolicy" >
+           <sizepolicy vsizetype="Expanding" hsizetype="Fixed" >
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="minimumSize" >
+           <size>
+            <width>220</width>
+            <height>192</height>
+           </size>
+          </property>
+          <property name="selectionBehavior" >
+           <enum>QAbstractItemView::SelectRows</enum>
+          </property>
+          <row>
+           <property name="text" >
+            <string>LTO1</string>
+           </property>
+          </row>
+          <row>
+           <property name="text" >
+            <string>New Row</string>
+           </property>
+          </row>
+          <column>
+           <property name="text" >
+            <string>Drive</string>
+           </property>
+          </column>
+          <column>
+           <property name="text" >
+            <string>Volume</string>
+           </property>
+          </column>
+          <item row="0" column="0" >
+           <property name="text" >
+            <string>LTO1</string>
+           </property>
+          </item>
+          <item row="0" column="1" >
+           <property name="text" >
+            <string>VOL1</string>
+           </property>
+          </item>
+          <item row="1" column="0" >
+           <property name="text" >
+            <string>LTO2</string>
+           </property>
+          </item>
+          <item row="1" column="1" >
+           <property name="text" >
+            <string>VOL2</string>
+           </property>
+          </item>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+     <item>
+      <widget class="QGroupBox" name="groupBox_4" >
+       <property name="sizePolicy" >
+        <sizepolicy vsizetype="Expanding" hsizetype="Fixed" >
+         <horstretch>0</horstretch>
+         <verstretch>0</verstretch>
+        </sizepolicy>
+       </property>
+       <property name="maximumSize" >
+        <size>
+         <width>240</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <property name="title" >
+        <string>Tray slots</string>
+       </property>
+       <layout class="QHBoxLayout" >
+        <item>
+         <widget class="QTableWidget" name="tableTray" >
+          <property name="sizePolicy" >
+           <sizepolicy vsizetype="Expanding" hsizetype="Fixed" >
+            <horstretch>0</horstretch>
+            <verstretch>0</verstretch>
+           </sizepolicy>
+          </property>
+          <property name="minimumSize" >
+           <size>
+            <width>100</width>
+            <height>0</height>
+           </size>
+          </property>
+          <property name="selectionBehavior" >
+           <enum>QAbstractItemView::SelectRows</enum>
+          </property>
+          <property name="sortingEnabled" >
+           <bool>false</bool>
+          </property>
+          <column>
+           <property name="text" >
+            <string>Slot</string>
+           </property>
+          </column>
+          <column>
+           <property name="text" >
+            <string>Volume</string>
+           </property>
+          </column>
+         </widget>
+        </item>
+       </layout>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QGroupBox" name="groupBox_2" >
+     <property name="title" >
+      <string>Content</string>
+     </property>
+     <layout class="QHBoxLayout" >
+      <item>
+       <widget class="QTableWidget" name="tableContent" >
+        <property name="alternatingRowColors" >
+         <bool>true</bool>
+        </property>
+        <property name="selectionMode" >
+         <enum>QAbstractItemView::ExtendedSelection</enum>
+        </property>
+        <property name="selectionBehavior" >
+         <enum>QAbstractItemView::SelectRows</enum>
+        </property>
+        <property name="rowCount" >
+         <number>0</number>
+        </property>
+        <column>
+         <property name="text" >
+          <string>  Slot  </string>
+         </property>
+        </column>
+        <column>
+         <property name="text" >
+          <string>  Volume   </string>
+         </property>
+        </column>
+        <column>
+         <property name="text" >
+          <string>   Bytes   </string>
+         </property>
+        </column>
+        <column>
+         <property name="text" >
+          <string>   Status   </string>
+         </property>
+        </column>
+        <column>
+         <property name="text" >
+          <string>   Media Type   </string>
+         </property>
+        </column>
+        <column>
+         <property name="text" >
+          <string>   Pool   </string>
+         </property>
+        </column>
+        <column>
+         <property name="text" >
+          <string>   Last Written   </string>
+         </property>
+        </column>
+        <column>
+         <property name="text" >
+          <string>   When expire?   </string>
+         </property>
+        </column>
+       </widget>
+      </item>
+     </layout>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../main.qrc" />
+ </resources>
+ <connections/>
+</ui>
index 7141787c7942242fb17f66038a6fbee3c610471e..2f26b550fdcb6ac345807787a329cab76e6c7f24 100644 (file)
@@ -39,6 +39,7 @@
 #include <QAbstractEventDispatcher>
 #include <QMenu>
 #include "storage.h"
+#include "content.h"
 #include "label/label.h"
 #include "mount/mount.h"
 #include "status/storstat.h"
@@ -326,6 +327,17 @@ void Storage::createContextMenu()
                 SLOT(consoleRelease()));
    connect(actionStatusStorageWindow, SIGNAL(triggered()), this,
                 SLOT(statusStorageWindow()));
+   connect(mp_treeWidget, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)),
+           this, SLOT(contentWindow()));
+
+}
+
+void Storage::contentWindow()
+{
+   if (m_currentStorage != "" && m_currentAutoChanger) { 
+      QTreeWidgetItem *parentItem = mainWin->getFromHash(this);
+      new Content(m_currentStorage, parentItem);
+   }
 }
 
 /*
index 8f3f416d5aa9ba423ca0f5751b19b226ac2dc8ae..e08e229ce0efe804d43f8c89e1dd26271967192c 100644 (file)
@@ -61,6 +61,7 @@ private slots:
    void consoleUpdateSlotsScan();
    void consoleRelease();
    void statusStorageWindow();
+   void contentWindow();
 
 private:
    void createContextMenu();
@@ -75,4 +76,6 @@ private:
    QTreeWidgetItem *m_topItem;
 };
 
+void table_get_selection(QTableWidget *table, QString &sel);
+
 #endif /* _STORAGE_H_ */
index b2bf07e29dc1aac11089cb608930d6cf272ebc5f..51cda83e734837496924ff333752d545f11c8a7a 100644 (file)
@@ -405,6 +405,9 @@ DCR *acquire_device_for_append(DCR *dcr)
       jcr->NumWriteVolumes = 1;
    }
    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
+   Dmsg4(100, "=== nwriters=%d nres=%d vcatjob=%d dev=%s\n", 
+      dev->num_writers, dev->num_reserved(), dev->VolCatInfo.VolCatJobs, 
+      dev->print_name());
    dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
    ok = true;
 
index 9a00694638ca4681fd0c2866708dd49a3c02f088..a458d4111ec5db847b8baeb1cd1658ab82507ea4 100644 (file)
@@ -148,7 +148,7 @@ bool do_append_data(JCR *jcr)
        *  The stream header consists of the following:
        *    file_index (sequential Bacula file index, base 1)
        *    stream     (Bacula number to distinguish parts of data)
-       *    info       (Info for Storage daemon -- compressed, encryped, ...)
+       *    info       (Info for Storage daemon -- compressed, encrypted, ...)
        *       info is not currently used, so is read, but ignored!
        */
      if ((n=bget_msg(ds)) <= 0) {
@@ -219,25 +219,26 @@ bool do_append_data(JCR *jcr)
          if (stream == STREAM_UNIX_ATTRIBUTES || stream == STREAM_UNIX_ATTRIBUTES_EX ||
              crypto_digest_stream_type(stream) != CRYPTO_DIGEST_NONE) {
             if (!jcr->no_attributes) {
+               BSOCK *dir = jcr->dir_bsock;
                if (are_attributes_spooled(jcr)) {
-                  jcr->dir_bsock->set_spooling();
+                  dir->set_spooling();
                }
                Dmsg0(850, "Send attributes to dir.\n");
                if (!dir_update_file_attributes(dcr, &rec)) {
-                  jcr->dir_bsock->clear_spooling();
+                  dir->clear_spooling();
                   Jmsg(jcr, M_FATAL, 0, _("Error updating file attributes. ERR=%s\n"),
-                     jcr->dir_bsock->bstrerror());
+                     dir->bstrerror());
                   ok = false;
                   break;
                }
-               jcr->dir_bsock->clear_spooling();
+               dir->clear_spooling();
             }
          }
          Dmsg0(650, "Enter bnet_get\n");
       }
       Dmsg1(650, "End read loop with FD. Stat=%d\n", n);
 
-      if (is_bnet_error(ds)) {
+      if (ds->is_error()) {
          Dmsg1(350, "Network read error from FD. ERR=%s\n", ds->bstrerror());
          Jmsg1(jcr, M_FATAL, 0, _("Network error on data channel. ERR=%s\n"),
                ds->bstrerror());
index 37d33bdeff4632f9fb4c1f327dc10535e18e07fe..b85d78e6ebbba8b90cac1caebc0f4eb8037b7053 100644 (file)
@@ -465,6 +465,10 @@ bool dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec)
    ser_bytes(rec->data, rec->data_len);
    dir->msglen = ser_length(dir->msg);
    Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
+   if (rec->Stream == STREAM_UNIX_ATTRIBUTES || 
+       rec->Stream == STREAM_UNIX_ATTRIBUTES_EX) {
+      dir->set_data_end();                 /* set offset of last valid data */
+   }
    return dir->send();
 }
 
index 117122919f2cacfea8296f20213206e5c062320d..abb53c25c37489e26826ef2cfc79330325a9f9e5 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2001-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2001-2009 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
index 98aa584f7202852585a76f36c51dcf14831e329c..d17c17f018f7687d8743edfc87ae2c83b789826c 100644 (file)
@@ -160,6 +160,7 @@ init_dev(JCR *jcr, DEVRES *device)
    dev->max_block_size = device->max_block_size;
    dev->max_volume_size = device->max_volume_size;
    dev->max_file_size = device->max_file_size;
+   dev->max_concurrent_jobs = device->max_concurrent_jobs;
    dev->volume_capacity = device->volume_capacity;
    dev->max_rewind_wait = device->max_rewind_wait;
    dev->max_open_wait = device->max_open_wait;
index 8c044f000320668a32f018b0c9104d5c35945eb7..052015e23f2b81d6b673b9cca3e9a34611ea1812 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -252,6 +252,7 @@ public:
    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 max_concurrent_jobs;      /* maximum simultaneous jobs this drive */
    uint64_t volume_capacity;          /* advisory capacity */
    uint64_t max_spool_size;           /* maximum spool file size */
    uint64_t spool_size;               /* current spool size for this device */
@@ -454,6 +455,7 @@ public:
 #endif
    void dblock(int why);                  /* in lock.c */
    void dunblock(bool locked=false);      /* in lock.c */
+   bool is_device_unmounted();            /* in lock.c */
    void set_blocked(int block) { m_blocked = block; };
    int blocked() const { return m_blocked; };
    bool is_blocked() const { return m_blocked != BST_NOT_BLOCKED; };
@@ -529,8 +531,13 @@ public:
    void clear_found_in_use() { m_found_in_use = false; };
    bool is_reserved() const { return m_reserved; };
    bool is_dev_locked() { return m_dev_locked; }
+#ifdef SD_DEBUG_LOCK
+   void _dlock(const char *, int);      /* in lock.c */
+   void _dunlock(const char *, int);    /* in lock.c */
+#else
    void dlock() { dev->dlock(); m_dev_locked = true; }
    void dunlock() { m_dev_locked = false; dev->dunlock(); }
+#endif
    void dblock(int why) { dev->dblock(why); }
 
 
index aea4b6a2039a2d940ffc1390c01796d4037b1820..a1e7aa69b60261619867d4063327480d94c9e7fd 100644 (file)
@@ -155,17 +155,28 @@ void DEVICE::dunblock(bool locked)
 
 
 #ifdef SD_DEBUG_LOCK
+void DCR::_dlock(const char *file, int line)
+{
+   dev->_dlock(file, line);
+   m_dev_locked = true;
+}
+void DCR::_dunlock(const char *file, int line)
+{
+   m_dev_locked = false;
+   dev->_dunlock(file, line);
+
+}
+
 void DEVICE::_dlock(const char *file, int line)
 {
-   Dmsg4(sd_dbglvl, "dlock from %s:%d precnt=%d JobId=%u\n", file, line,
-         m_count, get_jobid_from_tid()); 
+   Dmsg3(sd_dbglvl, "dlock from %s:%d precnt=%d\n", file, line, m_count); 
    /* Note, this *really* should be protected by a mutex, but
     *  since it is only debug code we don't worry too much.  
     */
    if (m_count > 0 && pthread_equal(m_pid, pthread_self())) {
-      Dmsg5(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d JobId=%u\n", 
+      Dmsg4(sd_dbglvl, "Possible DEADLOCK!! lock held by JobId=%u from %s:%d m_count=%d\n", 
             get_jobid_from_tid(m_pid),
-            file, line, m_count, get_jobid_from_tid());
+            file, line, m_count);
    }
    P(m_mutex);
    m_pid = pthread_self();
@@ -175,8 +186,7 @@ void DEVICE::_dlock(const char *file, int line)
 void DEVICE::_dunlock(const char *file, int line)
 {
    m_count--; 
-   Dmsg4(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d JobId=%u\n", file, line,
-         m_count, get_jobid_from_tid()); 
+   Dmsg3(sd_dbglvl+1, "dunlock from %s:%d postcnt=%d\n", file, line, m_count); 
    V(m_mutex);   
 }
 
@@ -198,14 +208,15 @@ void DEVICE::_r_dunlock(const char *file, int line)
 #ifdef SD_DEBUG_LOCK
 void DEVICE::_r_dlock(const char *file, int line)
 {
-   Dmsg4(sd_dbglvl+1, "r_dlock blked=%s from %s:%d JobId=%u\n", this->print_blocked(),
-         file, line, get_jobid_from_tid());
+   Dmsg3(sd_dbglvl+1, "r_dlock blked=%s from %s:%d\n", this->print_blocked(),
+         file, line);
 #else
 void DEVICE::r_dlock()
 {
 #endif
    int stat;
-   this->dlock();   
+   P(m_mutex); /*    this->dlock();   */
+   m_count++;  /*    this->dlock() */
    if (this->blocked() && !pthread_equal(this->no_wait_id, pthread_self())) {
       this->num_waiting++;             /* indicate that I am waiting */
       while (this->blocked()) {
@@ -321,11 +332,11 @@ const char *DEVICE::print_blocked() const
 /*
  * Check if the device is blocked or not
  */
-bool is_device_unmounted(DEVICE *dev)
+bool DEVICE::is_device_unmounted()
 {
    bool stat;
-   int blocked = dev->blocked();
-   stat = (blocked == BST_UNMOUNTED) ||
-          (blocked == BST_UNMOUNTED_WAITING_FOR_SYSOP);
+   int blk = blocked();
+   stat = (blk == BST_UNMOUNTED) ||
+          (blk == BST_UNMOUNTED_WAITING_FOR_SYSOP);
    return stat;
 }
index db34f428e0c27c1ffaa0f745801d32719d8b670b..e18ca3aa327687da80a575aa74369f8653df6a14 100644 (file)
@@ -131,7 +131,6 @@ bool     fixup_device_block_write_error(DCR *dcr);
 void     set_start_vol_position(DCR *dcr);
 void     set_new_volume_parameters(DCR *dcr);
 void     set_new_file_parameters(DCR *dcr);
-bool     is_device_unmounted(DEVICE *dev);
 
 /* From dircmd.c */
 void     *handle_connection_request(void *arg);
@@ -231,32 +230,30 @@ extern int reservations_lock_count;
 #ifdef  SD_DEBUG_LOCK
 
 #define lock_reservations() \
-         do { Dmsg4(sd_dbglvl, "lock_reservations at %s:%d precnt=%d JobId=%u\n", \
+         do { Dmsg3(sd_dbglvl, "lock_reservations at %s:%d precnt=%d\n", \
               __FILE__, __LINE__, \
-              reservations_lock_count, get_jobid_from_tid(pthread_self())); \
+              reservations_lock_count); \
               _lock_reservations(); \
-              Dmsg1(sd_dbglvl, "lock_reservations: got lock JobId=%u\n", \
-               get_jobid_from_tid(pthread_self())); \
+              Dmsg0(sd_dbglvl, "lock_reservations: got lock\n"); \
          } while (0)
 #define unlock_reservations() \
-         do { Dmsg4(sd_dbglvl, "unlock_reservations at %s:%d precnt=%d JobId=%u\n", \
+         do { Dmsg3(sd_dbglvl, "unlock_reservations at %s:%d precnt=%d\n", \
               __FILE__, __LINE__, \
-              reservations_lock_count, get_jobid_from_tid(pthread_self())); \
+              reservations_lock_count); \
                    _unlock_reservations(); } while (0)
 
 #define lock_volumes() \
-         do { Dmsg4(sd_dbglvl, "lock_volumes at %s:%d precnt=%d JobId=%u\n", \
+         do { Dmsg3(sd_dbglvl, "lock_volumes at %s:%d precnt=%d\n", \
               __FILE__, __LINE__, \
-              vol_list_lock_count, get_jobid_from_tid(pthread_self())); \
+              vol_list_lock_count); \
               _lock_volumes(); \
-              Dmsg1(sd_dbglvl, "lock_volumes: got lock JobId=%u\n", \
-               get_jobid_from_tid(pthread_self())); \
+              Dmsg0(sd_dbglvl, "lock_volumes: got lock\n"); \
          } while (0)
 
 #define unlock_volumes() \
-         do { Dmsg4(sd_dbglvl, "unlock_volumes at %s:%d precnt=%d JobId=%u\n", \
+         do { Dmsg3(sd_dbglvl, "unlock_volumes at %s:%d precnt=%d\n", \
               __FILE__, __LINE__, \
-              vol_list_lock_count, get_jobid_from_tid(pthread_self())); \
+              vol_list_lock_count); \
                    _unlock_volumes(); } while (0)
 
 #else
index c2377d8f0d6a7606690c53e5c70f5c88319c7728..2326d1bb9e0fc33167f0dac100ce71bc06461b6b 100644 (file)
@@ -761,7 +761,7 @@ static bool reserve_device_for_read(DCR *dcr)
 
    dev->dlock();  
 
-   if (is_device_unmounted(dev)) {             
+   if (dev->is_device_unmounted()) {             
       Dmsg1(dbglvl, "Device %s is BLOCKED due to user unmount.\n", dev->print_name());
       Mmsg(jcr->errmsg, _("3601 JobId=%u device %s is BLOCKED due to user unmount.\n"),
            jcr->JobId, dev->print_name());
@@ -828,7 +828,7 @@ static bool reserve_device_for_append(DCR *dcr, RCTX &rctx)
    }
 
    /* If device is unmounted, we are out of luck */
-   if (is_device_unmounted(dev)) {
+   if (dev->is_device_unmounted()) {
       Mmsg(jcr->errmsg, _("3604 JobId=%u device %s is BLOCKED due to user unmount.\n"), 
          jcr->JobId, dev->print_name());
       Dmsg1(dbglvl, "%s", jcr->errmsg);
@@ -886,6 +886,16 @@ static bool is_max_jobs_ok(DCR *dcr)
          dcr->VolCatInfo.VolCatJobs, dev->num_reserved(),
          dcr->VolCatInfo.VolCatStatus,
          dcr->VolumeName);
+   /* Limit max concurrent jobs on this drive */
+   if (dev->max_concurrent_jobs > 0 && dev->max_concurrent_jobs <= 
+              (uint32_t)(dev->num_writers + dev->num_reserved())) {
+      /* Max Concurrent Jobs depassed or already reserved */
+      Mmsg(jcr->errmsg, _("3609 JobId=%u Max concurrent jobs exceeded on drive %s.\n"), 
+            (uint32_t)jcr->JobId, dev->print_name());
+      queue_reserve_message(jcr);
+      Dmsg1(dbglvl, "reserve dev failed: %s", jcr->errmsg);
+      return false;
+   }
    if (strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0) {
       return true;
    }
index f13bfdf3e2c1e669efed606e40efda44733d1388..f462538bf7cf837dad512fa4bfa5b91d176cec58 100644 (file)
@@ -642,14 +642,19 @@ static void make_unique_spool_filename(JCR *jcr, POOLMEM **name, int fd)
       jcr->Job, fd);
 }
 
+/*
+ * Tell Director where to find the attributes spool file 
+ *  Note, if we are not on the same machine, the Director will
+ *  return an error, and the higher level routine will transmit
+ *  the data record by record -- using bsock->despool().
+ */
 static bool blast_attr_spool_file(JCR *jcr, boffset_t size)
 {
    /* send full spool file name */
    POOLMEM *name  = get_pool_memory(PM_MESSAGE);
    make_unique_spool_filename(jcr, &name, jcr->dir_bsock->m_fd);
    bash_spaces(name);
-   jcr->dir_bsock->fsend("BlastAttr Job=%s File=%s\n",
-                         jcr->Job, name);
+   jcr->dir_bsock->fsend("BlastAttr Job=%s File=%s\n", jcr->Job, name);
    free_pool_memory(name);
    
    if (jcr->dir_bsock->recv() <= 0) {
@@ -711,7 +716,7 @@ bail_out:
    return false;
 }
 
-bool open_attr_spool_file(JCR *jcr, BSOCK *bs)
+static bool open_attr_spool_file(JCR *jcr, BSOCK *bs)
 {
    POOLMEM *name  = get_pool_memory(PM_MESSAGE);
 
@@ -731,7 +736,7 @@ bool open_attr_spool_file(JCR *jcr, BSOCK *bs)
    return true;
 }
 
-bool close_attr_spool_file(JCR *jcr, BSOCK *bs)
+static bool close_attr_spool_file(JCR *jcr, BSOCK *bs)
 {
    POOLMEM *name;
 
index eadd47b9b759dbc0a5f23916ece5630704b35fa9..1229ad54d9dbc51f15733ca74b5fb62d36cc781a 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
 
 /* Set to debug mutexes */
 //#define SD_DEBUG_LOCK
+#ifdef SD_DEBUG_LOCK
+const int sd_dbglvl = 3;
+#else
 const int sd_dbglvl = 300;
+#endif
 
 #ifdef HAVE_MTIO_H
 #include <mtio.h>
index 79153ab836adea545aff141f5cdf05ceedd8d443..19bfec3720c47f68fdcb8a881c4b432766fca315 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -157,6 +157,7 @@ static RES_ITEM dev_items[] = {
    {"maximumvolumesize",     store_size,   ITEM(res_dev.max_volume_size), 0, 0, 0},
    {"maximumfilesize",       store_size,   ITEM(res_dev.max_file_size), 0, ITEM_DEFAULT, 1000000000},
    {"volumecapacity",        store_size,   ITEM(res_dev.volume_capacity), 0, 0, 0},
+   {"maximumconcurrentjobs", store_pint32, ITEM(res_dev.max_concurrent_jobs), 0, 0, 0},
    {"spooldirectory",        store_dir,    ITEM(res_dev.spool_directory), 0, 0, 0},
    {"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},
index 2f4f5d91346dd60f83a6353c251f094f08c3815d..7972f80c68f36c19a0f9119d6b3ed1b6f8165c9e 100644 (file)
@@ -1,7 +1,7 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2007 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
@@ -137,6 +137,7 @@ public:
    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 */
+   uint32_t max_concurrent_jobs;      /* maximum concurrent jobs this drive */
    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 */
index 3cdf8e095a7f9dbb9f1d7add33e2324a1b6a8978..573f97bacae8101bc10c9f789150ccdfdf123390 100644 (file)
@@ -69,7 +69,7 @@ int wait_for_sysop(DCR *dcr)
     */
    volume_unused(dcr);
 
-   unmounted = is_device_unmounted(dev);
+   unmounted = dev->is_device_unmounted();
    dev->poll = false;
    /*
     * Wait requested time (dev->rem_wait_sec).  However, we also wake up every
@@ -145,7 +145,7 @@ int wait_for_sysop(DCR *dcr)
       /*
        * Check if user unmounted the device while we were waiting
        */
-      unmounted = is_device_unmounted(dev);
+      unmounted = dev->is_device_unmounted();
 
       if (!unmounted && dev->vol_poll_interval &&
           (total_waited >= dev->vol_poll_interval)) {
index 87555e50e4a8029befb2555fb7b455e806b439d5..75091d4d8621ec973b9b3a13b85a4b3850c01ebf 100644 (file)
@@ -1,16 +1,7 @@
-/*
- *
- *  Program to test cache path
- *
- *   Eric Bollengier, March 2007
- *
- *
- *   Version $Id$
- */
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2001-2006 Free Software Foundation Europe e.V.
+   Copyright (C) 2009-2009 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
+/*
+ *
+ *  Program to test cache path
+ *
+ *   Eric Bollengier, August 2009
+ *
+ *
+ */
 
 #include "bacula.h"
 #include "cats/cats.h"
@@ -42,7 +41,7 @@
  
 /* Local variables */
 static B_DB *db;
-static char *file="COPYRIGHT";
+static const char *file = "COPYRIGHT";
 static DBId_t fnid=0;
 static const char *db_name = "regress";
 static const char *db_user = "regress";
@@ -75,7 +74,7 @@ static int result_handler(void *ctx, int fields, char **row)
 {
    Bvfs *vfs = (Bvfs *)ctx;
    ATTR *attr = vfs->get_attr();
-   char *empty = "A A A A A A A A A A A A A A";
+   char empty[] = "A A A A A A A A A A A A A A";
 
    memset(&attr->statp, 0, sizeof(struct stat));
    decode_stat((row[BVFS_LStat] && row[BVFS_LStat][0])?row[BVFS_LStat]:empty,
@@ -112,7 +111,8 @@ static int result_handler(void *ctx, int fields, char **row)
 int main (int argc, char *argv[])
 {
    int ch;
-   char *jobids="1", *path=NULL, *client=NULL;
+   char *jobids = (char *)"1";
+   char *path=NULL, *client=NULL;
    uint64_t limit=0;
    bool clean=false;
    setlocale(LC_ALL, "");
index d5ceb6dd4ac9159915eab7bce2d2e1af0eefea0e..da24eb4c3d123596f3055c9605e737098dab658c 100644 (file)
@@ -4,8 +4,8 @@
 
 #undef  VERSION
 #define VERSION "3.0.3"
-#define BDATE   "30 July 2009"
-#define LSMDATE "30Jul09"
+#define BDATE   "09 August 2009"
+#define LSMDATE "09Aug09"
 
 #define PROG_COPYRIGHT "Copyright (C) %d-2009 Free Software Foundation Europe e.V.\n"
 #define BYEAR "2009"       /* year for copyright messages in progs */
index c7cd195aa4b87fbd377bb443b209e0d1797eff98..ed456455f6d8ba95daba88c5ec4db499006e9584 100644 (file)
@@ -2,6 +2,28 @@
           
 General:
 
+13Aug09
+ebl  update lock manager to display file:line all the time
+kes  Make SD lock tracing work again. Has not worked for some time.
+ebl  bat: Add a re-run button on job info page, that allows to
+          run the selected job with the same properties (level, pool, 
+          etc...)
+ebl  bat: tweak the run job window to make it a bit more sexy
+12Aug09
+kes  Make new big-virtual-changer test. Test concurrency.
+ebl  Add .lsfiles, .lsdirs, .update command to interface user with bvfs object
+10Aug09
+kes  Pull Philipp Storz' bacula.spec changes for OpenSuSE build service
+kes  Implement MaximumConcurrentJobs for SD devices.
+     This should significantly help spread jobs among different drives.
+09Aug09
+kes  Fix bug #1344 show pool displayed wrong variable for maxvolbytes
+kes  Fix compiler warnings in acl and xattr code
+kes  Fix screw up with setting JobLevel and JobType
+kes  Change version
+kes  Apply Marco's acl/xattr rework code
+08Aug09
+ebl  bat: display a Warning icon when having Errors>0 and Status=T
 07Aug09
 ebl  bvfs: Add example to list files versions
 ebl  bvfs: Fix directory listing
@@ -24,17 +46,17 @@ kes  Remove installing gconsole start script from Makefile.in
 01Aug09
 ebl  Add Job Info panel to bat
 30Jul09
-ebl  Add restore from multiple storage functionnality with
+ebl  Add restore from multiple storage functionality with
      a part of Graham's patch.
 kes  Add 'show disabled' command that lists the disabled jobs.
 kes  Modify enable/disable commands to show only appropriate Jobs.
 29Jul09
-kes  Add ACL check for client in estimate commande
+kes  Add ACL check for client in estimate command
 ebl  Change time_t by utime_t in accurate function
 kes  Start reworking 3.0.2 bacula.spec file
      - Add SuSE build codes
      - Add depkgs-qt so bat can build on any system
-     - Reoganize defines
+     - Reorganize defines
 26Jul09
 kes  Tweak RedHat spec files
 24Jul09
@@ -84,7 +106,7 @@ ebl  Implement the project 'restore' menu: enter a JobId, automatically
 ebl  Should fix #1323 about verify accurate jobs and deleted files.
 13Jul09
 kes  Send bootstrap directly from DIR to SD
-kes  Create build scripts for Win64 somewhat equilavent to the Win32 ones.
+kes  Create build scripts for Win64 somewhat equivalent to the Win32 ones.
 10Jul09
 ebl  Print correct JobId in bls, should fix #1331
 kes  Apply python detect patch from Bastian Friedrich <bastian.friedrich@collax.com>
@@ -100,7 +122,7 @@ mvw  Call acl and xattr function only when requested for fileset
 mvw  Fix typo introduces by fix for bug #1305
 03Jul09
 ebl  Should fix the first part #1323 about the restore option
-     'List Jobs where a given File is saved' wich display deleted files
+     'List Jobs where a given File is saved' which display deleted files
 02Jul09
 kes  Another fix for bug #1311 to get the correct last_full_time
 ebl  Make estimate command accurate compatible. Should fix #1318
index 4f55fdb092db3336ac8a2c6fd2dacfeec6e651ca..3546d93b0384903653784f484e358d51df197571 100644 (file)
@@ -1,3 +1,5 @@
+1
+*/1
 config
 DartConfiguration.tcl
 DartTestfile.txt
@@ -10,6 +12,7 @@ tmp
 weird-files
 weird-files2
 working
+working2
 scripts/bacula-dir.conf.accurate
 scripts/bacula-dir.conf.errors
 scripts/bacula-dir.conf.maxruntime
index d7da80e55bc47112464be7c70a3441f6d022c3ea..7389690ffcfbd61829245b8d9dcefcdd661fa8b0 100644 (file)
@@ -1,5 +1,6 @@
 
 
+ADD_TEST(disk:acl-xattr-test "@regressdir@/tests/acl-xattr-test")
 ADD_TEST(disk:accurate-test "@regressdir@/tests/accurate-test")
 ADD_TEST(disk:auto-label-test "@regressdir@/tests/auto-label-test")
 ADD_TEST(disk:backup-bacula-test "@regressdir@/tests/backup-bacula-test")
index 31fe6ff5d8fd9753712df2a7a7f3133a91a4be16..76229f4b149b874550b3746c28055d4048db1730 100755 (executable)
@@ -6,6 +6,7 @@ echo " "
 echo " " >>test.out
 echo "Start non-root disk tests"
 echo "Start non-root disk tests" >>test.out
+nice tests/acl-xattr-test
 nice tests/accurate-test
 nice tests/auto-label-test
 nice tests/backup-bacula-test
index 1c47adde25c5bb3f47890417fce1b5d1f82a564e..df9daba16484a5eaf0501c2b3384dad4adc8b973 100644 (file)
@@ -193,6 +193,7 @@ Storage {
   Device = Virtual                    # must be same as Device in Storage daemon
   Media Type = Disk                   # must be same as MediaType in Storage daemon
   Maximum Concurrent Jobs = 100
+  Autochanger = yes
 }
 
 
index 05abe1b2baf740b7eb7e274ffbd9e20eee6e000b..614301dcfe5e727f71fbd7373c2606840b086f34 100644 (file)
@@ -16,6 +16,7 @@ Storage {                             # definition of myself
   WorkingDirectory = "@working_dir@"
   Pid Directory = "@piddir@"
   Subsys Directory = "@subsysdir@"
+  Maximum Concurrent Jobs = 100
 }
 
 #
@@ -68,11 +69,11 @@ Autochanger {
   Name = Virtual
   Changer Device = /dev/null
   Changer Command =""
-  Device = Virtual-1, Virtual-2
+  Device = vDrive-1, vDrive-2
 }
 
 Device {
-  Name = Virtual-1
+  Name = vDrive-1
   Device Type = File
   Media Type = Disk
   Archive Device = @tmpdir@
@@ -81,11 +82,12 @@ Device {
   Drive Index = 0
   AlwaysOpen = yes;
   RemovableMedia = yes;
+  Maximum Concurrent Jobs = 3
 # Maximum File Size = 1000000
 }
 
 Device {
-  Name = Virtual-2
+  Name = vDrive-2
   Device Type = File
   Media Type = Disk
   Archive Device = @tmpdir@
@@ -94,6 +96,7 @@ Device {
   Drive Index = 1
   AlwaysOpen = yes;
   RemovableMedia = yes;
+  Maximum Concurrent Jobs = 3
 # Maximum File Size = 1000000
 }
 
index fa7d6f01106b922064d9265cd1bc9f699320d65a..1ed46830d6cfaa6ca695be9e0fe30706aa9948a0 100644 (file)
@@ -353,7 +353,7 @@ copy_test_confs()
 disable_pluguins()
 {
    for i in ${conf}/bacula-fd.conf; do
-      sed 's/Plugin/#Plugin/i' $i > $tmp/1
+      sed 's/Plugin/#Plugin/' $i > $tmp/1
       cp -f $tmp/1 $i
    done
 }
@@ -492,6 +492,7 @@ export tmp
 export src
 export tmpsrc
 
+mkdir -p ${tmp}
 touch ${tmp}/dir.out ${tmp}/fd.out ${tmp}/sd.out
 
 CLIENT=${HOST}-fd
diff --git a/regress/tests/acl-xattr-test b/regress/tests/acl-xattr-test
new file mode 100755 (executable)
index 0000000..8fd26c1
--- /dev/null
@@ -0,0 +1,119 @@
+#!/bin/sh
+#
+# Run a backup of the Bacula build directory with some acls
+#   then restore it.
+#
+# Your filesystem must be mounted with the acl option (mount -o remount,acl,user_xattr /tmp)
+# on ubuntu, the attr package must be installed
+#
+# For this script to work, you will also need a number of acl packages loaded
+#   not default on Debian derivatives: 
+#   apt-get install acl libacl1 libacl1-dev attr
+#
+TestName="acl-xattr-test"
+JobName=backup
+. scripts/functions
+
+require_linux
+
+# Require getfacl to be installed
+getfacl Makefile 2>&1 >/dev/null
+if test  $? -ne 0; then
+  echo "$TestName skipped: getfacl not installed"
+  exit 0
+fi
+
+# Require getfattr to be installed
+getfattr -d Makefile 2>&1 >/dev/null
+if test $? -ne 0; then
+  echo "$TestName skipped: getfattr not installed"
+  exit 0
+fi
+
+scripts/cleanup
+scripts/copy-confs
+
+#
+# Zap out any schedule in default conf file so that
+#  it doesn't start during our test
+#
+outf="tmp/sed_tmp"
+echo "s%  Schedule =%# Schedule =%g" > $outf
+echo "s/Options {/Options { aclsupport=yes; xattrsupport = yes/" >> $outf
+cp ${cwd}/bin/bacula-dir.conf  $cwd/tmp/1
+sed -f ${outf} ${cwd}/tmp/1 >${cwd}/bin/bacula-dir.conf
+
+d=${cwd}/build/acl
+
+uid=`id -u`
+rm -rf $d
+mkdir $d
+mkdir $d/testdir
+cp ${cwd}/bin/bconsole $d
+setfacl -m d:user:$uid:r-x $d/testdir
+setfacl -m d:user:root:-wx $d/testdir
+setfacl -m user:nobody:--- $d/testdir
+setfacl -m user:nobody:--- $d/bconsole
+setfacl -m group:nogroup:--x $d/bconsole
+cp ${cwd}/bin/bconsole $d/testdir
+cp ${cwd}/bin/bconsole $d/other
+setfattr -n bacula.test -v rulez $d/other
+
+( cd $cwd/build
+  getfacl -R acl > $cwd/tmp/org
+  getfattr -R acl > $cwd/tmp/attr.org
+)
+
+change_jobname BackupClient1 $JobName
+start_test
+
+cat <<END_OF_DATA >${cwd}/tmp/bconcmds
+@output /dev/null
+messages
+@$out ${cwd}/tmp/log1.out
+label volume=TestVolume001 storage=File pool=Default
+setdebug level=400 trace=1 client
+setdebug level=300 trace=1 director
+setdebug level=300 trace=1 storage
+run job=$JobName yes
+wait
+messages
+@# 
+@# now do a restore
+@#
+@$out ${cwd}/tmp/log2.out  
+restore where=${cwd}/tmp/bacula-restores select all done
+yes
+wait
+messages
+@$out
+quit
+END_OF_DATA
+
+run_bacula
+check_for_zombie_jobs storage=File
+stop_bacula
+
+( cd $cwd/tmp/bacula-restores/$cwd/build
+  getfacl -R acl > $cwd/tmp/new
+  getfattr -R acl > $cwd/tmp/attr.new
+)
+
+diff $cwd/tmp/org $cwd/tmp/new
+if [ $? -ne 0 ]; then
+   rstat=1
+fi
+
+diff $cwd/tmp/attr.org $cwd/tmp/attr.new
+if [ $? -ne 0 ]; then
+   rstat=1
+fi
+
+check_two_logs
+check_restore_diff
+
+if [ x$REGRESS_DEBUG != x ]; then
+  rm -rf $d
+fi
+
+end_test
diff --git a/regress/tests/backup-acl-test b/regress/tests/backup-acl-test
deleted file mode 100755 (executable)
index b9da95c..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/bin/sh
-#
-# Run a backup of the Bacula build directory with some acls
-#   then restore it.
-#
-# The fs have to be mount with the acl option (mount -o remount,acl,user_xattr /tmp)
-# on ubuntu, it needs the attr package
-#
-# For this script to work, you will also need a number of acl packages loaded
-#   not default on Debian derivatives: 
-#   apt-get install acl libacl1 libacl1-dev attr
-#
-TestName="backup-acl-test"
-JobName=backup
-. scripts/functions
-
-require_linux
-scripts/cleanup
-scripts/copy-confs
-
-#
-# Zap out any schedule in default conf file so that
-#  it doesn't start during our test
-#
-outf="tmp/sed_tmp"
-echo "s%  Schedule =%# Schedule =%g" > $outf
-echo "s/Options {/Options { aclsupport=yes; xattrsupport = yes/" >> $outf
-cp ${cwd}/bin/bacula-dir.conf  $cwd/tmp/1
-sed -f ${outf} ${cwd}/tmp/1 >${cwd}/bin/bacula-dir.conf
-
-d=${cwd}/build/acl
-
-uid=`id -u`
-rm -rf $d
-mkdir $d
-mkdir $d/testdir
-cp ${cwd}/bin/bconsole $d
-setfacl -m d:user:$uid:r-x $d/testdir
-setfacl -m d:user:root:-wx $d/testdir
-setfacl -m user:nobody:--- $d/testdir
-setfacl -m user:nobody:--- $d/bconsole
-setfacl -m group:nogroup:--x $d/bconsole
-cp ${cwd}/bin/bconsole $d/testdir
-cp ${cwd}/bin/bconsole $d/other
-setfattr -n bacula.test -v rulez $d/other
-
-( cd $cwd/build
-  getfacl -R acl > $cwd/tmp/org
-  getfattr -R acl > $cwd/tmp/attr.org
-)
-
-change_jobname BackupClient1 $JobName
-start_test
-
-cat <<END_OF_DATA >${cwd}/tmp/bconcmds
-@output /dev/null
-messages
-@$out ${cwd}/tmp/log1.out
-label volume=TestVolume001 storage=File pool=Default
-setdebug level=400 trace=1 client
-setdebug level=300 trace=1 director
-setdebug level=300 trace=1 storage
-run job=$JobName yes
-wait
-messages
-@# 
-@# now do a restore
-@#
-@$out ${cwd}/tmp/log2.out  
-restore where=${cwd}/tmp/bacula-restores select all done
-yes
-wait
-messages
-@$out
-quit
-END_OF_DATA
-
-run_bacula
-check_for_zombie_jobs storage=File
-stop_bacula
-
-( cd $cwd/tmp/bacula-restores/$cwd/build
-  getfacl -R acl > $cwd/tmp/new
-  getfattr -R acl > $cwd/tmp/attr.new
-)
-
-diff $cwd/tmp/org $cwd/tmp/new
-if [ $? -ne 0 ]; then
-   rstat=1
-fi
-
-diff $cwd/tmp/attr.org $cwd/tmp/attr.new
-if [ $? -ne 0 ]; then
-   rstat=1
-fi
-
-check_two_logs
-check_restore_diff
-
-if [ x$REGRESS_DEBUG != x ]; then
-  rm -rf $d
-fi
-
-end_test
diff --git a/regress/tests/big-virtual-changer-test b/regress/tests/big-virtual-changer-test
new file mode 100755 (executable)
index 0000000..d38847d
--- /dev/null
@@ -0,0 +1,138 @@
+#!/bin/sh
+#
+# Run a simple backup of the Bacula build directory. Create three
+#   tapes, each in a different pool, then run two jobs both of which
+#   want the disk that is not loaded.  Note, they both have     
+#   prefers non-mounted tapes.  This should expose bug #801
+#
+#  This test the SD Virtual autochanger feature.  It is a disk based
+#    "autochanger", but does not use any changer script.
+#
+# This script uses the Virtual disk autochanger and two drives
+#
+TestName="virtual-changer-disk"
+JobName="virtualchangerdisk"
+. scripts/functions
+
+scripts/cleanup
+scripts/copy-2disk-drive-confs
+scripts/prepare-disk-changer
+
+CLIENT=2drive2disk
+
+echo "${cwd}/build" >${cwd}/tmp/file-list
+echo "${cwd}/build" >>${cwd}/tmp/file-list
+echo "${cwd}/build" >>${cwd}/tmp/file-list
+echo "${cwd}/build" >>${cwd}/tmp/file-list
+echo "${cwd}/build" >>${cwd}/tmp/file-list
+echo "${cwd}/build" >>${cwd}/tmp/file-list
+#change_jobname Virtual $JobName
+start_test
+
+# Turn off Prefer Mounted Volumes so we use 2 drives
+outf="${cwd}/tmp/sed_tmp"
+echo "s%# Prefer Mounted Volumes%  Prefer Mounted Volumes%g" >${outf}
+cp ${cwd}/bin/bacula-dir.conf ${cwd}/tmp/1
+# Comment the next line out to write everything to one drive
+#  otherwise, it writes the two jobs to different drives
+#sed -f ${outf} ${cwd}/tmp/1 >${cwd}/bin/bacula-dir.conf
+
+# Write out bconsole commands
+cat <<END_OF_DATA >${cwd}/tmp/bconcmds
+@output /dev/null
+messages
+@$out ${cwd}/tmp/log1.out
+setdebug level=10 storage=Virtual
+@#setdebug level=200 client=$CLIENT 
+label storage=Virtual volume=TestVolume001 slot=1 Pool=Default drive=0
+label storage=Virtual volume=TestVolume002 slot=2 Pool=Full    drive=0
+label storage=Virtual volume=TestVolume003 slot=3 Pool=Inc     drive=1
+label storage=Virtual volume=TestVolume004 slot=4 Pool=Default drive=0
+status storage=Virtual
+run job=Virtual level=Full Pool=Default yes
+run job=Virtual level=Full Pool=Default yes
+run job=Virtual level=Full Pool=Default yes
+run job=Virtual level=Full Pool=Default yes
+run job=Virtual level=Full Pool=Default yes
+run job=Virtual level=Full Pool=Default yes
+run job=Virtual level=Full Pool=Default yes
+run job=Virtual level=Full Pool=Default yes
+run job=Virtual level=Full Pool=Default yes
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 1
+status storage=Virtual
+status client
+@sleep 5
+status storage=Virtual
+status client
+list volumes
+wait
+list volumes
+list jobs
+status storage=Virtual
+status client
+messages
+quit
+END_OF_DATA
+
+# exit
+
+run_bacula
+cat <<END_OF_DATA >${cwd}/tmp/bconcmds
+@$out /dev/null
+messages
+@# 
+@# now do a restore
+@#
+@$out ${cwd}/tmp/log2.out
+restore where=${cwd}/tmp/bacula-restores select all storage=Virtual done
+yes
+wait
+messages
+@$out
+quit
+END_OF_DATA
+
+run_bconsole
+
+check_for_zombie_jobs storage=Virtual
+stop_bacula
+
+check_two_logs
+check_restore_diff
+
+end_test
index 5d6ffc488481af07a124a92c6ac473a251bea69b..6ab02e2cd6f90c25993921cd2dc32fb5fced75a7 100755 (executable)
@@ -102,7 +102,7 @@ wait
 messages
 @##################################
 @$out tmp/RUN_JobG
-restore strip_prefix="${cwd}" add_prefix="/tmp/bacula-restore.$$"
+restore strip_prefix="${cwd}" add_prefix="${tmp}/bacula-restore.$$"
 5
 cd ${cwd}/build/po
 m *.po
@@ -256,7 +256,7 @@ else
    echo "$J in error"
    rstat=1
 fi
-rm -rf /tmp/bacula-restore.$$
+rm -rf ${tmp}/bacula-restore.$$
 
 J=JobH
 grep "Restore OK"  tmp/RUN_$J > /dev/null && \
index e129fad8f94b37a12ddac814eb47a266dd5f9799..d29837235bc0554f2ae72f540270a146962869ac 100755 (executable)
@@ -10,10 +10,17 @@ scripts/cleanup
 scripts/copy-strip-confs
 
 
-rm -rf /tmp/$$-strip
-mkdir /tmp/$$-strip
-cp -rpf ${cwd}/build/src/dird/ /tmp/$$-strip/
-echo "/tmp/$$-strip" >${cwd}/tmp/file-list
+# Make a copy of build/src/dird to be backed up
+rm -rf ${tmp}/$$-strip
+mkdir ${tmp}/$$-strip
+cp -rpf ${cwd}/build/src/dird/ ${tmp}/$$-strip/
+echo "${tmp}/$$-strip" >${cwd}/tmp/file-list
+
+# Now, strip the first 4 parts of the path (which is what
+#   the backup will do and put the result in rpath
+echo "${tmp}/$$-strip/" >${tmp}/1
+rpath=`cut -f5- -d'/' ${tmp}/1`
+echo "========= $rpath"
 
 change_jobname NightlySave $JobName
 start_test
@@ -35,6 +42,8 @@ END_OF_DATA
 
 run_bacula
 
+rm -rf ${cwd}/tmp/bacula-restores
+
 cat <<END_OF_DATA >${cwd}/tmp/bconcmds
 @$out /dev/null
 messages
@@ -58,16 +67,13 @@ stop_bacula
 
 check_two_logs
 #
-# Kludge remove this next line when strip is fixed
-#
-rm -rf tmp/bacula-restores/tmp
 if test "$debug" -eq 1 ; then
-   diff -ur /tmp/$$-strip/dird/ tmp/bacula-restores/
+   diff -ur ${tmp}/$$-strip/ ${tmp}/bacula-restores/${rpath}
 else 
-   diff -r /tmp/$$-strip/dird/ tmp/bacula-restores/ 2>&1 >/dev/null
+   diff -r ${tmp}/$$-strip/ ${tmp}/bacula-restores/${rpath} 2>&1 >/dev/null
 fi
 dstat=$?
 
-rm -rf /tmp/$$-strip
+rm -rf ${tmp}/$$-strip
 
 end_test
index d613fe24746c372dacf7700d71c3ea59ee3772bc..69f1fb69fd8f14ce05f654f777a361b47043001b 100755 (executable)
@@ -1,9 +1,9 @@
 #!/bin/sh
 #
-# Run a simple backup of the Bacula build directory then do a virtual
-#   backup to another device.
+# Run a simple backup of the Bacula build directory then do a 
+#   Virtual Full backup to another device.
 #
-# This script uses the virtual disk autochanger
+# This script uses the disk autochanger
 #
 TestName="virtual-backup-test"
 JobName=Vbackup
index 6563a9170f6a375fd2cde0c495fb2bc211bfdd12..a2fa24b3f987d187e194649f8cbf9d567a76a43b 100755 (executable)
@@ -1,9 +1,9 @@
 #!/bin/sh
 #
-# Run a simple backup of the Bacula build directory then do a virtual
-#   backup to another device.
+# Run a simple backup of the Bacula build directory then do a 
+#   Virtual Full backup to another device.
 #
-# This script uses the virtual disk autochanger
+# This script uses the disk autochanger
 #
 TestName="virtual-backup-test"
 JobName=Vbackup
index 30a371bf8a49fb6f8cdf7350e33efdd8ed4ca03d..474c98d402ef81ec8dadc374eaf85ee5c7629eb7 100755 (executable)
@@ -5,7 +5,10 @@
 #   want the disk that is not loaded.  Note, they both have     
 #   prefers non-mounted tapes.  This should expose bug #801
 #
-# This script uses the virtual disk autochanger and two drives
+#  This test the SD Virtual autochanger feature.  It is a disk based
+#    "autochanger", but does not use any changer script.
+#
+# This script uses the Virtual disk autochanger and two drives
 #
 TestName="virtual-changer-disk"
 JobName="virtualchangerdisk"