From d3c35853300d8347c4b24efff70baa79db7b4e56 Mon Sep 17 00:00:00 2001 From: Marco van Wieringen Date: Mon, 11 Jun 2012 17:16:40 +0200 Subject: [PATCH] Add rudimentary support for saving AFS acls. Add support for saving and restoring AFS acls using the pioctl interface of (Open)AFS. This is mostly a proof of concept its no where ready for production and may put a enormous load on your AFS cell so please use it only for testing. It also only solves part of the AFS backup problem as we only save and restore acls on directories on an AFS filesystem but not the actual cell configuration etc. For that we advice you to use the native tooling using some script or the bpipe plugin. --- bacula/autoconf/acconfig.h | 6 -- bacula/autoconf/configure.in | 121 ++++++++++++++++++++++++++++- bacula/src/filed/Makefile.in | 14 ++-- bacula/src/filed/acl.c | 142 +++++++++++++++++++++++++++++++++-- 4 files changed, 264 insertions(+), 19 deletions(-) diff --git a/bacula/autoconf/acconfig.h b/bacula/autoconf/acconfig.h index c60296ab63..40a91d70e5 100644 --- a/bacula/autoconf/acconfig.h +++ b/bacula/autoconf/acconfig.h @@ -49,9 +49,6 @@ /* Define if you have GCC */ #undef HAVE_GCC -/* Define if you have the Andrew File System. */ -#undef AFS - /* Define If you want find -nouser and -nogroup to make tables of used UIDs and GIDs at startup instead of using getpwuid or getgrgid when needed. Speeds up -nouser and -nogroup unless you @@ -117,9 +114,6 @@ /* Define if you have libacl */ #undef HAVE_ACL -/* Define if you have AFS acls */ -#undef HAVE_AFS_ACL - /* General libs */ #undef LIBS diff --git a/bacula/autoconf/configure.in b/bacula/autoconf/configure.in index ff06afc523..5f46fc30b8 100644 --- a/bacula/autoconf/configure.in +++ b/bacula/autoconf/configure.in @@ -2517,6 +2517,113 @@ AC_CHECK_HEADER(lzo/lzoconf.h, ]) AC_SUBST(LZOLIBS) +dnl +dnl Check if we have AFS on this system +dnl +AFS_CFLAGS="" +AFS_LIBS="" +support_afs=auto +AC_ARG_ENABLE(afs, + AC_HELP_STRING([--disable-afs], [disable afs support @<:@default=auto@:>@]), + [ + if test x$enableval = xyes; then + support_afs=yes + elif test x$enableval = xno; then + support_afs=no + fi + ] +) + +have_afs=no +if test x$support_afs = xyes -o x$support_afs = xauto; then + AC_ARG_WITH(afsdir, + AC_HELP_STRING([--with-afsdir@<:@=DIR@:>@], [Directory holding AFS includes/libs]), + with_afsdir=$withval + ) + + dnl + dnl Search in standard places, or --with-afsdir not specified + dnl + if test x$with_afsdir = x; then + for root in /usr /usr/local; do + if test -d ${root}/include/afs/ ; then + with_afsdir=${root} + break + fi + if test -d ${root}/include/openafs/afs/ ; then + with_afsdir=${root} + break + fi + done + fi + + if test -d ${with_afsdir}/include/afs/ ; then + AFS_CFLAGS="-I${with_afsdir}/include" + else + if test -d ${with_afsdir}/include/openafs/afs/ ; then + AFS_CFLAGS="-I${with_afsdir}/include/openafs" + fi + fi + + saved_CFLAGS="${CFLAGS}" + saved_CPPFLAGS="${CPPFLAGS}" + CFLAGS="${AFS_CFLAGS} ${saved_CFLAGS}" + CPPFLAGS="${AFS_CFLAGS} ${saved_CPPFLAGS}" + + AC_CHECK_HEADERS(afs/afsint.h) + AC_TRY_CPP( + [ + #include + #include + ], + AC_DEFINE(HAVE_AFS_VENUS_H,1,[Define to 1 if you have the header file.]) + ) + + CFLAGS="${saved_CFLAGS}" + CPPFLAGS="${saved_CPPFLAGS}" + + dnl + dnl See if we can find a libsys with the pioctl symbol in there + dnl + AC_MSG_CHECKING(for pioctl in AFS libsys) + for dir in ${with_afsdir}/lib \ + ${with_afsdir}/lib/afs \ + ${with_afsdir}/lib/openafs \ + ${with_afsdir}/lib64 \ + ${with_afsdir}/lib64/afs \ + ${with_afsdir}/lib64/openafs + do + for arch_type in .a .so + do + A=`test -f ${dir}/libsys${arch_type} && nm ${dir}/libsys${arch_type} 2>/dev/null | grep pioctl` + pkg=$? + if test $pkg = 0; then + have_afs=yes + AFS_LIBS="-L${dir} -lsys -lrx -llwp ${dir}/util${arch_type}" + break + fi + done + done + + if test $have_afs = yes; then + AC_MSG_RESULT(yes) + else + AC_MSG_RESULT(no) + fi + + if test x$support_afs = xyes -a $have_afs != yes; then + AC_MSG_ERROR([afs support explicitly enabled but no supported afs implementation found, + please either load the afs libraries or rerun configure without --enable-afs]) + else + if test $have_afs = yes; then + AC_DEFINE(HAVE_AFS,1,[Define to 1 if your system has AFS support]) + AC_DEFINE(HAVE_AFS_ACL,1,[Andrew FileSystem ACL support]) + fi + fi +fi +AC_SUBST(AFS_CFLAGS) +AC_SUBST(AFS_LIBS) + dnl dnl Check for ACL support and libraries dnl @@ -2553,7 +2660,18 @@ if test x$support_acl = xyes -o x$support_acl = xauto; then AC_CHECK_LIB(acl, acl_get_file, [ have_acl=yes - FDLIBS="-lacl $FDLIBS" + if test $have_afs = yes; then + dnl + dnl Because of possible naming conflict with AFS libacl make sure we use the one in /usr/lib64 or /usr/lib !!! + dnl + if test -d /usr/lib64/; then + FDLIBS="-L/usr/lib64 -lacl $FDLIBS" + else + FDLIBS="-L/usr/lib -lacl $FDLIBS" + fi + else + FDLIBS="-lacl $FDLIBS" + fi ] ) fi @@ -3523,6 +3641,7 @@ Configuration on `date`: build-dird: ${build_dird} build-stored: ${build_stored} Plugin support: ${have_plugins} + AFS support: ${have_afs} ACL support: ${have_acl} XATTR support: ${have_xattr} Python support: ${support_python} ${PYTHON_LIBS} diff --git a/bacula/src/filed/Makefile.in b/bacula/src/filed/Makefile.in index c67a2e0320..d2f452888b 100644 --- a/bacula/src/filed/Makefile.in +++ b/bacula/src/filed/Makefile.in @@ -24,6 +24,8 @@ GETTEXT_LIBS = @LIBINTL@ PYTHON_LIBS = @PYTHON_LIBS@ PYTHON_INC = @PYTHON_INCDIR@ +AFS_CFLAGS = @AFS_CFLAGS@ +AFS_LIBS = @AFS_LIBS@ first_rule: all dummy: @@ -64,7 +66,7 @@ all: Makefile @WIN32@ bacula-fd @STATIC_FD@ acl.o: acl.c @echo "Compiling $<" - $(NO_ECHO)$(CXX) $(DEFS) $(DEBUG) -c $(WCFLAGS) $(CPPFLAGS) $(PYTHON_INC) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $< + $(NO_ECHO)$(CXX) $(DEFS) $(DEBUG) -c $(WCFLAGS) $(CPPFLAGS) $(PYTHON_INC) -I$(srcdir) -I$(basedir) $(DINCLUDE) $(CFLAGS) $(AFS_CFLAGS) $< win32/winlib.a: @if test -f win32/Makefile -a "${GMAKE}" != "none"; then \ @@ -94,13 +96,13 @@ win32: $(WIN32OBJS) bacula-fd: Makefile $(SVROBJS) ../findlib/libbacfind$(DEFAULT_ARCHIVE_TYPE) ../lib/libbacpy$(DEFAULT_ARCHIVE_TYPE) ../lib/libbaccfg$(DEFAULT_ARCHIVE_TYPE) ../lib/libbac$(DEFAULT_ARCHIVE_TYPE) @WIN32@ @echo "Linking $@ ..." $(LIBTOOL_LINK) $(CXX) $(WLDFLAGS) $(LDFLAGS) -L../lib -L../findlib -o $@ $(SVROBJS) \ - $(WIN32LIBS) $(FDLIBS) $(ZLIBS) $(LZOLIBS) -lbacfind -lbacpy -lbaccfg -lbac -lm $(PYTHON_LIBS) $(LIBS) \ - $(DLIB) $(WRAPLIBS) $(GETTEXT_LIBS) $(OPENSSL_LIBS) $(CAP_LIBS) + $(WIN32LIBS) $(FDLIBS) $(ZLIBS) -lbacfind -lbacpy -lbaccfg -lbac -lm $(PYTHON_LIBS) $(LIBS) \ + $(DLIB) $(WRAPLIBS) $(GETTEXT_LIBS) $(OPENSSL_LIBS) $(CAP_LIBS) $(AFS_LIBS) $(LZOLIBS) static-bacula-fd: Makefile $(SVROBJS) ../findlib/libbacfind.a ../lib/libbacpy$(DEFAULT_ARCHIVE_TYPE) ../lib/libbaccfg$(DEFAULT_ARCHIVE_TYPE) ../lib/libbac$(DEFAULT_ARCHIVE_TYPE) @WIN32@ $(LIBTOOL_LINK) $(CXX) $(WLDFLAGS) $(LDFLAGS) -static -L../lib -L../findlib -o $@ $(SVROBJS) \ - $(WIN32LIBS) $(FDLIBS) $(ZLIBS) $(LZOLIBS) -lbacfind -lbacpy -lbaccfg -lbac -lm $(PYTHON_LIBS) $(LIBS) \ - $(DLIB) $(WRAPLIBS) $(GETTEXT_LIBS) $(OPENSSL_LIBS) $(CAP_LIBS) + $(WIN32LIBS) $(FDLIBS) $(ZLIBS) -lbacfind -lbacpy -lbaccfg -lbac -lm $(PYTHON_LIBS) $(LIBS) \ + $(DLIB) $(WRAPLIBS) $(GETTEXT_LIBS) $(OPENSSL_LIBS) $(CAP_LIBS) $(AFS_LIBS) $(LZOLIBS) strip $@ Makefile: $(srcdir)/Makefile.in $(topdir)/config.status @@ -170,7 +172,7 @@ depend: @$(MV) Makefile Makefile.bak @$(SED) "/^# DO NOT DELETE:/,$$ d" Makefile.bak > Makefile @$(ECHO) "# DO NOT DELETE: nice dependency list follows" >> Makefile - @$(CXX) -S -M $(CPPFLAGS) $(XINC) $(PYTHON_INC) -I$(srcdir) -I$(basedir) *.c >> Makefile + @$(CXX) -S -M $(CPPFLAGS) $(AFS_CFLAGS) $(XINC) $(PYTHON_INC) -I$(srcdir) -I$(basedir) *.c >> Makefile @if test -f Makefile ; then \ $(RMF) Makefile.bak; \ else \ diff --git a/bacula/src/filed/acl.c b/bacula/src/filed/acl.c index 4880d70ae8..b83bd7a19e 100644 --- a/bacula/src/filed/acl.c +++ b/bacula/src/filed/acl.c @@ -38,6 +38,8 @@ * - Solaris (POSIX and NFSv4/ZFS acls) * - Tru64 * + * Next to OS specific acls we support AFS acls using the pioctl interface. + * * We handle two different types of ACLs: access and default ACLS. * On most systems that support default ACLs they only apply to directories. * @@ -63,7 +65,7 @@ #include "bacula.h" #include "filed.h" -#if !defined(HAVE_ACL) +#if !defined(HAVE_ACL) && !defined(HAVE_AFS_ACL) /** * Entry points when compiled without support for ACLs or on an unsupported platform. */ @@ -431,7 +433,9 @@ static bacl_exit_code aix_parse_acl_streams(JCR *jcr, if (cnt < 3) { continue; } - /* FALL THROUGH */ + /* + * FALLTHROUGH + */ default: Mmsg2(jcr->errmsg, _("aclx_scanStr error on file \"%s\": ERR=%s\n"), @@ -1977,8 +1981,9 @@ static bacl_exit_code solaris_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) char *acl_text; n = acl(jcr->last_fname, GETACLCNT, 0, NULL); - if (n < MIN_ACL_ENTRIES) + if (n < MIN_ACL_ENTRIES) { return bacl_exit_error; + } acls = (aclent_t *)malloc(n * sizeof(aclent_t)); if (acl(jcr->last_fname, GETACL, n, acls) == n) { @@ -2072,7 +2077,86 @@ static bacl_exit_code (*os_parse_acl_streams) #endif /* HAVE_SUN_OS */ #endif /* HAVE_ACL */ -/* +#if defined(HAVE_AFS_ACL) + +#if defined(HAVE_AFS_AFSINT_H) && defined(HAVE_AFS_VENUS_H) +#include +#include +#else +#error "configure failed to detect availability of afs/afsint.h and/or afs/venus.h" +#endif + +/** + * External references to functions in the libsys library function not in current include files. + */ +extern "C" { +long pioctl(char *pathp, long opcode, struct ViceIoctl *blobp, int follow); +} + +static bacl_exit_code afs_build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) +{ + int error; + struct ViceIoctl vip; + char acl_text[BUFSIZ]; + + /* + * AFS ACLs can only be set on a directory, so no need to try to + * request them for anything other then that. + */ + if (ff_pkt->type != FT_DIREND) { + return bacl_exit_ok; + } + + vip.in = NULL; + vip.in_size = 0; + vip.out = acl_text; + vip.out_size = sizeof(acl_text); + memset((caddr_t)acl_text, 0, sizeof(acl_text)); + + if ((error = pioctl(jcr->last_fname, VIOCGETAL, &vip, 0)) < 0) { + berrno be; + + Mmsg2(jcr->errmsg, + _("pioctl VIOCGETAL error on file \"%s\": ERR=%s\n"), + jcr->last_fname, be.bstrerror()); + Dmsg2(100, "pioctl VIOCGETAL error file=%s ERR=%s\n", + jcr->last_fname, be.bstrerror()); + return bacl_exit_error; + } + jcr->acl_data->u.build->content_length = + pm_strcpy(jcr->acl_data->u.build->content, acl_text); + return send_acl_stream(jcr, STREAM_ACL_AFS_TEXT); +} + +static bacl_exit_code afs_parse_acl_stream(JCR *jcr, + int stream, + char *content, + uint32_t content_length) +{ + int error; + struct ViceIoctl vip; + + vip.in = content; + vip.in_size = content_length; + vip.out = NULL; + vip.out_size = 0; + + if ((error = pioctl(jcr->last_fname, VIOCSETAL, &vip, 0)) < 0) { + berrno be; + + Mmsg2(jcr->errmsg, + _("pioctl VIOCSETAL error on file \"%s\": ERR=%s\n"), + jcr->last_fname, be.bstrerror()); + Dmsg2(100, "pioctl VIOCSETAL error file=%s ERR=%s\n", + jcr->last_fname, be.bstrerror()); + + return bacl_exit_error; + } + return bacl_exit_ok; +} +#endif /* HAVE_AFS_ACL */ + +/** * Entry points when compiled with support for ACLs on a supported platform. */ @@ -2083,7 +2167,7 @@ bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) { /* * See if we are changing from one device to an other. - * We save the current device we are restoring to and compare + * We save the current device we are scanning and compare * it with the current st_dev in the last stat performed on * the file we are currently storing. */ @@ -2093,14 +2177,35 @@ bacl_exit_code build_acl_streams(JCR *jcr, FF_PKT *ff_pkt) */ jcr->acl_data->flags = 0; +#if defined(HAVE_AFS_ACL) + /* + * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem + * Set the BACL_FLAG_SAVE_AFS flag if it is. If not set the BACL_FLAG_SAVE_NATIVE flag. + */ + if (fstype_equals(jcr->last_fname, "afs")) { + jcr->acl_data->flags |= BACL_FLAG_SAVE_AFS; + } else { + jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE; + } +#else jcr->acl_data->flags |= BACL_FLAG_SAVE_NATIVE; +#endif - /** + /* * Save that we started scanning a new filesystem. */ jcr->acl_data->current_dev = ff_pkt->statp.st_dev; } +#if defined(HAVE_AFS_ACL) + /* + * See if the BACL_FLAG_SAVE_AFS flag is set which lets us know if we should + * save AFS ACLs. + */ + if (jcr->acl_data->flags & BACL_FLAG_SAVE_AFS) { + return afs_build_acl_streams(jcr, ff_pkt); + } +#endif #if defined(HAVE_ACL) /* * See if the BACL_FLAG_SAVE_NATIVE flag is set which lets us know if we should @@ -2161,7 +2266,20 @@ bacl_exit_code parse_acl_streams(JCR *jcr, * Reset the acl save flags. */ jcr->acl_data->flags = 0; + +#if defined(HAVE_AFS_ACL) + /* + * AFS is a non OS specific filesystem so see if this path is on an AFS filesystem + * Set the BACL_FLAG_RESTORE_AFS flag if it is. If not set the BACL_FLAG_RETORE_NATIVE flag. + */ + if (fstype_equals(jcr->last_fname, "afs")) { + jcr->acl_data->flags |= BACL_FLAG_RESTORE_AFS; + } else { + jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE; + } +#else jcr->acl_data->flags |= BACL_FLAG_RESTORE_NATIVE; +#endif /* * Save that we started restoring to a new filesystem. @@ -2170,6 +2288,18 @@ bacl_exit_code parse_acl_streams(JCR *jcr, } switch (stream) { +#if defined(HAVE_AFS_ACL) + case STREAM_ACL_AFS_TEXT: + if (jcr->acl_data->flags & BACL_FLAG_RESTORE_AFS) { + return afs_parse_acl_stream(jcr, stream, content, content_length); + } else { + /* + * Increment error count but don't log an error again for the same filesystem. + */ + jcr->acl_data->u.parse->nr_errors++; + return bacl_exit_ok; + } +#endif #if defined(HAVE_ACL) case STREAM_UNIX_ACCESS_ACL: case STREAM_UNIX_DEFAULT_ACL: -- 2.39.5