lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Thu, 01 Mar 2018 10:23:48 -0800
From:   "Darrick J. Wong" <darrick.wong@...cle.com>
To:     tytso@....edu, darrick.wong@...cle.com
Cc:     djwong@...nel.org, linux-ext4@...r.kernel.org
Subject: [PATCH 3/7] 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              |   85 +++++++++++++++++++
 scrub/e2scrub.in               |   16 ++++
 scrub/e2scrub@...rvice.in      |   20 ++++
 scrub/e2scrub_all.cron.in      |    2 
 scrub/e2scrub_all.in           |   28 ++++++
 scrub/e2scrub_all.service.in   |   10 ++
 scrub/e2scrub_all.timer.in     |   11 ++
 scrub/e2scrub_fail.in          |   26 ++++++
 scrub/e2scrub_fail@...rvice.in |   10 ++
 scrub/e2scrub_reap.in          |   61 ++++++++++++++
 scrub/e2scrub_reap.service.in  |   21 +++++
 util/subst.conf.in             |    3 +
 18 files changed, 604 insertions(+), 4 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_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 4a11fc3..db6e4a0 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
@@ -898,6 +904,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
@@ -912,7 +920,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.
@@ -1590,6 +1600,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
@@ -1607,6 +1620,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.
@@ -13801,6 +13818,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 :
@@ -14007,6 +14025,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 6ffff5d..34935b7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1391,7 +1391,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
@@ -1513,6 +1514,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..2416786 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
+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,16 @@ 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 $@
+
 %.8: %.8.in $(DEP_SUBSTITUTE)
 	$(E) "	SUBST $@"
 	$(Q) $(SUBSTITUTE_UPTIME) $< $@
@@ -46,10 +72,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 +111,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 +151,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 32d11c8..c609530 100644
--- a/scrub/e2scrub.in
+++ b/scrub/e2scrub.in
@@ -40,6 +40,22 @@ print_help() {
 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
+		test -x "${SLEEP_PROG}" && "${SLEEP_PROG}" 2
+	fi
+
 	exit "${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..0c133bd
--- /dev/null
+++ b/scrub/e2scrub_all.cron.in
@@ -0,0 +1,2 @@
+30 3 * * 0 root test -e /run/systemd/system || @root_sbindir@...scrub_all
+10 3 * * * root test -e /run/systemd/system || @libdir@...scrub_reap
diff --git a/scrub/e2scrub_all.in b/scrub/e2scrub_all.in
index ff9eb8f..5da9a42 100644
--- a/scrub/e2scrub_all.in
+++ b/scrub/e2scrub_all.in
@@ -24,6 +24,22 @@ types="ext2,ext3,ext4"
 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
+		test -x "${SLEEP_PROG}" && "${SLEEP_PROG}" 2
+	fi
+
 	exit "${ret}"
 }
 
@@ -39,6 +55,8 @@ prog_path() {
 
 LVS_PROG="$(prog_path "@root_sbindir@...s" "lvs")"
 BLKID_PROG="$(prog_path "@root_sbindir@...kid" "blkid")"
+SYSTEMCTL_PROG="$(prog_path "@root_bindir@...stemctl")"
+SLEEP_PROG="$(prog_path "@root_bindir@...eep")"
 
 # Scrub any fs on lvm by creating a snapshot and fscking that.
 "${LVS_PROG}" -o vg_name,lv_name,lv_role --noheadings 2> /dev/null | while read vg lv role extra; do
@@ -51,7 +69,15 @@ BLKID_PROG="$(prog_path "@root_sbindir@...kid" "blkid")"
 	# Skip non-ext[234]
 	"${BLKID_PROG}" -p -n "${types}" "${dev}" > /dev/null 2>&1 || continue
 
-	${DBG} "@root_sbindir@...scrub" "${dev}"
+	if [ ! -x "${SYSTEMCTL_PROG}" ]; then
+		${DBG} "@root_sbindir@...scrub" "${dev}"
+	else
+		${DBG} "${SYSTEMCTL_PROG}" start "e2scrub@...ev}" 2> /dev/null
+		res=$?
+		if [ "${res}" -ne 0 ] && [ "${res}" -ne 1 ]; then
+			${DBG} "@root_sbindir@...scrub" "${dev}"
+		fi
+	fi
 done
 
 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_fail.in b/scrub/e2scrub_fail.in
new file mode 100644
index 0000000..c1696a0
--- /dev/null
+++ b/scrub/e2scrub_fail.in
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+# Email logs of failed e2scrub unit runs
+
+mailer=/usr/sbin/sendmail
+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 [ ! -x "${mailer}" ]; then
+	echo "${mailer}: Mailer 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}") | "${mailer}" -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..0c9f6c7
--- /dev/null
+++ b/scrub/e2scrub_reap.in
@@ -0,0 +1,61 @@
+#!/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
+
+prog_path() {
+	path="$1"
+	displayname="$2"
+
+	if ! type -P "${path}" && [ -n "${displayname}" ]; then
+		echo "${displayname}: Command not found."
+		exitcode 8
+	fi
+}
+
+LVS_PROG="$(prog_path "@root_sbindir@...s" "lvs")"
+LVREMOVE_PROG="$(prog_path "@root_sbindir@...remove" "lvremove")"
+
+# Find any ${lvname}.e2scrub snapshot and delete it
+"${LVS_PROG}" -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_PROG}" 2
+	test -e "${dev}" || continue
+
+	# Remove and wait for removal to succeed.
+	"${LVREMOVE_PROG}" -f "${vg}/${lv}" 3>&-
+	while [ -e "${dev}" ] && [ "$?" -eq "5" ]; do
+		"${SLEEP_PROG}" 0.5
+		"${LVREMOVE_PROG}" -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 effac78..eae3251 100644
--- a/util/subst.conf.in
+++ b/util/subst.conf.in
@@ -20,3 +20,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

Powered by Openwall GNU/*/Linux Powered by OpenVZ