summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTollef Fog Heen <tfheen@err.no>2011-03-01 17:05:35 +0100
committerTollef Fog Heen <tfheen@err.no>2011-03-01 17:05:35 +0100
commit8a796f3efa44f101c361d9c26252722a14e417f5 (patch)
tree87277f4c01fd46d81625be6c89d44fd609d906bf
parentf6f2f49345fd75fb27af159d96f17fa10e0181bb (diff)
parent020501d9524c2cba58873198c59909c9d591c292 (diff)
downloadsystemd-8a796f3efa44f101c361d9c26252722a14e417f5.tar.gz
systemd-8a796f3efa44f101c361d9c26252722a14e417f5.tar.bz2
systemd-8a796f3efa44f101c361d9c26252722a14e417f5.zip
Merge commit 'v19'
-rw-r--r--.gitignore1
-rw-r--r--CODING_STYLE2
-rw-r--r--Makefile.am28
-rw-r--r--README21
-rw-r--r--TODO59
-rw-r--r--configure.ac4
-rw-r--r--man/daemon.xml4
-rw-r--r--man/systemd.exec.xml2
-rw-r--r--man/systemd.unit.xml26
-rw-r--r--src/99-systemd.rules11
-rw-r--r--src/ask-password-api.c69
-rw-r--r--src/ask-password-api.h4
-rw-r--r--src/ask-password.c68
-rw-r--r--src/automount.c4
-rw-r--r--src/cgroups-agent.c2
-rw-r--r--src/condition.c29
-rw-r--r--src/condition.h1
-rw-r--r--src/cryptsetup.c131
-rw-r--r--src/dbus-job.c10
-rw-r--r--src/dbus-job.h4
-rw-r--r--src/dbus-manager.c2
-rw-r--r--src/dbus-path.c16
-rw-r--r--src/dbus-timer.c16
-rw-r--r--src/dbus.c3
-rw-r--r--src/detect-virt.c46
-rw-r--r--src/device.c4
-rw-r--r--src/device.h2
-rw-r--r--src/execute.c16
-rw-r--r--src/job.c54
-rw-r--r--src/job.h19
-rw-r--r--src/kmsg-syslogd.c2
-rw-r--r--src/label.c6
-rw-r--r--src/label.h3
-rw-r--r--src/load-fragment.c30
-rw-r--r--src/log.c8
-rw-r--r--src/logger.c6
-rw-r--r--src/main.c42
-rw-r--r--src/manager.c10
-rw-r--r--src/manager.h4
-rw-r--r--src/mount-setup.c4
-rw-r--r--src/mount.c2
-rw-r--r--src/namespace.c4
-rw-r--r--src/ratelimit.c14
-rw-r--r--src/ratelimit.h8
-rw-r--r--src/readahead-collect.c7
-rw-r--r--src/readahead-replay.c6
-rw-r--r--src/sd-daemon.h4
-rw-r--r--src/securebits.h2
-rw-r--r--src/service.c24
-rw-r--r--src/shutdown.c2
-rw-r--r--src/socket.c4
-rw-r--r--src/strv.c48
-rw-r--r--src/strv.h2
-rw-r--r--src/swap.h2
-rw-r--r--src/systemadm.vala2
-rw-r--r--src/systemctl.c140
-rw-r--r--src/systemd-interfaces.vala2
-rw-r--r--src/test-engine.c6
-rw-r--r--src/test-env-replace.c8
-rw-r--r--src/test-job-type.c2
-rw-r--r--src/tmpfiles.c10
-rw-r--r--src/tty-ask-password-agent.c151
-rw-r--r--src/unit-name.c2
-rw-r--r--src/unit.c33
-rw-r--r--src/unit.h8
-rw-r--r--src/util.c289
-rw-r--r--src/util.h10
-rw-r--r--src/utmp-wtmp.c2
-rw-r--r--units/emergency.service4
-rw-r--r--units/fsck-root.service.in1
-rw-r--r--units/fsck@.service.in3
-rw-r--r--units/getty@.service.m45
-rw-r--r--units/plymouth-quit-wait.service15
-rw-r--r--units/plymouth-quit.service4
-rw-r--r--units/quotacheck.service.in1
-rw-r--r--units/rescue.service.m42
-rw-r--r--units/serial-getty@.service.m48
77 files changed, 1254 insertions, 356 deletions
diff --git a/.gitignore b/.gitignore
index 1bb184f875..adee97f6ce 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
+systemd-detect-virt
systemd-sysctl
test-strv
systemd-ac-power
diff --git a/CODING_STYLE b/CODING_STYLE
index 93f54f6edc..9341b48d41 100644
--- a/CODING_STYLE
+++ b/CODING_STYLE
@@ -20,7 +20,7 @@
we those lookups involve synchronously talking to services that we
would need to start up.
-- Do not acccess any directories outside of /etc/, /dev, /lib from the
+- Do not access any directories outside of /etc/, /dev, /lib from the
init daemon to avoid deadlocks with the automounter.
- Don't synchronously talk to any other service, due to risk of
diff --git a/Makefile.am b/Makefile.am
index f508163d5b..1841ad5c5a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -129,6 +129,7 @@ rootlibexec_PROGRAMS = \
systemd-quotacheck \
systemd-timestamp \
systemd-ac-power \
+ systemd-detect-virt \
systemd-sysctl
if HAVE_LIBCRYPTSETUP
@@ -242,7 +243,6 @@ dist_systemunit_DATA = \
units/systemd-tmpfiles-clean.timer \
units/quotaon.service \
units/systemd-ask-password-wall.path \
- units/systemd-ask-password-plymouth.path \
units/systemd-ask-password-console.path
nodist_systemunit_DATA = \
@@ -269,7 +269,6 @@ nodist_systemunit_DATA = \
units/systemd-tmpfiles-clean.service \
units/systemd-user-sessions.service \
units/systemd-ask-password-wall.service \
- units/systemd-ask-password-plymouth.service \
units/systemd-ask-password-console.service \
units/systemd-sysctl.service \
units/syslog.target \
@@ -315,7 +314,6 @@ EXTRA_DIST = \
units/systemd-tmpfiles-clean.service.in \
units/systemd-user-sessions.service.in \
units/systemd-ask-password-wall.service.in \
- units/systemd-ask-password-plymouth.service.in \
units/systemd-ask-password-console.service.in \
units/systemd-sysctl.service.in \
units/syslog.target.in \
@@ -342,10 +340,18 @@ dist_systemunit_DATA += \
units/plymouth-start.service \
units/plymouth-read-write.service \
units/plymouth-quit.service \
+ units/plymouth-quit-wait.service \
units/plymouth-reboot.service \
units/plymouth-kexec.service \
units/plymouth-poweroff.service \
- units/plymouth-halt.service
+ units/plymouth-halt.service \
+ units/systemd-ask-password-plymouth.path
+
+nodist_systemunit_DATA += \
+ units/systemd-ask-password-plymouth.service
+
+EXTRA_DIST += \
+ units/systemd-ask-password-plymouth.service.in
endif
dist_doc_DATA = \
@@ -783,6 +789,15 @@ systemd_ac_power_LDADD = \
libsystemd-basic.la \
$(UDEV_LIBS)
+systemd_detect_virt_SOURCES = \
+ src/detect-virt.c
+
+systemd_detect_virt_CFLAGS = \
+ $(AM_CFLAGS)
+
+systemd_detect_virt_LDADD = \
+ libsystemd-basic.la
+
systemd_cryptsetup_SOURCES = \
src/cryptsetup.c \
src/ask-password-api.c
@@ -1292,8 +1307,9 @@ if HAVE_PLYMOUTH
$(LN_S) ../plymouth-start.service plymouth-start.service && \
$(LN_S) ../plymouth-read-write.service plymouth-read-write.service )
( cd $(DESTDIR)$(systemunitdir)/multi-user.target.wants && \
- rm -f plymouth-quit.service && \
- $(LN_S) ../plymouth-quit.service plymouth-quit.service )
+ rm -f plymouth-quit.service plymouth-quit-wait.service && \
+ $(LN_S) ../plymouth-quit.service plymouth-quit.service && \
+ $(LN_S) ../plymouth-quit-wait.service plymouth-quit-wait.service )
( cd $(DESTDIR)$(systemunitdir)/reboot.target.wants && \
rm -f plymouth-reboot.service && \
$(LN_S) ../plymouth-reboot.service plymouth-reboot.service )
diff --git a/README b/README
index 0e5532aed7..a183cb364f 100644
--- a/README
+++ b/README
@@ -27,7 +27,7 @@ AUTHOR:
Lennart Poettering with major support from Kay Sievers
REQUIREMENTS:
- Linux kernel >= 2.6.30 (with autofs4, devtmpfs, cgroups)
+ Linux kernel >= 2.6.30 (with devtmpfs, cgroups; optional but strongly recommended: autofs4, ipv6)
libudev >= 163
dbus >= 1.4.0
libcap
@@ -47,10 +47,27 @@ REQUIREMENTS:
automake
autoconf
libtool
+ make, gcc, and similar tools
During runtime you need the following dependencies:
util-linux > v2.18 (requires fsck -l, agetty -s)
- sulogin (from sysvinit-tools)
+ sulogin (from sysvinit-tools, optional but recommended)
plymouth (optional)
dracut (optional)
+
+WARNINGS:
+ systemd will warn you during boot if /etc/mtab is not a
+ symlink to /proc/mounts. Please ensure that /etc/mtab is a
+ proper symlink.
+
+ systemd will warn you during boot if /usr is on a different
+ file system than /. While in systemd itself very little will
+ break if /usr is on a seperate partition many of its
+ dependencies very likely will break sooner or later in one
+ form or another. For example udev rules tend to refer to
+ binaries in /usr, binaries that link to libraries in /usr or
+ binaries that refer to data files in /usr. Since these
+ breakages are not always directly visible systemd will warn
+ about this, since this kind of file system setup is not really
+ supported anymore by the basic set of Linux OS components.
diff --git a/TODO b/TODO
index b205a88f37..a7ff18ab97 100644
--- a/TODO
+++ b/TODO
@@ -1,18 +1,44 @@
-Bugs:
+F15:
+
+* swap units that are activated by one name but shown in the kernel under another are semi-broken
+
+* dep cycle basic → udev-retry → auditd → iptables → basic
* isolate multi-user.target doesn't start a getty@tty1 if we run it from graphical.target
-* when plymouth is disabled the console password entry stuff seems to be borked
- https://bugzilla.redhat.com/show_bug.cgi?id=655538
+* finish syslog socket stuff
+
+* load EnvironmentFile= when starting services, not when reloading configuration
+ https://bugzilla.redhat.com/show_bug.cgi?id=661282
+
+* drop IN_ATTRIB from inotify watches for .path units where possible to avoid
+ lots of wakeups due to /dev changing when we watch a subdir of /dev.
+
+* NFS, networkmanager ordering issue
+
+* add fstab fields to add wait timeouts, change Wants to Requires by local-fs.target
+
+* hook emergency.target into local-fs.target in some way as OnFailure with isolate
-* exclude java hsp files by default
- https://bugzilla.redhat.com/show_bug.cgi?id=527425
+* convince Karel to give us our own mount option prefix
Features:
-* Make use of UnknownInterface, UnknownObject
+* maybe implement "systemctl mask" and "systemctl unmask", but not
+ document it? When doing that add switch to make this temporary by
+ placing mask links in /dev.
+
+* introduce simple way to do mandatory conditions
+
+* detect LXC environment
+
+* invoke vhangup() before and after invoking getty
-* increase password timeout
+* skip readahead on physically r/o media
+
+* support "auto" and "comment=systemd.automount" at the same time for an fstab entry
+
+* Make use of UnknownInterface, UnknownObject
* look up crypto partition mount points via fstab to show to the user when prompting for a password
@@ -31,19 +57,8 @@ Features:
* support remote/ssh systemctl/systemadm, and local privileged access
-* finish syslog socket stuff
-
* configurable jitter for timer events
-* support caching password questions in plymouth and on the console
- https://bugzilla.redhat.com/show_bug.cgi?id=655538
-
-* load EnvironmentFile= when starting services, not when reloading configuration
- https://bugzilla.redhat.com/show_bug.cgi?id=661282
-
-* drop IN_ATTRIB from inotify watches for .path units where possible to avoid
- lots of wakeups due to /dev changing when we watch a subdir of /dev.
-
* Support ProcessNeededForShutdown=true to allow stuff like mdmon
to be killed very late after the rootfs is read only (?)
@@ -112,20 +127,12 @@ Features:
* allow runtime changing of log level and target
-Fedora:
-
-* chkconfig → systemd enable/daemon-reload glue
-
-* /var/lock, /var/run → what happens if rpm stuff is no %ghosted?
-
External:
* udisks should not use udisks-part-id, instead use blkid. also not probe /dev/loopxxx
* snd-seq should go, https://bugzilla.redhat.com/show_bug.cgi?id=676095
-* mount.tmpfs should be optimized, https://bugzilla.redhat.com/show_bug.cgi?id=676100
-
* gnome-shell python script/glxinfo/is-accelerated wech
* make cryptsetup lower --iter-time
diff --git a/configure.ac b/configure.ac
index ce5772d559..2cf31e4e84 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
AC_PREREQ(2.63)
-AC_INIT([systemd],[18],[systemd-devel@lists.freedesktop.org])
+AC_INIT([systemd],[19],[systemd-devel@lists.freedesktop.org])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
@@ -368,8 +368,10 @@ case $with_distro in
altlinux)
SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d
SYSTEM_SYSVRCND_PATH=/etc/rc.d
+ SPECIAL_SYSLOG_SERVICE=syslogd.service
AC_DEFINE(TARGET_ALTLINUX, [], [Target is ALTLinux])
M4_DISTRO_FLAG=-DTARGET_ALTLINUX=1
+ have_plymouth=true
;;
other)
AS_IF([test "x$with_syslog_service" = "x"],
diff --git a/man/daemon.xml b/man/daemon.xml
index 7e7039e07a..ea0e6d27f5 100644
--- a/man/daemon.xml
+++ b/man/daemon.xml
@@ -841,7 +841,7 @@ fi
%preun
if [ $1 -eq 0 ]; then
# On uninstall (not upgrade), disable and stop the units
- /bin/systemctl disable foobar.service foobar.socket >/dev/null 2>&amp;1 || :
+ /bin/systemctl --no-reload disable foobar.service foobar.socket >/dev/null 2>&amp;1 || :
/bin/systemctl stop foobar.service foobar.socket >/dev/null 2>&amp;1 || :
fi
@@ -870,7 +870,7 @@ fi</programlisting>
<programlisting>%triggerun -- foobar &lt; 0.47.11-1
if /sbin/chkconfig foobar ; then
- /bin/systemctl enable foobar.service foobar.socket >/dev/null 2>&amp;1 || :
+ /bin/systemctl --no-reload enable foobar.service foobar.socket >/dev/null 2>&amp;1 || :
fi</programlisting>
<para>Where 0.47.11-1 is the first package
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index e9576e1e72..1f79e1e19b 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -412,7 +412,7 @@
<filename>/dev/console</filename>.</para></listitem>
</varlistentry>
<varlistentry>
- <term><varname>SyslogIdentifer=</varname></term>
+ <term><varname>SyslogIdentifier=</varname></term>
<listitem><para>Sets the process name
to prefix log lines sent to syslog or
the kernel log buffer with. If not set
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 14ec4561b2..fa8821afe5 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -575,6 +575,7 @@
<term><varname>ConditionPathExists=</varname></term>
<term><varname>ConditionDirectoryNotEmpty=</varname></term>
<term><varname>ConditionKernelCommandLine=</varname></term>
+ <term><varname>ConditionVirtualization=</varname></term>
<term><varname>ConditionNull=</varname></term>
<listitem><para>Before starting a unit
@@ -615,7 +616,24 @@
assignment. In the latter case the
exact assignment is looked for with
right and left hand side
- matching. Finally,
+ matching. <varname>ConditionVirtualization=</varname>
+ may be used to check whether the
+ system is executed in a virtualized
+ environment and optionally test
+ whether it is a specific
+ implementation. Takes either boolean
+ value to check if being executed in any
+ virtual environment or one of the
+ <varname>qemu</varname>,
+ <varname>kvm</varname>,
+ <varname>vmware</varname>,
+ <varname>microsoft</varname>,
+ <varname>oracle</varname>,
+ <varname>xen</varname>,
+ <varname>openvz</varname> to test
+ against a specific implementation. The
+ test may be negated by prepending an
+ exclamation mark. Finally,
<varname>ConditionNull=</varname> may
be used to add a constant condition
check value to the unit. It takes a
@@ -623,9 +641,9 @@
<varname>false</varname> the condition
will always fail, otherwise
succeed. If multiple conditions are
- specified the unit will be executed
- if at least one of them applies
- (i.e. a logical OR is
+ specified the unit will be executed if
+ at least one of them applies (i.e. a
+ logical OR is
applied).</para></listitem>
</varlistentry>
</variablelist>
diff --git a/src/99-systemd.rules b/src/99-systemd.rules
index 0ac6d0023f..4fba6d4d0b 100644
--- a/src/99-systemd.rules
+++ b/src/99-systemd.rules
@@ -7,12 +7,17 @@
ACTION!="add|change", GOTO="systemd_end"
-KERNEL=="tty[0-9]|tty1[0-2]", TAG+="systemd"
-KERNEL=="ttyS*", TAG+="systemd"
+SUBSYSTEM=="tty", KERNEL=="tty[0-9]|tty1[0-2]", TAG+="systemd"
+SUBSYSTEM=="tty", KERNEL=="ttyS*", TAG+="systemd"
+SUBSYSTEM=="tty", KERNEL=="hvc*", TAG+="systemd"
+SUBSYSTEM=="tty", KERNEL=="ttyUSB*", TAG+="systemd"
SUBSYSTEM=="block", KERNEL!="ram*|loop*", TAG+="systemd"
SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
-SUBSYSTEM=="block", KERNEL!="ram*|loop*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"
+
+# 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
# use the /sys/subsystem path for this. Current vanilla kernels don't
diff --git a/src/ask-password-api.c b/src/ask-password-api.c
index 9f7023e328..af1b611f27 100644
--- a/src/ask-password-api.c
+++ b/src/ask-password-api.c
@@ -32,6 +32,7 @@
#include <sys/signalfd.h>
#include "util.h"
+#include "strv.h"
#include "ask-password-api.h"
@@ -110,7 +111,7 @@ int ask_password_tty(
y = now(CLOCK_MONOTONIC);
if (y > until) {
- r = -ETIMEDOUT;
+ r = -ETIME;
goto finish;
}
@@ -131,7 +132,7 @@ int ask_password_tty(
r = -errno;
goto finish;
} else if (k == 0) {
- r = -ETIMEDOUT;
+ r = -ETIME;
goto finish;
}
@@ -178,9 +179,6 @@ int ask_password_tty(
}
}
- if (ttyfd >= 0)
- loop_write(ttyfd, "\n", 1, false);
-
passphrase[p] = 0;
if (!(*_passphrase = strdup(passphrase))) {
@@ -195,8 +193,11 @@ finish:
close_nointr_nofail(notify);
if (ttyfd >= 0) {
- if (reset_tty)
+
+ if (reset_tty) {
+ loop_write(ttyfd, "\n", 1, false);
tcsetattr(ttyfd, TCSADRAIN, &old_termios);
+ }
close_nointr_nofail(ttyfd);
}
@@ -251,12 +252,12 @@ fail:
return r;
}
-
int ask_password_agent(
const char *message,
const char *icon,
usec_t until,
- char **_passphrase) {
+ bool accept_cached,
+ char ***_passphrases) {
enum {
FD_SOCKET,
@@ -273,6 +274,8 @@ int ask_password_agent(
sigset_t mask;
struct pollfd pollfd[_FD_MAX];
+ assert(_passphrases);
+
mkdir_p("/dev/.systemd/ask-password", 0755);
if ((fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY)) < 0) {
@@ -310,9 +313,11 @@ int ask_password_agent(
"[Ask]\n"
"PID=%lu\n"
"Socket=%s\n"
+ "AcceptCached=%i\n"
"NotAfter=%llu\n",
(unsigned long) getpid(),
socket_name,
+ accept_cached ? 1 : 0,
(unsigned long long) until);
if (message)
@@ -368,7 +373,7 @@ int ask_password_agent(
goto finish;
}
- if ((k = poll(pollfd, _FD_MAX, until-t/USEC_PER_MSEC)) < 0) {
+ if ((k = poll(pollfd, _FD_MAX, (until-t)/USEC_PER_MSEC)) < 0) {
if (errno == EINTR)
continue;
@@ -384,8 +389,10 @@ int ask_password_agent(
goto finish;
}
- if (pollfd[FD_SIGNAL].revents & POLLIN)
- break;
+ if (pollfd[FD_SIGNAL].revents & POLLIN) {
+ r = -EINTR;
+ goto finish;
+ }
if (pollfd[FD_SOCKET].revents != POLLIN) {
log_error("Unexpected poll() event.");
@@ -395,7 +402,7 @@ int ask_password_agent(
zero(iovec);
iovec.iov_base = passphrase;
- iovec.iov_len = sizeof(passphrase)-1;
+ iovec.iov_len = sizeof(passphrase);
zero(control);
zero(msghdr);
@@ -435,13 +442,21 @@ int ask_password_agent(
}
if (passphrase[0] == '+') {
- passphrase[n] = 0;
+ char **l;
- if (!(*_passphrase = strdup(passphrase+1))) {
+ if (!(l = strv_parse_nulstr(passphrase+1, n-1))) {
r = -ENOMEM;
goto finish;
}
+ if (strv_length(l) <= 0) {
+ strv_free(l);
+ log_error("Invalid packet");
+ continue;
+ }
+
+ *_passphrases = l;
+
} else if (passphrase[0] == '-') {
r = -ECANCELED;
goto finish;
@@ -481,12 +496,26 @@ finish:
return r;
}
-int ask_password_auto(const char *message, const char *icon, usec_t until, char **_passphrase) {
+int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases) {
assert(message);
- assert(_passphrase);
+ assert(_passphrases);
+
+ if (isatty(STDIN_FILENO)) {
+ int r;
+ char *s = NULL, **l = NULL;
+
+ if ((r = ask_password_tty(message, until, NULL, &s)) < 0)
+ return r;
+
+ l = strv_new(s, NULL);
+ free(s);
+
+ if (!l)
+ return -ENOMEM;
+
+ *_passphrases = l;
+ return r;
- if (isatty(STDIN_FILENO))
- return ask_password_tty(message, until, NULL, _passphrase);
- else
- return ask_password_agent(message, icon, until, _passphrase);
+ } else
+ return ask_password_agent(message, icon, until, accept_cached, _passphrases);
}
diff --git a/src/ask-password-api.h b/src/ask-password-api.h
index ec858bac78..fec8625a0f 100644
--- a/src/ask-password-api.h
+++ b/src/ask-password-api.h
@@ -26,8 +26,8 @@
int ask_password_tty(const char *message, usec_t until, const char *flag_file, char **_passphrase);
-int ask_password_agent(const char *message, const char *icon, usec_t until, char **_passphrase);
+int ask_password_agent(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases);
-int ask_password_auto(const char *message, const char *icon, usec_t until, char **_passphrase);
+int ask_password_auto(const char *message, const char *icon, usec_t until, bool accept_cached, char ***_passphrases);
#endif
diff --git a/src/ask-password.c b/src/ask-password.c
index 596c8e08f0..c77376482e 100644
--- a/src/ask-password.c
+++ b/src/ask-password.c
@@ -38,21 +38,26 @@
#include "log.h"
#include "macro.h"
#include "util.h"
+#include "strv.h"
#include "ask-password-api.h"
static const char *arg_icon = NULL;
static const char *arg_message = NULL;
static bool arg_use_tty = true;
static usec_t arg_timeout = 60 * USEC_PER_SEC;
+static bool arg_accept_cached = false;
+static bool arg_multiple = false;
static int help(void) {
printf("%s [OPTIONS...] MESSAGE\n\n"
"Query the user for a system passphrase, via the TTY or an UI agent.\n\n"
- " -h --help Show this help\n"
- " --icon=NAME Icon name\n"
- " --timeout=SEC Timeout in sec\n"
- " --no-tty Ask question via agent even on TTY\n",
+ " -h --help Show this help\n"
+ " --icon=NAME Icon name\n"
+ " --timeout=SEC Timeout in sec\n"
+ " --no-tty Ask question via agent even on TTY\n"
+ " --accept-cached Accept cached passwords\n"
+ " --multiple List multiple passwords if available\n",
program_invocation_short_name);
return 0;
@@ -63,15 +68,19 @@ static int parse_argv(int argc, char *argv[]) {
enum {
ARG_ICON = 0x100,
ARG_TIMEOUT,
- ARG_NO_TTY
+ ARG_NO_TTY,
+ ARG_ACCEPT_CACHED,
+ ARG_MULTIPLE
};
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "icon", required_argument, NULL, ARG_ICON },
- { "timeout", required_argument, NULL, ARG_TIMEOUT },
- { "no-tty", no_argument, NULL, ARG_NO_TTY },
- { NULL, 0, NULL, 0 }
+ { "help", no_argument, NULL, 'h' },
+ { "icon", required_argument, NULL, ARG_ICON },
+ { "timeout", required_argument, NULL, ARG_TIMEOUT },
+ { "no-tty", no_argument, NULL, ARG_NO_TTY },
+ { "accept-cached", no_argument, NULL, ARG_ACCEPT_CACHED },
+ { "multiple", no_argument, NULL, ARG_MULTIPLE },
+ { NULL, 0, NULL, 0 }
};
int c;
@@ -102,6 +111,14 @@ static int parse_argv(int argc, char *argv[]) {
arg_use_tty = false;
break;
+ case ARG_ACCEPT_CACHED:
+ arg_accept_cached = true;
+ break;
+
+ case ARG_MULTIPLE:
+ arg_multiple = true;
+ break;
+
case '?':
return -EINVAL;
@@ -122,7 +139,6 @@ static int parse_argv(int argc, char *argv[]) {
int main(int argc, char *argv[]) {
int r;
- char *password = NULL;
log_parse_environment();
log_open();
@@ -130,18 +146,32 @@ int main(int argc, char *argv[]) {
if ((r = parse_argv(argc, argv)) <= 0)
goto finish;
- if (arg_use_tty && isatty(STDIN_FILENO))
- r = ask_password_tty(arg_message, now(CLOCK_MONOTONIC) + arg_timeout, NULL, &password);
- else
- r = ask_password_agent(arg_message, arg_icon, now(CLOCK_MONOTONIC) + arg_timeout, &password);
+ if (arg_use_tty && isatty(STDIN_FILENO)) {
+ char *password = NULL;
+
+ if ((r = ask_password_tty(arg_message, now(CLOCK_MONOTONIC) + arg_timeout, NULL, &password)) >= 0) {
+ puts(password);
+ free(password);
+ }
+
+ } else {
+ char **l;
+
+ if ((r = ask_password_agent(arg_message, arg_icon, now(CLOCK_MONOTONIC) + arg_timeout, arg_accept_cached, &l)) >= 0) {
+ char **p;
+
+ STRV_FOREACH(p, l) {
+ puts(*p);
- if (r >= 0) {
- fputs(password, stdout);
- fflush(stdout);
+ if (!arg_multiple)
+ break;
+ }
+
+ strv_free(l);
+ }
}
finish:
- free(password);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
diff --git a/src/automount.c b/src/automount.c
index 9447c0d8fc..f6f83d43b6 100644
--- a/src/automount.c
+++ b/src/automount.c
@@ -305,7 +305,7 @@ static int open_dev_autofs(Manager *m) {
if (m->dev_autofs_fd >= 0)
return m->dev_autofs_fd;
- label_fix("/dev/autofs");
+ label_fix("/dev/autofs", false);
if ((m->dev_autofs_fd = open("/dev/autofs", O_CLOEXEC|O_RDONLY)) < 0) {
log_error("Failed to open /dev/autofs: %s", strerror(errno));
@@ -583,7 +583,7 @@ static void automount_enter_runnning(Automount *a) {
/* Before we do anything, let's see if somebody is playing games with us? */
if (lstat(a->where, &st) < 0) {
- log_warning("%s failed stat automount point: %m", a->meta.id);
+ log_warning("%s failed to stat automount point: %m", a->meta.id);
goto fail;
}
diff --git a/src/cgroups-agent.c b/src/cgroups-agent.c
index 3fd0de698f..7b4fca245d 100644
--- a/src/cgroups-agent.c
+++ b/src/cgroups-agent.c
@@ -46,7 +46,7 @@ int main(int argc, char *argv[]) {
/* We send this event to the private D-Bus socket and then the
* system instance will forward this to the system bus. We do
- * this to avoid an actviation loop when we start dbus when we
+ * this to avoid an activation loop when we start dbus when we
* are called when the dbus service is shut down. */
if (!(bus = dbus_connection_open_private("unix:abstract=/org/freedesktop/systemd1/private", &error))) {
diff --git a/src/condition.c b/src/condition.c
index 21da2eb9e9..630350ed36 100644
--- a/src/condition.c
+++ b/src/condition.c
@@ -64,6 +64,8 @@ static bool test_kernel_command_line(const char *parameter) {
size_t l, pl;
bool found = false;
+ assert(parameter);
+
if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
return false;
@@ -98,6 +100,28 @@ static bool test_kernel_command_line(const char *parameter) {
return found;
}
+static bool test_virtualization(const char *parameter) {
+ int r, b;
+ const char *id;
+
+ assert(parameter);
+
+ if ((r = detect_virtualization(&id)) < 0) {
+ log_warning("Failed to detect virtualization, ignoring: %s", strerror(-r));
+ return false;
+ }
+
+ b = parse_boolean(parameter);
+
+ if (r > 0 && b > 0)
+ return true;
+
+ if (r == 0 && b == 0)
+ return true;
+
+ return streq(parameter, id);
+}
+
bool condition_test(Condition *c) {
assert(c);
@@ -114,7 +138,10 @@ bool condition_test(Condition *c) {
}
case CONDITION_KERNEL_COMMAND_LINE:
- return !!test_kernel_command_line(c->parameter) == !c->negate;
+ return test_kernel_command_line(c->parameter) == !c->negate;
+
+ case CONDITION_VIRTUALIZATION:
+ return test_virtualization(c->parameter) == !c->negate;
case CONDITION_NULL:
return !c->negate;
diff --git a/src/condition.h b/src/condition.h
index 2f2689cc6d..f4903d76d9 100644
--- a/src/condition.h
+++ b/src/condition.h
@@ -30,6 +30,7 @@ typedef enum ConditionType {
CONDITION_PATH_EXISTS,
CONDITION_DIRECTORY_NOT_EMPTY,
CONDITION_KERNEL_COMMAND_LINE,
+ CONDITION_VIRTUALIZATION,
CONDITION_NULL,
_CONDITION_TYPE_MAX,
_CONDITION_TYPE_INVALID = -1
diff --git a/src/cryptsetup.c b/src/cryptsetup.c
index c80572aed9..989734be1b 100644
--- a/src/cryptsetup.c
+++ b/src/cryptsetup.c
@@ -22,12 +22,14 @@
#include <string.h>
#include <errno.h>
#include <sys/mman.h>
+#include <mntent.h>
#include <libcryptsetup.h>
#include <libudev.h>
#include "log.h"
#include "util.h"
+#include "strv.h"
#include "ask-password-api.h"
static const char *opt_type = NULL; /* LUKS1 or PLAIN */
@@ -163,7 +165,8 @@ static char *disk_description(const char *path) {
goto finish;
if ((model = udev_device_get_property_value(device, "ID_MODEL_FROM_DATABASE")) ||
- (model = udev_device_get_property_value(device, "ID_MODEL")))
+ (model = udev_device_get_property_value(device, "ID_MODEL")) ||
+ (model = udev_device_get_property_value(device, "DM_NAME")))
description = strdup(model);
finish:
@@ -176,12 +179,56 @@ finish:
return description;
}
+static char *disk_mount_point(const char *label) {
+ char *mp = NULL, *device = NULL;
+ FILE *f = NULL;
+ struct mntent *m;
+
+ /* Yeah, we don't support native systemd unit files here for now */
+
+ if (asprintf(&device, "/dev/mapper/%s", label) < 0)
+ goto finish;
+
+ if (!(f = setmntent("/etc/fstab", "r")))
+ goto finish;
+
+ while ((m = getmntent(f)))
+ if (path_equal(m->mnt_fsname, device)) {
+ mp = strdup(m->mnt_dir);
+ break;
+ }
+
+finish:
+ if (f)
+ endmntent(f);
+
+ free(device);
+
+ return mp;
+}
+
+static int help(void) {
+
+ printf("%s attach VOLUME SOURCEDEVICE [PASSWORD] [OPTIONS]\n"
+ "%s detach VOLUME\n\n"
+ "Attaches or detaches an encrypted block device.\n",
+ program_invocation_short_name,
+ program_invocation_short_name);
+
+ return 0;
+}
+
int main(int argc, char *argv[]) {
int r = EXIT_FAILURE;
struct crypt_device *cd = NULL;
- char *password = NULL, *truncated_cipher = NULL;
+ char **passwords = NULL, *truncated_cipher = NULL;
const char *cipher = NULL, *cipher_mode = NULL, *hash = NULL, *name = NULL;
- char *description = NULL;
+ char *description = NULL, *name_buffer = NULL, *mount_point = NULL;
+
+ if (argc <= 1) {
+ help();
+ return EXIT_SUCCESS;
+ }
if (argc < 3) {
log_error("This program requires at least two arguments.");
@@ -200,6 +247,8 @@ int main(int argc, char *argv[]) {
usec_t until;
crypt_status_info status;
+ /* Arguments: systemd-cryptsetup attach VOLUME SOURCE-DEVICE [PASSWORD] [OPTIONS] */
+
if (argc < 4) {
log_error("attach requires at least two arguments.");
goto finish;
@@ -223,7 +272,24 @@ int main(int argc, char *argv[]) {
mlockall(MCL_FUTURE);
description = disk_description(argv[3]);
- name = description ? description : argv[2];
+ mount_point = disk_mount_point(argv[2]);
+
+ if (description && streq(argv[2], description)) {
+ /* If the description string is simply the
+ * volume name, then let's not show this
+ * twice */
+ free(description);
+ description = NULL;
+ }
+
+ if (mount_point && description)
+ asprintf(&name_buffer, "%s (%s) on %s", description, argv[2], mount_point);
+ else if (mount_point)
+ asprintf(&name_buffer, "%s on %s", argv[2], mount_point);
+ else if (description)
+ asprintf(&name_buffer, "%s (%s)", description, argv[2]);
+
+ name = name_buffer ? name_buffer : argv[2];
if ((k = crypt_init(&cd, argv[3]))) {
log_error("crypt_init() failed: %s", strerror(-k));
@@ -268,18 +334,19 @@ int main(int argc, char *argv[]) {
for (try = 0; try < opt_tries; try++) {
bool pass_volume_key = false;
- free(password);
- password = NULL;
+ strv_free(passwords);
+ passwords = NULL;
if (!key_file) {
char *text;
+ char **p;
if (asprintf(&text, "Please enter passphrase for disk %s!", name) < 0) {
log_error("Out of memory");
goto finish;
}
- k = ask_password_auto(text, "drive-harddisk", until, &password);
+ k = ask_password_auto(text, "drive-harddisk", until, try == 0 && !opt_verify, &passwords);
free(text);
if (k < 0) {
@@ -288,14 +355,16 @@ int main(int argc, char *argv[]) {
}
if (opt_verify) {
- char *password2 = NULL;
+ char **passwords2 = NULL;
+
+ assert(strv_length(passwords) == 1);
if (asprintf(&text, "Please enter passphrase for disk %s! (verification)", name) < 0) {
log_error("Out of memory");
goto finish;
}
- k = ask_password_auto(text, "drive-harddisk", until, &password2);
+ k = ask_password_auto(text, "drive-harddisk", until, false, &passwords2);
free(text);
if (k < 0) {
@@ -303,28 +372,34 @@ int main(int argc, char *argv[]) {
goto finish;
}
- if (!streq(password, password2)) {
+ assert(strv_length(passwords2) == 1);
+
+ if (!streq(passwords[0], passwords2[0])) {
log_warning("Passwords did not match, retrying.");
- free(password2);
+ strv_free(passwords2);
continue;
}
- free(password2);
+ strv_free(passwords2);
}
- if (strlen(password)+1 < opt_key_size) {
+ strv_uniq(passwords);
+
+ STRV_FOREACH(p, passwords) {
char *c;
- /* Pad password if necessary */
+ if (strlen(*p)+1 >= opt_key_size)
+ continue;
+ /* Pad password if necessary */
if (!(c = new(char, opt_key_size))) {
log_error("Out of memory.");
goto finish;
}
- strncpy(c, password, opt_key_size);
- free(password);
- password = c;
+ strncpy(c, *p, opt_key_size);
+ free(*p);
+ *p = c;
}
}
@@ -367,10 +442,20 @@ int main(int argc, char *argv[]) {
if (key_file)
k = crypt_activate_by_keyfile(cd, argv[2], CRYPT_ANY_SLOT, key_file, opt_key_size, flags);
- else if (pass_volume_key)
- k = crypt_activate_by_volume_key(cd, argv[2], password, opt_key_size, flags);
- else
- k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, password, strlen(password), flags);
+ else {
+ char **p;
+
+ STRV_FOREACH(p, passwords) {
+
+ if (pass_volume_key)
+ k = crypt_activate_by_volume_key(cd, argv[2], *p, opt_key_size, flags);
+ else
+ k = crypt_activate_by_passphrase(cd, argv[2], CRYPT_ANY_SLOT, *p, strlen(*p), flags);
+
+ if (k >= 0)
+ break;
+ }
+ }
if (k >= 0)
break;
@@ -421,9 +506,11 @@ finish:
free(truncated_cipher);
- free(password);
+ strv_free(passwords);
free(description);
+ free(mount_point);
+ free(name_buffer);
return r;
}
diff --git a/src/dbus-job.c b/src/dbus-job.c
index 18da72d67a..2a33039bdb 100644
--- a/src/dbus-job.c
+++ b/src/dbus-job.c
@@ -97,7 +97,7 @@ static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusConnection *connec
if (!(reply = dbus_message_new_method_return(message)))
goto oom;
- job_free(j);
+ job_finish_and_invalidate(j, JOB_CANCELED);
} else
return bus_default_message_handler(j->manager, connection, message, INTROSPECTION, properties);
@@ -295,10 +295,10 @@ oom:
log_error("Failed to allocate job change signal.");
}
-void bus_job_send_removed_signal(Job *j, bool success) {
+void bus_job_send_removed_signal(Job *j) {
char *p = NULL;
DBusMessage *m = NULL;
- dbus_bool_t b = success;
+ const char *r;
assert(j);
@@ -314,10 +314,12 @@ void bus_job_send_removed_signal(Job *j, bool success) {
if (!(m = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "JobRemoved")))
goto oom;
+ r = job_result_to_string(j->result);
+
if (!dbus_message_append_args(m,
DBUS_TYPE_UINT32, &j->id,
DBUS_TYPE_OBJECT_PATH, &p,
- DBUS_TYPE_BOOLEAN, &b,
+ DBUS_TYPE_STRING, &r,
DBUS_TYPE_INVALID))
goto oom;
diff --git a/src/dbus-job.h b/src/dbus-job.h
index 801e3e6349..103c2ff3ec 100644
--- a/src/dbus-job.h
+++ b/src/dbus-job.h
@@ -24,8 +24,10 @@
#include <dbus/dbus.h>
+#include "job.h"
+
void bus_job_send_change_signal(Job *j);
-void bus_job_send_removed_signal(Job *j, bool success);
+void bus_job_send_removed_signal(Job *j);
extern const DBusObjectPathVTable bus_job_vtable;
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 6f98aa7308..1b3bddc348 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -143,7 +143,7 @@
" <signal name=\"JobRemoved\">\n" \
" <arg name=\"id\" type=\"u\"/>\n" \
" <arg name=\"job\" type=\"o\"/>\n" \
- " <arg name=\"success\" type=\"b\"/>\n" \
+ " <arg name=\"result\" type=\"s\"/>\n" \
" </signal>"
diff --git a/src/dbus-path.c b/src/dbus-path.c
index 9692d6a247..6155792d0d 100644
--- a/src/dbus-path.c
+++ b/src/dbus-path.c
@@ -72,10 +72,24 @@ static int bus_path_append_paths(Manager *m, DBusMessageIter *i, const char *pro
return 0;
}
+static int bus_path_append_unit(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+ Unit *u = data;
+ const char *t;
+
+ assert(m);
+ assert(i);
+ assert(property);
+ assert(u);
+
+ t = u->path.unit ? u->path.unit->meta.id : "";
+
+ return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
+}
+
DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
const BusProperty properties[] = {
BUS_UNIT_PROPERTIES,
- { "org.freedesktop.systemd1.Path", "Unit", bus_property_append_string, "s", u->path.unit->meta.id },
+ { "org.freedesktop.systemd1.Path", "Unit", bus_path_append_unit, "s", u },
{ "org.freedesktop.systemd1.Path", "Paths", bus_path_append_paths, "a(ss)", u },
{ NULL, NULL, NULL, NULL, NULL }
};
diff --git a/src/dbus-timer.c b/src/dbus-timer.c
index 56044661e7..f4c23e0ea7 100644
--- a/src/dbus-timer.c
+++ b/src/dbus-timer.c
@@ -96,10 +96,24 @@ static int bus_timer_append_timers(Manager *m, DBusMessageIter *i, const char *p
return 0;
}
+static int bus_timer_append_unit(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+ Unit *u = data;
+ const char *t;
+
+ assert(m);
+ assert(i);
+ assert(property);
+ assert(u);
+
+ t = u->timer.unit ? u->timer.unit->meta.id : "";
+
+ return dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t) ? 0 : -ENOMEM;
+}
+
DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
const BusProperty properties[] = {
BUS_UNIT_PROPERTIES,
- { "org.freedesktop.systemd1.Timer", "Unit", bus_property_append_string, "s", u->timer.unit->meta.id },
+ { "org.freedesktop.systemd1.Timer", "Unit", bus_timer_append_unit, "s", u },
{ "org.freedesktop.systemd1.Timer", "Timers", bus_timer_append_timers, "a(stt)", u },
{ "org.freedesktop.systemd1.Timer", "NextElapseUSec", bus_property_append_usec, "t", &u->timer.next_elapse },
{ NULL, NULL, NULL, NULL, NULL }
diff --git a/src/dbus.c b/src/dbus.c
index d7b80ba01d..965a3e2f21 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -418,7 +418,7 @@ static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBus
goto oom;
}
- /* On success we don't do anything, the service will be spwaned now */
+ /* On success we don't do anything, the service will be spawned now */
}
}
@@ -1361,6 +1361,7 @@ static const char *error_to_dbus(int error) {
return DBUS_ERROR_FILE_EXISTS;
case -ETIMEDOUT:
+ case -ETIME:
return DBUS_ERROR_TIMEOUT;
case -EIO:
diff --git a/src/detect-virt.c b/src/detect-virt.c
new file mode 100644
index 0000000000..57f0176668
--- /dev/null
+++ b/src/detect-virt.c
@@ -0,0 +1,46 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+
+#include "util.h"
+
+int main(int argc, char *argv[]) {
+ int 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) {
+ log_error("Failed to check for virtualization: %s", strerror(-r));
+ return EXIT_FAILURE;
+ }
+
+ if (r > 0)
+ puts(id);
+
+ return r == 0;
+}
diff --git a/src/device.c b/src/device.c
index b9d8a2b9cf..ccf2935a91 100644
--- a/src/device.c
+++ b/src/device.c
@@ -65,7 +65,7 @@ static void device_init(Unit *u) {
/* In contrast to all other unit types we timeout jobs waiting
* for devices by default. This is because they otherwise wait
- * indefinetely for plugged in devices, something which cannot
+ * indefinitely for plugged in devices, something which cannot
* happen for the other units since their operations time out
* anyway. */
d->meta.job_timeout = DEFAULT_TIMEOUT_USEC;
@@ -542,7 +542,7 @@ void device_fd_event(Manager *m, int events) {
if (!(dev = udev_monitor_receive_device(m->udev_monitor))) {
/*
* libudev might filter-out devices which pass the bloom filter,
- * so getting NULL here is not neccessarily an error
+ * so getting NULL here is not necessarily an error
*/
return;
}
diff --git a/src/device.h b/src/device.h
index ee50cfafc6..9a56a5205b 100644
--- a/src/device.h
+++ b/src/device.h
@@ -40,7 +40,7 @@ struct Device {
char *sysfs;
- /* In order to be able to distuingish dependencies on
+ /* In order to be able to distinguish dependencies on
different device nodes we might end up creating multiple
devices for the same sysfs path. We chain them up here. */
diff --git a/src/execute.c b/src/execute.c
index e01cbde974..d6f09e26fe 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -592,7 +592,7 @@ static int get_user_creds(const char **username, uid_t *uid, gid_t *gid, const c
/* If there are multiple users with the same id, make
* sure to leave $USER to the configured value instead
- * of the first occurence in the database. However if
+ * of the first occurrence in the database. However if
* the uid was configured by a numeric uid, then let's
* pick the real username from /etc/passwd. */
if (*username && p)
@@ -617,7 +617,7 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_
assert(context);
- /* Lookup and ser GID and supplementary group list. Here too
+ /* Lookup and set GID and supplementary group list. Here too
* we avoid NSS lookups for gid=0. */
if (context->group || username) {
@@ -700,7 +700,7 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
/* First step: If we need to keep capabilities but
* drop privileges we need to make sure we keep our
- * caps, whiel we drop priviliges. */
+ * caps, whiel we drop privileges. */
if (uid != 0) {
int sb = context->secure_bits|SECURE_KEEP_CAPS;
@@ -709,7 +709,7 @@ static int enforce_user(const ExecContext *context, uid_t uid) {
return -errno;
}
- /* Second step: set the capabilites. This will reduce
+ /* Second step: set the capabilities. This will reduce
* the capabilities to the minimum we need. */
if (!(d = cap_dup(context->capabilities)))
@@ -780,7 +780,7 @@ static int setup_pam(
assert(pam_env);
/* We set up PAM in the parent process, then fork. The child
- * will then stay around untill killed via PR_GET_PDEATHSIG or
+ * will then stay around until killed via PR_GET_PDEATHSIG or
* systemd via the cgroup logic. It will then remove the PAM
* session again. The parent process will exec() the actual
* daemon. We do things this way to ensure that the main PID
@@ -841,7 +841,7 @@ static int setup_pam(
/* Wait until our parent died. This will most likely
* not work since the kernel does not allow
- * unpriviliged paretns kill their priviliged children
+ * unprivileged parents kill their privileged children
* this way. We rely on the control groups kill logic
* to do the rest for us. */
if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
@@ -1242,7 +1242,7 @@ int exec_spawn(ExecCommand *command,
goto fail;
}
- /* PR_GET_SECUREBITS is not priviliged, while
+ /* PR_GET_SECUREBITS is not privileged, while
* PR_SET_SECUREBITS is. So to suppress
* potential EPERMs we'll try not to call
* PR_SET_SECUREBITS unless necessary. */
@@ -1779,7 +1779,7 @@ void exec_command_append_list(ExecCommand **l, ExecCommand *e) {
assert(e);
if (*l) {
- /* It's kinda important that we keep the order here */
+ /* It's kind of important, that we keep the order here */
LIST_FIND_TAIL(ExecCommand, command, *l, end);
LIST_INSERT_AFTER(ExecCommand, command, *l, end, e);
} else
diff --git a/src/job.c b/src/job.c
index 4700aab6ac..54bd4147e2 100644
--- a/src/job.c
+++ b/src/job.c
@@ -60,7 +60,7 @@ void job_free(Job *j) {
/* Detach from next 'bigger' objects */
if (j->installed) {
- bus_job_send_removed_signal(j, !j->failed);
+ bus_job_send_removed_signal(j);
if (j->unit->meta.job == j) {
j->unit->meta.job = NULL;
@@ -101,7 +101,7 @@ JobDependency* job_dependency_new(Job *subject, Job *object, bool matters, bool
/* Adds a new job link, which encodes that the 'subject' job
* needs the 'object' job in some way. If 'subject' is NULL
* this means the 'anchor' job (i.e. the one the user
- * explcitily asked for) is the requester. */
+ * explicitly asked for) is the requester. */
if (!(l = new0(JobDependency, 1)))
return NULL;
@@ -394,6 +394,7 @@ int job_run_and_invalidate(Job *j) {
* wait */
if (r == -EBADR)
r = 0;
+
break;
case JOB_VERIFY_ACTIVE: {
@@ -455,17 +456,17 @@ int job_run_and_invalidate(Job *j) {
if ((j = manager_get_job(m, id))) {
if (r == -EALREADY)
- r = job_finish_and_invalidate(j, true);
+ r = job_finish_and_invalidate(j, JOB_DONE);
else if (r == -EAGAIN)
j->state = JOB_WAITING;
else if (r < 0)
- r = job_finish_and_invalidate(j, false);
+ r = job_finish_and_invalidate(j, JOB_FAILED);
}
return r;
}
-int job_finish_and_invalidate(Job *j, bool success) {
+int job_finish_and_invalidate(Job *j, JobResult result) {
Unit *u;
Unit *other;
JobType t;
@@ -477,7 +478,7 @@ int job_finish_and_invalidate(Job *j, bool success) {
job_add_to_dbus_queue(j);
/* Patch restart jobs so that they become normal start jobs */
- if (success && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) {
+ if (result == JOB_DONE && (j->type == JOB_RESTART || j->type == JOB_TRY_RESTART)) {
log_debug("Converting job %s/%s -> %s/%s",
j->unit->meta.id, job_type_to_string(j->type),
@@ -490,22 +491,26 @@ int job_finish_and_invalidate(Job *j, bool success) {
return 0;
}
- j->failed = !success;
+ j->result = result;
- log_debug("Job %s/%s finished, success=%s", j->unit->meta.id, job_type_to_string(j->type), yes_no(success));
+ log_debug("Job %s/%s finished, result=%s", j->unit->meta.id, job_type_to_string(j->type), job_result_to_string(result));
- if (j->failed)
+ if (result == JOB_FAILED)
j->manager->n_failed_jobs ++;
u = j->unit;
t = j->type;
job_free(j);
- if (!success && j->type == JOB_START)
+ if (result == JOB_FAILED && t == JOB_START)
unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "failed" ANSI_HIGHLIGHT_OFF ", see 'systemctl status %s' for details.\n", unit_description(u), u->meta.id);
+ else if (result == JOB_TIMEOUT && t == JOB_START)
+ unit_status_printf(u, "Starting %s " ANSI_HIGHLIGHT_ON "timed out" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u), u->meta.id);
+ else if (result == JOB_TIMEOUT && t == JOB_STOP)
+ unit_status_printf(u, "Stopping %s " ANSI_HIGHLIGHT_ON "timed out" ANSI_HIGHLIGHT_OFF ".\n", unit_description(u), u->meta.id);
/* Fail depending jobs on failure */
- if (!success) {
+ if (result != JOB_DONE) {
if (t == JOB_START ||
t == JOB_VERIFY_ACTIVE ||
@@ -516,14 +521,14 @@ int job_finish_and_invalidate(Job *j, bool success) {
(other->meta.job->type == JOB_START ||
other->meta.job->type == JOB_VERIFY_ACTIVE ||
other->meta.job->type == JOB_RELOAD_OR_START))
- job_finish_and_invalidate(other->meta.job, false);
+ job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
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))
- job_finish_and_invalidate(other->meta.job, false);
+ job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
SET_FOREACH(other, u->meta.dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
if (other->meta.job &&
@@ -531,7 +536,7 @@ int job_finish_and_invalidate(Job *j, bool success) {
(other->meta.job->type == JOB_START ||
other->meta.job->type == JOB_VERIFY_ACTIVE ||
other->meta.job->type == JOB_RELOAD_OR_START))
- job_finish_and_invalidate(other->meta.job, false);
+ job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
} else if (t == JOB_STOP) {
@@ -540,10 +545,17 @@ int job_finish_and_invalidate(Job *j, bool success) {
(other->meta.job->type == JOB_START ||
other->meta.job->type == JOB_VERIFY_ACTIVE ||
other->meta.job->type == JOB_RELOAD_OR_START))
- job_finish_and_invalidate(other->meta.job, false);
+ job_finish_and_invalidate(other->meta.job, JOB_DEPENDENCY);
}
}
+ /* Trigger OnFailure dependencies that are not generated by
+ * the unit itself. We don't tread JOB_CANCELED as failure in
+ * this context. And JOB_FAILURE is already handled by the
+ * unit itself. */
+ if (result == JOB_TIMEOUT || result == JOB_DEPENDENCY)
+ unit_trigger_on_failure(u);
+
/* Try to start the next jobs that can be started */
SET_FOREACH(other, u->meta.dependencies[UNIT_AFTER], i)
if (other->meta.job)
@@ -646,7 +658,7 @@ void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w) {
assert(w == &j->timer_watch);
log_warning("Job %s/%s timed out.", j->unit->meta.id, job_type_to_string(j->type));
- job_finish_and_invalidate(j, false);
+ job_finish_and_invalidate(j, JOB_TIMEOUT);
}
static const char* const job_state_table[_JOB_STATE_MAX] = {
@@ -676,3 +688,13 @@ static const char* const job_mode_table[_JOB_MODE_MAX] = {
};
DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
+
+static const char* const job_result_table[_JOB_RESULT_MAX] = {
+ [JOB_DONE] = "done",
+ [JOB_CANCELED] = "canceled",
+ [JOB_TIMEOUT] = "timeout",
+ [JOB_FAILED] = "failed",
+ [JOB_DEPENDENCY] = "dependency"
+};
+
+DEFINE_STRING_TABLE_LOOKUP(job_result, JobResult);
diff --git a/src/job.h b/src/job.h
index 2499e6492a..de0c1d2317 100644
--- a/src/job.h
+++ b/src/job.h
@@ -30,6 +30,7 @@ typedef struct JobDependency JobDependency;
typedef enum JobType JobType;
typedef enum JobState JobState;
typedef enum JobMode JobMode;
+typedef enum JobResult JobResult;
#include "manager.h"
#include "unit.h"
@@ -71,6 +72,16 @@ enum JobMode {
_JOB_MODE_INVALID = -1
};
+enum JobResult {
+ JOB_DONE,
+ JOB_CANCELED,
+ JOB_TIMEOUT,
+ JOB_FAILED,
+ JOB_DEPENDENCY,
+ _JOB_RESULT_MAX,
+ _JOB_RESULT_INVALID = -1
+};
+
struct JobDependency {
/* Encodes that the 'subject' job needs the 'object' job in
* some way. This structure is used only while building a transaction. */
@@ -110,13 +121,14 @@ struct Job {
DBusConnection *bus;
char *bus_client;
+ JobResult result;
+
bool installed:1;
bool in_run_queue:1;
bool matters_to_anchor:1;
bool override:1;
bool in_dbus_queue:1;
bool sent_dbus_new_signal:1;
- bool failed:1;
bool ignore_deps:1;
};
@@ -146,7 +158,7 @@ int job_start_timer(Job *j);
void job_timer_event(Job *j, uint64_t n_elapsed, Watch *w);
int job_run_and_invalidate(Job *j);
-int job_finish_and_invalidate(Job *j, bool success);
+int job_finish_and_invalidate(Job *j, JobResult result);
char *job_dbus_path(Job *j);
@@ -159,4 +171,7 @@ JobState job_state_from_string(const char *s);
const char* job_mode_to_string(JobMode t);
JobMode job_mode_from_string(const char *s);
+const char* job_result_to_string(JobResult t);
+JobResult job_result_from_string(const char *s);
+
#endif
diff --git a/src/kmsg-syslogd.c b/src/kmsg-syslogd.c
index 2bdbb4b9f3..e23c9d3862 100644
--- a/src/kmsg-syslogd.c
+++ b/src/kmsg-syslogd.c
@@ -39,7 +39,7 @@
#include "fdset.h"
#define SERVER_FD_MAX 16
-#define TIMEOUT ((int) (10*MSEC_PER_SEC))
+#define TIMEOUT ((int) (5*60*MSEC_PER_SEC))
typedef struct Stream Stream;
diff --git a/src/label.c b/src/label.c
index 218d0dfa06..09ded642fb 100644
--- a/src/label.c
+++ b/src/label.c
@@ -65,7 +65,7 @@ int label_init(void) {
return r;
}
-int label_fix(const char *path) {
+int label_fix(const char *path, bool ignore_enoent) {
int r = 0;
#ifdef HAVE_SELINUX
@@ -90,6 +90,10 @@ int label_fix(const char *path) {
/* If the FS doesn't support labels, then exit without warning */
if (r < 0 && errno == ENOTSUP)
return 0;
+
+ /* Ignore ENOENT in some cases */
+ if (r < 0 && ignore_enoent && errno == ENOENT)
+ return 0;
}
}
diff --git a/src/label.h b/src/label.h
index f1bf5d6d5e..7ea11cdc55 100644
--- a/src/label.h
+++ b/src/label.h
@@ -23,11 +23,12 @@
***/
#include <sys/types.h>
+#include <stdbool.h>
int label_init(void);
void label_finish(void);
-int label_fix(const char *path);
+int label_fix(const char *path, bool ignore_enoent);
int label_socket_set(const char *label);
void label_socket_clear(void);
diff --git a/src/load-fragment.c b/src/load-fragment.c
index eaeaadaea4..2e67eccc00 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1503,6 +1503,34 @@ static int config_parse_condition_kernel(
return 0;
}
+static int config_parse_condition_virt(
+ const char *filename,
+ unsigned line,
+ const char *section,
+ const char *lvalue,
+ const char *rvalue,
+ void *data,
+ void *userdata) {
+
+ Unit *u = data;
+ bool negate;
+ Condition *c;
+
+ assert(filename);
+ assert(lvalue);
+ assert(rvalue);
+ assert(data);
+
+ if ((negate = rvalue[0] == '!'))
+ rvalue++;
+
+ if (!(c = condition_new(CONDITION_VIRTUALIZATION, rvalue, negate)))
+ return -ENOMEM;
+
+ LIST_PREPEND(Condition, conditions, u->meta.conditions, c);
+ return 0;
+}
+
static int config_parse_condition_null(
const char *filename,
unsigned line,
@@ -1714,6 +1742,7 @@ static void dump_items(FILE *f, const ConfigItem *items) {
{ config_parse_condition_path, "CONDITION" },
{ config_parse_condition_kernel, "CONDITION" },
{ config_parse_condition_null, "CONDITION" },
+ { config_parse_condition_virt, "CONDITION" },
};
assert(f);
@@ -1838,6 +1867,7 @@ static int load_from_path(Unit *u, const char *path) {
{ "ConditionPathExists", config_parse_condition_path, u, "Unit" },
{ "ConditionDirectoryNotEmpty", config_parse_condition_path, u, "Unit" },
{ "ConditionKernelCommandLine", config_parse_condition_kernel, u, "Unit" },
+ { "ConditionVirtualization",config_parse_condition_virt, u, "Unit" },
{ "ConditionNull", config_parse_condition_null, u, "Unit" },
{ "PIDFile", config_parse_path, &u->service.pid_file, "Service" },
diff --git a/src/log.c b/src/log.c
index a2a648a93c..b6d4bf9c1b 100644
--- a/src/log.c
+++ b/src/log.c
@@ -45,7 +45,7 @@ static bool syslog_is_stream = false;
static bool show_color = false;
static bool show_location = false;
-/* Akin to glibc's __abort_msg; which is private and we hance cannot
+/* Akin to glibc's __abort_msg; which is private and we hence cannot
* use here. */
static char *log_abort_msg = NULL;
@@ -74,7 +74,7 @@ static int log_open_console(void) {
return console_fd;
}
- log_debug("Succesfully opened /dev/console for logging.");
+ log_debug("Successfully opened /dev/console for logging.");
} else
console_fd = STDERR_FILENO;
@@ -100,7 +100,7 @@ static int log_open_kmsg(void) {
return -errno;
}
- log_debug("Succesfully opened /dev/kmsg for logging.");
+ log_debug("Successfully opened /dev/kmsg for logging.");
return 0;
}
@@ -171,7 +171,7 @@ static int log_open_syslog(void) {
} else
syslog_is_stream = false;
- log_debug("Succesfully opened syslog for logging.");
+ log_debug("Successfully opened syslog for logging.");
return 0;
diff --git a/src/logger.c b/src/logger.c
index 342c307899..104d7c385b 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -38,9 +38,9 @@
#include "sd-daemon.h"
#include "tcpwrap.h"
-#define STREAMS_MAX 256
+#define STREAMS_MAX 4096
#define SERVER_FD_MAX 16
-#define TIMEOUT ((int) (10*MSEC_PER_SEC))
+#define TIMEOUT ((int) (5*60*MSEC_PER_SEC))
typedef struct Stream Stream;
@@ -520,7 +520,7 @@ static int server_init(Server *s, unsigned n_sockets) {
/* We use ev.data.ptr instead of ev.data.fd here,
* since on 64bit archs fd is 32bit while a pointer is
- * 64bit. To make sure we can easily distuingish fd
+ * 64bit. To make sure we can easily distinguish fd
* values and pointer values we want to make sure to
* write the full field unconditionally. */
diff --git a/src/main.c b/src/main.c
index 96a282a34f..2c02217d89 100644
--- a/src/main.c
+++ b/src/main.c
@@ -858,7 +858,7 @@ static int prepare_reexecute(Manager *m, FILE **_f, FDSet **_fds) {
assert(_fds);
if ((r = manager_open_serialization(m, &f)) < 0) {
- log_error("Failed to create serialization faile: %s", strerror(-r));
+ log_error("Failed to create serialization file: %s", strerror(-r));
goto fail;
}
@@ -923,6 +923,8 @@ static struct dual_timestamp* parse_initrd_timestamp(struct dual_timestamp *t) {
static void test_mtab(void) {
char *p;
+ /* Check that /etc/mtab is a symlink */
+
if (readlink_malloc("/etc/mtab", &p) >= 0) {
bool b;
@@ -933,9 +935,33 @@ static void test_mtab(void) {
return;
}
- log_error("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. "
- "This is not supported anymore. "
- "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output.");
+ log_warning("/etc/mtab is not a symlink or not pointing to /proc/self/mounts. "
+ "This is not supported anymore. "
+ "Please make sure to replace this file by a symlink to avoid incorrect or misleading mount(8) output.");
+}
+
+static void test_usr(void) {
+ struct stat a, b;
+ bool seperate = false;
+
+ /* Check that /usr is not a seperate fs */
+
+ if (lstat("/", &a) >= 0 && lstat("/usr", &b) >= 0)
+ if (a.st_dev != b.st_dev)
+ seperate = true;
+
+ /* This check won't work usually during boot, since /usr is
+ * probably not mounted yet, hence let's add a second
+ * check. We just check whether /usr is an empty directory. */
+
+ if (dir_is_empty("/usr") > 0)
+ seperate = true;
+
+ if (!seperate)
+ return;
+
+ log_warning("/usr appears to be on a different file system than /. This is not supported anymore. "
+ "Some things will probably break (sometimes even silently) in mysterious ways.");
}
int main(int argc, char *argv[]) {
@@ -948,7 +974,7 @@ int main(int argc, char *argv[]) {
char systemd[] = "systemd";
if (getpid() != 1 && strstr(program_invocation_short_name, "init")) {
- /* This is compatbility support for SysV, where
+ /* This is compatibility support for SysV, where
* calling init as a user is identical to telinit. */
errno = -ENOENT;
@@ -1012,6 +1038,11 @@ int main(int argc, char *argv[]) {
if (parse_argv(argc, argv) < 0)
goto finish;
+ if (arg_action == ACTION_TEST && geteuid() == 0) {
+ log_error("Don't run test mode as root.");
+ goto finish;
+ }
+
/* If Plymouth is being run make sure we show the status, so
* that there's something nice to see when people press Esc */
if (access("/dev/.systemd/plymouth", F_OK) >= 0)
@@ -1103,6 +1134,7 @@ int main(int argc, char *argv[]) {
mkdir_p("/dev/.systemd/ask-password/", 0755);
test_mtab();
+ test_usr();
}
if ((r = manager_new(arg_running_as, &m)) < 0) {
diff --git a/src/manager.c b/src/manager.c
index f266aaa01c..194ad66a02 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -294,7 +294,7 @@ static unsigned manager_dispatch_cleanup_queue(Manager *m) {
}
enum {
- GC_OFFSET_IN_PATH, /* This one is on the path we were travelling */
+ GC_OFFSET_IN_PATH, /* This one is on the path we were traveling */
GC_OFFSET_UNSURE, /* No clue */
GC_OFFSET_GOOD, /* We still need this unit */
GC_OFFSET_BAD, /* We don't need this unit anymore */
@@ -768,7 +768,7 @@ static int delete_one_unmergeable_job(Manager *m, Job *j) {
/* Tries to delete one item in the linked list
* j->transaction_next->transaction_next->... that conflicts
- * whith another one, in an attempt to make an inconsistent
+ * with another one, in an attempt to make an inconsistent
* transaction work. */
/* We rely here on the fact that if a merged with b does not
@@ -1286,7 +1286,7 @@ static int transaction_activate(Manager *m, JobMode mode, DBusError *e) {
break;
if (r != -EAGAIN) {
- log_warning("Requested transaction contains unmergable jobs: %s", bus_error(e, r));
+ log_warning("Requested transaction contains unmergeable jobs: %s", bus_error(e, r));
goto rollback;
}
@@ -1330,7 +1330,7 @@ static Job* transaction_add_one_job(Manager *m, JobType type, Unit *unit, bool o
assert(m);
assert(unit);
- /* Looks for an axisting prospective job and returns that. If
+ /* Looks for an existing prospective job and returns that. If
* it doesn't exist it is created and added to the prospective
* jobs list. */
@@ -1823,7 +1823,7 @@ void manager_clear_jobs(Manager *m) {
transaction_abort(m);
while ((j = hashmap_first(m->jobs)))
- job_free(j);
+ job_finish_and_invalidate(j, JOB_CANCELED);
}
unsigned manager_dispatch_run_queue(Manager *m) {
diff --git a/src/manager.h b/src/manager.h
index 19679686b1..efca4ff7f6 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -93,7 +93,7 @@ struct Watch {
struct Manager {
/* Note that the set of units we know of is allowed to be
- * incosistent. However the subset of it that is loaded may
+ * inconsistent. However the subset of it that is loaded may
* not, and the list of jobs may neither. */
/* Active jobs and units */
@@ -194,7 +194,7 @@ struct Manager {
int gc_marker;
unsigned n_in_gc_queue;
- /* Make sure the user cannot accidentaly unmount our cgroup
+ /* Make sure the user cannot accidentally unmount our cgroup
* file system */
int pin_cgroupfs_fd;
diff --git a/src/mount-setup.c b/src/mount-setup.c
index 64fb4765f6..5cbaee6be7 100644
--- a/src/mount-setup.c
+++ b/src/mount-setup.c
@@ -121,7 +121,7 @@ static int mount_one(const MountPoint *p) {
return p->fatal ? -errno : 0;
}
- label_fix(p->where);
+ label_fix(p->where, false);
return 0;
}
@@ -216,7 +216,7 @@ static int nftw_cb(
if (ftwbuf->level == 0)
return 0;
- label_fix(fpath);
+ label_fix(fpath, true);
return 0;
};
diff --git a/src/mount.c b/src/mount.c
index 102d88b6e0..88b54bbb29 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -306,7 +306,7 @@ static int mount_add_target_links(Mount *m) {
return r;
if (after)
- if ((r = unit_add_dependency_by_name(tu, UNIT_AFTER, after, NULL, true)) < 0)
+ if ((r = unit_add_dependency_by_name(UNIT(m), UNIT_AFTER, after, NULL, true)) < 0)
return r;
if (automount && m->meta.manager->running_as == MANAGER_SYSTEM) {
diff --git a/src/namespace.c b/src/namespace.c
index 1d8f35ba57..54b22f494e 100644
--- a/src/namespace.c
+++ b/src/namespace.c
@@ -161,11 +161,11 @@ static int apply_mount(Path *p, const char *root_dir, const char *inaccessible_d
/* The bind mount will always inherit the original
* flags. If we want to set any flag we need
- * to do so in a second indepdant step. */
+ * to do so in a second independent step. */
if (flags)
r = mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|MS_REC|flags, NULL);
- /* Avoid expontial growth of trees */
+ /* Avoid exponential growth of trees */
if (r >= 0 && path_equal(p->path, "/"))
r = mount(NULL, where, NULL, MS_REMOUNT|MS_BIND|MS_UNBINDABLE|flags, NULL);
diff --git a/src/ratelimit.c b/src/ratelimit.c
index 5adf1ae10d..1ddc83187f 100644
--- a/src/ratelimit.c
+++ b/src/ratelimit.c
@@ -38,25 +38,19 @@ bool ratelimit_test(RateLimit *r) {
if (r->begin <= 0 ||
r->begin + r->interval < ts) {
-
- if (r->n_missed > 0)
- log_warning("%u events suppressed", r->n_missed);
-
r->begin = ts;
- /* Reset counters */
- r->n_printed = 0;
- r->n_missed = 0;
+ /* Reset counter */
+ r->num = 0;
goto good;
}
- if (r->n_printed <= r->burst)
+ if (r->num <= r->burst)
goto good;
- r->n_missed++;
return false;
good:
- r->n_printed++;
+ r->num++;
return true;
}
diff --git a/src/ratelimit.h b/src/ratelimit.h
index 2c77787d3c..a44ef70db4 100644
--- a/src/ratelimit.h
+++ b/src/ratelimit.h
@@ -28,15 +28,14 @@ typedef struct RateLimit {
usec_t interval;
usec_t begin;
unsigned burst;
- unsigned n_printed, n_missed;
+ unsigned num;
} RateLimit;
#define RATELIMIT_DEFINE(_name, _interval, _burst) \
RateLimit _name = { \
.interval = (_interval), \
.burst = (_burst), \
- .n_printed = 0, \
- .n_missed = 0, \
+ .num = 0, \
.begin = 0 \
}
@@ -45,8 +44,7 @@ typedef struct RateLimit {
RateLimit *_r = &(v); \
_r->interval = (_interval); \
_r->burst = (_burst); \
- _r->n_printed = 0; \
- _r->n_missed = 0; \
+ _r->num = 0; \
_r->begin = 0; \
} while (false);
diff --git a/src/readahead-collect.c b/src/readahead-collect.c
index 4ca6d74726..330d10776f 100644
--- a/src/readahead-collect.c
+++ b/src/readahead-collect.c
@@ -96,6 +96,9 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) {
if (errno == ENOENT)
return 0;
+ if (errno == EPERM || errno == EACCES)
+ return 0;
+
log_warning("open(%s) failed: %m", fn);
r = -errno;
goto finish;
@@ -649,8 +652,8 @@ int main(int argc, char *argv[]) {
return 0;
}
- if (running_in_vm()) {
- log_info("Disabling readahead collector due to execution in virtual machine.");
+ if (detect_virtualization(NULL) > 0) {
+ log_info("Disabling readahead collector due to execution in virtualized environment.");
return 0;
}
diff --git a/src/readahead-replay.c b/src/readahead-replay.c
index e9c573a593..cd89654f98 100644
--- a/src/readahead-replay.c
+++ b/src/readahead-replay.c
@@ -62,7 +62,7 @@ static int unpack_file(FILE *pack) {
if ((fd = open(fn, O_RDONLY|O_CLOEXEC|O_NOATIME|O_NOCTTY|O_NOFOLLOW)) < 0) {
- if (errno != ENOENT)
+ if (errno != ENOENT && errno != EPERM && errno != EACCES)
log_warning("open(%s) failed: %m", fn);
} else if (file_verify(fd, fn, arg_file_size_max, &st) <= 0) {
@@ -346,8 +346,8 @@ int main(int argc, char*argv[]) {
return 0;
}
- if (running_in_vm()) {
- log_info("Disabling readahead replay due to execution in virtual machine.");
+ if (detect_virtualization(NULL) > 0) {
+ log_info("Disabling readahead replay due to execution in virtualized environment.");
return 0;
}
diff --git a/src/sd-daemon.h b/src/sd-daemon.h
index d0a0a9459a..4b853a15be 100644
--- a/src/sd-daemon.h
+++ b/src/sd-daemon.h
@@ -185,7 +185,7 @@ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t
READY=1 Tells systemd that daemon startup is finished (only
relevant for services of Type=notify). The passed
argument is a boolean "1" or "0". Since there is
- little value in signalling non-readiness the only
+ little value in signaling non-readiness the only
value daemons should send is "READY=1".
STATUS=... Passes a single-line status string back to systemd
@@ -206,7 +206,7 @@ int sd_is_socket_unix(int fd, int type, int listening, const char *path, size_t
fork off the process itself. Example: "MAINPID=4711"
Daemons can choose to send additional variables. However, it is
- recommened to prefix variable names not listed above with X_.
+ recommended to prefix variable names not listed above with X_.
Returns a negative errno-style error code on failure. Returns > 0
if systemd could be notified, 0 if it couldn't possibly because
diff --git a/src/securebits.h b/src/securebits.h
index a5b99a3dbf..ba0bba5353 100644
--- a/src/securebits.h
+++ b/src/securebits.h
@@ -16,7 +16,7 @@
#define SECURE_NOROOT_LOCKED 1 /* make bit-0 immutable */
/* When set, setuid to/from uid 0 does not trigger capability-"fixup".
- When unset, to provide compatiblility with old programs relying on
+ When unset, to provide compatibility with old programs relying on
set*uid to gain/lose privilege, transitions to/from uid 0 cause
capabilities to be gained/lost. */
#define SECURE_NO_SETUID_FIXUP 2
diff --git a/src/service.c b/src/service.c
index e928d1a5e0..39a46d6cf5 100644
--- a/src/service.c
+++ b/src/service.c
@@ -335,7 +335,7 @@ static int sysv_translate_facility(const char *name, const char *filename, char
/* Facilities starting with $ are most likely targets */
r = unit_name_build(n, NULL, ".target");
} else if (filename && streq(name, filename))
- /* Names equalling the file name of the services are redundant */
+ /* Names equaling the file name of the services are redundant */
return 0;
else
/* Everything else we assume to be normal service names */
@@ -2496,16 +2496,26 @@ static const char *service_sub_state_to_string(Unit *u) {
return service_state_to_string(SERVICE(u)->state);
}
-#ifdef HAVE_SYSV_COMPAT
static bool service_check_gc(Unit *u) {
Service *s = SERVICE(u);
assert(s);
- return !!s->sysv_path;
-}
+ /* Never clean up services that still have a process around,
+ * even if the service is formally dead. */
+ if (cgroup_good(s) > 0 ||
+ main_pid_good(s) > 0 ||
+ control_pid_good(s) > 0)
+ return true;
+
+#ifdef HAVE_SYSV_COMPAT
+ if (s->sysv_path)
+ return true;
#endif
+ return false;
+}
+
static bool service_check_snapshot(Unit *u) {
Service *s = SERVICE(u);
@@ -2767,7 +2777,7 @@ static void service_timer_event(Unit *u, uint64_t elapsed, Watch* w) {
break;
case SERVICE_STOP_SIGKILL:
- /* Uh, wie sent a SIGKILL and it is still not gone?
+ /* Uh, we sent a SIGKILL and it is still not gone?
* Must be something we cannot kill, so let's just be
* weirded out and continue */
@@ -3042,7 +3052,7 @@ static int service_enumerate(Manager *m) {
/* We honour K links only for halt/reboot. For the normal
* runlevels we assume the stop jobs will be implicitly added
- * by the core logic. Also, we don't really distuingish here
+ * by the core logic. Also, we don't really distinguish here
* between the runlevels 0 and 6 and just add them to the
* special shutdown target. On SUSE the boot.d/ runlevel is
* also used for shutdown, so we add links for that too to the
@@ -3317,9 +3327,7 @@ const UnitVTable service_vtable = {
.active_state = service_active_state,
.sub_state_to_string = service_sub_state_to_string,
-#ifdef HAVE_SYSV_COMPAT
.check_gc = service_check_gc,
-#endif
.check_snapshot = service_check_snapshot,
.sigchld_event = service_sigchld_event,
diff --git a/src/shutdown.c b/src/shutdown.c
index 23b9f1b545..5c082cf4a5 100644
--- a/src/shutdown.c
+++ b/src/shutdown.c
@@ -334,7 +334,7 @@ int main(int argc, char *argv[]) {
}
if (retries >= FINALIZE_ATTEMPTS)
- log_error("Too many interations, giving up.");
+ log_error("Too many iterations, giving up.");
execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, NULL);
diff --git a/src/socket.c b/src/socket.c
index c41130ce72..96c649b0ab 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -1363,7 +1363,7 @@ static int socket_start(Unit *u) {
if (s->service->meta.load_state != UNIT_LOADED)
return -ENOENT;
- /* If the service is alredy active we cannot start the
+ /* If the service is already active we cannot start the
* socket */
if (s->service->state != SERVICE_DEAD &&
s->service->state != SERVICE_FAILED &&
@@ -1798,7 +1798,7 @@ void socket_connection_unref(Socket *s) {
/* The service is dead. Yay!
*
- * This is strictly for one-onstance-per-connection
+ * This is strictly for one-instance-per-connection
* services. */
assert(s->n_connections > 0);
diff --git a/src/strv.c b/src/strv.c
index d1c7b2c32d..c8ff5745e8 100644
--- a/src/strv.c
+++ b/src/strv.c
@@ -355,7 +355,7 @@ char **strv_remove(char **l, const char *s) {
if (!l)
return NULL;
- /* Drops every occurence of s in the string list */
+ /* Drops every occurrence of s in the string list */
for (f = t = l; *f; f++) {
@@ -379,7 +379,7 @@ static int env_append(char **r, char ***k, char **a) {
return 0;
/* Add the entries of a to *k unless they already exist in *r
- * in which case they are overriden instead. This assumes
+ * in which case they are overridden instead. This assumes
* there is enough space in the r array. */
for (; *a; a++) {
@@ -474,7 +474,7 @@ char **strv_env_delete(char **x, unsigned n_lists, ...) {
char **l, **k, **r, **j;
va_list ap;
- /* Deletes every entry fromx that is mentioned in the other
+ /* Deletes every entry from x that is mentioned in the other
* string lists */
n = strv_length(x);
@@ -577,3 +577,45 @@ char **strv_env_clean(char **l) {
return ret;
}
+
+char **strv_parse_nulstr(const char *s, size_t l) {
+ const char *p;
+ unsigned c = 0, i = 0;
+ char **v;
+
+ assert(s || l <= 0);
+
+ if (l <= 0)
+ return strv_new(NULL, NULL);
+
+ for (p = s; p < s + l; p++)
+ if (*p == 0)
+ c++;
+
+ if (s[l-1] != 0)
+ c++;
+
+ if (!(v = new0(char*, c+1)))
+ return NULL;
+
+ p = s;
+ while (p < s + l) {
+ const char *e;
+
+ e = memchr(p, 0, s + l - p);
+
+ if (!(v[i++] = strndup(p, e ? e - p : s + l - p))) {
+ strv_free(v);
+ return NULL;
+ }
+
+ if (!e)
+ break;
+
+ p = e + 1;
+ }
+
+ assert(i == c);
+
+ return v;
+}
diff --git a/src/strv.h b/src/strv.h
index 5af84ee41f..064576ce1e 100644
--- a/src/strv.h
+++ b/src/strv.h
@@ -65,6 +65,8 @@ char *strv_env_get(char **x, const char *n);
char **strv_env_clean(char **l);
+char **strv_parse_nulstr(const char *s, size_t l);
+
#define STRV_FOREACH(s, l) \
for ((s) = (l); (s) && *(s); (s)++)
diff --git a/src/swap.h b/src/swap.h
index c39caa6658..0d5c9a23f0 100644
--- a/src/swap.h
+++ b/src/swap.h
@@ -89,7 +89,7 @@ struct Swap {
Watch timer_watch;
- /* In order to be able to distuingish dependencies on
+ /* In order to be able to distinguish dependencies on
different device nodes we might end up creating multiple
devices for the same swap. We chain them up here. */
diff --git a/src/systemadm.vala b/src/systemadm.vala
index 33777b6b8b..c262794cb7 100644
--- a/src/systemadm.vala
+++ b/src/systemadm.vala
@@ -762,7 +762,7 @@ public class MainWindow : Window {
} while (unit_model.iter_next(ref iter));
}
- public void on_job_removed(uint32 id, ObjectPath path, bool success) {
+ public void on_job_removed(uint32 id, ObjectPath path, string res) {
TreeIter iter;
if (!(job_model.get_iter_first(out iter)))
return;
diff --git a/src/systemctl.c b/src/systemctl.c
index 4a8b9a196f..c08e78c26d 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -112,6 +112,7 @@ static enum dot {
static bool private_bus = false;
static pid_t pager_pid = 0;
+static pid_t agent_pid = 0;
static int daemon_reload(DBusConnection *bus, char **args, unsigned n);
static void pager_open(void);
@@ -132,7 +133,10 @@ static bool on_tty(void) {
}
static void spawn_ask_password_agent(void) {
- pid_t parent, child;
+ pid_t parent;
+
+ if (agent_pid > 0)
+ return;
/* We check STDIN here, not STDOUT, since this is about input,
* not output */
@@ -150,16 +154,11 @@ static void spawn_ask_password_agent(void) {
/* Spawns a temporary TTY agent, making sure it goes away when
* we go away */
- if ((child = fork()) < 0)
+ if ((agent_pid = fork()) < 0)
return;
- if (child == 0) {
+ if (agent_pid == 0) {
/* In the child */
- const char * const args[] = {
- SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH,
- "--watch",
- NULL
- };
int fd;
bool stdout_is_tty, stderr_is_tty;
@@ -202,7 +201,9 @@ static void spawn_ask_password_agent(void) {
close(fd);
}
- execv(args[0], (char **) args);
+ execl(SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, SYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH, "--watch", NULL);
+
+ log_error("Unable to execute agent: %m");
_exit(EXIT_FAILURE);
}
}
@@ -1120,7 +1121,7 @@ finish:
typedef struct WaitData {
Set *set;
- bool failed;
+ char *result;
} WaitData;
static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *message, void *data) {
@@ -1144,26 +1145,52 @@ static DBusHandlerResult wait_filter(DBusConnection *connection, DBusMessage *me
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
- const char *path;
+ const char *path, *result;
dbus_bool_t success = true;
- if (!dbus_message_get_args(message, &error,
- DBUS_TYPE_UINT32, &id,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_BOOLEAN, &success,
- DBUS_TYPE_INVALID))
- log_error("Failed to parse message: %s", bus_error_message(&error));
- else {
+ if (dbus_message_get_args(message, &error,
+ DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &result,
+ DBUS_TYPE_INVALID)) {
+ char *p;
+
+ if ((p = set_remove(d->set, (char*) path)))
+ free(p);
+
+ if (*result)
+ d->result = strdup(result);
+
+ goto finish;
+ }
+#ifndef LEGACY
+ dbus_error_free(&error);
+
+ if (dbus_message_get_args(message, &error,
+ DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_BOOLEAN, &success,
+ DBUS_TYPE_INVALID)) {
char *p;
+ /* Compatibility with older systemd versions <
+ * 19 during upgrades. This should be dropped
+ * one day */
+
if ((p = set_remove(d->set, (char*) path)))
free(p);
if (!success)
- d->failed = true;
+ d->result = strdup("failed");
+
+ goto finish;
}
+#endif
+
+ log_error("Failed to parse message: %s", bus_error_message(&error));
}
+finish:
dbus_error_free(&error);
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
@@ -1204,7 +1231,6 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) {
zero(d);
d.set = s;
- d.failed = false;
if (!dbus_connection_add_filter(bus, wait_filter, &d, NULL)) {
log_error("Failed to add filter.");
@@ -1216,10 +1242,27 @@ static int wait_for_jobs(DBusConnection *bus, Set *s) {
dbus_connection_read_write_dispatch(bus, -1))
;
- if (!arg_quiet && d.failed)
- log_error("Job failed. See system logs and 'systemctl status' for details.");
+ if (!arg_quiet && d.result) {
+ if (streq(d.result, "timeout"))
+ log_error("Job timed out.");
+ else if (streq(d.result, "canceled"))
+ log_error("Job canceled.");
+ else if (streq(d.result, "dependency"))
+ log_error("A dependency job failed. See system logs for details.");
+ else if (!streq(d.result, "done"))
+ log_error("Job failed. See system logs and 'systemctl status' for details.");
+ }
+
+ if (streq_ptr(d.result, "timeout"))
+ r = -ETIME;
+ else if (streq_ptr(d.result, "canceled"))
+ r = -ECANCELED;
+ else if (!streq_ptr(d.result, "done"))
+ r = -EIO;
+ else
+ r = 0;
- r = d.failed ? -EIO : 0;
+ free(d.result);
finish:
/* This is slightly dirty, since we don't undo the filter registration. */
@@ -2750,11 +2793,12 @@ static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage
} else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
- const char *path;
+ const char *path, *result;
if (!dbus_message_get_args(message, &error,
DBUS_TYPE_UINT32, &id,
DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_STRING, &result,
DBUS_TYPE_INVALID))
log_error("Failed to parse message: %s", bus_error_message(&error));
else if (streq(dbus_message_get_member(message), "JobNew"))
@@ -4668,6 +4712,18 @@ static int parse_time_spec(const char *t, usec_t *_u) {
return 0;
}
+static bool kexec_loaded(void) {
+ bool loaded = false;
+ char *s;
+
+ if (read_one_line_file("/sys/kernel/kexec_loaded", &s) >= 0) {
+ if (s[0] == '1')
+ loaded = true;
+ free(s);
+ }
+ return loaded;
+}
+
static int shutdown_parse_argv(int argc, char *argv[]) {
enum {
@@ -4705,7 +4761,10 @@ static int shutdown_parse_argv(int argc, char *argv[]) {
break;
case 'r':
- arg_action = ACTION_REBOOT;
+ if (kexec_loaded())
+ arg_action = ACTION_KEXEC;
+ else
+ arg_action = ACTION_REBOOT;
break;
case 'h':
@@ -4898,7 +4957,10 @@ static int parse_argv(int argc, char *argv[]) {
arg_action = ACTION_POWEROFF;
return halt_parse_argv(argc, argv);
} else if (strstr(program_invocation_short_name, "reboot")) {
- arg_action = ACTION_REBOOT;
+ if (kexec_loaded())
+ arg_action = ACTION_KEXEC;
+ else
+ arg_action = ACTION_REBOOT;
return halt_parse_argv(argc, argv);
} else if (strstr(program_invocation_short_name, "shutdown")) {
arg_action = ACTION_POWEROFF;
@@ -5386,6 +5448,7 @@ static int runlevel_main(void) {
static void pager_open(void) {
int fd[2];
const char *pager;
+ pid_t parent_pid;
if (pager_pid > 0)
return;
@@ -5406,6 +5469,8 @@ static void pager_open(void) {
return;
}
+ parent_pid = getpid();
+
pager_pid = fork();
if (pager_pid < 0) {
log_error("Failed to fork pager: %m");
@@ -5421,7 +5486,14 @@ static void pager_open(void) {
setenv("LESS", "FRSX", 0);
- prctl(PR_SET_PDEATHSIG, SIGTERM);
+ /* Make sure the pager goes away when the parent dies */
+ if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
+ _exit(EXIT_FAILURE);
+
+ /* Check whether our parent died before we were able
+ * to set the death signal */
+ if (getppid() != parent_pid)
+ _exit(EXIT_SUCCESS);
if (pager) {
execlp(pager, pager, NULL);
@@ -5462,6 +5534,18 @@ static void pager_close(void) {
pager_pid = 0;
}
+static void agent_close(void) {
+ siginfo_t dummy;
+
+ if (agent_pid <= 0)
+ return;
+
+ /* Inform agent that we are done */
+ kill(agent_pid, SIGTERM);
+ wait_for_terminate(agent_pid, &dummy);
+ agent_pid = 0;
+}
+
int main(int argc, char*argv[]) {
int r, retval = EXIT_FAILURE;
DBusConnection *bus = NULL;
@@ -5498,6 +5582,7 @@ int main(int argc, char*argv[]) {
case ACTION_HALT:
case ACTION_POWEROFF:
case ACTION_REBOOT:
+ case ACTION_KEXEC:
r = halt_main(bus);
break;
@@ -5543,6 +5628,7 @@ finish:
strv_free(arg_property);
pager_close();
+ agent_close();
return retval;
}
diff --git a/src/systemd-interfaces.vala b/src/systemd-interfaces.vala
index e3b7941288..a380f7970b 100644
--- a/src/systemd-interfaces.vala
+++ b/src/systemd-interfaces.vala
@@ -85,7 +85,7 @@ public interface Manager : DBusProxy {
public abstract signal void unit_new(string id, ObjectPath path);
public abstract signal void unit_removed(string id, ObjectPath path);
public abstract signal void job_new(uint32 id, ObjectPath path);
- public abstract signal void job_removed(uint32 id, ObjectPath path, bool success);
+ public abstract signal void job_removed(uint32 id, ObjectPath path, string res);
}
[DBus (name = "org.freedesktop.systemd1.Unit")]
diff --git a/src/test-engine.c b/src/test-engine.c
index 157b7f9fda..60619b9d36 100644
--- a/src/test-engine.c
+++ b/src/test-engine.c
@@ -74,14 +74,14 @@ int main(int argc, char *argv[]) {
assert_se(manager_add_job(m, JOB_START, g, JOB_REPLACE, false, NULL, &j) == 0);
manager_dump_jobs(m, stdout, "\t");
- printf("Test7: (Unmeargable job type, fail)\n");
+ printf("Test7: (Unmergeable job type, fail)\n");
assert_se(manager_add_job(m, JOB_STOP, g, JOB_FAIL, false, NULL, &j) == -EEXIST);
printf("Test8: (Mergeable job type, fail)\n");
assert_se(manager_add_job(m, JOB_RESTART, g, JOB_FAIL, false, NULL, &j) == 0);
manager_dump_jobs(m, stdout, "\t");
- printf("Test9: (Unmeargable job type, replace)\n");
+ printf("Test9: (Unmergeable job type, replace)\n");
assert_se(manager_add_job(m, JOB_STOP, g, JOB_REPLACE, false, NULL, &j) == 0);
manager_dump_jobs(m, stdout, "\t");
@@ -89,7 +89,7 @@ int main(int argc, char *argv[]) {
assert_se(manager_load_unit(m, "h.service", NULL, NULL, &h) >= 0);
manager_dump_units(m, stdout, "\t");
- printf("Test10: (Unmeargable job type of auxiliary job, fail)\n");
+ printf("Test10: (Unmergeable job type of auxiliary job, fail)\n");
assert_se(manager_add_job(m, JOB_START, h, JOB_FAIL, false, NULL, &j) == 0);
manager_dump_jobs(m, stdout, "\t");
diff --git a/src/test-env-replace.c b/src/test-env-replace.c
index 4188c67dde..05dbacd7df 100644
--- a/src/test-env-replace.c
+++ b/src/test-env-replace.c
@@ -48,6 +48,14 @@ int main(int argc, char *argv[]) {
};
char **i, **r, *t, **a, **b;
+ const char nulstr[] = "fuck\0fuck2\0fuck3\0\0fuck5\0\0xxx";
+
+ a = strv_parse_nulstr(nulstr, sizeof(nulstr)-1);
+
+ STRV_FOREACH(i, a)
+ printf("nulstr--%s\n", *i);
+
+ strv_free(a);
r = replace_env_argv((char**) line, (char**) env);
diff --git a/src/test-job-type.c b/src/test-job-type.c
index 9e2fc35f4e..9de21e1823 100644
--- a/src/test-job-type.c
+++ b/src/test-job-type.c
@@ -55,7 +55,7 @@ int main(int argc, char*argv[]) {
assert(!job_type_is_mergeable(b, c) || job_type_is_mergeable(d, c));
/* Verify that if a merged
- * with b is not mergable with
+ * with b is not mergeable with
* c then either a or b is not
* mergeable with c either. */
assert(job_type_is_mergeable(d, c) || !job_type_is_mergeable(a, c) || !job_type_is_mergeable(b, c));
diff --git a/src/tmpfiles.c b/src/tmpfiles.c
index 01668da87e..0c3b88d35b 100644
--- a/src/tmpfiles.c
+++ b/src/tmpfiles.c
@@ -147,6 +147,8 @@ static void load_unix_sockets(void) {
if (!(s = strdup(p)))
goto fail;
+ path_kill_slashes(s);
+
if ((k = set_put(unix_sockets, s)) < 0) {
free(s);
@@ -301,6 +303,10 @@ static int dir_cleanup(
if (S_ISSOCK(s.st_mode) && unix_socket_alive(sub_path))
continue;
+ /* Ignore device nodes */
+ if (S_ISCHR(s.st_mode) || S_ISBLK(s.st_mode))
+ continue;
+
age = MAX3(timespec_load(&s.st_mtim),
timespec_load(&s.st_atim),
timespec_load(&s.st_ctim));
@@ -501,7 +507,7 @@ static int create_item(Item *i) {
break;
}
- if ((r = label_fix(i->path)) < 0)
+ if ((r = label_fix(i->path, false)) < 0)
goto finish;
log_debug("%s created successfully.", i->path);
@@ -846,7 +852,7 @@ static int parse_argv(int argc, char *argv[]) {
}
if (!arg_clean && !arg_create && !arg_remove) {
- log_error("You need to specify at leat one of --clean, --create or --remove.");
+ log_error("You need to specify at least one of --clean, --create or --remove.");
return -EINVAL;
}
diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c
index 00496e7119..a9d06ac001 100644
--- a/src/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent.c
@@ -37,6 +37,7 @@
#include "utmp-wtmp.h"
#include "socket-util.h"
#include "ask-password-api.h"
+#include "strv.h"
static enum {
ACTION_LIST,
@@ -48,7 +49,13 @@ static enum {
static bool arg_plymouth = false;
static bool arg_console = false;
-static int ask_password_plymouth(const char *message, usec_t until, const char *flag_file, char **_passphrase) {
+static int ask_password_plymouth(
+ const char *message,
+ usec_t until,
+ const char *flag_file,
+ bool accept_cached,
+ char ***_passphrases) {
+
int fd = -1, notify = -1;
union sockaddr_union sa;
char *packet = NULL;
@@ -62,6 +69,8 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
POLL_INOTIFY
};
+ assert(_passphrases);
+
if (flag_file) {
if ((notify = inotify_init1(IN_CLOEXEC|IN_NONBLOCK)) < 0) {
r = -errno;
@@ -83,12 +92,18 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
sa.sa.sa_family = AF_UNIX;
strncpy(sa.un.sun_path+1, "/org/freedesktop/plymouthd", sizeof(sa.un.sun_path)-1);
if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
- log_error("FAILED TO CONNECT: %m");
+ log_error("Failed to connect to Plymouth: %m");
r = -errno;
goto finish;
}
- if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
+ if (accept_cached) {
+ packet = strdup("c");
+ n = 1;
+ } else
+ asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n);
+
+ if (!packet) {
r = -ENOMEM;
goto finish;
}
@@ -113,7 +128,7 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
y = now(CLOCK_MONOTONIC);
if (y > until) {
- r = -ETIMEDOUT;
+ r = -ETIME;
goto finish;
}
@@ -134,7 +149,7 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
r = -errno;
goto finish;
} else if (j == 0) {
- r = -ETIMEDOUT;
+ r = -ETIME;
goto finish;
}
@@ -155,15 +170,38 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
continue;
if (buffer[0] == 5) {
+
+ if (accept_cached) {
+ /* Hmm, first try with cached
+ * passwords failed, so let's retry
+ * with a normal password request */
+ free(packet);
+ packet = NULL;
+
+ if (asprintf(&packet, "*\002%c%s%n", (int) (strlen(message) + 1), message, &n) < 0) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ if ((k = loop_write(fd, packet, n+1, true)) != n+1) {
+ r = k < 0 ? (int) k : -EIO;
+ goto finish;
+ }
+
+ accept_cached = false;
+ p = 0;
+ continue;
+ }
+
/* No password, because UI not shown */
r = -ENOENT;
goto finish;
- } else if (buffer[0] == 2) {
+ } else if (buffer[0] == 2 || buffer[0] == 9) {
uint32_t size;
- char *s;
+ char **l;
- /* One answer */
+ /* One ore more answers */
if (p < 5)
continue;
@@ -176,13 +214,14 @@ static int ask_password_plymouth(const char *message, usec_t until, const char *
if (p-5 < size)
continue;
- if (!(s = strndup(buffer + 5, size))) {
+ if (!(l = strv_parse_nulstr(buffer + 5, size))) {
r = -ENOMEM;
goto finish;
}
- *_passphrase = s;
+ *_passphrases = l;
break;
+
} else {
/* Unknown packet */
r = -EIO;
@@ -209,12 +248,14 @@ static int parse_password(const char *filename, char **wall) {
uint64_t not_after = 0;
unsigned pid = 0;
int socket_fd = -1;
+ bool accept_cached = false;
const ConfigItem items[] = {
- { "Socket", config_parse_string, &socket_name, "Ask" },
- { "NotAfter", config_parse_uint64, &not_after, "Ask" },
- { "Message", config_parse_string, &message, "Ask" },
- { "PID", config_parse_unsigned, &pid, "Ask" },
+ { "Socket", config_parse_string, &socket_name, "Ask" },
+ { "NotAfter", config_parse_uint64, &not_after, "Ask" },
+ { "Message", config_parse_string, &message, "Ask" },
+ { "PID", config_parse_unsigned, &pid, "Ask" },
+ { "AcceptCached", config_parse_bool, &accept_cached, "Ask" },
{ NULL, NULL, NULL, NULL }
};
@@ -274,7 +315,7 @@ static int parse_password(const char *filename, char **wall) {
struct sockaddr sa;
struct sockaddr_un un;
} sa;
- char *password;
+ size_t packet_length = 0;
assert(arg_action == ACTION_QUERY ||
arg_action == ACTION_WATCH);
@@ -288,10 +329,32 @@ static int parse_password(const char *filename, char **wall) {
goto finish;
}
- if (arg_plymouth)
- r = ask_password_plymouth(message, not_after, filename, &password);
- else {
+ if (arg_plymouth) {
+ char **passwords = NULL;
+
+ if ((r = ask_password_plymouth(message, not_after, filename, accept_cached, &passwords)) >= 0) {
+ char **p;
+
+ packet_length = 1;
+ STRV_FOREACH(p, passwords)
+ packet_length += strlen(*p) + 1;
+
+ if (!(packet = new(char, packet_length)))
+ r = -ENOMEM;
+ else {
+ char *d;
+
+ packet[0] = '+';
+ d = packet+1;
+
+ STRV_FOREACH(p, passwords)
+ d = stpcpy(d, *p) + 1;
+ }
+ }
+
+ } else {
int tty_fd = -1;
+ char *password;
if (arg_console)
if ((tty_fd = acquire_terminal("/dev/console", false, false, false)) < 0) {
@@ -305,16 +368,25 @@ static int parse_password(const char *filename, char **wall) {
close_nointr_nofail(tty_fd);
release_terminal();
}
+
+ asprintf(&packet, "+%s", password);
+ free(password);
+
+ packet_length = strlen(packet);
+ }
+
+ if (r == -ETIME || r == -ENOENT) {
+ /* If the query went away, that's OK */
+ r = 0;
+ goto finish;
}
if (r < 0) {
+
log_error("Failed to query password: %s", strerror(-r));
goto finish;
}
- asprintf(&packet, "+%s", password);
- free(password);
-
if (!packet) {
log_error("Out of memory");
r = -ENOMEM;
@@ -331,7 +403,7 @@ static int parse_password(const char *filename, char **wall) {
sa.un.sun_family = AF_UNIX;
strncpy(sa.un.sun_path, socket_name, sizeof(sa.un.sun_path));
- if (sendto(socket_fd, packet, strlen(packet), MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) {
+ if (sendto(socket_fd, packet, packet_length, MSG_NOSIGNAL, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(socket_name)) < 0) {
log_error("Failed to send: %m");
r = -errno;
goto finish;
@@ -353,13 +425,13 @@ finish:
static int wall_tty_block(void) {
char *p;
- const char *t;
- int fd;
+ int fd, r;
+ dev_t devnr;
- if (!(t = ttyname(STDIN_FILENO)))
- return -errno;
+ if ((r = get_ctty_devnr(&devnr)) < 0)
+ return -r;
- if (asprintf(&p, "/dev/.systemd/ask-password-block/%s", file_name_from_path(t)) < 0)
+ if (asprintf(&p, "/dev/.systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0)
return -ENOMEM;
mkdir_parents(p, 0700);
@@ -375,8 +447,25 @@ static int wall_tty_block(void) {
}
static bool wall_tty_match(const char *path) {
- int fd;
+ int fd, k;
char *p;
+ struct stat st;
+
+ if (path_is_absolute(path))
+ k = lstat(path, &st);
+ else {
+ if (asprintf(&p, "/dev/%s", path) < 0)
+ return true;
+
+ k = lstat(p, &st);
+ free(p);
+ }
+
+ if (k < 0)
+ return true;
+
+ if (!S_ISCHR(st.st_mode))
+ return true;
/* We use named pipes to ensure that wall messages suggesting
* password entry are not printed over password prompts
@@ -386,7 +475,7 @@ static bool wall_tty_match(const char *path) {
* advantage that the block will automatically go away if the
* process dies. */
- if (asprintf(&p, "/dev/.systemd/ask-password-block/%s", file_name_from_path(path)) < 0)
+ if (asprintf(&p, "/dev/.systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0)
return true;
fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
@@ -536,8 +625,8 @@ static int help(void) {
" -h --help Show this help\n"
" --list Show pending password requests\n"
" --query Process pending password requests\n"
- " --watch Continously process password requests\n"
- " --wall Continously forward password requests to wall\n"
+ " --watch Continuously process password requests\n"
+ " --wall Continuously forward password requests to wall\n"
" --plymouth Ask question with Plymouth instead of on TTY\n"
" --console Ask question on /dev/console instead of current TTY\n",
program_invocation_short_name);
diff --git a/src/unit-name.c b/src/unit-name.c
index debf2b2653..be4e73edcc 100644
--- a/src/unit-name.c
+++ b/src/unit-name.c
@@ -213,7 +213,7 @@ char *unit_name_build_escape(const char *prefix, const char *instance, const cha
* suffix and makes a nice string suitable as unit name of it,
* escaping all weird chars on the way.
*
- * / becomes ., and all chars not alloweed in a unit name get
+ * / becomes ., and all chars not allowed in a unit name get
* escaped as \xFF, including \ and ., of course. This
* escaping is hence reversible.
*
diff --git a/src/unit.c b/src/unit.c
index 0d5312376c..359cb2d084 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -736,7 +736,7 @@ int unit_add_default_target_dependency(Unit *u, Unit *target) {
if (target->meta.type != UNIT_TARGET)
return 0;
- /* Only add the dependency if boths units are loaded, so that
+ /* Only add the dependency if both units are loaded, so that
* that loop check below is reliable */
if (u->meta.load_state != UNIT_LOADED ||
target->meta.load_state != UNIT_LOADED)
@@ -1071,6 +1071,16 @@ static void retroactively_stop_dependencies(Unit *u) {
unit_check_unneeded(other);
}
+void unit_trigger_on_failure(Unit *u) {
+ Unit *other;
+ Iterator i;
+
+ assert(u);
+
+ SET_FOREACH(other, u->meta.dependencies[UNIT_ON_FAILURE], i)
+ manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
+}
+
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
dual_timestamp ts;
bool unexpected;
@@ -1114,7 +1124,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
job_add_to_run_queue(u->meta.job);
/* Let's check whether this state change constitutes a
- * finished job, or maybe cotradicts a running job and
+ * finished job, or maybe contradicts a running job and
* hence needs to invalidate jobs. */
switch (u->meta.job->type) {
@@ -1123,12 +1133,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
case JOB_VERIFY_ACTIVE:
if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
- job_finish_and_invalidate(u->meta.job, true);
+ job_finish_and_invalidate(u->meta.job, JOB_DONE);
else if (u->meta.job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
unexpected = true;
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->meta.job, ns != UNIT_FAILED);
+ job_finish_and_invalidate(u->meta.job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE);
}
break;
@@ -1138,12 +1148,12 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
if (u->meta.job->state == JOB_RUNNING) {
if (ns == UNIT_ACTIVE)
- job_finish_and_invalidate(u->meta.job, reload_success);
+ job_finish_and_invalidate(u->meta.job, reload_success ? JOB_DONE : JOB_FAILED);
else if (ns != UNIT_ACTIVATING && ns != UNIT_RELOADING) {
unexpected = true;
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->meta.job, ns != UNIT_FAILED);
+ job_finish_and_invalidate(u->meta.job, ns == UNIT_FAILED ? JOB_FAILED : JOB_DONE);
}
}
@@ -1154,10 +1164,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
case JOB_TRY_RESTART:
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
- job_finish_and_invalidate(u->meta.job, true);
+ job_finish_and_invalidate(u->meta.job, JOB_DONE);
else if (u->meta.job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
unexpected = true;
- job_finish_and_invalidate(u->meta.job, false);
+ job_finish_and_invalidate(u->meta.job, JOB_FAILED);
}
break;
@@ -1183,13 +1193,8 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
}
if (ns != os && ns == UNIT_FAILED) {
- Iterator i;
- Unit *other;
-
- SET_FOREACH(other, u->meta.dependencies[UNIT_ON_FAILURE], i)
- manager_add_job(u->meta.manager, JOB_START, other, JOB_REPLACE, true, NULL, NULL);
-
log_notice("Unit %s entered failed state.", u->meta.id);
+ unit_trigger_on_failure(u);
}
/* Some names are special */
diff --git a/src/unit.h b/src/unit.h
index b30f0cf9cb..5f55a89da8 100644
--- a/src/unit.h
+++ b/src/unit.h
@@ -40,7 +40,7 @@ typedef enum UnitDependency UnitDependency;
#include "execute.h"
#include "condition.h"
-#define DEFAULT_TIMEOUT_USEC (60*USEC_PER_SEC)
+#define DEFAULT_TIMEOUT_USEC (3*USEC_PER_MINUTE)
#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
enum UnitType {
@@ -196,7 +196,7 @@ struct Meta {
/* Garbage collect us we nobody wants or requires us anymore */
bool stop_when_unneeded;
- /* Create default depedencies */
+ /* Create default dependencies */
bool default_dependencies;
/* Refuse manual starting, allow starting only indirectly via dependency. */
@@ -290,7 +290,7 @@ struct UnitVTable {
/* Returns the substate specific to this unit type as
* string. This is purely information so that we can give the
- * user a more finegrained explanation in which actual state a
+ * user a more fine grained explanation in which actual state a
* unit is in. */
const char* (*sub_state_to_string)(Unit *u);
@@ -511,6 +511,8 @@ int unit_following_set(Unit *u, Set **s);
UnitType unit_name_to_type(const char *n);
bool unit_name_is_valid(const char *n, bool template_ok);
+void unit_trigger_on_failure(Unit *u);
+
const char *unit_load_state_to_string(UnitLoadState i);
UnitLoadState unit_load_state_from_string(const char *s);
diff --git a/src/util.c b/src/util.c
index 16e4ab289a..e2859fafc1 100644
--- a/src/util.c
+++ b/src/util.c
@@ -2134,8 +2134,32 @@ finish:
int open_terminal(const char *name, int mode) {
int fd, r;
+ unsigned c = 0;
- if ((fd = open(name, mode)) < 0)
+ /*
+ * If a TTY is in the process of being closed opening it might
+ * cause EIO. This is horribly awful, but unlikely to be
+ * changed in the kernel. Hence we work around this problem by
+ * retrying a couple of times.
+ *
+ * https://bugs.launchpad.net/ubuntu/+source/linux/+bug/554172/comments/245
+ */
+
+ for (;;) {
+ if ((fd = open(name, mode)) >= 0)
+ break;
+
+ if (errno != EIO)
+ return -errno;
+
+ if (c >= 20)
+ return -errno;
+
+ usleep(50 * USEC_PER_MSEC);
+ c++;
+ }
+
+ if (fd < 0)
return -errno;
if ((r = isatty(fd)) < 0) {
@@ -2749,28 +2773,121 @@ char* getlogname_malloc(void) {
return name;
}
-int getttyname_malloc(char **r) {
- char path[PATH_MAX], *p, *c;
+int getttyname_malloc(int fd, char **r) {
+ char path[PATH_MAX], *c;
int k;
assert(r);
- if ((k = ttyname_r(STDIN_FILENO, path, sizeof(path))) != 0)
+ if ((k = ttyname_r(fd, path, sizeof(path))) != 0)
return -k;
char_array_0(path);
- p = path;
- if (startswith(path, "/dev/"))
- p += 5;
-
- if (!(c = strdup(p)))
+ if (!(c = strdup(startswith(path, "/dev/") ? path + 5 : path)))
return -ENOMEM;
*r = c;
return 0;
}
+int getttyname_harder(int fd, char **r) {
+ int k;
+ char *s;
+
+ if ((k = getttyname_malloc(fd, &s)) < 0)
+ return k;
+
+ if (streq(s, "tty")) {
+ free(s);
+ return get_ctty(r);
+ }
+
+ *r = s;
+ return 0;
+}
+
+int get_ctty_devnr(dev_t *d) {
+ int k;
+ char line[256], *p;
+ unsigned long ttynr;
+ FILE *f;
+
+ if (!(f = fopen("/proc/self/stat", "r")))
+ return -errno;
+
+ if (!(fgets(line, sizeof(line), f))) {
+ k = -errno;
+ fclose(f);
+ return k;
+ }
+
+ fclose(f);
+
+ if (!(p = strrchr(line, ')')))
+ return -EIO;
+
+ p++;
+
+ if (sscanf(p, " "
+ "%*c " /* state */
+ "%*d " /* ppid */
+ "%*d " /* pgrp */
+ "%*d " /* session */
+ "%lu ", /* ttynr */
+ &ttynr) != 1)
+ return -EIO;
+
+ *d = (dev_t) ttynr;
+ return 0;
+}
+
+int get_ctty(char **r) {
+ int k;
+ char fn[128], *s, *b, *p;
+ dev_t devnr;
+
+ assert(r);
+
+ if ((k = get_ctty_devnr(&devnr)) < 0)
+ return k;
+
+ snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr));
+ char_array_0(fn);
+
+ if ((k = readlink_malloc(fn, &s)) < 0) {
+
+ if (k != -ENOENT)
+ return k;
+
+ /* Probably something like the ptys which have no
+ * symlink in /dev/char. Let's return something
+ * vaguely useful. */
+
+ if (!(b = strdup(fn + 5)))
+ return -ENOMEM;
+
+ *r = b;
+ return 0;
+ }
+
+ if (startswith(s, "/dev/"))
+ p = s + 5;
+ else if (startswith(s, "../"))
+ p = s + 3;
+ else
+ p = s;
+
+ b = strdup(p);
+ free(s);
+
+ if (!b)
+ return -ENOMEM;
+
+ *r = b;
+ return 0;
+}
+
static int rm_rf_children(int fd, bool only_dirs) {
DIR *d;
int ret = 0;
@@ -3589,51 +3706,51 @@ const char *default_term_for_tty(const char *tty) {
return term;
}
-bool running_in_vm(void) {
+/* 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... */
- const char *const dmi_vendors[] = {
+ static const char *const dmi_vendors[] = {
"/sys/class/dmi/id/sys_vendor",
"/sys/class/dmi/id/board_vendor",
"/sys/class/dmi/id/bios_vendor"
};
- uint32_t eax = 0x40000000;
+ 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"
+ "\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"
+ "\0";
+
+ uint32_t eax, ecx;
union {
uint32_t sig32[3];
char text[13];
} sig;
-
unsigned i;
-
- for (i = 0; i < ELEMENTSOF(dmi_vendors); i++) {
- char *s;
- bool b;
-
- if (read_one_line_file(dmi_vendors[i], &s) < 0)
- continue;
-
- b = startswith(s, "QEMU") ||
- /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
- startswith(s, "VMware") ||
- startswith(s, "VMW") ||
- startswith(s, "Microsoft Corporation") ||
- startswith(s, "innotek GmbH") ||
- startswith(s, "Xen");
-
- free(s);
-
- if (b)
- return true;
- }
+ const char *j, *k;
+ bool hypervisor;
/* http://lwn.net/Articles/301888/ */
zero(sig);
-
#if defined (__i386__)
#define REG_a "eax"
#define REG_b "ebx"
@@ -3642,27 +3759,109 @@ bool running_in_vm(void) {
#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"
- " mov %%ebx, %1 \n\t"
" pop %%"REG_b" \n\t"
- : "=a" (eax), "=r" (sig.sig32[0]), "=c" (sig.sig32[1]), "=d" (sig.sig32[2])
+ : "=a" (eax), "=c" (ecx)
: "0" (eax)
);
- if (streq(sig.text, "XenVMMXenVMM") ||
- streq(sig.text, "KVMKVMKVM") ||
- /* http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=1009458 */
- streq(sig.text, "VMwareVMware") ||
- /* http://msdn.microsoft.com/en-us/library/bb969719.aspx */
- streq(sig.text, "Microsoft Hv"))
- return true;
+ hypervisor = !!(ecx & 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;
+}
- return false;
+/* Returns a short identifier for the various VM/container implementations */
+int detect_virtualization(const char **id) {
+ int r;
+
+ /* Unfortunately most of these operations require root access
+ * in one way or another */
+ if (geteuid() != 0)
+ return -EPERM;
+
+ if ((r = running_in_chroot()) > 0) {
+ if (id)
+ *id = "chroot";
+
+ return r;
+ }
+
+ /* /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;
+ }
+
+ return detect_vm(id);
}
void execute_directory(const char *directory, DIR *d, char *argv[]) {
diff --git a/src/util.h b/src/util.h
index 3898b89ff1..7f2cc080a7 100644
--- a/src/util.h
+++ b/src/util.h
@@ -331,7 +331,12 @@ void sigset_add_many(sigset_t *ss, ...);
char* gethostname_malloc(void);
char* getlogname_malloc(void);
-int getttyname_malloc(char **r);
+
+int getttyname_malloc(int fd, char **r);
+int getttyname_harder(int fd, char **r);
+
+int get_ctty_devnr(dev_t *d);
+int get_ctty(char **r);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
@@ -373,7 +378,8 @@ void filter_environ(const char *prefix);
bool tty_is_vc(const char *tty);
const char *default_term_for_tty(const char *tty);
-bool running_in_vm(void);
+int detect_vm(const char **id);
+int detect_virtualization(const char **id);
void execute_directory(const char *directory, DIR *_d, char *argv[]);
diff --git a/src/utmp-wtmp.c b/src/utmp-wtmp.c
index 83da640bf3..b03a3e70af 100644
--- a/src/utmp-wtmp.c
+++ b/src/utmp-wtmp.c
@@ -370,7 +370,7 @@ int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) {
goto finish;
}
- getttyname_malloc(&tty);
+ getttyname_harder(STDIN_FILENO, &tty);
if (asprintf(&text,
"\a\r\n"
diff --git a/units/emergency.service b/units/emergency.service
index aa3d9856c0..cb28a78385 100644
--- a/units/emergency.service
+++ b/units/emergency.service
@@ -16,10 +16,10 @@ Before=shutdown.target
[Service]
Environment=HOME=/root
WorkingDirectory=/root
-ExecStartPre=-/bin/plymouth --hide-splash
+ExecStartPre=-/bin/plymouth quit
ExecStartPre=-/bin/echo 'Welcome to emergency mode. Use "systemctl default" or ^D to activate default mode.'
ExecStart=-/sbin/sulogin
-ExecStopPost=/bin/systemctl default
+ExecStopPost=/bin/systemctl --fail default
StandardInput=tty-force
KillMode=process-group
diff --git a/units/fsck-root.service.in b/units/fsck-root.service.in
index 3df2cd3809..290c8453cc 100644
--- a/units/fsck-root.service.in
+++ b/units/fsck-root.service.in
@@ -20,3 +20,4 @@ RemainAfterExit=no
ExecStart=@rootlibexecdir@/systemd-fsck
StandardOutput=syslog+console
FsckPassNo=1
+TimeoutSec=0
diff --git a/units/fsck@.service.in b/units/fsck@.service.in
index 4751974312..ad9ec3bcc9 100644
--- a/units/fsck@.service.in
+++ b/units/fsck@.service.in
@@ -10,10 +10,11 @@ Description=File System Check on %f
DefaultDependencies=no
BindTo=%i.device
After=systemd-readahead-collect.service systemd-readahead-replay.service %i.device
-Before=local-fs.target shutdown.target
+Before=basic.target shutdown.target
[Service]
Type=oneshot
RemainAfterExit=no
ExecStart=@rootlibexecdir@/systemd-fsck %f
StandardOutput=syslog+console
+TimeoutSec=0
diff --git a/units/getty@.service.m4 b/units/getty@.service.m4
index 74ec1f30d5..d282912274 100644
--- a/units/getty@.service.m4
+++ b/units/getty@.service.m4
@@ -8,7 +8,7 @@
[Unit]
Description=Getty on %I
BindTo=dev-%i.device
-After=dev-%i.device systemd-user-sessions.service
+After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service
m4_ifdef(`TARGET_FEDORA',
After=rc-local.service
)m4_dnl
@@ -18,6 +18,9 @@ After=rc-local.service
m4_ifdef(`TARGET_FRUGALWARE',
After=local.service
)m4_dnl
+m4_ifdef(`TARGET_ALTLINUX',
+After=rc-local.service
+)m4_dnl
# If additional gettys are spawned during boot then we should make
# sure that this is synchronized before getty.target, even though
diff --git a/units/plymouth-quit-wait.service b/units/plymouth-quit-wait.service
new file mode 100644
index 0000000000..45c67bdabd
--- /dev/null
+++ b/units/plymouth-quit-wait.service
@@ -0,0 +1,15 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Wait for Plymouth Boot Screen to Quit
+After=rc-local.service plymouth-start.service
+
+[Service]
+ExecStart=-/bin/plymouth --wait
+Type=oneshot
+TimeoutSec=20
diff --git a/units/plymouth-quit.service b/units/plymouth-quit.service
index 6310eff495..164499a2a6 100644
--- a/units/plymouth-quit.service
+++ b/units/plymouth-quit.service
@@ -7,9 +7,9 @@
[Unit]
Description=Terminate Plymouth Boot Screen
-Before=getty@tty1.service
-After=dev-tty1.device rc-local.service plymouth-start.service
+After=rc-local.service plymouth-start.service
[Service]
ExecStart=-/bin/plymouth quit
Type=oneshot
+TimeoutSec=20
diff --git a/units/quotacheck.service.in b/units/quotacheck.service.in
index 59a0c773eb..d46a335649 100644
--- a/units/quotacheck.service.in
+++ b/units/quotacheck.service.in
@@ -17,6 +17,7 @@ Type=oneshot
RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-quotacheck
StandardOutput=syslog
+TimeoutSec=0
[Install]
WantedBy=local-fs.target
diff --git a/units/rescue.service.m4 b/units/rescue.service.m4
index ba29f6e6e6..2a0d3280ec 100644
--- a/units/rescue.service.m4
+++ b/units/rescue.service.m4
@@ -17,7 +17,7 @@ Before=shutdown.target
[Service]
Environment=HOME=/root
WorkingDirectory=/root
-ExecStartPre=-/bin/plymouth --hide-splash
+ExecStartPre=-/bin/plymouth quit
ExecStartPre=-/bin/echo 'Welcome to rescue mode. Use "systemctl default" or ^D to activate default mode.'
m4_ifdef(`TARGET_FEDORA',
`EnvironmentFile=/etc/sysconfig/init
diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4
index c7a11b1fa0..2b3c8edd57 100644
--- a/units/serial-getty@.service.m4
+++ b/units/serial-getty@.service.m4
@@ -8,13 +8,19 @@
[Unit]
Description=Serial Getty on %I
BindTo=dev-%i.device
-After=dev-%i.device systemd-user-sessions.service
+After=dev-%i.device systemd-user-sessions.service plymouth-quit-wait.service
m4_ifdef(`TARGET_FEDORA',
After=rc-local.service
)m4_dnl
m4_ifdef(`TARGET_ARCH',
After=rc-local.service
)m4_dnl
+m4_ifdef(`TARGET_FRUGALWARE',
+After=local.service
+)m4_dnl
+m4_ifdef(`TARGET_ALTLINUX',
+After=rc-local.service
+)m4_dnl
# If additional gettys are spawned during boot then we should make
# sure that this is synchronized before getty.target, even though