diff options
author | Tollef Fog Heen <tfheen@err.no> | 2011-09-23 19:27:55 +0200 |
---|---|---|
committer | Tollef Fog Heen <tfheen@err.no> | 2011-09-23 19:27:55 +0200 |
commit | baf8bb13719693fbc4be438dd3c358f2f9d861cd (patch) | |
tree | 7deb946240ba261983a61e1b174db16f5d7a7411 | |
parent | 055bf2bf621b62b6e07af358878c761488a2e6b5 (diff) | |
parent | 7c83341a593160e2b4739bdb8a1ad76b21bbdf9e (diff) | |
download | systemd-baf8bb13719693fbc4be438dd3c358f2f9d861cd.tar.gz |
Merge commit 'v36'
77 files changed, 1314 insertions, 592 deletions
diff --git a/Makefile.am b/Makefile.am index e1d1186887..66a64fd4fa 100644 --- a/Makefile.am +++ b/Makefile.am @@ -20,7 +20,7 @@ ACLOCAL_AMFLAGS = -I m4 SUBDIRS = po LIBSYSTEMD_LOGIN_CURRENT=0 -LIBSYSTEMD_LOGIN_REVISION=4 +LIBSYSTEMD_LOGIN_REVISION=5 LIBSYSTEMD_LOGIN_AGE=0 LIBSYSTEMD_DAEMON_CURRENT=0 @@ -357,14 +357,12 @@ dist_systemunit_DATA = \ units/systemd-stdout-syslog-bridge.socket \ units/systemd-shutdownd.socket \ units/syslog.socket \ - units/dev-hugepages.automount \ units/dev-hugepages.mount \ - units/dev-mqueue.automount \ units/dev-mqueue.mount \ - units/sys-kernel-debug.automount \ + units/sys-kernel-config.mount \ units/sys-kernel-debug.mount \ - units/sys-kernel-security.automount \ units/sys-kernel-security.mount \ + units/sys-fs-fuse-connections.mount \ units/var-run.mount \ units/media.mount \ units/remount-rootfs.service \ @@ -615,6 +613,7 @@ noinst_LTLIBRARIES = \ libsystemd_basic_la_SOURCES = \ src/util.c \ + src/virt.c \ src/label.c \ src/hashmap.c \ src/set.c \ @@ -1838,10 +1837,12 @@ endif rm -f remote-fs.target && \ $(LN_S) $(systemunitdir)/remote-fs.target remote-fs.target ) ( cd $(DESTDIR)$(systemunitdir)/sysinit.target.wants && \ - rm -f dev-hugepages.automount \ - dev-mqueue.automount \ - sys-kernel-debug.automount \ - sys-kernel-security.automount \ + rm -f dev-hugepages.mount \ + dev-mqueue.mount \ + sys-kernel-config.mount \ + sys-kernel-debug.mount \ + sys-kernel-security.mount \ + sys-fs-fuse-connections.mount \ systemd-vconsole-setup.service \ systemd-modules-load.service \ systemd-random-seed-load.service \ @@ -1850,10 +1851,12 @@ endif systemd-ask-password-console.path \ systemd-kmsg-syslogd.service \ cryptsetup.target && \ - $(LN_S) ../dev-hugepages.automount dev-hugepages.automount && \ - $(LN_S) ../dev-mqueue.automount dev-mqueue.automount && \ - $(LN_S) ../sys-kernel-debug.automount sys-kernel-debug.automount && \ - $(LN_S) ../sys-kernel-security.automount sys-kernel-security.automount && \ + $(LN_S) ../dev-hugepages.mount dev-hugepages.mount && \ + $(LN_S) ../dev-mqueue.mount dev-mqueue.mount && \ + $(LN_S) ../sys-kernel-config.mount sys-kernel-config.mount && \ + $(LN_S) ../sys-kernel-debug.mount sys-kernel-debug.mount && \ + $(LN_S) ../sys-kernel-security.mount sys-kernel-security.mount && \ + $(LN_S) ../sys-fs-fuse-connections.mount sys-fs-fuse-connections.mount && \ $(LN_S) ../systemd-vconsole-setup.service systemd-vconsole-setup.service && \ $(LN_S) ../systemd-modules-load.service systemd-modules-load.service && \ $(LN_S) ../systemd-random-seed-load.service systemd-random-seed-load.service && \ @@ -7,18 +7,31 @@ Bugfixes: * make anaconda write timeout=0 for encrypted devices -* fix broken Sockets=syslog-ng.socket packaging - -* logind: ensure ACLs are updated on login and logout - -* fix CUPS .path unit for globbing - * service: pid file reading after reload doesn't work, since we don't reset the pid variable * make sure timeouts are applied to Type=oneshot services. +* Dangling symlinks of .automount unit files in .wants/ directories, set up + automount points even when the original .automount file did not exist + anymore. Only the .mount unit was still around. + Features: +* add an option to make mounts private/shareable and so on, enable this for root by default + +* internal restart counter for units (focus on auto-respawn) + +* finer-grained auto-respawn settings (rate-limit) + +* be able to specify a forced restart of service A where service B depends on, in case B + needs to be auto-respawned? + +* Something is wrong with symlink handling of "autovt@.service" in "systemctl list-unit-files" + +* introduce sd_log_open() to create a connection to the syslog bridge via sd-daemon.h + +* when a bus name of a service disappears from the bus make sure to queue further activation requests + * something like ConditionExec= or ExecStartPre= without failure state * service restart retry configuration @@ -47,8 +60,6 @@ Features: * logind: non-local X11 server handling -* logind: use sysfs path in device hash table instead of sysname, as soon as fb driver is fixed - * implement Register= switch in .socket units to enable registration in Avahi, RPC and other socket registration services. @@ -85,8 +96,6 @@ Features: * GC unreferenced jobs (such as .device jobs) -* avoid DefaultStandardOutput=syslog to have any effect on StandardInput=socket services - * cgroup_notify_empty(): recursively check groups up the tree, too * when failing to start a service due to ratelimiting, try again later, if restart=always is set @@ -100,13 +109,14 @@ Features: - how to pass throw-away units to systemd, or dynamically change properties of existing units - how to integrate cgconfig and suchlike with systemd - security properties + - xinetd conversion + - details of instantiated @.service setups * allow port=0 in .socket units * move readahead files into /var, look for them with .path units * teach dbus to activate all services it finds in /etc/systemd/services/org-*.service -* figure out what happened to bluez patch * support systemd.mask= on the kernel command line. @@ -122,8 +132,6 @@ Features: * maybe introduce ExecRestartPre= -* Patch systemd-fsck to use -C and pass console fd to it - * configurable jitter for timer events * timer events with system resume @@ -143,6 +151,8 @@ Features: * exec settings override * writable cgroups dbus properties for live changes +* read config fragments for all units from /lib/systemd/system/foobar.service.d/ to override/extend specific settings + * port over to LISTEN_FDS/LISTEN_PID: - rpcbind (/var/run/rpcbind.sock!) HAVEPATCH - cups HAVEPATCH diff --git a/configure.ac b/configure.ac index ca07456be6..18dc3fe36a 100644 --- a/configure.ac +++ b/configure.ac @@ -17,7 +17,7 @@ AC_PREREQ(2.63) -AC_INIT([systemd],[35],[systemd-devel@lists.freedesktop.org]) +AC_INIT([systemd],[36],[systemd-devel@lists.freedesktop.org]) AC_CONFIG_SRCDIR([src/main.c]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([config.h]) diff --git a/man/sd-daemon.xml b/man/sd-daemon.xml index cbfe28f842..cd67d9992a 100644 --- a/man/sd-daemon.xml +++ b/man/sd-daemon.xml @@ -52,6 +52,11 @@ <funcsynopsis> <funcsynopsisinfo>#include "sd-daemon.h"</funcsynopsisinfo> </funcsynopsis> + + <cmdsynopsis> + <command>pkg-config --cflags --libs libsystemd-daemon</command> + </cmdsynopsis> + </refsynopsisdiv> <refsect1> @@ -129,17 +134,20 @@ resp. <ulink url="http://cgit.freedesktop.org/systemd/tree/src/sd-daemon.h"/></para> <para>These APIs are implemented in the reference - implementation's drop-in - <filename>sd-daemon.c</filename> and - <filename>sd-daemon.h</filename> files. It is - recommended that applications consuming these APIs copy - the implementation into their source tree, either - verbatim or in excerpts. These interfaces are - currently not available in a dynamic library.</para> + implementation's <filename>sd-daemon.c</filename> and + <filename>sd-daemon.h</filename> files. These + interfaces are available as shared library, which can + be compiled and linked to with the + <literal>libsystemd-daemon</literal> + <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> + file. Alternatively, applications consuming these APIs + may copy the implementation into their source tree, + either verbatim or in excerpts.</para> <para>The functions directly related to new-style daemons become NOPs when -DDISABLE_SYSTEMD is set - during compilation. In addition, if + during compilation and the reference implementation is + used as drop-in files. In addition, if <filename>sd-daemon.c</filename> is compiled on non-Linux systems they become NOPs.</para> </refsect1> @@ -156,7 +164,8 @@ <citerefentry><refentrytitle>systemd.service</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>systemd.socket</refentrytitle><manvolnum>5</manvolnum></citerefentry>, <citerefentry><refentrytitle>fprintf</refentrytitle><manvolnum>3</manvolnum></citerefentry>, - <citerefentry><refentrytitle>sd-readahead</refentrytitle><manvolnum>7</manvolnum></citerefentry> + <citerefentry><refentrytitle>sd-readahead</refentrytitle><manvolnum>7</manvolnum></citerefentry>, + <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> </para> </refsect1> diff --git a/man/sd_booted.xml b/man/sd_booted.xml index 841ee1d479..ebcde36b48 100644 --- a/man/sd_booted.xml +++ b/man/sd_booted.xml @@ -98,17 +98,23 @@ url="http://cgit.freedesktop.org/systemd/tree/src/sd-daemon.h"/></para> <para><function>sd_booted()</function> is implemented - in the reference implementation's drop-in + in the reference implementation's <filename>sd-daemon.c</filename> and - <filename>sd-daemon.h</filename> files. It is - recommended that applications consuming these APIs - copy the implementation into their source tree. For - more details about the reference implementation see - <citerefentry><refentrytitle>sd_daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry></para> - - <para>If -DDISABLE_SYSTEMD is set during compilation - this function will always return 0 and otherwise - become a NOP.</para> + <filename>sd-daemon.h</filename> files. These + interfaces are available as shared library, which can + be compiled and linked to with the + <literal>libsystemd-daemon</literal> + <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> + file. Alternatively, applications consuming these APIs + may copy the implementation into their source + tree. For more details about the reference + implementation see + <citerefentry><refentrytitle>sd_daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para> + + <para>If the reference implementation is used as + drop-in files and -DDISABLE_SYSTEMD is set during + compilation this function will always return 0 and + otherwise become a NOP.</para> </refsect1> <refsect1> diff --git a/man/sd_is_fifo.xml b/man/sd_is_fifo.xml index 251f45ce0f..f6fafabc39 100644 --- a/man/sd_is_fifo.xml +++ b/man/sd_is_fifo.xml @@ -178,7 +178,7 @@ <filename>getsockname()</filename> to check the file descriptor type and where it is bound to.</para> - <para>For details about the algorithm check the + <para>For details about the algorithms check the liberally licensed reference implementation sources: <ulink url="http://cgit.freedesktop.org/systemd/tree/src/sd-daemon.c"/> resp. <ulink @@ -186,13 +186,17 @@ <para><function>sd_is_fifo()</function> and the related functions are implemented in the reference - implementation's drop-in - <filename>sd-daemon.c</filename> and - <filename>sd-daemon.h</filename> files. It is - recommended that applications consuming these APIs - copy the implementation into their source tree. For - more details about the reference implementation see - <citerefentry><refentrytitle>sd_daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry></para> + implementation's <filename>sd-daemon.c</filename> and + <filename>sd-daemon.h</filename> files. These + interfaces are available as shared library, which can + be compiled and linked to with the + <literal>libsystemd-daemon</literal> + <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> + file. Alternatively, applications consuming these APIs + may copy the implementation into their source + tree. For more details about the reference + implementation see + <citerefentry><refentrytitle>sd_daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para> <para>These functions continue to work as described, even if -DDISABLE_SYSTEMD is set during diff --git a/man/sd_listen_fds.xml b/man/sd_listen_fds.xml index 128d859b97..3276aff63d 100644 --- a/man/sd_listen_fds.xml +++ b/man/sd_listen_fds.xml @@ -145,17 +145,23 @@ url="http://cgit.freedesktop.org/systemd/tree/src/sd-daemon.h"/></para> <para><function>sd_listen_fds()</function> is - implemented in the reference implementation's drop-in + implemented in the reference implementation's <filename>sd-daemon.c</filename> and - <filename>sd-daemon.h</filename> files. It is - recommended that applications consuming these APIs - copy the implementation into their source tree. For - more details about the reference implementation see - <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry></para> - - <para>If -DDISABLE_SYSTEMD is set during compilation - this function will always return 0 and otherwise - become a NOP.</para> + <filename>sd-daemon.h</filename> files. These + interfaces are available as shared library, which can + be compiled and linked to with the + <literal>libsystemd-daemon</literal> + <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> + file. Alternatively, applications consuming these APIs + may copy the implementation into their source + tree. For more details about the reference + implementation see + <citerefentry><refentrytitle>sd-daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para> + + <para>If the reference implementation is used as + drop-in files and -DDISABLE_SYSTEMD is set during + compilation this function will always return 0 and + otherwise become a NOP.</para> </refsect1> <refsect1> diff --git a/man/sd_notify.xml b/man/sd_notify.xml index c060bbad27..dd0ba935d6 100644 --- a/man/sd_notify.xml +++ b/man/sd_notify.xml @@ -206,7 +206,7 @@ datagram is accompanied by the process credentials of the sending daemon, using SCM_CREDENTIALS.</para> - <para>For details about the algorithm check the + <para>For details about the algorithms check the liberally licensed reference implementation sources: <ulink url="http://cgit.freedesktop.org/systemd/tree/src/sd-daemon.c"/> resp. <ulink @@ -214,17 +214,22 @@ <para><function>sd_notify()</function> and <function>sd_notifyf()</function> are implemented in - the reference implementation's drop-in + the reference implementation's <filename>sd-daemon.c</filename> and - <filename>sd-daemon.h</filename> files. It is - recommended that applications consuming these APIs - copy the implementation into their source tree. For + <filename>sd-daemon.h</filename> files. These + interfaces are available as shared library, which can + be compiled and linked to with the + <literal>libsystemd-daemon</literal> + <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> + file. Alternatively, applications consuming these APIs + may copy the implementation into their source tree. For more details about the reference implementation see - <citerefentry><refentrytitle>sd_daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry></para> + <citerefentry><refentrytitle>sd_daemon</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para> - <para>If -DDISABLE_SYSTEMD is set during compilation - this function will always return 0 and otherwise - become a NOP.</para> + <para>If the reference implementation is used as + drop-in files and -DDISABLE_SYSTEMD is set during + compilation these functions will always return 0 and + otherwise become a NOP.</para> </refsect1> <refsect1> diff --git a/man/sd_readahead.xml b/man/sd_readahead.xml index 004608dfba..88b135b7ec 100644 --- a/man/sd_readahead.xml +++ b/man/sd_readahead.xml @@ -134,17 +134,23 @@ url="http://cgit.freedesktop.org/systemd/tree/src/sd-readahead.h"/></para> <para><function>sd_readahead()</function> is - implemented in the reference implementation's drop-in + implemented in the reference implementation's <filename>sd-readahead.c</filename> and - <filename>sd-readahead.h</filename> files. It is - recommended that applications consuming this API copy - the implementation into their source tree. For more - details about the reference implementation see - <citerefentry><refentrytitle>sd-readahead</refentrytitle><manvolnum>7</manvolnum></citerefentry></para> - - <para>If -DDISABLE_SYSTEMD is set during compilation - this function will always return 0 and otherwise - become a NOP.</para> + <filename>sd-readahead.h</filename> files. These + interfaces are available as shared library, which can + be compiled and linked to with the + <literal>libsystemd-daemon</literal> + <citerefentry><refentrytitle>pkg-config</refentrytitle><manvolnum>1</manvolnum></citerefentry> + file. Alternatively, applications consuming this API + may copy the implementation into their source + tree. For more details about the reference + implementation see + <citerefentry><refentrytitle>sd-readahead</refentrytitle><manvolnum>7</manvolnum></citerefentry>.</para> + + <para>If the reference implementation is used as + drop-in files and -DDISABLE_SYSTEMD is set during + compilation this function will always return 0 and + otherwise become a NOP.</para> </refsect1> <refsect1> diff --git a/man/systemd.path.xml b/man/systemd.path.xml index f99931ab1e..10d8f73004 100644 --- a/man/systemd.path.xml +++ b/man/systemd.path.xml @@ -154,7 +154,11 @@ activated, then the configured unit is immediately activated as well. Something similar does not apply - to <varname>PathChanged=</varname>. + to + <varname>PathChanged=</varname>. The + latter is not activated on simple + writes but only if files with were + opened for writing are closed. </para></listitem> </varlistentry> <varlistentry> diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml index d38a001366..bf8de322dd 100644 --- a/man/systemd.unit.xml +++ b/man/systemd.unit.xml @@ -180,30 +180,86 @@ and no file by that name is found, systemd will look for <filename>getty@.service</filename> and instantiate a service from that configuration file if - it is found. To refer to the instance string from + it is found.</para> + + <para>To refer to the instance string from within the configuration file you may use the special <literal>%i</literal> specifier in many of the - configuration options. Other specifiers that may be - used are <literal>%n</literal>, <literal>%N</literal>, - <literal>%p</literal>, <literal>%P</literal>, - <literal>%I</literal>, <literal>%f</literal>, - <literal>%c</literal>, <literal>%r</literal>, - <literal>%R</literal> and <literal>%t</literal> for - the full unit name, the unescaped unit name, the - prefix name, the unescaped prefix name, the unescaped - instance name, the unescaped filename, the control - group path of the unit, the root control group path of - systemd, and the parent directory of the root control - cgroup path of systemd and the runtime socket dir, - respectively. The unescaped filename is either the - unescaped instance name (if set) with / prepended (if - necessary), or the prefix name similarly prepended - with /. The prefix name here refers to the string - before the @, i.e. "getty" in the example above, where - "tty3" is the instance name. The runtime socket - directory is either <filename>/run</filename> (for the - system manager) or <literal>$XDG_RUNTIME_DIR</literal> - (for user managers).</para> + configuration options. Other specifiers exist, the + full list is:</para> + + <table> + <title>Specifiers available in unit files</title> + <tgroup cols='3' align='left' colsep='1' rowsep='1'> + <colspec colname="spec" /> + <colspec colname="mean" /> + <colspec colname="detail" /> + <thead> + <row> + <entry>Specifier</entry> + <entry>Meaning</entry> + <entry>Details</entry> + </row> + </thead> + <tbody> + <row> + <entry><literal>%n</literal></entry> + <entry>Full unit name</entry> + <entry></entry> + </row> + <row> + <entry><literal>%N</literal></entry> + <entry>Unescaped full unit name</entry> + <entry></entry> + </row> + <row> + <entry><literal>%p</literal></entry> + <entry>Prefix name</entry> + <entry>This refers to the string before the @, i.e. "getty" in the example above, where "tty3" is the instance name.</entry> + </row> + <row> + <entry><literal>%P</literal></entry> + <entry>Unescaped prefix name</entry> + <entry></entry> + </row> + <row> + <entry><literal>%i</literal></entry> + <entry>Instance name</entry> + <entry>This is the string between the @ character and the suffix.</entry> + </row> + <row> + <entry><literal>%I</literal></entry> + <entry>Unescaped instance name</entry> + <entry></entry> + </row> + <row> + <entry><literal>%f</literal></entry> + <entry>Unescaped file name</entry> + <entry>This is either the unescaped instance name (if set) with / prepended (if necessary), or the prefix name similarly prepended with /.</entry> + </row> + <row> + <entry><literal>%c</literal></entry> + <entry>Control group path of the unit</entry> + <entry></entry> + </row> + <row> + <entry><literal>%r</literal></entry> + <entry>Root control group path of systemd</entry> + <entry></entry> + </row> + <row> + <entry><literal>%R</literal></entry> + <entry>Parent directory of the root control group path of systemd</entry> + <entry></entry> + </row> + <row> + <entry><literal>%t</literal></entry> + <entry>Runtime socket dir</entry> + <entry>This is either /run (for the system manager) or $XDG_RUNTIME_DIR (for user managers).</entry> + </row> + </tbody> + </tgroup> + </table> <para>If a unit file is empty (i.e. has the file size 0) or is symlinked to <filename>/dev/null</filename> @@ -609,6 +665,8 @@ <term><varname>ConditionPathExists=</varname></term> <term><varname>ConditionPathExistsGlob=</varname></term> <term><varname>ConditionPathIsDirectory=</varname></term> + <term><varname>ConditionPathIsSymbolicLink=</varname></term> + <term><varname>ConditionPathIsMountPoint=</varname></term> <term><varname>ConditionDirectoryNotEmpty=</varname></term> <term><varname>ConditionFileIsExecutable=</varname></term> <term><varname>ConditionKernelCommandLine=</varname></term> @@ -623,7 +681,7 @@ a file existence condition can be checked before a unit is started. If the specified absolute path name does - not exist startup of a unit will not + not exist, startup of a unit will not actually happen, however the unit is still useful for ordering purposes in this case. The condition is checked at @@ -633,10 +691,11 @@ <varname>ConditionPathExists=</varname> is prefixed with an exclamation mark (!), the test is negated, and the unit - only started if the path does not - exist. <varname>ConditionPathExistsGlob=</varname> - work in a similar way, but checks for - the existance of at least one file or + is only started if the path does not + exist. + <varname>ConditionPathExistsGlob=</varname> + works in a similar way, but checks for + the existence of at least one file or directory matching the specified globbing pattern. <varname>ConditionPathIsDirectory=</varname> @@ -644,7 +703,17 @@ <varname>ConditionPathExists=</varname> but verifies whether a certain path exists and is a - directory. <varname>ConditionFileIsExecutable=</varname> + directory. <varname>ConditionPathIsSymbolicLink=</varname> + is similar to + <varname>ConditionPathExists=</varname> + but verifies whether a certain path + exists and is a symbolic + link. <varname>ConditionPathIsMountPoint=</varname> + is similar to + <varname>ConditionPathExists=</varname> + but verifies whether a certain path + exists and is a mount + point. <varname>ConditionFileIsExecutable=</varname> is similar to <varname>ConditionPathExists=</varname> but verifies whether a certain path @@ -677,18 +746,28 @@ whether it is a specific implementation. Takes either boolean value to check if being executed in - any virtual environment or one of the + any virtualized environment, or one of + <varname>vm</varname> and + <varname>container</varname> to test against + a specific type of virtualization + solution, or one of <varname>qemu</varname>, <varname>kvm</varname>, <varname>vmware</varname>, <varname>microsoft</varname>, <varname>oracle</varname>, <varname>xen</varname>, - <varname>pidns</varname>, - <varname>openvz</varname> to test - against a specific implementation. The - test may be negated by prepending an - exclamation mark. + <varname>bochs</varname>, + <varname>chroot</varname>, + <varname>openvz</varname>, + <varname>lxc</varname>, + <varname>systemd-nspawn</varname>, + <varname>pidns</varname> to test + against a specific implementation. If + multiple virtualization technologies + are nested only the innermost is + considered. The test may be negated by + prepending an exclamation mark. <varname>ConditionSecurity=</varname> may be used to check whether the given security module is enabled on the @@ -717,7 +796,10 @@ prefix an argument with the pipe symbol and an exclamation mark the pipe symbol must be passed first, the - exclamation second.</para></listitem> + exclamation second. Except for + <varname>ConditionPathIsSymbolicLink=</varname>, + all path checks follow + symlinks.</para></listitem> </varlistentry> <varlistentry> diff --git a/man/systemd.xml b/man/systemd.xml index a11c96e7f1..a8a6967446 100644 --- a/man/systemd.xml +++ b/man/systemd.xml @@ -259,7 +259,7 @@ services and sockets, i.e. controls the default for <option>StandardOutput=</option> - resp. <option>StandardExecute=</option> + resp. <option>StandardError=</option> (see <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details). Takes one of diff --git a/src/99-systemd.rules.in b/src/99-systemd.rules.in index 884a614404..b2481aea9a 100644 --- a/src/99-systemd.rules.in +++ b/src/99-systemd.rules.in @@ -17,6 +17,7 @@ SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}= # Ignore encrypted devices with no identified superblock on it, since # we are probably still calling mke2fs or mkswap on it. + SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0" # We need a hardware independent way to identify network devices. We @@ -41,6 +42,14 @@ SUBSYSTEM=="printer", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" SUBSYSTEM=="usb", KERNEL=="lp*", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="systemd", ENV{SYSTEMD_WANTS}="printer.target" +# Apply sysctl variables to network devices (and only to those) as they appear. + SUBSYSTEM=="net", RUN+="@rootlibexecdir@/systemd-sysctl --prefix=/proc/sys/net/ipv4/conf/$name --prefix=/proc/sys/net/ipv4/neigh/$name --prefix=/proc/sys/net/ipv6/conf/$name --prefix=/proc/sys/net/ipv6/neigh/$name" +# Asynchronously mount file systems implemented by these modules as +# soon as they are loaded. + +SUBSYSTEM=="module", KERNEL=="fuse", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}="sys-fs-fuse-connections.mount" +SUBSYSTEM=="module", KERNEL=="configfs", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}="sys-kernel-config.mount" + LABEL="systemd_end" diff --git a/src/binfmt.c b/src/binfmt.c index 552d8cc227..e8d6524391 100644 --- a/src/binfmt.c +++ b/src/binfmt.c @@ -33,7 +33,7 @@ #include "util.h" static int delete_rule(const char *rule) { - char *x, *fn, *e; + char *x, *fn = NULL, *e; int r; assert(rule[0]); diff --git a/src/condition.c b/src/condition.c index f9202f6850..e978656772 100644 --- a/src/condition.c +++ b/src/condition.c @@ -30,24 +30,28 @@ #include "util.h" #include "condition.h" +#include "virt.h" Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) { Condition *c; assert(type < _CONDITION_TYPE_MAX); - if (!(c = new0(Condition, 1))) + c = new0(Condition, 1); + if (!c) return NULL; c->type = type; c->trigger = trigger; c->negate = negate; - if (parameter) - if (!(c->parameter = strdup(parameter))) { + if (parameter) { + c->parameter = strdup(parameter); + if (!c->parameter) { free(c); return NULL; } + } return c; } @@ -75,10 +79,11 @@ static bool test_kernel_command_line(const char *parameter) { assert(parameter); - if (detect_virtualization(NULL) > 0) + if (detect_container(NULL) > 0) return false; - if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) { + r = read_one_line_file("/proc/cmdline", &line); + if (r < 0) { log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r)); return false; } @@ -89,7 +94,8 @@ static bool test_kernel_command_line(const char *parameter) { FOREACH_WORD_QUOTED(w, l, line, state) { free(word); - if (!(word = strndup(w, l))) + word = strndup(w, l); + if (!word) break; if (equal) { @@ -113,24 +119,35 @@ static bool test_kernel_command_line(const char *parameter) { } static bool test_virtualization(const char *parameter) { - int r, b; + int b; + Virtualization v; const char *id; assert(parameter); - if ((r = detect_virtualization(&id)) < 0) { - log_warning("Failed to detect virtualization, ignoring: %s", strerror(-r)); + v = detect_virtualization(&id); + if (v < 0) { + log_warning("Failed to detect virtualization, ignoring: %s", strerror(-v)); return false; } + /* First, compare with yes/no */ b = parse_boolean(parameter); - if (r > 0 && b > 0) + if (v > 0 && b > 0) + return true; + + if (v == 0 && b == 0) return true; - if (r == 0 && b == 0) + /* Then, compare categorization */ + if (v == VIRTUALIZATION_VM && streq(parameter, "vm")) return true; + if (v == VIRTUALIZATION_CONTAINER && streq(parameter, "container")) + return true; + + /* Finally compare id */ return streq(parameter, id); } @@ -156,11 +173,22 @@ bool condition_test(Condition *c) { case CONDITION_PATH_IS_DIRECTORY: { struct stat st; - if (lstat(c->parameter, &st) < 0) - return !c->negate; + if (stat(c->parameter, &st) < 0) + return c->negate; return S_ISDIR(st.st_mode) == !c->negate; } + case CONDITION_PATH_IS_SYMBOLIC_LINK: { + struct stat st; + + if (lstat(c->parameter, &st) < 0) + return c->negate; + return S_ISLNK(st.st_mode) == !c->negate; + } + + case CONDITION_PATH_IS_MOUNT_POINT: + return (path_is_mount_point(c->parameter, true) > 0) == !c->negate; + case CONDITION_DIRECTORY_NOT_EMPTY: { int k; @@ -171,8 +199,8 @@ bool condition_test(Condition *c) { case CONDITION_FILE_IS_EXECUTABLE: { struct stat st; - if (lstat(c->parameter, &st) < 0) - return !c->negate; + if (stat(c->parameter, &st) < 0) + return c->negate; return (S_ISREG(st.st_mode) && (st.st_mode & 0111)) == !c->negate; } @@ -247,6 +275,8 @@ static const char* const condition_type_table[_CONDITION_TYPE_MAX] = { [CONDITION_PATH_EXISTS] = "ConditionPathExists", [CONDITION_PATH_EXISTS_GLOB] = "ConditionPathExistsGlob", [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory", + [CONDITION_PATH_IS_SYMBOLIC_LINK] = "ConditionPathIsSymbolicLink", + [CONDITION_PATH_IS_MOUNT_POINT] = "ConditionPathIsMountPoint", [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty", [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine", [CONDITION_VIRTUALIZATION] = "ConditionVirtualization", diff --git a/src/condition.h b/src/condition.h index 672996e836..dd65aa6054 100644 --- a/src/condition.h +++ b/src/condition.h @@ -30,6 +30,8 @@ typedef enum ConditionType { CONDITION_PATH_EXISTS, CONDITION_PATH_EXISTS_GLOB, CONDITION_PATH_IS_DIRECTORY, + CONDITION_PATH_IS_SYMBOLIC_LINK, + CONDITION_PATH_IS_MOUNT_POINT, CONDITION_DIRECTORY_NOT_EMPTY, CONDITION_FILE_IS_EXECUTABLE, CONDITION_KERNEL_COMMAND_LINE, diff --git a/src/conf-parser.c b/src/conf-parser.c index 3bb430e375..a71dcd0d8f 100644 --- a/src/conf-parser.c +++ b/src/conf-parser.c @@ -314,7 +314,7 @@ int config_parse( continuation = c; else { continuation = strdup(l); - if (!c) { + if (!continuation) { r = -ENOMEM; goto finish; } diff --git a/src/dbus-common.c b/src/dbus-common.c index 43729f0372..40754e1e0d 100644 --- a/src/dbus-common.c +++ b/src/dbus-common.c @@ -971,3 +971,77 @@ int generic_print_property(const char *name, DBusMessageIter *iter, bool all) { return 0; } + +static void release_name_pending_cb(DBusPendingCall *pending, void *userdata) { + DBusMessage *reply; + DBusConnection *bus = userdata; + + assert_se(reply = dbus_pending_call_steal_reply(pending)); + dbus_message_unref(reply); + + dbus_connection_close(bus); +} + +void bus_async_unregister_and_exit(DBusConnection *bus, const char *name) { + DBusMessage *m = NULL; + DBusPendingCall *pending = NULL; + + assert(bus); + + /* We unregister the name here, but we continue to process + * requests, until we get the response for it, so that all + * requests are guaranteed to be processed. */ + + m = dbus_message_new_method_call( + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "ReleaseName"); + if (!m) + goto oom; + + if (!dbus_message_append_args( + m, + DBUS_TYPE_STRING, + &name, + DBUS_TYPE_INVALID)) + goto oom; + + if (!dbus_connection_send_with_reply(bus, m, &pending, -1)) + goto oom; + + if (!dbus_pending_call_set_notify(pending, release_name_pending_cb, bus, NULL)) + goto oom; + + dbus_message_unref(m); + dbus_pending_call_unref(pending); + + return; + +oom: + log_error("Out of memory"); + + if (pending) { + dbus_pending_call_cancel(pending); + dbus_pending_call_unref(pending); + } + + if (m) + dbus_message_unref(m); +} + +DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata) { + usec_t *remain_until = userdata; + + assert(bus); + assert(m); + assert(remain_until); + + /* Everytime we get a new message we reset out timeout */ + *remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; + + if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) + dbus_connection_close(bus); + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} diff --git a/src/dbus-common.h b/src/dbus-common.h index aab65639c1..acd9208d66 100644 --- a/src/dbus-common.h +++ b/src/dbus-common.h @@ -167,4 +167,8 @@ int bus_iter_get_basic_and_next(DBusMessageIter *iter, int type, void *data, boo int generic_print_property(const char *name, DBusMessageIter *iter, bool all); +void bus_async_unregister_and_exit(DBusConnection *bus, const char *name); + +DBusHandlerResult bus_exit_idle_filter(DBusConnection *bus, DBusMessage *m, void *userdata); + #endif diff --git a/src/dbus-manager.c b/src/dbus-manager.c index 822189b103..7b68156abf 100644 --- a/src/dbus-manager.c +++ b/src/dbus-manager.c @@ -300,7 +300,7 @@ static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, free(p); if (access("/proc/cgroups", F_OK) < 0) - e = stpcpy(e, "cgroups-missing "); + stpcpy(e, "cgroups-missing "); t = strstrip(buf); diff --git a/src/detect-virt.c b/src/detect-virt.c index 57f0176668..79cad5d8ab 100644 --- a/src/detect-virt.c +++ b/src/detect-virt.c @@ -25,16 +25,18 @@ #include <string.h> #include "util.h" +#include "virt.h" int main(int argc, char *argv[]) { - int r; + Virtualization r; const char *id; /* This is mostly intended to be used for scripts which want * to detect whether we are being run in a virtualized * environment or not */ - if ((r = detect_virtualization(&id)) < 0) { + r = detect_virtualization(&id); + if (r < 0) { log_error("Failed to check for virtualization: %s", strerror(-r)); return EXIT_FAILURE; } @@ -42,5 +44,5 @@ int main(int argc, char *argv[]) { if (r > 0) puts(id); - return r == 0; + return r > 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/src/fsck.c b/src/fsck.c index 5d9cf24f4d..c5088ad71c 100644 --- a/src/fsck.c +++ b/src/fsck.c @@ -25,6 +25,7 @@ #include <errno.h> #include <unistd.h> #include <fcntl.h> +#include <sys/file.h> #include <libudev.h> #include <dbus/dbus.h> @@ -33,9 +34,11 @@ #include "dbus-common.h" #include "special.h" #include "bus-errors.h" +#include "virt.h" static bool arg_skip = false; static bool arg_force = false; +static bool arg_show_progress = false; static void start_target(const char *target, bool isolate) { DBusMessage *m = NULL, *reply = NULL; @@ -142,10 +145,103 @@ static void test_files(void) { if (access("/forcefsck", F_OK) >= 0) arg_force = true; + + if (access("/run/systemd/show-status", F_OK) >= 0 || plymouth_running()) + arg_show_progress = true; +} + +static double percent(int pass, unsigned long cur, unsigned long max) { + /* Values stolen from e2fsck */ + + static const int pass_table[] = { + 0, 70, 90, 92, 95, 100 + }; + + if (pass <= 0) + return 0.0; + + if ((unsigned) pass >= ELEMENTSOF(pass_table) || max == 0) + return 100.0; + + return (double) pass_table[pass-1] + + ((double) pass_table[pass] - (double) pass_table[pass-1]) * + (double) cur / (double) max; +} + +static int process_progress(int fd) { + FILE *f, *console; + usec_t last = 0; + bool locked = false; + int clear = 0; + + f = fdopen(fd, "r"); + if (!f) { + close_nointr_nofail(fd); + return -errno; + } + + console = fopen("/dev/console", "w"); + if (!console) { + fclose(f); + return -ENOMEM; + } + + while (!feof(f)) { + int pass, m; + unsigned long cur, max; + char *device; + double p; + usec_t t; + + if (fscanf(f, "%i %lu %lu %ms", &pass, &cur, &max, &device) != 4) + break; + + /* Only show one progress counter at max */ + if (!locked) { + if (flock(fileno(console), LOCK_EX|LOCK_NB) < 0) { + free(device); + continue; + } + + locked = true; + } + + /* Only update once every 50ms */ + t = now(CLOCK_MONOTONIC); + if (last + 50 * USEC_PER_MSEC > t) { + free(device); + continue; + } + + last = t; + + p = percent(pass, cur, max); + fprintf(console, "\r%s: fsck %3.1f%% complete...\r%n", device, p, &m); + fflush(console); + + free(device); + + if (m > clear) + clear = m; + } + + if (clear > 0) { + unsigned j; + + fputc('\r', console); + for (j = 0; j < (unsigned) clear; j++) + fputc(' ', console); + fputc('\r', console); + fflush(console); + } + + fclose(f); + fclose(console); + return 0; } int main(int argc, char *argv[]) { - const char *cmdline[8]; + const char *cmdline[9]; int i = 0, r = EXIT_FAILURE, q; pid_t pid; siginfo_t status; @@ -153,13 +249,15 @@ int main(int argc, char *argv[]) { struct udev_device *udev_device = NULL; const char *device; bool root_directory; + int progress_pipe[2] = { -1, -1 }; + char dash_c[2+10+1]; if (argc > 2) { log_error("This program expects one or no arguments."); return EXIT_FAILURE; } - log_set_target(LOG_TARGET_SYSLOG_OR_KMSG); + log_set_target(LOG_TARGET_AUTO); log_parse_environment(); log_open(); @@ -215,6 +313,12 @@ int main(int argc, char *argv[]) { root_directory = true; } + if (arg_show_progress) + if (pipe(progress_pipe) < 0) { + log_error("pipe(): %m"); + goto finish; + } + cmdline[i++] = "/sbin/fsck"; cmdline[i++] = "-a"; cmdline[i++] = "-T"; @@ -226,19 +330,39 @@ int main(int argc, char *argv[]) { if (arg_force) cmdline[i++] = "-f"; + if (progress_pipe[1] >= 0) { + snprintf(dash_c, sizeof(dash_c), "-C%i", progress_pipe[1]); + char_array_0(dash_c); + cmdline[i++] = dash_c; + } + cmdline[i++] = device; cmdline[i++] = NULL; - if ((pid = fork()) < 0) { + pid = fork(); + if (pid < 0) { log_error("fork(): %m"); goto finish; } else if (pid == 0) { /* Child */ + if (progress_pipe[0] >= 0) + close_nointr_nofail(progress_pipe[0]); execv(cmdline[0], (char**) cmdline); _exit(8); /* Operational error */ } - if ((q = wait_for_terminate(pid, &status)) < 0) { + if (progress_pipe[1] >= 0) { + close_nointr_nofail(progress_pipe[1]); + progress_pipe[1] = -1; + } + + if (progress_pipe[0] >= 0) { + process_progress(progress_pipe[0]); + progress_pipe[0] = -1; + } + + q = wait_for_terminate(pid, &status); + if (q < 0) { log_error("waitid(): %s", strerror(-q)); goto finish; } @@ -276,5 +400,7 @@ finish: if (udev) udev_unref(udev); + close_pipe(progress_pipe); + return r; } diff --git a/src/getty-generator.c b/src/getty-generator.c index d4beffaeff..6b5b254e6a 100644 --- a/src/getty-generator.c +++ b/src/getty-generator.c @@ -26,6 +26,7 @@ #include "log.h" #include "util.h" #include "unit-name.h" +#include "virt.h" const char *arg_dest = "/tmp"; diff --git a/src/hostnamed.c b/src/hostnamed.c index e3b89a4c62..f3b2c94173 100644 --- a/src/hostnamed.c +++ b/src/hostnamed.c @@ -30,6 +30,8 @@ #include "strv.h" #include "dbus-common.h" #include "polkit.h" +#include "def.h" +#include "virt.h" #define INTERFACE \ " <interface name=\"org.freedesktop.hostname1\">\n" \ @@ -85,6 +87,8 @@ static char *data[_PROP_MAX] = { NULL }; +static usec_t remain_until = 0; + static void free_data(void) { int p; @@ -230,7 +234,7 @@ static int write_data_other(void) { assert(name[p]); if (isempty(data[p])) { - l = strv_env_unset(l, name[p]); + strv_env_unset(l, name[p]); continue; } @@ -393,7 +397,7 @@ static DBusHandlerResult hostname_message_handler( return bus_send_error_reply(connection, message, NULL, r); } - log_info("Changed static host name to '%s'", strempty(data[PROP_HOSTNAME])); + log_info("Changed static host name to '%s'", strempty(data[PROP_STATIC_HOSTNAME])); changed = bus_properties_changed_new( "/org/freedesktop/hostname1", @@ -518,7 +522,10 @@ static int connect_bus(DBusConnection **_bus) { goto fail; } - if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL)) { + dbus_connection_set_exit_on_disconnect(bus, FALSE); + + if (!dbus_connection_register_object_path(bus, "/org/freedesktop/hostname1", &hostname_vtable, NULL) || + !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) { log_error("Not enough memory"); r = -ENOMEM; goto fail; @@ -554,6 +561,7 @@ fail: int main(int argc, char *argv[]) { int r; DBusConnection *bus = NULL; + bool exiting = false; log_set_target(LOG_TARGET_AUTO); log_parse_environment(); @@ -588,8 +596,17 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - while (dbus_connection_read_write_dispatch(bus, -1)) - ; + remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; + for (;;) { + + if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))) + break; + + if (!exiting && remain_until < now(CLOCK_MONOTONIC)) { + exiting = true; + bus_async_unregister_and_exit(bus, "org.freedesktop.hostname1"); + } + } r = 0; diff --git a/src/install.c b/src/install.c index 7443973502..cfbd50ead9 100644 --- a/src/install.c +++ b/src/install.c @@ -479,7 +479,6 @@ static int find_symlinks_fd( t = path_make_absolute(name, config_path); if (!t) { free(p); - free(dest); r = -ENOMEM; break; } @@ -1905,7 +1904,7 @@ int unit_file_get_list( } else if (r > 0) { f->state = UNIT_FILE_DISABLED; goto found; - } else if (r == 0) { + } else { f->state = UNIT_FILE_STATIC; goto found; } @@ -544,7 +544,9 @@ int job_finish_and_invalidate(Job *j, JobResult result) { j->type = JOB_START; job_add_to_run_queue(j); - return 0; + + u = j->unit; + goto finish; } j->result = result; @@ -613,6 +615,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) { unit_trigger_on_failure(u); } +finish: /* Try to start the next jobs that can be started */ SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i) if (other->meta.job) diff --git a/src/kmsg-syslogd.c b/src/kmsg-syslogd.c index 83c2047a7a..0901a0e49b 100644 --- a/src/kmsg-syslogd.c +++ b/src/kmsg-syslogd.c @@ -379,7 +379,7 @@ static int process_event(Server *s, struct epoll_event *ev) { return -errno; } - log_debug("Received SIG%s", strna(signal_to_string(sfsi.ssi_signo))); + log_debug("Received SIG%s", signal_to_string(sfsi.ssi_signo)); return 0; } else { diff --git a/src/load-fragment-gperf.gperf.m4 b/src/load-fragment-gperf.gperf.m4 index 08223c5c1b..7749b88dfb 100644 --- a/src/load-fragment-gperf.gperf.m4 +++ b/src/load-fragment-gperf.gperf.m4 @@ -112,6 +112,8 @@ Unit.JobTimeoutSec, config_parse_usec, 0, Unit.ConditionPathExists, config_parse_unit_condition_path, CONDITION_PATH_EXISTS, 0 Unit.ConditionPathExistsGlob, config_parse_unit_condition_path, CONDITION_PATH_EXISTS_GLOB, 0 Unit.ConditionPathIsDirectory, config_parse_unit_condition_path, CONDITION_PATH_IS_DIRECTORY, 0 +Unit.ConditionPathIsSymbolicLink,config_parse_unit_condition_path, CONDITION_PATH_IS_SYMBOLIC_LINK,0 +Unit.ConditionPathIsMountPoint, config_parse_unit_condition_path, CONDITION_PATH_IS_MOUNT_POINT, 0 Unit.ConditionDirectoryNotEmpty, config_parse_unit_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, 0 Unit.ConditionFileIsExecutable, config_parse_unit_condition_path, CONDITION_FILE_IS_EXECUTABLE, 0 Unit.ConditionKernelCommandLine, config_parse_unit_condition_string, CONDITION_KERNEL_COMMAND_LINE, 0 diff --git a/src/load-fragment.c b/src/load-fragment.c index c8b4b5a9c6..12079c640f 100644 --- a/src/load-fragment.c +++ b/src/load-fragment.c @@ -554,6 +554,7 @@ int config_parse_exec( if (!n[0]) { log_error("[%s:%u] Invalid command line, ignoring: %s", filename, line, rvalue); strv_free(n); + free(path); return 0; } @@ -1545,10 +1546,12 @@ int config_parse_unit_condition_path( assert(rvalue); assert(data); - if ((trigger = rvalue[0] == '|')) + trigger = rvalue[0] == '|'; + if (trigger) rvalue++; - if ((negate = rvalue[0] == '!')) + negate = rvalue[0] == '!'; + if (negate) rvalue++; if (!path_is_absolute(rvalue)) { @@ -1556,7 +1559,8 @@ int config_parse_unit_condition_path( return 0; } - if (!(c = condition_new(cond, rvalue, trigger, negate))) + c = condition_new(cond, rvalue, trigger, negate); + if (!c) return -ENOMEM; LIST_PREPEND(Condition, conditions, u->meta.conditions, c); diff --git a/src/locale-setup.c b/src/locale-setup.c index 41eb50bbba..340293619f 100644 --- a/src/locale-setup.c +++ b/src/locale-setup.c @@ -26,6 +26,7 @@ #include "locale-setup.h" #include "util.h" #include "macro.h" +#include "virt.h" enum { /* We don't list LC_ALL here on purpose. People should be diff --git a/src/localed.c b/src/localed.c index d7dcc9e95b..fbb5a41d1a 100644 --- a/src/localed.c +++ b/src/localed.c @@ -29,6 +29,7 @@ #include "strv.h" #include "dbus-common.h" #include "polkit.h" +#include "def.h" #define INTERFACE \ " <interface name=\"org.freedesktop.locale1\">\n" \ @@ -108,6 +109,8 @@ static char *data[_PROP_MAX] = { NULL }; +static usec_t remain_until = 0; + static void free_data(void) { int p; @@ -212,6 +215,7 @@ static int write_data(void) { } if (strv_isempty(l)) { + strv_free(l); if (unlink("/etc/locale.conf") < 0) return errno == ENOENT ? 0 : -errno; @@ -456,6 +460,8 @@ static DBusHandlerResult locale_message_handler( } } + strv_free(l); + for (p = 0; p < _PROP_MAX; p++) { if (passed[p]) continue; @@ -537,7 +543,10 @@ static int connect_bus(DBusConnection **_bus) { goto fail; } - if (!dbus_connection_register_object_path(bus, "/org/freedesktop/locale1", &locale_vtable, NULL)) { + dbus_connection_set_exit_on_disconnect(bus, FALSE); + + if (!dbus_connection_register_object_path(bus, "/org/freedesktop/locale1", &locale_vtable, NULL) || + !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) { log_error("Not enough memory"); r = -ENOMEM; goto fail; @@ -573,6 +582,7 @@ fail: int main(int argc, char *argv[]) { int r; DBusConnection *bus = NULL; + bool exiting = false; log_set_target(LOG_TARGET_AUTO); log_parse_environment(); @@ -604,8 +614,17 @@ int main(int argc, char *argv[]) { if (r < 0) goto finish; - while (dbus_connection_read_write_dispatch(bus, -1)) - ; + remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; + for (;;) { + + if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))) + break; + + if (!exiting && remain_until < now(CLOCK_MONOTONIC)) { + exiting = true; + bus_async_unregister_and_exit(bus, "org.freedesktop.locale1"); + } + } r = 0; diff --git a/src/loginctl.c b/src/loginctl.c index 53058d07a7..89762b66b0 100644 --- a/src/loginctl.c +++ b/src/loginctl.c @@ -64,6 +64,8 @@ static bool on_tty(void) { } static void pager_open_if_enabled(void) { + + /* Cache result before we open the pager */ on_tty(); if (!arg_no_pager) @@ -1061,10 +1063,9 @@ static int show(DBusConnection *bus, char **args, unsigned n) { uid_t uid; uint32_t u; - r = get_user_creds((const char**) (args+i), &uid, NULL, NULL); - if (r < 0) { + ret = get_user_creds((const char**) (args+i), &uid, NULL, NULL); + if (ret < 0) { log_error("User %s unknown.", args[i]); - r = -ENOENT; goto finish; } @@ -1146,7 +1147,7 @@ finish: } static int activate(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int ret = 0; DBusError error; unsigned i; @@ -1157,6 +1158,8 @@ static int activate(DBusConnection *bus, char **args, unsigned n) { dbus_error_init(&error); for (i = 1; i < n; i++) { + DBusMessage *reply; + m = dbus_message_new_method_call( "org.freedesktop.login1", "/org/freedesktop/login1", @@ -1195,16 +1198,13 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return ret; } static int kill_session(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int ret = 0; DBusError error; unsigned i; @@ -1218,6 +1218,8 @@ static int kill_session(DBusConnection *bus, char **args, unsigned n) { arg_kill_who = "all"; for (i = 1; i < n; i++) { + DBusMessage *reply; + m = dbus_message_new_method_call( "org.freedesktop.login1", "/org/freedesktop/login1", @@ -1255,16 +1257,13 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return ret; } static int enable_linger(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int ret = 0; DBusError error; unsigned i; @@ -1278,6 +1277,7 @@ static int enable_linger(DBusConnection *bus, char **args, unsigned n) { b = streq(args[0], "enable-linger"); for (i = 1; i < n; i++) { + DBusMessage *reply; uint32_t u; uid_t uid; @@ -1327,16 +1327,13 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return ret; } static int terminate_user(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int ret = 0; DBusError error; unsigned i; @@ -1349,6 +1346,7 @@ static int terminate_user(DBusConnection *bus, char **args, unsigned n) { for (i = 1; i < n; i++) { uint32_t u; uid_t uid; + DBusMessage *reply; m = dbus_message_new_method_call( "org.freedesktop.login1", @@ -1394,16 +1392,13 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return ret; } static int kill_user(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int ret = 0; DBusError error; unsigned i; @@ -1417,6 +1412,7 @@ static int kill_user(DBusConnection *bus, char **args, unsigned n) { arg_kill_who = "all"; for (i = 1; i < n; i++) { + DBusMessage *reply; uid_t uid; uint32_t u; @@ -1465,16 +1461,13 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return ret; } static int attach(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int ret = 0; DBusError error; unsigned i; @@ -1486,6 +1479,8 @@ static int attach(DBusConnection *bus, char **args, unsigned n) { dbus_error_init(&error); for (i = 2; i < n; i++) { + DBusMessage *reply; + m = dbus_message_new_method_call( "org.freedesktop.login1", "/org/freedesktop/login1", @@ -1523,9 +1518,6 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return ret; @@ -1581,7 +1573,7 @@ finish: } static int terminate_seat(DBusConnection *bus, char **args, unsigned n) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int ret = 0; DBusError error; unsigned i; @@ -1592,6 +1584,8 @@ static int terminate_seat(DBusConnection *bus, char **args, unsigned n) { dbus_error_init(&error); for (i = 1; i < n; i++) { + DBusMessage *reply; + m = dbus_message_new_method_call( "org.freedesktop.login1", "/org/freedesktop/login1", @@ -1627,9 +1621,6 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return ret; diff --git a/src/logind-dbus.c b/src/logind-dbus.c index b8f7d6718b..b33a096f3c 100644 --- a/src/logind-dbus.c +++ b/src/logind-dbus.c @@ -381,6 +381,7 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess session = hashmap_get(m->sessions, id); if (session) { + free(id); fifo_fd = session_create_fifo(session); if (fifo_fd < 0) { @@ -421,6 +422,9 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess close_nointr_nofail(fifo_fd); *_reply = reply; + strv_free(controllers); + strv_free(reset_controllers); + return 0; } diff --git a/src/logind.c b/src/logind.c index 1aad48d2dc..4633a5ef29 100644 --- a/src/logind.c +++ b/src/logind.c @@ -413,6 +413,7 @@ static int manager_enumerate_users_from_cgroup(Manager *m) { int r = 0; char *name; DIR *d; + int k; r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_path, &d); if (r < 0) { @@ -423,9 +424,8 @@ static int manager_enumerate_users_from_cgroup(Manager *m) { return r; } - while ((r = cg_read_subgroup(d, &name)) > 0) { + while ((k = cg_read_subgroup(d, &name)) > 0) { User *user; - int k; k = manager_add_user_by_name(m, name, &user); if (k < 0) { @@ -446,6 +446,9 @@ static int manager_enumerate_users_from_cgroup(Manager *m) { free(name); } + if (r >= 0 && k < 0) + r = k; + closedir(d); return r; diff --git a/src/main.c b/src/main.c index 7af060aa40..5c28a6c191 100644 --- a/src/main.c +++ b/src/main.c @@ -52,6 +52,7 @@ #include "build.h" #include "strv.h" #include "def.h" +#include "virt.h" static enum { ACTION_RUN, @@ -1364,7 +1365,6 @@ int main(int argc, char *argv[]) { } m->confirm_spawn = arg_confirm_spawn; - m->show_status = arg_show_status; #ifdef HAVE_SYSV_COMPAT m->sysv_console = arg_sysv_console; #endif @@ -1379,6 +1379,8 @@ int main(int argc, char *argv[]) { if (arg_default_controllers) manager_set_default_controllers(m, arg_default_controllers); + manager_set_show_status(m, arg_show_status); + before_startup = now(CLOCK_MONOTONIC); if ((r = manager_startup(m, serialization, fds)) < 0) diff --git a/src/manager.c b/src/manager.c index 163f69c22f..e626347dec 100644 --- a/src/manager.c +++ b/src/manager.c @@ -59,6 +59,7 @@ #include "bus-errors.h" #include "exit-status.h" #include "sd-daemon.h" +#include "virt.h" /* As soon as 16 units are in our GC queue, make sure to run a gc sweep */ #define GC_QUEUE_ENTRIES_MAX 16 @@ -2111,11 +2112,11 @@ static int manager_process_signal_fd(Manager *m) { get_process_name(sfsi.ssi_pid, &p); log_debug("Received SIG%s from PID %lu (%s).", - strna(signal_to_string(sfsi.ssi_signo)), + signal_to_string(sfsi.ssi_signo), (unsigned long) sfsi.ssi_pid, strna(p)); free(p); } else - log_debug("Received SIG%s.", strna(signal_to_string(sfsi.ssi_signo))); + log_debug("Received SIG%s.", signal_to_string(sfsi.ssi_signo)); switch (sfsi.ssi_signo) { @@ -2233,8 +2234,9 @@ static int manager_process_signal_fd(Manager *m) { if ((int) sfsi.ssi_signo >= SIGRTMIN+0 && (int) sfsi.ssi_signo < SIGRTMIN+(int) ELEMENTSOF(target_table)) { - manager_start_target(m, target_table[sfsi.ssi_signo - SIGRTMIN], - (sfsi.ssi_signo == 1 || sfsi.ssi_signo == 2) ? JOB_ISOLATE : JOB_REPLACE); + int idx = (int) sfsi.ssi_signo - SIGRTMIN; + manager_start_target(m, target_table[idx], + (idx == 1 || idx == 2) ? JOB_ISOLATE : JOB_REPLACE); break; } @@ -2248,12 +2250,12 @@ static int manager_process_signal_fd(Manager *m) { case 20: log_debug("Enabling showing of status."); - m->show_status = true; + manager_set_show_status(m, true); break; case 21: log_debug("Disabling showing of status."); - m->show_status = false; + manager_set_show_status(m, false); break; case 22: @@ -2282,7 +2284,7 @@ static int manager_process_signal_fd(Manager *m) { break; default: - log_warning("Got unhandled signal <%s>.", strna(signal_to_string(sfsi.ssi_signo))); + log_warning("Got unhandled signal <%s>.", signal_to_string(sfsi.ssi_signo)); } } } @@ -2904,7 +2906,8 @@ bool manager_is_booting_or_shutting_down(Manager *m) { return true; /* Is there a job for the shutdown target? */ - if (((u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET)))) + u = manager_get_unit(m, SPECIAL_SHUTDOWN_TARGET); + if (u) return !!u->meta.job; return false; @@ -3134,6 +3137,35 @@ void manager_recheck_syslog(Manager *m) { log_open(); } +void manager_set_show_status(Manager *m, bool b) { + assert(m); + + if (m->running_as != MANAGER_SYSTEM) + return; + + m->show_status = b; + + if (b) + touch("/run/systemd/show-status"); + else + unlink("/run/systemd/show-status"); +} + +bool manager_get_show_status(Manager *m) { + assert(m); + + if (m->running_as != MANAGER_SYSTEM) + return false; + + if (m->show_status) + return true; + + /* If Plymouth is running make sure we show the status, so + * that there's something nice to see when people press Esc */ + + return plymouth_running(); +} + static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = { [MANAGER_SYSTEM] = "system", [MANAGER_USER] = "user" diff --git a/src/manager.h b/src/manager.h index 22730d2176..5deb5696b7 100644 --- a/src/manager.h +++ b/src/manager.h @@ -290,6 +290,9 @@ void manager_undo_generators(Manager *m); void manager_recheck_syslog(Manager *m); +void manager_set_show_status(Manager *m, bool b); +bool manager_get_show_status(Manager *m); + const char *manager_running_as_to_string(ManagerRunningAs i); ManagerRunningAs manager_running_as_from_string(const char *s); diff --git a/src/modules-load.c b/src/modules-load.c index 4b3b12109c..8dd98f73d8 100644 --- a/src/modules-load.c +++ b/src/modules-load.c @@ -77,7 +77,6 @@ int main(int argc, char *argv[]) { continue; log_error("Failed to open %s: %m", *fn); - free(fn); r = EXIT_FAILURE; continue; } @@ -131,6 +130,7 @@ finish: if (n_arguments > 3) { arguments[n_arguments] = NULL; + strv_uniq(arguments); execv("/sbin/modprobe", arguments); log_error("Failed to execute /sbin/modprobe: %m"); diff --git a/src/mount.c b/src/mount.c index 829c2cc13c..2fc799a6ed 100644 --- a/src/mount.c +++ b/src/mount.c @@ -320,7 +320,10 @@ static bool needs_quota(MountParameters *p) { return false; return mount_test_option(p->options, "usrquota") || - mount_test_option(p->options, "grpquota"); + mount_test_option(p->options, "grpquota") || + mount_test_option(p->options, "quota") || + mount_test_option(p->options, "usrjquota") || + mount_test_option(p->options, "grpjquota"); } static int mount_add_fstab_links(Mount *m) { diff --git a/src/nspawn.c b/src/nspawn.c index 8c3cf6bfaa..8441c057b9 100644 --- a/src/nspawn.c +++ b/src/nspawn.c @@ -197,8 +197,10 @@ static int mount_all(const char *dest) { /* Fix the timezone, if possible */ if (asprintf(&where, "%s/%s", dest, "/etc/localtime") >= 0) { - mount("/etc/localtime", where, "bind", MS_BIND, NULL); - mount("/etc/localtime", where, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL); + + if (mount("/etc/localtime", where, "bind", MS_BIND, NULL) >= 0) + mount("/etc/localtime", where, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL); + free(where); } @@ -725,6 +727,7 @@ int main(int argc, char *argv[]) { gid_t gid = (gid_t) -1; const char *envp[] = { "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "container=systemd-nspawn", /* LXC sets container=lxc, so follow the scheme here */ NULL, /* TERM */ NULL, /* HOME */ NULL, /* USER */ @@ -732,7 +735,7 @@ int main(int argc, char *argv[]) { NULL }; - envp[1] = strv_find_prefix(environ, "TERM="); + envp[2] = strv_find_prefix(environ, "TERM="); close_nointr_nofail(master); @@ -828,9 +831,9 @@ int main(int argc, char *argv[]) { } } - if ((asprintf((char**)(envp + 2), "HOME=%s", home? home: "/root") < 0) || - (asprintf((char**)(envp + 3), "USER=%s", arg_user? arg_user : "root") < 0) || - (asprintf((char**)(envp + 4), "LOGNAME=%s", arg_user? arg_user : "root") < 0)) { + if ((asprintf((char**)(envp + 3), "HOME=%s", home? home: "/root") < 0) || + (asprintf((char**)(envp + 4), "USER=%s", arg_user? arg_user : "root") < 0) || + (asprintf((char**)(envp + 5), "LOGNAME=%s", arg_user? arg_user : "root") < 0)) { log_error("Out of memory"); goto child_fail; } diff --git a/src/path.c b/src/path.c index 1d4aa2174a..f15c9214ef 100644 --- a/src/path.c +++ b/src/path.c @@ -563,7 +563,7 @@ static void path_fd_event(Unit *u, int fd, uint32_t events, Watch *w) { assert(l > 0); if (!(buf = malloc(l))) { - log_error("Failed to allocate buffer: %s", strerror(-ENOMEM)); + log_error("Failed to allocate buffer: %s", strerror(ENOMEM)); goto fail; } diff --git a/src/quotacheck.c b/src/quotacheck.c index c475cecc91..98b59a090a 100644 --- a/src/quotacheck.c +++ b/src/quotacheck.c @@ -26,6 +26,7 @@ #include <unistd.h> #include "util.h" +#include "virt.h" static bool arg_skip = false; static bool arg_force = false; diff --git a/src/readahead-collect.c b/src/readahead-collect.c index df467f1a42..eac11e7e5c 100644 --- a/src/readahead-collect.c +++ b/src/readahead-collect.c @@ -49,6 +49,7 @@ #include "sd-daemon.h" #include "ioprio.h" #include "readahead-common.h" +#include "virt.h" /* fixme: * diff --git a/src/readahead-replay.c b/src/readahead-replay.c index e97a0cfbbf..65011ac4be 100644 --- a/src/readahead-replay.c +++ b/src/readahead-replay.c @@ -41,6 +41,7 @@ #include "sd-daemon.h" #include "ioprio.h" #include "readahead-common.h" +#include "virt.h" static off_t arg_file_size_max = READAHEAD_FILE_SIZE_MAX; diff --git a/src/sd-login.c b/src/sd-login.c index 2489d78c60..a0a56c4952 100644 --- a/src/sd-login.c +++ b/src/sd-login.c @@ -481,33 +481,39 @@ _public_ int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **ui if (uids && t) { char *w, *state; size_t l; - unsigned i = 0; FOREACH_WORD(w, l, t, state) n++; - b = new(uid_t, n); - if (!b) { - strv_free(a); - return -ENOMEM; - } - - FOREACH_WORD(w, l, t, state) { - char *k; + if (n == 0) + b = NULL; + else { + unsigned i = 0; - k = strndup(w, l); - if (!k) { - free(t); - free(b); + b = new(uid_t, n); + if (!b) { + strv_free(a); return -ENOMEM; } - r = parse_uid(k, b + i); - free(k); - if (r < 0) - continue; + FOREACH_WORD(w, l, t, state) { + char *k; + + k = strndup(w, l); + if (!k) { + free(t); + free(b); + strv_free(a); + return -ENOMEM; + } - i++; + r = parse_uid(k, b + i); + free(k); + if (r < 0) + continue; + + i++; + } } } @@ -574,6 +580,9 @@ _public_ int sd_get_uids(uid_t **users) { uid_t *l = NULL; d = opendir("/run/systemd/users/"); + if (!d) + return -errno; + for (;;) { struct dirent buffer, *de; int k; diff --git a/src/selinux-setup.c b/src/selinux-setup.c index 2abd99e6a2..a7e1fa4007 100644 --- a/src/selinux-setup.c +++ b/src/selinux-setup.c @@ -98,11 +98,13 @@ int selinux_setup(bool *loaded_policy) { *loaded_policy = true; } else { + log_open(); + if (enforce > 0) { - log_error("Failed to load SELinux policy."); + log_error("Failed to load SELinux policy. Freezing."); return -EIO; } else - log_debug("Unable to load SELinux policy."); + log_debug("Unable to load SELinux policy. Ignoring."); } #endif diff --git a/src/service.c b/src/service.c index abd8f36bdd..c2053ce3ac 100644 --- a/src/service.c +++ b/src/service.c @@ -121,8 +121,6 @@ static void service_init(Unit *u) { s->guess_main_pid = true; exec_context_init(&s->exec_context); - s->exec_context.std_output = u->meta.manager->default_std_output; - s->exec_context.std_error = u->meta.manager->default_std_error; RATELIMIT_INIT(s->ratelimit, 10*USEC_PER_SEC, 5); @@ -783,19 +781,6 @@ static int service_load_sysv_path(Service *s, const char *path) { free(short_description); short_description = d; - } else if (startswith_no_case(t, "X-Interactive:")) { - int b; - - if ((b = parse_boolean(strstrip(t+14))) < 0) { - log_warning("[%s:%u] Couldn't parse interactive flag. Ignoring.", path, line); - continue; - } - - if (b) - s->exec_context.std_input = EXEC_INPUT_TTY; - else - s->exec_context.std_input = EXEC_INPUT_NULL; - } else if (state == LSB_DESCRIPTION) { if (startswith(l, "#\t") || startswith(l, "# ")) { @@ -845,9 +830,10 @@ static int service_load_sysv_path(Service *s, const char *path) { s->type = SERVICE_FORKING; s->remain_after_exit = !s->pid_file; s->restart = SERVICE_RESTART_NO; - s->exec_context.std_output = - (s->meta.manager->sysv_console || s->exec_context.std_input == EXEC_INPUT_TTY) - ? EXEC_OUTPUT_TTY : s->meta.manager->default_std_output; + + if (s->meta.manager->sysv_console) + s->exec_context.std_output = EXEC_OUTPUT_TTY; + s->exec_context.kill_mode = KILL_PROCESS; /* We use the long description only if @@ -1113,6 +1099,24 @@ static int service_add_default_dependencies(Service *s) { return unit_add_two_dependencies_by_name(UNIT(s), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true); } +static void service_fix_output(Service *s) { + assert(s); + + /* If nothing has been explicitly configured, patch default + * output in. If input is socket/tty we avoid this however, + * since in that case we want output to default to the same + * place as we read input from. */ + + if (s->exec_context.std_error == EXEC_OUTPUT_INHERIT && + s->exec_context.std_output == EXEC_OUTPUT_INHERIT && + s->exec_context.std_input == EXEC_INPUT_NULL) + s->exec_context.std_error = s->meta.manager->default_std_error; + + if (s->exec_context.std_output == EXEC_OUTPUT_INHERIT && + s->exec_context.std_input == EXEC_INPUT_NULL) + s->exec_context.std_output = s->meta.manager->default_std_output; +} + static int service_load(Unit *u) { int r; Service *s = SERVICE(u); @@ -1141,6 +1145,8 @@ static int service_load(Unit *u) { /* This is a new unit? Then let's add in some extras */ if (u->meta.load_state == UNIT_LOADED) { + service_fix_output(s); + if ((r = unit_add_exec_dependencies(u, &s->exec_context)) < 0) return r; @@ -1275,21 +1281,22 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) { free(p2); } -static int service_load_pid_file(Service *s) { +static int service_load_pid_file(Service *s, bool warn_if_missing) { char *k; int r; pid_t pid; assert(s); - if (s->main_pid_known) - return 0; - if (!s->pid_file) - return 0; + return -ENOENT; - if ((r = read_one_line_file(s->pid_file, &k)) < 0) + if ((r = read_one_line_file(s->pid_file, &k)) < 0) { + if (warn_if_missing) + log_warning("Failed to read PID file %s after %s. The service might be broken.", + s->pid_file, service_state_to_string(s->state)); return r; + } r = parse_pid(k, &pid); free(k); @@ -1303,6 +1310,16 @@ static int service_load_pid_file(Service *s) { return -ESRCH; } + if (s->main_pid_known) { + if (pid == s->main_pid) + return 0; + + log_debug("Main PID changing: %lu -> %lu", + (unsigned long) s->main_pid, (unsigned long) pid); + service_unwatch_main_pid(s); + s->main_pid_known = false; + } + if ((r = service_set_main_pid(s, pid)) < 0) return r; @@ -2588,6 +2605,11 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { success = is_clean_exit(code, status); if (s->main_pid == pid) { + /* Forking services may occasionally move to a new PID. + * As long as they update the PID file before exiting the old + * PID, they're fine. */ + if (service_load_pid_file(s, false) == 0) + return; s->main_pid = 0; exec_status_exit(&s->main_exec_status, &s->exec_context, pid, code, status); @@ -2718,7 +2740,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { * START_POST script */ if (success) { - service_load_pid_file(s); + service_load_pid_file(s, !s->exec_command[SERVICE_EXEC_START_POST]); service_search_main_pid(s); service_enter_start_post(s); @@ -2729,7 +2751,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { case SERVICE_START_POST: if (success) { - service_load_pid_file(s); + service_load_pid_file(s, true); service_search_main_pid(s); } @@ -2739,7 +2761,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) { case SERVICE_RELOAD: if (success) { - service_load_pid_file(s); + service_load_pid_file(s, true); service_search_main_pid(s); } @@ -3093,7 +3115,7 @@ static int service_enumerate(Manager *m) { free(fpath); fpath = join(path, "/", de->d_name, NULL); - if (!path) { + if (!fpath) { r = -ENOMEM; goto finish; } diff --git a/src/shutdown.c b/src/shutdown.c index 1c6dc6597b..11213f9d59 100644 --- a/src/shutdown.c +++ b/src/shutdown.c @@ -41,6 +41,7 @@ #include "log.h" #include "umount.h" #include "util.h" +#include "virt.h" #define TIMEOUT_USEC (5 * USEC_PER_SEC) #define FINALIZE_ATTEMPTS 50 diff --git a/src/socket.c b/src/socket.c index 572e622011..7ddf326a22 100644 --- a/src/socket.c +++ b/src/socket.c @@ -844,7 +844,7 @@ static int mq_address_create( fd = mq_open(path, O_RDONLY|O_CLOEXEC|O_NONBLOCK|O_CREAT, mq_mode, attr); umask(old_mask); - if (fd < 0 && errno != EEXIST) { + if (fd < 0) { r = -errno; goto fail; } @@ -1962,6 +1962,12 @@ int socket_collect_fds(Socket *s, int **fds, unsigned *n_fds) { if (p->fd >= 0) rn_fds++; + if (rn_fds <= 0) { + *fds = NULL; + *n_fds = 0; + return 0; + } + if (!(rfds = new(int, rn_fds))) return -ENOMEM; diff --git a/src/stdout-syslog-bridge.c b/src/stdout-syslog-bridge.c index 48a301f6a7..9a0408819e 100644 --- a/src/stdout-syslog-bridge.c +++ b/src/stdout-syslog-bridge.c @@ -88,7 +88,7 @@ struct Stream { bool prefix:1; bool tee_console:1; - char buffer[LINE_MAX]; + char buffer[LINE_MAX+1]; size_t length; LIST_FIELDS(Stream, stream); @@ -111,9 +111,9 @@ static int stream_log(Stream *s, char *p, usec_t ts) { if (*p == 0) return 0; - /* Patch in LOG_USER facility if necessary */ + /* Patch in configured facility if necessary */ if ((priority & LOG_FACMASK) == 0) - priority = LOG_USER | LOG_PRI(priority); + priority = (s->priority & LOG_FACMASK) | priority; /* * The format glibc uses to talk to the syslog daemon is: @@ -321,16 +321,25 @@ static int stream_scan(Stream *s, usec_t ts) { p = s->buffer; remaining = s->length; for (;;) { - char *newline; - - if (!(newline = memchr(p, '\n', remaining))) - break; + char *end; + size_t skip; + + end = memchr(p, '\n', remaining); + if (!end) { + if (remaining >= LINE_MAX) { + end = p + LINE_MAX; + skip = LINE_MAX; + } else + break; + } else + skip = end - p + 1; - *newline = 0; + *end = 0; - if ((r = stream_line(s, p, ts)) >= 0) { - remaining -= newline-p+1; - p = newline+1; + r = stream_line(s, p, ts); + if (r >= 0) { + remaining -= skip; + p += skip; } } @@ -347,7 +356,8 @@ static int stream_process(Stream *s, usec_t ts) { int r; assert(s); - if ((l = read(s->fd, s->buffer+s->length, LINE_MAX-s->length)) < 0) { + l = read(s->fd, s->buffer+s->length, LINE_MAX-s->length); + if (l < 0) { if (errno == EAGAIN) return 0; diff --git a/src/strv.c b/src/strv.c index 92851b2233..bb309d9f92 100644 --- a/src/strv.c +++ b/src/strv.c @@ -67,7 +67,8 @@ void strv_free(char **l) { char **strv_copy(char **l) { char **r, **k; - if (!(k = r = new(char*, strv_length(l)+1))) + k = r = new(char*, strv_length(l)+1); + if (!k) return NULL; if (l) @@ -198,15 +199,23 @@ char **strv_merge_concat(char **a, char **b, const char *suffix) { if (!b) return strv_copy(a); - if (!(r = new(char*, strv_length(a)+strv_length(b)+1))) + r = new(char*, strv_length(a) + strv_length(b) + 1); + if (!r) return NULL; - for (k = r; *a; k++, a++) - if (!(*k = strdup(*a))) - goto fail; - for (; *b; k++, b++) - if (!(*k = strappend(*b, suffix))) + k = r; + if (a) + for (; *a; k++, a++) { + *k = strdup(*a); + if (!*k) + goto fail; + } + + for (; *b; k++, b++) { + *k = strappend(*b, suffix); + if (!*k) goto fail; + } *k = NULL; return r; @@ -317,7 +326,8 @@ char **strv_append(char **l, const char *s) { if (!s) return strv_copy(l); - if (!(r = new(char*, strv_length(l)+2))) + r = new(char*, strv_length(l)+2); + if (!r) return NULL; for (k = r; *l; k++, l++) diff --git a/src/sysfs-show.c b/src/sysfs-show.c index ab866a4707..b8b356d77b 100644 --- a/src/sysfs-show.c +++ b/src/sysfs-show.c @@ -165,6 +165,9 @@ int show_sysfs(const char *seat, const char *prefix, unsigned n_columns) { else r = udev_enumerate_add_match_tag(e, "seat"); + if (r < 0) + goto finish; + r = udev_enumerate_scan_devices(e); if (r < 0) goto finish; diff --git a/src/systemctl.c b/src/systemctl.c index 7caeb6dd91..2bf2b697e2 100644 --- a/src/systemctl.c +++ b/src/systemctl.c @@ -137,6 +137,8 @@ static bool on_tty(void) { } static void pager_open_if_enabled(void) { + + /* Cache result before we open the pager */ on_tty(); if (arg_no_pager) @@ -608,6 +610,7 @@ static int list_unit_files(DBusConnection *bus, char **args) { r = unit_file_get_list(arg_scope, arg_root, h); if (r < 0) { + unit_file_list_free(h); log_error("Failed to get unit file list: %s", strerror(-r)); return r; } @@ -1054,7 +1057,7 @@ finish: } static int load_unit(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; DBusError error; int r; char **name; @@ -1065,6 +1068,7 @@ static int load_unit(DBusConnection *bus, char **args) { assert(args); STRV_FOREACH(name, args+1) { + DBusMessage *reply; if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", @@ -1102,9 +1106,6 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return r; @@ -1794,7 +1795,7 @@ finish: } static int kill_unit(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int r = 0; DBusError error; char **name; @@ -1811,6 +1812,7 @@ static int kill_unit(DBusConnection *bus, char **args) { arg_kill_mode = streq(arg_kill_who, "all") ? "control-group" : "process"; STRV_FOREACH(name, args+1) { + DBusMessage *reply; if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", @@ -1850,9 +1852,6 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return r; @@ -2155,8 +2154,6 @@ static void print_status_info(UnitStatusInfo *i) { printf(")%s\n", off); - on = off = NULL; - if (i->main_pid == p->pid && i->start_timestamp == p->start_timestamp && i->exit_timestamp == p->start_timestamp) @@ -3230,7 +3227,7 @@ finish: } static int reset_failed(DBusConnection *bus, char **args) { - DBusMessage *m = NULL, *reply = NULL; + DBusMessage *m = NULL; int r; DBusError error; char **name; @@ -3242,6 +3239,7 @@ static int reset_failed(DBusConnection *bus, char **args) { return daemon_reload(bus, args); STRV_FOREACH(name, args+1) { + DBusMessage *reply; if (!(m = dbus_message_new_method_call( "org.freedesktop.systemd1", @@ -3278,9 +3276,6 @@ finish: if (m) dbus_message_unref(m); - if (reply) - dbus_message_unref(reply); - dbus_error_free(&error); return r; diff --git a/src/systemd-analyze b/src/systemd-analyze index ae7dcfbd8a..ac6404099e 100755 --- a/src/systemd-analyze +++ b/src/systemd-analyze @@ -147,7 +147,7 @@ elif sys.argv[1] == 'plot': context.set_line_width(1) context.set_source_rgb(0.7, 0.7, 0.7) - for x in range(0, (finish_time - start_time)/10000, 100): + for x in range(0, max((finish_time - start_time)/10000,110), 100): context.move_to(x, 0) context.line_to(x, height-border*2) @@ -163,7 +163,7 @@ elif sys.argv[1] == 'plot': banner = "Running on %s (%s %s) %s" % (os.uname()[1], os.uname()[2], os.uname()[3], os.uname()[4]) draw_text(context, 0, -15, banner, hcenter = 0, vcenter = 1) - for x in range(0, (finish_time - start_time)/10000, 100): + for x in range(0, max((finish_time - start_time)/10000,110), 100): draw_text(context, x, -5, "%lus" % (x/100), vcenter = 0, hcenter = 0) y = 0 @@ -221,6 +221,18 @@ elif sys.argv[1] == 'plot': draw_text(context, 0, height-border*2, "Legend: Red = Activating; Pink = Active; Dark Pink = Deactivating", hcenter = 0, vcenter = -1) + if initrd_time > 0: + draw_text(context, 0, height-border*2 + bar_height, "Startup finished in %lums (kernel) + %lums (initrd) + %lums (userspace) = %lums" % ( \ + initrd_time/1000, \ + (start_time - initrd_time)/1000, \ + (finish_time - start_time)/1000, \ + finish_time/1000), hcenter = 0, vcenter = -1) + else: + draw_text(context, 0, height-border*2 + bar_height, "Startup finished in %lums (kernel) + %lums (userspace) = %lums" % ( \ + start_time/1000, \ + (finish_time - start_time)/1000, \ + finish_time/1000), hcenter = 0, vcenter = -1) + surface.finish() elif sys.argv[1] in ("help", "--help", "-h"): help() diff --git a/src/timedated.c b/src/timedated.c index 734538882f..f6fe2d83b6 100644 --- a/src/timedated.c +++ b/src/timedated.c @@ -29,6 +29,7 @@ #include "strv.h" #include "dbus-common.h" #include "polkit.h" +#include "def.h" #define NULL_ADJTIME_UTC "0.0 0 0\n0\nUTC\n" #define NULL_ADJTIME_LOCAL "0.0 0 0\n0\nLOCAL\n" @@ -69,7 +70,7 @@ #define INTERFACES_LIST \ BUS_GENERIC_INTERFACES_LIST \ - "org.freedesktop.locale1\0" + "org.freedesktop.timedate1\0" const char timedate_interface[] _introspect_("timedate1") = INTERFACE; @@ -77,6 +78,8 @@ static char *zone = NULL; static bool local_rtc = false; static int use_ntp = -1; +static usec_t remain_until = 0; + static void free_data(void) { free(zone); zone = NULL; @@ -243,7 +246,7 @@ static int write_data_local_rtc(void) { p++; e = strchr(p, '\n'); - if (!p) { + if (!e) { free(s); return -EIO; } @@ -788,7 +791,10 @@ static int connect_bus(DBusConnection **_bus) { goto fail; } - if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL)) { + dbus_connection_set_exit_on_disconnect(bus, FALSE); + + if (!dbus_connection_register_object_path(bus, "/org/freedesktop/timedate1", &timedate_vtable, NULL) || + !dbus_connection_add_filter(bus, bus_exit_idle_filter, &remain_until, NULL)) { log_error("Not enough memory"); r = -ENOMEM; goto fail; @@ -824,6 +830,7 @@ fail: int main(int argc, char *argv[]) { int r; DBusConnection *bus = NULL; + bool exiting = false; log_set_target(LOG_TARGET_AUTO); log_parse_environment(); @@ -861,8 +868,17 @@ int main(int argc, char *argv[]) { goto finish; } - while (dbus_connection_read_write_dispatch(bus, -1)) - ; + remain_until = now(CLOCK_MONOTONIC) + DEFAULT_EXIT_USEC; + for (;;) { + + if (!dbus_connection_read_write_dispatch(bus, exiting ? -1 : (int) (DEFAULT_EXIT_USEC/USEC_PER_MSEC))) + break; + + if (!exiting && remain_until < now(CLOCK_MONOTONIC)) { + exiting = true; + bus_async_unregister_and_exit(bus, "org.freedesktop.hostname1"); + } + } r = 0; diff --git a/src/umount.c b/src/umount.c index 67be42ea33..4e036d82a3 100644 --- a/src/umount.c +++ b/src/umount.c @@ -565,10 +565,13 @@ int umount_all(bool *changed) { /* retry umount, until nothing can be umounted anymore */ do { umount_changed = false; - r = mount_points_list_umount(&mp_list_head, &umount_changed, false); + + mount_points_list_umount(&mp_list_head, &umount_changed, false); if (umount_changed) *changed = true; - } while(umount_changed); + + } while (umount_changed); + /* umount one more time with logging enabled */ r = mount_points_list_umount(&mp_list_head, &umount_changed, true); if (r <= 0) diff --git a/src/unit.c b/src/unit.c index 031e61993d..903a8e4da4 100644 --- a/src/unit.c +++ b/src/unit.c @@ -774,7 +774,7 @@ int unit_add_default_target_dependency(Unit *u, Unit *target) { /* If either side wants no automatic dependencies, then let's * skip this */ if (!u->meta.default_dependencies || - target->meta.default_dependencies) + !target->meta.default_dependencies) return 0; /* Don't create loops */ @@ -888,16 +888,20 @@ int unit_start(Unit *u) { if (u->meta.load_state != UNIT_LOADED) return -EINVAL; - /* If this is already (being) started, then this will - * succeed. Note that this will even succeed if this unit is - * not startable by the user. This is relied on to detect when - * we need to wait for units and when waiting is finished. */ + /* If this is already started, then this will succeed. Note + * that this will even succeed if this unit is not startable + * by the user. This is relied on to detect when we need to + * wait for units and when waiting is finished. */ state = unit_active_state(u); if (UNIT_IS_ACTIVE_OR_RELOADING(state)) return -EALREADY; - /* If the conditions failed, don't do anything at all */ - if (!unit_condition_test(u)) { + /* If the conditions failed, don't do anything at all. If we + * already are activating this call might still be useful to + * speed up activation in case there is some hold-off time, + * but we don't want to recheck the condition in that case. */ + if (state != UNIT_ACTIVATING && + !unit_condition_test(u)) { log_debug("Starting of %s requested but condition failed. Ignoring.", u->meta.id); return -EALREADY; } @@ -2431,13 +2435,7 @@ void unit_status_printf(Unit *u, const char *format, ...) { if (!UNIT_VTABLE(u)->show_status) return; - if (u->meta.manager->running_as != MANAGER_SYSTEM) - return; - - /* If Plymouth is running make sure we show the status, so - * that there's something nice to see when people press Esc */ - - if (!u->meta.manager->show_status && !plymouth_running()) + if (!manager_get_show_status(u->meta.manager)) return; if (!manager_is_booting_or_shutting_down(u->meta.manager)) diff --git a/src/util.c b/src/util.c index 6033aa05b2..425a732344 100644 --- a/src/util.c +++ b/src/util.c @@ -782,13 +782,7 @@ int read_full_file(const char *fn, char **contents, size_t *size) { } } - if (buf) - buf[l] = 0; - else if (!(buf = calloc(1, 1))) { - r = -errno; - goto finish; - } - + buf[l] = 0; *contents = buf; buf = NULL; @@ -4273,224 +4267,6 @@ const char *default_term_for_tty(const char *tty) { return term; } -/* Returns a short identifier for the various VM implementations */ -int detect_vm(const char **id) { - -#if defined(__i386__) || defined(__x86_64__) - - /* Both CPUID and DMI are x86 specific interfaces... */ - - static const char *const dmi_vendors[] = { - "/sys/class/dmi/id/sys_vendor", - "/sys/class/dmi/id/board_vendor", - "/sys/class/dmi/id/bios_vendor" - }; - - static const char dmi_vendor_table[] = - "QEMU\0" "qemu\0" - /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ - "VMware\0" "vmware\0" - "VMW\0" "vmware\0" - "Microsoft Corporation\0" "microsoft\0" - "innotek GmbH\0" "oracle\0" - "Xen\0" "xen\0" - "Bochs\0" "bochs\0"; - - static const char cpuid_vendor_table[] = - "XenVMMXenVMM\0" "xen\0" - "KVMKVMKVM\0" "kvm\0" - /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ - "VMwareVMware\0" "vmware\0" - /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */ - "Microsoft Hv\0" "microsoft\0"; - - uint32_t eax, ecx; - union { - uint32_t sig32[3]; - char text[13]; - } sig; - unsigned i; - const char *j, *k; - bool hypervisor; - - /* http://lwn.net/Articles/301888/ */ - zero(sig); - -#if defined (__i386__) -#define REG_a "eax" -#define REG_b "ebx" -#elif defined (__amd64__) -#define REG_a "rax" -#define REG_b "rbx" -#endif - - /* First detect whether there is a hypervisor */ - eax = 1; - __asm__ __volatile__ ( - /* ebx/rbx is being used for PIC! */ - " push %%"REG_b" \n\t" - " cpuid \n\t" - " pop %%"REG_b" \n\t" - - : "=a" (eax), "=c" (ecx) - : "0" (eax) - ); - - hypervisor = !!(ecx & 0x80000000U); - - if (hypervisor) { - - /* There is a hypervisor, see what it is */ - eax = 0x40000000U; - __asm__ __volatile__ ( - /* ebx/rbx is being used for PIC! */ - " push %%"REG_b" \n\t" - " cpuid \n\t" - " mov %%ebx, %1 \n\t" - " pop %%"REG_b" \n\t" - - : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2]) - : "0" (eax) - ); - - NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table) - if (streq(sig.text, j)) { - - if (id) - *id = k; - - return 1; - } - } - - for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) { - char *s; - int r; - const char *found = NULL; - - if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) { - if (r != -ENOENT) - return r; - - continue; - } - - NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table) - if (startswith(s, j)) - found = k; - free(s); - - if (found) { - if (id) - *id = found; - - return 1; - } - } - - if (hypervisor) { - if (id) - *id = "other"; - - return 1; - } - -#endif - return 0; -} - -int detect_container(const char **id) { - FILE *f; - - /* Unfortunately many of these operations require root access - * in one way or another */ - - if (geteuid() != 0) - return -EPERM; - - if (running_in_chroot() > 0) { - - if (id) - *id = "chroot"; - - return 1; - } - - /* /proc/vz exists in container and outside of the container, - * /proc/bc only outside of the container. */ - if (access("/proc/vz", F_OK) >= 0 && - access("/proc/bc", F_OK) < 0) { - - if (id) - *id = "openvz"; - - return 1; - } - - if ((f = fopen("/proc/self/cgroup", "re"))) { - - for (;;) { - char line[LINE_MAX], *p; - - if (!fgets(line, sizeof(line), f)) - break; - - if (!(p = strchr(strstrip(line), ':'))) - continue; - - if (strncmp(p, ":ns:", 4)) - continue; - - if (!streq(p, ":ns:/")) { - fclose(f); - - if (id) - *id = "pidns"; - - return 1; - } - } - - fclose(f); - } - - return 0; -} - -/* Returns a short identifier for the various VM/container implementations */ -int detect_virtualization(const char **id) { - static __thread const char *cached_id = NULL; - const char *_id; - int r; - - if (_likely_(cached_id)) { - - if (cached_id == (const char*) -1) - return 0; - - if (id) - *id = cached_id; - - return 1; - } - - if ((r = detect_container(&_id)) != 0) - goto finish; - - r = detect_vm(&_id); - -finish: - if (r > 0) { - cached_id = _id; - - if (id) - *id = _id; - } else if (r == 0) - cached_id = (const char*) -1; - - return r; -} - bool dirent_is_file(struct dirent *de) { assert(de); @@ -5529,6 +5305,9 @@ int get_files_in_directory(const char *path, char ***list) { * number */ d = opendir(path); + if (!d) + return -errno; + for (;;) { struct dirent buffer, *de; int k; @@ -5629,6 +5408,8 @@ char *join(const char *x, ...) { p = stpcpy(p, t); } + + va_end(ap); } else r[0] = 0; @@ -5815,7 +5596,7 @@ static const char* const ip_tos_table[] = { DEFINE_STRING_TABLE_LOOKUP(ip_tos, int); -static const char *const signal_table[] = { +static const char *const __signal_table[] = { [SIGHUP] = "HUP", [SIGINT] = "INT", [SIGQUIT] = "QUIT", @@ -5851,7 +5632,44 @@ static const char *const signal_table[] = { [SIGSYS] = "SYS" }; -DEFINE_STRING_TABLE_LOOKUP(signal, int); +DEFINE_PRIVATE_STRING_TABLE_LOOKUP(__signal, int); + +const char *signal_to_string(int signo) { + static __thread char buf[12]; + const char *name; + + name = __signal_to_string(signo); + if (name) + return name; + + if (signo >= SIGRTMIN && signo <= SIGRTMAX) + snprintf(buf, sizeof(buf) - 1, "RTMIN+%d", signo - SIGRTMIN); + else + snprintf(buf, sizeof(buf) - 1, "%d", signo); + char_array_0(buf); + return buf; +} + +int signal_from_string(const char *s) { + int signo; + int offset = 0; + unsigned u; + + signo =__signal_from_string(s); + if (signo > 0) + return signo; + + if (startswith(s, "RTMIN+")) { + s += 6; + offset = SIGRTMIN; + } + if (safe_atou(s, &u) >= 0) { + signo = (int) u + offset; + if (signo > 0 && signo < _NSIG) + return signo; + } + return -1; +} bool kexec_loaded(void) { bool loaded = false; diff --git a/src/util.h b/src/util.h index 3e1f46d826..ba0800dc07 100644 --- a/src/util.h +++ b/src/util.h @@ -288,13 +288,13 @@ int make_null_stdio(void); unsigned long long random_ull(void); -#define DEFINE_STRING_TABLE_LOOKUP(name,type) \ - const char *name##_to_string(type i) { \ +#define __DEFINE_STRING_TABLE_LOOKUP(name,type,scope) \ + scope const char *name##_to_string(type i) { \ if (i < 0 || i >= (type) ELEMENTSOF(name##_table)) \ return NULL; \ return name##_table[i]; \ } \ - type name##_from_string(const char *s) { \ + scope type name##_from_string(const char *s) { \ type i; \ unsigned u = 0; \ assert(s); \ @@ -309,6 +309,8 @@ unsigned long long random_ull(void); } \ struct __useless_struct_to_allow_trailing_semicolon__ +#define DEFINE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,) +#define DEFINE_PRIVATE_STRING_TABLE_LOOKUP(name,type) __DEFINE_STRING_TABLE_LOOKUP(name,type,static) int fd_nonblock(int fd, bool nonblock); int fd_cloexec(int fd, bool cloexec); @@ -404,10 +406,6 @@ bool tty_is_vc(const char *tty); int vtnr_from_tty(const char *tty); const char *default_term_for_tty(const char *tty); -int detect_vm(const char **id); -int detect_container(const char **id); -int detect_virtualization(const char **id); - void execute_directory(const char *directory, DIR *_d, char *argv[]); int kill_and_sigcont(pid_t pid, int sig); diff --git a/src/vconsole-setup.c b/src/vconsole-setup.c index 4347a2078f..8a89358a2d 100644 --- a/src/vconsole-setup.c +++ b/src/vconsole-setup.c @@ -39,6 +39,7 @@ #include "util.h" #include "log.h" #include "macro.h" +#include "virt.h" static bool is_vconsole(int fd) { unsigned char data[1]; diff --git a/src/virt.c b/src/virt.c new file mode 100644 index 0000000000..380fabded2 --- /dev/null +++ b/src/virt.c @@ -0,0 +1,314 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2011 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 <string.h> +#include <errno.h> +#include <unistd.h> + +#include "util.h" +#include "virt.h" + +/* Returns a short identifier for the various VM implementations */ +int detect_vm(const char **id) { + +#if defined(__i386__) || defined(__x86_64__) + + /* Both CPUID and DMI are x86 specific interfaces... */ + + static const char *const dmi_vendors[] = { + "/sys/class/dmi/id/sys_vendor", + "/sys/class/dmi/id/board_vendor", + "/sys/class/dmi/id/bios_vendor" + }; + + static const char dmi_vendor_table[] = + "QEMU\0" "qemu\0" + /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ + "VMware\0" "vmware\0" + "VMW\0" "vmware\0" + "Microsoft Corporation\0" "microsoft\0" + "innotek GmbH\0" "oracle\0" + "Xen\0" "xen\0" + "Bochs\0" "bochs\0"; + + static const char cpuid_vendor_table[] = + "XenVMMXenVMM\0" "xen\0" + "KVMKVMKVM\0" "kvm\0" + /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */ + "VMwareVMware\0" "vmware\0" + /* http://msdn.microsoft.com/en-us/library/ff542428.aspx */ + "Microsoft Hv\0" "microsoft\0"; + + uint32_t eax, ecx; + union { + uint32_t sig32[3]; + char text[13]; + } sig; + unsigned i; + const char *j, *k; + bool hypervisor; + + /* http://lwn.net/Articles/301888/ */ + zero(sig); + +#if defined (__i386__) +#define REG_a "eax" +#define REG_b "ebx" +#elif defined (__amd64__) +#define REG_a "rax" +#define REG_b "rbx" +#endif + + /* First detect whether there is a hypervisor */ + eax = 1; + __asm__ __volatile__ ( + /* ebx/rbx is being used for PIC! */ + " push %%"REG_b" \n\t" + " cpuid \n\t" + " pop %%"REG_b" \n\t" + + : "=a" (eax), "=c" (ecx) + : "0" (eax) + ); + + hypervisor = !!(ecx & 0x80000000U); + + if (hypervisor) { + + /* There is a hypervisor, see what it is */ + eax = 0x40000000U; + __asm__ __volatile__ ( + /* ebx/rbx is being used for PIC! */ + " push %%"REG_b" \n\t" + " cpuid \n\t" + " mov %%ebx, %1 \n\t" + " pop %%"REG_b" \n\t" + + : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2]) + : "0" (eax) + ); + + NULSTR_FOREACH_PAIR(j, k, cpuid_vendor_table) + if (streq(sig.text, j)) { + + if (id) + *id = k; + + return 1; + } + } + + for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) { + char *s; + int r; + const char *found = NULL; + + if ((r = read_one_line_file(dmi_vendors[i], &s)) < 0) { + if (r != -ENOENT) + return r; + + continue; + } + + NULSTR_FOREACH_PAIR(j, k, dmi_vendor_table) + if (startswith(s, j)) + found = k; + free(s); + + if (found) { + if (id) + *id = found; + + return 1; + } + } + + if (hypervisor) { + if (id) + *id = "other"; + + return 1; + } + +#endif + return 0; +} + +int detect_container(const char **id) { + FILE *f; + + /* Unfortunately many of these operations require root access + * in one way or another */ + + if (geteuid() != 0) + return -EPERM; + + if (running_in_chroot() > 0) { + + if (id) + *id = "chroot"; + + return 1; + } + + /* /proc/vz exists in container and outside of the container, + * /proc/bc only outside of the container. */ + if (access("/proc/vz", F_OK) >= 0 && + access("/proc/bc", F_OK) < 0) { + + if (id) + *id = "openvz"; + + return 1; + } + + f = fopen("/proc/1/environ", "re"); + if (f) { + bool done = false; + + do { + char line[LINE_MAX]; + unsigned i; + + for (i = 0; i < sizeof(line)-1; i++) { + int c; + + c = getc(f); + if (_unlikely_(c == EOF)) { + done = true; + break; + } else if (c == 0) + break; + + line[i] = c; + } + line[i] = 0; + + if (streq(line, "container=lxc")) { + fclose(f); + + if (id) + *id = "lxc"; + return 1; + + } else if (streq(line, "container=systemd-nspawn")) { + fclose(f); + + if (id) + *id = "systemd-nspawn"; + return 1; + + } else if (startswith(line, "container=")) { + fclose(f); + + if (id) + *id = "other"; + return 1; + } + + } while (!done); + + fclose(f); + } + + f = fopen("/proc/self/cgroup", "re"); + if (f) { + + for (;;) { + char line[LINE_MAX], *p; + + if (!fgets(line, sizeof(line), f)) + break; + + p = strchr(strstrip(line), ':'); + if (!p) + continue; + + if (strncmp(p, ":ns:", 4)) + continue; + + if (!streq(p, ":ns:/")) { + fclose(f); + + if (id) + *id = "pidns"; + + return 1; + } + } + + fclose(f); + } + + return 0; +} + +/* Returns a short identifier for the various VM/container implementations */ +Virtualization detect_virtualization(const char **id) { + + static __thread Virtualization cached_virt = _VIRTUALIZATION_INVALID; + static __thread const char *cached_id = NULL; + + const char *_id; + int r; + Virtualization v; + + if (_likely_(cached_virt >= 0)) { + + if (id && cached_virt > 0) + *id = cached_id; + + return cached_virt; + } + + r = detect_container(&_id); + if (r < 0) { + v = r; + goto finish; + } else if (r > 0) { + v = VIRTUALIZATION_CONTAINER; + goto finish; + } + + r = detect_vm(&_id); + if (r < 0) { + v = r; + goto finish; + } else if (r > 0) { + v = VIRTUALIZATION_VM; + goto finish; + } + + v = VIRTUALIZATION_NONE; + +finish: + if (v > 0) { + cached_id = _id; + + if (id) + *id = _id; + } + + if (v >= 0) + cached_virt = v; + + return v; +} diff --git a/src/virt.h b/src/virt.h new file mode 100644 index 0000000000..f55c9a68fd --- /dev/null +++ b/src/virt.h @@ -0,0 +1,38 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#ifndef foovirthfoo +#define foovirthfoo + +/*** + This file is part of systemd. + + Copyright 2011 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/>. +***/ + +int detect_vm(const char **id); +int detect_container(const char **id); + +typedef enum Virtualization { + VIRTUALIZATION_NONE = 0, + VIRTUALIZATION_VM, + VIRTUALIZATION_CONTAINER, + _VIRTUALIZATION_MAX, + _VIRTUALIZATION_INVALID = -1 +} Virtualization; + +Virtualization detect_virtualization(const char **id); + +#endif diff --git a/units/console-shell.service.m4 b/units/console-shell.service.m4 index cce2d5a5a4..a4a9108b32 100644 --- a/units/console-shell.service.m4 +++ b/units/console-shell.service.m4 @@ -31,6 +31,8 @@ WorkingDirectory=/root ExecStart=-/sbin/sulogin ExecStopPost=-/bin/systemctl poweroff StandardInput=tty-force +StandardOutput=inherit +StandardError=inherit KillMode=process # Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash diff --git a/units/dev-hugepages.mount b/units/dev-hugepages.mount index e6014e54a0..72a522e69c 100644 --- a/units/dev-hugepages.mount +++ b/units/dev-hugepages.mount @@ -8,6 +8,8 @@ [Unit] Description=Huge Pages File System DefaultDependencies=no +Before=sysinit.target +ConditionPathExists=/sys/kernel/mm/hugepages [Mount] What=hugetlbfs diff --git a/units/dev-mqueue.mount b/units/dev-mqueue.mount index 8519df5aca..cffdaf773f 100644 --- a/units/dev-mqueue.mount +++ b/units/dev-mqueue.mount @@ -8,6 +8,8 @@ [Unit] Description=POSIX Message Queue File System DefaultDependencies=no +Before=sysinit.target +ConditionPathExists=/proc/sys/fs/mqueue [Mount] What=mqueue diff --git a/units/emergency.service b/units/emergency.service index eff5261868..4847f4f0c6 100644 --- a/units/emergency.service +++ b/units/emergency.service @@ -21,6 +21,8 @@ ExecStartPre=-/bin/echo 'Welcome to emergency mode. Use "systemctl default" or ^ ExecStart=-/sbin/sulogin ExecStopPost=/bin/systemctl --fail --no-block default StandardInput=tty-force +StandardOutput=inherit +StandardError=inherit KillMode=process # Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash diff --git a/units/rescue.service.m4 b/units/rescue.service.m4 index d2fd582e86..19b30d89f9 100644 --- a/units/rescue.service.m4 +++ b/units/rescue.service.m4 @@ -11,7 +11,7 @@ Description=Rescue Shell DefaultDependencies=no Conflicts=shutdown.target -After=basic.target +After=basic.target plymouth-start.service Before=shutdown.target [Service] @@ -25,12 +25,14 @@ ExecStart=-/bin/bash -c "exec ${SINGLE}"', m4_ifdef(`TARGET_MANDRIVA', `EnvironmentFile=/etc/sysconfig/init ExecStart=-/bin/bash -c "exec ${SINGLE}"', -`ExecStart=-/sbin/sulogin' m4_ifdef(`TARGET_MEEGO', `EnvironmentFile=/etc/sysconfig/init -ExecStart=-/bin/bash -c "exec ${SINGLE}"',))) +ExecStart=-/bin/bash -c "exec ${SINGLE}"', +`ExecStart=-/sbin/sulogin'))) ExecStopPost=-/bin/systemctl --fail --no-block default StandardInput=tty-force +StandardOutput=inherit +StandardError=inherit KillMode=process # Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash diff --git a/units/dev-mqueue.automount b/units/sys-fs-fuse-connections.mount index 1061597571..037471537b 100644 --- a/units/dev-mqueue.automount +++ b/units/sys-fs-fuse-connections.mount @@ -6,10 +6,13 @@ # (at your option) any later version. [Unit] -Description=POSIX Message Queue File System Automount Point +Description=FUSE Control File System DefaultDependencies=no +ConditionPathExists=/sys/fs/fuse/connections +After=systemd-modules-load.service Before=sysinit.target -ConditionPathExists=/proc/sys/fs/mqueue -[Automount] -Where=/dev/mqueue +[Mount] +What=fusectl +Where=/sys/fs/fuse/connections +Type=fusectl diff --git a/units/dev-hugepages.automount b/units/sys-kernel-config.mount index 6e03df3560..d6862bf6bd 100644 --- a/units/dev-hugepages.automount +++ b/units/sys-kernel-config.mount @@ -6,10 +6,13 @@ # (at your option) any later version. [Unit] -Description=Huge Pages File System Automount Point +Description=Configuration File System DefaultDependencies=no +ConditionPathExists=/sys/kernel/config +After=systemd-modules-load.service Before=sysinit.target -ConditionPathExists=/sys/kernel/mm/hugepages -[Automount] -Where=/dev/hugepages +[Mount] +What=configfs +Where=/sys/kernel/config +Type=configfs diff --git a/units/sys-kernel-debug.automount b/units/sys-kernel-debug.automount deleted file mode 100644 index 2f2de9829f..0000000000 --- a/units/sys-kernel-debug.automount +++ /dev/null @@ -1,15 +0,0 @@ -# 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=Debug File System Automount Point -DefaultDependencies=no -Before=sysinit.target -ConditionPathExists=/sys/kernel/debug - -[Automount] -Where=/sys/kernel/debug diff --git a/units/sys-kernel-debug.mount b/units/sys-kernel-debug.mount index 53d107260b..d9fca1ff3d 100644 --- a/units/sys-kernel-debug.mount +++ b/units/sys-kernel-debug.mount @@ -8,6 +8,8 @@ [Unit] Description=Debug File System DefaultDependencies=no +ConditionPathExists=/sys/kernel/debug +Before=sysinit.target [Mount] What=debugfs diff --git a/units/sys-kernel-security.automount b/units/sys-kernel-security.automount deleted file mode 100644 index b7b16e19aa..0000000000 --- a/units/sys-kernel-security.automount +++ /dev/null @@ -1,15 +0,0 @@ -# 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=Security File System Automount Point -DefaultDependencies=no -Before=sysinit.target -ConditionPathExists=/sys/kernel/security - -[Automount] -Where=/sys/kernel/security diff --git a/units/sys-kernel-security.mount b/units/sys-kernel-security.mount index 770207f004..80cd7617d4 100644 --- a/units/sys-kernel-security.mount +++ b/units/sys-kernel-security.mount @@ -8,6 +8,8 @@ [Unit] Description=Security File System DefaultDependencies=no +ConditionPathExists=/sys/kernel/security +Before=sysinit.target [Mount] What=securityfs diff --git a/units/systemd-readahead-collect.service.in b/units/systemd-readahead-collect.service.in index 1a66f9fa6f..56ba54f0b3 100644 --- a/units/systemd-readahead-collect.service.in +++ b/units/systemd-readahead-collect.service.in @@ -16,6 +16,7 @@ Before=sysinit.target shutdown.target Type=notify ExecStart=@rootlibexecdir@/systemd-readahead-collect RemainAfterExit=yes +StandardOutput=null [Install] WantedBy=default.target diff --git a/units/systemd-readahead-replay.service.in b/units/systemd-readahead-replay.service.in index 5cc6defd9b..7c82e408e2 100644 --- a/units/systemd-readahead-replay.service.in +++ b/units/systemd-readahead-replay.service.in @@ -16,6 +16,7 @@ ConditionPathExists=/.readahead Type=notify ExecStart=@rootlibexecdir@/systemd-readahead-replay RemainAfterExit=yes +StandardOutput=null [Install] WantedBy=default.target diff --git a/units/var-lock.mount b/units/var-lock.mount index 80e1bab261..07277adac3 100644 --- a/units/var-lock.mount +++ b/units/var-lock.mount @@ -10,6 +10,7 @@ Description=Lock Directory Before=local-fs.target # skip mounting if the directory does not exist or is a symlink ConditionPathIsDirectory=/var/lock +ConditionPathIsSymbolicLink=!/var/lock [Mount] What=/run/lock diff --git a/units/var-run.mount b/units/var-run.mount index c513dfecd2..ab4da424c9 100644 --- a/units/var-run.mount +++ b/units/var-run.mount @@ -10,6 +10,7 @@ Description=Runtime Directory Before=local-fs.target # skip mounting if the directory does not exist or is a symlink ConditionPathIsDirectory=/var/run +ConditionPathIsSymbolicLink=!/var/run [Mount] What=/run |