[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <152087129979.4129.17793206888283838985.stgit@magnolia>
Date: Mon, 12 Mar 2018 09:14:59 -0700
From: "Darrick J. Wong" <darrick.wong@...cle.com>
To: tytso@....edu, darrick.wong@...cle.com
Cc: linux-ext4@...r.kernel.org
Subject: [PATCH 4/4] e2scrub: add service (cron, systemd) support
From: Darrick J. Wong <darrick.wong@...cle.com>
Add the ability to run the e2scrub utilities as a periodically scheduled
system service.
Signed-off-by: Darrick J. Wong <darrick.wong@...cle.com>
---
MCONFIG.in | 5 +
configure | 179 ++++++++++++++++++++++++++++++++++++++++
configure.ac | 74 ++++++++++++++++-
debian/e2fsprogs.files | 3 +
debian/e2fsprogs.postinst | 19 ++++
debian/e2fsprogs.postrm | 35 ++++++++
scrub/Makefile.in | 90 ++++++++++++++++++++
scrub/e2scrub.in | 38 +++++++-
scrub/e2scrub@...rvice.in | 20 ++++
scrub/e2scrub_all.cron.in | 2
scrub/e2scrub_all.in | 38 ++++++++
scrub/e2scrub_all.service.in | 10 ++
scrub/e2scrub_all.timer.in | 11 ++
scrub/e2scrub_all_cron.in | 68 +++++++++++++++
scrub/e2scrub_fail.in | 25 ++++++
scrub/e2scrub_fail@...rvice.in | 10 ++
scrub/e2scrub_reap.in | 48 +++++++++++
scrub/e2scrub_reap.service.in | 21 +++++
util/subst.conf.in | 3 +
19 files changed, 684 insertions(+), 15 deletions(-)
create mode 100644 debian/e2fsprogs.postrm
create mode 100644 scrub/e2scrub@...rvice.in
create mode 100644 scrub/e2scrub_all.cron.in
create mode 100644 scrub/e2scrub_all.service.in
create mode 100644 scrub/e2scrub_all.timer.in
create mode 100644 scrub/e2scrub_all_cron.in
create mode 100644 scrub/e2scrub_fail.in
create mode 100644 scrub/e2scrub_fail@...rvice.in
create mode 100644 scrub/e2scrub_reap.in
create mode 100644 scrub/e2scrub_reap.service.in
diff --git a/MCONFIG.in b/MCONFIG.in
index adeb5bd..ee83554 100644
--- a/MCONFIG.in
+++ b/MCONFIG.in
@@ -32,9 +32,14 @@ man8dir = $(mandir)/man8
infodir = @infodir@
datadir = @datadir@
pkgconfigdir = $(libdir)/pkgconfig
+pkglibdir = $(libdir)/e2fsprogs
HAVE_UDEV = @have_udev@
UDEV_RULES_DIR = @pkg_udev_rules_dir@
+HAVE_CROND = @have_crond@
+CROND_DIR = @crond_dir@
+HAVE_SYSTEMD = @have_systemd@
+SYSTEMD_SYSTEM_UNIT_DIR = @systemd_system_unit_dir@
@SET_MAKE@
diff --git a/configure b/configure
index 986e057..f6a0dea 100755
--- a/configure
+++ b/configure
@@ -625,6 +625,12 @@ gl_use_threads_default=
ac_func_list=
ac_subst_vars='LTLIBOBJS
LIBOBJS
+systemd_system_unit_dir
+have_systemd
+systemd_LIBS
+systemd_CFLAGS
+crond_dir
+have_crond
pkg_udev_rules_dir
have_udev
udev_LIBS
@@ -899,6 +905,8 @@ with_libintl_prefix
enable_fuse2fs
with_multiarch
with_udev_rules_dir
+with_crond_dir
+with_systemd_unit_dir
'
ac_precious_vars='build_alias
host_alias
@@ -913,7 +921,9 @@ PKG_CONFIG
PKG_CONFIG_PATH
PKG_CONFIG_LIBDIR
udev_CFLAGS
-udev_LIBS'
+udev_LIBS
+systemd_CFLAGS
+systemd_LIBS'
# Initialize some variables set by options.
@@ -1591,6 +1601,9 @@ Optional Packages:
--with-multiarch=ARCH specify the multiarch triplet
--with-udev-rules-dir[=DIR]
Install udev rules into DIR.
+ --with-crond-dir[=DIR] Install system crontabs into DIR.
+ --with-systemd-unit-dir[=DIR]
+ Install systemd system units into DIR.
Some influential environment variables:
CC C compiler command
@@ -1608,6 +1621,10 @@ Some influential environment variables:
path overriding pkg-config's built-in search path
udev_CFLAGS C compiler flags for udev, overriding pkg-config
udev_LIBS linker flags for udev, overriding pkg-config
+ systemd_CFLAGS
+ C compiler flags for systemd, overriding pkg-config
+ systemd_LIBS
+ linker flags for systemd, overriding pkg-config
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@@ -13803,6 +13820,7 @@ else
fi
fi
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can link with -static" >&5
$as_echo_n "checking whether we can link with -static... " >&6; }
if ${ac_cv_e2fsprogs_use_static+:} false; then :
@@ -14009,6 +14027,165 @@ fi
+
+# Check whether --with-crond_dir was given.
+if test "${with_crond_dir+set}" = set; then :
+ withval=$with_crond_dir;
+else
+ with_crond_dir=yes
+fi
+
+if test "x${with_crond_dir}" != "xno"; then :
+
+ if test "x${with_crond_dir}" = "xyes"; then :
+
+ if test -d "/etc/cron.d"; then :
+ with_crond_dir="/etc/cron.d"
+fi
+
+fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for system crontab dir" >&5
+$as_echo_n "checking for system crontab dir... " >&6; }
+ crond_dir="${with_crond_dir}"
+ if test -n "${crond_dir}"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${crond_dir}" >&5
+$as_echo "${crond_dir}" >&6; }
+ have_crond="yes"
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ have_crond="no"
+
+fi
+
+else
+
+ have_crond="disabled"
+
+fi
+
+
+
+
+# Check whether --with-systemd_unit_dir was given.
+if test "${with_systemd_unit_dir+set}" = set; then :
+ withval=$with_systemd_unit_dir;
+else
+ with_systemd_unit_dir=yes
+fi
+
+if test "x${with_systemd_unit_dir}" != "xno"; then :
+
+ if test "x${with_systemd_unit_dir}" = "xyes"; then :
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for systemd" >&5
+$as_echo_n "checking for systemd... " >&6; }
+
+if test -n "$systemd_CFLAGS"; then
+ pkg_cv_systemd_CFLAGS="$systemd_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "systemd") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_systemd_CFLAGS=`$PKG_CONFIG --cflags "systemd" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$systemd_LIBS"; then
+ pkg_cv_systemd_LIBS="$systemd_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"systemd\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "systemd") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_systemd_LIBS=`$PKG_CONFIG --libs "systemd" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ systemd_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "systemd" 2>&1`
+ else
+ systemd_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "systemd" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$systemd_PKG_ERRORS" >&5
+
+
+ with_systemd_unit_dir=""
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+ with_systemd_unit_dir=""
+
+else
+ systemd_CFLAGS=$pkg_cv_systemd_CFLAGS
+ systemd_LIBS=$pkg_cv_systemd_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+ with_systemd_unit_dir="$($PKG_CONFIG --variable=systemdsystemunitdir systemd)"
+
+fi
+
+
+fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for systemd system unit dir" >&5
+$as_echo_n "checking for systemd system unit dir... " >&6; }
+ systemd_system_unit_dir="${with_systemd_unit_dir}"
+ if test -n "${systemd_system_unit_dir}"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${systemd_system_unit_dir}" >&5
+$as_echo "${systemd_system_unit_dir}" >&6; }
+ have_systemd="yes"
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ have_systemd="no"
+
+fi
+
+else
+
+ have_systemd="disabled"
+
+fi
+
+
+
test -d lib || mkdir lib
test -d include || mkdir include
test -d include/linux || mkdir include/linux
diff --git a/configure.ac b/configure.ac
index 6e549c5..5a2c8be 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1392,7 +1392,8 @@ else
libdir=$libdir/$withval
root_libdir=$root_libdir/$withval
fi
-)dnl
+)
+dnl
dnl
dnl See if -static works. This could fail if the linker does not
dnl support -static, or if required external libraries are not available
@@ -1514,6 +1515,77 @@ AC_SUBST(have_udev)
AC_SUBST(pkg_udev_rules_dir)
dnl
+dnl Where do cron jobs go?
+dnl
+AC_ARG_WITH([crond_dir],
+ [AS_HELP_STRING([--with-crond-dir@<:@=DIR@:>@],
+ [Install system crontabs into DIR.])],
+ [],
+ [with_crond_dir=yes])
+AS_IF([test "x${with_crond_dir}" != "xno"],
+ [
+ AS_IF([test "x${with_crond_dir}" = "xyes"],
+ [
+ AS_IF([test -d "/etc/cron.d"],
+ [with_crond_dir="/etc/cron.d"])
+ ])
+ AC_MSG_CHECKING([for system crontab dir])
+ crond_dir="${with_crond_dir}"
+ AS_IF([test -n "${crond_dir}"],
+ [
+ AC_MSG_RESULT(${crond_dir})
+ have_crond="yes"
+ ],
+ [
+ AC_MSG_RESULT(no)
+ have_crond="no"
+ ])
+ ],
+ [
+ have_crond="disabled"
+ ])
+AC_SUBST(have_crond)
+AC_SUBST(crond_dir)
+
+dnl
+dnl Where do systemd services go?
+dnl
+AC_ARG_WITH([systemd_unit_dir],
+ [AS_HELP_STRING([--with-systemd-unit-dir@<:@=DIR@:>@],
+ [Install systemd system units into DIR.])],
+ [],
+ [with_systemd_unit_dir=yes])
+AS_IF([test "x${with_systemd_unit_dir}" != "xno"],
+ [
+ AS_IF([test "x${with_systemd_unit_dir}" = "xyes"],
+ [
+ PKG_CHECK_MODULES([systemd], [systemd],
+ [
+ with_systemd_unit_dir="$($PKG_CONFIG --variable=systemdsystemunitdir systemd)"
+ ], [
+ with_systemd_unit_dir=""
+ ])
+ m4_pattern_allow([^PKG_(MAJOR|MINOR|BUILD|REVISION)$])
+ ])
+ AC_MSG_CHECKING([for systemd system unit dir])
+ systemd_system_unit_dir="${with_systemd_unit_dir}"
+ AS_IF([test -n "${systemd_system_unit_dir}"],
+ [
+ AC_MSG_RESULT(${systemd_system_unit_dir})
+ have_systemd="yes"
+ ],
+ [
+ AC_MSG_RESULT(no)
+ have_systemd="no"
+ ])
+ ],
+ [
+ have_systemd="disabled"
+ ])
+AC_SUBST(have_systemd)
+AC_SUBST(systemd_system_unit_dir)
+
+dnl
dnl Make our output files, being sure that we create the some miscellaneous
dnl directories
dnl
diff --git a/debian/e2fsprogs.files b/debian/e2fsprogs.files
index 78720fe..e0e49ce 100644
--- a/debian/e2fsprogs.files
+++ b/debian/e2fsprogs.files
@@ -1,6 +1,9 @@
sbin
usr/bin
+usr/lib
usr/sbin
usr/share/man
etc
lib/udev/rules.d
+lib/systemd/system
+usr/lib
diff --git a/debian/e2fsprogs.postinst b/debian/e2fsprogs.postinst
index 00ac363..e7acb0e 100644
--- a/debian/e2fsprogs.postinst
+++ b/debian/e2fsprogs.postinst
@@ -10,4 +10,23 @@ fi
#DEBHELPER#
+# debhelper doesn't know what timers are...
+update_svc() {
+ deb-systemd-helper unmask "$1" >/dev/null || true
+
+ if deb-systemd-helper --quiet was-enabled "$1"; then
+ deb-systemd-helper enable "$1" >/dev/null || true
+ else
+ deb-systemd-helper update-state "$1" >/dev/null || true
+ fi
+}
+update_svc e2scrub_all.timer
+update_svc e2scrub_reap.service
+
+# Start our new services
+if [ -d /run/systemd/system ]; then
+ systemctl --system daemon-reload >/dev/null || true
+ deb-systemd-invoke start e2scrub_all.timer >/dev/null || true
+fi
+
exit 0
diff --git a/debian/e2fsprogs.postrm b/debian/e2fsprogs.postrm
new file mode 100644
index 0000000..32cb642
--- /dev/null
+++ b/debian/e2fsprogs.postrm
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+update_svc() {
+ deb-systemd-helper mask "$1" >/dev/null || true
+
+ if deb-systemd-helper --quiet was-enabled "$1"; then
+ # Enables the unit on first installation, creates new
+ # symlinks on upgrades if the unit file has changed.
+ deb-systemd-helper disable "$1" >/dev/null || true
+ fi
+}
+
+if [ "$1" != "upgrade" ]; then
+ # Abort on error.
+ set -e
+
+ if [ -x /usr/sbin/update-initramfs -a \
+ -e /etc/initramfs-tools/initramfs.conf ]; then
+ update-initramfs -u
+ fi
+
+ #DEBHELPER#
+
+ # debhelper doesn't know what timers are...
+ update_svc e2scrub_all.timer
+ update_svc e2scrub_reap.service
+
+ # Start our new services
+ if [ -d /run/systemd/system ]; then
+ deb-systemd-invoke stop e2scrub_all.timer >/dev/null || true
+ fi
+fi
+
+exit 0
+
diff --git a/scrub/Makefile.in b/scrub/Makefile.in
index 1744941..cc2e9ce 100644
--- a/scrub/Makefile.in
+++ b/scrub/Makefile.in
@@ -22,7 +22,23 @@ INSTALL_TGT += install-udev
UNINSTALL_TGT += uninstall-udev
endif
-all:: $(PROGS) $(MANPAGES) $(CONFFILES) $(UDEV_RULES)
+ifeq ($(HAVE_CROND),yes)
+CRONTABS = e2scrub_all.cron
+LIBPROGS += e2scrub_reap e2scrub_all_cron
+INSTALLDIRS_TGT += installdirs-crond installdirs-libprogs
+INSTALL_TGT += install-crond install-libprogs
+UNINSTALL_TGT += uninstall-crond uninstall-libprogs
+endif
+
+ifeq ($(HAVE_SYSTEMD),yes)
+SERVICE_FILES = e2scrub@...rvice e2scrub_all.service e2scrub_all.timer e2scrub_fail@...rvice e2scrub_reap.service
+LIBPROGS += e2scrub_fail e2scrub_reap
+INSTALLDIRS_TGT += installdirs-systemd installdirs-libprogs
+INSTALL_TGT += install-systemd install-libprogs
+UNINSTALL_TGT += uninstall-systemd uninstall-libprogs
+endif
+
+all:: $(PROGS) $(MANPAGES) $(CONFFILES) $(UDEV_RULES) $(SERVICE_FILES) $(CRONTABS) $(LIBPROGS)
e2scrub: $(DEP_SUBSTITUTE) e2scrub.in
$(E) " SUBST $@"
@@ -34,6 +50,21 @@ e2scrub_all: e2scrub_all.in
$(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2scrub_all.in $@
$(Q) chmod a+x $@
+e2scrub_fail: e2scrub_fail.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2scrub_fail.in $@
+ $(Q) chmod a+x $@
+
+e2scrub_reap: e2scrub_reap.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2scrub_reap.in $@
+ $(Q) chmod a+x $@
+
+e2scrub_all_cron: e2scrub_all_cron.in
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $(srcdir)/e2scrub_all_cron.in $@
+ $(Q) chmod a+x $@
+
%.8: %.8.in $(DEP_SUBSTITUTE)
$(E) " SUBST $@"
$(Q) $(SUBSTITUTE_UPTIME) $< $@
@@ -46,10 +77,34 @@ e2scrub_all: e2scrub_all.in
$(E) " SUBST $@"
$(Q) $(SUBSTITUTE_UPTIME) $< $@
+%.service: %.service.in $(DEP_SUBSTITUTE)
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $< $@
+
+%.cron: %.cron.in $(DEP_SUBSTITUTE)
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $< $@
+
+%.timer: %.timer.in $(DEP_SUBSTITUTE)
+ $(E) " SUBST $@"
+ $(Q) $(SUBSTITUTE_UPTIME) $< $@
+
installdirs-udev:
$(E) " MKINSTALLDIRS $(UDEV_RULES_DIR)"
$(Q) $(MKINSTALLDIRS) $(DESTDIR)$(UDEV_RULES_DIR)
+installdirs-crond:
+ $(E) " MKINSTALLDIRS $(CROND_DIR)"
+ $(Q) $(MKINSTALLDIRS) $(DESTDIR)$(CROND_DIR)
+
+installdirs-libprogs:
+ $(E) " MKINSTALLDIRS $(pkglibdir)"
+ $(Q) $(MKINSTALLDIRS) $(DESTDIR)$(pkglibdir)
+
+installdirs-systemd:
+ $(E) " MKINSTALLDIRS $(SYSTEMD_SYSTEM_UNIT_DIR)"
+ $(Q) $(MKINSTALLDIRS) $(DESTDIR)$(SYSTEMD_SYSTEM_UNIT_DIR)
+
installdirs: $(INSTALLDIRS_TGT)
$(E) " MKINSTALLDIRS $(root_sbindir) $(man8dir) $(root_sysconfdir)"
$(Q) $(MKINSTALLDIRS) $(DESTDIR)$(root_sbindir) \
@@ -61,6 +116,24 @@ install-udev:
$(INSTALL_PROGRAM) $$i $(DESTDIR)$(UDEV_RULES_DIR)/96-$$i; \
done
+install-crond:
+ $(Q) for i in $(CRONTABS); do \
+ $(ES) " INSTALL $(CROND_DIR)/$$i"; \
+ $(INSTALL_PROGRAM) $$i $(DESTDIR)$(CROND_DIR)/$$i; \
+ done
+
+install-libprogs: $(LIBPROGS)
+ $(Q) for i in $(LIBPROGS); do \
+ $(ES) " INSTALL $(pkglibdir)/$$i"; \
+ $(INSTALL_PROGRAM) $$i $(DESTDIR)$(pkglibdir)/$$i; \
+ done
+
+install-systemd: $(SERVICE_FILES)
+ $(Q) for i in $(SERVICE_FILES); do \
+ $(ES) " INSTALL_DATA $(SYSTEMD_SYSTEM_UNIT_DIR)/$$i"; \
+ $(INSTALL_DATA) $$i $(DESTDIR)$(SYSTEMD_SYSTEM_UNIT_DIR)/$$i; \
+ done
+
install: $(PROGS) $(MANPAGES) $(FMANPAGES) installdirs $(INSTALL_TGT)
$(Q) for i in $(PROGS); do \
$(ES) " INSTALL $(root_sbindir)/$$i"; \
@@ -83,6 +156,21 @@ uninstall-udev:
$(RM) -f $(DESTDIR)$(UDEV_RULES_DIR)/96-$$i; \
done
+uninstall-crond:
+ for i in $(CRONTABS); do \
+ $(RM) -f $(DESTDIR)$(CROND_DIR)/$$i; \
+ done
+
+uninstall-libprogs:
+ for i in $(LIBPROGS); do \
+ $(RM) -f $(DESTDIR)$(pkglibdir)/$$i; \
+ done
+
+uninstall-systemd:
+ for i in $(SERVICE_FILES); do \
+ $(RM) -f $(DESTDIR)$(SYSTEMD_SYSTEM_UNIT_DIR)/$$i; \
+ done
+
uninstall: $(UNINSTALL_TGT)
for i in $(PROGS); do \
$(RM) -f $(DESTDIR)$(root_sbindir)/$$i; \
diff --git a/scrub/e2scrub.in b/scrub/e2scrub.in
index f77ec6f..a19b6bb 100644
--- a/scrub/e2scrub.in
+++ b/scrub/e2scrub.in
@@ -44,12 +44,34 @@ print_version() {
echo "e2scrub @E2FSPROGS_VERSION@ (@E2FSPROGS_DATE@)"
}
+exitcode() {
+ ret="$1"
+
+ # If we're being run as a service, the return code must fit the LSB
+ # init script action error guidelines, which is to say that we
+ # compress all errors to 1 ("generic or unspecified error", LSB 5.0
+ # section 22.2) and hope the admin will scan the log for what
+ # actually happened.
+
+ # We have to sleep 2 seconds here because journald uses the pid to
+ # connect our log messages to the systemd service. This is critical
+ # for capturing all the log messages if the scrub fails, because the
+ # fail service uses the service name to gather log messages for the
+ # error report.
+ if [ -n "${SERVICE_MODE}" ]; then
+ test "${ret}" -ne 0 && ret=1
+ sleep 2
+ fi
+
+ exit "${ret}"
+}
+
while getopts "rtV" opt; do
case "${opt}" in
"r") reap=1;;
"t") fstrim=1;;
- "V") print_version; exit 0;;
- *) print_help; exit 2;;
+ "V") print_version; exitcode 0;;
+ *) print_help; exitcode 2;;
esac
done
shift "$((OPTIND - 1))"
@@ -57,18 +79,18 @@ shift "$((OPTIND - 1))"
dev="$1"
if [ -z "${dev}" ]; then
print_help
- exit 1
+ exitcode 1
elif [ ! -b "${dev}" ]; then
echo "${dev}: Not a block device?"
print_help
- exit 16
+ exitcode 16
fi
# Make sure this is an LVM device we can snapshot
eval $(lvs --nameprefixes -o name,vgname --noheadings "${dev}")
if [ -z "${LVM2_VG_NAME}" ] || [ -z "${LVM2_LV_NAME}" ]; then
echo "${dev}: Not a LVM device."
- exit 16
+ exitcode 16
fi
start_time="$(date +'%Y%m%d%H%M%S')"
snap="${LVM2_LV_NAME}.e2scrub"
@@ -80,7 +102,7 @@ ext[234])
;;
*)
echo "${dev}: Filesystem of type ${fstype} not supported."
- exit 16
+ exitcode 16
;;
esac
@@ -128,7 +150,7 @@ if [ "${reap}" -gt 0 ]; then
fi
if ! setup; then
echo "Snapshot of ${dev} FAILED, will not check!"
- exit 1
+ exitcode 1
fi
# Check and react
@@ -167,4 +189,4 @@ else
fi
fi
-exit "${ret}"
+exitcode "${ret}"
diff --git a/scrub/e2scrub@...rvice.in b/scrub/e2scrub@...rvice.in
new file mode 100644
index 0000000..496f894
--- /dev/null
+++ b/scrub/e2scrub@...rvice.in
@@ -0,0 +1,20 @@
+[Unit]
+Description=Online ext4 Metadata Check for %I
+OnFailure=e2scrub_fail@...service
+Documentation=man:e2scrub(8)
+
+[Service]
+Type=oneshot
+WorkingDirectory=/
+PrivateNetwork=true
+ProtectSystem=true
+ProtectHome=read-only
+PrivateTmp=yes
+AmbientCapabilities=CAP_SYS_ADMIN CAP_SYS_RAWIO
+NoNewPrivileges=yes
+User=root
+IOSchedulingClass=idle
+CPUSchedulingPolicy=idle
+Environment=SERVICE_MODE=1
+ExecStart=@...t_sbindir@...scrub -t %I
+SyslogIdentifier=%N
diff --git a/scrub/e2scrub_all.cron.in b/scrub/e2scrub_all.cron.in
new file mode 100644
index 0000000..0cb5f1f
--- /dev/null
+++ b/scrub/e2scrub_all.cron.in
@@ -0,0 +1,2 @@
+30 3 * * 0 root test -e /run/systemd/system || @pkglibdir@...scrub_all_cron
+10 3 * * * root test -e /run/systemd/system || @pkglibdir@...scrub_reap
diff --git a/scrub/e2scrub_all.in b/scrub/e2scrub_all.in
index 453981b..fbf2e95 100644
--- a/scrub/e2scrub_all.in
+++ b/scrub/e2scrub_all.in
@@ -30,10 +30,32 @@ print_version() {
echo "e2scrub_all @E2FSPROGS_VERSION@ (@E2FSPROGS_DATE@)"
}
+exitcode() {
+ ret="$1"
+
+ # If we're being run as a service, the return code must fit the LSB
+ # init script action error guidelines, which is to say that we
+ # compress all errors to 1 ("generic or unspecified error", LSB 5.0
+ # section 22.2) and hope the admin will scan the log for what
+ # actually happened.
+
+ # We have to sleep 2 seconds here because journald uses the pid to
+ # connect our log messages to the systemd service. This is critical
+ # for capturing all the log messages if the scrub fails, because the
+ # fail service uses the service name to gather log messages for the
+ # error report.
+ if [ -n "${SERVICE_MODE}" ]; then
+ test "${ret}" -ne 0 && ret=1
+ sleep 2
+ fi
+
+ exit "${ret}"
+}
+
while getopts "V" opt; do
case "${opt}" in
- "V") print_version; exit 0;;
- *) print_help; exit 2;;
+ "V") print_version; exitcode 0;;
+ *) print_help; exitcode 2;;
esac
done
shift "$((OPTIND - 1))"
@@ -49,7 +71,15 @@ lvs -o vg_name,lv_name,lv_role --noheadings 2> /dev/null | while read vg lv role
# Skip non-ext[234]
blkid -p -n "${types}" "${dev}" > /dev/null 2>&1 || continue
- ${DBG} "@root_sbindir@...scrub" "${dev}"
+ if type systemctl > /dev/null 2>&1; then
+ ${DBG} systemctl start "e2scrub@...ev}" 2> /dev/null
+ res=$?
+ if [ "${res}" -ne 0 ] && [ "${res}" -ne 1 ]; then
+ ${DBG} "@root_sbindir@...scrub" "${dev}"
+ fi
+ else
+ ${DBG} "@root_sbindir@...scrub" "${dev}"
+ fi
done
-exit 0
+exitcode 0
diff --git a/scrub/e2scrub_all.service.in b/scrub/e2scrub_all.service.in
new file mode 100644
index 0000000..bc05184
--- /dev/null
+++ b/scrub/e2scrub_all.service.in
@@ -0,0 +1,10 @@
+[Unit]
+Description=Online ext4 Metadata Check for All Filesystems
+ConditionACPower=true
+Documentation=man:e2scrub_all(8)
+
+[Service]
+Type=oneshot
+Environment=SERVICE_MODE=1
+ExecStart=@...t_sbindir@...scrub_all
+SyslogIdentifier=e2scrub_all
diff --git a/scrub/e2scrub_all.timer.in b/scrub/e2scrub_all.timer.in
new file mode 100644
index 0000000..3d558bb
--- /dev/null
+++ b/scrub/e2scrub_all.timer.in
@@ -0,0 +1,11 @@
+[Unit]
+Description=Periodic ext4 Online Metadata Check for All Filesystems
+
+[Timer]
+# Run on Sunday at 3:10am, to avoid running afoul of DST changes
+OnCalendar=Sun *-*-* 03:10:00
+RandomizedDelaySec=60
+Persistent=true
+
+[Install]
+WantedBy=timers.target
diff --git a/scrub/e2scrub_all_cron.in b/scrub/e2scrub_all_cron.in
new file mode 100644
index 0000000..f9cff87
--- /dev/null
+++ b/scrub/e2scrub_all_cron.in
@@ -0,0 +1,68 @@
+#!/bin/bash
+
+# Copyright (C) 2018 Oracle. All Rights Reserved.
+#
+# Author: Darrick J. Wong <darrick.wong@...cle.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it would 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 the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Run e2scrub_all from a cronjob if we don't have systemd and we're not
+# running on AC power.
+
+on_ac_power() {
+ local any_known=no
+
+ # try sysfs power class first
+ if [ -d /sys/class/power_supply ]; then
+ for psu in /sys/class/power_supply/*; do
+ if [ -r "$psu/type" ]; then
+ type=$(cat "$psu/type")
+
+ # ignore batteries
+ [ "$type" = "Battery" ] && continue
+
+ online=$(cat "$psu/online")
+
+ [ "$online" = 1 ] && return 0
+ [ "$online" = 0 ] && any_known=yes
+ fi
+ done
+
+ [ "$any_known" = "yes" ] && return 1
+ fi
+
+ # else fall back to AC adapters in /proc
+ if [ -d /proc/acpi/ac_adapter ]; then
+ for ac in /proc/acpi/ac_adapter/*; do
+ if [ -r "$ac/state" ]; then
+ grep -q on-line "$ac/state" && return 0
+ grep -q off-line "$ac/state" && any_known=yes
+ elif [ -r "$ac/status" ]; then
+ grep -q on-line "$ac/status" && return 0
+ grep -q off-line "$ac/status" && any_known=yes
+ fi
+ done
+
+ [ "$any_known" = "yes" ] && return 1
+ fi
+
+ # Can't tell, just assume we're on AC.
+ return 0
+}
+
+test -e /run/systemd/system && exit 0
+on_ac_power || exit 0
+
+exec @root_sbindir@...scrub_all
diff --git a/scrub/e2scrub_fail.in b/scrub/e2scrub_fail.in
new file mode 100644
index 0000000..f27197a
--- /dev/null
+++ b/scrub/e2scrub_fail.in
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+# Email logs of failed e2scrub unit runs when the systemd service fails.
+
+recipient="$1"
+test -z "${recipient}" && exit 0
+device="$2"
+test -z "${device}" && exit 0
+hostname="$(hostname -f 2>/dev/null)"
+test -z "${hostname}" && hostname="${HOSTNAME}"
+if ! type sendmail > /dev/null 2>&1; then
+ echo "$0: sendmail program not found."
+ exit 1
+fi
+
+(cat << ENDL
+To: $1
+From: <e2scrub@...ostname}>
+Subject: e2scrub failure on ${device}
+
+So sorry, the automatic e2scrub of ${device} on ${hostname} failed.
+
+A log of what happened follows:
+ENDL
+systemctl status --full --lines 4294967295 "e2scrub@...evice}") | sendmail -t -i
diff --git a/scrub/e2scrub_fail@...rvice.in b/scrub/e2scrub_fail@...rvice.in
new file mode 100644
index 0000000..df87949
--- /dev/null
+++ b/scrub/e2scrub_fail@...rvice.in
@@ -0,0 +1,10 @@
+[Unit]
+Description=Online ext4 Metadata Check Failure Reporting for %I
+
+[Service]
+Type=oneshot
+Environment=EMAIL_ADDR=root
+ExecStart=@...libdir@...scrub_fail "${EMAIL_ADDR}" %I
+User=mail
+Group=mail
+SupplementaryGroups=systemd-journal
diff --git a/scrub/e2scrub_reap.in b/scrub/e2scrub_reap.in
new file mode 100644
index 0000000..0fde0e6
--- /dev/null
+++ b/scrub/e2scrub_reap.in
@@ -0,0 +1,48 @@
+#!/bin/bash
+
+# Copyright (C) 2018 Oracle. All Rights Reserved.
+#
+# Author: Darrick J. Wong <darrick.wong@...cle.com>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it would 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 the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Clean up leftover e2scrub snapshots
+
+# Find any ${lvname}.e2scrub snapshot and delete it
+lvs -o vg_name,lv_name,lv_role --noheadings 2> /dev/null | while read vg lv role extra; do
+ # Parse error?
+ test -n "${extra}" || continue
+ # Is this really a snapshot?
+ echo "${role}" | grep -q "snapshot" || continue
+ # An e2scrub snapshot?
+ echo "${lv}" | grep -q ".e2scrub$" || continue
+
+ # Check that the e2scrub snap still exists after waiting a brief period.
+ # This is how try to avoid deleting a snap from underneath a running
+ # scrub.
+ dev="/dev/${vg}/${lv}"
+ test -e "${dev}" || continue
+ sleep 2
+ test -e "${dev}" || continue
+
+ # Remove and wait for removal to succeed.
+ lvremove -f "${vg}/${lv}" 3>&-
+ while [ -e "${dev}" ] && [ "$?" -eq "5" ]; do
+ sleep 0.5
+ lvremove -f "${vg}/${lv}" 3>&-
+ done
+done
+
+exitcode 0
diff --git a/scrub/e2scrub_reap.service.in b/scrub/e2scrub_reap.service.in
new file mode 100644
index 0000000..38eefc4
--- /dev/null
+++ b/scrub/e2scrub_reap.service.in
@@ -0,0 +1,21 @@
+[Unit]
+Description=Remove Stale Online ext4 Metadata Check Snapshots
+
+[Service]
+Type=oneshot
+WorkingDirectory=/
+PrivateNetwork=true
+ProtectSystem=true
+ProtectHome=read-only
+PrivateTmp=yes
+AmbientCapabilities=CAP_SYS_ADMIN CAP_SYS_RAWIO
+NoNewPrivileges=yes
+User=root
+IOSchedulingClass=idle
+CPUSchedulingPolicy=idle
+ExecStart=@...libdir@...scrub_reap
+SyslogIdentifier=%N
+RemainAfterExit=no
+
+[Install]
+WantedBy=default.target
diff --git a/util/subst.conf.in b/util/subst.conf.in
index 6bf658d..0da4554 100644
--- a/util/subst.conf.in
+++ b/util/subst.conf.in
@@ -21,3 +21,6 @@ JDEV
TDB_MAN_COMMENT @TDB_MAN_COMMENT@
root_sbindir @root_sbindir@
root_bindir @root_bindir@
+libdir @libdir@
+$exec_prefix @exec_prefix@
+pkglibdir @libdir@...fsprogs
Powered by blists - more mailing lists