diff options
Diffstat (limited to 'sh')
-rw-r--r-- | sh/.gitignore | 1 | ||||
-rw-r--r-- | sh/Makefile | 6 | ||||
-rw-r--r-- | sh/binfmt.sh.in | 85 |
3 files changed, 89 insertions, 3 deletions
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 <w.d.hubbs@gmail.com> +# 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: |