diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile.am | 22 | ||||
-rw-r--r-- | man/binfmt.d.xml | 103 | ||||
-rw-r--r-- | src/binfmt.c | 187 | ||||
-rw-r--r-- | src/util.c | 11 | ||||
-rw-r--r-- | units/.gitignore | 1 | ||||
-rw-r--r-- | units/systemd-binfmt.service.in | 19 |
7 files changed, 340 insertions, 4 deletions
diff --git a/.gitignore b/.gitignore index 7213a8ba99..be44cb60bb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +systemd-binfmt systemd-getty-generator systemd-nspawn systemd-stdio-bridge diff --git a/Makefile.am b/Makefile.am index 7bf32aa832..4fd3e6257c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -144,7 +144,8 @@ rootlibexec_PROGRAMS = \ systemd-timestamp \ systemd-ac-power \ systemd-detect-virt \ - systemd-sysctl + systemd-sysctl \ + systemd-binfmt systemgenerator_PROGRAMS = \ systemd-getty-generator @@ -300,6 +301,7 @@ nodist_systemunit_DATA = \ units/systemd-ask-password-wall.service \ units/systemd-ask-password-console.service \ units/systemd-sysctl.service \ + units/systemd-binfmt.service \ units/halt.service \ units/poweroff.service \ units/reboot.service \ @@ -343,6 +345,7 @@ EXTRA_DIST = \ units/systemd-ask-password-wall.service.in \ units/systemd-ask-password-console.service.in \ units/systemd-sysctl.service.in \ + units/systemd-binfmt.service.in \ units/halt.service.in \ units/poweroff.service.in \ units/reboot.service.in \ @@ -569,7 +572,8 @@ MANPAGES = \ man/vconsole.conf.5 \ man/locale.conf.5 \ man/os-release.5 \ - man/modules-load.d.5 + man/modules-load.d.5 \ + man/binfmt.d.5 MANPAGES_ALIAS = \ man/reboot.8 \ @@ -799,6 +803,15 @@ systemd_sysctl_CFLAGS = \ systemd_sysctl_LDADD = \ libsystemd-basic.la +systemd_binfmt_SOURCES = \ + src/binfmt.c + +systemd_binfmt_CFLAGS = \ + $(AM_CFLAGS) + +systemd_binfmt_LDADD = \ + libsystemd-basic.la + systemd_fsck_SOURCES = \ src/fsck.c \ src/dbus-common.c @@ -1240,9 +1253,10 @@ CLEANFILES += \ install-data-hook: $(MKDIR_P) -m 0755 \ - $(DESTDIR)$(sysconfdir)/modules-load.d \ $(DESTDIR)$(tmpfilesdir) \ + $(DESTDIR)$(sysconfdir)/modules-load.d \ $(DESTDIR)$(sysconfdir)/sysctl.d \ + $(DESTDIR)$(sysconfdir)/binfmt.d \ $(DESTDIR)$(systemshutdowndir) \ $(DESTDIR)$(systemgeneratordir) \ $(DESTDIR)$(usergeneratordir) @@ -1364,6 +1378,7 @@ install-data-hook: systemd-random-seed-load.service \ systemd-tmpfiles-setup.service \ systemd-sysctl.service \ + systemd-binfmt.service \ systemd-ask-password-console.path \ systemd-kmsg-syslogd.service \ cryptsetup.target && \ @@ -1377,6 +1392,7 @@ install-data-hook: $(LN_S) ../systemd-random-seed-load.service systemd-random-seed-load.service && \ $(LN_S) ../systemd-tmpfiles-setup.service systemd-tmpfiles-setup.service && \ $(LN_S) ../systemd-sysctl.service systemd-sysctl.service && \ + $(LN_S) ../systemd-binfmt.service systemd-binfmt.service && \ $(LN_S) ../systemd-ask-password-console.path systemd-ask-password-console.path && \ $(LN_S) ../systemd-kmsg-syslogd.service && \ $(LN_S) ../cryptsetup.target cryptsetup.target ) diff --git a/man/binfmt.d.xml b/man/binfmt.d.xml new file mode 100644 index 0000000000..d2a0d7932c --- /dev/null +++ b/man/binfmt.d.xml @@ -0,0 +1,103 @@ +<?xml version="1.0"?> +<!--*-nxml-*--> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> +<!-- + This file is part of systemd. + + Copyright 2010 Brandon Philips + + systemd 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. + + systemd is distributed in the hope that it will 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 systemd; If not, see <http://www.gnu.org/licenses/>. +--> +<refentry id="binfmt.d"> + + <refentryinfo> + <title>binfmt.d</title> + <productname>systemd</productname> + + <authorgroup> + <author> + <contrib>Developer</contrib> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <email>lennart@poettering.net</email> + </author> + </authorgroup> + </refentryinfo> + + <refmeta> + <refentrytitle>binfmt.d</refentrytitle> + <manvolnum>5</manvolnum> + </refmeta> + + <refnamediv> + <refname>binfmt.d</refname> + <refpurpose>Configure additional binary formats at boot</refpurpose> + </refnamediv> + + <refsynopsisdiv> + <para><filename>/etc/binfmt.d/*.conf</filename></para> + </refsynopsisdiv> + + <refsect1> + <title>Description</title> + + <para><command>systemd</command> uses + <filename>/etc/binfmt.d/</filename> to configure + additional binary formats to register during boot in + the kernel. Each configuration file is named in the + style of + <filename>/etc/binfmt.d/<program>.conf</filename>.</para> + + + </refsect1> + + <refsect1> + <title>Configuration Format</title> + + <para>Each file contains a list of binfmt_misc kernel + binary format rules. Consult <ulink + url="http://www.kernel.org/doc/Documentation/binfmt_misc.txt">binfmt_misc.txt</ulink> + for more information on registration of additional + binary formats and how to write rules.</para> + + <para>Empty lines and lines beginning with ; and # are + ignored. Note that this means you may not use ; and # + as delimiter in binary format rules.</para> + + <para>Configuration files are loaded in alphabetical + order. To ensure that a specific rule takes precedence + over another place it in a file with an alphabetically + later name.</para> + + </refsect1> + + <refsect1> + <title>Example</title> + <example> + <title>/etc/binfmt.d/wine.conf example:</title> + + <programlisting># Start WINE on Windows executables +:DOSWin:M::MZ::/usr/bin/wine:</programlisting> + </example> + </refsect1> + + <refsect1> + <title>See Also</title> + <para> + <citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>, + <citerefentry><refentrytitle>wine</refentrytitle><manvolnum>8</manvolnum></citerefentry> + </para> + </refsect1> + +</refentry> diff --git a/src/binfmt.c b/src/binfmt.c new file mode 100644 index 0000000000..6ebd212ee1 --- /dev/null +++ b/src/binfmt.c @@ -0,0 +1,187 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2010 Lennart Poettering + + systemd 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. + + systemd is distributed in the hope that it will 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 systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdlib.h> +#include <stdbool.h> +#include <errno.h> +#include <string.h> +#include <stdio.h> +#include <limits.h> + +#include "log.h" +#include "util.h" + +static int delete_rule(const char *rule) { + char *x, *fn, *e; + int r; + + assert(rule[0]); + + if (!(x = strdup(rule))) + return -ENOMEM; + + e = strchrnul(x+1, x[0]); + *e = 0; + + asprintf(&fn, "/proc/sys/fs/binfmt_misc/%s", x+1); + free(x); + + if (!fn) + return -ENOMEM; + + r = write_one_line_file(fn, "-1"); + free(fn); + + return r; +} + +static int apply_rule(const char *rule) { + int r; + + delete_rule(rule); + + if ((r = write_one_line_file("/proc/sys/fs/binfmt_misc/register", rule)) < 0) { + log_error("Failed to add binary format: %s", strerror(-r)); + return r; + } + + return 0; +} + +static int apply_file(const char *path, bool ignore_enoent) { + FILE *f; + int r = 0; + + assert(path); + + if (!(f = fopen(path, "re"))) { + if (ignore_enoent && errno == ENOENT) + return 0; + + log_error("Failed to open file '%s', ignoring: %m", path); + return -errno; + } + + while (!feof(f)) { + char l[LINE_MAX], *p; + int k; + + if (!fgets(l, sizeof(l), f)) { + if (feof(f)) + break; + + log_error("Failed to read file '%s', ignoring: %m", path); + r = -errno; + goto finish; + } + + p = strstrip(l); + + if (!*p) + continue; + + if (strchr(COMMENTS, *p)) + continue; + + if ((k = apply_rule(p)) < 0 && r == 0) + r = k; + } + +finish: + fclose(f); + + return r; +} + +static int scandir_filter(const struct dirent *d) { + assert(d); + + if (ignore_file(d->d_name)) + return 0; + + if (d->d_type != DT_REG && + d->d_type != DT_LNK && + d->d_type != DT_UNKNOWN) + return 0; + + return endswith(d->d_name, ".conf"); +} + +static int apply_tree(const char *path) { + struct dirent **de = NULL; + int n, i, r = 0; + + if ((n = scandir(path, &de, scandir_filter, alphasort)) < 0) { + + if (errno == ENOENT) + return 0; + + log_error("Failed to enumerate %s files: %m", path); + return -errno; + } + + for (i = 0; i < n; i++) { + char *fn; + int k; + + k = asprintf(&fn, "%s/%s", path, de[i]->d_name); + free(de[i]); + + if (k < 0) { + log_error("Failed to allocate file name."); + + if (r == 0) + r = -ENOMEM; + continue; + } + + if ((k = apply_file(fn, true)) < 0 && r == 0) + r = k; + } + + free(de); + + return r; +} + +int main(int argc, char *argv[]) { + int r = 0; + + if (argc > 2) { + log_error("This program expects one or no arguments."); + return EXIT_FAILURE; + } + + log_set_target(LOG_TARGET_AUTO); + log_parse_environment(); + log_open(); + + if (argc > 1) + r = apply_file(argv[1], false); + else { + /* Flush out all rules */ + write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1"); + + r = apply_tree("/etc/binfmt.d"); + } + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/src/util.c b/src/util.c index a1686ed389..5daafdf7c2 100644 --- a/src/util.c +++ b/src/util.c @@ -513,7 +513,16 @@ int write_one_line_file(const char *fn, const char *line) { if (!endswith(line, "\n")) fputc('\n', f); - r = 0; + fflush(f); + + if (ferror(f)) { + if (errno != 0) + r = -errno; + else + r = -EIO; + } else + r = 0; + finish: fclose(f); return r; diff --git a/units/.gitignore b/units/.gitignore index 41ab51b2a5..cbf9f255f0 100644 --- a/units/.gitignore +++ b/units/.gitignore @@ -34,3 +34,4 @@ remote-fs.target systemd-update-utmp-runlevel.service systemd-update-utmp-shutdown.service test-env-replace +systemd-binfmt.service diff --git a/units/systemd-binfmt.service.in b/units/systemd-binfmt.service.in new file mode 100644 index 0000000000..0bf6df2011 --- /dev/null +++ b/units/systemd-binfmt.service.in @@ -0,0 +1,19 @@ +# This file is part of systemd. +# +# systemd 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. + +[Unit] +Description=Set Up Additional Binary Formats +DefaultDependencies=no +Conflicts=shutdown.target +After=systemd-readahead-collect.service systemd-readahead-replay.service proc-sys-fs-binfmt_misc.automount +Before=sysinit.target shutdown.target +ConditionDirectoryNotEmpty=/etc/binfmt.d + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=@rootlibexecdir@/systemd-binfmt |