summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTollef Fog Heen <tfheen@err.no>2010-06-05 08:03:15 +0200
committerTollef Fog Heen <tfheen@err.no>2010-06-05 08:03:15 +0200
commit6aa3df795bcccabab9ff82d8ff8a00cb7b39049b (patch)
treecbc682e3d83cc2a6761a6c3e3a58cfe84cdbeff1
parent68fd55f23f1d6d4357a654224a0c1f3457302179 (diff)
parentdfd8eeed3911ce1a4ffc51b9c444f3f18d545040 (diff)
downloadsystemd-6aa3df795bcccabab9ff82d8ff8a00cb7b39049b.tar.gz
Merge remote branch 'origin/master'
-rw-r--r--Makefile.am72
-rwxr-xr-xbootstrap.sh2
-rw-r--r--configure.ac11
-rw-r--r--fixme2
-rw-r--r--man/systemd.special.xml.in37
-rw-r--r--src/dbus-manager.c79
-rw-r--r--src/dbus-unit.c6
-rw-r--r--src/dbus.c170
-rw-r--r--src/hostname-setup.c3
-rw-r--r--src/initctl.c31
-rw-r--r--src/load-fragment.c2
-rw-r--r--src/log.c23
-rw-r--r--src/log.h17
-rw-r--r--src/macro.h28
-rw-r--r--src/main.c4
-rw-r--r--src/manager.c81
-rw-r--r--src/manager.h1
-rw-r--r--src/mount-setup.c13
-rw-r--r--src/mount.c19
-rw-r--r--src/sd-daemon.c1
-rw-r--r--src/sd-daemon.h27
-rw-r--r--src/service.c27
-rw-r--r--src/service.h2
-rw-r--r--src/socket-util.c4
-rw-r--r--src/socket-util.h2
-rw-r--r--src/socket.c8
-rw-r--r--src/strv.h16
-rw-r--r--src/swap.c2
-rw-r--r--src/systemctl.vala25
-rw-r--r--src/systemd-interfaces.vala5
-rw-r--r--src/test-engine.c14
-rw-r--r--src/unit.c118
-rw-r--r--src/unit.h10
-rw-r--r--test2/a.service5
-rw-r--r--test2/b.service5
-rw-r--r--test2/c.service5
-rw-r--r--test2/d.service5
-rw-r--r--test2/e.service5
-rw-r--r--test2/f.service5
-rw-r--r--test2/g.service5
-rw-r--r--test2/h.service5
-rw-r--r--units/.gitignore2
-rw-r--r--units/basic.target (renamed from units/sys-fs-fuse-connections.automount)11
-rw-r--r--units/dev-hugepages.automount2
-rw-r--r--units/dev-mqueue.automount2
-rw-r--r--units/emergency.service3
-rw-r--r--units/fedora/halt.service2
-rw-r--r--units/fedora/poweroff.service2
-rw-r--r--units/fedora/prefdm.service1
-rw-r--r--units/fedora/rc-local.service2
-rw-r--r--units/fedora/reboot.service2
l---------units/gentoo/Makefile1
-rw-r--r--units/gentoo/halt.service2
-rw-r--r--units/gentoo/killall.service1
-rw-r--r--units/gentoo/poweroff.service2
-rw-r--r--units/gentoo/reboot.service2
-rw-r--r--units/gentoo/xdm.service1
-rw-r--r--units/getty@.service.m43
-rw-r--r--units/proc-sys-fs-binfmt_misc.automount2
l---------units/suse/Makefile1
-rw-r--r--units/suse/halt.service19
-rw-r--r--units/suse/poweroff.service17
-rw-r--r--units/suse/reboot.service (renamed from units/sys-fs-fuse-connections.mount)13
-rw-r--r--units/sys-kernel-debug.automount2
-rw-r--r--units/sys-kernel-security.automount2
-rw-r--r--units/sysinit.target.m4 (renamed from units/basic.target.m4)4
-rw-r--r--units/systemd-initctl.service.in3
-rw-r--r--units/systemd-initctl.socket2
-rw-r--r--units/systemd-logger.service.in3
-rw-r--r--units/systemd-logger.socket2
70 files changed, 729 insertions, 284 deletions
diff --git a/Makefile.am b/Makefile.am
index 53f485e05b..a1c08364d9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -17,13 +17,20 @@
ACLOCAL_AMFLAGS = -I m4
+# Dirs of external packages
dbuspolicydir=$(sysconfdir)/dbus-1/system.d
udevrulesdir=@udevrulesdir@
+interfacedir=$(datadir)/dbus-1/interfaces
+# Our own, non-special dirs
pkgsysconfdir=$(sysconfdir)/systemd
-systemunitdir=$(pkgdatadir)/system
sessionunitdir=$(pkgdatadir)/session
-interfacedir=$(datadir)/dbus-1/interfaces
+
+# And these are the special ones for /
+rootdir=@rootdir@
+rootbindir=$(rootdir)/bin
+rootlibexecdir=$(rootdir)/lib/systemd
+systemunitdir=$(rootdir)/lib/systemd/system
AM_CPPFLAGS = \
-include $(top_builddir)/config.h \
@@ -33,22 +40,20 @@ AM_CPPFLAGS = \
-DSYSTEM_SYSVRCND_PATH=\"$(SYSTEM_SYSVRCND_PATH)\" \
-DSESSION_CONFIG_UNIT_PATH=\"$(pkgsysconfdir)/session\" \
-DSESSION_DATA_UNIT_PATH=\"$(sessionunitdir)\" \
- -DCGROUP_AGENT_PATH=\"$(pkglibexecdir)/systemd-cgroups-agent\" \
- -DSYSTEMD_BINARY_PATH=\"$(sbindir)/systemd\" \
+ -DCGROUP_AGENT_PATH=\"$(rootlibexecdir)/systemd-cgroups-agent\" \
+ -DSYSTEMD_BINARY_PATH=\"$(rootbindir)/systemd\" \
-I $(top_srcdir)/src
-sbin_PROGRAMS = \
- systemd
-
-bin_PROGRAMS = \
+rootbin_PROGRAMS = \
+ systemd \
systemctl
if HAVE_GTK
-bin_PROGRAMS += \
+bin_PROGRAMS = \
systemadm
endif
-pkglibexec_PROGRAMS = \
+rootlibexec_PROGRAMS = \
systemd-logger \
systemd-cgroups-agent \
systemd-initctl
@@ -82,6 +87,7 @@ interface_DATA = \
dist_systemunit_DATA = \
units/emergency.service \
+ units/basic.target \
units/getty.target \
units/halt.target \
units/local-fs.target \
@@ -106,8 +112,6 @@ dist_systemunit_DATA = \
units/dev-mqueue.mount \
units/proc-sys-fs-binfmt_misc.automount \
units/proc-sys-fs-binfmt_misc.mount \
- units/sys-fs-fuse-connections.automount \
- units/sys-fs-fuse-connections.mount \
units/sys-kernel-debug.automount \
units/sys-kernel-debug.mount \
units/sys-kernel-security.automount \
@@ -116,7 +120,7 @@ dist_systemunit_DATA = \
units/var-run.mount
systemunit_DATA = \
- units/basic.target \
+ units/sysinit.target \
units/getty@.service \
units/graphical.target \
units/multi-user.target \
@@ -132,7 +136,7 @@ sessionunit_DATA = \
units/session/exit.service
EXTRA_DIST = \
- units/basic.target.m4 \
+ units/sysinit.target.m4 \
units/getty@.service.m4 \
units/graphical.target.m4 \
units/multi-user.target.m4 \
@@ -163,6 +167,13 @@ dist_systemunit_DATA += \
units/debian/reboot.service
endif
+if TARGET_SUSE
+dist_systemunit_DATA += \
+ units/suse/halt.service \
+ units/suse/poweroff.service \
+ units/suse/reboot.service
+endif
+
if TARGET_GENTOO
dist_systemunit_DATA += \
units/gentoo/halt.service \
@@ -285,7 +296,7 @@ test_engine_LDADD = $(systemd_LDADD)
test_job_type_SOURCES = \
$(COMMON_SOURCES) \
- src/test-engine.c
+ src/test-job-type.c
test_job_type_CPPFLAGS = $(systemd_CPPFLAGS)
test_job_type_LDADD = $(systemd_LDADD)
@@ -365,11 +376,10 @@ systemadm_LDADD = $(DBUSGLIB_LIBS) $(GTK_LIBS)
SED_PROCESS = \
$(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
- $(SED) -e 's,@libexecdir\@,$(libexecdir),g' \
- -e 's,@pkglibexecdir\@,$(pkglibexecdir),g' \
+ $(SED) -e 's,@rootlibexecdir\@,$(rootlibexecdir),g' \
-e 's,@SPECIAL_SYSLOG_SERVICE\@,$(SPECIAL_SYSLOG_SERVICE),g' \
-e 's,@SPECIAL_DBUS_SERVICE\@,$(SPECIAL_DBUS_SERVICE),g' \
- -e 's,@SYSTEMCTL\@,$(bindir)/systemctl,g' \
+ -e 's,@SYSTEMCTL\@,$(rootbindir)/systemctl,g' \
< $< > $@
units/%: units/%.in Makefile
@@ -396,7 +406,7 @@ CLEANFILES = \
units/systemd-initctl.service \
units/systemd-logger.service \
units/syslog.target \
- units/basic.target \
+ units/sysinit.target \
units/getty@.service \
units/graphical.target \
units/multi-user.target \
@@ -468,7 +478,7 @@ install-data-hook:
$(DESTDIR)$(systemunitdir) \
$(DESTDIR)$(sessionunitdir) \
$(DESTDIR)$(systemunitdir)/sockets.target.wants \
- $(DESTDIR)$(systemunitdir)/basic.target.wants \
+ $(DESTDIR)$(systemunitdir)/sysinit.target.wants \
$(DESTDIR)$(pkgsysconfdir)/system \
$(DESTDIR)$(pkgsysconfdir)/system/getty.target.wants \
$(DESTDIR)$(pkgsysconfdir)/system/multi-user.target.wants \
@@ -486,10 +496,10 @@ install-data-hook:
$(LN_S) ../systemd-initctl.socket systemd-initctl.socket )
( cd $(DESTDIR)$(sessionunitdir) && \
rm -f shutdown.target sockets.target local-fs.target swap.target && \
- $(LN_S) ../system/shutdown.target shutdown.target && \
- $(LN_S) ../system/sockets.target sockets.target && \
- $(LN_S) ../system/local-fs.target local-fs.target && \
- $(LN_S) ../system/swap.target swap.target )
+ $(LN_S) $(systemunitdir)/shutdown.target shutdown.target && \
+ $(LN_S) $(systemunitdir)/sockets.target sockets.target && \
+ $(LN_S) $(systemunitdir)/local-fs.target local-fs.target && \
+ $(LN_S) $(systemunitdir)/swap.target swap.target )
( cd $(DESTDIR)$(systemunitdir) && \
rm -f runlevel0.target runlevel1.target runlevel6.target && \
$(LN_S) poweroff.target runlevel0.target && \
@@ -514,21 +524,20 @@ install-data-hook:
$(LN_S) $(systemunitdir)/getty@.service getty@tty5.service && \
$(LN_S) $(systemunitdir)/getty@.service getty@tty6.service )
( cd $(DESTDIR)$(pkgsysconfdir)/system/multi-user.target.wants && \
- rm -f getty.target && \
- $(LN_S) $(systemunitdir)/getty.target getty.target )
- ( cd $(DESTDIR)$(systemunitdir)/basic.target.wants && \
+ rm -f getty.target remote-fs.target && \
+ $(LN_S) $(systemunitdir)/getty.target getty.target && \
+ $(LN_S) $(systemunitdir)/remote-fs.target remote-fs.target )
+ ( cd $(DESTDIR)$(systemunitdir)/sysinit.target.wants && \
rm -f dev-hugepages.automount \
dev-mqueue.automount \
proc-sys-fs-binfmt_misc.automount \
sys-kernel-debug.automount \
- sys-fs-fuse-connections.automount \
sys-kernel-security.automount && \
$(LN_S) ../dev-hugepages.automount dev-hugepages.automount && \
$(LN_S) ../dev-mqueue.automount dev-mqueue.automount && \
$(LN_S) ../proc-sys-fs-binfmt_misc.automount proc-sys-fs-binfmt_misc.automount && \
$(LN_S) ../sys-kernel-debug.automount sys-kernel-debug.automount && \
- $(LN_S) ../sys-kernel-security.automount sys-kernel-security.automount && \
- $(LN_S) ../sys-fs-fuse-connections.automount sys-fs-fuse-connections.automount )
+ $(LN_S) ../sys-kernel-security.automount sys-kernel-security.automount )
if TARGET_FEDORA
( cd $(DESTDIR)$(pkgsysconfdir)/system && \
rm -f display-manager.service && \
@@ -555,4 +564,5 @@ if TARGET_GENTOO
endif
DISTCHECK_CONFIGURE_FLAGS = \
- --with-udevrulesdir=$$dc_install_base/$(udevrulesdir)
+ --with-udevrulesdir=$$dc_install_base/$(udevrulesdir) \
+ --with-rootdir=$$dc_install_base/$(rootdir)
diff --git a/bootstrap.sh b/bootstrap.sh
index cb87bf782c..f59a8156bf 100755
--- a/bootstrap.sh
+++ b/bootstrap.sh
@@ -65,7 +65,7 @@ else
run_versioned automake "$AM_VERSION" --copy --foreign --add-missing
if [ "x$1" != "xac" ]; then
- CFLAGS="$CFLAGS -g -O0" ./configure --sysconfdir=/etc --localstatedir=/var "$@"
+ CFLAGS="$CFLAGS -g -O0" ./configure --sysconfdir=/etc --localstatedir=/var --with-rootdir= "$@"
make clean
fi
fi
diff --git a/configure.ac b/configure.ac
index ffdedeedff..af20151fbb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -269,7 +269,14 @@ AC_ARG_WITH([udevrulesdir],
[with_udevrulesdir=/lib/udev/rules.d])
AC_SUBST([udevrulesdir], [$with_udevrulesdir])
-AC_OUTPUT([Makefile])
+AC_ARG_WITH([rootdir],
+ AS_HELP_STRING([--with-rootdir=DIR], [Root directory for files necessary for boot]),
+ [],
+ [with_rootdir=${ac_default_prefix}])
+AC_SUBST([rootdir], [$with_rootdir])
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
echo "
$PACKAGE_NAME $VERSION
@@ -280,5 +287,7 @@ echo "
Syslog service: ${SPECIAL_SYSLOG_SERVICE}
D-Bus service: ${SPECIAL_DBUS_SERVICE}
Gtk: ${have_gtk}
+ prefix: ${prefix}
+ root dir: ${with_rootdir}
udev rules dir: ${with_udevrulesdir}
"
diff --git a/fixme b/fixme
index b6752d9bf6..514e3731fd 100644
--- a/fixme
+++ b/fixme
@@ -64,6 +64,8 @@
* tcpwrap
+* use setproctitle() when forking, before exec() (waiting for (PR_SET_PROCTITLE_AREA to enter the kernel)
+
Regularly:
* look for close() vs. close_nointr() vs. close_nointr_nofail()
diff --git a/man/systemd.special.xml.in b/man/systemd.special.xml.in
index 1d9c1326b4..a2e1bb2cbd 100644
--- a/man/systemd.special.xml.in
+++ b/man/systemd.special.xml.in
@@ -80,6 +80,7 @@
<filename>sigpwr.target</filename>,
<filename>sockets.target</filename>,
<filename>swap.target</filename>,
+ <filename>sysinit.target</filename>,
<filename>syslog.target</filename>,
<filename>@SPECIAL_SYSLOG_SERVICE@</filename>,
<filename>systemd-initctl.service</filename>,
@@ -111,16 +112,15 @@
target unit to all SysV
service units configured for
runlevel 1 to 5.</para>
- <para>systemd automatically
- adds dependencies of the types
- Wants and After for all
- SysV service units configured
- for runlevels that are not 0
- to 6 to this target unit.
- This covers the special
- boot-up runlevels some
- distributions have, such as S
- or b.</para>
+ <para>Usually this should pull
+ in all sockets, mount points,
+ swap devices and other basic
+ initialization necessary for
+ the general purpose
+ daemons. Most normal daemon
+ should have dependencies of
+ type After and Requires on
+ this unit.</para>
</listitem>
</varlistentry>
<varlistentry>
@@ -587,6 +587,23 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><filename>sysinit.target</filename></term>
+ <listitem>
+ <para>A special target unit
+ covering early boot-up scripts.</para>
+ <para>systemd automatically
+ adds dependencies of the types
+ Wants and After for all
+ SysV service units configured
+ for runlevels that are not 0
+ to 6 to this target unit.
+ This covers the special
+ boot-up runlevels some
+ distributions have, such as S
+ or b.</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><filename>@SPECIAL_SYSLOG_SERVICE@</filename></term>
<listitem>
<para>A special unit for the
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 6a323019fe..c80b22b9e6 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -36,6 +36,26 @@
" <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
" <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
" </method>\n" \
+ " <method name=\"StartUnit\">\n" \
+ " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"StopUnit\">\n" \
+ " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"ReloadUnit\">\n" \
+ " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
+ " </method>\n" \
+ " <method name=\"RestartUnit\">\n" \
+ " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
+ " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
+ " </method>\n" \
" <method name=\"GetJob\">\n" \
" <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
" <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
@@ -184,6 +204,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection
DBusError error;
DBusMessage *reply = NULL;
char * path = NULL;
+ JobType job_type = _JOB_TYPE_INVALID;
assert(connection);
assert(message);
@@ -248,7 +269,15 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection
DBUS_TYPE_INVALID))
goto oom;
- } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
+ } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
+ job_type = JOB_START;
+ else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
+ job_type = JOB_STOP;
+ else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
+ job_type = JOB_RELOAD;
+ else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
+ job_type = JOB_RESTART;
+ else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
uint32_t id;
Job *j;
@@ -297,7 +326,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection
HASHMAP_FOREACH_KEY(u, k, m->units, i) {
char *u_path, *j_path;
- const char *description, *load_state, *active_state, *sub_state, *job_type;
+ const char *description, *load_state, *active_state, *sub_state, *sjob_type;
DBusMessageIter sub2;
uint32_t job_id;
@@ -323,11 +352,11 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection
goto oom;
}
- job_type = job_type_to_string(u->meta.job->type);
+ sjob_type = job_type_to_string(u->meta.job->type);
} else {
job_id = 0;
j_path = u_path;
- job_type = "";
+ sjob_type = "";
}
if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->meta.id) ||
@@ -337,7 +366,7 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
- !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &job_type) ||
+ !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
free(u_path);
if (u->meta.job)
@@ -636,6 +665,46 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection
} else
return bus_default_message_handler(m, message, NULL, properties);
+
+ if (job_type != _JOB_TYPE_INVALID) {
+ const char *name, *smode;
+ JobMode mode;
+ Job *j;
+ Unit *u;
+
+ if (!dbus_message_get_args(
+ message,
+ &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &smode,
+ DBUS_TYPE_INVALID))
+ return bus_send_error_reply(m, message, &error, -EINVAL);
+
+ if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID)
+ return bus_send_error_reply(m, message, NULL, -EINVAL);
+
+ if ((r = manager_load_unit(m, name, NULL, &u)) < 0)
+ return bus_send_error_reply(m, message, NULL, r);
+
+ if (job_type == JOB_START && u->meta.only_by_dependency)
+ return bus_send_error_reply(m, message, NULL, -EPERM);
+
+ if ((r = manager_add_job(m, job_type, u, mode, true, &j)) < 0)
+ return bus_send_error_reply(m, message, NULL, r);
+
+ if (!(reply = dbus_message_new_method_return(message)))
+ goto oom;
+
+ if (!(path = job_dbus_path(j)))
+ goto oom;
+
+ if (!dbus_message_append_args(
+ reply,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ goto oom;
+ }
+
free(path);
if (reply) {
diff --git a/src/dbus-unit.c b/src/dbus-unit.c
index 87218cd2ee..8e35377dc5 100644
--- a/src/dbus-unit.c
+++ b/src/dbus-unit.c
@@ -260,6 +260,7 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusMessage *message
Manager *m = u->meta.manager;
DBusError error;
JobType job_type = _JOB_TYPE_INVALID;
+ char *path = NULL;
dbus_error_init(&error);
@@ -281,7 +282,6 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusMessage *message
JobMode mode;
Job *j;
int r;
- char *path;
if (job_type == JOB_START && u->meta.only_by_dependency)
return bus_send_error_reply(m, message, NULL, -EPERM);
@@ -312,6 +312,8 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusMessage *message
goto oom;
}
+ free(path);
+
if (reply) {
if (!dbus_connection_send(m->api_bus, reply, NULL))
goto oom;
@@ -322,6 +324,8 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusMessage *message
return DBUS_HANDLER_RESULT_HANDLED;
oom:
+ free(path);
+
if (reply)
dbus_message_unref(reply);
diff --git a/src/dbus.c b/src/dbus.c
index f5bbc5815a..7e6d65e2c8 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -65,6 +65,8 @@ const char *const bus_interface_table[] = {
NULL
};
+static const char *error_to_dbus(int error);
+
static void api_bus_dispatch_status(DBusConnection *bus, DBusDispatchStatus status, void *data) {
Manager *m = data;
@@ -333,6 +335,7 @@ static void bus_toggle_timeout(DBusTimeout *timeout, void *data) {
static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
Manager *m = data;
DBusError error;
+ DBusMessage *reply = NULL;
assert(connection);
assert(message);
@@ -370,10 +373,67 @@ static DBusHandlerResult api_bus_message_filter(DBusConnection *connection, DBu
manager_dispatch_bus_name_owner_changed(m, name, old_owner, new_owner);
}
+ } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Activator", "ActivationRequest")) {
+ const char *name;
+
+ if (!dbus_message_get_args(message, &error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+ log_error("Failed to parse ActivationRequest message: %s", error.message);
+ else {
+ int r;
+ Unit *u;
+
+ log_debug("Got D-Bus activation request for %s", name);
+
+ r = manager_load_unit(m, name, NULL, &u);
+
+ if (r >= 0 && u->meta.only_by_dependency)
+ r = -EPERM;
+
+ if (r >= 0)
+ r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, NULL);
+
+ if (r < 0) {
+ const char *id, *text;
+
+ if (!(reply = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure")))
+ goto oom;
+
+ id = error_to_dbus(r);
+ text = strerror(-r);
+
+ if (!dbus_message_set_destination(reply, DBUS_SERVICE_DBUS) ||
+ !dbus_message_append_args(reply,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_STRING, &id,
+ DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INVALID))
+ goto oom;
+ }
+
+ /* On success we don't do anything, the service will be spwaned now */
+ }
}
dbus_error_free(&error);
+
+ if (reply) {
+ if (!dbus_connection_send(connection, reply, NULL))
+ goto oom;
+
+ dbus_message_unref(reply);
+ }
+
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+oom:
+ if (reply)
+ dbus_message_unref(reply);
+
+ dbus_error_free(&error);
+
+ return DBUS_HANDLER_RESULT_NEED_MEMORY;
}
static DBusHandlerResult system_bus_message_filter(DBusConnection *connection, DBusMessage *message, void *data) {
@@ -531,6 +591,95 @@ oom:
return -ENOMEM;
}
+static void query_name_list_pending_cb(DBusPendingCall *pending, void *userdata) {
+ DBusMessage *reply;
+ DBusError error;
+ Manager *m = userdata;
+
+ assert(m);
+
+ dbus_error_init(&error);
+
+ assert_se(reply = dbus_pending_call_steal_reply(pending));
+
+ switch (dbus_message_get_type(reply)) {
+
+ case DBUS_MESSAGE_TYPE_ERROR:
+
+ assert_se(dbus_set_error_from_message(&error, reply));
+ log_warning("ListNames() failed: %s", error.message);
+ break;
+
+ case DBUS_MESSAGE_TYPE_METHOD_RETURN: {
+ int r;
+ char **l;
+
+ if ((r = bus_parse_strv(reply, &l)) < 0)
+ log_warning("Failed to parse ListNames() reply: %s", strerror(-r));
+ else {
+ char **t;
+
+ STRV_FOREACH(t, l)
+ /* This is a bit hacky, we say the
+ * owner of the name is the name
+ * itself, because we don't want the
+ * extra traffic to figure out the
+ * real owner. */
+ manager_dispatch_bus_name_owner_changed(m, *t, NULL, *t);
+
+ strv_free(l);
+ }
+
+ break;
+ }
+
+ default:
+ assert_not_reached("Invalid reply message");
+ }
+
+ dbus_message_unref(reply);
+ dbus_error_free(&error);
+}
+
+static int query_name_list(Manager *m) {
+ DBusMessage *message = NULL;
+ DBusPendingCall *pending = NULL;
+
+ /* Asks for the currently installed bus names */
+
+ if (!(message = dbus_message_new_method_call(
+ DBUS_SERVICE_DBUS,
+ DBUS_PATH_DBUS,
+ DBUS_INTERFACE_DBUS,
+ "ListNames")))
+ goto oom;
+
+ if (!dbus_connection_send_with_reply(m->api_bus, message, &pending, -1))
+ goto oom;
+
+ if (!dbus_pending_call_set_notify(pending, query_name_list_pending_cb, m, NULL))
+ goto oom;
+
+ dbus_message_unref(message);
+ dbus_pending_call_unref(pending);
+
+ /* We simple ask for the list and don't wait for it. Sooner or
+ * later we'll get it. */
+
+ return 0;
+
+oom:
+ if (pending) {
+ dbus_pending_call_cancel(pending);
+ dbus_pending_call_unref(pending);
+ }
+
+ if (message)
+ dbus_message_unref(message);
+
+ return -ENOMEM;
+}
+
static int bus_setup_loop(Manager *m, DBusConnection *bus) {
assert(m);
assert(bus);
@@ -642,6 +791,7 @@ int bus_init_api(Manager *m) {
return -ENOMEM;
}
+ /* Get NameOwnerChange messages */
dbus_bus_add_match(m->api_bus,
"type='signal',"
"sender='"DBUS_SERVICE_DBUS"',"
@@ -656,11 +806,31 @@ int bus_init_api(Manager *m) {
return -ENOMEM;
}
+ /* Get activation requests */
+ dbus_bus_add_match(m->api_bus,
+ "type='signal',"
+ "sender='"DBUS_SERVICE_DBUS"',"
+ "interface='org.freedesktop.systemd1.Activator',"
+ "path='"DBUS_PATH_DBUS"'",
+ &error);
+
+ if (dbus_error_is_set(&error)) {
+ log_error("Failed to register match: %s", error.message);
+ dbus_error_free(&error);
+ bus_done_api(m);
+ return -ENOMEM;
+ }
+
if ((r = request_name(m)) < 0) {
bus_done_api(m);
return r;
}
+ if ((r = query_name_list(m)) < 0) {
+ bus_done_api(m);
+ return r;
+ }
+
log_debug("Successfully connected to API D-Bus bus %s as %s",
strnull((id = dbus_connection_get_server_id(m->api_bus))),
strnull(dbus_bus_get_unique_name(m->api_bus)));
diff --git a/src/hostname-setup.c b/src/hostname-setup.c
index 3b988d4c8b..e9f722e622 100644
--- a/src/hostname-setup.c
+++ b/src/hostname-setup.c
@@ -52,7 +52,8 @@ static char* strip_bad_chars(char *s) {
(*p >= 'A' && *p <= 'Z') ||
(*p >= '0' && *p <= '9') ||
*p == '-' ||
- *p == '_')
+ *p == '_' ||
+ *p == '.')
*(d++) = *p;
*d = 0;
diff --git a/src/initctl.c b/src/initctl.c
index 407d32d93f..9872437aa9 100644
--- a/src/initctl.c
+++ b/src/initctl.c
@@ -96,7 +96,7 @@ static void change_runlevel(Server *s, int runlevel) {
const char *target;
DBusMessage *m = NULL, *reply = NULL;
DBusError error;
- const char *path, *replace = "isolate";
+ const char *replace = "replace";
assert(s);
@@ -109,44 +109,19 @@ static void change_runlevel(Server *s, int runlevel) {
log_debug("Running request %s", target);
- if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "LoadUnit"))) {
+ if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "StartUnit"))) {
log_error("Could not allocate message.");
goto finish;
}
if (!dbus_message_append_args(m,
DBUS_TYPE_STRING, &target,
- DBUS_TYPE_INVALID)) {
- log_error("Could not attach group information to signal message.");
- goto finish;
- }
-
- if (!(reply = dbus_connection_send_with_reply_and_block(s->bus, m, -1, &error))) {
- log_error("Failed to get unit path: %s", error.message);
- goto finish;
- }
-
- if (!dbus_message_get_args(reply, &error,
- DBUS_TYPE_OBJECT_PATH, &path,
- DBUS_TYPE_INVALID)) {
- log_error("Failed to parse unit path: %s", error.message);
- goto finish;
- }
-
- dbus_message_unref(m);
- if (!(m = dbus_message_new_method_call("org.freedesktop.systemd1", path, "org.freedesktop.systemd1.Unit", "Start"))) {
- log_error("Could not allocate message.");
- goto finish;
- }
-
- if (!dbus_message_append_args(m,
DBUS_TYPE_STRING, &replace,
DBUS_TYPE_INVALID)) {
- log_error("Could not attach group information to signal message.");
+ log_error("Could not attach target and flag information to signal message.");
goto finish;
}
- dbus_message_unref(reply);
if (!(reply = dbus_connection_send_with_reply_and_block(s->bus, m, -1, &error))) {
log_error("Failed to start unit: %s", error.message);
goto finish;
diff --git a/src/load-fragment.c b/src/load-fragment.c
index a706880b9a..5f5e37397b 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -1366,7 +1366,7 @@ static int load_from_path(Unit *u, const char *path) {
{ "Environment", config_parse_strv, &(context).environment, section }, \
{ "StandardInput", config_parse_input, &(context).std_input, section }, \
{ "StandardOutput", config_parse_output, &(context).std_output, section }, \
- { "StandardError", config_parse_output, &(context).std_output, section }, \
+ { "StandardError", config_parse_output, &(context).std_error, section }, \
{ "TTYPath", config_parse_path, &(context).tty_path, section }, \
{ "SyslogIdentifier", config_parse_string, &(context).syslog_identifier, section }, \
{ "SyslogFacility", config_parse_facility, &(context).syslog_priority, section }, \
diff --git a/src/log.c b/src/log.c
index 1343b9d986..bf2382dfaf 100644
--- a/src/log.c
+++ b/src/log.c
@@ -357,6 +357,27 @@ static int log_dispatch(
return r;
}
+int log_dump_internal(
+ int level,
+ const char*file,
+ int line,
+ const char *func,
+ char *buffer) {
+
+ int saved_errno, r;
+
+ /* This modifies the buffer... */
+
+ if (_likely_(LOG_PRI(level) > log_max_level))
+ return 0;
+
+ saved_errno = errno;
+ r = log_dispatch(level, file, line, func, buffer);
+ errno = saved_errno;
+
+ return r;
+}
+
int log_meta(
int level,
const char*file,
@@ -368,7 +389,7 @@ int log_meta(
int saved_errno, r;
va_list ap;
- if (_likely(LOG_PRI(level) > log_max_level))
+ if (_likely_(LOG_PRI(level) > log_max_level))
return 0;
saved_errno = errno;
diff --git a/src/log.h b/src/log.h
index 6df1d59961..9d141dcdda 100644
--- a/src/log.h
+++ b/src/log.h
@@ -59,13 +59,21 @@ int log_meta(
const char*file,
int line,
const char *func,
- const char *format, ...) _printf_attr(5,6);
+ const char *format, ...) _printf_attr_(5,6);
-_noreturn void log_assert(
+_noreturn_ void log_assert(
const char*file,
int line,
const char *func,
- const char *format, ...) _printf_attr(4,5);
+ const char *format, ...) _printf_attr_(4,5);
+
+/* This modifies the buffer passed! */
+int log_dump_internal(
+ int level,
+ const char*file,
+ int line,
+ const char *func,
+ char *buffer);
#define log_debug(...) log_meta(LOG_DEBUG, __FILE__, __LINE__, __func__, __VA_ARGS__)
#define log_info(...) log_meta(LOG_INFO, __FILE__, __LINE__, __func__, __VA_ARGS__)
@@ -73,6 +81,9 @@ _noreturn void log_assert(
#define log_warning(...) log_meta(LOG_WARNING, __FILE__, __LINE__, __func__, __VA_ARGS__)
#define log_error(...) log_meta(LOG_ERR, __FILE__, __LINE__, __func__, __VA_ARGS__)
+/* This modifies the buffer passed! */
+#define log_dump(level, buffer) log_dump_internal(level, __FILE__, __LINE__, __func__, buffer)
+
const char *log_target_to_string(LogTarget target);
LogTarget log_target_from_string(const char *s);
diff --git a/src/macro.h b/src/macro.h
index 622c08eeda..763a4de27a 100644
--- a/src/macro.h
+++ b/src/macro.h
@@ -25,19 +25,19 @@
#include <assert.h>
#include <sys/types.h>
-#define _printf_attr(a,b) __attribute__ ((format (printf, a, b)))
-#define _sentinel __attribute__ ((sentinel))
-#define _noreturn __attribute__((noreturn))
-#define _unused __attribute__ ((unused))
-#define _destructor __attribute__ ((destructor))
-#define _pure __attribute__ ((pure))
-#define _const __attribute__ ((const))
-#define _deprecated __attribute__ ((deprecated))
-#define _packed __attribute__ ((packed))
-#define _malloc __attribute__ ((malloc))
-#define _weak __attribute__ ((weak))
-#define _likely(x) (__builtin_expect(!!(x),1))
-#define _unlikely(x) (__builtin_expect(!!(x),0))
+#define _printf_attr_(a,b) __attribute__ ((format (printf, a, b)))
+#define _sentinel_ __attribute__ ((sentinel))
+#define _noreturn_ __attribute__((noreturn))
+#define _unused_ __attribute__ ((unused))
+#define _destructor_ __attribute__ ((destructor))
+#define _pure_ __attribute__ ((pure))
+#define _const_ __attribute__ ((const))
+#define _deprecated_ __attribute__ ((deprecated))
+#define _packed_ __attribute__ ((packed))
+#define _malloc_ __attribute__ ((malloc))
+#define _weak_ __attribute__ ((weak))
+#define _likely_(x) (__builtin_expect(!!(x),1))
+#define _unlikely_(x) (__builtin_expect(!!(x),0))
/* Rounds up */
static inline size_t ALIGN(size_t l) {
@@ -70,7 +70,7 @@ static inline size_t ALIGN(size_t l) {
#define assert_se(expr) \
do { \
- if (_unlikely(!(expr))) \
+ if (_unlikely_(!(expr))) \
log_assert(__FILE__, __LINE__, __PRETTY_FUNCTION__, \
"Assertion '%s' failed at %s:%u, function %s(). Aborting.", \
#expr , __FILE__, __LINE__, __PRETTY_FUNCTION__); \
diff --git a/src/main.c b/src/main.c
index 7a829cea5c..7c93f6d9c7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -58,7 +58,7 @@ static int crash_chvt = -1;
static bool confirm_spawn = false;
static FILE* serialization = NULL;
-_noreturn static void freeze(void) {
+_noreturn_ static void freeze(void) {
for (;;)
pause();
}
@@ -66,7 +66,7 @@ _noreturn static void freeze(void) {
static void nop_handler(int sig) {
}
-_noreturn static void crash(int sig) {
+_noreturn_ static void crash(int sig) {
if (!dump_core)
log_error("Caught <%s>, not dumping core.", strsignal(sig));
diff --git a/src/manager.c b/src/manager.c
index 933dd5064f..38964939c3 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -548,6 +548,19 @@ static void manager_clear_jobs_and_units(Manager *m) {
while ((u = hashmap_first(m->units)))
unit_free(u);
+
+ manager_dispatch_cleanup_queue(m);
+
+ assert(!m->load_queue);
+ assert(!m->run_queue);
+ assert(!m->dbus_unit_queue);
+ assert(!m->dbus_job_queue);
+ assert(!m->cleanup_queue);
+ assert(!m->gc_queue);
+
+ assert(hashmap_isempty(m->transaction_jobs));
+ assert(hashmap_isempty(m->jobs));
+ assert(hashmap_isempty(m->units));
}
void manager_free(Manager *m) {
@@ -555,7 +568,6 @@ void manager_free(Manager *m) {
assert(m);
- manager_dispatch_cleanup_queue(m);
manager_clear_jobs_and_units(m);
for (c = 0; c < _UNIT_TYPE_MAX; c++)
@@ -625,9 +637,8 @@ int manager_coldplug(Manager *m) {
if (u->meta.id != k)
continue;
- if (UNIT_VTABLE(u)->coldplug)
- if ((q = UNIT_VTABLE(u)->coldplug(u)) < 0)
- r = q;
+ if ((q = unit_coldplug(u)) < 0)
+ r = q;
}
return r;
@@ -964,20 +975,25 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned
/* Does a recursive sweep through the ordering graph, looking
* for a cycle. If we find cycle we try to break it. */
- /* Did we find a cycle? */
- if (j->marker && j->generation == generation) {
+ /* Have we seen this before? */
+ if (j->generation == generation) {
Job *k;
- /* So, we already have been here. We have a
- * cycle. Let's try to break it. We go backwards in
- * our path and try to find a suitable job to
- * remove. We use the marker to find our way back,
- * since smart how we are we stored our way back in
- * there. */
+ /* If the marker is NULL we have been here already and
+ * decided the job was loop-free from here. Hence
+ * shortcut things and return right-away. */
+ if (!j->marker)
+ return 0;
+ /* So, the marker is not NULL and we already have been
+ * here. We have a cycle. Let's try to break it. We go
+ * backwards in our path and try to find a suitable
+ * job to remove. We use the marker to find our way
+ * back, since smart how we are we stored our way back
+ * in there. */
log_debug("Found ordering cycle on %s/%s", j->unit->meta.id, job_type_to_string(j->type));
- for (k = from; k; k = (k->generation == generation ? k->marker : NULL)) {
+ for (k = from; k; k = ((k->generation == generation && k->marker != k) ? k->marker : NULL)) {
log_debug("Walked on cycle path to %s/%s", k->unit->meta.id, job_type_to_string(k->type));
@@ -1002,8 +1018,10 @@ static int transaction_verify_order_one(Manager *m, Job *j, Job *from, unsigned
}
/* Make the marker point to where we come from, so that we can
- * find our way backwards if we want to break a cycle */
- j->marker = from;
+ * find our way backwards if we want to break a cycle. We use
+ * a special marker for the beginning: we point to
+ * ourselves. */
+ j->marker = from ? from : j;
j->generation = generation;
/* We assume that the the dependencies are bidirectional, and
@@ -1035,6 +1053,7 @@ static int transaction_verify_order(Manager *m, unsigned *generation) {
Job *j;
int r;
Iterator i;
+ unsigned g;
assert(m);
assert(generation);
@@ -1042,8 +1061,10 @@ static int transaction_verify_order(Manager *m, unsigned *generation) {
/* Check if the ordering graph is cyclic. If it is, try to fix
* that up by dropping one of the jobs. */
+ g = (*generation)++;
+
HASHMAP_FOREACH(j, m->transaction_jobs, i)
- if ((r = transaction_verify_order_one(m, j, NULL, (*generation)++)) < 0)
+ if ((r = transaction_verify_order_one(m, j, NULL, g)) < 0)
return r;
return 0;
@@ -1882,10 +1903,32 @@ static int manager_process_signal_fd(Manager *m) {
break;
}
- case SIGUSR2:
- manager_dump_units(m, stdout, "\t");
- manager_dump_jobs(m, stdout, "\t");
+ case SIGUSR2: {
+ FILE *f;
+ char *dump = NULL;
+ size_t size;
+
+ if (!(f = open_memstream(&dump, &size))) {
+ log_warning("Failed to allocate memory stream.");
+ break;
+ }
+
+ manager_dump_units(m, f, "\t");
+ manager_dump_jobs(m, f, "\t");
+
+ if (ferror(f)) {
+ fclose(f);
+ free(dump);
+ log_warning("Failed to write status stream");
+ break;
+ }
+
+ fclose(f);
+ log_dump(LOG_INFO, dump);
+ free(dump);
+
break;
+ }
case SIGHUP:
m->exit_code = MANAGER_RELOAD;
diff --git a/src/manager.h b/src/manager.h
index 210e66053c..a2084e924b 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -108,6 +108,7 @@ struct Watch {
#define SPECIAL_DISPLAY_MANAGER_SERVICE "display-manager.service" /* Debian's $x-display-manager */
#define SPECIAL_MAIL_TRANSFER_AGENT_TARGET "mail-transfer-agent.target" /* Debian's $mail-{transport|transfer-agent */
#define SPECIAL_BASIC_TARGET "basic.target"
+#define SPECIAL_SYSINIT_TARGET "sysinit.target"
#define SPECIAL_RESCUE_TARGET "rescue.target"
#define SPECIAL_EXIT_SERVICE "exit.service"
diff --git a/src/mount-setup.c b/src/mount-setup.c
index 889cf67eb5..33e6f4fa0e 100644
--- a/src/mount-setup.c
+++ b/src/mount-setup.c
@@ -42,12 +42,13 @@ typedef struct MountPoint {
} MountPoint;
static const MountPoint mount_table[] = {
- { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
- { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
- { "devtmps", "/dev", "devtmpfs", "mode=755", MS_NOSUID, true },
- { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
- { "devpts", "/dev/pts", "devpts", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
- { "cgroup", "/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+ { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+ { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+ { "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID, true },
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+ { "devpts", "/dev/pts", "devpts", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, false },
+ { "tmpfs", "/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+ { "cgroup", "/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
};
bool mount_point_is_api(const char *path) {
diff --git a/src/mount.c b/src/mount.c
index dfe4f875e1..5577f16dfd 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -1262,7 +1262,7 @@ finish:
static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
int r;
- char *device, *path, *options, *fstype, *d, *p;
+ char *device, *path, *options, *options2, *fstype, *d, *p, *o;
assert(m);
@@ -1271,7 +1271,7 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
for (;;) {
int k;
- device = path = options = fstype = d = p = NULL;
+ device = path = options = options2 = fstype = d = p = o = NULL;
if ((k = fscanf(m->proc_self_mountinfo,
"%*s " /* (1) mount id */
@@ -1284,11 +1284,13 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
"- " /* (8) seperator */
"%ms " /* (9) file system type */
"%ms" /* (10) mount source */
+ "%ms" /* (11) mount options 2 */
"%*[^\n]", /* some rubbish at the end */
&path,
&options,
&fstype,
- &device)) != 4) {
+ &device,
+ &options2)) != 5) {
if (k == EOF)
break;
@@ -1297,21 +1299,28 @@ static int mount_load_proc_self_mountinfo(Manager *m, bool set_flags) {
goto finish;
}
+ if (asprintf(&o, "%s,%s", options, options2) < 0) {
+ r = -ENOMEM;
+ goto finish;
+ }
+
if (!(d = cunescape(device)) ||
!(p = cunescape(path))) {
r = -ENOMEM;
goto finish;
}
- if ((r = mount_add_one(m, d, p, options, fstype, true, set_flags)) < 0)
+ if ((r = mount_add_one(m, d, p, o, fstype, true, set_flags)) < 0)
goto finish;
free(device);
free(path);
free(options);
+ free(options2);
free(fstype);
free(d);
free(p);
+ free(o);
}
r = 0;
@@ -1320,9 +1329,11 @@ finish:
free(device);
free(path);
free(options);
+ free(options2);
free(fstype);
free(d);
free(p);
+ free(o);
return r;
}
diff --git a/src/sd-daemon.c b/src/sd-daemon.c
index 2e1bf3213c..29bd204680 100644
--- a/src/sd-daemon.c
+++ b/src/sd-daemon.c
@@ -89,7 +89,6 @@ int sd_listen_fds(int unset_environment) {
goto finish;
}
-
for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + (int) l; fd ++) {
int flags;
diff --git a/src/sd-daemon.h b/src/sd-daemon.h
index e209af6489..0d8de45b72 100644
--- a/src/sd-daemon.h
+++ b/src/sd-daemon.h
@@ -30,10 +30,11 @@
#include <inttypes.h>
/* Reference implementation of a few systemd related interfaces for
- * writing daemons. These interfaces are trivial to implement, however
- * to simplify porting we provide this reference
- * implementation. Applications are free to reimplement the algorithms
- * described here. */
+ * writing daemons. These interfaces are trivial to implement. To
+ * simplify porting we provide this reference
+ * implementation. Applications are welcome to reimplement the
+ * algorithms described here, if they do not want to include these two
+ * source files. */
/*
Log levels for usage on stderr:
@@ -56,12 +57,16 @@
#define SD_LISTEN_FDS_START 3
/* Returns how many file descriptors have been passed, or a negative
- * errno code on failure. Optionally removes the $LISTEN_FDS and
- * $LISTEN_PID file descriptors from the environment
- * (recommended). You'll find the file descriptors passed as fds
- * SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1 if r is the return
- * value of this functioin. Returns a negative errno style error code
- * on failure. */
+ * errno code on failure. Optionally, removes the $LISTEN_FDS and
+ * $LISTEN_PID file descriptors from the environment (recommended, but
+ * problematic in threaded environments). If r is the return value of
+ * this function you'll find the file descriptors passed as fds
+ * SD_LISTEN_FDS_START to SD_LISTEN_FDS_START+r-1. Returns a negative
+ * errno style error code on failure. This function call ensures that
+ * the FD_CLOEXEC flag is set for the passed file descriptors, to make
+ * sure they are not passed on to child processes. If FD_CLOEXEC shall
+ * not be set, the caller needs to unset it after this call for all file
+ * descriptors that are used.*/
int sd_listen_fds(int unset_environment);
/* Helper call for identifying a passed file descriptor. Returns 1 if
@@ -86,7 +91,7 @@ int sd_is_socket(int fd, int family, int type, int listening);
/* Helper call for identifying a passed file descriptor. Returns 1 if
* the file descriptor is an Internet socket, of the specified family
- * (either AF_INET or AF_INET6) of the specified type (SOCK_DGRAM,
+ * (either AF_INET or AF_INET6) and the specified type (SOCK_DGRAM,
* SOCK_STREAM, ...), 0 otherwise. If version is 0 a protocol version
* check is not done. If type is 0 a socket type check will not be
* done. If port is 0 a socket port check will not be done. The
diff --git a/src/service.c b/src/service.c
index 8ff7b73138..8b1fab785a 100644
--- a/src/service.c
+++ b/src/service.c
@@ -58,10 +58,10 @@ static const struct {
{ "rc6.d", SPECIAL_RUNLEVEL6_TARGET, RUNLEVEL_DOWN },
/* SUSE style boot.d */
- { "boot.d", SPECIAL_BASIC_TARGET, RUNLEVEL_BASIC },
+ { "boot.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_BASIC },
/* Debian style rcS.d */
- { "rcS.d", SPECIAL_BASIC_TARGET, RUNLEVEL_BASIC },
+ { "rcS.d", SPECIAL_SYSINIT_TARGET, RUNLEVEL_BASIC },
};
#define RUNLEVELS_UP "12345"
@@ -340,9 +340,6 @@ static int service_load_sysv_path(Service *s, const char *path) {
goto finish;
}
- s->type = SERVICE_FORKING;
- s->restart = SERVICE_ONCE;
-
free(s->sysv_path);
if (!(s->sysv_path = strdup(path))) {
r = -ENOMEM;
@@ -650,8 +647,10 @@ static int service_load_sysv_path(Service *s, const char *path) {
s->timeout_usec = 0;
/* Special setting for all SysV services */
+ s->type = SERVICE_FORKING;
s->valid_no_process = true;
s->kill_mode = KILL_PROCESS_GROUP;
+ s->restart = SERVICE_ONCE;
u->meta.load_state = UNIT_LOADED;
r = 0;
@@ -1964,14 +1963,18 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
break;
case SERVICE_START:
- assert(s->type == SERVICE_FINISH);
+ if (s->type == SERVICE_FINISH) {
+ /* This was our main goal, so let's go on */
+ if (success)
+ service_enter_start_post(s);
+ else
+ service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
+ break;
+ } else {
+ assert(s->type == SERVICE_DBUS);
- /* This was our main goal, so let's go on */
- if (success)
- service_enter_start_post(s);
- else
- service_enter_signal(s, SERVICE_FINAL_SIGTERM, false);
- break;
+ /* Fall through */
+ }
case SERVICE_RUNNING:
service_enter_running(s, success);
diff --git a/src/service.h b/src/service.h
index 40bd57e256..5242de58fa 100644
--- a/src/service.h
+++ b/src/service.h
@@ -56,8 +56,8 @@ typedef enum ServiceRestart {
} ServiceRestart;
typedef enum ServiceType {
- SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */
SERVICE_SIMPLE, /* we fork and go on right-away (i.e. modern socket activated daemons) */
+ SERVICE_FORKING, /* forks by itself (i.e. traditional daemons) */
SERVICE_FINISH, /* we fork and wait until the program finishes (i.e. programs like fsck which run and need to finish before we continue) */
SERVICE_DBUS, /* we fork and wait until a specific D-Bus name appears on the bus */
_SERVICE_TYPE_MAX,
diff --git a/src/socket-util.c b/src/socket-util.c
index 0c9fc9f999..4a1b3d8b51 100644
--- a/src/socket-util.c
+++ b/src/socket-util.c
@@ -443,7 +443,7 @@ bool socket_address_equal(const SocketAddress *a, const SocketAddress *b) {
return true;
}
-bool socket_address_is(const SocketAddress *a, const char *s) {
+bool socket_address_is(const SocketAddress *a, const char *s, int type) {
struct SocketAddress b;
assert(a);
@@ -452,6 +452,8 @@ bool socket_address_is(const SocketAddress *a, const char *s) {
if (socket_address_parse(&b, s) < 0)
return false;
+ b.type = type;
+
return socket_address_equal(a, &b);
}
diff --git a/src/socket-util.h b/src/socket-util.h
index 993972c458..ffcc86882f 100644
--- a/src/socket-util.h
+++ b/src/socket-util.h
@@ -72,7 +72,7 @@ int socket_address_listen(
mode_t socket_mode,
int *ret);
-bool socket_address_is(const SocketAddress *a, const char *s);
+bool socket_address_is(const SocketAddress *a, const char *s, int type);
bool socket_address_equal(const SocketAddress *a, const SocketAddress *b);
diff --git a/src/socket.c b/src/socket.c
index 909151752c..19f1d22097 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -1067,7 +1067,7 @@ static int socket_serialize(Unit *u, FILE *f, FDSet *fds) {
if ((r = socket_address_print(&p->address, &t)) < 0)
return r;
- unit_serialize_item_format(u, f, "socket", "%i %s", copy, t);
+ unit_serialize_item_format(u, f, "socket", "%i %i %s", copy, p->address.type, t);
free(t);
} else {
assert(p->type == SOCKET_FIFO);
@@ -1145,15 +1145,15 @@ static int socket_deserialize_item(Unit *u, const char *key, const char *value,
}
} else if (streq(key, "socket")) {
- int fd, skip = 0;
+ int fd, type, skip = 0;
SocketPort *p;
- if (sscanf(value, "%i %n", &fd, &skip) < 1 || fd < 0 || !fdset_contains(fds, fd))
+ if (sscanf(value, "%i %i %n", &fd, &type, &skip) < 2 || fd < 0 || type < 0 || !fdset_contains(fds, fd))
log_debug("Failed to parse socket value %s", value);
else {
LIST_FOREACH(port, p, s->ports)
- if (socket_address_is(&p->address, value+skip))
+ if (socket_address_is(&p->address, value+skip, type))
break;
if (p) {
diff --git a/src/strv.h b/src/strv.h
index f0be83dd59..11d2ea1207 100644
--- a/src/strv.h
+++ b/src/strv.h
@@ -29,7 +29,7 @@
char *strv_find(char **l, const char *name);
void strv_free(char **l);
-char **strv_copy(char **l) _malloc;
+char **strv_copy(char **l) _malloc_;
unsigned strv_length(char **l);
char **strv_merge(char **a, char **b);
@@ -41,20 +41,20 @@ char **strv_uniq(char **l);
#define strv_contains(l, s) (!!strv_find((l), (s)))
-char **strv_new(const char *x, ...) _sentinel _malloc;
-char **strv_new_ap(const char *x, va_list ap) _malloc;
+char **strv_new(const char *x, ...) _sentinel_ _malloc_;
+char **strv_new_ap(const char *x, va_list ap) _malloc_;
static inline bool strv_isempty(char **l) {
return !l || !*l;
}
-char **strv_split(const char *s, const char *separator) _malloc;
-char **strv_split_quoted(const char *s) _malloc;
+char **strv_split(const char *s, const char *separator) _malloc_;
+char **strv_split_quoted(const char *s) _malloc_;
-char *strv_join(char **l, const char *separator) _malloc;
+char *strv_join(char **l, const char *separator) _malloc_;
-char **strv_env_merge(char **x, ...) _sentinel;
-char **strv_env_delete(char **x, ...) _sentinel;
+char **strv_env_merge(char **x, ...) _sentinel_;
+char **strv_env_delete(char **x, ...) _sentinel_;
#define STRV_FOREACH(s, l) \
for ((s) = (l); (s) && *(s); (s)++)
diff --git a/src/swap.c b/src/swap.c
index 2c7e4924d6..c35a8e785a 100644
--- a/src/swap.c
+++ b/src/swap.c
@@ -246,7 +246,7 @@ int swap_add_one(
bool from_proc_swaps) {
Unit *u = NULL;
char *e = NULL, *w = NULL;
- bool delete;
+ bool delete = false;
int r;
SwapParameters *p;
diff --git a/src/systemctl.vala b/src/systemctl.vala
index e3e675f479..6cce93bec6 100644
--- a/src/systemctl.vala
+++ b/src/systemctl.vala
@@ -252,25 +252,17 @@ int main (string[] args) {
for (int i = 2; i < args.length; i++) {
- ObjectPath p = manager.load_unit(args[i]);
-
- Unit u = bus.get_object(
- "org.freedesktop.systemd1",
- p,
- "org.freedesktop.systemd1.Unit") as Unit;
-
string mode = replace ? "replace" : "fail";
-
ObjectPath j = null;
if (args[1] == "start")
- j = u.start(mode);
+ j = manager.start_unit(args[i], mode);
else if (args[1] == "stop")
- j = u.stop(mode);
+ j = manager.stop_unit(args[i], mode);
else if (args[1] == "restart")
- j = u.restart(mode);
+ j = manager.restart_unit(args[i], mode);
else if (args[1] == "reload")
- j = u.reload(mode);
+ j = manager.reload_unit(args[i], mode);
if (block)
jobs.append(j);
@@ -283,14 +275,7 @@ int main (string[] args) {
return 1;
}
- ObjectPath p = manager.load_unit(args[2]);
-
- Unit u = bus.get_object(
- "org.freedesktop.systemd1",
- p,
- "org.freedesktop.systemd1.Unit") as Unit;
-
- ObjectPath j = u.start("isolate");
+ ObjectPath j = manager.start_unit(args[2], "isolate");
if (block) {
manager.subscribe();
diff --git a/src/systemd-interfaces.vala b/src/systemd-interfaces.vala
index a8aeb75579..7445479911 100644
--- a/src/systemd-interfaces.vala
+++ b/src/systemd-interfaces.vala
@@ -52,6 +52,11 @@ public interface Manager : DBus.Object {
public abstract ObjectPath load_unit(string name) throws DBus.Error;
public abstract ObjectPath get_job(uint32 id) throws DBus.Error;
+ public abstract ObjectPath start_unit(string name, string mode) throws DBus.Error;
+ public abstract ObjectPath stop_unit(string name, string mode) throws DBus.Error;
+ public abstract ObjectPath reload_unit(string name, string mode) throws DBus.Error;
+ public abstract ObjectPath restart_unit(string name, string mode) throws DBus.Error;
+
public abstract void clear_jobs() throws DBus.Error;
public abstract void subscribe() throws DBus.Error;
diff --git a/src/test-engine.c b/src/test-engine.c
index 27e16f3484..eb17f580e2 100644
--- a/src/test-engine.c
+++ b/src/test-engine.c
@@ -36,9 +36,9 @@ int main(int argc, char *argv[]) {
assert_se(manager_new(MANAGER_INIT, false, &m) >= 0);
printf("Load1:\n");
- assert_se(manager_load_unit(m, "a.service", NULL, &a) == 0);
- assert_se(manager_load_unit(m, "b.service", NULL, &b) == 0);
- assert_se(manager_load_unit(m, "c.service", NULL, &c) == 0);
+ assert_se(manager_load_unit(m, "a.service", NULL, &a) >= 0);
+ assert_se(manager_load_unit(m, "b.service", NULL, &b) >= 0);
+ assert_se(manager_load_unit(m, "c.service", NULL, &c) >= 0);
manager_dump_units(m, stdout, "\t");
printf("Test1: (Trivial)\n");
@@ -47,8 +47,8 @@ int main(int argc, char *argv[]) {
printf("Load2:\n");
manager_clear_jobs(m);
- assert_se(manager_load_unit(m, "d.service", NULL, &d) == 0);
- assert_se(manager_load_unit(m, "e.service", NULL, &e) == 0);
+ assert_se(manager_load_unit(m, "d.service", NULL, &d) >= 0);
+ assert_se(manager_load_unit(m, "e.service", NULL, &e) >= 0);
manager_dump_units(m, stdout, "\t");
printf("Test2: (Cyclic Order, Unfixable)\n");
@@ -64,7 +64,7 @@ int main(int argc, char *argv[]) {
manager_dump_jobs(m, stdout, "\t");
printf("Load3:\n");
- assert_se(manager_load_unit(m, "g.service", NULL, &g) == 0);
+ assert_se(manager_load_unit(m, "g.service", NULL, &g) >= 0);
manager_dump_units(m, stdout, "\t");
printf("Test5: (Colliding transaction, fail)\n");
@@ -86,7 +86,7 @@ int main(int argc, char *argv[]) {
manager_dump_jobs(m, stdout, "\t");
printf("Load4:\n");
- assert_se(manager_load_unit(m, "h.service", NULL, &h) == 0);
+ assert_se(manager_load_unit(m, "h.service", NULL, &h) >= 0);
manager_dump_units(m, stdout, "\t");
printf("Test10: (Unmeargable job type of auxiliary job, fail)\n");
diff --git a/src/unit.c b/src/unit.c
index 57b3b77954..3bb41a4239 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -67,6 +67,7 @@ Unit *unit_new(Manager *m) {
u->meta.manager = m;
u->meta.type = _UNIT_TYPE_INVALID;
+ u->meta.deserialized_job = _JOB_TYPE_INVALID;
return u;
}
@@ -318,10 +319,19 @@ void unit_free(Unit *u) {
bus_unit_send_removed_signal(u);
- /* Detach from next 'bigger' objects */
+ if (u->meta.load_state != UNIT_STUB)
+ if (UNIT_VTABLE(u)->done)
+ UNIT_VTABLE(u)->done(u);
+
SET_FOREACH(t, u->meta.names, i)
hashmap_remove_value(u->meta.manager->units, t, u);
+ if (u->meta.job)
+ job_free(u->meta.job);
+
+ for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
+ bidi_set_free(u, u->meta.dependencies[d]);
+
if (u->meta.type != _UNIT_TYPE_INVALID)
LIST_REMOVE(Meta, units_per_type, u->meta.manager->units_per_type[u->meta.type], &u->meta);
@@ -339,19 +349,8 @@ void unit_free(Unit *u) {
u->meta.manager->n_in_gc_queue--;
}
- /* Free data and next 'smaller' objects */
- if (u->meta.job)
- job_free(u->meta.job);
-
- if (u->meta.load_state != UNIT_STUB)
- if (UNIT_VTABLE(u)->done)
- UNIT_VTABLE(u)->done(u);
-
cgroup_bonding_free_list(u->meta.cgroup_bondings);
- for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++)
- bidi_set_free(u, u->meta.dependencies[d]);
-
free(u->meta.description);
free(u->meta.fragment_path);
@@ -968,56 +967,54 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns) {
* failed previously due to EAGAIN. */
job_add_to_run_queue(u->meta.job);
- else {
- assert(u->meta.job->state == JOB_RUNNING);
- /* Let's check whether this state change
- * constitutes a finished job, or maybe
- * cotradicts a running job and hence needs to
- * invalidate jobs. */
+ /* Let's check whether this state change constitutes a
+ * finished job, or maybe cotradicts a running job and
+ * hence needs to invalidate jobs. */
- switch (u->meta.job->type) {
+ switch (u->meta.job->type) {
- case JOB_START:
- case JOB_VERIFY_ACTIVE:
+ case JOB_START:
+ case JOB_VERIFY_ACTIVE:
- if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
- job_finish_and_invalidate(u->meta.job, true);
- else if (ns != UNIT_ACTIVATING) {
- unexpected = true;
- job_finish_and_invalidate(u->meta.job, false);
- }
+ if (UNIT_IS_ACTIVE_OR_RELOADING(ns))
+ job_finish_and_invalidate(u->meta.job, true);
+ else if (u->meta.job->state == JOB_RUNNING && ns != UNIT_ACTIVATING) {
+ unexpected = true;
+ job_finish_and_invalidate(u->meta.job, false);
+ }
- break;
+ break;
- case JOB_RELOAD:
- case JOB_RELOAD_OR_START:
+ case JOB_RELOAD:
+ case JOB_RELOAD_OR_START:
+ if (u->meta.job->state == JOB_RUNNING) {
if (ns == UNIT_ACTIVE)
job_finish_and_invalidate(u->meta.job, true);
else if (ns != UNIT_ACTIVATING && ns != UNIT_ACTIVE_RELOADING) {
unexpected = true;
job_finish_and_invalidate(u->meta.job, false);
}
+ }
- break;
+ break;
- case JOB_STOP:
- case JOB_RESTART:
- case JOB_TRY_RESTART:
+ case JOB_STOP:
+ case JOB_RESTART:
+ case JOB_TRY_RESTART:
- if (ns == UNIT_INACTIVE)
- job_finish_and_invalidate(u->meta.job, true);
- else if (ns != UNIT_DEACTIVATING) {
- unexpected = true;
- job_finish_and_invalidate(u->meta.job, false);
- }
+ if (ns == UNIT_INACTIVE)
+ job_finish_and_invalidate(u->meta.job, true);
+ else if (u->meta.job->state == JOB_RUNNING && ns != UNIT_DEACTIVATING) {
+ unexpected = true;
+ job_finish_and_invalidate(u->meta.job, false);
+ }
- break;
+ break;
- default:
- assert_not_reached("Job type unknown");
- }
+ default:
+ assert_not_reached("Job type unknown");
}
}
@@ -1794,6 +1791,9 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds) {
if ((r = UNIT_VTABLE(u)->serialize(u, f, fds)) < 0)
return r;
+ if (u->meta.job)
+ unit_serialize_item(u, f, "job", job_type_to_string(u->meta.job->type));
+
/* End marker */
fputc('\n', f);
return 0;
@@ -1860,6 +1860,17 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
} else
v = l+k;
+ if (streq(l, "job")) {
+ JobType type;
+
+ if ((type = job_type_from_string(v)) < 0)
+ log_debug("Failed to parse job type value %s", v);
+ else
+ u->meta.deserialized_job = type;
+
+ continue;
+ }
+
if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0)
return r;
}
@@ -1902,6 +1913,25 @@ int unit_add_node_link(Unit *u, const char *what, bool wants) {
return 0;
}
+int unit_coldplug(Unit *u) {
+ int r;
+
+ assert(u);
+
+ if (UNIT_VTABLE(u)->coldplug)
+ if ((r = UNIT_VTABLE(u)->coldplug(u)) < 0)
+ return r;
+
+ if (u->meta.deserialized_job >= 0) {
+ if ((r = manager_add_job(u->meta.manager, u->meta.deserialized_job, u, JOB_FAIL, false, NULL)) < 0)
+ return r;
+
+ u->meta.deserialized_job = _JOB_TYPE_INVALID;
+ }
+
+ return 0;
+}
+
static const char* const unit_type_table[_UNIT_TYPE_MAX] = {
[UNIT_SERVICE] = "service",
[UNIT_TIMER] = "timer",
diff --git a/src/unit.h b/src/unit.h
index f585fa6238..5e61f7c027 100644
--- a/src/unit.h
+++ b/src/unit.h
@@ -40,7 +40,7 @@ typedef enum UnitDependency UnitDependency;
#include "execute.h"
#define UNIT_NAME_MAX 128
-#define DEFAULT_TIMEOUT_USEC (20*USEC_PER_SEC)
+#define DEFAULT_TIMEOUT_USEC (60*USEC_PER_SEC)
#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
typedef enum KillMode {
@@ -185,6 +185,10 @@ struct Meta {
/* Garbage collect us we nobody wants or requires us anymore */
bool stop_when_unneeded;
+ /* When deserializing, temporarily store the job type for this
+ * unit here, if there was a job scheduled */
+ int deserialized_job; /* This is actually of type JobType */
+
bool in_load_queue:1;
bool in_dbus_queue:1;
bool in_cleanup_queue:1;
@@ -431,12 +435,14 @@ char **unit_full_printf_strv(Unit *u, char **l);
bool unit_can_serialize(Unit *u);
int unit_serialize(Unit *u, FILE *f, FDSet *fds);
-void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_attr(4,5);
+void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *value, ...) _printf_attr_(4,5);
void unit_serialize_item(Unit *u, FILE *f, const char *key, const char *value);
int unit_deserialize(Unit *u, FILE *f, FDSet *fds);
int unit_add_node_link(Unit *u, const char *what, bool wants);
+int unit_coldplug(Unit *u);
+
const char *unit_type_to_string(UnitType i);
UnitType unit_type_from_string(const char *s);
diff --git a/test2/a.service b/test2/a.service
index 4ddb8b4622..4168d2d051 100644
--- a/test2/a.service
+++ b/test2/a.service
@@ -1,4 +1,7 @@
-[Meta]
+[Unit]
Description=A
Requires=b.service
Before=b.service
+
+[Service]
+ExecStart=/bin/true
diff --git a/test2/b.service b/test2/b.service
index ca946073d3..e03bae36be 100644
--- a/test2/b.service
+++ b/test2/b.service
@@ -1,3 +1,6 @@
-[Meta]
+[Unit]
Description=B
Wants=f.service
+
+[Service]
+ExecStart=/bin/true
diff --git a/test2/c.service b/test2/c.service
index 8800ff70c7..e2f60a8fbf 100644
--- a/test2/c.service
+++ b/test2/c.service
@@ -1,3 +1,6 @@
-[Meta]
+[Unit]
Description=C
Requires=a.service
+
+[Service]
+ExecStart=/bin/true
diff --git a/test2/d.service b/test2/d.service
index 279c1716c2..921fd2ee1b 100644
--- a/test2/d.service
+++ b/test2/d.service
@@ -1,5 +1,8 @@
-[Meta]
+[Unit]
Description=D:Cyclic
After=b.service
Before=a.service
Requires=a.service
+
+[Service]
+ExecStart=/bin/true
diff --git a/test2/e.service b/test2/e.service
index 2e86e33daf..5ba98c7c43 100644
--- a/test2/e.service
+++ b/test2/e.service
@@ -1,5 +1,8 @@
-[Meta]
+[Unit]
Description=E:Cyclic
After=b.service
Before=a.service
Wants=a.service
+
+[Service]
+ExecStart=/bin/true
diff --git a/test2/f.service b/test2/f.service
index d0b30effd7..7dde681c17 100644
--- a/test2/f.service
+++ b/test2/f.service
@@ -1,2 +1,5 @@
-[Meta]
+[Unit]
Description=F
+
+[Service]
+ExecStart=/bin/true
diff --git a/test2/g.service b/test2/g.service
index e811e6083d..cbfa82a454 100644
--- a/test2/g.service
+++ b/test2/g.service
@@ -1,3 +1,6 @@
-[Meta]
+[Unit]
Description=G
Conflicts=e.service
+
+[Service]
+ExecStart=/bin/true
diff --git a/test2/h.service b/test2/h.service
index 4b9ffa3e83..74a7751cad 100644
--- a/test2/h.service
+++ b/test2/h.service
@@ -1,3 +1,6 @@
-[Meta]
+[Unit]
Description=H
Wants=g.service
+
+[Service]
+ExecStart=/bin/true
diff --git a/units/.gitignore b/units/.gitignore
index 7e61543864..ea85dc081e 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -1,7 +1,7 @@
systemd-initctl.service
systemd-logger.service
syslog.target
-basic.target
+sysinit.target
graphical.target
multi-user.target
getty@.service
diff --git a/units/sys-fs-fuse-connections.automount b/units/basic.target
index db1316277f..aa94b94ad6 100644
--- a/units/sys-fs-fuse-connections.automount
+++ b/units/basic.target
@@ -5,9 +5,10 @@
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
-[Unit]
-Description=FUSE Control File System Automount Point
-Before=basic.target
+# See systemd.special(7) for details
-[Automount]
-Where=/sys/fs/fuse/connections
+[Unit]
+Description=Basic System
+Requires=sysinit.target local-fs.target swap.target sockets.target
+After=sysinit.target local-fs.target swap.target sockets.target
+OnlyByDependency=yes
diff --git a/units/dev-hugepages.automount b/units/dev-hugepages.automount
index 9fef9eeb37..4e7f8ff5a9 100644
--- a/units/dev-hugepages.automount
+++ b/units/dev-hugepages.automount
@@ -7,7 +7,7 @@
[Unit]
Description=Huge Pages File System Automount Point
-Before=basic.target
+Before=sysinit.target
[Automount]
Where=/dev/hugepages
diff --git a/units/dev-mqueue.automount b/units/dev-mqueue.automount
index a24ffe68f5..4df53dcaa4 100644
--- a/units/dev-mqueue.automount
+++ b/units/dev-mqueue.automount
@@ -7,7 +7,7 @@
[Unit]
Description=POSIX Message Queue File System Automount Point
-Before=basic.target
+Before=sysinit.target
[Automount]
Where=/dev/mqueue
diff --git a/units/emergency.service b/units/emergency.service
index 3cbca3d012..924723fefe 100644
--- a/units/emergency.service
+++ b/units/emergency.service
@@ -12,8 +12,7 @@ Description=Emergency Shell
[Service]
ExecStart=/bin/sh
-Type=simple
StandardInput=tty
Restart=restart-always
RestartSec=0
-KillMode=process
+KillMode=process-group
diff --git a/units/fedora/halt.service b/units/fedora/halt.service
index ff498e4375..50373d48b6 100644
--- a/units/fedora/halt.service
+++ b/units/fedora/halt.service
@@ -9,7 +9,7 @@
Description=Halt
Requires=shutdown.target killall.service
After=shutdown.target killall.service
-Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount
+Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount sys-kernel-security.automount
[Service]
Type=finish
diff --git a/units/fedora/poweroff.service b/units/fedora/poweroff.service
index 07af6c62c3..f237e32719 100644
--- a/units/fedora/poweroff.service
+++ b/units/fedora/poweroff.service
@@ -9,7 +9,7 @@
Description=Power-Off
Requires=shutdown.target killall.service
After=shutdown.target killall.service
-Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount
+Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount sys-kernel-security.automount
[Service]
Type=finish
diff --git a/units/fedora/prefdm.service b/units/fedora/prefdm.service
index 291910239f..3428026c54 100644
--- a/units/fedora/prefdm.service
+++ b/units/fedora/prefdm.service
@@ -14,4 +14,3 @@ Conflicts=shutdown.target
[Service]
ExecStart=/etc/X11/prefdm -nodaemon
-Type=simple
diff --git a/units/fedora/rc-local.service b/units/fedora/rc-local.service
index cb0700700b..58b59820e2 100644
--- a/units/fedora/rc-local.service
+++ b/units/fedora/rc-local.service
@@ -10,6 +10,7 @@ Description=/etc/rc.local Compatibility
Requires=basic.target
After=basic.target
Conflicts=shutdown.target
+Before=getty@tty1.service
# The rcN.d symlink uses the name "local" while the script itself is
# called "rc.local", hence carry both names here.
@@ -17,7 +18,6 @@ Names=rc-local.service local.service
[Service]
ExecStart=/etc/rc.local start
-Type=simple
TimeoutSec=0
StandardInput=tty
ValidNoProcess=yes
diff --git a/units/fedora/reboot.service b/units/fedora/reboot.service
index 77f5cb3f53..b99dfdc8ac 100644
--- a/units/fedora/reboot.service
+++ b/units/fedora/reboot.service
@@ -9,7 +9,7 @@
Description=Reboot
Requires=shutdown.target killall.service
After=shutdown.target killall.service
-Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount
+Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount sys-kernel-security.automount
[Service]
Type=finish
diff --git a/units/gentoo/Makefile b/units/gentoo/Makefile
new file mode 120000
index 0000000000..50be21181f
--- /dev/null
+++ b/units/gentoo/Makefile
@@ -0,0 +1 @@
+../../src/Makefile \ No newline at end of file
diff --git a/units/gentoo/halt.service b/units/gentoo/halt.service
index 8762a7827b..c5d96043c0 100644
--- a/units/gentoo/halt.service
+++ b/units/gentoo/halt.service
@@ -9,7 +9,7 @@
Description=Halt
Requires=shutdown.target killall.service
After=shutdown.target killall.service
-Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount
+Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount sys-kernel-security.automount
[Service]
Type=finish
diff --git a/units/gentoo/killall.service b/units/gentoo/killall.service
index a02062f815..626e9d1f68 100644
--- a/units/gentoo/killall.service
+++ b/units/gentoo/killall.service
@@ -8,6 +8,7 @@
[Unit]
Description=Kill All Processes
After=shutdown.target
+OnlyByDependency=yes
[Service]
Type=finish
diff --git a/units/gentoo/poweroff.service b/units/gentoo/poweroff.service
index 1a0a6a44f8..2cc645ec53 100644
--- a/units/gentoo/poweroff.service
+++ b/units/gentoo/poweroff.service
@@ -9,7 +9,7 @@
Description=Power-Off
Requires=shutdown.target killall.service
After=shutdown.target killall.service
-Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount
+Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount sys-kernel-security.automount
[Service]
Type=finish
diff --git a/units/gentoo/reboot.service b/units/gentoo/reboot.service
index 080a084c75..fdca6f866e 100644
--- a/units/gentoo/reboot.service
+++ b/units/gentoo/reboot.service
@@ -9,7 +9,7 @@
Description=Reboot
Requires=shutdown.target killall.service
After=shutdown.target killall.service
-Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount
+Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount sys-kernel-security.automount
[Service]
Type=finish
diff --git a/units/gentoo/xdm.service b/units/gentoo/xdm.service
index 8370ef24f8..ac1df75722 100644
--- a/units/gentoo/xdm.service
+++ b/units/gentoo/xdm.service
@@ -14,4 +14,3 @@ Conflicts=shutdown.target
[Service]
ExecStart=/etc/init.d/xdm start
-Type=simple
diff --git a/units/getty@.service.m4 b/units/getty@.service.m4
index d330fdf32b..a302bf9722 100644
--- a/units/getty@.service.m4
+++ b/units/getty@.service.m4
@@ -17,7 +17,8 @@ After=basic.target
Conflicts=shutdown.target
[Service]
-Type=simple
+Environment=TERM=linux
ExecStart=GETTY %I
Restart=restart-always
RestartSec=0
+KillMode=process-group
diff --git a/units/proc-sys-fs-binfmt_misc.automount b/units/proc-sys-fs-binfmt_misc.automount
index 4e9b23b938..82369c56b3 100644
--- a/units/proc-sys-fs-binfmt_misc.automount
+++ b/units/proc-sys-fs-binfmt_misc.automount
@@ -7,7 +7,7 @@
[Unit]
Description=Arbitrary Executable File Formats File System Automount Point
-Before=basic.target
+Before=sysinit.target
[Automount]
Where=/proc/sys/fs/binfmt_misc
diff --git a/units/suse/Makefile b/units/suse/Makefile
new file mode 120000
index 0000000000..50be21181f
--- /dev/null
+++ b/units/suse/Makefile
@@ -0,0 +1 @@
+../../src/Makefile \ No newline at end of file
diff --git a/units/suse/halt.service b/units/suse/halt.service
new file mode 100644
index 0000000000..bc237f02f0
--- /dev/null
+++ b/units/suse/halt.service
@@ -0,0 +1,19 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Halt
+Requires=shutdown.target
+After=shutdown.target
+Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount sys-kernel-security.automount
+
+[Service]
+Type=finish
+ValidNoProcess=yes
+Environment=INIT_HALT=HALT
+Environment=RUNLEVEL=0
+ExecStart=/etc/init.d/halt start
diff --git a/units/suse/poweroff.service b/units/suse/poweroff.service
new file mode 100644
index 0000000000..a68c10cfd3
--- /dev/null
+++ b/units/suse/poweroff.service
@@ -0,0 +1,17 @@
+# 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=Power-Off
+Requires=shutdown.target
+After=shutdown.target
+Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount sys-kernel-security.automount
+
+[Service]
+Type=finish
+ValidNoProcess=yes
+ExecStart=/etc/init.d/halt start
diff --git a/units/sys-fs-fuse-connections.mount b/units/suse/reboot.service
index 0a0a4e8ccb..3dbb469117 100644
--- a/units/sys-fs-fuse-connections.mount
+++ b/units/suse/reboot.service
@@ -6,9 +6,12 @@
# (at your option) any later version.
[Unit]
-Description=FUSE Control File System
+Description=Reboot
+Requires=shutdown.target
+After=shutdown.target
+Conflicts=dev-hugepages.automount dev-mqueue.automount proc-sys-fs-binfmt_misc.automount sys-kernel-debug.automount sys-kernel-security.automount
-[Mount]
-What=fusectl
-Where=/sys/fs/fuse/connections
-Type=fusectl
+[Service]
+Type=finish
+ValidNoProcess=yes
+ExecStart=/etc/init.d/reboot start
diff --git a/units/sys-kernel-debug.automount b/units/sys-kernel-debug.automount
index 3d5b52d049..4da3f20531 100644
--- a/units/sys-kernel-debug.automount
+++ b/units/sys-kernel-debug.automount
@@ -7,7 +7,7 @@
[Unit]
Description=Debug File System Automount Point
-Before=basic.target
+Before=sysinit.target
[Automount]
Where=/sys/kernel/debug
diff --git a/units/sys-kernel-security.automount b/units/sys-kernel-security.automount
index 061a5a23ad..5d8356e513 100644
--- a/units/sys-kernel-security.automount
+++ b/units/sys-kernel-security.automount
@@ -7,7 +7,7 @@
[Unit]
Description=Security File System Automount Point
-Before=basic.target
+Before=sysinit.target
[Automount]
Where=/sys/kernel/security
diff --git a/units/basic.target.m4 b/units/sysinit.target.m4
index 537ad8daf7..68c661ef02 100644
--- a/units/basic.target.m4
+++ b/units/sysinit.target.m4
@@ -8,9 +8,7 @@
# See systemd.special(7) for details
[Unit]
-Description=Basic System
-Requires=local-fs.target swap.target sockets.target
-After=local-fs.target swap.target sockets.target
+Description=Systemd Initialization
Conflicts=emergency.service
OnlyByDependency=yes
m4_dnl
diff --git a/units/systemd-initctl.service.in b/units/systemd-initctl.service.in
index 283c057cf4..7450e07e61 100644
--- a/units/systemd-initctl.service.in
+++ b/units/systemd-initctl.service.in
@@ -11,5 +11,4 @@
Description=systemd /dev/initctl Compatibility Daemon
[Service]
-ExecStart=@pkglibexecdir@/systemd-initctl
-Type=simple
+ExecStart=@rootlibexecdir@/systemd-initctl
diff --git a/units/systemd-initctl.socket b/units/systemd-initctl.socket
index fdb95deddd..26b526cdcb 100644
--- a/units/systemd-initctl.socket
+++ b/units/systemd-initctl.socket
@@ -9,6 +9,8 @@
[Unit]
Description=systemd /dev/initctl Compatibility Socket
+After=sysinit.target
+Before=sockets.target
[Socket]
ListenFIFO=/dev/initctl
diff --git a/units/systemd-logger.service.in b/units/systemd-logger.service.in
index 39a20013b4..2004438971 100644
--- a/units/systemd-logger.service.in
+++ b/units/systemd-logger.service.in
@@ -12,5 +12,4 @@ Description=systemd Logging Daemon
After=@SPECIAL_SYSLOG_SERVICE@
[Service]
-ExecStart=@pkglibexecdir@/systemd-logger
-Type=simple
+ExecStart=@rootlibexecdir@/systemd-logger
diff --git a/units/systemd-logger.socket b/units/systemd-logger.socket
index f62b582d3e..44684ce1d0 100644
--- a/units/systemd-logger.socket
+++ b/units/systemd-logger.socket
@@ -9,6 +9,8 @@
[Unit]
Description=systemd Logging Socket
+After=sysinit.target
+Before=sockets.target
[Socket]
ListenStream=@/org/freedesktop/systemd1/logger