src/tools/bregtest
src/tools/grow
src/tools/.libs
+src/tools/bvfs_test
# src/tray-monitor/
src/tray-monitor/tray-monitor.conf
# choose database backend here
# postgres, mysql, sqlite
-%define build_postgresql 1
+%define build_mysql 1
# Build Service: Determine Distribution
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
%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.}
%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
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
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
# 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}
--with-mysql \
%endif
%if %{sqlite}
+%if %{su9} || %{su10}
+ --with-sqlite \
+%else
--with-sqlite3 \
%endif
+%endif # sqlite?
%if %{postgresql}
--with-postgresql \
%endif
# 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
%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
%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
%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)
%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
%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
%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`
%{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
%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`
%{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
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
/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}
%{_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
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
%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
Dmsg1(dbglevel, "Affected row(s) = %d\n", nb);
db_end_transaction(jcr, mdb);
+ free_pool_memory(jobids);
}
/*
}
/* 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);
/*
* 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);
"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) "
/*
* 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();
/*
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.
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),
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;
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;
#include "bacula.h"
#include "dird.h"
+#include "cats/bvfs.h"
+#include "findlib/find.h"
/* Imported variables */
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);
{ 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)))
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);
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)) {
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;
}
/* 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;
}
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);
}
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;
}
* 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
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;
}
/*
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;
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>
#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;
}
*/
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);
* 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.
*/
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;
tag != ACL_OTHER_OBJ)
return false;
}
-
return true;
#elif defined(HAVE_OSF1_OS)
int count;
while (count > 0) {
tag = ace->entry->acl_type;
-
/*
* Anything other the ACL_USER_OBJ, ACL_GROUP_OBJ or ACL_OTHER breaks the spell.
*/
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
}
/*
* 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);
*/
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
* 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;
}
/*
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
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
* 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)
/*
*
* 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.
* 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:
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)
#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.
for (n = 0; n < count; n++) {
ace = entries[n];
-
/*
* See if this acl just is the stat mode in acl form.
*/
(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)) {
/*
* 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
* 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>
* 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.
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;
/*
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;
}
* 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) {
* 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)
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;
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.
* 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:
* 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:
}
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;
}
/*
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:
* 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.
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) {
*/
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;
}
/*
* 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 */
/*
/*
* 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
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 */
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);
*/
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;
+ }
}
}
*/
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;
+ }
}
}
* 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"
#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"
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);
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);
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)) {
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++;
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++;
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);
/*
* 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
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;
}
/*
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;
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
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;
}
/*
*/
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';
}
if (count == 0) {
- free(xattr_list);
-
- return true;
+ retval = bxattr_exit_ok;
+ goto bail_out;
}
/*
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;
*/
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;
+ }
}
/*
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;
+ }
}
/*
* 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;
}
* 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;
}
/*
* 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.
*/
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;
}
/*
* 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;
+ }
}
/*
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
#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
* 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;
}
}
{
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)
fattr = name_to_attr(name);
} else {
retval = true;
- goto cleanup;
+ goto bail_out;
}
type = nvpair_type(pair);
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);
}
}
#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
*/
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) {
} 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
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;
+ }
}
/*
*/
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;
} 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.
* 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;
+ }
}
/*
/*
* 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;
/*
* 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.
* 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:
* 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);
/*
* For a hard linked file we are ready now, no need to recursively save the attributes.
*/
- goto cleanup;
+ goto bail_out;
}
/*
/*
* 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);
* 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;
* 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);
/*
* 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;
}
/*
* 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) {
}
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;
* 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);
}
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
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;
+ }
}
/*
* 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;
}
/*
* 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;
}
/*
*/
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;
}
/*
* 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 */
* 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)
}
#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;
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.
* 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;
}
/*
*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);
* 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);
* 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;
*/
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:
*/
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:
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;
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) {
}
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;
}
}
* 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;
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;
}
/*
* 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 */
/*
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);
}
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.
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;
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;
}
/*
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
/*
* 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.
@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 " "
#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 */
#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 || \
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; };
};
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 */
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 */
*/
bool is_bnet_stop(BSOCK * bsock)
{
- return bsock->errors || bsock->is_terminated();
+ return bsock->is_stop();
}
/*
*/
int is_bnet_error(BSOCK * bsock)
{
- errno = bsock->b_errno;
- return bsock->errors;
+ return bsock->is_error();
}
/*
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 */
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; };
/*
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 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) {
/* 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;
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
case JS_ErrorTerminated:
case JS_FatalError:
case JS_Canceled:
+ case JS_Incomplete:
priority = 10;
break;
case JS_Error:
/* 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;
}
* 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);
}
/*
/*
* 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();
}
/* 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,
/*
* 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
# 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
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 */
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);
} 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);
/* 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);
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 {
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
#include "job.h"
#include "util/fmtwidgetitem.h"
#include "mediainfo/mediainfo.h"
+#include "run/run.h"
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();
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();
void Job::populateAll()
{
- Pmsg0(0, "populateAll()\n");
+// Pmsg0(50, "populateAll()\n");
populateText();
populateForm();
populateVolumes();
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 ? */
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 */
*/
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, "
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;
"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;
void populateAll();
void deleteJob();
void showInfoVolume(QListWidgetItem *);
+ void rerun();
private slots:
</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>
<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>
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
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()));
}
/*
"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) "
#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;
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()
+/*
+ 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_
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;
};
<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><h3>Run a Job</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><h3>Backup<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><h3>Backup<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><h3>Run a Job</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>
--- /dev/null
+/*
+ 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);
+}
--- /dev/null
+#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_ */
--- /dev/null
+<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>
#include <QAbstractEventDispatcher>
#include <QMenu>
#include "storage.h"
+#include "content.h"
#include "label/label.h"
#include "mount/mount.h"
#include "status/storstat.h"
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);
+ }
}
/*
void consoleUpdateSlotsScan();
void consoleRelease();
void statusStorageWindow();
+ void contentWindow();
private:
void createContextMenu();
QTreeWidgetItem *m_topItem;
};
+void table_get_selection(QTableWidget *table, QString &sel);
+
#endif /* _STORAGE_H_ */
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;
* 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) {
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());
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();
}
/*
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.
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;
/*
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.
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 */
#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; };
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); }
#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();
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);
}
#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()) {
/*
* 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;
}
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);
#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
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());
}
/* 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);
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;
}
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) {
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);
return true;
}
-bool close_attr_spool_file(JCR *jcr, BSOCK *bs)
+static bool close_attr_spool_file(JCR *jcr, BSOCK *bs)
{
POOLMEM *name;
/*
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>
/*
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.
{"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},
/*
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.
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 */
*/
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
/*
* 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)) {
-/*
- *
- * 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"
/* 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";
{
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,
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, "");
#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 */
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
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
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>
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
+1
+*/1
config
DartConfiguration.tcl
DartTestfile.txt
weird-files
weird-files2
working
+working2
scripts/bacula-dir.conf.accurate
scripts/bacula-dir.conf.errors
scripts/bacula-dir.conf.maxruntime
+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")
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
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
}
WorkingDirectory = "@working_dir@"
Pid Directory = "@piddir@"
Subsys Directory = "@subsysdir@"
+ Maximum Concurrent Jobs = 100
}
#
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@
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@
Drive Index = 1
AlwaysOpen = yes;
RemovableMedia = yes;
+ Maximum Concurrent Jobs = 3
# Maximum File Size = 1000000
}
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
}
export src
export tmpsrc
+mkdir -p ${tmp}
touch ${tmp}/dir.out ${tmp}/fd.out ${tmp}/sd.out
CLIENT=${HOST}-fd
--- /dev/null
+#!/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
+++ /dev/null
-#!/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
--- /dev/null
+#!/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
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
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 && \
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
run_bacula
+rm -rf ${cwd}/tmp/bacula-restores
+
cat <<END_OF_DATA >${cwd}/tmp/bconcmds
@$out /dev/null
messages
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
#!/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
#!/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
# 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"