From ee1768a419122d288256cce1723d4997bd965eab Mon Sep 17 00:00:00 2001 From: William Hubbs Date: Tue, 31 Mar 2015 12:48:45 -0500 Subject: [PATCH] Add binfmt service to sysinit runlevel This makes binfmt processing behave like tmpfiles processing which follows the same specification as systemd. This fixes #48. X-Gentoo-Bug: 545162 X-Gentoo-Bug-URL: https://bugs.gentoo.org/show_bug.cgi?id=545162 --- init.d/Makefile | 2 +- init.d/binfmt.in | 20 +++++++++++ init.d/procfs.in | 13 +------ runlevels/Makefile | 3 +- sh/.gitignore | 1 + sh/Makefile | 6 ++-- sh/binfmt.sh.in | 85 ++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 113 insertions(+), 17 deletions(-) create mode 100644 init.d/binfmt.in create mode 100644 sh/binfmt.sh.in diff --git a/init.d/Makefile b/init.d/Makefile index 85925b15..0bd3651b 100644 --- a/init.d/Makefile +++ b/init.d/Makefile @@ -21,7 +21,7 @@ SRCS-FreeBSD= hostid.in moused.in newsyslog.in pf.in rarpd.in rc-enabled.in \ SRCS-FreeBSD+= adjkerntz.in devd.in dumpon.in encswap.in ipfw.in \ mixer.in nscd.in powerd.in syscons.in -SRCS-Linux= devfs.in dmesg.in hwclock.in consolefont.in keymaps.in \ +SRCS-Linux= binfmt.in devfs.in dmesg.in hwclock.in consolefont.in keymaps.in \ killprocs.in modules.in mount-ro.in mtab.in numlock.in \ procfs.in sysfs.in termencoding.in tmpfiles.dev.in diff --git a/init.d/binfmt.in b/init.d/binfmt.in new file mode 100644 index 00000000..651b1315 --- /dev/null +++ b/init.d/binfmt.in @@ -0,0 +1,20 @@ +#!@SBINDIR@/openrc-run +# Copyright 2015 William Hubbs +# Released under the 2-clause BSD license. + +description="Register misc binary format handlers" + +depend() +{ + after procfs + use modules devfs + keyword -openvz -prefix -vserver -lxc +} + +start() +{ + ebegin "Loading custom binary format handlers" + "$RC_LIBEXECDIR"/sh/binfmt.sh + eend $? +return 0 +} diff --git a/init.d/procfs.in b/init.d/procfs.in index dfe58cb6..167a1aa3 100644 --- a/init.d/procfs.in +++ b/init.d/procfs.in @@ -15,24 +15,13 @@ start() { # Setup Kernel Support for miscellaneous Binary Formats if [ -d /proc/sys/fs/binfmt_misc -a ! -e /proc/sys/fs/binfmt_misc/register ]; then + modprobe -q binfmt-misc if grep -qs binfmt_misc /proc/filesystems; then ebegin "Mounting misc binary format filesystem" mount -t binfmt_misc -o nodev,noexec,nosuid \ binfmt_misc /proc/sys/fs/binfmt_misc - if eend $? ; then - local fmts - ebegin "Loading custom binary format handlers" - fmts=$(grep -hsv -e '^[#;]' -e '^[[:space:]]*$' \ - /run/binfmt.d/*.conf \ - /etc/binfmt.d/*.conf \ - ""/usr/lib/binfmt.d/*.conf) - if [ -n "${fmts}" ]; then - echo "${fmts}" > /proc/sys/fs/binfmt_misc/register - fi eend $? - fi fi fi - return 0 } diff --git a/runlevels/Makefile b/runlevels/Makefile index 25e3e1ab..682d6e15 100644 --- a/runlevels/Makefile +++ b/runlevels/Makefile @@ -34,7 +34,8 @@ BOOT-FreeBSD+= hostid newsyslog savecore syslogd # FreeBSD specific stuff BOOT-FreeBSD+= adjkerntz dumpon syscons -BOOT-Linux+= hwclock keymaps modules mtab procfs termencoding tmpfiles.setup +BOOT-Linux+= binfmt hwclock keymaps modules mtab procfs termencoding \ + tmpfiles.setup SHUTDOWN-Linux= killprocs mount-ro SYSINIT-Linux= devfs dmesg sysfs tmpfiles.dev diff --git a/sh/.gitignore b/sh/.gitignore index d5cb215a..c83b730b 100644 --- a/sh/.gitignore +++ b/sh/.gitignore @@ -8,3 +8,4 @@ init-early.sh rc-cgroup.sh tmpfiles.sh migrate-to-run.sh +binfmt.sh diff --git a/sh/Makefile b/sh/Makefile index c1953f31..8f742dc8 100644 --- a/sh/Makefile +++ b/sh/Makefile @@ -12,9 +12,9 @@ include ${MK}/os.mk SRCS-FreeBSD= BIN-FreeBSD= -SRCS-Linux= cgroup-release-agent.sh.in init-early.sh.in migrate-to-run.sh.in \ - rc-cgroup.sh.in -BIN-Linux= cgroup-release-agent.sh init-early.sh migrate-to-run.sh \ +SRCS-Linux= binfmt.sh.in cgroup-release-agent.sh.in init-early.sh.in \ + migrate-to-run.sh.in rc-cgroup.sh.in +BIN-Linux= binfmt.sh cgroup-release-agent.sh init-early.sh migrate-to-run.sh \ rc-cgroup.sh SRCS-NetBSD= diff --git a/sh/binfmt.sh.in b/sh/binfmt.sh.in new file mode 100644 index 00000000..b636bac7 --- /dev/null +++ b/sh/binfmt.sh.in @@ -0,0 +1,85 @@ +#!@SHELL@ +# This is a reimplementation of the systemd binfmt.d code to register +# misc binary formats with the kernel. +# +# Copyright (c) 2015 William Hubbs +# Released under the 2-clause BSD license. +# +# See the binfmt.d manpage as well: +# http://0pointer.de/public/systemd-man/binfmt.d.html +# This script should match the manpage as of 2015/03/31 +# + +apply_file() { + [ $# -lt 1 ] && return 0 + FILE="$1" + LINENUM=0 + + ### FILE FORMAT ### + # See https://www.kernel.org/doc/Documentation/binfmt_misc.txt + while read line; do + LINENUM=$(( LINENUM+1 )) + case $line in + \#*) continue ;; + \;*) continue ;; + esac + + echo "${line}" > /proc/sys/fs/binfmt_misc/register + rc=$? + if [ $rc -ne 0 ]; then + printf "binfmt: invalid entry on line %d of \`%s'\n" \ + "$LINENUM" "$FILE" >&2 + error=1 + fi + done <$FILE + return $rc +} + +[ -e /proc/sys/fs/binfmt_misc/register ] || exit 0 +error=0 +if [ $# -gt 0 ]; then + while [ $# -gt 0 ]; do + apply_file "$1" + shift + done +else + # The hardcoding of these paths is intentional; we are following the + # systemd spec. + binfmt_dirs='/usr/lib/binfmt.d/ /run/binfmt.d/ /etc/binfmt.d/' + binfmt_basenames='' + binfmt_d='' + + # Build a list of sorted unique basenames + # directories declared later in the binfmt_d list will override earlier + # directories, on a per file basename basis. + # `/run/binfmt.d/foo.conf' supersedes `/usr/lib/binfmt.d/foo.conf'. + # `/run/binfmt.d/foo.conf' will always be read after `/etc/binfmt.d/bar.conf' + for d in ${binfmt_dirs} ; do + [ -d $d ] && for f in ${d}/*.conf ; do + case "${f##*/}" in + systemd.conf|systemd-*.conf) continue;; + esac + [ -e $f ] && binfmt_basenames="${binfmt_basenames}\n${f##*/}" + done # for f in ${d} + done # for d in ${binfmt_dirs} + binfmt_basenames="$(printf "${binfmt_basenames}\n" | sort -u )" + + for b in $binfmt_basenames ; do + real_f='' + for d in $binfmt_dirs ; do + f=${d}/${b} + [ -e "${f}" ] && real_f=$f + done + [ -e "${real_f}" ] && binfmt_d="${binfmt_d} ${real_f}" + done + + # loop through the gathered fragments, sorted globally by filename. + # `/run/binfmt.d/foo.conf' will always be read after `/etc/binfmt.d/bar.conf' + for FILE in $binfmt_d ; do + apply_file "$FILE" + done +fi + +exit $error + +# vim: set ts=2 sw=2 sts=2 noet ft=sh: