chiark / gitweb /
Merge remote-tracking branch 'zbigniew/systemadm_changes'
authorLennart Poettering <lennart@poettering.net>
Wed, 2 Nov 2011 13:08:49 +0000 (14:08 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 2 Nov 2011 13:08:49 +0000 (14:08 +0100)
105 files changed:
Makefile.am
README
TODO
configure.ac
man/sd-daemon.xml
man/sd_booted.xml
man/sd_is_fifo.xml
man/sd_listen_fds.xml
man/sd_notify.xml
man/sd_readahead.xml
man/systemctl.xml
man/systemd.exec.xml
man/systemd.path.xml
man/systemd.service.xml
man/systemd.special.xml.in
man/systemd.unit.xml
po/pl.po
src/99-systemd.rules.in
src/binfmt.c
src/cgroup.c
src/condition.c
src/condition.h
src/conf-parser.c
src/cryptsetup-generator.c
src/dbus-manager.c
src/detect-virt.c
src/execute.c
src/fsck.c
src/generate-kbd-model-map [new file with mode: 0755]
src/getty-generator.c
src/hashmap.c
src/hostname-setup.c
src/hostnamed.c
src/initctl.c
src/install.c
src/job.c
src/kbd-model-map [new file with mode: 0644]
src/kmsg-syslogd.c
src/load-fragment-gperf.gperf.m4
src/load-fragment.c
src/locale-setup.c
src/localed.c
src/loginctl.c
src/logind-dbus.c
src/logind.c
src/main.c
src/manager.c
src/modules-load.c
src/mount.c
src/nspawn.c
src/org.freedesktop.locale1.policy.in
src/pager.c
src/path.c
src/quotacheck.c
src/random-seed.c
src/readahead-collect.c
src/readahead-common.h
src/readahead-replay.c
src/sd-login.c
src/sd-login.h
src/selinux-setup.c
src/service.c
src/shutdown.c
src/socket.c
src/special.h
src/stdout-syslog-bridge.c
src/strv.c
src/sysfs-show.c
src/systemctl-bash-completion.sh [deleted file]
src/systemctl.c
src/systemd-analyze
src/systemd-bash-completion.sh [new file with mode: 0644]
src/timedated.c
src/tmpfiles.c
src/tty-ask-password-agent.c
src/umount.c
src/unit.c
src/update-utmp.c
src/util.c
src/util.h
src/vconsole-setup.c
src/virt.c [new file with mode: 0644]
src/virt.h [new file with mode: 0644]
units/console-shell.service.m4
units/dev-hugepages.mount
units/dev-mqueue.mount
units/emergency.service
units/getty@.service.m4
units/local-fs-pre.target [moved from units/sys-kernel-debug.automount with 63% similarity]
units/mageia/prefdm.service [new file with mode: 0644]
units/remote-fs-pre.target [moved from units/dev-mqueue.automount with 62% similarity]
units/remount-rootfs.service
units/rescue.service.m4
units/serial-getty@.service.m4
units/sys-fs-fuse-connections.mount [moved from units/dev-hugepages.automount with 64% similarity]
units/sys-kernel-config.mount [moved from units/sys-kernel-security.automount with 66% similarity]
units/sys-kernel-debug.mount
units/sys-kernel-security.mount
units/systemd-logind.service.in
units/systemd-readahead-collect.service.in
units/systemd-readahead-replay.service.in
units/systemd-remount-api-vfs.service.in
units/systemd-stdout-syslog-bridge.service.in
units/var-lock.mount
units/var-run.mount

index 0712945..d30d626 100644 (file)
@@ -20,7 +20,7 @@ ACLOCAL_AMFLAGS = -I m4
 SUBDIRS = po
 
 LIBSYSTEMD_LOGIN_CURRENT=0
-LIBSYSTEMD_LOGIN_REVISION=4
+LIBSYSTEMD_LOGIN_REVISION=6
 LIBSYSTEMD_LOGIN_AGE=0
 
 LIBSYSTEMD_DAEMON_CURRENT=0
@@ -76,6 +76,7 @@ AM_CPPFLAGS = \
        -DSYSTEM_GENERATOR_PATH=\"$(systemgeneratordir)\" \
        -DUSER_GENERATOR_PATH=\"$(usergeneratordir)\" \
        -DSYSTEM_SHUTDOWN_PATH=\"$(systemshutdowndir)\" \
+        -DSYSTEMD_KBD_MODEL_MAP=\"$(pkgdatadir)/kbd-model-map\" \
        -I $(top_srcdir)/src
 
 if TARGET_GENTOO
@@ -118,6 +119,13 @@ AM_CPPFLAGS += \
        -DKBD_LOADKEYS=\"/bin/loadkeys\" \
        -DKBD_SETFONT=\"/bin/setfont\" \
        -DDEFAULT_FONT=\"latarcyrheb-sun16\"
+else
+if TARGET_MAGEIA
+AM_CPPFLAGS += \
+       -DKBD_LOADKEYS=\"/bin/loadkeys\" \
+       -DKBD_SETFONT=\"/bin/setfont\" \
+       -DDEFAULT_FONT=\"LatArCyrHeb-16\"
+endif
 endif
 endif
 endif
@@ -313,7 +321,7 @@ dbusinterface_DATA += \
 endif
 
 dist_bashcompletion_DATA = \
-       src/systemctl-bash-completion.sh
+       src/systemd-bash-completion.sh
 
 dist_tmpfiles_DATA = \
        tmpfiles.d/systemd.conf \
@@ -336,7 +344,9 @@ dist_systemunit_DATA = \
        units/halt.target \
        units/kexec.target \
        units/local-fs.target \
+        units/local-fs-pre.target \
        units/remote-fs.target \
+        units/remote-fs-pre.target \
        units/cryptsetup.target \
        units/network.target \
        units/nss-lookup.target \
@@ -357,14 +367,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 \
@@ -541,6 +549,13 @@ dist_systemunit_DATA += \
        units/suse/halt-local.service
 endif
 
+if TARGET_MAGEIA
+dist_systemunit_DATA += \
+       units/mageia/prefdm.service \
+       units/fedora/rc-local.service \
+       units/fedora/halt-local.service
+endif
+
 if HAVE_PLYMOUTH
 dist_systemunit_DATA += \
        units/plymouth-start.service \
@@ -615,6 +630,7 @@ noinst_LTLIBRARIES = \
 
 libsystemd_basic_la_SOURCES = \
        src/util.c \
+        src/virt.c \
        src/label.c \
        src/hashmap.c \
        src/set.c \
@@ -1032,6 +1048,12 @@ systemd_localed_LDADD = \
        libsystemd-daemon.la \
        $(DBUS_LIBS)
 
+dist_pkgdata_DATA = \
+        src/kbd-model-map
+
+dist_noinst_SCRIPT = \
+        src/generate-kbd-model-map
+
 systemd_timedated_SOURCES = \
        src/timedated.c \
         src/dbus-common.c \
@@ -1840,10 +1862,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 \
@@ -1852,10 +1876,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 && \
@@ -1989,6 +2015,23 @@ if TARGET_SUSE
                $(LN_S) $(systemunitdir)/halt-local.service halt-local.service )
 endif
 
+if TARGET_MAGEIA
+       $(MKDIR_P) -m 0755 $(DESTDIR)$(systemunitdir)/final.target.wants
+       ( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \
+               rm -f rc-local.service && \
+               $(LN_S) $(systemunitdir)/rc-local.service rc-local.service )
+       ( cd $(DESTDIR)$(systemunitdir)/final.target.wants && \
+               rm -f halt-local.service && \
+               $(LN_S) $(systemunitdir)/halt-local.service halt-local.service )
+       ( cd $(DESTDIR)$(systemunitdir) && \
+               rm -f display-manager.service && \
+               $(LN_S) prefdm.service display-manager.service && \
+               $(LN_S) prefdm.service dm.service )
+       ( cd $(DESTDIR)$(systemunitdir)/graphical.target.wants && \
+               rm -f display-manager.service && \
+               $(LN_S) $(systemunitdir)/display-manager.service display-manager.service )
+endif
+
 if HAVE_SYSV_COMPAT
        ( cd $(DESTDIR)$(systemunitdir)/local-fs.target.wants && \
                rm -f var-lock.mount && \
@@ -2015,3 +2058,6 @@ upload: all distcheck
 
 git-tag:
        git tag "v$(VERSION)" -m "systemd $(VERSION)"
+
+update-kbd-model-map:
+       src/generate-kbd-model-map > src/kbd-model-map
diff --git a/README b/README
index 15afb2c..a4cbeae 100644 (file)
--- a/README
+++ b/README
@@ -30,7 +30,10 @@ LICENSE:
         GPLv2+ for all code, except sd-daemon.[ch] which is MIT
 
 REQUIREMENTS:
-        Linux kernel >= 2.6.39 (with devtmpfs, cgroups; optional but strongly recommended: autofs4, ipv6)
+        Linux kernel >= 2.6.39
+                with devtmpfs
+                with cgroups (but it's OK to disable all controllers)
+                optional but strongly recommended: autofs4, ipv6
         libudev >= 172
         dbus >= 1.4.0
         libcap
diff --git a/TODO b/TODO
index 4dda3f9..fe73283 100644 (file)
--- a/TODO
+++ b/TODO
@@ -11,8 +11,38 @@ Bugfixes:
 
 * 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.
+
+* make polkit checks async
+
 Features:
 
+* as Tom Gundersen pointed out there's a always a dep loop if people use crypto file systems with random keys
+
+* unset container= in PID1?
+
+* automatically escape unit names passed on the service (i.e. think "systemctl start serial-getty.service@serial/by-path/jshdfjsdfhkjh" being automatically escaped as necessary.
+
+* if we can not get user quota for tmpfs, mount a separate tmpfs instance
+  for every user in /run/user/$USER with a configured maximum size
+
+* default to actual 32bit PIDs, via /proc/sys/kernel/pid_max
+
+* 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
@@ -43,8 +73,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.
 
@@ -81,8 +109,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
@@ -96,6 +122,8 @@ 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
 
@@ -136,6 +164,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
index b2411c9..596a32a 100644 (file)
@@ -17,7 +17,7 @@
 
 AC_PREREQ(2.63)
 
-AC_INIT([systemd],[35],[systemd-devel@lists.freedesktop.org])
+AC_INIT([systemd],[37],[systemd-devel@lists.freedesktop.org])
 AC_CONFIG_SRCDIR([src/main.c])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_HEADERS([config.h])
@@ -371,6 +371,7 @@ if test "z$with_distro" = "z"; then
                 test -f "/etc/mandriva-release" && with_distro="mandriva"
                 test -f "/etc/meego-release" && with_distro="meego"
                 test -f "/etc/angstrom-version" && with_distro="angstrom"
+                test -f "/etc/mageia-release" && with_distro="mageia"
                 if test "x`lsb_release -is 2>/dev/null`" = "xUbuntu"; then
                         with_distro="ubuntu"
                 fi
@@ -458,6 +459,12 @@ case $with_distro in
                 AC_DEFINE(TARGET_ANGSTROM, [], [Target is Ångström])
                 M4_DEFINES=-DTARGET_ANGSTROM=1
                 ;;
+        mageia)
+                SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d
+                AC_DEFINE(TARGET_MAGEIA, [], [Target is Mageia])
+                M4_DISTRO_FLAG=-DTARGET_MAGEIA=1
+                have_plymouth=yes
+                ;;
         other)
                 ;;
         *)
@@ -515,6 +522,7 @@ AM_CONDITIONAL(TARGET_ALTLINUX, test x"$with_distro" = xaltlinux)
 AM_CONDITIONAL(TARGET_MANDRIVA, test x"$with_distro" = xmandriva)
 AM_CONDITIONAL(TARGET_MEEGO, test x"$with_distro" = xmeego)
 AM_CONDITIONAL(TARGET_ANGSTROM, test x"$with_distro" = xangstrom)
+AM_CONDITIONAL(TARGET_MAGEIA, test x"$with_distro" = xmageia)
 
 AM_CONDITIONAL(HAVE_PLYMOUTH, test "$have_plymouth" = "yes")
 AM_CONDITIONAL(HAVE_SYSV_COMPAT, test "$SYSTEM_SYSV_COMPAT" = "yes")
index cbfe28f..cd67d99 100644 (file)
                 <funcsynopsis>
                         <funcsynopsisinfo>#include "sd-daemon.h"</funcsynopsisinfo>
                 </funcsynopsis>
+
+                <cmdsynopsis>
+                        <command>pkg-config --cflags --libs libsystemd-daemon</command>
+                </cmdsynopsis>
+
         </refsynopsisdiv>
 
         <refsect1>
                 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>
                         <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>
 
index 841ee1d..ebcde36 100644 (file)
                 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>
index 251f45c..f6fafab 100644 (file)
                 <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
 
                 <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
index 128d859..3276aff 100644 (file)
                 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>
index c060bba..dd0ba93 100644 (file)
                 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
 
                 <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>
index 004608d..88b135b 100644 (file)
                 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>
index 468141c..5adee45 100644 (file)
                         </varlistentry>
 
                         <varlistentry>
+                                <term><option>--no-legend</option></term>
+
+                               <listitem><para>Do not print a legend, i.e.
+                                the column headers and the footer with hints.
+                               </para></listitem>
+                       </varlistentry>
+
+                        <varlistentry>
                                 <term><option>--no-pager</option></term>
 
                                <listitem><para>Do not pipe output into a
                         </varlistentry>
 
                         <varlistentry>
+                                <term><command>list-unit-files</command></term>
+
+                                <listitem><para>List installed unit files.
+                                </para></listitem>
+                        </varlistentry>
+
+                        <varlistentry>
                                 <term><command>enable [NAME...]</command></term>
 
                                 <listitem><para>Enable one or more
index 609484b..230c4a3 100644 (file)
                                 assignments. Empty lines and lines
                                 starting with ; or # will be ignored,
                                 which may be used for commenting. The
+                                parser strips leading and
+                                trailing whitespace from the values
+                                of assignments, unless you use
+                                double quotes (").
+                                The
                                 argument passed should be an absolute
                                 file name, optionally prefixed with
                                 "-", which indicates that if the file
index f99931a..10d8f73 100644 (file)
                                 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>
index 4f11020..7b6f12d 100644 (file)
                                 main process of the daemon. The
                                 command line accepts % specifiers as
                                 described in
-                                <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>. On
-                                top of that basic environment variable
-                                substitution is supported, where
-                                <literal>${FOO}</literal> is replaced
-                                by the string value of the environment
-                                variable of the same name. Also
-                                <literal>$FOO</literal> may appear as
-                                separate word on the command line in
-                                which case the variable is replaced by
-                                its value split at whitespaces. Note
-                                that the first argument (i.e. the
-                                binary to execute) may not be a
-                                variable, and must be a literal and
-                                absolute path name.</para></listitem>
+                                <citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
+
+                                <para>On top of that basic environment
+                                variable substitution is
+                                supported. Use
+                                <literal>${FOO}</literal> as part of a
+                                word, or as word of its own on the
+                                command line, in which case it will be
+                                replaced by the value of the
+                                environment variable including all
+                                whitespace it contains, resulting in a
+                                single argument.  Use
+                                <literal>$FOO</literal> as a separate
+                                word on the command line, in which
+                                case it will be replaced by the value
+                                of the environment variable split up
+                                at whitespace, resulting in no or more
+                                arguments. Note that the first
+                                argument (i.e. the program to execute)
+                                may not be a variable, and must be a
+                                literal and absolute path
+                                name.</para></listitem>
                         </varlistentry>
 
                         <varlistentry>
index 2187540..116a43c 100644 (file)
@@ -59,6 +59,7 @@
                 <filename>halt.target</filename>,
                 <filename>kbrequest.target</filename>,
                 <filename>local-fs.target</filename>,
+                <filename>local-fs-pre.target</filename>,
                 <filename>mail-transfer-agent.target</filename>,
                 <filename>multi-user.target</filename>,
                 <filename>network.target</filename>,
@@ -66,6 +67,7 @@
                 <filename>poweroff.target</filename>,
                 <filename>reboot.target</filename>,
                 <filename>remote-fs.target</filename>,
+                <filename>remote-fs-pre.target</filename>,
                 <filename>rescue.target</filename>,
                 <filename>rpcbind.target</filename>,
                 <filename>runlevel2.target</filename>,
                                 </listitem>
                         </varlistentry>
                         <varlistentry>
+                                <term><filename>local-fs-pre.target</filename></term>
+                                <listitem>
+                                        <para>This target unit is
+                                        automatically ordered before
+                                        all local mount points marked
+                                        with <option>auto</option>
+                                        (see above). It can be used to
+                                        execute certain units before
+                                        all local mounts.</para>
+                                </listitem>
+                        </varlistentry>
+                        <varlistentry>
                                 <term><filename>mail-transfer-agent.target</filename></term>
                                 <listitem>
                                         <para>The mail transfer agent
                                 </listitem>
                         </varlistentry>
                         <varlistentry>
+                                <term><filename>remote-fs-pre.target</filename></term>
+                                <listitem>
+                                        <para>This target unit is
+                                        automatically ordered before
+                                        all remote mount points marked
+                                        with <option>auto</option>
+                                        (see above). It can be used to
+                                        execute certain units before
+                                        all remote mounts.</para>
+                                </listitem>
+                        </varlistentry>
+                        <varlistentry>
                                 <term><filename>rescue.target</filename></term>
                                 <listitem>
                                         <para>A special target unit
index b222f9f..897f99f 100644 (file)
 
                 <para>If a line starts with <option>.include</option>
                 followed by a file name, the specified file will be
-                read as if its contents were listed in place of the
-                <option>.include</option> directive.</para>
+                parsed at this point. Make sure that the file that is
+                included has the appropiate section headers before
+                any directives.</para>
 
                 <para>Along with a unit file
                 <filename>foo.service</filename> a directory
                                 <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>
                                 <term><varname>ConditionVirtualization=</varname></term>
                                 <term><varname>ConditionSecurity=</varname></term>
+                                <term><varname>ConditionCapability=</varname></term>
                                 <term><varname>ConditionNull=</varname></term>
 
                                 <listitem><para>Before starting a unit
                                 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
                                 <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>
                                 <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
                                 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
                                 system.  Currently the only recognized
                                 value is <varname>selinux</varname>.
                                 The test may be negated by prepending
-                                an exclamation mark. Finally,
+                                an exclamation
+                                mark. <varname>ConditionCapability=</varname>
+                                may be used to check whether the given
+                                capability exists in the capability
+                                bounding set of the service manager
+                                (i.e. this does not check whether
+                                capability is actually available in
+                                the permitted or effective sets, see
+                                <citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
+                                for details). Pass a capability name
+                                such as <literal>CAP_MKNOD</literal>,
+                                possibly prefixed with an exclamation
+                                mark to negate the check. Finally,
                                 <varname>ConditionNull=</varname> may
                                 be used to add a constant condition
                                 check value to the unit. It takes a
                                 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>
                         <citerefentry><refentrytitle>systemd.target</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd.path</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
                         <citerefentry><refentrytitle>systemd.timer</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
-                        <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+                        <citerefentry><refentrytitle>systemd.snapshot</refentrytitle><manvolnum>5</manvolnum></citerefentry>,
+                        <citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
                 </para>
         </refsect1>
 
index 52a21c8..3816864 100644 (file)
--- a/po/pl.po
+++ b/po/pl.po
@@ -53,7 +53,7 @@ msgstr "Ustawienie lokalizacji systemu"
 
 #: ../src/org.freedesktop.login1.policy.in.h:1
 msgid "Allow attaching devices to seats"
-msgstr "Zezwolenie na podłączanie urządzeń do siedzeń"
+msgstr "Zezwolenie na podłączanie urządzeń do stanowisk"
 
 #: ../src/org.freedesktop.login1.policy.in.h:2
 msgid "Allow non-logged-in users to run programs"
@@ -69,8 +69,8 @@ msgstr ""
 #: ../src/org.freedesktop.login1.policy.in.h:4
 msgid "Authentication is required to allow attaching a device to a seat"
 msgstr ""
-"Wymagane jest uwierzytelnienie, aby zezwolić na podłączanie urządzeń do "
-"siedzeń"
+"Wymagane jest uwierzytelnienie, aby zezwolić na podłączenie urządzenia do "
+"stanowiska"
 
 #: ../src/org.freedesktop.login1.policy.in.h:5
 msgid "Authentication is required to allow powering off the system"
@@ -103,11 +103,11 @@ msgid ""
 "seats"
 msgstr ""
 "Wymagane jest uwierzytelnienie, aby zezwolić na ponowne ustawianie sposobu "
-"podłączenia urządzeń do siedzeń"
+"podłączenia urządzeń do stanowisk"
 
 #: ../src/org.freedesktop.login1.policy.in.h:10
 msgid "Flush device to seat attachments"
-msgstr "Czyszczenie podłączeń urządzeń do siedzeń"
+msgstr "Usunięcie podłączenia urządzeń do stanowisk"
 
 #: ../src/org.freedesktop.login1.policy.in.h:11
 msgid "Power off the system"
index 884a614..b2481ae 100644 (file)
@@ -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"
index 552d8cc..e8d6524 100644 (file)
@@ -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]);
index dcf2c2f..be837c3 100644 (file)
@@ -38,9 +38,6 @@ int cgroup_bonding_realize(CGroupBonding *b) {
         assert(b->path);
         assert(b->controller);
 
-        if (b->realized)
-                return 0;
-
         r = cg_create(b->controller, b->path);
         if (r < 0) {
                 log_warning("Failed to create cgroup %s:%s: %s", b->controller, b->path, strerror(-r));
index f9202f6..2b51a16 100644 (file)
@@ -23,6 +23,7 @@
 #include <errno.h>
 #include <string.h>
 #include <unistd.h>
+#include <sys/capability.h>
 
 #ifdef HAVE_SELINUX
 #include <selinux/selinux.h>
 
 #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 +80,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 +95,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,25 +120,36 @@ 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;
+
+        /* Then, compare categorization */
+        if (v == VIRTUALIZATION_VM && streq(parameter, "vm"))
                 return true;
 
-        if (r == 0 && b == 0)
+        if (v == VIRTUALIZATION_CONTAINER && streq(parameter, "container"))
                 return true;
 
-        return streq(parameter, id);
+        /* Finally compare id */
+        return v > 0 && streq(parameter, id);
 }
 
 static bool test_security(const char *parameter) {
@@ -142,6 +160,38 @@ static bool test_security(const char *parameter) {
         return false;
 }
 
+static bool test_capability(const char *parameter) {
+        cap_value_t value;
+        FILE *f;
+        char line[LINE_MAX];
+        unsigned long long capabilities = (unsigned long long) -1;
+
+        /* If it's an invalid capability, we don't have it */
+
+        if (cap_from_name(parameter, &value) < 0)
+                return false;
+
+        /* If it's a valid capability we default to assume
+         * that we have it */
+
+        f = fopen("/proc/self/status", "re");
+        if (!f)
+                return true;
+
+        while (fgets(line, sizeof(line), f)) {
+                truncate_nl(line);
+
+                if (startswith(line, "CapBnd:")) {
+                        (void) sscanf(line+7, "%llx", &capabilities);
+                        break;
+                }
+        }
+
+        fclose(f);
+
+        return !!(capabilities & (1ULL << value));
+}
+
 bool condition_test(Condition *c) {
         assert(c);
 
@@ -156,11 +206,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 +232,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;
         }
@@ -186,6 +247,9 @@ bool condition_test(Condition *c) {
         case CONDITION_SECURITY:
                 return test_security(c->parameter) == !c->negate;
 
+        case CONDITION_CAPABILITY:
+                return test_capability(c->parameter) == !c->negate;
+
         case CONDITION_NULL:
                 return !c->negate;
 
@@ -247,6 +311,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",
index 672996e..71b1c67 100644 (file)
@@ -30,11 +30,14 @@ 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,
         CONDITION_VIRTUALIZATION,
         CONDITION_SECURITY,
+        CONDITION_CAPABILITY,
         CONDITION_NULL,
         _CONDITION_TYPE_MAX,
         _CONDITION_TYPE_INVALID = -1
index 3bb430e..a71dcd0 100644 (file)
@@ -314,7 +314,7 @@ int config_parse(
                                 continuation = c;
                         else {
                                 continuation = strdup(l);
-                                if (!c) {
+                                if (!continuation) {
                                         r = -ENOMEM;
                                         goto finish;
                                 }
index 6f3aa78..a48b7a4 100644 (file)
@@ -112,8 +112,7 @@ static int create_disk(
                 "DefaultDependencies=no\n"
                 "BindTo=%s dev-mapper-%%i.device\n"
                 "After=systemd-readahead-collect.service systemd-readahead-replay.service %s\n"
-                "Before=umount.target\n"
-                "Before=local-fs.target\n",
+                "Before=umount.target\n",
                 d, d);
 
         if (!nofail)
@@ -125,6 +124,9 @@ static int create_disk(
                          streq(password, "/dev/hw_random")))
                 fprintf(f,
                         "After=systemd-random-seed-load.service\n");
+        else
+                fprintf(f,
+                        "Before=local-fs.target\n");
 
         fprintf(f,
                 "\n[Service]\n"
index 822189b..7b68156 100644 (file)
@@ -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);
 
index 57f0176..79cad5d 100644 (file)
 #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;
 }
index 53e7e77..866e8bf 100644 (file)
@@ -895,12 +895,9 @@ static int do_capability_bounding_set_drop(uint64_t drop) {
                 }
         }
 
-        for (i = 0; i <= MAX(63LU, (unsigned long) CAP_LAST_CAP); i++)
+        for (i = 0; i <= cap_last_cap(); i++)
                 if (drop & ((uint64_t) 1ULL << (uint64_t) i)) {
                         if (prctl(PR_CAPBSET_DROP, i) < 0) {
-                                if (errno == EINVAL)
-                                        break;
-
                                 r = -errno;
                                 goto finish;
                         }
@@ -1720,7 +1717,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
                 unsigned long l;
                 fprintf(f, "%sCapabilityBoundingSet:", prefix);
 
-                for (l = 0; l <= (unsigned long) CAP_LAST_CAP; l++)
+                for (l = 0; l <= cap_last_cap(); l++)
                         if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) l))) {
                                 char *t;
 
index d7d4839..3477ba1 100644 (file)
@@ -34,6 +34,7 @@
 #include "dbus-common.h"
 #include "special.h"
 #include "bus-errors.h"
+#include "virt.h"
 
 static bool arg_skip = false;
 static bool arg_force = false;
@@ -126,7 +127,7 @@ static int parse_proc_cmdline(void) {
                         arg_skip = true;
                 else if (startswith(w, "fsck.mode"))
                         log_warning("Invalid fsck.mode= parameter. Ignoring.");
-#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA)
+#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
                 else if (strneq(w, "fastboot", l))
                         arg_skip = true;
                 else if (strneq(w, "forcefsck", l))
diff --git a/src/generate-kbd-model-map b/src/generate-kbd-model-map
new file mode 100755 (executable)
index 0000000..624c517
--- /dev/null
@@ -0,0 +1,33 @@
+#!/usr/bin/python
+
+import sys
+import system_config_keyboard.keyboard_models
+
+def strdash(s):
+        return s.strip() or '-'
+
+def tab_extend(s, n=1):
+        s = strdash(s)
+        k = len(s) // 8
+
+        if k >= n:
+                f = 1
+        else:
+                f = n - k
+
+        return s + '\t'*f
+
+
+models = system_config_keyboard.keyboard_models.KeyboardModels().get_models()
+
+print "# Generated from system-config-keyboard's model list"
+print "# consolelayout\t\txlayout\txmodel\t\txvariant\txoptions"
+
+for key, value in reversed(models.items()):
+        options = "terminate:ctrl_alt_bksp"
+        if value[4]:
+                options += ',' + value[4]
+
+        print ''.join((tab_extend(key, 3), tab_extend(value[1]),
+                       tab_extend(value[2], 2), tab_extend(value[3], 2),
+                       options))
index d4beffa..6b5b254 100644 (file)
@@ -26,6 +26,7 @@
 #include "log.h"
 #include "util.h"
 #include "unit-name.h"
+#include "virt.h"
 
 const char *arg_dest = "/tmp";
 
index 0d89da4..95ea45d 100644 (file)
@@ -124,11 +124,13 @@ __attribute__((destructor)) static void cleanup_pool(void) {
 #endif
 
 unsigned string_hash_func(const void *p) {
-        unsigned hash = 0;
-        const char *c;
+        unsigned hash = 5381;
+        const signed char *c;
+
+        /* DJB's hash function */
 
         for (c = p; *c; c++)
-                hash = 31 * hash + (unsigned) *c;
+                hash = (hash << 5) + hash + (unsigned) *c;
 
         return hash;
 }
index 57db9fb..2c2f10c 100644 (file)
@@ -30,9 +30,9 @@
 #include "util.h"
 #include "log.h"
 
-#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO)
+#if defined(TARGET_FEDORA) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) || defined(TARGET_MAGEIA)
 #define FILENAME "/etc/sysconfig/network"
-#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE) || defined(TARGET_FRUGALWARE)
+#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
 #define FILENAME "/etc/HOSTNAME"
 #elif defined(TARGET_ARCH)
 #define FILENAME "/etc/rc.conf"
@@ -64,7 +64,7 @@ static int read_and_strip_hostname(const char *path, char **hn) {
 
 static int read_distro_hostname(char **hn) {
 
-#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO)
+#if defined(TARGET_FEDORA) || defined(TARGET_ARCH) || defined(TARGET_GENTOO) || defined(TARGET_ALTLINUX) || defined(TARGET_MANDRIVA) || defined(TARGET_MEEGO) || defined(TARGET_MAGEIA)
         int r;
         FILE *f;
 
@@ -114,7 +114,7 @@ finish:
         fclose(f);
         return r;
 
-#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE) || defined(TARGET_FRUGALWARE)
+#elif defined(TARGET_SUSE) || defined(TARGET_SLACKWARE)
         return read_and_strip_hostname(FILENAME, hn);
 #else
         return -ENOENT;
index 9e8825d..f3b2c94 100644 (file)
@@ -31,6 +31,7 @@
 #include "dbus-common.h"
 #include "polkit.h"
 #include "def.h"
+#include "virt.h"
 
 #define INTERFACE \
         " <interface name=\"org.freedesktop.hostname1\">\n"             \
@@ -233,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;
                 }
 
@@ -396,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",
index eaa717a..097c85f 100644 (file)
@@ -56,6 +56,8 @@ typedef struct Server {
         unsigned n_fifos;
 
         DBusConnection *bus;
+
+        bool quit;
 } Server;
 
 struct Fifo {
@@ -174,6 +176,13 @@ static void request_process(Server *s, const struct init_request *req) {
                         case 'U':
                                 if (kill(1, SIGTERM) < 0)
                                         log_error("kill() failed: %m");
+
+                                /* The bus connection will be
+                                 * terminated if PID 1 is reexecuted,
+                                 * hence let's just exit here, and
+                                 * rely on that we'll be restarted on
+                                 * the next request */
+                                s->quit = true;
                                 break;
 
                         case 'q':
@@ -404,7 +413,7 @@ int main(int argc, char *argv[]) {
                   "READY=1\n"
                   "STATUS=Processing requests...");
 
-        for (;;) {
+        while (!server.quit) {
                 struct epoll_event event;
                 int k;
 
index 7443973..cfbd50e 100644 (file)
@@ -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;
                         }
index 26e1a7c..20971da 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -527,6 +527,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
         Unit *other;
         JobType t;
         Iterator i;
+        bool recursed = false;
 
         assert(j);
         assert(j->installed);
@@ -544,7 +545,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;
@@ -571,23 +574,29 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
                                 if (other->meta.job &&
                                     (other->meta.job->type == JOB_START ||
                                      other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START))
+                                     other->meta.job->type == JOB_RELOAD_OR_START)) {
                                         job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+                                        recursed = true;
+                                }
 
                         SET_FOREACH(other, u->meta.dependencies[UNIT_BOUND_BY], i)
                                 if (other->meta.job &&
                                     (other->meta.job->type == JOB_START ||
                                      other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START))
+                                     other->meta.job->type == JOB_RELOAD_OR_START)) {
                                         job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+                                        recursed = true;
+                                }
 
                         SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
                                 if (other->meta.job &&
                                     !other->meta.job->override &&
                                     (other->meta.job->type == JOB_START ||
                                      other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START))
+                                     other->meta.job->type == JOB_RELOAD_OR_START)) {
                                         job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+                                        recursed = true;
+                                }
 
                 } else if (t == JOB_STOP) {
 
@@ -595,8 +604,10 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
                                 if (other->meta.job &&
                                     (other->meta.job->type == JOB_START ||
                                      other->meta.job->type == JOB_VERIFY_ACTIVE ||
-                                     other->meta.job->type == JOB_RELOAD_OR_START))
+                                     other->meta.job->type == JOB_RELOAD_OR_START)) {
                                         job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
+                                        recursed = true;
+                                }
                 }
         }
 
@@ -613,6 +624,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)
@@ -623,7 +635,7 @@ int job_finish_and_invalidate(Job *j, JobResult result) {
 
         manager_check_finished(u->meta.manager);
 
-        return 0;
+        return recursed;
 }
 
 int job_start_timer(Job *j) {
diff --git a/src/kbd-model-map b/src/kbd-model-map
new file mode 100644 (file)
index 0000000..a895880
--- /dev/null
@@ -0,0 +1,72 @@
+# Generated from system-config-keyboard's model list
+# consolelayout                xlayout xmodel          xvariant        xoptions
+sg                     ch      pc105           de_nodeadkeys   terminate:ctrl_alt_bksp
+nl                     nl      pc105           -               terminate:ctrl_alt_bksp
+mk-utf                 mkd,us  pc105           -               terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+trq                    tr      pc105           -               terminate:ctrl_alt_bksp
+guj                    in,us   pc105           guj             terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+uk                     gb      pc105           -               terminate:ctrl_alt_bksp
+is-latin1              is      pc105           -               terminate:ctrl_alt_bksp
+de                     de      pc105           -               terminate:ctrl_alt_bksp
+gur                    gur,us  pc105           -               terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+la-latin1              latam   pc105           -               terminate:ctrl_alt_bksp
+us                     us      pc105+inet      -               terminate:ctrl_alt_bksp
+ko                     kr      pc105           -               terminate:ctrl_alt_bksp
+ro-std                 ro      pc105           std             terminate:ctrl_alt_bksp
+de-latin1              de      pc105           -               terminate:ctrl_alt_bksp
+tml-inscript           in,us   pc105           tam             terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+slovene                        si      pc105           -               terminate:ctrl_alt_bksp
+hu101                  hu      pc105           qwerty          terminate:ctrl_alt_bksp
+jp106                  jp      jp106           -               terminate:ctrl_alt_bksp
+croat                  hr      pc105           -               terminate:ctrl_alt_bksp
+ben-probhat            in,us   pc105           ben_probhat     terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+fi-latin1              fi      pc105           -               terminate:ctrl_alt_bksp
+it2                    it      pc105           -               terminate:ctrl_alt_bksp
+hu                     hu      pc105           -               terminate:ctrl_alt_bksp
+sr-latin               rs      pc105           latin           terminate:ctrl_alt_bksp
+fi                     fi      pc105           -               terminate:ctrl_alt_bksp
+fr_CH                  ch      pc105           fr              terminate:ctrl_alt_bksp
+dk-latin1              dk      pc105           -               terminate:ctrl_alt_bksp
+fr                     fr      pc105           -               terminate:ctrl_alt_bksp
+it                     it      pc105           -               terminate:ctrl_alt_bksp
+tml-uni                        in,us   pc105           tam_TAB         terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ua-utf                 ua,us   pc105           -               terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+fr-latin1              fr      pc105           -               terminate:ctrl_alt_bksp
+sg-latin1              ch      pc105           de_nodeadkeys   terminate:ctrl_alt_bksp
+be-latin1              be      pc105           -               terminate:ctrl_alt_bksp
+dk                     dk      pc105           -               terminate:ctrl_alt_bksp
+fr-pc                  fr      pc105           -               terminate:ctrl_alt_bksp
+bg_pho-utf8            bg,us   pc105           ,phonetic       terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+it-ibm                 it      pc105           -               terminate:ctrl_alt_bksp
+cz-us-qwertz           cz,us   pc105           -               terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ar-digits              ara,us  pc105           digits          terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+br-abnt2               br      abnt2           -               terminate:ctrl_alt_bksp
+ro                     ro      pc105           -               terminate:ctrl_alt_bksp
+us-acentos             us      pc105           intl            terminate:ctrl_alt_bksp
+pt-latin1              pt      pc105           -               terminate:ctrl_alt_bksp
+ro-std-cedilla         ro      pc105           std_cedilla     terminate:ctrl_alt_bksp
+tj                     tj      pc105           -               terminate:ctrl_alt_bksp
+ar-qwerty              ara,us  pc105           qwerty          terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ar-azerty-digits       ara,us  pc105           azerty_digits   terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ben                    in,us   pc105           ben             terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+de-latin1-nodeadkeys   de      pc105           nodeadkeys      terminate:ctrl_alt_bksp
+no                     no      pc105           -               terminate:ctrl_alt_bksp
+bg_bds-utf8            bg,us   pc105           -               terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+dvorak                 us      pc105           dvorak          terminate:ctrl_alt_bksp
+ru                     ru,us   pc105           -               terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+cz-lat2                        cz      pc105           qwerty          terminate:ctrl_alt_bksp
+pl2                    pl      pc105           -               terminate:ctrl_alt_bksp
+es                     es      pc105           -               terminate:ctrl_alt_bksp
+ro-cedilla             ro      pc105           cedilla         terminate:ctrl_alt_bksp
+ie                     ie      pc105           -               terminate:ctrl_alt_bksp
+ar-azerty              ara,us  pc105           azerty          terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+ar-qwerty-digits       ara,us  pc105           qwerty_digits   terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+et                     ee      pc105           -               terminate:ctrl_alt_bksp
+sk-qwerty              sk      pc105           -               terminate:ctrl_alt_bksp,qwerty
+dev                    dev,us  pc105           -               terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
+fr-latin9              fr      pc105           latin9          terminate:ctrl_alt_bksp
+fr_CH-latin1           ch      pc105           fr              terminate:ctrl_alt_bksp
+cf                     ca(fr)  pc105           -               terminate:ctrl_alt_bksp
+sv-latin1              se      pc105           -               terminate:ctrl_alt_bksp
+sr-cy                  rs      pc105           -               terminate:ctrl_alt_bksp
+gr                     gr,us   pc105           -               terminate:ctrl_alt_bksp,grp:shifts_toggle,grp_led:scroll
index 83c2047..0901a0e 100644 (file)
@@ -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 {
index 08223c5..41797d2 100644 (file)
@@ -112,11 +112,14 @@ 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
 Unit.ConditionVirtualization,    config_parse_unit_condition_string, CONDITION_VIRTUALIZATION,      0
 Unit.ConditionSecurity,          config_parse_unit_condition_string, CONDITION_SECURITY,            0
+Unit.ConditionCapability,        config_parse_unit_condition_string, CONDITION_CAPABILITY,          0
 Unit.ConditionNull,              config_parse_unit_condition_null,   0,                             0
 m4_dnl
 Service.PIDFile,                 config_parse_unit_path_printf,      0,                             offsetof(Service, pid_file)
index c8b4b5a..12079c6 100644 (file)
@@ -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);
index 41eb50b..7f692e9 100644 (file)
@@ -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
@@ -198,7 +199,7 @@ int locale_setup(void) {
                 if (r != -ENOENT)
                         log_warning("Failed to read /etc/profile.env: %s", strerror(-r));
         }
-#elif defined(TARGET_MANDRIVA)
+#elif defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA )
         if (r <= 0 &&
             (r = parse_env_file("/etc/sysconfig/i18n", NEWLINE,
                                 "LANG",              &variables[VARIABLE_LANG],
index f652110..c6b48de 100644 (file)
 #define INTERFACE                                                       \
         " <interface name=\"org.freedesktop.locale1\">\n"               \
         "  <property name=\"Locale\" type=\"as\" access=\"read\"/>\n"   \
+        "  <property name=\"VConsoleKeymap\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"VConsoleKeymapToggle\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"X11Layout\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"X11Model\" type=\"s\" access=\"read\"/>\n"  \
+        "  <property name=\"X11Variant\" type=\"s\" access=\"read\"/>\n" \
+        "  <property name=\"X11Options\" type=\"s\" access=\"read\"/>\n" \
         "  <method name=\"SetLocale\">\n"                               \
         "   <arg name=\"locale\" type=\"as\" direction=\"in\"/>\n"      \
         "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
         "  </method>\n"                                                 \
+        "  <method name=\"SetVConsoleKeyboard\">\n"                      \
+        "   <arg name=\"keymap\" type=\"s\" direction=\"in\"/>\n"       \
+        "   <arg name=\"keymap_toggle\" type=\"s\" direction=\"in\"/>\n" \
+        "   <arg name=\"convert\" type=\"b\" direction=\"in\"/>\n"      \
+        "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
+        "  </method>\n"                                                 \
+        "  <method name=\"SetX11Keyboard\">\n"                          \
+        "   <arg name=\"layout\" type=\"s\" direction=\"in\"/>\n"       \
+        "   <arg name=\"model\" type=\"s\" direction=\"in\"/>\n"        \
+        "   <arg name=\"variant\" type=\"s\" direction=\"in\"/>\n"      \
+        "   <arg name=\"options\" type=\"s\" direction=\"in\"/>\n"      \
+        "   <arg name=\"convert\" type=\"b\" direction=\"in\"/>\n"      \
+        "   <arg name=\"user_interaction\" type=\"b\" direction=\"in\"/>\n" \
+        "  </method>\n"                                                 \
         " </interface>\n"
 
 #define INTROSPECTION                                                   \
@@ -109,9 +129,28 @@ static char *data[_PROP_MAX] = {
         NULL
 };
 
+static char *x11_layout = NULL, *x11_model = NULL, *x11_variant = NULL, *x11_options = NULL;
+static char *vc_keymap = NULL, *vc_keymap_toggle = NULL;
+
 static usec_t remain_until = 0;
 
-static void free_data(void) {
+static int free_and_set(char **s, const char *v) {
+        int r;
+        char *t;
+
+        assert(s);
+
+        r = strdup_or_null(isempty(v) ? NULL : v, &t);
+        if (r < 0)
+                return r;
+
+        free(*s);
+        *s = t;
+
+        return 0;
+}
+
+static void free_data_locale(void) {
         int p;
 
         for (p = 0; p < _PROP_MAX; p++) {
@@ -120,6 +159,22 @@ static void free_data(void) {
         }
 }
 
+static void free_data_x11(void) {
+        free(x11_layout);
+        free(x11_model);
+        free(x11_variant);
+        free(x11_options);
+
+        x11_layout = x11_model = x11_variant = x11_options = NULL;
+}
+
+static void free_data_vconsole(void) {
+        free(vc_keymap);
+        free(vc_keymap_toggle);
+
+        vc_keymap = vc_keymap_toggle = NULL;
+}
+
 static void simplify(void) {
         int p;
 
@@ -130,10 +185,10 @@ static void simplify(void) {
                 }
 }
 
-static int read_data(void) {
+static int read_data_locale(void) {
         int r;
 
-        free_data();
+        free_data_locale();
 
         r = parse_env_file("/etc/locale.conf", NEWLINE,
                            "LANG",              &data[PROP_LANG],
@@ -181,7 +236,129 @@ static int read_data(void) {
         return r;
 }
 
-static int write_data(void) {
+static void free_data(void) {
+        free_data_locale();
+        free_data_vconsole();
+        free_data_x11();
+}
+
+static int read_data_vconsole(void) {
+        int r;
+
+        free_data_vconsole();
+
+        r = parse_env_file("/etc/vconsole.conf", NEWLINE,
+                           "KEYMAP",        &vc_keymap,
+                           "KEYMAP_TOGGLE", &vc_keymap_toggle,
+                           NULL);
+
+        if (r < 0 && r != -ENOENT)
+                return r;
+
+        return 0;
+}
+
+static int read_data_x11(void) {
+        FILE *f;
+        char line[LINE_MAX];
+        bool in_section = false;
+
+        free_data_x11();
+
+        f = fopen("/etc/X11/xorg.conf.d/00-keyboard.conf", "re");
+        if (!f) {
+                if (errno == ENOENT) {
+
+#ifdef TARGET_FEDORA
+                        f = fopen("/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf", "re");
+                        if (!f) {
+                                if (errno == ENOENT)
+                                        return 0;
+                                else
+                                        return -errno;
+                        }
+#else
+                        return 0;
+#endif
+
+                } else
+                          return -errno;
+        }
+
+        while (fgets(line, sizeof(line), f)) {
+                char *l;
+
+                char_array_0(line);
+                l = strstrip(line);
+
+                if (l[0] == 0 || l[0] == '#')
+                        continue;
+
+                if (in_section && first_word(l, "Option")) {
+                        char **a;
+
+                        a = strv_split_quoted(l);
+                        if (!a) {
+                                fclose(f);
+                                return -ENOMEM;
+                        }
+
+                        if (strv_length(a) == 3) {
+
+                                if (streq(a[1], "XkbLayout")) {
+                                        free(x11_layout);
+                                        x11_layout = a[2];
+                                        a[2] = NULL;
+                                } else if (streq(a[1], "XkbModel")) {
+                                        free(x11_model);
+                                        x11_model = a[2];
+                                        a[2] = NULL;
+                                } else if (streq(a[1], "XkbVariant")) {
+                                        free(x11_variant);
+                                        x11_variant = a[2];
+                                        a[2] = NULL;
+                                } else if (streq(a[1], "XkbOptions")) {
+                                        free(x11_options);
+                                        x11_options = a[2];
+                                        a[2] = NULL;
+                                }
+                        }
+
+                        strv_free(a);
+
+                } else if (!in_section && first_word(l, "Section")) {
+                        char **a;
+
+                        a = strv_split_quoted(l);
+                        if (!a) {
+                                fclose(f);
+                                return -ENOMEM;
+                        }
+
+                        if (strv_length(a) == 2 && streq(a[1], "InputClass"))
+                                in_section = true;
+
+                        strv_free(a);
+                } else if (in_section && first_word(l, "EndSection"))
+                        in_section = false;
+        }
+
+        fclose(f);
+
+        return 0;
+}
+
+static int read_data(void) {
+        int r, q, p;
+
+        r = read_data_locale();
+        q = read_data_vconsole();
+        p = read_data_x11();
+
+        return r < 0 ? r : q < 0 ? q : p;
+}
+
+static int write_data_locale(void) {
         int r, p;
         char **l = NULL;
 
@@ -215,6 +392,7 @@ static int write_data(void) {
         }
 
         if (strv_isempty(l)) {
+                strv_free(l);
 
                 if (unlink("/etc/locale.conf") < 0)
                         return errno == ENOENT ? 0 : -errno;
@@ -319,6 +497,482 @@ finish:
         free(l_unset);
 }
 
+static int write_data_vconsole(void) {
+        int r;
+        char **l = NULL;
+
+        r = load_env_file("/etc/vconsole.conf", &l);
+        if (r < 0 && r != -ENOENT)
+                return r;
+
+        if (isempty(vc_keymap))
+                l = strv_env_unset(l, "KEYMAP");
+        else {
+                char *s, **u;
+
+                s = strappend("KEYMAP=", vc_keymap);
+                if (!s) {
+                        strv_free(l);
+                        return -ENOMEM;
+                }
+
+                u = strv_env_set(l, s);
+                free(s);
+                strv_free(l);
+
+                if (!u)
+                        return -ENOMEM;
+
+                l = u;
+        }
+
+        if (isempty(vc_keymap_toggle))
+                l = strv_env_unset(l, "KEYMAP_TOGGLE");
+        else  {
+                char *s, **u;
+
+                s = strappend("KEYMAP_TOGGLE=", vc_keymap_toggle);
+                if (!s) {
+                        strv_free(l);
+                        return -ENOMEM;
+                }
+
+                u = strv_env_set(l, s);
+                free(s);
+                strv_free(l);
+
+                if (!u)
+                        return -ENOMEM;
+
+                l = u;
+        }
+
+        if (strv_isempty(l)) {
+                strv_free(l);
+
+                if (unlink("/etc/vconsole.conf") < 0)
+                        return errno == ENOENT ? 0 : -errno;
+
+                return 0;
+        }
+
+        r = write_env_file("/etc/vconsole.conf", l);
+        strv_free(l);
+
+        return r;
+}
+
+static int write_data_x11(void) {
+        FILE *f;
+        char *temp_path;
+        int r;
+
+        if (isempty(x11_layout) &&
+            isempty(x11_model) &&
+            isempty(x11_variant) &&
+            isempty(x11_options)) {
+
+#ifdef TARGET_FEDORA
+                unlink("/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf");
+
+                /* Symlink this to /dev/null, so that s-s-k (if it is
+                 * still running) doesn't recreate this. */
+                symlink("/dev/null", "/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf");
+#endif
+
+                if (unlink("/etc/X11/xorg.conf.d/00-keyboard.conf") < 0)
+                        return errno == ENOENT ? 0 : -errno;
+
+                return 0;
+        }
+
+        mkdir_parents("/etc/X11/xorg.conf.d", 0755);
+
+        r = fopen_temporary("/etc/X11/xorg.conf.d/00-keyboard.conf", &f, &temp_path);
+        if (r < 0)
+                return r;
+
+        fchmod(fileno(f), 0644);
+
+        fputs("# Read and parsed by systemd-localed. It's probably wise not to edit this file\n"
+              "# manually too freely.\n"
+              "Section \"InputClass\"\n"
+              "        Identifier \"system-keyboard\"\n"
+              "        MatchIsKeyboard \"on\"\n", f);
+
+        if (!isempty(x11_layout))
+                fprintf(f, "        Option \"XkbLayout\" \"%s\"\n", x11_layout);
+
+        if (!isempty(x11_model))
+                fprintf(f, "        Option \"XkbModel\" \"%s\"\n", x11_model);
+
+        if (!isempty(x11_variant))
+                fprintf(f, "        Option \"XkbVariant\" \"%s\"\n", x11_variant);
+
+        if (!isempty(x11_options))
+                fprintf(f, "        Option \"XkbOptions\" \"%s\"\n", x11_options);
+
+        fputs("EndSection\n", f);
+        fflush(f);
+
+        if (ferror(f) || rename(temp_path, "/etc/X11/xorg.conf.d/00-keyboard.conf") < 0) {
+                r = -errno;
+                unlink("/etc/X11/xorg.conf.d/00-keyboard.conf");
+                unlink(temp_path);
+        } else {
+
+#ifdef TARGET_FEDORA
+                unlink("/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf");
+
+                /* Symlink this to /dev/null, so that s-s-k (if it is
+                 * still running) doesn't recreate this. */
+                symlink("/dev/null", "/etc/X11/xorg.conf.d/00-system-setup-keyboard.conf");
+#endif
+
+                r = 0;
+        }
+
+        fclose(f);
+        free(temp_path);
+
+        return r;
+}
+
+static int load_vconsole_keymap(DBusConnection *bus, DBusError *error) {
+        DBusMessage *m = NULL, *reply = NULL;
+        const char *name = "systemd-vconsole-setup.service", *mode = "replace";
+        int r;
+        DBusError _error;
+
+        assert(bus);
+
+        if (!error) {
+                dbus_error_init(&_error);
+                error = &_error;
+        }
+
+        m = dbus_message_new_method_call(
+                        "org.freedesktop.systemd1",
+                        "/org/freedesktop/systemd1",
+                        "org.freedesktop.systemd1.Manager",
+                        "RestartUnit");
+        if (!m) {
+                log_error("Could not allocate message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        if (!dbus_message_append_args(m,
+                                      DBUS_TYPE_STRING, &name,
+                                      DBUS_TYPE_STRING, &mode,
+                                      DBUS_TYPE_INVALID)) {
+                log_error("Could not append arguments to message.");
+                r = -ENOMEM;
+                goto finish;
+        }
+
+        reply = dbus_connection_send_with_reply_and_block(bus, m, -1, error);
+        if (!reply) {
+                log_error("Failed to issue method call: %s", bus_error_message(error));
+                r = -EIO;
+                goto finish;
+        }
+
+        r = 0;
+
+finish:
+        if (m)
+                dbus_message_unref(m);
+
+        if (reply)
+                dbus_message_unref(reply);
+
+        if (error == &_error)
+                dbus_error_free(error);
+
+        return r;
+}
+
+static char *strnulldash(const char *s) {
+        return s == NULL || *s == 0 || (s[0] == '-' && s[1] == 0) ? NULL : (char*) s;
+}
+
+static int read_next_mapping(FILE *f, unsigned *n, char ***a) {
+        assert(f);
+        assert(n);
+        assert(a);
+
+        for (;;) {
+                char line[LINE_MAX];
+                char *l, **b;
+
+                errno = 0;
+                if (!fgets(line, sizeof(line), f)) {
+
+                        if (ferror(f))
+                                return errno ? -errno : -EIO;
+
+                        return 0;
+                }
+
+                (*n) ++;
+
+                l = strstrip(line);
+                if (l[0] == 0 || l[0] == '#')
+                        continue;
+
+                b = strv_split_quoted(l);
+                if (!b)
+                        return -ENOMEM;
+
+                if (strv_length(b) < 5) {
+                        log_error("Invalid line "SYSTEMD_KBD_MODEL_MAP":%u, ignoring.", *n);
+                        strv_free(b);
+                        continue;
+
+                }
+
+                *a = b;
+                return 1;
+        }
+}
+
+static int convert_vconsole_to_x11(DBusConnection *connection) {
+        bool modified = false;
+
+        assert(connection);
+
+        if (isempty(vc_keymap)) {
+
+                modified =
+                        !isempty(x11_layout) ||
+                        !isempty(x11_model) ||
+                        !isempty(x11_variant) ||
+                        !isempty(x11_options);
+
+                free_data_x11();
+        } else {
+                FILE *f;
+                unsigned n = 0;
+
+                f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
+                if (!f)
+                        return -errno;
+
+                for (;;) {
+                        char **a;
+                        int r;
+
+                        r = read_next_mapping(f, &n, &a);
+                        if (r < 0) {
+                                fclose(f);
+                                return r;
+                        }
+
+                        if (r == 0)
+                                break;
+
+                        if (!streq(vc_keymap, a[0])) {
+                                strv_free(a);
+                                continue;
+                        }
+
+                        if (!streq_ptr(x11_layout, strnulldash(a[1])) ||
+                            !streq_ptr(x11_model, strnulldash(a[2])) ||
+                            !streq_ptr(x11_variant, strnulldash(a[3])) ||
+                            !streq_ptr(x11_options, strnulldash(a[4]))) {
+
+                                if (free_and_set(&x11_layout, strnulldash(a[1])) < 0 ||
+                                    free_and_set(&x11_model, strnulldash(a[2])) < 0 ||
+                                    free_and_set(&x11_variant, strnulldash(a[3])) < 0 ||
+                                    free_and_set(&x11_options, strnulldash(a[4])) < 0) {
+                                        strv_free(a);
+                                        fclose(f);
+                                        return -ENOMEM;
+                                }
+
+                                modified = true;
+                        }
+
+                        strv_free(a);
+                        break;
+                }
+
+                fclose(f);
+        }
+
+        if (modified) {
+                dbus_bool_t b;
+                DBusMessage *changed;
+                int r;
+
+                r = write_data_x11();
+                if (r < 0)
+                        log_error("Failed to set X11 keyboard layout: %s", strerror(-r));
+
+                changed = bus_properties_changed_new(
+                                "/org/freedesktop/locale1",
+                                "org.freedesktop.locale1",
+                                "X11Layout\0"
+                                "X11Model\0"
+                                "X11Variant\0"
+                                "X11Options\0");
+
+                if (!changed)
+                        return -ENOMEM;
+
+                b = dbus_connection_send(connection, changed, NULL);
+                dbus_message_unref(changed);
+
+                if (!b)
+                        return -ENOMEM;
+        }
+
+        return 0;
+}
+
+static int convert_x11_to_vconsole(DBusConnection *connection) {
+        bool modified = false;
+
+        assert(connection);
+
+        if (isempty(x11_layout)) {
+
+                modified =
+                        !isempty(vc_keymap) ||
+                        !isempty(vc_keymap_toggle);
+
+                free_data_x11();
+        } else {
+                FILE *f;
+                unsigned n = 0;
+                unsigned best_matching = 0;
+                char *new_keymap = NULL;
+
+                f = fopen(SYSTEMD_KBD_MODEL_MAP, "re");
+                if (!f)
+                        return -errno;
+
+                for (;;) {
+                        char **a;
+                        unsigned matching = 0;
+                        int r;
+
+                        r = read_next_mapping(f, &n, &a);
+                        if (r < 0) {
+                                fclose(f);
+                                return r;
+                        }
+
+                        if (r == 0)
+                                break;
+
+                        /* Determine how well matching this entry is */
+                        if (streq_ptr(x11_layout, a[1]))
+                                /* If we got an exact match, this is best */
+                                matching = 10;
+                        else {
+                                size_t x;
+
+                                x = strcspn(x11_layout, ",");
+
+                                /* We have multiple X layouts, look
+                                 * for an entry that matches our key
+                                 * with the everything but the first
+                                 * layout stripped off. */
+                                if (x > 0 &&
+                                    strlen(a[1]) == x &&
+                                    strncmp(x11_layout, a[1], x) == 0)
+                                        matching = 5;
+                                else  {
+                                        size_t w;
+
+                                        /* If that didn't work, strip
+                                         * off the other layouts from
+                                         * the entry, too */
+
+                                        w = strcspn(a[1], ",");
+
+                                        if (x > 0 && x == w &&
+                                            memcmp(x11_layout, a[1], x) == 0)
+                                                matching = 1;
+                                }
+                        }
+
+                        if (matching > 0 &&
+                            streq_ptr(x11_model, a[2])) {
+                                matching++;
+
+                                if (streq_ptr(x11_variant, a[3])) {
+                                        matching++;
+
+                                        if (streq_ptr(x11_options, a[4]))
+                                                matching++;
+                                }
+                        }
+
+                        /* The best matching entry so far, then let's
+                         * save that */
+                        if (matching > best_matching) {
+                                best_matching = matching;
+
+                                free(new_keymap);
+                                new_keymap = strdup(a[0]);
+
+                                if (!new_keymap) {
+                                        strv_free(a);
+                                        fclose(f);
+                                        return -ENOMEM;
+                                }
+                        }
+
+                        strv_free(a);
+                }
+
+                fclose(f);
+
+                if (!streq_ptr(vc_keymap, new_keymap)) {
+                        free(vc_keymap);
+                        vc_keymap = new_keymap;
+
+                        free(vc_keymap_toggle);
+                        vc_keymap_toggle = NULL;
+
+                        modified = true;
+                } else
+                        free(new_keymap);
+        }
+
+        if (modified) {
+                dbus_bool_t b;
+                DBusMessage *changed;
+                int r;
+
+                r = write_data_vconsole();
+                if (r < 0)
+                        log_error("Failed to set virtual console keymap: %s", strerror(-r));
+
+                changed = bus_properties_changed_new(
+                                "/org/freedesktop/locale1",
+                                "org.freedesktop.locale1",
+                                "VConsoleKeymap\0"
+                                "VConsoleKeymapToggle\0");
+
+                if (!changed)
+                        return -ENOMEM;
+
+                b = dbus_connection_send(connection, changed, NULL);
+                dbus_message_unref(changed);
+
+                if (!b)
+                        return -ENOMEM;
+
+                return load_vconsole_keymap(connection, NULL);
+        }
+
+        return 0;
+}
+
 static int append_locale(DBusMessageIter *i, const char *property, void *userdata) {
         int r, c = 0, p;
         char **l;
@@ -353,7 +1007,13 @@ static DBusHandlerResult locale_message_handler(
                 void *userdata) {
 
         const BusProperty properties[] = {
-                { "org.freedesktop.locale1", "Locale", append_locale, "as", NULL},
+                { "org.freedesktop.locale1", "Locale",               append_locale,              "as", NULL                   },
+                { "org.freedesktop.locale1", "X11Layout",            bus_property_append_string, "s",  x11_layout             },
+                { "org.freedesktop.locale1", "X11Model",             bus_property_append_string, "s",  x11_model              },
+                { "org.freedesktop.locale1", "X11Variant",           bus_property_append_string, "s",  x11_variant            },
+                { "org.freedesktop.locale1", "X11Options",           bus_property_append_string, "s",  x11_options            },
+                { "org.freedesktop.locale1", "VConsoleKeymap",       bus_property_append_string, "s",  vc_keymap              },
+                { "org.freedesktop.locale1", "VConsoleKeymapToggle", bus_property_append_string, "s",  vc_keymap_toggle       },
                 { NULL, NULL, NULL, NULL, NULL }
         };
 
@@ -459,6 +1119,8 @@ static DBusHandlerResult locale_message_handler(
                                 }
                         }
 
+                        strv_free(l);
+
                         for (p = 0; p < _PROP_MAX; p++) {
                                 if (passed[p])
                                         continue;
@@ -469,7 +1131,7 @@ static DBusHandlerResult locale_message_handler(
 
                         simplify();
 
-                        r = write_data();
+                        r = write_data_locale();
                         if (r < 0) {
                                 log_error("Failed to set locale: %s", strerror(-r));
                                 return bus_send_error_reply(connection, message, NULL, r);
@@ -486,10 +1148,139 @@ static DBusHandlerResult locale_message_handler(
                         if (!changed)
                                 goto oom;
                 }
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetVConsoleKeyboard")) {
 
+                const char *keymap, *keymap_toggle;
+                dbus_bool_t convert, interactive;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &keymap,
+                                    DBUS_TYPE_STRING, &keymap_toggle,
+                                    DBUS_TYPE_BOOLEAN, &convert,
+                                    DBUS_TYPE_BOOLEAN, &interactive,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (isempty(keymap))
+                        keymap = NULL;
+
+                if (isempty(keymap_toggle))
+                        keymap_toggle = NULL;
+
+                if (!streq_ptr(keymap, vc_keymap) ||
+                    !streq_ptr(keymap_toggle, vc_keymap_toggle)) {
+
+                        r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, &error);
+                        if (r < 0)
+                                return bus_send_error_reply(connection, message, &error, r);
+
+                        if (free_and_set(&vc_keymap, keymap) < 0 ||
+                            free_and_set(&vc_keymap_toggle, keymap_toggle) < 0)
+                                goto oom;
+
+                        r = write_data_vconsole();
+                        if (r < 0) {
+                                log_error("Failed to set virtual console keymap: %s", strerror(-r));
+                                return bus_send_error_reply(connection, message, NULL, r);
+                        }
+
+                        log_info("Changed virtual console keymap to '%s'", strempty(vc_keymap));
+
+                        r = load_vconsole_keymap(connection, NULL);
+                        if (r < 0)
+                                log_error("Failed to request keymap reload: %s", strerror(-r));
+
+                        changed = bus_properties_changed_new(
+                                        "/org/freedesktop/locale1",
+                                        "org.freedesktop.locale1",
+                                        "VConsoleKeymap\0"
+                                        "VConsoleKeymapToggle\0");
+                        if (!changed)
+                                goto oom;
+
+                        if (convert) {
+                                r = convert_vconsole_to_x11(connection);
+
+                                if (r < 0)
+                                        log_error("Failed to convert keymap data: %s", strerror(-r));
+                        }
+                }
+
+        } else if (dbus_message_is_method_call(message, "org.freedesktop.locale1", "SetX11Keyboard")) {
+
+                const char *layout, *model, *variant, *options;
+                dbus_bool_t convert, interactive;
+
+                if (!dbus_message_get_args(
+                                    message,
+                                    &error,
+                                    DBUS_TYPE_STRING, &layout,
+                                    DBUS_TYPE_STRING, &model,
+                                    DBUS_TYPE_STRING, &variant,
+                                    DBUS_TYPE_STRING, &options,
+                                    DBUS_TYPE_BOOLEAN, &convert,
+                                    DBUS_TYPE_BOOLEAN, &interactive,
+                                    DBUS_TYPE_INVALID))
+                        return bus_send_error_reply(connection, message, &error, -EINVAL);
+
+                if (isempty(layout))
+                        layout = NULL;
+
+                if (isempty(model))
+                        model = NULL;
+
+                if (isempty(variant))
+                        variant = NULL;
+
+                if (isempty(options))
+                        options = NULL;
+
+                if (!streq_ptr(layout, x11_layout) ||
+                    !streq_ptr(model, x11_model) ||
+                    !streq_ptr(variant, x11_variant) ||
+                    !streq_ptr(options, x11_options)) {
+
+                        r = verify_polkit(connection, message, "org.freedesktop.locale1.set-keyboard", interactive, &error);
+                        if (r < 0)
+                                return bus_send_error_reply(connection, message, &error, r);
+
+                        if (free_and_set(&x11_layout, layout) < 0 ||
+                            free_and_set(&x11_model, model) < 0 ||
+                            free_and_set(&x11_variant, variant) < 0 ||
+                            free_and_set(&x11_options, options) < 0)
+                                goto oom;
+
+                        r = write_data_x11();
+                        if (r < 0) {
+                                log_error("Failed to set X11 keyboard layout: %s", strerror(-r));
+                                return bus_send_error_reply(connection, message, NULL, r);
+                        }
+
+                        log_info("Changed X11 keyboard layout to '%s'", strempty(x11_layout));
+
+                        changed = bus_properties_changed_new(
+                                        "/org/freedesktop/locale1",
+                                        "org.freedesktop.locale1",
+                                        "X11Layout\0"
+                                        "X11Model\0"
+                                        "X11Variant\0"
+                                        "X11Options\0");
+                        if (!changed)
+                                goto oom;
+
+                        if (convert) {
+                                r = convert_x11_to_vconsole(connection);
+
+                                if (r < 0)
+                                        log_error("Failed to convert keymap data: %s", strerror(-r));
+                        }
+                }
         } else
                 return bus_default_message_handler(connection, message, INTROSPECTION, INTERFACES_LIST, properties);
 
+
         if (!(reply = dbus_message_new_method_return(message)))
                 goto oom;
 
index 53058d0..89762b6 100644 (file)
@@ -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;
index b8f7d67..0550d1b 100644 (file)
@@ -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) {
@@ -404,12 +405,16 @@ static int bus_manager_create_session(Manager *m, DBusMessage *message, DBusMess
                                 goto fail;
                         }
 
+                        seat = session->seat ? session->seat->id : "";
+                        vtnr = session->vtnr;
                         b = dbus_message_append_args(
                                         reply,
                                         DBUS_TYPE_STRING, &session->id,
                                         DBUS_TYPE_OBJECT_PATH, &p,
                                         DBUS_TYPE_STRING, &session->user->runtime_path,
                                         DBUS_TYPE_UNIX_FD, &fifo_fd,
+                                        DBUS_TYPE_STRING, &seat,
+                                        DBUS_TYPE_UINT32, &vtnr,
                                         DBUS_TYPE_INVALID);
                         free(p);
 
@@ -421,6 +426,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;
                 }
 
@@ -965,8 +973,11 @@ static DBusHandlerResult manager_message_handler(
         } else if (dbus_message_is_method_call(message, "org.freedesktop.login1.Manager", "CreateSession")) {
 
                 r = bus_manager_create_session(m, message, &reply);
-                if (r == -ENOMEM)
-                        goto oom;
+
+                /* Don't delay the work on OOM here, since it might be
+                 * triggered by a low RLIMIT_NOFILE here (since we
+                 * send a dupped fd to the client), and we'd rather
+                 * see this fail quickly then be retried later */
 
                 if (r < 0)
                         return bus_send_error_reply(connection, message, &error, r);
index 1aad48d..4633a5e 100644 (file)
@@ -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;
index bfc48e5..5c28a6c 100644 (file)
@@ -52,6 +52,7 @@
 #include "build.h"
 #include "strv.h"
 #include "def.h"
+#include "virt.h"
 
 static enum {
         ACTION_RUN,
index 6311c10..111167a 100644 (file)
@@ -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
@@ -285,7 +286,10 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
                 goto fail;
 
 #ifdef HAVE_AUDIT
-        if ((m->audit_fd = audit_open()) < 0)
+        if ((m->audit_fd = audit_open()) < 0 &&
+            /* If the kernel lacks netlink or audit support,
+             * don't worry about it. */
+            errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
                 log_error("Failed to connect to audit log: %m");
 #endif
 
@@ -1213,13 +1217,18 @@ static int transaction_apply(Manager *m, JobMode mode) {
 
                 /* When isolating first kill all installed jobs which
                  * aren't part of the new transaction */
+        rescan:
                 HASHMAP_FOREACH(j, m->jobs, i) {
                         assert(j->installed);
 
                         if (hashmap_get(m->transaction_jobs, j->unit))
                                 continue;
 
-                        job_finish_and_invalidate(j, JOB_CANCELED);
+                        /* 'j' itself is safe to remove, but if other jobs
+                           are invalidated recursively, our iterator may become
+                           invalid and we need to start over. */
+                        if (job_finish_and_invalidate(j, JOB_CANCELED) > 0)
+                                goto rescan;
                 }
         }
 
@@ -2111,11 +2120,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 +2242,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;
                         }
 
@@ -2282,7 +2292,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));
                         }
                 }
                 }
index 4b3b121..8dd98f7 100644 (file)
@@ -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");
index 829c2cc..f9cfe91 100644 (file)
@@ -320,11 +320,14 @@ 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) {
-        const char *target, *after = NULL;
+        const char *target, *after = NULL, *after2 = NULL;
         MountParameters *p;
         Unit *tu;
         int r;
@@ -354,9 +357,12 @@ static int mount_add_fstab_links(Mount *m) {
 
         if (mount_is_network(p)) {
                 target = SPECIAL_REMOTE_FS_TARGET;
-                after = SPECIAL_NETWORK_TARGET;
-        } else
+                after = SPECIAL_REMOTE_FS_PRE_TARGET;
+                after2 = SPECIAL_NETWORK_TARGET;
+        } else {
                 target = SPECIAL_LOCAL_FS_TARGET;
+                after = SPECIAL_LOCAL_FS_PRE_TARGET;
+        }
 
         if (!path_equal(m->where, "/"))
                 if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0)
@@ -369,6 +375,10 @@ static int mount_add_fstab_links(Mount *m) {
                 if ((r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true)) < 0)
                         return r;
 
+        if (after2)
+                if ((r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after2, NULL, true)) < 0)
+                        return r;
+
         if (automount) {
                 Unit *am;
 
index 8c3cf6b..653d7db 100644 (file)
@@ -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);
         }
 
@@ -359,7 +361,7 @@ static int drop_capabilities(void) {
 
         unsigned long l;
 
-        for (l = 0; l <= MAX(63LU, (unsigned long) CAP_LAST_CAP); l++) {
+        for (l = 0; l <= cap_last_cap(); l++) {
                 unsigned i;
 
                 for (i = 0; i < ELEMENTSOF(retain); i++)
@@ -370,12 +372,6 @@ static int drop_capabilities(void) {
                         continue;
 
                 if (prctl(PR_CAPBSET_DROP, l) < 0) {
-
-                        /* If this capability is not known, EINVAL
-                         * will be returned, let's ignore this. */
-                        if (errno == EINVAL)
-                                break;
-
                         log_error("PR_CAPBSET_DROP failed: %m");
                         return -errno;
                 }
@@ -725,6 +721,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 +729,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 +825,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;
                 }
index 186d7d3..1ac50bf 100644 (file)
                 </defaults>
         </action>
 
+        <action id="org.freedesktop.locale1.set-keyboard">
+                <_description>Set system keyboard settings</_description>
+                <_message>Authentication is required to set the system keyboard settings.</_message>
+                <defaults>
+                        <allow_any>auth_admin_keep</allow_any>
+                        <allow_inactive>auth_admin_keep</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+        </action>
+
 </policyconfig>
index be284da..3fc8182 100644 (file)
@@ -20,6 +20,7 @@
 ***/
 
 #include <sys/types.h>
+#include <fcntl.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <string.h>
 
 static pid_t pager_pid = 0;
 
+_noreturn_ static void pager_fallback(void) {
+        ssize_t n;
+        do {
+                n = splice(STDIN_FILENO, NULL, STDOUT_FILENO, NULL, 64*1024, 0);
+        } while (n > 0);
+        if (n < 0) {
+                log_error("Internal pager failed: %m");
+                _exit(EXIT_FAILURE);
+        }
+        _exit(EXIT_SUCCESS);
+}
+
 void pager_open(void) {
         int fd[2];
         const char *pager;
@@ -96,10 +109,9 @@ void pager_open(void) {
 
                 execlp("less", "less", NULL);
                 execlp("more", "more", NULL);
-                execlp("cat", "cat", NULL);
 
-                log_error("Unable to execute pager: %m");
-                _exit(EXIT_FAILURE);
+                pager_fallback();
+                /* not reached */
         }
 
         /* Return in the parent */
index 1d4aa21..f15c921 100644 (file)
@@ -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;
         }
 
index c475cec..60033a8 100644 (file)
@@ -26,6 +26,7 @@
 #include <unistd.h>
 
 #include "util.h"
+#include "virt.h"
 
 static bool arg_skip = false;
 static bool arg_force = false;
@@ -53,7 +54,7 @@ static int parse_proc_cmdline(void) {
                         arg_skip = true;
                 else if (startswith(w, "quotacheck.mode"))
                         log_warning("Invalid quotacheck.mode= parameter. Ignoring.");
-#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA)
+#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
                 else if (strneq(w, "forcequotacheck", l))
                         arg_force = true;
 #endif
@@ -64,8 +65,8 @@ static int parse_proc_cmdline(void) {
 }
 
 static void test_files(void) {
-#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA)
-        /* This exists only on Fedora or Mandriva */
+#if defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
+        /* This exists only on Fedora, Mandriva or Mageia */
         if (access("/forcequotacheck", F_OK) >= 0)
                 arg_force = true;
 #endif
index ee5cae3..0c63794 100644 (file)
@@ -51,7 +51,11 @@ int main(int argc, char *argv[]) {
 
         /* Read pool size, if possible */
         if ((f = fopen("/proc/sys/kernel/random/poolsize", "re"))) {
-                fscanf(f, "%zu", &buf_size);
+                if (fscanf(f, "%zu", &buf_size) > 0) {
+                        /* poolsize is in bits on 2.6, but we want bytes */
+                        buf_size /= 8;
+                }
+
                 fclose(f);
         }
 
index df467f1..eac11e7 100644 (file)
@@ -49,6 +49,7 @@
 #include "sd-daemon.h"
 #include "ioprio.h"
 #include "readahead-common.h"
+#include "virt.h"
 
 /* fixme:
  *
index 167df31..9547ad2 100644 (file)
@@ -27,7 +27,7 @@
 
 #include "macro.h"
 
-#define READAHEAD_FILE_SIZE_MAX (128*1024*1024)
+#define READAHEAD_FILE_SIZE_MAX (10*1024*1024)
 
 int file_verify(int fd, const char *fn, off_t file_size_max, struct stat *st);
 
index e97a0cf..65011ac 100644 (file)
@@ -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;
 
index 2489d78..a0a56c4 100644 (file)
@@ -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;
index 7102eb8..0cb0bf0 100644 (file)
@@ -83,7 +83,7 @@ int sd_session_get_seat(const char *session, char **seat);
 int sd_seat_get_active(const char *seat, char **session, uid_t *uid);
 
 /* Return sessions and users on seat. Returns number of sessions as
- * return value. If sessions is NULL returs only the number of
+ * return value. If sessions is NULL returns only the number of
  * sessions. */
 int sd_seat_get_sessions(const char *seat, char ***sessions, uid_t **uid, unsigned *n_uids);
 
@@ -94,7 +94,7 @@ int sd_seat_can_multi_session(const char *seat);
  * seats is NULL only returns number of seats. */
 int sd_get_seats(char ***seats);
 
-/* Get all sessions, store in *seessions. Returns the number of
+/* Get all sessions, store in *sessions. Returns the number of
  * sessions. If sessions is NULL only returns number of sessions. */
 int sd_get_sessions(char ***sessions);
 
index 2abd99e..a7e1fa4 100644 (file)
@@ -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
 
index abd8f36..eb475d9 100644 (file)
@@ -83,7 +83,7 @@ static const struct {
 
 #define RUNLEVELS_UP "12345"
 /* #define RUNLEVELS_DOWN "06" */
-/* #define RUNLEVELS_BOOT "bBsS" */
+#define RUNLEVELS_BOOT "bBsS"
 #endif
 
 static const UnitActiveState state_translation_table[_SERVICE_STATE_MAX] = {
@@ -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);
 
@@ -279,7 +277,8 @@ static int sysv_translate_facility(const char *name, const char *filename, char
         static const char * const table[] = {
                 /* LSB defined facilities */
                 "local_fs",             SPECIAL_LOCAL_FS_TARGET,
-#ifndef TARGET_MANDRIVA
+#if defined(TARGET_MANDRIVA) || defined(TARGET_MAGEIA)
+#else
                 /* Due to unfortunate name selection in Mandriva,
                  * $network is provided by network-up which is ordered
                  * after network which actually starts interfaces.
@@ -783,19 +782,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, "#  ")) {
@@ -826,6 +812,13 @@ static int service_load_sysv_path(Service *s, const char *path) {
 
         if ((r = sysv_exec_commands(s)) < 0)
                 goto finish;
+        if (s->sysv_runlevels &&
+            chars_intersect(RUNLEVELS_BOOT, s->sysv_runlevels) &&
+            chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
+                /* Service has both boot and "up" runlevels
+                   configured.  Kill the "up" ones. */
+                delete_chars(s->sysv_runlevels, RUNLEVELS_UP);
+        }
 
         if (s->sysv_runlevels && !chars_intersect(RUNLEVELS_UP, s->sysv_runlevels)) {
                 /* If there a runlevels configured for this service
@@ -844,10 +837,12 @@ static int service_load_sysv_path(Service *s, const char *path) {
         /* Special setting for all SysV services */
         s->type = SERVICE_FORKING;
         s->remain_after_exit = !s->pid_file;
+        s->guess_main_pid = false;
         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 +1108,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 +1154,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 +1290,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 +1319,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 +2614,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 +2749,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 +2760,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 +2770,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 +3124,7 @@ static int service_enumerate(Manager *m) {
 
                                 free(fpath);
                                 fpath = join(path, "/", de->d_name, NULL);
-                                if (!path) {
+                                if (!fpath) {
                                         r = -ENOMEM;
                                         goto finish;
                                 }
index 1c6dc65..11213f9 100644 (file)
@@ -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
index 572e622..7ddf326 100644 (file)
@@ -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;
 
index 614e53c..3fe34c9 100644 (file)
@@ -45,7 +45,9 @@
 #define SPECIAL_SYSINIT_TARGET "sysinit.target"
 #define SPECIAL_SOCKETS_TARGET "sockets.target"
 #define SPECIAL_LOCAL_FS_TARGET "local-fs.target"         /* LSB's $local_fs */
+#define SPECIAL_LOCAL_FS_PRE_TARGET "local-fs-pre.target"
 #define SPECIAL_REMOTE_FS_TARGET "remote-fs.target"       /* LSB's $remote_fs */
+#define SPECIAL_REMOTE_FS_PRE_TARGET "remote-fs-pre.target"
 #define SPECIAL_SWAP_TARGET "swap.target"
 #define SPECIAL_BASIC_TARGET "basic.target"
 
index 7358a42..9a04088 100644 (file)
@@ -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);
@@ -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;
index 92851b2..bb309d9 100644 (file)
@@ -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++)
index ab866a4..b8b356d 100644 (file)
@@ -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-bash-completion.sh b/src/systemctl-bash-completion.sh
deleted file mode 100644 (file)
index 6369a6c..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-# This file is part of systemd.
-#
-# Copyright 2010 Ran Benita
-#
-# 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/>.
-
-__contains_word () {
-        local word=$1; shift
-        for w in $*; do [[ $w = $word ]] && return 0; done
-        return 1
-}
-
-__filter_units_by_property () {
-        local property=$1 value=$2 ; shift ; shift
-        local -a units=( $* )
-        local -a props=( $(systemctl show --property "$property" -- ${units[*]} | grep -v ^$) )
-        for ((i=0; $i < ${#units[*]}; i++)); do
-                if [[ "${props[i]}" = "$property=$value" ]]; then
-                        echo "${units[i]}"
-                fi
-        done
-}
-
-__get_all_units      () { systemctl list-units --full --all | awk '                 {print $1}' ; }
-__get_active_units   () { systemctl list-units --full       | awk '                 {print $1}' ; }
-__get_inactive_units () { systemctl list-units --full --all | awk '$3 == "inactive" {print $1}' ; }
-__get_failed_units   () { systemctl list-units --full       | awk '$3 == "failed"   {print $1}' ; }
-
-_systemctl () {
-        local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
-        local verb comps
-
-        local -A OPTS=(
-               [STANDALONE]='--all -a --defaults --fail --ignore-dependencies --failed --force -f --full --global
-                             --help -h --no-ask-password --no-block --no-pager --no-reload --no-wall
-                             --order --require --quiet -q --privileged -P --system --user --version'
-                      [ARG]='--host -H --kill-mode --kill-who --property -p --signal -s --type -t'
-        )
-
-        if __contains_word "$prev" ${OPTS[ARG]}; then
-                case $prev in
-                        --signal|-s)
-                                comps=$(compgen -A signal | grep '^SIG' | grep -Ev 'RTMIN|RTMAX|JUNK')
-                        ;;
-                        --type|-t)
-                                comps='automount device mount path service snapshot socket swap target timer'
-                        ;;
-                        --kill-who)
-                                comps='all control main'
-                        ;;
-                        --kill-mode)
-                                comps='control-group process'
-                        ;;
-                        --property|-p|--host|-H)
-                                comps=''
-                        ;;
-                esac
-                COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
-                return 0
-        fi
-
-
-        if [[ "$cur" = -* ]]; then
-                COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") )
-                return 0
-        fi
-
-        local -A VERBS=(
-                [ALL_UNITS]='enable disable is-active is-enabled status show'
-             [FAILED_UNITS]='reset-failed'
-          [STARTABLE_UNITS]='start'
-          [STOPPABLE_UNITS]='stop kill try-restart condrestart'
-         [ISOLATABLE_UNITS]='isolate'
-         [RELOADABLE_UNITS]='reload reload-or-try-restart force-reload'
-          [RESTARTABLE_UNITS]='restart reload-or-restart'
-                     [JOBS]='cancel'
-                [SNAPSHOTS]='delete'
-                     [ENVS]='set-environment unset-environment'
-               [STANDALONE]='daemon-reexec daemon-reload default dot dump emergency exit halt kexec
-                             list-jobs list-units poweroff reboot rescue show-environment'
-                     [NAME]='snapshot load'
-        )
-
-        local verb
-        for ((i=0; $i <= $COMP_CWORD; i++)); do
-                if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} &&
-                 ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG}]}; then
-                        verb=${COMP_WORDS[i]}
-                        break
-                fi
-        done
-
-        if   [[ -z $verb ]]; then
-                comps="${VERBS[*]}"
-
-        elif __contains_word "$verb" ${VERBS[ALL_UNITS]}; then
-                comps=$( __get_all_units )
-
-        elif __contains_word "$verb" ${VERBS[STARTABLE_UNITS]}; then
-                comps=$( __filter_units_by_property CanStart yes \
-                      $( __get_inactive_units | grep -Ev '\.(device|snapshot)$' ))
-
-        elif __contains_word "$verb" ${VERBS[RESTARTABLE_UNITS]}; then
-                comps=$( __filter_units_by_property CanStart yes \
-                      $( __get_all_units | grep -Ev '\.(device|snapshot|socket|timer)$' ))
-
-        elif __contains_word "$verb" ${VERBS[STOPPABLE_UNITS]}; then
-                comps=$( __filter_units_by_property CanStop yes \
-                      $( __get_active_units ) )
-
-        elif __contains_word "$verb" ${VERBS[RELOADABLE_UNITS]}; then
-                comps=$( __filter_units_by_property CanReload yes \
-                      $( __get_active_units ) )
-
-        elif __contains_word "$verb" ${VERBS[ISOLATABLE_UNITS]}; then
-                comps=$( __filter_units_by_property AllowIsolate yes \
-                      $( __get_all_units ) )
-
-        elif __contains_word "$verb" ${VERBS[FAILED_UNITS]}; then
-                comps=$( __get_failed_units )
-
-        elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[NAME]}; then
-                comps=''
-
-        elif __contains_word "$verb" ${VERBS[JOBS]}; then
-                comps=$( systemctl list-jobs | awk '{print $1}' )
-
-        elif __contains_word "$verb" ${VERBS[SNAPSHOTS]}; then
-                comps=$( systemctl list-units --type snapshot --full --all | awk '{print $1}' )
-
-        elif __contains_word "$verb" ${VERBS[ENVS]}; then
-                comps=$( systemctl show-environment | sed 's_\([^=]\+=\).*_\1_' )
-                compopt -o nospace
-        fi
-
-        COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
-        return 0
-}
-complete -F _systemctl systemctl
index 7caeb6d..175159d 100644 (file)
@@ -66,6 +66,7 @@ static const char *arg_job_mode = "replace";
 static UnitFileScope arg_scope = UNIT_FILE_SYSTEM;
 static bool arg_immediate = false;
 static bool arg_no_block = false;
+static bool arg_no_legend = false;
 static bool arg_no_pager = false;
 static bool arg_no_wtmp = false;
 static bool arg_no_sync = false;
@@ -137,6 +138,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)
@@ -312,35 +315,60 @@ static bool output_show_unit(const struct unit_info *u) {
 }
 
 static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
-        unsigned active_len, sub_len, job_len, n_shown = 0;
+        unsigned id_len, max_id_len, active_len, sub_len, job_len, desc_len, n_shown = 0;
         const struct unit_info *u;
 
+        max_id_len = sizeof("UNIT")-1;
         active_len = sizeof("ACTIVE")-1;
         sub_len = sizeof("SUB")-1;
         job_len = sizeof("JOB")-1;
+        desc_len = 0;
 
         for (u = unit_infos; u < unit_infos + c; u++) {
                 if (!output_show_unit(u))
                         continue;
 
+                max_id_len = MAX(max_id_len, strlen(u->id));
                 active_len = MAX(active_len, strlen(u->active_state));
                 sub_len = MAX(sub_len, strlen(u->sub_state));
                 if (u->job_id != 0)
                         job_len = MAX(job_len, strlen(u->job_type));
         }
 
-        if (on_tty()) {
-                printf("%-25s %-6s %-*s %-*s %-*s", "UNIT", "LOAD",
+        if (!arg_full) {
+                unsigned basic_len;
+                id_len = MIN(max_id_len, 25);
+                basic_len = 5 + id_len + 6 + active_len + sub_len + job_len;
+                if (basic_len < (unsigned) columns()) {
+                        unsigned extra_len, incr;
+                        extra_len = columns() - basic_len;
+                        /* Either UNIT already got 25, or is fully satisfied.
+                         * Grant up to 25 to DESC now. */
+                        incr = MIN(extra_len, 25);
+                        desc_len += incr;
+                        extra_len -= incr;
+                        /* split the remaining space between UNIT and DESC,
+                         * but do not give UNIT more than it needs. */
+                        if (extra_len > 0) {
+                                incr = MIN(extra_len / 2, max_id_len - id_len);
+                                id_len += incr;
+                                desc_len += extra_len - incr;
+                        }
+                }
+        } else
+                id_len = max_id_len;
+
+        if (!arg_no_legend) {
+                printf("%-*s %-6s %-*s %-*s %-*s ", id_len, "UNIT", "LOAD",
                        active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
-                if (columns() >= 80+12 || arg_full || !arg_no_pager)
-                        printf(" %s\n", "DESCRIPTION");
+                if (!arg_full && arg_no_pager)
+                        printf("%.*s\n", desc_len, "DESCRIPTION");
                 else
-                        printf("\n");
+                        printf("%s\n", "DESCRIPTION");
         }
 
         for (u = unit_infos; u < unit_infos + c; u++) {
                 char *e;
-                int a = 0, b = 0;
                 const char *on_loaded, *off_loaded;
                 const char *on_active, *off_active;
 
@@ -362,39 +390,23 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
                 } else
                         on_active = off_active = "";
 
-                e = arg_full ? NULL : ellipsize(u->id, 25, 33);
+                e = arg_full ? NULL : ellipsize(u->id, id_len, 33);
 
-                printf("%-25s %s%-6s%s %s%-*s %-*s%s%n",
-                       e ? e : u->id,
+                printf("%-*s %s%-6s%s %s%-*s %-*s%s %-*s ",
+                       id_len, e ? e : u->id,
                        on_loaded, u->load_state, off_loaded,
                        on_active, active_len, u->active_state,
                        sub_len, u->sub_state, off_active,
-                       &a);
-
-                free(e);
-
-                a -= strlen(on_loaded) + strlen(off_loaded);
-                a -= strlen(on_active) + strlen(off_active);
-
-                if (u->job_id != 0)
-                        printf(" %-*s", job_len, u->job_type);
+                       job_len, u->job_id ? u->job_type : "");
+                if (!arg_full && arg_no_pager)
+                        printf("%.*s\n", desc_len, u->description);
                 else
-                        b = 1 + job_len;
-
-                if (a + b + 1 < columns()) {
-                        if (u->job_id == 0)
-                                printf(" %-*s", job_len, "");
+                        printf("%s\n", u->description);
 
-                        if (arg_full || !arg_no_pager)
-                                printf(" %s", u->description);
-                        else
-                                printf(" %.*s", columns() - a - b - 1, u->description);
-                }
-
-                fputs("\n", stdout);
+                free(e);
         }
 
-        if (on_tty()) {
+        if (!arg_no_legend) {
                 printf("\nLOAD   = Reflects whether the unit definition was properly loaded.\n"
                        "ACTIVE = The high-level unit activation state, i.e. generalization of SUB.\n"
                        "SUB    = The low-level unit activation state, values depend on unit type.\n"
@@ -539,11 +551,30 @@ static bool output_show_unit_file(const UnitFileList *u) {
 }
 
 static void output_unit_file_list(const UnitFileList *units, unsigned c) {
-        unsigned n_shown = 0;
+        unsigned max_id_len, id_cols, state_cols, n_shown = 0;
         const UnitFileList *u;
 
-        if (on_tty())
-                printf("%-25s %-6s\n", "UNIT FILE", "STATE");
+        max_id_len = sizeof("UNIT FILE")-1;
+        state_cols = sizeof("STATE")-1;
+        for (u = units; u < units + c; u++) {
+                if (!output_show_unit_file(u))
+                        continue;
+
+                max_id_len = MAX(max_id_len, strlen(file_name_from_path(u->path)));
+                state_cols = MAX(state_cols, strlen(unit_file_state_to_string(u->state)));
+        }
+
+        if (!arg_full) {
+                unsigned basic_cols;
+                id_cols = MIN(max_id_len, 25);
+                basic_cols = 1 + id_cols + state_cols;
+                if (basic_cols < (unsigned) columns())
+                        id_cols += MIN(columns() - basic_cols, max_id_len - id_cols);
+        } else
+                id_cols = max_id_len;
+
+        if (!arg_no_legend)
+                printf("%-*s %-*s\n", id_cols, "UNIT FILE", state_cols, "STATE");
 
         for (u = units; u < units + c; u++) {
                 char *e;
@@ -568,16 +599,16 @@ static void output_unit_file_list(const UnitFileList *units, unsigned c) {
 
                 id = file_name_from_path(u->path);
 
-                e = arg_full ? NULL : ellipsize(id, 25, 33);
+                e = arg_full ? NULL : ellipsize(id, id_cols, 33);
 
-                printf("%-25s %s%-6s%s\n",
-                       e ? e : id,
-                       on, unit_file_state_to_string(u->state), off);
+                printf("%-*s %s%-*s%s\n",
+                       id_cols, e ? e : id,
+                       on, state_cols, unit_file_state_to_string(u->state), off);
 
                 free(e);
         }
 
-        if (on_tty())
+        if (!arg_no_legend)
                 printf("\n%u unit files listed.\n", n_shown);
 }
 
@@ -608,6 +639,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 +1086,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 +1097,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 +1135,6 @@ finish:
         if (m)
                 dbus_message_unref(m);
 
-        if (reply)
-                dbus_message_unref(reply);
-
         dbus_error_free(&error);
 
         return r;
@@ -1794,7 +1824,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 +1841,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 +1881,6 @@ finish:
         if (m)
                 dbus_message_unref(m);
 
-        if (reply)
-                dbus_message_unref(reply);
-
         dbus_error_free(&error);
 
         return r;
@@ -2155,8 +2183,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 +3256,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 +3268,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 +3305,6 @@ finish:
         if (m)
                 dbus_message_unref(m);
 
-        if (reply)
-                dbus_message_unref(reply);
-
         dbus_error_free(&error);
 
         return r;
@@ -3438,7 +3462,7 @@ finish:
 static int enable_sysv_units(char **args) {
         int r = 0;
 
-#if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX))
+#if defined (HAVE_SYSV_COMPAT) && (defined(TARGET_FEDORA) || defined(TARGET_MANDRIVA) || defined(TARGET_SUSE) || defined(TARGET_MEEGO) || defined(TARGET_ALTLINUX) || defined(TARGET_MAGEIA))
         const char *verb = args[0];
         unsigned f = 1, t = 1;
         LookupPaths paths;
@@ -3929,6 +3953,7 @@ static int systemctl_help(void) {
                "     --no-wall        Don't send wall message before halt/power-off/reboot\n"
                "     --no-reload      When enabling/disabling unit files, don't reload daemon\n"
                "                      configuration\n"
+               "     --no-legend      Do not print a legend (column headers and hints)\n"
                "     --no-pager       Do not pipe output into a pager\n"
                "     --no-ask-password\n"
                "                      Do not ask for system passwords\n"
@@ -4079,6 +4104,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 ARG_SYSTEM,
                 ARG_GLOBAL,
                 ARG_NO_BLOCK,
+                ARG_NO_LEGEND,
                 ARG_NO_PAGER,
                 ARG_NO_WALL,
                 ARG_ORDER,
@@ -4107,6 +4133,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                 { "system",    no_argument,       NULL, ARG_SYSTEM    },
                 { "global",    no_argument,       NULL, ARG_GLOBAL    },
                 { "no-block",  no_argument,       NULL, ARG_NO_BLOCK  },
+                { "no-legend", no_argument,       NULL, ARG_NO_LEGEND },
                 { "no-pager",  no_argument,       NULL, ARG_NO_PAGER  },
                 { "no-wall",   no_argument,       NULL, ARG_NO_WALL   },
                 { "quiet",     no_argument,       NULL, 'q'           },
@@ -4195,6 +4222,10 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
                         arg_no_block = true;
                         break;
 
+                case ARG_NO_LEGEND:
+                        arg_no_legend = true;
+                        break;
+
                 case ARG_NO_PAGER:
                         arg_no_pager = true;
                         break;
@@ -4981,8 +5012,17 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
                         return 0;
                 }
 
+                if (!bus) {
+                        log_error("Failed to get D-Bus connection: %s",
+                                  dbus_error_is_set(error) ? error->message : "No connection to service manager.");
+                        return -EIO;
+                }
+
+        } else {
+
                 if (!bus && !avoid_bus()) {
-                        log_error("Failed to get D-Bus connection: %s", error->message);
+                        log_error("Failed to get D-Bus connection: %s",
+                                  dbus_error_is_set(error) ? error->message : "No connection to service manager.");
                         return -EIO;
                 }
         }
index ae7dcfb..729aa05 100755 (executable)
@@ -82,7 +82,7 @@ if len(sys.argv) <= 1 or sys.argv[1] == 'time':
         initrd_time, start_time, finish_time = acquire_start_time()
 
         if initrd_time > 0:
-                print "Startup finished in %lums (kernel) + %lums (initrd) + %lums (userspace) = %lums" % ( \
+                print "Startup finished in %lums (kernel) + %lums (initramfs) + %lums (userspace) = %lums" % ( \
                         initrd_time/1000, \
                         (start_time - initrd_time)/1000, \
                         (finish_time - start_time)/1000, \
@@ -116,7 +116,11 @@ elif sys.argv[1] == 'plot':
         data = acquire_time_data()
         s = sorted(data, key = lambda i: i[1])
 
-        count = 0
+        # Account for kernel and initramfs bars if they exist
+        if initrd_time > 0:
+                count = 3
+        else:
+                count = 2
 
         for name, ixt, aet, axt, iet in s:
 
@@ -130,7 +134,7 @@ elif sys.argv[1] == 'plot':
         bar_space = bar_height * 0.1
 
         # 1000px = 10s, 1px = 10ms
-        width = (finish_time - start_time)/10000 + border*2
+        width = finish_time/10000 + border*2
         height = count * (bar_height + bar_space) + border * 2
 
         if width < 1000:
@@ -147,7 +151,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, finish_time/10000 + 100, 100):
                 context.move_to(x, 0)
                 context.line_to(x, height-border*2)
 
@@ -163,11 +167,30 @@ 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, finish_time/10000 + 100, 100):
                 draw_text(context, x, -5, "%lus" % (x/100), vcenter = 0, hcenter = 0)
 
         y = 0
 
+        # draw boxes for kernel and initramfs boot time
+        if initrd_time > 0:
+                draw_box(context, 0, y, initrd_time/10000, bar_height, 0.7, 0.7, 0.7)
+                draw_text(context, 10, y + bar_height/2, "kernel", hcenter = 0)
+                y += bar_height + bar_space
+
+                draw_box(context, initrd_time/10000, y, start_time/10000-initrd_time/10000, bar_height, 0.7, 0.7, 0.7)
+                draw_text(context, initrd_time/10000 + 10, y + bar_height/2, "initramfs", hcenter = 0)
+                y += bar_height + bar_space
+
+        else:
+                draw_box(context, 0, y, start_time/10000, bar_height, 0.6, 0.6, 0.6)
+                draw_text(context, 10, y + bar_height/2, "kernel", hcenter = 0)
+                y += bar_height + bar_space
+
+        draw_box(context, start_time/10000, y, finish_time/10000-start_time/10000, bar_height, 0.7, 0.7, 0.7)
+        draw_text(context, start_time/10000 + 10, y + bar_height/2, "userspace", hcenter = 0)
+        y += bar_height + bar_space
+
         for name, ixt, aet, axt, iet in s:
 
                 drawn = False
@@ -176,7 +199,7 @@ elif sys.argv[1] == 'plot':
                 if ixt >= start_time and ixt <= finish_time:
 
                         # Activating
-                        a = ixt - start_time
+                        a = ixt
                         b = min(filter(lambda x: x >= ixt, (aet, axt, iet, finish_time))) - ixt
 
                         draw_box(context, a/10000, y, b/10000, bar_height, 1, 0, 0)
@@ -188,7 +211,7 @@ elif sys.argv[1] == 'plot':
                 if aet >= start_time and aet <= finish_time:
 
                         # Active
-                        a = aet - start_time
+                        a = aet
                         b = min(filter(lambda x: x >= aet, (axt, iet, finish_time))) - aet
 
                         draw_box(context, a/10000, y, b/10000, bar_height, .8, .6, .6)
@@ -200,7 +223,7 @@ elif sys.argv[1] == 'plot':
                 if axt >= start_time and axt <= finish_time:
 
                         # Deactivating
-                        a = axt - start_time
+                        a = axt
                         b = min(filter(lambda x: x >= axt, (iet, finish_time))) - axt
 
                         draw_box(context, a/10000, y, b/10000, bar_height, .6, .4, .4)
@@ -221,6 +244,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 (initramfs) + %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/systemd-bash-completion.sh b/src/systemd-bash-completion.sh
new file mode 100644 (file)
index 0000000..176591f
--- /dev/null
@@ -0,0 +1,264 @@
+# This file is part of systemd.
+#
+# Copyright 2010 Ran Benita
+#
+# 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/>.
+
+__systemctl() {
+        systemctl --full --no-legend "$@"
+}
+
+__contains_word () {
+        local word=$1; shift
+        for w in $*; do [[ $w = $word ]] && return 0; done
+        return 1
+}
+
+__filter_units_by_property () {
+        local property=$1 value=$2 ; shift ; shift
+        local -a units=( $* )
+        local -a props=( $(__systemctl show --property "$property" -- ${units[*]} | grep -v ^$) )
+        for ((i=0; $i < ${#units[*]}; i++)); do
+                if [[ "${props[i]}" = "$property=$value" ]]; then
+                        echo "${units[i]}"
+                fi
+        done
+}
+
+__get_all_units      () { __systemctl list-units --all | awk '                 {print $1}' ; }
+__get_active_units   () { __systemctl list-units       | awk '                 {print $1}' ; }
+__get_inactive_units () { __systemctl list-units --all | awk '$3 == "inactive" {print $1}' ; }
+__get_failed_units   () { __systemctl list-units       | awk '$3 == "failed"   {print $1}' ; }
+__get_enabled_units  () { __systemctl list-unit-files  | awk '$2 == "enabled"  {print $1}' ; }
+__get_disabled_units () { __systemctl list-unit-files  | awk '$2 == "disabled" {print $1}' ; }
+__get_masked_units   () { __systemctl list-unit-files  | awk '$2 == "masked"   {print $1}' ; }
+
+_systemctl () {
+        local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+        local verb comps
+
+        local -A OPTS=(
+               [STANDALONE]='--all -a --defaults --fail --ignore-dependencies --failed --force -f --full --global
+                             --help -h --no-ask-password --no-block --no-legend --no-pager --no-reload --no-wall
+                             --order --require --quiet -q --privileged -P --system --user --version --runtime'
+                      [ARG]='--host -H --kill-mode --kill-who --property -p --signal -s --type -t --root'
+        )
+
+        if __contains_word "$prev" ${OPTS[ARG]}; then
+                case $prev in
+                        --signal|-s)
+                                comps=$(compgen -A signal)
+                        ;;
+                        --type|-t)
+                                comps='automount device mount path service snapshot socket swap target timer'
+                        ;;
+                        --kill-who)
+                                comps='all control main'
+                        ;;
+                        --kill-mode)
+                                comps='control-group process'
+                        ;;
+                        --root)
+                                comps=$(compgen -A directory -- "$cur" )
+                                compopt -o filenames
+                        ;;
+                        --host|-H)
+                                comps=$(compgen -A hostname)
+                        ;;
+                        --property|-p)
+                                comps=''
+                        ;;
+                esac
+                COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
+                return 0
+        fi
+
+
+        if [[ "$cur" = -* ]]; then
+                COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") )
+                return 0
+        fi
+
+        local -A VERBS=(
+                [ALL_UNITS]='is-active is-enabled status show mask preset'
+            [ENABLED_UNITS]='disable reenable'
+           [DISABLED_UNITS]='enable'
+             [FAILED_UNITS]='reset-failed'
+          [STARTABLE_UNITS]='start'
+          [STOPPABLE_UNITS]='stop condstop kill try-restart condrestart'
+         [ISOLATABLE_UNITS]='isolate'
+         [RELOADABLE_UNITS]='reload condreload reload-or-try-restart force-reload'
+        [RESTARTABLE_UNITS]='restart reload-or-restart'
+             [MASKED_UNITS]='unmask'
+                     [JOBS]='cancel'
+                [SNAPSHOTS]='delete'
+                     [ENVS]='set-environment unset-environment'
+               [STANDALONE]='daemon-reexec daemon-reload default dot dump
+                             emergency exit halt kexec list-jobs list-units
+                             list-unit-files poweroff reboot rescue show-environment'
+                     [NAME]='snapshot load'
+                     [FILE]='link'
+        )
+
+        for ((i=0; $i <= $COMP_CWORD; i++)); do
+                if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} &&
+                 ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG}]}; then
+                        verb=${COMP_WORDS[i]}
+                        break
+                fi
+        done
+
+        if   [[ -z $verb ]]; then
+                comps="${VERBS[*]}"
+
+        elif __contains_word "$verb" ${VERBS[ALL_UNITS]}; then
+                comps=$( __get_all_units )
+
+        elif __contains_word "$verb" ${VERBS[ENABLED_UNITS]}; then
+                comps=$( __get_enabled_units )
+
+        elif __contains_word "$verb" ${VERBS[DISABLED_UNITS]}; then
+                comps=$( __get_disabled_units )
+
+        elif __contains_word "$verb" ${VERBS[STARTABLE_UNITS]}; then
+                comps=$( __filter_units_by_property CanStart yes \
+                      $( __get_inactive_units | grep -Ev '\.(device|snapshot)$' ))
+
+        elif __contains_word "$verb" ${VERBS[RESTARTABLE_UNITS]}; then
+                comps=$( __filter_units_by_property CanStart yes \
+                      $( __get_all_units | grep -Ev '\.(device|snapshot|socket|timer)$' ))
+
+        elif __contains_word "$verb" ${VERBS[STOPPABLE_UNITS]}; then
+                comps=$( __filter_units_by_property CanStop yes \
+                      $( __get_active_units ) )
+
+        elif __contains_word "$verb" ${VERBS[RELOADABLE_UNITS]}; then
+                comps=$( __filter_units_by_property CanReload yes \
+                      $( __get_active_units ) )
+
+        elif __contains_word "$verb" ${VERBS[ISOLATABLE_UNITS]}; then
+                comps=$( __filter_units_by_property AllowIsolate yes \
+                      $( __get_all_units ) )
+
+        elif __contains_word "$verb" ${VERBS[FAILED_UNITS]}; then
+                comps=$( __get_failed_units )
+
+        elif __contains_word "$verb" ${VERBS[MASKED_UNITS]}; then
+                comps=$( __get_masked_units )
+
+        elif __contains_word "$verb" ${VERBS[STANDALONE]} ${VERBS[NAME]}; then
+                comps=''
+
+        elif __contains_word "$verb" ${VERBS[JOBS]}; then
+                comps=$( __systemctl list-jobs | awk '{print $1}' )
+
+        elif __contains_word "$verb" ${VERBS[SNAPSHOTS]}; then
+                comps=$( __systemctl list-units --type snapshot --full --all | awk '{print $1}' )
+
+        elif __contains_word "$verb" ${VERBS[ENVS]}; then
+                comps=$( __systemctl show-environment | sed 's_\([^=]\+=\).*_\1_' )
+                compopt -o nospace
+
+        elif __contains_word "$verb" ${VERBS[FILE]}; then
+                comps=$( compgen -A file -- "$cur" )
+                compopt -o filenames
+        fi
+
+        COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
+        return 0
+}
+complete -F _systemctl systemctl
+
+__get_all_sessions () { systemd-loginctl list-sessions | awk '{print $1}' ; }
+__get_all_users    () { systemd-loginctl list-users    | awk '{print $2}' ; }
+__get_all_seats    () { systemd-loginctl list-seats    | awk '{print $1}' ; }
+
+_systemd_loginctl () {
+        local cur=${COMP_WORDS[COMP_CWORD]} prev=${COMP_WORDS[COMP_CWORD-1]}
+        local verb comps
+
+        local -A OPTS=(
+               [STANDALONE]='--all -a --help -h --no-pager --privileged -P --version'
+                      [ARG]='--host -H --kill-who --property -p --signal -s'
+        )
+
+        if __contains_word "$prev" ${OPTS[ARG]}; then
+                case $prev in
+                        --signal|-s)
+                                comps=$(compgen -A signal)
+                        ;;
+                        --kill-who)
+                                comps='all leader'
+                        ;;
+                        --host|-H)
+                                comps=$(compgen -A hostname)
+                        ;;
+                        --property|-p)
+                                comps=''
+                        ;;
+                esac
+                COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
+                return 0
+        fi
+
+
+        if [[ "$cur" = -* ]]; then
+                COMPREPLY=( $(compgen -W "${OPTS[*]}" -- "$cur") )
+                return 0
+        fi
+
+        local -A VERBS=(
+                [SESSIONS]='session-status show-session activate lock-session unlock-session terminate-session kill-session'
+                [USERS]='user-status show-user enable-linger disable-linger terminate-user kill-user'
+                [SEATS]='seat-status show-seat terminate-seat'
+                [STANDALONE]='list-sessions list-users list-seats flush-devices'
+                [ATTACH]='attach'
+        )
+
+        for ((i=0; $i <= $COMP_CWORD; i++)); do
+                if __contains_word "${COMP_WORDS[i]}" ${VERBS[*]} &&
+                 ! __contains_word "${COMP_WORDS[i-1]}" ${OPTS[ARG}]}; then
+                        verb=${COMP_WORDS[i]}
+                        break
+                fi
+        done
+
+        if   [[ -z $verb ]]; then
+                comps="${VERBS[*]}"
+
+        elif __contains_word "$verb" ${VERBS[SESSIONS]}; then
+                comps=$( __get_all_sessions )
+
+        elif __contains_word "$verb" ${VERBS[USERS]}; then
+                comps=$( __get_all_users )
+
+        elif __contains_word "$verb" ${VERBS[SEATS]}; then
+                comps=$( __get_all_seats )
+
+        elif __contains_word "$verb" ${VERBS[STANDALONE]}; then
+                comps=''
+
+        elif __contains_word "$verb" ${VERBS[ATTACH]}; then
+                if [[ $prev = $verb ]]; then
+                        comps=$( __get_all_seats )
+                else
+                        comps=$(compgen -A file -- "$cur" )
+                        compopt -o filenames
+                fi
+        fi
+
+        COMPREPLY=( $(compgen -W "$comps" -- "$cur") )
+        return 0
+}
+complete -F _systemd_loginctl systemd-loginctl
index 66e50a6..16f54b5 100644 (file)
@@ -170,8 +170,24 @@ static int read_data(void) {
         free_data();
 
         r = read_one_line_file("/etc/timezone", &zone);
-        if (r < 0 && r != -ENOENT)
-                return r;
+        if (r < 0) {
+                if (r != -ENOENT)
+                        log_warning("Failed to read /etc/timezone: %s", strerror(-r));
+
+#ifdef TARGET_FEDORA
+                r = parse_env_file("/etc/sysconfig/clock", NEWLINE,
+                                   "ZONE", &zone,
+                                   NULL);
+
+                if (r < 0 && r != -ENOENT)
+                        log_warning("Failed to read /etc/sysconfig/clock: %s", strerror(-r));
+#endif
+        }
+
+        if (isempty(zone)) {
+                free(zone);
+                zone = NULL;
+        }
 
         verify_timezone();
 
@@ -246,7 +262,7 @@ static int write_data_local_rtc(void) {
 
                 p++;
                 e = strchr(p, '\n');
-                if (!p) {
+                if (!e) {
                         free(s);
                         return -EIO;
                 }
index a6b8f85..21bf44d 100644 (file)
@@ -157,6 +157,7 @@ static void load_unix_sockets(void) {
                 }
         }
 
+        fclose(f);
         return;
 
 fail:
index 43d008f..13481b2 100644 (file)
@@ -206,6 +206,7 @@ static int ask_password_plymouth(
                                 continue;
 
                         memcpy(&size, buffer+1, sizeof(size));
+                        size = le32toh(size);
                         if (size+5 > sizeof(buffer)) {
                                 r = -EIO;
                                 goto finish;
index 67be42e..4e036d8 100644 (file)
@@ -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)
index 3ce87ea..903a8e4 100644 (file)
@@ -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;
         }
index f81e7f4..12e4d11 100644 (file)
@@ -376,7 +376,10 @@ int main(int argc, char *argv[]) {
         umask(0022);
 
 #ifdef HAVE_AUDIT
-        if ((c.audit_fd = audit_open()) < 0)
+        if ((c.audit_fd = audit_open()) < 0 &&
+            /* If the kernel lacks netlink or audit support,
+             * don't worry about it. */
+            errno != EAFNOSUPPORT && errno != EPROTONOSUPPORT)
                 log_error("Failed to connect to audit log: %m");
 #endif
 
index 6033aa0..e93e6f6 100644 (file)
@@ -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;
 
@@ -2313,8 +2307,10 @@ int chvt(int vt) {
                         0
                 };
 
-                if (ioctl(fd, TIOCLINUX, tiocl) < 0)
-                        return -errno;
+                if (ioctl(fd, TIOCLINUX, tiocl) < 0) {
+                        r = -errno;
+                        goto fail;
+                }
 
                 vt = tiocl[0] <= 0 ? 1 : tiocl[0];
         }
@@ -2322,7 +2318,8 @@ int chvt(int vt) {
         if (ioctl(fd, VT_ACTIVATE, vt) < 0)
                 r = -errno;
 
-        close_nointr_nofail(r);
+fail:
+        close_nointr_nofail(fd);
         return r;
 }
 
@@ -4273,224 +4270,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 +5308,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 +5411,8 @@ char *join(const char *x, ...) {
 
                         p = stpcpy(p, t);
                 }
+
+                va_end(ap);
         } else
                 r[0] = 0;
 
@@ -5815,7 +5599,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 +5635,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;
@@ -5864,3 +5685,54 @@ bool kexec_loaded(void) {
        }
        return loaded;
 }
+
+int strdup_or_null(const char *a, char **b) {
+        char *c;
+
+        assert(b);
+
+        if (!a) {
+                *b = NULL;
+                return 0;
+        }
+
+        c = strdup(a);
+        if (!c)
+                return -ENOMEM;
+
+        *b = c;
+        return 0;
+}
+
+unsigned long cap_last_cap(void) {
+        static __thread unsigned long saved;
+        static __thread bool valid = false;
+        unsigned long p;
+
+        if (valid)
+                return saved;
+
+        p = (unsigned long) CAP_LAST_CAP;
+
+        if (prctl(PR_CAPBSET_READ, p) < 0) {
+
+                /* Hmm, look downwards, until we find one that
+                 * works */
+                for (p--; p > 0; p --)
+                        if (prctl(PR_CAPBSET_READ, p) >= 0)
+                                break;
+
+        } else {
+
+                /* Hmm, look upwards, until we find one that doesn't
+                 * work */
+                for (;; p++)
+                        if (prctl(PR_CAPBSET_READ, p+1) < 0)
+                                break;
+        }
+
+        saved = p;
+        valid = true;
+
+        return p;
+}
index 3e1f46d..a71a297 100644 (file)
@@ -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);
@@ -469,6 +467,8 @@ int block_get_whole_disk(dev_t d, dev_t *ret);
 
 int file_is_sticky(const char *p);
 
+int strdup_or_null(const char *a, char **b);
+
 #define NULSTR_FOREACH(i, l)                                    \
         for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
 
@@ -506,4 +506,6 @@ extern char **saved_argv;
 
 bool kexec_loaded(void);
 
+unsigned long cap_last_cap(void);
+
 #endif
index 4347a20..9196789 100644 (file)
@@ -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];
@@ -159,7 +160,7 @@ int main(int argc, char **argv) {