diff --git a/.gitignore b/.gitignore
index 0584d900d..be44cb60b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,7 @@
+systemd-binfmt
+systemd-getty-generator
+systemd-nspawn
+systemd-stdio-bridge
systemd-machine-id-setup
systemd-detect-virt
systemd-sysctl
diff --git a/Makefile.am b/Makefile.am
index 4caa2433b..2f08ceb17 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -30,18 +30,17 @@ bashcompletiondir=$(sysconfdir)/bash_completion.d
# Our own, non-special dirs
pkgsysconfdir=$(sysconfdir)/systemd
-userunitdir=$(pkgdatadir)/user
+userunitdir=$(prefix)/lib/systemd/user
tmpfilesdir=$(sysconfdir)/tmpfiles.d
usergeneratordir=$(pkglibexecdir)/user-generators
# And these are the special ones for /
rootdir=@rootdir@
rootbindir=$(rootdir)/bin
-rootsbindir=$(rootdir)/sbin
rootlibexecdir=$(rootdir)/lib/systemd
+systemgeneratordir=$(rootlibexecdir)/system-generators
+systemshutdowndir=$(rootlibexecdir)/system-shutdown
systemunitdir=$(rootdir)/lib/systemd/system
-systemgeneratordir=$(rootdir)/lib/systemd/system-generators
-systemshutdowndir=$(rootdir)/lib/systemd/system-shutdown
AM_CPPFLAGS = \
-include $(top_builddir)/config.h \
@@ -58,7 +57,8 @@ AM_CPPFLAGS = \
-DSYSTEMD_SHUTDOWN_BINARY_PATH=\"$(rootlibexecdir)/systemd-shutdown\" \
-DSYSTEMCTL_BINARY_PATH=\"$(rootbindir)/systemctl\" \
-DSYSTEMD_TTY_ASK_PASSWORD_AGENT_BINARY_PATH=\"$(rootbindir)/systemd-tty-ask-password-agent\" \
- -DRUNTIME_DIR=\"$(localstatedir)/run\" \
+ -DSYSTEMD_STDIO_BRIDGE_BINARY_PATH=\"$(bindir)/systemd-stdio-bridge\" \
+ -DRUNTIME_DIR=\"/run\" \
-DRANDOM_SEED=\"$(localstatedir)/lib/random-seed\" \
-DSYSTEMD_CRYPTSETUP_PATH=\"$(rootlibexecdir)/systemd-cryptsetup\" \
-DSYSTEM_GENERATOR_PATH=\"$(systemgeneratordir)\" \
@@ -109,7 +109,12 @@ rootbin_PROGRAMS = \
systemd-machine-id-setup
bin_PROGRAMS = \
- systemd-cgls
+ systemd-cgls \
+ systemd-stdio-bridge \
+ systemd-nspawn
+
+dist_bin_SCRIPTS = \
+ src/systemd-analyze
if HAVE_GTK
bin_PROGRAMS += \
@@ -138,13 +143,17 @@ rootlibexec_PROGRAMS = \
systemd-timestamp \
systemd-ac-power \
systemd-detect-virt \
- systemd-sysctl
+ systemd-sysctl \
+ systemd-binfmt
+
+systemgenerator_PROGRAMS = \
+ systemd-getty-generator
if HAVE_LIBCRYPTSETUP
rootlibexec_PROGRAMS += \
systemd-cryptsetup
-systemgenerator_PROGRAMS = \
+systemgenerator_PROGRAMS += \
systemd-cryptsetup-generator
endif
@@ -192,13 +201,20 @@ dbusinterface_DATA = \
org.freedesktop.systemd1.Path.xml
dist_bashcompletion_DATA = \
- src/systemctl-bash-completion.sh
+ src/systemctl-bash-completion.sh
dist_tmpfiles_DATA = \
tmpfiles.d/systemd.conf \
tmpfiles.d/x11.conf
+if HAVE_SYSV_COMPAT
+dist_tmpfiles_DATA += \
+ tmpfiles.d/legacy.conf
+endif
+
dist_systemunit_DATA = \
+ units/graphical.target \
+ units/multi-user.target \
units/emergency.service \
units/emergency.target \
units/sysinit.target \
@@ -216,14 +232,13 @@ dist_systemunit_DATA = \
units/reboot.target \
units/rescue.target \
units/rpcbind.target \
- units/rtc-set.target \
+ units/time-sync.target \
units/shutdown.target \
units/final.target \
units/umount.target \
units/sigpwr.target \
units/sockets.target \
units/swap.target \
- units/dbus.target \
units/systemd-initctl.socket \
units/systemd-logger.socket \
units/systemd-shutdownd.socket \
@@ -238,7 +253,6 @@ dist_systemunit_DATA = \
units/sys-kernel-debug.mount \
units/sys-kernel-security.automount \
units/sys-kernel-security.mount \
- units/var-lock.mount \
units/var-run.mount \
units/media.mount \
units/hwclock-load.service \
@@ -252,14 +266,19 @@ dist_systemunit_DATA = \
units/systemd-tmpfiles-clean.timer \
units/quotaon.service \
units/systemd-ask-password-wall.path \
- units/systemd-ask-password-console.path
+ units/systemd-ask-password-console.path \
+ units/syslog.target
+
+if HAVE_SYSV_COMPAT
+dist_systemunit_DATA += \
+ units/var-lock.mount
+endif
nodist_systemunit_DATA = \
units/getty@.service \
units/serial-getty@.service \
- units/graphical.target \
+ units/console-shell.service \
units/remote-fs.target \
- units/multi-user.target \
units/systemd-initctl.service \
units/systemd-logger.service \
units/systemd-shutdownd.service \
@@ -280,7 +299,7 @@ nodist_systemunit_DATA = \
units/systemd-ask-password-wall.service \
units/systemd-ask-password-console.service \
units/systemd-sysctl.service \
- units/syslog.target \
+ units/systemd-binfmt.service \
units/halt.service \
units/poweroff.service \
units/reboot.service \
@@ -301,8 +320,7 @@ nodist_userunit_DATA = \
EXTRA_DIST = \
units/getty@.service.m4 \
units/serial-getty@.service.m4 \
- units/graphical.target.m4 \
- units/multi-user.target.m4 \
+ units/console-shell.service.m4 \
units/remote-fs.target.m4 \
units/rescue.service.m4 \
units/systemd-initctl.service.in \
@@ -325,7 +343,7 @@ EXTRA_DIST = \
units/systemd-ask-password-wall.service.in \
units/systemd-ask-password-console.service.in \
units/systemd-sysctl.service.in \
- units/syslog.target.in \
+ units/systemd-binfmt.service.in \
units/halt.service.in \
units/poweroff.service.in \
units/reboot.service.in \
@@ -335,7 +353,8 @@ EXTRA_DIST = \
units/fsck-root.service.in \
units/quotacheck.service.in \
systemd.pc.in \
- introspect.awk
+ introspect.awk \
+ src/org.freedesktop.systemd1.policy.in
if TARGET_FEDORA
dist_systemunit_DATA += \
@@ -351,6 +370,11 @@ dist_systemunit_DATA += \
units/fedora/halt-local.service
endif
+if TARGET_FRUGALWARE
+dist_systemunit_DATA += \
+ units/frugalware/display-manager.service
+endif
+
if HAVE_PLYMOUTH
dist_systemunit_DATA += \
units/plymouth-start.service \
@@ -382,7 +406,7 @@ dist_doc_DATA = \
pkgconfigdata_DATA = \
systemd.pc
-dist_polkitpolicy_DATA = \
+polkitpolicy_DATA = \
src/org.freedesktop.systemd1.policy
noinst_LTLIBRARIES = \
@@ -487,6 +511,7 @@ EXTRA_DIST += \
${libsystemd_core_la_SOURCES:.c=.h} \
${libsystemd_daemon_la_SOURCES:.c=.h} \
src/macro.h \
+ src/def.h \
src/ioprio.h \
src/missing.h \
src/list.h \
@@ -510,6 +535,7 @@ MANPAGES = \
man/systemctl.1 \
man/systemadm.1 \
man/systemd-cgls.1 \
+ man/systemd-nspawn.1 \
man/systemd-tmpfiles.8 \
man/systemd-notify.1 \
man/sd_notify.3 \
@@ -544,7 +570,9 @@ MANPAGES = \
man/vconsole.conf.5 \
man/locale.conf.5 \
man/os-release.5 \
- man/modules-load.d.5
+ man/modules-load.d.5 \
+ man/binfmt.d.5 \
+ man/sysctl.d.5
MANPAGES_ALIAS = \
man/reboot.8 \
@@ -774,6 +802,15 @@ systemd_sysctl_CFLAGS = \
systemd_sysctl_LDADD = \
libsystemd-basic.la
+systemd_binfmt_SOURCES = \
+ src/binfmt.c
+
+systemd_binfmt_CFLAGS = \
+ $(AM_CFLAGS)
+
+systemd_binfmt_LDADD = \
+ libsystemd-basic.la
+
systemd_fsck_SOURCES = \
src/fsck.c \
src/dbus-common.c
@@ -850,6 +887,16 @@ systemd_cryptsetup_generator_CFLAGS = \
systemd_cryptsetup_generator_LDADD = \
libsystemd-basic.la
+systemd_getty_generator_SOURCES = \
+ src/getty-generator.c \
+ src/unit-name.c
+
+systemd_getty_generator_CFLAGS = \
+ $(AM_CFLAGS)
+
+systemd_getty_generator_LDADD = \
+ libsystemd-basic.la
+
systemd_user_sessions_SOURCES = \
src/user-sessions.c \
src/cgroup-util.c
@@ -978,6 +1025,23 @@ systemd_cgls_CFLAGS = \
systemd_cgls_LDADD = \
libsystemd-basic.la
+systemd_nspawn_SOURCES = \
+ src/nspawn.c \
+ src/cgroup-util.c
+
+systemd_nspawn_CFLAGS = \
+ $(AM_CFLAGS)
+
+systemd_nspawn_LDADD = \
+ libsystemd-basic.la \
+ libsystemd-daemon.la
+
+systemd_stdio_bridge_SOURCES = \
+ src/bridge.c
+
+systemd_stdio_bridge_LDADD = \
+ libsystemd-basic.la
+
systemadm_SOURCES = \
src/systemadm.vala \
src/systemd-interfaces.vala
@@ -1058,13 +1122,15 @@ pam_systemd_la_LIBADD = \
SED_PROCESS = \
$(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
$(SED) -e 's,@rootlibexecdir\@,$(rootlibexecdir),g' \
- -e 's,@rootbindir\@,$(rootbindir),g' \
- -e 's,@SPECIAL_SYSLOG_SERVICE\@,$(SPECIAL_SYSLOG_SERVICE),g' \
+ -e 's,@rootbindir\@,$(rootbindir),g' \
+ -e 's,@bindir\@,$(bindir),g' \
-e 's,@SYSTEMCTL\@,$(rootbindir)/systemctl,g' \
-e 's,@SYSTEMD_NOTIFY\@,$(rootbindir)/systemd-notify,g' \
-e 's,@pkgsysconfdir\@,$(pkgsysconfdir),g' \
-e 's,@pkgdatadir\@,$(pkgdatadir),g' \
+ -e 's,@pkglibexecdir\@,$(pkglibexecdir),g' \
-e 's,@systemunitdir\@,$(systemunitdir),g' \
+ -e 's,@userunitdir\@,$(userunitdir),g' \
-e 's,@PACKAGE_VERSION\@,$(PACKAGE_VERSION),g' \
-e 's,@PACKAGE_NAME\@,$(PACKAGE_NAME),g' \
-e 's,@PACKAGE_URL\@,$(PACKAGE_URL),g' \
@@ -1080,6 +1146,9 @@ man/%: man/%.in Makefile
%.pc: %.pc.in Makefile
$(SED_PROCESS)
+src/%.policy: src/%.policy.in Makefile
+ $(SED_PROCESS)
+
M4_PROCESS_SYSTEM = \
$(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
$(M4) -P $(M4_DISTRO_FLAG) -DFOR_SYSTEM=1 < $< > $@ || rm $@
@@ -1099,7 +1168,8 @@ CLEANFILES = \
$(nodist_userunit_DATA) \
$(nodist_man_MANS) \
${XML_IN_FILES:.xml.in=.html} \
- $(pkgconfigdata_DATA)
+ $(pkgconfigdata_DATA) \
+ src/org.freedesktop.systemd1.policy
if HAVE_VALAC
CLEANFILES += \
@@ -1183,6 +1253,14 @@ CLEANFILES += \
$(dbusinterface_DATA)
install-data-hook:
+ $(MKDIR_P) -m 0755 \
+ $(DESTDIR)$(tmpfilesdir) \
+ $(DESTDIR)$(sysconfdir)/modules-load.d \
+ $(DESTDIR)$(sysconfdir)/sysctl.d \
+ $(DESTDIR)$(sysconfdir)/binfmt.d \
+ $(DESTDIR)$(systemshutdowndir) \
+ $(DESTDIR)$(systemgeneratordir) \
+ $(DESTDIR)$(usergeneratordir)
$(MKDIR_P) -m 0755 \
$(DESTDIR)$(systemunitdir) \
$(DESTDIR)$(userunitdir) \
@@ -1241,13 +1319,11 @@ install-data-hook:
fsck-root.service \
remount-rootfs.service \
var-run.mount \
- var-lock.mount \
media.mount && \
$(LN_S) ../systemd-remount-api-vfs.service systemd-remount-api-vfs.service && \
$(LN_S) ../fsck-root.service fsck-root.service && \
$(LN_S) ../remount-rootfs.service remount-rootfs.service && \
$(LN_S) ../var-run.mount var-run.mount && \
- $(LN_S) ../var-lock.mount var-lock.mount && \
$(LN_S) ../media.mount media.mount )
( cd $(DESTDIR)$(userunitdir) && \
rm -f shutdown.target sockets.target local-fs.target swap.target bluetooth.target printer.target sound.target && \
@@ -1284,10 +1360,6 @@ install-data-hook:
$(LN_S) $(systemunitdir)/getty@.service getty@tty4.service && \
$(LN_S) $(systemunitdir)/getty@.service getty@tty5.service && \
$(LN_S) $(systemunitdir)/getty@.service getty@tty6.service )
- ( cd $(DESTDIR)$(pkgsysconfdir)/system/local-fs.target.wants && \
- rm -f quotaon.service quotacheck.service && \
- $(LN_S) $(systemunitdir)/quotacheck.service quotacheck.service && \
- $(LN_S) $(systemunitdir)/quotaon.service quotaon.service )
( cd $(DESTDIR)$(pkgsysconfdir)/system/multi-user.target.wants && \
rm -f remote-fs.target && \
$(LN_S) $(systemunitdir)/remote-fs.target remote-fs.target )
@@ -1305,6 +1377,7 @@ install-data-hook:
systemd-random-seed-load.service \
systemd-tmpfiles-setup.service \
systemd-sysctl.service \
+ systemd-binfmt.service \
systemd-ask-password-console.path \
systemd-kmsg-syslogd.service \
cryptsetup.target && \
@@ -1318,6 +1391,7 @@ install-data-hook:
$(LN_S) ../systemd-random-seed-load.service systemd-random-seed-load.service && \
$(LN_S) ../systemd-tmpfiles-setup.service systemd-tmpfiles-setup.service && \
$(LN_S) ../systemd-sysctl.service systemd-sysctl.service && \
+ $(LN_S) ../systemd-binfmt.service systemd-binfmt.service && \
$(LN_S) ../systemd-ask-password-console.path systemd-ask-password-console.path && \
$(LN_S) ../systemd-kmsg-syslogd.service && \
$(LN_S) ../cryptsetup.target cryptsetup.target )
@@ -1365,8 +1439,9 @@ if TARGET_FEDORA
rm -f halt-local.service && \
$(LN_S) $(systemunitdir)/halt-local.service halt-local.service )
( cd $(DESTDIR)$(systemunitdir) && \
- rm -f display-manager.service && \
- $(LN_S) prefdm.service display-manager.service )
+ rm -f display-manager.service single.service && \
+ $(LN_S) prefdm.service display-manager.service && \
+ $(LN_S) rescue.service single.service )
( cd $(DESTDIR)$(systemunitdir)/graphical.target.wants && \
rm -f display-manager.service && \
$(LN_S) $(systemunitdir)/display-manager.service display-manager.service )
@@ -1381,8 +1456,10 @@ if TARGET_MANDRIVA
rm -f halt-local.service && \
$(LN_S) $(systemunitdir)/halt-local.service halt-local.service )
( cd $(DESTDIR)$(systemunitdir) && \
- rm -f display-manager.service && \
- $(LN_S) prefdm.service display-manager.service )
+ rm -f display-manager.service dm.service single.service && \
+ $(LN_S) prefdm.service display-manager.service && \
+ $(LN_S) prefdm.service dm.service && \
+ $(LN_S) rescue.service single.service )
( cd $(DESTDIR)$(systemunitdir)/graphical.target.wants && \
rm -f display-manager.service && \
$(LN_S) $(systemunitdir)/display-manager.service display-manager.service )
@@ -1394,6 +1471,12 @@ if TARGET_DEBIAN_OR_UBUNTU
$(LN_S) multi-user.target runlevel5.target )
endif
+if HAVE_SYSV_COMPAT
+ ( cd $(DESTDIR)$(systemunitdir)/local-fs.target.wants && \
+ rm -f var-lock.mount && \
+ $(LN_S) ../var-lock.mount var-lock.mount )
+endif
+
DISTCHECK_CONFIGURE_FLAGS = \
--with-dbuspolicydir=$$dc_install_base/$(dbuspolicydir) \
--with-dbussessionservicedir=$$dc_install_base/$(dbussessionservicedir) \
diff --git a/TODO b/TODO
index ad844d5cd..e8c1388ed 100644
--- a/TODO
+++ b/TODO
@@ -2,28 +2,113 @@ 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
+ https://bugzilla.redhat.com/show_bug.cgi?id=688661
-* finish syslog socket stuff
+* NFS, networkmanager ordering issue (PENDING)
-* NFS, networkmanager ordering issue
+* NM should pull in network.target (PENDING)
+ https://bugzilla.redhat.com/show_bug.cgi?id=692008
+
+* ntpd should pull in time-sync.target. (PENDING)
* 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
-* mount /dev/.run and /var/run as bind mounts
+* bind mounts are ignored
+ https://bugzilla.redhat.com/show_bug.cgi?id=682662
-* Make use of UnknownInterface
+* 0595f9a1c182a84581749823ef47c5f292e545f9 is borked, freezes shutdown
+ (path: after installing inotify watches, recheck file again to fix race)
-* support chkconfig without forwarding to systemctl to facilitate upgrades
+* bluetooth should be possible to disable
-* drop SIGHUP handling from rsyslog.service upstream
+* fix alsa mixer restore to not print error when no config is stored
Features:
+* don't trim empty cgroups
+ https://bugzilla.redhat.com/show_bug.cgi?id=678555
+
+* serialize used job ids and max job id
+
+* show enablement status in systemctl status
+
+* expose monotonic timestamps on the bus and make systemd-analyze use it
+
+* write blog stories about:
+ - chroot, nspawn and friends
+ - the blame game: systemd-analyze
+ - enabling dbus services
+ - status update
+
+* allow port = 0 in .socket units
+
+* rename systemd-logger to systemd-stdio-syslog-bridge
+
+* introduce /usr/lib/binfmt.d/, /usr/lib/tmpfiles.d/
+
+* in pam_systemd: don't rely on /proc/self/loginuid in a container
+
+* take BSD file lock on tty devices when using them?
+
+* tmpfiles should allow two identical lines
+ https://bugzilla.redhat.com/show_bug.cgi?id=690253
+
+* avoid any flag files, or readahead files in /, we need to support r/o /
+ or / on tmpfs like Android setups.
+
+* teach dbus to activate all services it finds in /etc/systemd/services/org-*.service
+
+* get process transport into dbus for systemctl -P/-H
+
+* document default dependencies
+
+* support systemd.whitelist=/systemd.blacklist= on the kernel command
+ line.
+
+* Find a way to replace /var/run, /var/lock directories with
+ symlinks during an RPM package upgrade (filesystem.rpm or systemd.rpm).
+ We soon want to get rid of var-run.mount var-lock.mount units.
+
+* when key file cannot be found, read it from kbd in cryptsetup
+
+* get rid of random file name in generator directory?
+ /run/systemd/generator-IH1vFu
+
+* add switch to systemctl to show enabled but not running services. Or
+ another switch that shows service that have been running since
+ booting but aren't running anymore.
+
+* reuse mkdtemp namespace dirs in /tmp?
+
+* don't strip facility from kmsg log messages as soon as that is possible:
+ http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=9d90c8d9cde929cbc575098e825d7c29d9f45054
+
+* recreate systemd's D-Bus private socket file on SIGUSR2
+
+* be more specific what failed:
+ ...
+ Unmounting file systems.
+ Not all file systems unmounted, 1 left.
+ Disabling swaps.
+ Detaching loop devices.
+ Detaching DM devices.
+ Cannot finalize remaining file systems and devices, trying to kill remaining processes.
+ Unmounting file systems.
+ Not all file systems unmounted, 1 left.
+ Cannot finalize remaining file systems and devices, giving up.
+ ...
+
+* check for compiled-in, but not active selinux, and don't print any warnings
+ about policy loading. Probably check for available selinux in /proc/filesystems,
+ and check for active selinux with getcon_raw() == "kernel"
+
+* optionally create watched directories in .path units
+
+* Support --test based on current system state
+
* consider services with no [Install] section and stored in /lib enabled by "systemctl is-enabled"
* consider services with any kind of link in /etc/systemd/system enabled
@@ -32,17 +117,21 @@ Features:
* make sure timeouts are applied to Type=oneshot services.
-* maybe implement "systemctl mask" and "systemctl unmask", but not
+* 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.
+ Consider moving the actual fs operations into systemd behind a D-Bus
+ interface, to make namespaces/containers/remote connections work properly.
* detect LXC environment
* invoke vhangup() before and after invoking getty
+ http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=3c95c985fa91ecf6a0e29622bbdd13dcfc5ce9f1
* support "auto" and "comment=systemd.automount" at the same time for an fstab entry
* Maybe store in unit files whether a service should be enabled by default on package installation
+ (belongs into a distro pattern though, not in an upstream package's service file)
* perhaps add "systemctl reenable" as combination of "systemctl disable" and "systemctl enable"
@@ -55,7 +144,7 @@ Features:
* Patch systemd-fsck to use -C and pass console fd to it
-* support remote/ssh systemctl/systemadm, and local privileged access
+* support remote/ssh systemctl/systemadm, and local privileged access → dbus patches need to be merged
* configurable jitter for timer events
@@ -74,32 +163,28 @@ Features:
- get PR_SET_ANCHOR merged: http://lkml.org/lkml/2010/2/2/165
* add VT tracking:
- - provide CK functionality
- - start getty only when actual vt switch happens (same model as
- socket on-demand activation). allocate the next free tty and
- start a getty there. this way, pressing alt-f[1-12] will switch
- through running X and getty sessions, and any unallocated
- activated tty will start a new getty. the hardcoding of
- getty[1-6] will entirely go away.
- - http://git.kernel.org/?p=linux/kernel/git/gregkh/tty-2.6.git;a=commitdiff;h=fbc92a3455577ab17615cbcb91826399061bd789
+ - provide CK functionality
+ - start getty only when actual vt switch happens (same model as
+ socket on-demand activation). allocate the next free tty and
+ start a getty there. this way, pressing alt-f[1-12] will switch
+ through running X and getty sessions, and any unallocated
+ activated tty will start a new getty. the hardcoding of
+ getty[1-6] will entirely go away.
+ - http://git.kernel.org/?p=linux/kernel/git/gregkh/tty-2.6.git;a=commitdiff;h=fbc92a3455577ab17615cbcb91826399061bd789
* implicitly import "defaults" settings file into all types
* port over to LISTEN_FDS/LISTEN_PID:
- - uuidd DONE
- - dbus DONE
- - rsyslog DONE
- - rpcbind (/var/run/rpcbind.sock!) DONE
- - cups DONE
- - avahi-daemon (/var/run/avahi-daemon/socket) DONE
- - ssh CLASSIC
+ - uuidd HAVEPATCH
+ - rpcbind (/var/run/rpcbind.sock!) HAVEPATCH
+ - cups HAVEPATCH
- postfix, saslauthd
- apache/samba
- libvirtd (/var/run/libvirt/libvirt-sock-ro)
- bluetoothd (/var/run/sdp! @/org/bluez/audio!)
- distccd
-* fingerprint.target, wireless.target, gps.target
+* fingerprint.target, wireless.target, gps.target, netdevice.target
* set_put(), hashmap_put() return values check. i.e. == 0 doesn't free()!
@@ -115,16 +200,12 @@ Features:
* add systemctl switch to dump transaction without executing it
-* suspend, resume
+* suspend, resume support?
* readahead: btrfs/LVM SSD detection
* add separate man page for [Install] settings
-* only add quotacheck deps to .mount units which mention grpquota/usrquota in the mount flags
-
-* systemctl condrestart should return 0 if service isn't running
-
* allow runtime changing of log level and target
External:
@@ -133,7 +214,7 @@ External:
* snd-seq should go, https://bugzilla.redhat.com/show_bug.cgi?id=676095
-* gnome-shell python script/glxinfo/is-accelerated wech
+* gnome-shell python script/glxinfo/is-accelerated must die
* make cryptsetup lower --iter-time
@@ -141,6 +222,7 @@ External:
* patch kernel for cpu feature modalias for autoloading aes/kvm/...
http://git.kernel.org/?p=linux/kernel/git/ak/linux-misc-2.6.git;a=shortlog;h=refs/heads/cpuid-match
+ (Rafael J. Wysocki's sysdev rework is on the way. After that CPUs can be exported a proper bus.)
* procps, psmisc, sysvinit-tools, hostname → util-linux-ng
diff --git a/autogen.sh b/autogen.sh
index 74f814d28..826d9b0d0 100755
--- a/autogen.sh
+++ b/autogen.sh
@@ -66,7 +66,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 --with-rootdir= "$@"
+ CFLAGS="$CFLAGS -g -O0" ./configure --sysconfdir=/etc --localstatedir=/var --with-rootdir= --libexecdir=/usr/lib "$@"
make clean
fi
fi
diff --git a/configure.ac b/configure.ac
index cae2dce36..fa8c8ba6d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -17,7 +17,7 @@
AC_PREREQ(2.63)
-AC_INIT([systemd],[20],[systemd-devel@lists.freedesktop.org])
+AC_INIT([systemd],[24],[systemd-devel@lists.freedesktop.org])
AC_CONFIG_SRCDIR([src/main.c])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_HEADERS([config.h])
@@ -28,6 +28,9 @@ AC_SUBST(PACKAGE_URL, [http://www.freedesktop.org/wiki/Software/systemd])
AC_CANONICAL_HOST
AC_DEFINE_UNQUOTED([CANONICAL_HOST], "$host", [Canonical host string.])
+AS_IF([test "x$host_cpu" = "xmips" || test "x$host_cpu" = "xmipsel" ||
+ test "x$host_cpu" = "xmips64" || test "x$host_cpu" = "xmips64el"],
+ [AC_DEFINE(ARCH_MIPS, [], [Whether on mips arch])])
AM_SILENT_RULES([yes])
@@ -294,30 +297,15 @@ fi
with_distro=`echo ${with_distro} | tr '[[:upper:]]' '[[:lower:]]' `
AC_DEFINE_UNQUOTED(DISTRIBUTION, ["${with_distro}"], [Target Distribution])
-# Default generic names
-SPECIAL_SYSLOG_SERVICE=syslog.service
-
# Location of the init scripts as mandated by LSB
SYSTEM_SYSVINIT_PATH=/etc/init.d
+SYSTEM_SYSVRCND_PATH=/etc/rc.d
M4_DISTRO_FLAG=
case $with_distro in
fedora)
SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d
- SYSTEM_SYSVRCND_PATH=/etc/rc.d
-
- # A little background why we define this special unit
- # names here in configure.ac: SysV services currently
- # cannot have aliases. As long as syslog is started
- # via a SysV init script we hence define this name to
- # the actual SysV name here. Later on when SysV init
- # scripts are not used anymore it is advisable to use
- # the generic name instead and use symlinks in the
- # unit directories to point to the right native unit
- # file.
-
- SPECIAL_SYSLOG_SERVICE=rsyslog.service
AC_DEFINE(TARGET_FEDORA, [], [Target is Fedora/RHEL])
M4_DISTRO_FLAG=-DTARGET_FEDORA=1
have_plymouth=true
@@ -330,61 +318,49 @@ case $with_distro in
;;
debian)
SYSTEM_SYSVRCND_PATH=/etc
- SPECIAL_SYSLOG_SERVICE=rsyslog.service
AC_DEFINE(TARGET_DEBIAN, [], [Target is Debian])
M4_DISTRO_FLAG=-DTARGET_DEBIAN=1
;;
ubuntu)
SYSTEM_SYSVRCND_PATH=/etc
- SPECIAL_SYSLOG_SERVICE=rsyslog.service
AC_DEFINE(TARGET_UBUNTU, [], [Target is Ubuntu])
M4_DISTRO_FLAG=-DTARGET_UBUNTU=1
;;
arch)
SYSTEM_SYSVINIT_PATH=/etc/rc.d
SYSTEM_SYSVRCND_PATH=/etc
- SPECIAL_SYSLOG_SERVICE=syslog-ng.service
AC_DEFINE(TARGET_ARCH, [], [Target is ArchLinux])
M4_DISTRO_FLAG=-DTARGET_ARCH=1
;;
gentoo)
SYSTEM_SYSVINIT_PATH=
SYSTEM_SYSVRCND_PATH=
- SPECIAL_SYSLOG_SERVICE=syslog-ng.service
AC_DEFINE(TARGET_GENTOO, [], [Target is Gentoo])
M4_DISTRO_FLAG=-DTARGET_GENTOO=1
;;
slackware)
SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d
- SYSTEM_SYSVRCND_PATH=/etc/rc.d
AC_DEFINE(TARGET_SLACKWARE, [], [Target is Slackware])
M4_DISTRO_FLAG=-DTARGET_SLACKWARE=1
;;
frugalware)
SYSTEM_SYSVINIT_PATH=/etc/rc.d
- SYSTEM_SYSVRCND_PATH=/etc/rc.d
AC_DEFINE(TARGET_FRUGALWARE, [], [Target is Frugalware])
M4_DISTRO_FLAG=-DTARGET_FRUGALWARE=1
;;
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
;;
mandriva)
SYSTEM_SYSVINIT_PATH=/etc/rc.d/init.d
- SYSTEM_SYSVRCND_PATH=/etc/rc.d
- SPECIAL_SYSLOG_SERVICE=rsyslog.service
AC_DEFINE(TARGET_MANDRIVA, [], [Target is Mandriva])
M4_DISTRO_FLAG=-DTARGET_MANDRIVA=1
have_plymouth=true
;;
other)
- AS_IF([test "x$with_syslog_service" = "x"],
- [AC_MSG_ERROR([With --distro=other, you must pass --with-syslog-service= to configure])])
;;
*)
AC_MSG_ERROR([Your distribution (${with_distro}) is not yet supported, SysV init scripts could not be found! (patches welcome); you can specify --with-distro=other to skip this check])
@@ -403,15 +379,8 @@ AC_ARG_WITH([sysvrcd-path],
[SYSTEM_SYSVRCND_PATH="$withval"],
[])
-AC_ARG_WITH([syslog-service],
- [AS_HELP_STRING([--with-syslog-service=UNIT],
- [Specify the name of the special syslog service @<:@default=based on distro@:>@])],
- [SPECIAL_SYSLOG_SERVICE="$withval"],
- [])
-
AC_SUBST(SYSTEM_SYSVINIT_PATH)
AC_SUBST(SYSTEM_SYSVRCND_PATH)
-AC_SUBST(SPECIAL_SYSLOG_SERVICE)
AC_SUBST(M4_DISTRO_FLAG)
if test "x${SYSTEM_SYSVINIT_PATH}" != "x" -a "x${SYSTEM_SYSVRCND_PATH}" != "x"; then
@@ -442,8 +411,7 @@ AM_CONDITIONAL(TARGET_ALTLINUX, test x"$with_distro" = xaltlinux)
AM_CONDITIONAL(TARGET_MANDRIVA, test x"$with_distro" = xmandriva)
AM_CONDITIONAL(HAVE_PLYMOUTH, test -n "$have_plymouth")
-
-AC_DEFINE_UNQUOTED(SPECIAL_SYSLOG_SERVICE, ["$SPECIAL_SYSLOG_SERVICE"], [Syslog service name])
+AM_CONDITIONAL(HAVE_SYSV_COMPAT, test "$SYSTEM_SYSV_COMPAT" = "yes")
AC_ARG_WITH([dbuspolicydir],
AS_HELP_STRING([--with-dbuspolicydir=DIR], [D-Bus policy directory]),
@@ -498,7 +466,6 @@ echo "
SysV compatibility: ${SYSTEM_SYSV_COMPAT}
SysV init scripts: ${SYSTEM_SYSVINIT_PATH}
SysV rc?.d directories: ${SYSTEM_SYSVRCND_PATH}
- Syslog service: ${SPECIAL_SYSLOG_SERVICE}
Gtk: ${have_gtk}
libcryptsetup: ${have_libcryptsetup}
tcpwrap: ${have_tcpwrap}
diff --git a/man/binfmt.d.xml b/man/binfmt.d.xml
new file mode 100644
index 000000000..64c27554e
--- /dev/null
+++ b/man/binfmt.d.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+ binfmt.d
+ systemd
+
+
+
+ Developer
+ Lennart
+ Poettering
+ lennart@poettering.net
+
+
+
+
+
+ binfmt.d
+ 5
+
+
+
+ binfmt.d
+ Configure additional binary formats at boot
+
+
+
+ /etc/binfmt.d/*.conf
+
+
+
+ Description
+
+ systemd uses
+ /etc/binfmt.d/ to configure
+ additional binary formats to register during boot in
+ the kernel. Each configuration file is named in the
+ style of
+ /etc/binfmt.d/<program>.conf.
+
+
+
+
+
+ Configuration Format
+
+ Each file contains a list of binfmt_misc kernel
+ binary format rules. Consult binfmt_misc.txt
+ for more information on registration of additional
+ binary formats and how to write rules.
+
+ Empty lines and lines beginning with ; and # are
+ ignored. Note that this means you may not use ; and #
+ as delimiter in binary format rules.
+
+ Configuration files are loaded in alphabetical
+ order. To ensure that a specific rule takes precedence
+ over another place it in a file with an alphabetically
+ later name.
+
+
+
+
+ Example
+
+ /etc/binfmt.d/wine.conf example:
+
+ # Start WINE on Windows executables
+:DOSWin:M::MZ::/usr/bin/wine:
+
+
+
+
+ See Also
+
+ systemd1,
+ wine8
+
+
+
+
diff --git a/man/locale.conf.xml b/man/locale.conf.xml
index d36e7bda6..bb7e1130e 100644
--- a/man/locale.conf.xml
+++ b/man/locale.conf.xml
@@ -128,7 +128,7 @@
/etc/locale.conf:
LANG=de_DE.UTF-8
-LC_MESSAGE=C
+LC_MESSAGES=C
diff --git a/man/modules-load.d.xml b/man/modules-load.d.xml
index 77a286055..34076916d 100644
--- a/man/modules-load.d.xml
+++ b/man/modules-load.d.xml
@@ -4,7 +4,7 @@
+
+
+
+
+
+ sysctl.d
+ systemd
+
+
+
+ Developer
+ Lennart
+ Poettering
+ lennart@poettering.net
+
+
+
+
+
+ sysctl.d
+ 5
+
+
+
+ sysctl.d
+ Configure kernel parameters at boot
+
+
+
+ /etc/sysctl.d/*.conf
+
+
+
+ Description
+
+ systemd uses
+ /etc/sysctl.d/ to configure
+ sysctl8
+ kernel parameters to load during boot. Each
+ configuration file is named in the style of
+ /etc/sysctl.d/<program>.conf.
+
+
+
+ Configuration Format
+
+ The configuration files should simply contain a
+ list of variable assignments, separated by
+ newlines. Empty lines and lines whose first
+ non-whitespace character is # or ; are ignored.
+
+ Note that both / and . are accepted as
+ separators in sysctl variable names.
+
+
+
+
+ Example
+
+ /etc/sysctl.d/domain-name.conf example:
+
+ # Set kernel YP domain name
+kernel.domainname=example.com
+
+
+
+
+ See Also
+
+ systemd1,
+ sysctl8,
+ sysctl.conf5
+
+
+
+
diff --git a/man/systemctl.xml b/man/systemctl.xml
index d37a7d95d..e9e3371ba 100644
--- a/man/systemctl.xml
+++ b/man/systemctl.xml
@@ -304,13 +304,11 @@
kill, choose the
mode how to kill the selected
processes. Must be one of
- ,
- or
+ or
to select
whether to kill the entire control
- group, the process group or only the
- selected process itself. If omitted
- defaults to
+ group or only the selected process
+ itself. If omitted defaults to
if
is
set, or
@@ -382,6 +380,27 @@
file that shall be
disabled.
+
+
+
+
+
+ Execute operation
+ remotely. Specifiy a hostname, or
+ username and hostname seperated by @,
+ to connect to. This will use SSH to
+ talk to the remote systemd
+ instance.
+
+
+
+
+
+
+ Acquire privileges via
+ PolicyKit before executing the
+ operation.
+
The following commands are understood:
@@ -447,9 +466,9 @@
Restart one or more
units specified on the command
- line. If the units are not running yet
- the operation will
- fail. Note that for compatibility
+ line if the units are running. Do
+ nothing if units are not running.
+ Note that for compatibility
with Red Hat init scripts
condrestart is
equivalent to this command.
@@ -468,12 +487,13 @@
Reload one or more
units if they support it. If not,
- restart them instead. If the units
- are not running yet the operation
- will fail. Note that for
- compatibility with SysV init scripts
+ restart them instead. Do nothing if
+ the units are not running. Note that
+ for compatibility with SysV init
+ scripts
force-reload is
- equivalent to this command.
+ equivalent to this
+ command.
isolate [NAME]
diff --git a/man/systemd-nspawn.xml b/man/systemd-nspawn.xml
new file mode 100644
index 000000000..667e75c2c
--- /dev/null
+++ b/man/systemd-nspawn.xml
@@ -0,0 +1,190 @@
+
+
+
+
+
+
+
+
+ systemd-nspawn
+ systemd
+
+
+
+ Developer
+ Lennart
+ Poettering
+ lennart@poettering.net
+
+
+
+
+
+ systemd-nspawn
+ 1
+
+
+
+ systemd-nspawn
+ Spawn a namespace container for debugging, testing and building
+
+
+
+
+ systemd-nspawn OPTIONS COMMAND ARGS
+
+
+
+
+ Description
+
+ systemd-nspawn may be used to
+ run a command or OS in a light-weight namespace
+ container. In many ways it is similar to
+ chroot1,
+ but more powerful since it fully virtualizes the file
+ system hierachy, as well as the process tree, the
+ various IPC subsystems and the host and domain
+ name.
+
+ systemd-nspawn limits access
+ to various kernel interfaces in the container to
+ read-only, such as /sys,
+ /proc/sys or
+ /selinux. Network interfaces and
+ the system clock may not be changed from within the
+ container. Device nodes may not be created. The host
+ system cannot be rebooted and kernel modules may not
+ be loaded from within the container.
+
+ Note that even though these security precautions
+ are taken systemd-nspawn is not
+ suitable for secure container setups. Many of the
+ security features may be circumvented and are hence
+ primarily useful to avoid accidental changes to the
+ host system from the container. The intended use of
+ this program is debugging and testing as well as
+ building of packages, distributions and software
+ involved with boot and systems management.
+
+ In contrast to
+ chroot1
+ systemd-nspawn may be used to boot
+ full Linux-based operating systems in a
+ container.
+
+ Use a tool like
+ debootstrap8 or mock1
+ to set up an OS directory tree suitable as file system
+ hierarchy for systemd-nspawn containers.
+
+ Note that systemd-nspawn will
+ mount file systems private to the container to
+ /dev,
+ /run and similar. These will
+ not be visible outside of the container, and their
+ contents will be lost when the container exits.
+
+ Note that running two
+ systemd-nspawn containers from the
+ same directory tree will not make processes in them
+ see each other. The PID namespace seperation of the
+ two containers is complete and the containers will
+ share very few runtime objects except for the
+ underlying file system.
+
+
+
+ Options
+
+ If no arguments are passed the container is set
+ up and a shell started in it, otherwise the passed
+ command and arguments are executed in it. The
+ following options are understood:
+
+
+
+
+
+ Prints a short help
+ text and exits.
+
+
+
+
+
+
+ Directory to use as
+ file system root for the namespace
+ container. If omitted the current
+ directory will be
+ used.
+
+
+
+
+
+
+
+ Example 1
+
+ # debootstrap --arch=amd64 unstable debian-tree/
+# systemd-nspawn -D debian-tree/
+
+ This installs a minimal Debian unstable
+ distribution into the directory
+ debian-tree/ and then spawns a
+ shell in a namespace container in it.
+
+
+
+
+ Example 2
+
+ # mock --init
+# systemd-nspawn -D /var/lib/mock/fedora-rawhide-x86_64/root/ /bin/systemd systemd.log_level=debug
+
+ This installs a minimal Fedora distribution into
+ a subdirectory of /var/lib/mock/
+ and then boots an OS in a namespace container in it,
+ with systemd as init system, configured for debug
+ logging.
+
+
+
+
+ Exit status
+
+ The exit code of the program executed in the
+ container is returned.
+
+
+
+ See Also
+
+ systemd1,
+ chroot1,
+ debootstrap8
+ mock1
+
+
+
+
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index f96d181a9..5b0d2ce37 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -558,7 +558,10 @@
various resource limits for executed
processes. See
setrlimit2
- for details.
+ for details. Use the string
+ infinity to
+ configure no limit on a specific
+ resource.
@@ -597,16 +600,34 @@
- Capabilities=
- Controls the
+ CapabilityBoundingSet=
+
+ Controls which
+ capabilities to include in the
+ capability bounding set for the
+ executed process. See
capabilities7
- set for the executed process. Take a
- capability string as described in
- cap_from_text3.
- Note that this capability set is
- usually influenced by the capabilities
- attached to the executed
- file.
+ for details. Takes a whitespace
+ seperated list of capability names as
+ read by
+ cap_from_name3.
+ Capabilities listed will be included
+ in the bounding set, all others are
+ removed. If the list of capabilities
+ is prefixed with ~ all but the listed
+ capabilities will be included, the
+ effect of this assignment
+ inverted. Note that this option does
+ not actually set or unset any
+ capabilities in the effective,
+ permitted or inherited capability
+ sets. That's what
+ Capabilities= is
+ for. If this option is not used the
+ capability bounding set is not
+ modified on process execution, hence
+ no limits on the capabilities of the
+ process are enforced.
@@ -625,16 +646,21 @@
- CapabilityBoundingSetDrop=
-
+ Capabilities=
Controls the
- capability bounding set drop set for
- the executed process. See
capabilities7
- for details. Takes a list of
- capability names as read by
- cap_from_name3.
-
+ set for the executed process. Take a
+ capability string describing the
+ effective, permitted and inherited
+ capability sets as documented in
+ cap_from_text3.
+ Note that these capability sets are
+ usually influenced by the capabilities
+ attached to the executed file. Due to
+ that
+ CapabilityBoundingSet=
+ is probably the much more useful
+ setting.
diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
index c7045e842..dd66d2ad7 100644
--- a/man/systemd.mount.xml
+++ b/man/systemd.mount.xml
@@ -221,7 +221,6 @@
processes of this mount shall be
killed. One of
,
- ,
,
.
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 7200525c0..7458720a3 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -180,7 +180,7 @@
acquired. Service units with this
option configured implicitly gain
dependencies on the
- dbus.target
+ dbus.socket
unit.
Behaviour of
@@ -558,7 +558,6 @@
processes of this service shall be
killed. One of
,
- ,
,
.
@@ -570,10 +569,6 @@
stop command (as configured with
ExecStop=) is
executed. If set to
- only
- the members of the process group of
- the main service process are
- killed. If set to
only the main
process itself is killed. If set to
no process is
diff --git a/man/systemd.socket.xml b/man/systemd.socket.xml
index 3b7581c54..8cbb512ec 100644
--- a/man/systemd.socket.xml
+++ b/man/systemd.socket.xml
@@ -519,7 +519,6 @@
processes of this socket unit shall be
killed. One of
,
- ,
,
.
diff --git a/man/systemd.special.xml.in b/man/systemd.special.xml.in
index afe882e51..efc4c32be 100644
--- a/man/systemd.special.xml.in
+++ b/man/systemd.special.xml.in
@@ -51,7 +51,6 @@
basic.target,
ctrl-alt-del.target,
dbus.service,
- dbus.target,
default.target,
display-manager.service,
emergency.target,
@@ -69,7 +68,7 @@
remote-fs.target,
rescue.target,
rpcbind.target,
- rtc-set.target,
+ time-sync.target,
runlevel2.target,
runlevel3.target,
runlevel4.target,
@@ -79,7 +78,6 @@
sockets.target,
swap.target,
sysinit.target,
- @SPECIAL_SYSLOG_SERVICE@,
syslog.target,
systemd-initctl.service,
systemd-initctl.socket,
@@ -143,28 +141,6 @@
up systemd will connect to it
and register its
service.
-
- Units should generally
- avoid depending on this unit
- directly and instead refer to
- the
- dbus.target
- unit instead, which pulls this
- one in directly or indirectly
- via socket-based activation.
-
-
-
- dbus.target
-
- Administrators should
- ensure that this target pulls
- in a service unit with the
- name or alias of
- dbus.service
- (or a socket unit that
- activates this
- service).
@@ -180,7 +156,7 @@
The default unit systemd
starts at bootup can be
overriden with the
- systemd.default=
+ systemd.unit=
kernel command line option.
@@ -213,7 +189,7 @@
console. This unit is supposed
to be used with the kernel
command line option
- systemd.default=
+ systemd.unit=
and has otherwise little use.
@@ -423,7 +399,7 @@
- rtc-set.target
+ time-sync.target
systemd automatically
adds dependencies of type
@@ -565,27 +541,6 @@
or b.
-
- @SPECIAL_SYSLOG_SERVICE@
-
- A special unit for the
- syslog daemon. As soon as
- this service is fully started
- up systemd will connect to it
- and use it for logging if it
- has been configured for
- that.
-
- Units should generally
- avoid depending on this unit
- directly and instead refer to
- the
- syslog.target
- unit instead, which pulls this
- one in directly or indirectly
- via socket-based activation.
-
-
syslog.target
@@ -597,15 +552,6 @@
referring to the
$syslog
facility.
-
- Administrators should
- ensure that this target pulls
- in a service unit with the
- name or alias of
- @SPECIAL_SYSLOG_SERVICE@
- (or a socket unit that
- activates this
- service).
diff --git a/man/systemd.swap.xml b/man/systemd.swap.xml
index 45f8f40ae..3277ddbd4 100644
--- a/man/systemd.swap.xml
+++ b/man/systemd.swap.xml
@@ -68,13 +68,23 @@
specific configuration options are configured in the
[Swap] section.
- Swap units must be named after the devices they
- control. Example: the swap device
+ Swap units must be named after the devices
+ (resp. files) they control. Example: the swap device
/dev/sda5 must be configured in a
unit file dev-sda5.swap. For
details about the escaping logic used to convert a
file system path to a unit name see
systemd.unit5.
+
+ All swap units automatically get the appropriate
+ dependencies on the devices (resp. on the mount points
+ of the files) they are actived from.
+
+ Swap units with
+ DefaultDependencies= enabled
+ implicitly acquire a conflicting dependency to
+ umount.target so that they are
+ deactivated at shutdown.
@@ -88,6 +98,13 @@
If a swap device or file is configured in both
/etc/fstab and a unit file the
configuration in the latter takes precedence.
+
+ Unless the option is set
+ for them all swap units configured in
+ /etc/fstab are also added as
+ requirements to swap.target, so
+ that they are waited for and activated during
+ boot.
@@ -149,7 +166,7 @@
a time span value such as "5min
20s". Pass 0 to disable the timeout
logic. Defaults to
- 60s.
+ 3min.
@@ -158,7 +175,6 @@
processes of this swap shall be
killed. One of
,
- ,
,
.
diff --git a/man/systemd.target.xml b/man/systemd.target.xml
index 5c2642759..6b1dbfbde 100644
--- a/man/systemd.target.xml
+++ b/man/systemd.target.xml
@@ -83,14 +83,15 @@
systemd.special7
for details).
- Unless
- DefaultDependencies= is set to
- , target units will
- implicitly complement all configured dependencies of type
- Wants=,
+ Unless DefaultDependencies=
+ is set to , target units will
+ implicitly complement all configured dependencies of
+ type Wants=,
Requires=,
RequiresOverridable= with
- dependencies of type After=.
+ dependencies of type After= if the
+ units in question also have
+ DefaultDependencies=true.
diff --git a/man/systemd.unit.xml b/man/systemd.unit.xml
index 54903fb52..5460ebeb2 100644
--- a/man/systemd.unit.xml
+++ b/man/systemd.unit.xml
@@ -139,7 +139,10 @@
with the enable command of the
systemctl1
tool which reads information from the [Install]
- section of unit files. (See below.)
+ section of unit files. (See below.) A similar
+ functionality exists for Requires=
+ type dependencies as well, the directory suffix is
+ .requires/ in this case.
Note that while systemd offers a flexible
dependency system between units it is recommended to
@@ -216,21 +219,6 @@
dependent on the type of unit:
-
- Names=
-
- Additional names for
- this unit. The names listed here must
- have the same suffix (i.e. type) as
- the unit file name. This option may be
- specified more than once, in which
- case all listed names are used. Note
- that this option is different from the
- Alias= option from
- the [Install] section mentioned
- below. See below for details.
-
-
Description=
@@ -573,9 +561,11 @@
ConditionPathExists=
+ ConditionPathIsDirectory=
ConditionDirectoryNotEmpty=
ConditionKernelCommandLine=
ConditionVirtualization=
+ ConditionSecurity=
ConditionNull=
Before starting a unit
@@ -596,10 +586,15 @@
is prefixed with an exclamation mark
(!), the test is negated, and the unit
only started if the path does not
- exist. ConditionDirectoryNotEmpty=
+ exist. ConditionPathIsDirectory=
is similar to
ConditionPathExists=
- but verifies whether a certain path is
+ but verifies whether a certain path
+ exists and is a directory.
+ ConditionDirectoryNotEmpty=
+ is similar to
+ ConditionPathExists=
+ but verifies whether a certain path
exists and is a non-empty
directory. Similarly
ConditionKernelCommandLine=
@@ -630,9 +625,17 @@
microsoft,
oracle,
xen,
+ pidns,
openvz to test
against a specific implementation. The
test may be negated by prepending an
+ exclamation mark.
+ ConditionSecurity=
+ may be used to check whether the given security
+ module is enabled on the system.
+ Currently the only recognized value is
+ selinux.
+ The test may be negated by prepending an
exclamation mark. Finally,
ConditionNull= may
be used to add a constant condition
@@ -657,6 +660,35 @@
pipe symbol must be passed first, the
exclamation second.
+
+
+ Names=
+
+ Additional names for
+ this unit. The names listed here must
+ have the same suffix (i.e. type) as
+ the unit file name. This option may be
+ specified more than once, in which
+ case all listed names are used. Note
+ that this option is different from the
+ Alias= option from
+ the [Install] section mentioned
+ below. See below for details. Note
+ that in almost all cases this option
+ is not what you want. A symlink alias
+ in the file system is generally
+ preferable since it can be used as
+ lookup key. If a unit with a symlinked
+ alias name is not loaded and needs to
+ be it is easily found via the
+ symlink. However, if a unit with an
+ alias name configured with this
+ setting is not loaded it will not be
+ discovered. This settings' only use is
+ in conjunction with service
+ instances.
+
+
Unit file may include a [Install] section, which
diff --git a/man/systemd.xml b/man/systemd.xml
index 2c42a0291..a7dc4530e 100644
--- a/man/systemd.xml
+++ b/man/systemd.xml
@@ -269,7 +269,7 @@
,
,
,
- . If the
+ . If the
argument is omitted it defaults to
.
@@ -1024,20 +1024,19 @@
- @/org/freedesktop/systemd1/notify
+ /run/systemd/notify
Daemon status
- notification socket. This is an AF_UNIX
- datagram socket in the Linux abstract
- namespace, and is used to implement
- the daemon notification logic as
- implemented by
+ notification socket. This is an
+ AF_UNIX datagram socket and is used to
+ implement the daemon notification
+ logic as implemented by
sd_notify3.
- @/org/freedesktop/systemd1/logger
+ /run/systemd/logger
Used internally by the
systemd-logger.service
@@ -1045,32 +1044,30 @@
of spawned processes to
syslog3
or the kernel log buffer. This is an
- AF_UNIX stream socket in the Linux
- abstract namespace.
+ AF_UNIX stream
+ socket.
- @/org/freedesktop/systemd1/shutdown
+ /run/systemd/shutdownd
Used internally by the
shutdown8
tool to implement delayed
shutdowns. This is an AF_UNIX datagram
- socket in the Linux abstract
- namespace.
+ socket.
- @/org/freedesktop/systemd1/private
+ /run/systemd/private
Used internally as
communication channel between
systemctl1
and the systemd process. This is an
- AF_UNIX stream socket in the Linux
- abstract namespace. This interface is
- private to systemd and should not be
- used in external
+ AF_UNIX stream socket. This interface
+ is private to systemd and should not
+ be used in external
projects.
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index 868b57e93..8568fcd59 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -58,7 +58,7 @@
/etc/tmpfiles.d/ to describe the
creation, cleaning and removal of volatile and
temporary files and directories which usually reside
- in directories such as /var/run
+ in directories such as /run
or /tmp. Each configuration file
is named in the style of
/etc/tmpfiles.d/<program>.conf.
@@ -72,7 +72,7 @@
fields:
Type Path Mode UID GID Age
-d /var/run/user 0755 root root 10d
+d /run/user 0755 root root 10d
Type
diff --git a/src/.gitignore b/src/.gitignore
index 9c01ae1fd..4c7d3c882 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,3 +1,4 @@
+org.freedesktop.systemd1.policy
gnome-ask-password-agent.c
systemd-interfaces.c
systemadm.c
diff --git a/src/99-systemd.rules b/src/99-systemd.rules
index 4fba6d4d0..186ef45f4 100644
--- a/src/99-systemd.rules
+++ b/src/99-systemd.rules
@@ -8,9 +8,7 @@
ACTION!="add|change", GOTO="systemd_end"
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=="tty", KERNEL=="tty[a-zA-Z]*|hvc*", 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"
diff --git a/src/ask-password-api.c b/src/ask-password-api.c
index af1b611f2..da967ab7a 100644
--- a/src/ask-password-api.c
+++ b/src/ask-password-api.c
@@ -18,7 +18,7 @@
You should have received a copy of the GNU General Public License
along with systemd; If not, see .
***/
-
+#include
#include
#include
#include
@@ -36,6 +36,18 @@
#include "ask-password-api.h"
+static void backspace_chars(int ttyfd, size_t p) {
+
+ if (ttyfd < 0)
+ return;
+
+ while (p > 0) {
+ p--;
+
+ loop_write(ttyfd, "\b \b", 3, false);
+ }
+}
+
int ask_password_tty(
const char *message,
usec_t until,
@@ -48,6 +60,8 @@ int ask_password_tty(
int r, ttyfd = -1, notify = -1;
struct pollfd pollfd[2];
bool reset_tty = false;
+ bool silent_mode = false;
+ bool dirty = false;
enum {
POLL_TTY,
POLL_INOTIFY
@@ -155,27 +169,50 @@ int ask_password_tty(
if (c == '\n')
break;
- else if (c == 21) {
+ else if (c == 21) { /* C-u */
- while (p > 0) {
- p--;
-
- if (ttyfd >= 0)
- loop_write(ttyfd, "\b \b", 3, false);
- }
+ if (!silent_mode)
+ backspace_chars(ttyfd, p);
+ p = 0;
} else if (c == '\b' || c == 127) {
- if (p > 0) {
- p--;
+ if (p > 0) {
+
+ if (!silent_mode)
+ backspace_chars(ttyfd, 1);
+
+ p--;
+ } else if (!dirty && !silent_mode) {
+
+ silent_mode = true;
+
+ /* There are two ways to enter silent
+ * mode. Either by pressing backspace
+ * as first key (and only as first key),
+ * or ... */
if (ttyfd >= 0)
- loop_write(ttyfd, "\b \b", 3, false);
- }
+ loop_write(ttyfd, "(no echo) ", 10, false);
+
+ } else if (ttyfd >= 0)
+ loop_write(ttyfd, "\a", 1, false);
+
+ } else if (c == '\t' && !silent_mode) {
+
+ backspace_chars(ttyfd, p);
+ silent_mode = true;
+
+ /* ... or by pressing TAB at any time. */
+
+ if (ttyfd >= 0)
+ loop_write(ttyfd, "(no echo) ", 10, false);
} else {
passphrase[p++] = c;
- if (ttyfd >= 0)
+ if (!silent_mode && ttyfd >= 0)
loop_write(ttyfd, "*", 1, false);
+
+ dirty = true;
}
}
@@ -223,7 +260,7 @@ static int create_socket(char **name) {
zero(sa);
sa.un.sun_family = AF_UNIX;
- snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/dev/.systemd/ask-password/sck.%llu", random_ull());
+ snprintf(sa.un.sun_path, sizeof(sa.un.sun_path)-1, "/run/systemd/ask-password/sck.%llu", random_ull());
if (bind(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + strlen(sa.un.sun_path)) < 0) {
r = -errno;
@@ -265,18 +302,22 @@ int ask_password_agent(
_FD_MAX
};
- char temp[] = "/dev/.systemd/ask-password/tmp.XXXXXX";
+ char temp[] = "/run/systemd/ask-password/tmp.XXXXXX";
char final[sizeof(temp)] = "";
int fd = -1, r;
FILE *f = NULL;
char *socket_name = NULL;
int socket_fd = -1, signal_fd = -1;
- sigset_t mask;
+ sigset_t mask, oldmask;
struct pollfd pollfd[_FD_MAX];
assert(_passphrases);
- mkdir_p("/dev/.systemd/ask-password", 0755);
+ assert_se(sigemptyset(&mask) == 0);
+ sigset_add_many(&mask, SIGINT, SIGTERM, -1);
+ assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
+
+ mkdir_p("/run/systemd/ask-password", 0755);
if ((fd = mkostemp(temp, O_CLOEXEC|O_CREAT|O_WRONLY)) < 0) {
log_error("Failed to create password file: %m");
@@ -294,10 +335,6 @@ int ask_password_agent(
fd = -1;
- assert_se(sigemptyset(&mask) == 0);
- sigset_add_many(&mask, SIGINT, SIGTERM, -1);
- assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
-
if ((signal_fd = signalfd(-1, &mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) {
log_error("signalfd(): %m");
r = -errno;
@@ -493,6 +530,8 @@ finish:
if (final[0])
unlink(final);
+ assert_se(sigprocmask(SIG_SETMASK, &oldmask, NULL) == 0);
+
return r;
}
diff --git a/src/binfmt.c b/src/binfmt.c
new file mode 100644
index 000000000..6ebd212ee
--- /dev/null
+++ b/src/binfmt.c
@@ -0,0 +1,187 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2010 Lennart Poettering
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with systemd; If not, see .
+***/
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "log.h"
+#include "util.h"
+
+static int delete_rule(const char *rule) {
+ char *x, *fn, *e;
+ int r;
+
+ assert(rule[0]);
+
+ if (!(x = strdup(rule)))
+ return -ENOMEM;
+
+ e = strchrnul(x+1, x[0]);
+ *e = 0;
+
+ asprintf(&fn, "/proc/sys/fs/binfmt_misc/%s", x+1);
+ free(x);
+
+ if (!fn)
+ return -ENOMEM;
+
+ r = write_one_line_file(fn, "-1");
+ free(fn);
+
+ return r;
+}
+
+static int apply_rule(const char *rule) {
+ int r;
+
+ delete_rule(rule);
+
+ if ((r = write_one_line_file("/proc/sys/fs/binfmt_misc/register", rule)) < 0) {
+ log_error("Failed to add binary format: %s", strerror(-r));
+ return r;
+ }
+
+ return 0;
+}
+
+static int apply_file(const char *path, bool ignore_enoent) {
+ FILE *f;
+ int r = 0;
+
+ assert(path);
+
+ if (!(f = fopen(path, "re"))) {
+ if (ignore_enoent && errno == ENOENT)
+ return 0;
+
+ log_error("Failed to open file '%s', ignoring: %m", path);
+ return -errno;
+ }
+
+ while (!feof(f)) {
+ char l[LINE_MAX], *p;
+ int k;
+
+ if (!fgets(l, sizeof(l), f)) {
+ if (feof(f))
+ break;
+
+ log_error("Failed to read file '%s', ignoring: %m", path);
+ r = -errno;
+ goto finish;
+ }
+
+ p = strstrip(l);
+
+ if (!*p)
+ continue;
+
+ if (strchr(COMMENTS, *p))
+ continue;
+
+ if ((k = apply_rule(p)) < 0 && r == 0)
+ r = k;
+ }
+
+finish:
+ fclose(f);
+
+ return r;
+}
+
+static int scandir_filter(const struct dirent *d) {
+ assert(d);
+
+ if (ignore_file(d->d_name))
+ return 0;
+
+ if (d->d_type != DT_REG &&
+ d->d_type != DT_LNK &&
+ d->d_type != DT_UNKNOWN)
+ return 0;
+
+ return endswith(d->d_name, ".conf");
+}
+
+static int apply_tree(const char *path) {
+ struct dirent **de = NULL;
+ int n, i, r = 0;
+
+ if ((n = scandir(path, &de, scandir_filter, alphasort)) < 0) {
+
+ if (errno == ENOENT)
+ return 0;
+
+ log_error("Failed to enumerate %s files: %m", path);
+ return -errno;
+ }
+
+ for (i = 0; i < n; i++) {
+ char *fn;
+ int k;
+
+ k = asprintf(&fn, "%s/%s", path, de[i]->d_name);
+ free(de[i]);
+
+ if (k < 0) {
+ log_error("Failed to allocate file name.");
+
+ if (r == 0)
+ r = -ENOMEM;
+ continue;
+ }
+
+ if ((k = apply_file(fn, true)) < 0 && r == 0)
+ r = k;
+ }
+
+ free(de);
+
+ return r;
+}
+
+int main(int argc, char *argv[]) {
+ int r = 0;
+
+ if (argc > 2) {
+ log_error("This program expects one or no arguments.");
+ return EXIT_FAILURE;
+ }
+
+ log_set_target(LOG_TARGET_AUTO);
+ log_parse_environment();
+ log_open();
+
+ if (argc > 1)
+ r = apply_file(argv[1], false);
+ else {
+ /* Flush out all rules */
+ write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1");
+
+ r = apply_tree("/etc/binfmt.d");
+ }
+
+ return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
diff --git a/src/bridge.c b/src/bridge.c
new file mode 100644
index 000000000..878856cfd
--- /dev/null
+++ b/src/bridge.c
@@ -0,0 +1,367 @@
+/*-*- 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 .
+***/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "log.h"
+#include "util.h"
+#include "socket-util.h"
+
+#define BUFFER_SIZE (64*1024)
+#define EXTRA_SIZE 16
+
+static bool initial_nul = false;
+static bool auth_over = false;
+
+static void format_uid(char *buf, size_t l) {
+ char text[20 + 1]; /* enough space for a 64bit integer plus NUL */
+ unsigned j;
+
+ assert(l > 0);
+
+ snprintf(text, sizeof(text)-1, "%llu", (unsigned long long) geteuid());
+ text[sizeof(text)-1] = 0;
+
+ memset(buf, 0, l);
+
+ for (j = 0; text[j] && j*2+2 < l; j++) {
+ buf[j*2] = hexchar(text[j] >> 4);
+ buf[j*2+1] = hexchar(text[j] & 0xF);
+ }
+
+ buf[j*2] = 0;
+}
+
+static size_t patch_in_line(char *line, size_t l, size_t left) {
+ size_t r;
+
+ if (line[0] == 0 && !initial_nul) {
+ initial_nul = true;
+ line += 1;
+ l -= 1;
+ r = 1;
+ } else
+ r = 0;
+
+ if (l == 5 && strncmp(line, "BEGIN", 5) == 0) {
+ r += l;
+ auth_over = true;
+
+ } else if (l == 17 && strncmp(line, "NEGOTIATE_UNIX_FD", 17) == 0) {
+ memmove(line + 13, line + 17, left);
+ memcpy(line, "NEGOTIATE_NOP", 13);
+ r += 13;
+
+ } else if (l >= 14 && strncmp(line, "AUTH EXTERNAL ", 14) == 0) {
+ char uid[20*2 + 1];
+ size_t len;
+
+ format_uid(uid, sizeof(uid));
+ len = strlen(uid);
+ assert(len <= EXTRA_SIZE);
+
+ memmove(line + 14 + len, line + l, left);
+ memcpy(line + 14, uid, len);
+
+ r += 14 + len;
+ } else
+ r += l;
+
+ return r;
+}
+
+static size_t patch_in_buffer(char* in_buffer, size_t *in_buffer_full) {
+ size_t i, good = 0;
+
+ if (*in_buffer_full <= 0)
+ return *in_buffer_full;
+
+ /* If authentication is done, we don't touch anything anymore */
+ if (auth_over)
+ return *in_buffer_full;
+
+ if (*in_buffer_full < 2)
+ return 0;
+
+ for (i = 0; i <= *in_buffer_full - 2; i ++) {
+
+ /* Fully lines can be send on */
+ if (in_buffer[i] == '\r' && in_buffer[i+1] == '\n') {
+ if (i > good) {
+ size_t old_length, new_length;
+
+ old_length = i - good;
+ new_length = patch_in_line(in_buffer+good, old_length, *in_buffer_full - i);
+ *in_buffer_full = *in_buffer_full + new_length - old_length;
+
+ good += new_length + 2;
+
+ } else
+ good = i+2;
+ }
+
+ if (auth_over)
+ break;
+ }
+
+ return good;
+}
+
+int main(int argc, char *argv[]) {
+ int r = EXIT_FAILURE, fd = -1, ep = -1;
+ union sockaddr_union sa;
+ char in_buffer[BUFFER_SIZE+EXTRA_SIZE], out_buffer[BUFFER_SIZE+EXTRA_SIZE];
+ size_t in_buffer_full = 0, out_buffer_full = 0;
+ struct epoll_event stdin_ev, stdout_ev, fd_ev;
+ bool stdin_readable = false, stdout_writable = false, fd_readable = false, fd_writable = false;
+ bool stdin_rhup = false, stdout_whup = false, fd_rhup = false, fd_whup = false;
+
+ if (argc > 1) {
+ log_error("This program takes no argument.");
+ return EXIT_FAILURE;
+ }
+
+ log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+ log_parse_environment();
+ log_open();
+
+ if ((fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0)) < 0) {
+ log_error("Failed to create socket: %s", strerror(errno));
+ goto finish;
+ }
+
+ zero(sa);
+ sa.un.sun_family = AF_UNIX;
+ strncpy(sa.un.sun_path, "/run/dbus/system_bus_socket", sizeof(sa.un.sun_path));
+
+ 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");
+ goto finish;
+ }
+
+ fd_nonblock(STDIN_FILENO, 1);
+ fd_nonblock(STDOUT_FILENO, 1);
+
+ if ((ep = epoll_create1(EPOLL_CLOEXEC)) < 0) {
+ log_error("Failed to create epoll: %m");
+ goto finish;
+ }
+
+ zero(stdin_ev);
+ stdin_ev.events = EPOLLIN|EPOLLET;
+ stdin_ev.data.fd = STDIN_FILENO;
+
+ zero(stdout_ev);
+ stdout_ev.events = EPOLLOUT|EPOLLET;
+ stdout_ev.data.fd = STDOUT_FILENO;
+
+ zero(fd_ev);
+ fd_ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
+ fd_ev.data.fd = fd;
+
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0 ||
+ epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0 ||
+ epoll_ctl(ep, EPOLL_CTL_ADD, fd, &fd_ev) < 0) {
+ log_error("Failed to regiser fds in epoll: %m");
+ goto finish;
+ }
+
+ do {
+ struct epoll_event ev[16];
+ ssize_t k;
+ int i, nfds;
+
+ if ((nfds = epoll_wait(ep, ev, ELEMENTSOF(ev), -1)) < 0) {
+
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+
+ log_error("epoll_wait(): %m");
+ goto finish;
+ }
+
+ assert(nfds >= 1);
+
+ for (i = 0; i < nfds; i++) {
+ if (ev[i].data.fd == STDIN_FILENO) {
+
+ if (!stdin_rhup && (ev[i].events & (EPOLLHUP|EPOLLIN)))
+ stdin_readable = true;
+
+ } else if (ev[i].data.fd == STDOUT_FILENO) {
+
+ if (ev[i].events & EPOLLHUP) {
+ stdout_writable = false;
+ stdout_whup = true;
+ }
+
+ if (!stdout_whup && (ev[i].events & EPOLLOUT))
+ stdout_writable = true;
+
+ } else if (ev[i].data.fd == fd) {
+
+ if (ev[i].events & EPOLLHUP) {
+ fd_writable = false;
+ fd_whup = true;
+ }
+
+ if (!fd_rhup && (ev[i].events & (EPOLLHUP|EPOLLIN)))
+ fd_readable = true;
+
+ if (!fd_whup && (ev[i].events & EPOLLOUT))
+ fd_writable = true;
+ }
+ }
+
+ while ((stdin_readable && in_buffer_full <= 0) ||
+ (fd_writable && patch_in_buffer(in_buffer, &in_buffer_full) > 0) ||
+ (fd_readable && out_buffer_full <= 0) ||
+ (stdout_writable && out_buffer_full > 0)) {
+
+ size_t in_buffer_good = 0;
+
+ if (stdin_readable && in_buffer_full < BUFFER_SIZE) {
+
+ if ((k = read(STDIN_FILENO, in_buffer + in_buffer_full, BUFFER_SIZE - in_buffer_full)) < 0) {
+
+ if (errno == EAGAIN)
+ stdin_readable = false;
+ else if (errno == EPIPE || errno == ECONNRESET)
+ k = 0;
+ else {
+ log_error("read(): %m");
+ goto finish;
+ }
+ } else
+ in_buffer_full += (size_t) k;
+
+ if (k == 0) {
+ stdin_rhup = true;
+ stdin_readable = false;
+ shutdown(STDIN_FILENO, SHUT_RD);
+ close_nointr_nofail(STDIN_FILENO);
+ }
+ }
+
+ in_buffer_good = patch_in_buffer(in_buffer, &in_buffer_full);
+
+ if (fd_writable && in_buffer_good > 0) {
+
+ if ((k = write(fd, in_buffer, in_buffer_good)) < 0) {
+
+ if (errno == EAGAIN)
+ fd_writable = false;
+ else if (errno == EPIPE || errno == ECONNRESET) {
+ fd_whup = true;
+ fd_writable = false;
+ shutdown(fd, SHUT_WR);
+ } else {
+ log_error("write(): %m");
+ goto finish;
+ }
+
+ } else {
+ assert(in_buffer_full >= (size_t) k);
+ memmove(in_buffer, in_buffer + k, in_buffer_full - k);
+ in_buffer_full -= k;
+ }
+ }
+
+ if (fd_readable && out_buffer_full < BUFFER_SIZE) {
+
+ if ((k = read(fd, out_buffer + out_buffer_full, BUFFER_SIZE - out_buffer_full)) < 0) {
+
+ if (errno == EAGAIN)
+ fd_readable = false;
+ else if (errno == EPIPE || errno == ECONNRESET)
+ k = 0;
+ else {
+ log_error("read(): %m");
+ goto finish;
+ }
+ } else
+ out_buffer_full += (size_t) k;
+
+ if (k == 0) {
+ fd_rhup = true;
+ fd_readable = false;
+ shutdown(fd, SHUT_RD);
+ }
+ }
+
+ if (stdout_writable && out_buffer_full > 0) {
+
+ if ((k = write(STDOUT_FILENO, out_buffer, out_buffer_full)) < 0) {
+
+ if (errno == EAGAIN)
+ stdout_writable = false;
+ else if (errno == EPIPE || errno == ECONNRESET) {
+ stdout_whup = true;
+ stdout_writable = false;
+ shutdown(STDOUT_FILENO, SHUT_WR);
+ close_nointr(STDOUT_FILENO);
+ } else {
+ log_error("write(): %m");
+ goto finish;
+ }
+
+ } else {
+ assert(out_buffer_full >= (size_t) k);
+ memmove(out_buffer, out_buffer + k, out_buffer_full - k);
+ out_buffer_full -= k;
+ }
+ }
+ }
+
+ if (stdin_rhup && in_buffer_full <= 0 && !fd_whup) {
+ fd_whup = true;
+ fd_writable = false;
+ shutdown(fd, SHUT_WR);
+ }
+
+ if (fd_rhup && out_buffer_full <= 0 && !stdout_whup) {
+ stdout_whup = true;
+ stdout_writable = false;
+ shutdown(STDOUT_FILENO, SHUT_WR);
+ close_nointr(STDOUT_FILENO);
+ }
+
+ } while (!stdout_whup || !fd_whup);
+
+ r = EXIT_SUCCESS;
+
+finish:
+ if (fd >= 0)
+ close_nointr_nofail(fd);
+
+ if (ep >= 0)
+ close_nointr_nofail(ep);
+
+ return r;
+}
diff --git a/src/cgls.c b/src/cgls.c
index 93617ddc2..2bde743ac 100644
--- a/src/cgls.c
+++ b/src/cgls.c
@@ -106,8 +106,22 @@ int main(int argc, char *argv[]) {
if (path_startswith(p, "/sys/fs/cgroup")) {
printf("Working Directory %s:\n", p);
r = show_cgroup_by_path(p, NULL, 0);
- } else
- r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, "/", NULL, 0);
+ } else {
+ char *root = NULL;
+ const char *t = NULL;
+
+ if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root)) < 0)
+ t = "/";
+ else {
+ if (endswith(root, "/system"))
+ root[strlen(root)-7] = 0;
+
+ t = root[0] ? root : "/";
+ }
+
+ r = show_cgroup(SYSTEMD_CGROUP_CONTROLLER, t, NULL, 0);
+ free(root);
+ }
free(p);
}
diff --git a/src/cgroup-util.c b/src/cgroup-util.c
index 055c90610..090573bd3 100644
--- a/src/cgroup-util.c
+++ b/src/cgroup-util.c
@@ -484,6 +484,7 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
const char *p;
char *mp;
int r;
+ static __thread bool good = false;
assert(controller);
assert(fs);
@@ -504,9 +505,14 @@ int cg_get_path(const char *controller, const char *path, const char *suffix, ch
if (asprintf(&mp, "/sys/fs/cgroup/%s", p) < 0)
return -ENOMEM;
- if ((r = path_is_mount_point(mp)) <= 0) {
- free(mp);
- return r < 0 ? r : -ENOENT;
+ if (!good) {
+ if ((r = path_is_mount_point(mp)) <= 0) {
+ free(mp);
+ return r < 0 ? r : -ENOENT;
+ }
+
+ /* Cache this to save a few stat()s */
+ good = true;
}
if (path && suffix)
@@ -967,3 +973,31 @@ int cg_fix_path(const char *path, char **result) {
return r;
}
+
+int cg_get_user_path(char **path) {
+ char *root, *p;
+
+ assert(path);
+
+ /* Figure out the place to put user cgroups below. We use the
+ * same as PID 1 has but with the "/system" suffix replaced by
+ * "/user" */
+
+ if (cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 1, &root) < 0)
+ p = strdup("/user");
+ else {
+ if (endswith(root, "/system"))
+ root[strlen(root) - 7] = 0;
+ else if (streq(root, "/"))
+ root[0] = 0;
+
+ p = strappend(root, "/user");
+ free(root);
+ }
+
+ if (!p)
+ return -ENOMEM;
+
+ *path = p;
+ return 0;
+}
diff --git a/src/cgroup-util.h b/src/cgroup-util.h
index 73df9697e..d142af34b 100644
--- a/src/cgroup-util.h
+++ b/src/cgroup-util.h
@@ -27,8 +27,7 @@
#include
#include "set.h"
-
-#define SYSTEMD_CGROUP_CONTROLLER "name=systemd"
+#include "def.h"
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f);
int cg_enumerate_tasks(const char *controller, const char *path, FILE **_f);
@@ -68,4 +67,6 @@ int cg_install_release_agent(const char *controller, const char *agent);
int cg_is_empty(const char *controller, const char *path, bool ignore_self);
int cg_is_empty_recursive(const char *controller, const char *path, bool ignore_self);
+int cg_get_user_path(char **path);
+
#endif
diff --git a/src/cgroup.c b/src/cgroup.c
index b75fe0bee..5864858dd 100644
--- a/src/cgroup.c
+++ b/src/cgroup.c
@@ -226,8 +226,10 @@ int manager_setup_cgroup(Manager *m) {
assert(m);
/* 1. Determine hierarchy */
- if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, ¤t)) < 0)
+ if ((r = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, ¤t)) < 0) {
+ log_error("Cannot determine cgroup we are running in: %s", strerror(-r));
goto finish;
+ }
if (m->running_as == MANAGER_SYSTEM)
strcpy(suffix, "/system");
@@ -246,14 +248,17 @@ int manager_setup_cgroup(Manager *m) {
/* We need a new root cgroup */
m->cgroup_hierarchy = NULL;
if (asprintf(&m->cgroup_hierarchy, "%s%s", streq(current, "/") ? "" : current, suffix) < 0) {
+ log_error("Out of memory");
r = -ENOMEM;
goto finish;
}
}
/* 2. Show data */
- if ((r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path)) < 0)
+ if ((r = cg_get_path(SYSTEMD_CGROUP_CONTROLLER, m->cgroup_hierarchy, NULL, &path)) < 0) {
+ log_error("Cannot find cgroup mount point: %s", strerror(-r));
goto finish;
+ }
log_debug("Using cgroup controller " SYSTEMD_CGROUP_CONTROLLER ". File system hierarchy is at %s.", path);
@@ -276,6 +281,7 @@ int manager_setup_cgroup(Manager *m) {
close_nointr_nofail(m->pin_cgroupfs_fd);
if ((m->pin_cgroupfs_fd = open(path, O_RDONLY|O_CLOEXEC|O_DIRECTORY|O_NOCTTY|O_NONBLOCK)) < 0) {
+ log_error("Failed to open pin file: %m");
r = -errno;
goto finish;
}
diff --git a/src/cgroups-agent.c b/src/cgroups-agent.c
index 7b4fca245..e0868b613 100644
--- a/src/cgroups-agent.c
+++ b/src/cgroups-agent.c
@@ -49,10 +49,19 @@ int main(int argc, char *argv[]) {
* 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))) {
- log_error("Failed to get D-Bus connection: %s", bus_error_message(&error));
- goto finish;
+ if (!(bus = dbus_connection_open_private("unix:path=/run/systemd/private", &error))) {
+#ifndef LEGACY
+ dbus_error_free(&error);
+
+ /* Retry with the pre v21 socket name, to ease upgrades */
+ if (!(bus = dbus_connection_open_private("unix:abstract=/org/freedesktop/systemd1/private", &error))) {
+#endif
+ log_error("Failed to get D-Bus connection: %s", bus_error_message(&error));
+ goto finish;
+ }
+#ifndef LEGACY
}
+#endif
if (bus_check_peercred(bus) < 0) {
log_error("Bus owner not root.");
diff --git a/src/condition.c b/src/condition.c
index 1d6cf12ad..a520e4343 100644
--- a/src/condition.c
+++ b/src/condition.c
@@ -24,13 +24,19 @@
#include
#include
+#ifdef HAVE_SELINUX
+#include
+#endif
+
#include "util.h"
#include "condition.h"
Condition* condition_new(ConditionType type, const char *parameter, bool trigger, bool negate) {
Condition *c;
- c = new0(Condition, 1);
+ if (!(c = new0(Condition, 1)))
+ return NULL;
+
c->type = type;
c->trigger = trigger;
c->negate = negate;
@@ -67,6 +73,9 @@ static bool test_kernel_command_line(const char *parameter) {
assert(parameter);
+ if (detect_virtualization(NULL) > 0)
+ return false;
+
if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
return false;
@@ -123,6 +132,14 @@ static bool test_virtualization(const char *parameter) {
return streq(parameter, id);
}
+static bool test_security(const char *parameter) {
+#ifdef HAVE_SELINUX
+ if (streq(parameter, "selinux"))
+ return is_selinux_enabled() > 0;
+#endif
+ return false;
+}
+
bool condition_test(Condition *c) {
assert(c);
@@ -131,6 +148,14 @@ bool condition_test(Condition *c) {
case CONDITION_PATH_EXISTS:
return (access(c->parameter, F_OK) >= 0) == !c->negate;
+ case CONDITION_PATH_IS_DIRECTORY: {
+ struct stat st;
+
+ if (lstat(c->parameter, &st) < 0)
+ return !c->negate;
+ return S_ISDIR(st.st_mode) == !c->negate;
+ }
+
case CONDITION_DIRECTORY_NOT_EMPTY: {
int k;
@@ -144,6 +169,9 @@ bool condition_test(Condition *c) {
case CONDITION_VIRTUALIZATION:
return test_virtualization(c->parameter) == !c->negate;
+ case CONDITION_SECURITY:
+ return test_security(c->parameter) == !c->negate;
+
case CONDITION_NULL:
return !c->negate;
@@ -186,7 +214,7 @@ void condition_dump(Condition *c, FILE *f, const char *prefix) {
prefix = "";
fprintf(f,
- "%s%s: %s%s%s\n",
+ "%s\t%s: %s%s%s\n",
prefix,
condition_type_to_string(c->type),
c->trigger ? "|" : "",
@@ -202,8 +230,12 @@ void condition_dump_list(Condition *first, FILE *f, const char *prefix) {
}
static const char* const condition_type_table[_CONDITION_TYPE_MAX] = {
- [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
[CONDITION_PATH_EXISTS] = "ConditionPathExists",
+ [CONDITION_PATH_IS_DIRECTORY] = "ConditionPathIsDirectory",
+ [CONDITION_DIRECTORY_NOT_EMPTY] = "ConditionDirectoryNotEmpty",
+ [CONDITION_KERNEL_COMMAND_LINE] = "ConditionKernelCommandLine",
+ [CONDITION_VIRTUALIZATION] = "ConditionVirtualization",
+ [CONDITION_SECURITY] = "ConditionSecurity",
[CONDITION_NULL] = "ConditionNull"
};
diff --git a/src/condition.h b/src/condition.h
index 0ce713bc1..84028028c 100644
--- a/src/condition.h
+++ b/src/condition.h
@@ -28,9 +28,11 @@
typedef enum ConditionType {
CONDITION_PATH_EXISTS,
+ CONDITION_PATH_IS_DIRECTORY,
CONDITION_DIRECTORY_NOT_EMPTY,
CONDITION_KERNEL_COMMAND_LINE,
CONDITION_VIRTUALIZATION,
+ CONDITION_SECURITY,
CONDITION_NULL,
_CONDITION_TYPE_MAX,
_CONDITION_TYPE_INVALID = -1
diff --git a/src/conf-parser.c b/src/conf-parser.c
index aac64b29a..a086cf7a0 100644
--- a/src/conf-parser.c
+++ b/src/conf-parser.c
@@ -61,7 +61,7 @@ static int next_assignment(
if (!t->parse)
return 0;
- return t->parse(filename, line, section, lvalue, rvalue, t->data, userdata);
+ return t->parse(filename, line, section, lvalue, t->ltype, rvalue, t->data, userdata);
}
/* Warn about unknown non-extension fields. */
@@ -226,6 +226,7 @@ int config_parse_int(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -251,6 +252,7 @@ int config_parse_uint64(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -276,6 +278,7 @@ int config_parse_unsigned(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -301,6 +304,7 @@ int config_parse_size(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -328,6 +332,7 @@ int config_parse_bool(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -354,6 +359,7 @@ int config_parse_string(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -383,6 +389,7 @@ int config_parse_path(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -416,6 +423,7 @@ int config_parse_strv(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -468,6 +476,7 @@ int config_parse_path_strv(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
diff --git a/src/conf-parser.h b/src/conf-parser.h
index 019b7afd1..3432695db 100644
--- a/src/conf-parser.h
+++ b/src/conf-parser.h
@@ -28,12 +28,13 @@
/* An abstract parser for simple, line based, shallow configuration
* files consisting of variable assignments only. */
-typedef int (*ConfigParserCallback)(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+typedef int (*ConfigParserCallback)(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
/* Wraps info for parsing a specific configuration variable */
typedef struct ConfigItem {
const char *lvalue; /* name of the variable */
ConfigParserCallback parse; /* Function that is called to parse the variable's value */
+ int ltype; /* Distinguish differnt variables passed to the same callback */
void *data; /* Where to store the variable's data */
const char *section;
} ConfigItem;
@@ -44,15 +45,15 @@ typedef struct ConfigItem {
int config_parse(const char *filename, FILE *f, const char* const *sections, const ConfigItem *t, bool relaxed, void *userdata);
/* Generic parsers */
-int config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_uint64(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_path(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_strv(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
-int config_parse_path_strv(const char *filename, unsigned line, const char *section, const char *lvalue, const char *rvalue, void *data, void *userdata);
+int config_parse_int(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_unsigned(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_uint64(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_size(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_bool(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_string(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_path(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
+int config_parse_path_strv(const char *filename, unsigned line, const char *section, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);
#define DEFINE_CONFIG_PARSE_ENUM(function,name,type,msg) \
int function( \
@@ -60,6 +61,7 @@ int config_parse_path_strv(const char *filename, unsigned line, const char *sect
unsigned line, \
const char *section, \
const char *lvalue, \
+ int ltype, \
const char *rvalue, \
void *data, \
void *userdata) { \
diff --git a/src/cryptsetup-generator.c b/src/cryptsetup-generator.c
index 00120f67a..00f48009e 100644
--- a/src/cryptsetup-generator.c
+++ b/src/cryptsetup-generator.c
@@ -222,7 +222,8 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
- arg_dest = argv[1];
+ if (argc > 1)
+ arg_dest = argv[1];
log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
log_parse_environment();
diff --git a/src/cryptsetup.c b/src/cryptsetup.c
index 989734be1..3aa822a1d 100644
--- a/src/cryptsetup.c
+++ b/src/cryptsetup.c
@@ -31,6 +31,7 @@
#include "util.h"
#include "strv.h"
#include "ask-password-api.h"
+#include "def.h"
static const char *opt_type = NULL; /* LUKS1 or PLAIN */
static char *opt_cipher = NULL;
@@ -308,7 +309,7 @@ int main(int argc, char *argv[]) {
if (opt_readonly)
flags |= CRYPT_ACTIVATE_READONLY;
- until = now(CLOCK_MONOTONIC) + (opt_timeout > 0 ? opt_timeout : 60 * USEC_PER_SEC);
+ until = now(CLOCK_MONOTONIC) + (opt_timeout > 0 ? opt_timeout : DEFAULT_TIMEOUT_USEC);
opt_tries = opt_tries > 0 ? opt_tries : 3;
opt_key_size = (opt_key_size > 0 ? opt_key_size : 256);
diff --git a/src/dbus-automount.c b/src/dbus-automount.c
index af277af39..eccad37e8 100644
--- a/src/dbus-automount.c
+++ b/src/dbus-automount.c
@@ -38,6 +38,10 @@
BUS_INTROSPECTABLE_INTERFACE \
"\n"
+#define INTERFACES_LIST \
+ BUS_UNIT_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Automount\0"
+
const char bus_automount_interface[] _introspect_("Automount") = BUS_AUTOMOUNT_INTERFACE;
DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
@@ -48,5 +52,5 @@ DBusHandlerResult bus_automount_message_handler(Unit *u, DBusConnection *c, DBus
{ NULL, NULL, NULL, NULL, NULL }
};
- return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, properties);
+ return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties);
}
diff --git a/src/dbus-common.c b/src/dbus-common.c
index 69593cd18..dcce10e55 100644
--- a/src/dbus-common.c
+++ b/src/dbus-common.c
@@ -23,10 +23,14 @@
#include
#include
#include
+#include
+#include
#include
#include "log.h"
#include "dbus-common.h"
+#include "util.h"
+#include "def.h"
int bus_check_peercred(DBusConnection *c) {
int fd;
@@ -54,18 +58,66 @@ int bus_check_peercred(DBusConnection *c) {
return 1;
}
+static int sync_auth(DBusConnection *bus, DBusError *error) {
+ usec_t begin, tstamp;
+
+ assert(bus);
+
+ /* This complexity should probably move into D-Bus itself:
+ *
+ * https://bugs.freedesktop.org/show_bug.cgi?id=35189 */
+
+ begin = tstamp = now(CLOCK_MONOTONIC);
+ for (;;) {
+
+ if (tstamp > begin + DEFAULT_TIMEOUT_USEC)
+ break;
+
+ if (dbus_connection_get_is_authenticated(bus))
+ break;
+
+ if (!dbus_connection_read_write_dispatch(bus, ((begin + DEFAULT_TIMEOUT_USEC - tstamp) + USEC_PER_MSEC - 1) / USEC_PER_MSEC))
+ break;
+
+ tstamp = now(CLOCK_MONOTONIC);
+ }
+
+ if (!dbus_connection_get_is_connected(bus)) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_SERVER, "Connection terminated during authentication.");
+ return -ECONNREFUSED;
+ }
+
+ if (!dbus_connection_get_is_authenticated(bus)) {
+ dbus_set_error_const(error, DBUS_ERROR_TIMEOUT, "Failed to authenticate in time.");
+ return -EACCES;
+ }
+
+ return 0;
+}
+
int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private, DBusError *error) {
DBusConnection *bus;
+ int r;
assert(_bus);
/* If we are root, then let's not go via the bus */
if (geteuid() == 0 && t == DBUS_BUS_SYSTEM) {
- if (!(bus = dbus_connection_open_private("unix:abstract=/org/freedesktop/systemd1/private", error)))
- return -EIO;
+ if (!(bus = dbus_connection_open_private("unix:path=/run/systemd/private", error))) {
+#ifndef LEGACY
+ dbus_error_free(error);
+
+ /* Retry with the pre v21 socket name, to ease upgrades */
+ if (!(bus = dbus_connection_open_private("unix:abstract=/org/freedesktop/systemd1/private", error)))
+#endif
+ return -EIO;
+ }
+
+ dbus_connection_set_exit_on_disconnect(bus, FALSE);
if (bus_check_peercred(bus) < 0) {
+ dbus_connection_close(bus);
dbus_connection_unref(bus);
dbus_set_error_const(error, DBUS_ERROR_ACCESS_DENIED, "Failed to verify owner of bus.");
@@ -79,12 +131,93 @@ int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private, DBusError *
if (!(bus = dbus_bus_get_private(t, error)))
return -EIO;
+ dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
if (private)
*private = false;
}
+ if ((r = sync_auth(bus, error)) < 0) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ return r;
+ }
+
+ *_bus = bus;
+ return 0;
+}
+
+int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error) {
+ DBusConnection *bus;
+ char *p = NULL;
+ int r;
+
+ assert(_bus);
+ assert(user || host);
+
+ if (user && host)
+ asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s@%s,argv3=systemd-stdio-bridge", user, host);
+ else if (user)
+ asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s@localhost,argv3=systemd-stdio-bridge", user);
+ else if (host)
+ asprintf(&p, "exec:path=ssh,argv1=-xT,argv2=%s,argv3=systemd-stdio-bridge", host);
+
+ if (!p) {
+ dbus_set_error_const(error, DBUS_ERROR_NO_MEMORY, NULL);
+ return -ENOMEM;
+ }
+
+ bus = dbus_connection_open_private(p, error);
+ free(p);
+
+ if (!bus)
+ return -EIO;
+
dbus_connection_set_exit_on_disconnect(bus, FALSE);
+ if ((r = sync_auth(bus, error)) < 0) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ return r;
+ }
+
+ if (!dbus_bus_register(bus, error)) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ return r;
+ }
+
+ *_bus = bus;
+ return 0;
+}
+
+int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error) {
+ DBusConnection *bus;
+ int r;
+
+ assert(_bus);
+
+ /* Don't bother with PolicyKit if we are root */
+ if (geteuid() == 0)
+ return bus_connect(DBUS_BUS_SYSTEM, _bus, NULL, error);
+
+ if (!(bus = dbus_connection_open_private("exec:path=pkexec,argv1=" SYSTEMD_STDIO_BRIDGE_BINARY_PATH, error)))
+ return -EIO;
+
+ dbus_connection_set_exit_on_disconnect(bus, FALSE);
+
+ if ((r = sync_auth(bus, error)) < 0) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ return r;
+ }
+
+ if (!dbus_bus_register(bus, error)) {
+ dbus_connection_close(bus);
+ dbus_connection_unref(bus);
+ return r;
+ }
+
*_bus = bus;
return 0;
}
diff --git a/src/dbus-common.h b/src/dbus-common.h
index 9a66b7874..76333cd4f 100644
--- a/src/dbus-common.h
+++ b/src/dbus-common.h
@@ -28,6 +28,9 @@ int bus_check_peercred(DBusConnection *c);
int bus_connect(DBusBusType t, DBusConnection **_bus, bool *private_bus, DBusError *error);
+int bus_connect_system_ssh(const char *user, const char *host, DBusConnection **_bus, DBusError *error);
+int bus_connect_system_polkit(DBusConnection **_bus, DBusError *error);
+
const char *bus_error_message(const DBusError *error);
#endif
diff --git a/src/dbus-device.c b/src/dbus-device.c
index aafe5d61f..b046eae9f 100644
--- a/src/dbus-device.c
+++ b/src/dbus-device.c
@@ -37,11 +37,14 @@
BUS_INTROSPECTABLE_INTERFACE \
"\n"
+#define INTERFACES_LIST \
+ BUS_UNIT_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Device\0"
+
const char bus_device_interface[] _introspect_("Device") = BUS_DEVICE_INTERFACE;
const char bus_device_invalidating_properties[] =
- "SysFSPath\0"
- "\0";
+ "SysFSPath\0";
DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
const BusProperty properties[] = {
@@ -50,5 +53,5 @@ DBusHandlerResult bus_device_message_handler(Unit *u, DBusConnection *c, DBusMes
{ NULL, NULL, NULL, NULL, NULL }
};
- return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, properties);
+ return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties);
}
diff --git a/src/dbus-execute.c b/src/dbus-execute.c
index 504651fc9..35e6d377e 100644
--- a/src/dbus-execute.c
+++ b/src/dbus-execute.c
@@ -234,6 +234,24 @@ int bus_execute_append_timer_slack_nsec(Manager *m, DBusMessageIter *i, const ch
return 0;
}
+int bus_execute_append_capability_bs(Manager *m, DBusMessageIter *i, const char *property, void *data) {
+ ExecContext *c = data;
+ uint64_t normal, inverted;
+
+ assert(m);
+ assert(i);
+ assert(property);
+ assert(c);
+
+ /* We store this negated internally, to match the kernel, bu
+ * we expose it normalized. */
+
+ normal = *(uint64_t*) data;
+ inverted = ~normal;
+
+ return bus_property_append_uint64(m, i, property, &inverted);
+}
+
int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data) {
ExecContext *c = data;
char *t = NULL;
diff --git a/src/dbus-execute.h b/src/dbus-execute.h
index 082456a9e..8bfaaaf12 100644
--- a/src/dbus-execute.h
+++ b/src/dbus-execute.h
@@ -131,7 +131,7 @@
{ interface, "SyslogLevelPrefix", bus_property_append_bool, "b", &(context).syslog_level_prefix }, \
{ interface, "Capabilities", bus_execute_append_capabilities, "s",&(context) }, \
{ interface, "SecureBits", bus_property_append_int, "i", &(context).secure_bits }, \
- { interface, "CapabilityBoundingSetDrop", bus_property_append_uint64, "t", &(context).capability_bounding_set_drop }, \
+ { interface, "CapabilityBoundingSet", bus_execute_append_capability_bs, "t", &(context).capability_bounding_set_drop }, \
{ interface, "User", bus_property_append_string, "s", (context).user }, \
{ interface, "Group", bus_property_append_string, "s", (context).group }, \
{ interface, "SupplementaryGroups", bus_property_append_strv, "as", (context).supplementary_groups }, \
@@ -167,6 +167,7 @@ int bus_execute_append_cpu_sched_priority(Manager *m, DBusMessageIter *i, const
int bus_execute_append_affinity(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_execute_append_timer_slack_nsec(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_execute_append_capabilities(Manager *m, DBusMessageIter *i, const char *property, void *data);
+int bus_execute_append_capability_bs(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_execute_append_rlimits(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_execute_append_command(Manager *m, DBusMessageIter *u, const char *property, void *data);
int bus_execute_append_kill_mode(Manager *m, DBusMessageIter *i, const char *property, void *data);
diff --git a/src/dbus-job.c b/src/dbus-job.c
index e90d585b6..908ddba53 100644
--- a/src/dbus-job.c
+++ b/src/dbus-job.c
@@ -45,9 +45,12 @@
const char bus_job_interface[] _introspect_("Job") = BUS_JOB_INTERFACE;
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Job\0"
+
#define INVALIDATING_PROPERTIES \
- "State\0" \
- "\0" \
+ "State\0"
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_state, job_state, JobState);
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_job_append_type, job_type, JobType);
@@ -100,7 +103,7 @@ static DBusHandlerResult bus_job_message_dispatch(Job *j, DBusConnection *connec
job_finish_and_invalidate(j, JOB_CANCELED);
} else
- return bus_default_message_handler(j->manager, connection, message, INTROSPECTION, properties);
+ return bus_default_message_handler(j->manager, connection, message, INTROSPECTION, INTERFACES_LIST, properties);
if (reply) {
if (!dbus_connection_send(connection, reply, NULL))
@@ -195,6 +198,8 @@ static DBusHandlerResult bus_job_message_handler(DBusConnection *connection, DBu
if (r == -ENOENT) {
DBusError e;
+
+ dbus_error_init(&e);
dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown job");
return bus_send_error_reply(m, connection, message, &e, r);
}
diff --git a/src/dbus-manager.c b/src/dbus-manager.c
index 7d4703b88..2f755bcc6 100644
--- a/src/dbus-manager.c
+++ b/src/dbus-manager.c
@@ -20,6 +20,7 @@
***/
#include
+#include
#include "dbus.h"
#include "log.h"
@@ -206,6 +207,10 @@
#define INTROSPECTION_END \
"\n"
+#define INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Manager\0"
+
const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs);
@@ -219,17 +224,18 @@ static int bus_manager_append_tainted(Manager *m, DBusMessageIter *i, const char
assert(i);
assert(property);
- if (path_is_mount_point("/usr") > 0 || dir_is_empty("/usr") > 0)
- e = stpcpy(e, "usr-separate-fs");
+ if (m->taint_usr)
+ e = stpcpy(e, "usr-separate-fs ");
- if (readlink_malloc("/etc/mtab", &p) < 0) {
- if (e != buf)
- e = stpcpy(e, " ");
- e = stpcpy(e, "etc-mtab-not-symlink");
- } else
+ if (readlink_malloc("/etc/mtab", &p) < 0)
+ e = stpcpy(e, "etc-mtab-not-symlink ");
+ else
free(p);
- t = buf;
+ if (access("/proc/cgroups", F_OK) < 0)
+ e = stpcpy(e, "cgroups-missing ");
+
+ t = strstrip(buf);
if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
return -ENOMEM;
@@ -1014,14 +1020,16 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
if (!e)
goto oom;
- if (!(reply = dbus_message_new_method_return(message)))
+ if (!(reply = dbus_message_new_method_return(message))) {
+ strv_free(e);
goto oom;
+ }
strv_free(m->environment);
m->environment = e;
} else
- return bus_default_message_handler(m, connection, message, NULL, properties);
+ return bus_default_message_handler(m, connection, message, NULL, INTERFACES_LIST, properties);
if (job_type != _JOB_TYPE_INVALID) {
const char *name, *smode, *old_name = NULL;
@@ -1102,8 +1110,6 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
goto oom;
}
- free(path);
-
if (reply) {
if (!dbus_connection_send(connection, reply, NULL))
goto oom;
@@ -1111,6 +1117,8 @@ static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection,
dbus_message_unref(reply);
}
+ free(path);
+
return DBUS_HANDLER_RESULT_HANDLED;
oom:
diff --git a/src/dbus-mount.c b/src/dbus-mount.c
index fa319febd..5fb9a3f07 100644
--- a/src/dbus-mount.c
+++ b/src/dbus-mount.c
@@ -50,6 +50,10 @@
BUS_INTROSPECTABLE_INTERFACE \
"\n"
+#define INTERFACES_LIST \
+ BUS_UNIT_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Mount\0"
+
const char bus_mount_interface[] _introspect_("Mount") = BUS_MOUNT_INTERFACE;
const char bus_mount_invalidating_properties[] =
@@ -59,8 +63,7 @@ const char bus_mount_invalidating_properties[] =
"ExecMount\0"
"ExecUnmount\0"
"ExecRemount\0"
- "ControlPID\0"
- "\0";
+ "ControlPID\0";
static int bus_mount_append_what(Manager *n, DBusMessageIter *i, const char *property, void *data) {
Mount *m = data;
@@ -151,5 +154,5 @@ DBusHandlerResult bus_mount_message_handler(Unit *u, DBusConnection *c, DBusMess
{ NULL, NULL, NULL, NULL, NULL }
};
- return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, properties);
+ return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties);
}
diff --git a/src/dbus-path.c b/src/dbus-path.c
index 6155792d0..cb1d4f09c 100644
--- a/src/dbus-path.c
+++ b/src/dbus-path.c
@@ -41,6 +41,10 @@
BUS_INTROSPECTABLE_INTERFACE \
"\n"
+#define INTERFACES_LIST \
+ BUS_UNIT_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Path\0"
+
const char bus_path_interface[] _introspect_("Path") = BUS_PATH_INTERFACE;
static int bus_path_append_paths(Manager *m, DBusMessageIter *i, const char *property, void *data) {
@@ -94,5 +98,5 @@ DBusHandlerResult bus_path_message_handler(Unit *u, DBusConnection *c, DBusMessa
{ NULL, NULL, NULL, NULL, NULL }
};
- return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, properties);
+ return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties);
}
diff --git a/src/dbus-service.c b/src/dbus-service.c
index 93fc2a3b6..9c3d73cbf 100644
--- a/src/dbus-service.c
+++ b/src/dbus-service.c
@@ -26,34 +26,14 @@
#include "dbus-service.h"
#ifdef HAVE_SYSV_COMPAT
-#define BUS_SERVICE_INTERFACE \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n" \
- BUS_EXEC_COMMAND_INTERFACE("ExecStartPre") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStart") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStartPost") \
- BUS_EXEC_COMMAND_INTERFACE("ExecReload") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStop") \
- BUS_EXEC_COMMAND_INTERFACE("ExecStopPost") \
- BUS_EXEC_CONTEXT_INTERFACE \
- " \n" \
- " \n" \
- " \n" \
- BUS_EXEC_STATUS_INTERFACE("ExecMain") \
- " \n" \
- " \n" \
+#define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT \
" \n" \
" \n" \
- " \n" \
- " \n" \
- " \n" \
- " \n"
+ " \n"
#else
+#define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT ""
+#endif
+
#define BUS_SERVICE_INTERFACE \
" \n" \
" \n" \
@@ -77,8 +57,10 @@
" \n" \
" \n" \
" \n" \
+ " \n" \
+ " \n" \
+ BUS_SERVICE_SYSV_INTERFACE_FRAGMENT \
" \n"
-#endif
#define INTROSPECTION \
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
@@ -90,6 +72,10 @@
BUS_INTROSPECTABLE_INTERFACE \
"\n"
+#define INTERFACES_LIST \
+ BUS_UNIT_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Service\0"
+
const char bus_service_interface[] _introspect_("Service") = BUS_SERVICE_INTERFACE;
const char bus_service_invalidating_properties[] =
@@ -102,8 +88,7 @@ const char bus_service_invalidating_properties[] =
"ExecMain\0"
"MainPID\0"
"ControlPID\0"
- "StatusText\0"
- "\0";
+ "StatusText\0";
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_type, service_type, ServiceType);
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_service_append_restart, service_restart, ServiceRestart);
@@ -132,18 +117,17 @@ DBusHandlerResult bus_service_message_handler(Unit *u, DBusConnection *connectio
BUS_EXEC_STATUS_PROPERTIES("org.freedesktop.systemd1.Service", u->service.main_exec_status, "ExecMain"),
{ "org.freedesktop.systemd1.Service", "MainPID", bus_property_append_pid, "u", &u->service.main_pid },
{ "org.freedesktop.systemd1.Service", "ControlPID", bus_property_append_pid, "u", &u->service.control_pid },
-#ifdef HAVE_SYSV_COMPAT
- { "org.freedesktop.systemd1.Service", "SysVPath", bus_property_append_string, "s", u->service.sysv_path },
-#endif
{ "org.freedesktop.systemd1.Service", "BusName", bus_property_append_string, "s", u->service.bus_name },
{ "org.freedesktop.systemd1.Service", "StatusText", bus_property_append_string, "s", u->service.status_text },
+ { "org.freedesktop.systemd1.Service", "Sockets", bus_unit_append_dependencies, "as", u->service.configured_sockets },
#ifdef HAVE_SYSV_COMPAT
{ "org.freedesktop.systemd1.Service", "SysVRunLevels", bus_property_append_string, "s", u->service.sysv_runlevels },
{ "org.freedesktop.systemd1.Service", "SysVStartPriority", bus_property_append_int, "i", &u->service.sysv_start_priority },
+ { "org.freedesktop.systemd1.Service", "SysVPath", bus_property_append_string, "s", u->service.sysv_path },
#endif
{ "org.freedesktop.systemd1.Service", "FsckPassNo", bus_property_append_int, "i", &u->service.fsck_passno },
{ NULL, NULL, NULL, NULL, NULL }
};
- return bus_default_message_handler(u->meta.manager, connection, message, INTROSPECTION, properties);
+ return bus_default_message_handler(u->meta.manager, connection, message, INTROSPECTION, INTERFACES_LIST, properties);
}
diff --git a/src/dbus-snapshot.c b/src/dbus-snapshot.c
index a9903ec48..cc12b1bd8 100644
--- a/src/dbus-snapshot.c
+++ b/src/dbus-snapshot.c
@@ -38,6 +38,10 @@
BUS_INTROSPECTABLE_INTERFACE \
"\n"
+#define INTERFACES_LIST \
+ BUS_UNIT_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Snapshot\0"
+
const char bus_snapshot_interface[] _introspect_("Snapshot") = BUS_SNAPSHOT_INTERFACE;
DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
@@ -60,7 +64,7 @@ DBusHandlerResult bus_snapshot_message_handler(Unit *u, DBusConnection *c, DBusM
goto oom;
} else
- return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, properties);
+ return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties);
if (reply) {
if (!dbus_connection_send(c, reply, NULL))
diff --git a/src/dbus-socket.c b/src/dbus-socket.c
index a9cb1c38f..5b068b45f 100644
--- a/src/dbus-socket.c
+++ b/src/dbus-socket.c
@@ -64,6 +64,10 @@
BUS_INTROSPECTABLE_INTERFACE \
"\n"
+#define INTERFACES_LIST \
+ BUS_UNIT_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Socket\0"
+
const char bus_socket_interface[] _introspect_("Socket") = BUS_SOCKET_INTERFACE;
const char bus_socket_invalidating_properties[] =
@@ -73,12 +77,12 @@ const char bus_socket_invalidating_properties[] =
"ExecStopPost\0"
"ControlPID\0"
"NAccepted\0"
- "NConnections\0"
- "\0";
+ "NConnections\0";
static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_socket_append_bind_ipv6_only, socket_address_bind_ipv6_only, SocketAddressBindIPv6Only);
DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
+
const BusProperty properties[] = {
BUS_UNIT_PROPERTIES,
{ "org.freedesktop.systemd1.Socket", "BindIPv6Only", bus_socket_append_bind_ipv6_only, "s", &u->socket.bind_ipv6_only },
@@ -109,5 +113,5 @@ DBusHandlerResult bus_socket_message_handler(Unit *u, DBusConnection *c, DBusMes
{ NULL, NULL, NULL, NULL, NULL }
};
- return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, properties);
+ return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties);
}
diff --git a/src/dbus-swap.c b/src/dbus-swap.c
index 06acb22dc..079912a53 100644
--- a/src/dbus-swap.c
+++ b/src/dbus-swap.c
@@ -47,6 +47,10 @@
BUS_INTROSPECTABLE_INTERFACE \
"\n"
+#define INTERFACES_LIST \
+ BUS_UNIT_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Swap\0"
+
const char bus_swap_interface[] _introspect_("Swap") = BUS_SWAP_INTERFACE;
const char bus_swap_invalidating_properties[] =
@@ -54,8 +58,7 @@ const char bus_swap_invalidating_properties[] =
"Priority\0"
"ExecActivate\0"
"ExecDeactivate\0"
- "ControlPID\0"
- "\0";
+ "ControlPID\0";
static int bus_swap_append_priority(Manager *m, DBusMessageIter *i, const char *property, void *data) {
Swap *s = data;
@@ -93,5 +96,5 @@ DBusHandlerResult bus_swap_message_handler(Unit *u, DBusConnection *c, DBusMessa
{ NULL, NULL, NULL, NULL, NULL }
};
- return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, properties);
+ return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties);
}
diff --git a/src/dbus-target.c b/src/dbus-target.c
index 1eb3c249f..1cbeccb57 100644
--- a/src/dbus-target.c
+++ b/src/dbus-target.c
@@ -38,6 +38,10 @@
BUS_INTROSPECTABLE_INTERFACE \
"\n"
+#define INTERFACES_LIST \
+ BUS_UNIT_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Target\0"
+
const char bus_target_interface[] _introspect_("Target") = BUS_TARGET_INTERFACE;
DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMessage *message) {
@@ -46,5 +50,5 @@ DBusHandlerResult bus_target_message_handler(Unit *u, DBusConnection *c, DBusMes
{ NULL, NULL, NULL, NULL, NULL }
};
- return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, properties);
+ return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties);
}
diff --git a/src/dbus-timer.c b/src/dbus-timer.c
index f4c23e0ea..e44f4e2fe 100644
--- a/src/dbus-timer.c
+++ b/src/dbus-timer.c
@@ -42,12 +42,15 @@
BUS_INTROSPECTABLE_INTERFACE \
"\n"
+#define INTERFACES_LIST \
+ BUS_UNIT_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Timer\0"
+
const char bus_timer_interface[] _introspect_("Timer") = BUS_TIMER_INTERFACE;
const char bus_timer_invalidating_properties[] =
"Timers\0"
- "NextElapseUSec\0"
- "\0";
+ "NextElapseUSec\0";
static int bus_timer_append_timers(Manager *m, DBusMessageIter *i, const char *property, void *data) {
Timer *p = data;
@@ -119,5 +122,5 @@ DBusHandlerResult bus_timer_message_handler(Unit *u, DBusConnection *c, DBusMess
{ NULL, NULL, NULL, NULL, NULL }
};
- return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, properties);
+ return bus_default_message_handler(u->meta.manager, c, message, INTROSPECTION, INTERFACES_LIST, properties);
}
diff --git a/src/dbus-unit.c b/src/dbus-unit.c
index cd6ad843f..b5daa66b5 100644
--- a/src/dbus-unit.c
+++ b/src/dbus-unit.c
@@ -37,8 +37,7 @@ const char bus_unit_interface[] _introspect_("Unit") = BUS_UNIT_INTERFACE;
"ActiveExitTimestamp\0" \
"InactiveEnterTimestamp\0" \
"Job\0" \
- "NeedDaemonReload\0" \
- "\0"
+ "NeedDaemonReload\0"
int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, void *data) {
char *t;
@@ -456,8 +455,6 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn
goto oom;
}
- free(path);
-
if (reply) {
if (!dbus_connection_send(connection, reply, NULL))
goto oom;
@@ -465,6 +462,8 @@ static DBusHandlerResult bus_unit_message_dispatch(Unit *u, DBusConnection *conn
dbus_message_unref(reply);
}
+ free(path);
+
return DBUS_HANDLER_RESULT_HANDLED;
oom:
@@ -569,6 +568,8 @@ static DBusHandlerResult bus_unit_message_handler(DBusConnection *connection, DB
if (r == -ENOENT) {
DBusError e;
+
+ dbus_error_init(&e);
dbus_set_error_const(&e, DBUS_ERROR_UNKNOWN_OBJECT, "Unknown unit");
return bus_send_error_reply(m, connection, message, &e, r);
}
diff --git a/src/dbus-unit.h b/src/dbus-unit.h
index b51fe4eb6..efb61797f 100644
--- a/src/dbus-unit.h
+++ b/src/dbus-unit.h
@@ -102,8 +102,14 @@
" \n" \
" \n" \
" \n" \
+ " \n" \
+ " \n" \
" \n"
+#define BUS_UNIT_INTERFACES_LIST \
+ BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.systemd1.Unit\0"
+
#define BUS_UNIT_PROPERTIES \
{ "org.freedesktop.systemd1.Unit", "Id", bus_property_append_string, "s", u->meta.id }, \
{ "org.freedesktop.systemd1.Unit", "Names", bus_unit_append_names, "as", u }, \
@@ -128,10 +134,10 @@
{ "org.freedesktop.systemd1.Unit", "ActiveState", bus_unit_append_active_state, "s", u }, \
{ "org.freedesktop.systemd1.Unit", "SubState", bus_unit_append_sub_state, "s", u }, \
{ "org.freedesktop.systemd1.Unit", "FragmentPath", bus_property_append_string, "s", u->meta.fragment_path }, \
- { "org.freedesktop.systemd1.Unit", "InactiveExitTimestamp",bus_property_append_uint64, "t", &u->meta.inactive_exit_timestamp.realtime }, \
- { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestamp", bus_property_append_uint64, "t", &u->meta.active_enter_timestamp.realtime }, \
- { "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp", bus_property_append_uint64, "t", &u->meta.active_exit_timestamp.realtime }, \
- { "org.freedesktop.systemd1.Unit", "InactiveEnterTimestamp",bus_property_append_uint64, "t", &u->meta.inactive_enter_timestamp.realtime }, \
+ { "org.freedesktop.systemd1.Unit", "InactiveExitTimestamp",bus_property_append_usec, "t", &u->meta.inactive_exit_timestamp.realtime }, \
+ { "org.freedesktop.systemd1.Unit", "ActiveEnterTimestamp", bus_property_append_usec, "t", &u->meta.active_enter_timestamp.realtime }, \
+ { "org.freedesktop.systemd1.Unit", "ActiveExitTimestamp", bus_property_append_usec, "t", &u->meta.active_exit_timestamp.realtime }, \
+ { "org.freedesktop.systemd1.Unit", "InactiveEnterTimestamp",bus_property_append_usec, "t", &u->meta.inactive_enter_timestamp.realtime }, \
{ "org.freedesktop.systemd1.Unit", "CanStart", bus_unit_append_can_start, "b", u }, \
{ "org.freedesktop.systemd1.Unit", "CanStop", bus_unit_append_can_stop, "b", u }, \
{ "org.freedesktop.systemd1.Unit", "CanReload", bus_unit_append_can_reload, "b", u }, \
@@ -145,7 +151,9 @@
{ "org.freedesktop.systemd1.Unit", "DefaultControlGroup", bus_unit_append_default_cgroup, "s", u }, \
{ "org.freedesktop.systemd1.Unit", "ControlGroup", bus_unit_append_cgroups, "as", u }, \
{ "org.freedesktop.systemd1.Unit", "NeedDaemonReload", bus_unit_append_need_daemon_reload, "b", u }, \
- { "org.freedesktop.systemd1.Unit", "JobTimeoutUSec", bus_property_append_usec, "t", &u->meta.job_timeout }
+ { "org.freedesktop.systemd1.Unit", "JobTimeoutUSec", bus_property_append_usec, "t", &u->meta.job_timeout }, \
+ { "org.freedesktop.systemd1.Unit", "ConditionTimestamp", bus_property_append_usec, "t", &u->meta.condition_timestamp.realtime }, \
+ { "org.freedesktop.systemd1.Unit", "ConditionResult", bus_property_append_bool, "b", &u->meta.condition_result }
int bus_unit_append_names(Manager *m, DBusMessageIter *i, const char *property, void *data);
int bus_unit_append_following(Manager *m, DBusMessageIter *i, const char *property, void *data);
diff --git a/src/dbus.c b/src/dbus.c
index 5a4750d6b..6f43c4108 100644
--- a/src/dbus.c
+++ b/src/dbus.c
@@ -176,8 +176,8 @@ static dbus_bool_t bus_add_watch(DBusWatch *bus_watch, void *data) {
}
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, w->fd, &ev) < 0) {
- free(w);
close_nointr_nofail(w->fd);
+ free(w);
return FALSE;
}
@@ -236,7 +236,7 @@ static int bus_timeout_arm(Manager *m, Watch *w) {
if (dbus_timeout_get_enabled(w->data.bus_timeout)) {
timespec_store(&its.it_value, dbus_timeout_get_interval(w->data.bus_timeout) * USEC_PER_MSEC);
- its.it_interval = its.it_interval;
+ its.it_interval = its.it_value;
}
if (timerfd_settime(w->fd, 0, &its, NULL) < 0)
@@ -269,7 +269,7 @@ static dbus_bool_t bus_add_timeout(DBusTimeout *timeout, void *data) {
if (!(w = new0(Watch, 1)))
return FALSE;
- if (!(w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
+ if ((w->fd = timerfd_create(CLOCK_MONOTONIC, TFD_NONBLOCK|TFD_CLOEXEC)) < 0)
goto fail;
w->type = WATCH_DBUS_TIMEOUT;
@@ -955,7 +955,8 @@ static int bus_init_private(Manager *m) {
if (getpid() != 1)
return 0;
- if (!(m->private_bus = dbus_server_listen("unix:abstract=/org/freedesktop/systemd1/private", &error))) {
+ unlink("/run/systemd/private");
+ if (!(m->private_bus = dbus_server_listen("unix:path=/run/systemd/private", &error))) {
log_error("Failed to create private D-Bus server: %s", error.message);
r = -EIO;
goto fail;
@@ -1213,12 +1214,20 @@ oom:
return -ENOMEM;
}
-DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBusMessage *message, const char*introspection, const BusProperty *properties) {
+DBusHandlerResult bus_default_message_handler(
+ Manager *m,
+ DBusConnection *c,
+ DBusMessage *message,
+ const char *introspection,
+ const char *interfaces,
+ const BusProperty *properties) {
+
DBusError error;
DBusMessage *reply = NULL;
int r;
assert(m);
+ assert(c);
assert(message);
dbus_error_init(&error);
@@ -1269,6 +1278,13 @@ DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBu
if (!dbus_message_iter_close_container(&iter, &sub))
goto oom;
+ } else {
+ if (!nulstr_contains(interfaces, interface))
+ dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
+ else
+ dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
+
+ return bus_send_error_reply(m, c, message, &error, -EINVAL);
}
} else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "GetAll") && properties) {
@@ -1283,6 +1299,11 @@ DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBu
DBUS_TYPE_INVALID))
return bus_send_error_reply(m, c, message, &error, -EINVAL);
+ if (interface[0] && !nulstr_contains(interfaces, interface)) {
+ dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
+ return bus_send_error_reply(m, c, message, &error, -EINVAL);
+ }
+
if (!(reply = dbus_message_new_method_return(message)))
goto oom;
@@ -1316,6 +1337,7 @@ DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBu
if (!dbus_message_iter_close_container(&iter, &sub))
goto oom;
+
} else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set") && properties) {
const char *interface, *property;
DBusMessageIter iter;
@@ -1366,8 +1388,20 @@ DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBu
if (!(reply = dbus_message_new_method_return(message)))
goto oom;
- } else
- return bus_send_error_reply(m, c, message, NULL, -EINVAL);
+ } else {
+ if (p->property)
+ dbus_set_error_const(&error, DBUS_ERROR_PROPERTY_READ_ONLY, "Property read-only");
+ else if (!nulstr_contains(interfaces, interface))
+ dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
+ else
+ dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_PROPERTY, "Unknown property");
+
+ return bus_send_error_reply(m, c, message, &error, -EINVAL);
+ }
+
+ } else if (!nulstr_contains(interfaces, dbus_message_get_interface(message))) {
+ dbus_set_error_const(&error, DBUS_ERROR_UNKNOWN_INTERFACE, "Unknown interface");
+ return bus_send_error_reply(m, c, message, &error, -EINVAL);
}
if (reply) {
diff --git a/src/dbus.h b/src/dbus.h
index 2aaeb4745..f93ad6203 100644
--- a/src/dbus.h
+++ b/src/dbus.h
@@ -32,6 +32,14 @@
#define DBUS_ERROR_UNKNOWN_INTERFACE "org.freedesktop.DBus.Error.UnknownInterface"
#endif
+#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
+#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
+#endif
+
+#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
+#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
+#endif
+
#include "manager.h"
typedef int (*BusPropertyCallback)(Manager *m, DBusMessageIter *iter, const char *property, void *data);
@@ -84,6 +92,11 @@ typedef struct BusProperty {
" \n" \
"\n"
+#define BUS_GENERIC_INTERFACES_LIST \
+ "org.freedesktop.DBus.Properties\0" \
+ "org.freedesktop.DBus.Introspectable\0" \
+ "org.freedesktop.DBus.Peer\0"
+
int bus_init(Manager *m, bool try_bus_connect);
void bus_done(Manager *m);
@@ -94,7 +107,7 @@ void bus_timeout_event(Manager *m, Watch *w, int events);
int bus_query_pid(Manager *m, const char *name);
-DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBusMessage *message, const char* introspection, const BusProperty *properties);
+DBusHandlerResult bus_default_message_handler(Manager *m, DBusConnection *c, DBusMessage *message, const char* introspection, const char *interfaces, const BusProperty *properties);
DBusHandlerResult bus_send_error_reply(Manager *m, DBusConnection *c, DBusMessage *message, DBusError *bus_error, int error);
int bus_broadcast(Manager *m, DBusMessage *message);
diff --git a/src/def.h b/src/def.h
new file mode 100644
index 000000000..c23cd33d8
--- /dev/null
+++ b/src/def.h
@@ -0,0 +1,35 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+#ifndef foodefhfoo
+#define foodefhfoo
+
+/***
+ 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 .
+***/
+
+#include "util.h"
+
+#define DEFAULT_TIMEOUT_USEC (3*USEC_PER_MINUTE)
+#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
+
+#define SYSTEMD_CGROUP_CONTROLLER "name=systemd"
+
+#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
+#define SIGNALS_IGNORE SIGKILL,SIGPIPE
+
+#endif
diff --git a/src/device.c b/src/device.c
index ccf2935a9..41c96cef0 100644
--- a/src/device.c
+++ b/src/device.c
@@ -29,6 +29,7 @@
#include "log.h"
#include "unit-name.h"
#include "dbus-device.h"
+#include "def.h"
static const UnitActiveState state_translation_table[_DEVICE_STATE_MAX] = {
[DEVICE_DEAD] = UNIT_INACTIVE,
diff --git a/src/execute.c b/src/execute.c
index ee05e9944..d67916c24 100644
--- a/src/execute.c
+++ b/src/execute.c
@@ -55,6 +55,7 @@
#include "exit-status.h"
#include "missing.h"
#include "utmp-wtmp.h"
+#include "def.h"
/* This assumes there is a 'tty' group */
#define TTY_MODE 0620
@@ -173,9 +174,9 @@ static int connect_logger_as(const ExecContext *context, ExecOutput output, cons
zero(sa);
sa.sa.sa_family = AF_UNIX;
- strncpy(sa.un.sun_path+1, LOGGER_SOCKET, sizeof(sa.un.sun_path)-1);
+ strncpy(sa.un.sun_path, LOGGER_SOCKET, sizeof(sa.un.sun_path));
- if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + sizeof(LOGGER_SOCKET) - 1) < 0) {
+ if (connect(fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + sizeof(LOGGER_SOCKET) - 1) < 0) {
close_nointr_nofail(fd);
return -errno;
}
@@ -645,7 +646,7 @@ static int enforce_groups(const ExecContext *context, const char *username, gid_
char **i;
/* Final step, initialize any manually set supplementary groups */
- ngroups_max = (int) sysconf(_SC_NGROUPS_MAX);
+ assert_se((ngroups_max = (int) sysconf(_SC_NGROUPS_MAX)) > 0);
if (!(gids = new(gid_t, ngroups_max)))
return -ENOMEM;
@@ -980,7 +981,7 @@ int exec_spawn(ExecCommand *command,
/* This string must fit in 10 chars (i.e. the length
* of "/sbin/init") */
- rename_process("sd:exec");
+ rename_process("sd.exec");
/* We reset exactly these signals, since they are the
* only ones we set to SIG_IGN in the main daemon. All
@@ -1248,6 +1249,15 @@ int exec_spawn(ExecCommand *command,
}
}
+ if (context->capability_bounding_set_drop)
+ for (i = 0; i <= CAP_LAST_CAP; i++)
+ if (context->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) i)) {
+ if (prctl(PR_CAPBSET_DROP, i) < 0) {
+ r = EXIT_CAPABILITIES;
+ goto fail_child;
+ }
+ }
+
if (context->user)
if (enforce_user(context, uid) < 0) {
r = EXIT_USER;
@@ -1640,7 +1650,7 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
fprintf(f,
"%sSyslogFacility: %s\n"
"%sSyslogLevel: %s\n",
- prefix, log_facility_to_string(LOG_FAC(c->syslog_priority)),
+ prefix, log_facility_unshifted_to_string(c->syslog_priority >> 3),
prefix, log_level_to_string(LOG_PRI(c->syslog_priority)));
if (c->capabilities) {
@@ -1663,15 +1673,15 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
(c->secure_bits & SECURE_NOROOT_LOCKED) ? "noroot-locked" : "");
if (c->capability_bounding_set_drop) {
- fprintf(f, "%sCapabilityBoundingSetDrop:", prefix);
+ fprintf(f, "%sCapabilityBoundingSet:", prefix);
for (i = 0; i <= CAP_LAST_CAP; i++)
- if (c->capability_bounding_set_drop & (1 << i)) {
+ if (!(c->capability_bounding_set_drop & ((uint64_t) 1ULL << (uint64_t) i))) {
char *t;
if ((t = cap_to_name(i))) {
fprintf(f, " %s", t);
- free(t);
+ cap_free(t);
}
}
@@ -1923,7 +1933,6 @@ DEFINE_STRING_TABLE_LOOKUP(exec_output, ExecOutput);
static const char* const kill_mode_table[_KILL_MODE_MAX] = {
[KILL_CONTROL_GROUP] = "control-group",
- [KILL_PROCESS_GROUP] = "process-group",
[KILL_PROCESS] = "process",
[KILL_NONE] = "none"
};
diff --git a/src/execute.h b/src/execute.h
index 2856d2f33..208fe4ad5 100644
--- a/src/execute.h
+++ b/src/execute.h
@@ -39,16 +39,10 @@ struct CGroupBonding;
#include "list.h"
#include "util.h"
-/* Abstract namespace! */
-#define LOGGER_SOCKET "/org/freedesktop/systemd1/logger"
-
-/* This doesn't really belong here, but I couldn't find a better place to put this. */
-#define SIGNALS_CRASH_HANDLER SIGSEGV,SIGILL,SIGFPE,SIGBUS,SIGQUIT,SIGABRT
-#define SIGNALS_IGNORE SIGKILL,SIGPIPE
+#define LOGGER_SOCKET "/run/systemd/logger"
typedef enum KillMode {
KILL_CONTROL_GROUP = 0,
- KILL_PROCESS_GROUP,
KILL_PROCESS,
KILL_NONE,
_KILL_MODE_MAX,
diff --git a/src/fsck.c b/src/fsck.c
index dbfb47517..19ca75311 100644
--- a/src/fsck.c
+++ b/src/fsck.c
@@ -106,6 +106,9 @@ static int parse_proc_cmdline(void) {
int r;
size_t l;
+ if (detect_container(NULL) > 0)
+ return 0;
+
if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
return 0;
@@ -262,7 +265,7 @@ int main(int argc, char *argv[]) {
r = EXIT_SUCCESS;
if (status.si_code == CLD_EXITED && (status.si_status & 1))
- touch("/dev/.systemd/quotacheck");
+ touch("/run/systemd/quotacheck");
finish:
if (udev_device)
diff --git a/src/getty-generator.c b/src/getty-generator.c
new file mode 100644
index 000000000..f49f9eae9
--- /dev/null
+++ b/src/getty-generator.c
@@ -0,0 +1,127 @@
+/*-*- 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 .
+***/
+
+#include
+#include
+#include
+
+#include "log.h"
+#include "util.h"
+#include "unit-name.h"
+
+const char *arg_dest = "/tmp";
+
+static int add_symlink(const char *fservice, const char *tservice) {
+ char *from = NULL, *to = NULL;
+ int r;
+
+ asprintf(&from, SYSTEM_DATA_UNIT_PATH "/%s", fservice);
+ asprintf(&to, "%s/getty.target.wants/%s", arg_dest, tservice);
+
+ if (!from || !to) {
+ log_error("Out of memory");
+ r = -ENOMEM;
+ goto finish;
+ }
+
+ mkdir_parents(to, 0755);
+
+ if ((r = symlink(from, to)) < 0) {
+ log_error("Failed to create symlink from %s to %s: %m", from, to);
+ r = -errno;
+ }
+
+finish:
+
+ free(from);
+ free(to);
+
+ return r;
+}
+
+int main(int argc, char *argv[]) {
+ int r = EXIT_SUCCESS;
+ char *active;
+
+ if (argc > 2) {
+ log_error("This program takes one or no arguments.");
+ return EXIT_FAILURE;
+ }
+
+ if (argc > 1)
+ arg_dest = argv[1];
+
+ log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+ log_parse_environment();
+ log_open();
+
+ if (detect_container(NULL) > 0) {
+ log_debug("Automatic adding console shell.");
+
+ if (add_symlink("console-shell.service", "console-shell.service") < 0)
+ r = EXIT_FAILURE;
+
+ /* Don't add any further magic if we are in a container */
+ goto finish;
+ }
+
+ if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
+ const char *tty;
+
+ truncate_nl(active);
+ if ((tty = strrchr(active, ' ')))
+ tty ++;
+ else
+ tty = active;
+
+ /* Automatically add in a serial getty on the kernel
+ * console */
+ if (!tty_is_vc(tty)) {
+ char *n;
+
+ /* We assume that gettys on virtual terminals are
+ * started via manual configuration and do this magic
+ * only for non-VC terminals. */
+
+ log_debug("Automatically adding serial getty for /dev/%s.", tty);
+
+ if (!(n = unit_name_replace_instance("serial-getty@.service", tty)) ||
+ add_symlink("serial-getty@.service", n) < 0)
+ r = EXIT_FAILURE;
+
+ free(n);
+ }
+
+ free(active);
+ }
+
+ /* Automatically add in a serial getty on the first
+ * virtualizer console */
+ if (access("/sys/class/tty/hvc0", F_OK) == 0) {
+ log_debug("Automatic adding serial getty for hvc0.");
+
+ if (add_symlink("serial-getty@.service", "serial-getty@hvc0.service") < 0)
+ r = EXIT_FAILURE;
+ }
+
+finish:
+ return r;
+}
diff --git a/src/gnome-ask-password-agent.vala b/src/gnome-ask-password-agent.vala
index 84f254973..2bfc6a9c8 100644
--- a/src/gnome-ask-password-agent.vala
+++ b/src/gnome-ask-password-agent.vala
@@ -89,9 +89,9 @@ public class MyStatusIcon : StatusIcon {
public MyStatusIcon() throws GLib.Error {
GLib.Object(icon_name : "dialog-password");
- set_title("System Password");
+ set_title("System Password Request");
- directory = File.new_for_path("/dev/.systemd/ask-password/");
+ directory = File.new_for_path("/run/systemd/ask-password/");
file_monitor = directory.monitor_directory(0);
file_monitor.changed.connect(file_monitor_changed);
@@ -145,7 +145,6 @@ public class MyStatusIcon : StatusIcon {
if (current == null)
set_visible(false);
-
}
bool load_password() throws GLib.Error {
@@ -179,6 +178,7 @@ public class MyStatusIcon : StatusIcon {
} catch (GLib.Error e) {
message = "Please Enter System Password!";
}
+
set_tooltip_text(message);
try {
@@ -239,8 +239,7 @@ public class MyStatusIcon : StatusIcon {
null);
OutputStream stream = new UnixOutputStream(to_process, true);
-
-#if LIBNOTIFY07
+#if VALA_0_12
stream.write(password.data, null);
#else
stream.write(password, password.length, null);
diff --git a/src/hostname-setup.c b/src/hostname-setup.c
index ef68d7839..e9869bb4d 100644
--- a/src/hostname-setup.c
+++ b/src/hostname-setup.c
@@ -174,16 +174,36 @@ int hostname_setup(void) {
else
log_warning("Failed to read configured hostname: %s", strerror(-r));
- hn = "localhost";
+ hn = NULL;
} else
hn = b;
+ if (!hn) {
+ /* Don't override the hostname if it is unset and not
+ * explicitly configured */
+
+ char *old_hostname = NULL;
+
+ if ((old_hostname = gethostname_malloc())) {
+ bool already_set;
+
+ already_set = old_hostname[0] != 0;
+ free(old_hostname);
+
+ if (already_set)
+ goto finish;
+ }
+
+ hn = "localhost";
+ }
+
if (sethostname(hn, strlen(hn)) < 0) {
log_warning("Failed to set hostname to <%s>: %m", hn);
r = -errno;
} else
log_info("Set hostname to <%s>.", hn);
+finish:
free(b);
return r;
diff --git a/src/job.c b/src/job.c
index f5d3ff8a3..a3be7beca 100644
--- a/src/job.c
+++ b/src/job.c
@@ -313,7 +313,7 @@ bool job_is_runnable(Job *j) {
* type. */
/* First check if there is an override */
- if (j->ignore_deps)
+ if (j->ignore_order)
return true;
if (j->type == JOB_START ||
@@ -694,7 +694,8 @@ static const char* const job_mode_table[_JOB_MODE_MAX] = {
[JOB_FAIL] = "fail",
[JOB_REPLACE] = "replace",
[JOB_ISOLATE] = "isolate",
- [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies"
+ [JOB_IGNORE_DEPENDENCIES] = "ignore-dependencies",
+ [JOB_IGNORE_REQUIREMENTS] = "ignore-requirements"
};
DEFINE_STRING_TABLE_LOOKUP(job_mode, JobMode);
diff --git a/src/job.h b/src/job.h
index 2c65d9487..2121426b3 100644
--- a/src/job.h
+++ b/src/job.h
@@ -64,10 +64,11 @@ enum JobState {
};
enum JobMode {
- JOB_FAIL,
- JOB_REPLACE,
- JOB_ISOLATE,
- JOB_IGNORE_DEPENDENCIES,
+ JOB_FAIL, /* Fail if a conflicting job is already queued */
+ JOB_REPLACE, /* Replace an existing conflicting job */
+ JOB_ISOLATE, /* Start a unit, and stop all others */
+ JOB_IGNORE_DEPENDENCIES, /* Ignore both requirement and ordering dependencies */
+ JOB_IGNORE_REQUIREMENTS, /* Ignore requirement dependencies */
_JOB_MODE_MAX,
_JOB_MODE_INVALID = -1
};
@@ -130,7 +131,7 @@ struct Job {
bool override:1;
bool in_dbus_queue:1;
bool sent_dbus_new_signal:1;
- bool ignore_deps:1;
+ bool ignore_order:1;
};
Job* job_new(Manager *m, JobType type, Unit *unit);
diff --git a/src/kmsg-syslogd.c b/src/kmsg-syslogd.c
index 4edb16136..60d3244b3 100644
--- a/src/kmsg-syslogd.c
+++ b/src/kmsg-syslogd.c
@@ -154,50 +154,6 @@ fail:
return r;
}
-static int read_priority(const char **buf) {
- int priority;
- size_t n;
- const char *p;
- int a, b, c;
-
- assert(buf);
- assert(*buf);
-
- p = *buf;
- n = strlen(p);
-
- if (n < 3 || p[0] != '<')
- goto fail;
-
- if (p[2] == '>') {
- a = b = 0;
- c = undecchar(p[1]);
- p += 3;
- } else if (n >= 4 && p[3] == '>') {
- a = 0;
- b = undecchar(p[1]);
- c = undecchar(p[2]);
- p += 4;
- } else if (n >= 5 && p[4] == '>') {
- a = undecchar(p[1]);
- b = undecchar(p[2]);
- c = undecchar(p[3]);
- p += 5;
- } else
- goto fail;
-
- if (a < 0 || b < 0 || c < 0)
- goto fail;
-
- *buf = p;
-
- priority = 100*a + 10*b + c;
- return LOG_PRI(priority);
-
-fail:
- return LOG_INFO;
-}
-
static void skip_date(const char **buf) {
enum {
LETTER,
@@ -334,17 +290,26 @@ static void skip_pid(const char **buf) {
static int write_message(Server *s, const char *buf, struct ucred *ucred) {
ssize_t k;
- char priority[4], pid[16];
+ char priority[6], pid[16];
struct iovec iovec[5];
unsigned i = 0;
char *process = NULL;
int r = 0;
+ int prio = LOG_USER | LOG_INFO;
assert(s);
assert(buf);
+ parse_syslog_priority((char**) &buf, &prio);
+
+ if (*buf == 0)
+ return 0;
+
+ if ((prio & LOG_FACMASK) == 0)
+ prio = LOG_USER | LOG_PRI(prio);
+
/* First, set priority field */
- snprintf(priority, sizeof(priority), "<%i>", read_priority(&buf));
+ snprintf(priority, sizeof(priority), "<%i>", prio);
char_array_0(priority);
IOVEC_SET_STRING(iovec[i++], priority);
@@ -354,7 +319,9 @@ static int write_message(Server *s, const char *buf, struct ucred *ucred) {
/* Then, add process if set */
if (read_process(&buf, &iovec[i]) > 0)
i++;
- else if (ucred && get_process_name(ucred->pid, &process) >= 0)
+ else if (ucred &&
+ ucred->pid > 0 &&
+ get_process_name(ucred->pid, &process) >= 0)
IOVEC_SET_STRING(iovec[i++], process);
/* Skip the stored PID if we have a better one */
diff --git a/src/load-fragment.c b/src/load-fragment.c
index 334bc713b..8635bdb22 100644
--- a/src/load-fragment.c
+++ b/src/load-fragment.c
@@ -30,6 +30,8 @@
#include
#include
#include
+#include
+#include
#include "unit.h"
#include "strv.h"
@@ -48,6 +50,7 @@ static int config_parse_warn_compat(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -62,6 +65,7 @@ static int config_parse_deps(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -108,6 +112,7 @@ static int config_parse_names(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -154,6 +159,7 @@ static int config_parse_string_printf(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -187,6 +193,7 @@ static int config_parse_listen(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -249,6 +256,7 @@ static int config_parse_socket_bind(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -283,6 +291,7 @@ static int config_parse_nice(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -316,6 +325,7 @@ static int config_parse_oom_score_adjust(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -349,6 +359,7 @@ static int config_parse_mode(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -383,6 +394,7 @@ static int config_parse_exec(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -500,6 +512,7 @@ static int config_parse_usec(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -527,6 +540,7 @@ static int config_parse_bindtodevice(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -559,6 +573,7 @@ static int config_parse_facility(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -571,12 +586,12 @@ static int config_parse_facility(
assert(rvalue);
assert(data);
- if ((x = log_facility_from_string(rvalue)) < 0) {
+ if ((x = log_facility_unshifted_from_string(rvalue)) < 0) {
log_error("[%s:%u] Failed to parse log facility, ignoring: %s", filename, line, rvalue);
return 0;
}
- *o = LOG_MAKEPRI(x, LOG_PRI(*o));
+ *o = (x << 3) | LOG_PRI(*o);
return 0;
}
@@ -586,6 +601,7 @@ static int config_parse_level(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -603,7 +619,7 @@ static int config_parse_level(
return 0;
}
- *o = LOG_MAKEPRI(LOG_FAC(*o), x);
+ *o = (*o & LOG_FACMASK) | x;
return 0;
}
@@ -612,6 +628,7 @@ static int config_parse_io_class(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -640,6 +657,7 @@ static int config_parse_io_priority(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -668,6 +686,7 @@ static int config_parse_cpu_sched_policy(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -697,6 +716,7 @@ static int config_parse_cpu_sched_prio(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -726,6 +746,7 @@ static int config_parse_cpu_affinity(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -771,6 +792,7 @@ static int config_parse_capabilities(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -803,6 +825,7 @@ static int config_parse_secure_bits(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -844,6 +867,7 @@ static int config_parse_bounding_set(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -852,12 +876,24 @@ static int config_parse_bounding_set(
char *w;
size_t l;
char *state;
+ bool invert = false;
+ uint64_t sum = 0;
assert(filename);
assert(lvalue);
assert(rvalue);
assert(data);
+ if (rvalue[0] == '~') {
+ invert = true;
+ rvalue++;
+ }
+
+ /* Note that we store this inverted internally, since the
+ * kernel wants it like this. But we actually expose it
+ * non-inverted everywhere to have a fully normalized
+ * interface. */
+
FOREACH_WORD_QUOTED(w, l, rvalue, state) {
char *t;
int r;
@@ -874,9 +910,14 @@ static int config_parse_bounding_set(
return 0;
}
- c->capability_bounding_set_drop |= 1 << cap;
+ sum |= ((uint64_t) 1ULL) << (uint64_t) cap;
}
+ if (invert)
+ c->capability_bounding_set_drop |= sum;
+ else
+ c->capability_bounding_set_drop |= ~sum;
+
return 0;
}
@@ -885,6 +926,7 @@ static int config_parse_timer_slack_nsec(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -912,6 +954,7 @@ static int config_parse_limit(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -924,7 +967,9 @@ static int config_parse_limit(
assert(rvalue);
assert(data);
- if (safe_atollu(rvalue, &u) < 0) {
+ if (streq(rvalue, "infinity"))
+ u = (unsigned long long) RLIM_INFINITY;
+ else if (safe_atollu(rvalue, &u) < 0) {
log_error("[%s:%u] Failed to parse resource value, ignoring: %s", filename, line, rvalue);
return 0;
}
@@ -942,6 +987,7 @@ static int config_parse_cgroup(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -976,6 +1022,7 @@ static int config_parse_sysv_priority(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1003,6 +1050,7 @@ static int config_parse_fsck_passno(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1031,6 +1079,7 @@ static int config_parse_kill_signal(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1057,6 +1106,7 @@ static int config_parse_mount_flags(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1094,6 +1144,7 @@ static int config_parse_timer(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1134,6 +1185,7 @@ static int config_parse_timer_unit(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1168,6 +1220,7 @@ static int config_parse_path_spec(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1214,6 +1267,7 @@ static int config_parse_path_unit(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1248,6 +1302,7 @@ static int config_parse_socket_service(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1282,6 +1337,7 @@ static int config_parse_service_sockets(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1336,6 +1392,7 @@ static int config_parse_env_file(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1366,6 +1423,7 @@ static int config_parse_ip_tos(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1392,10 +1450,12 @@ static int config_parse_condition_path(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
+ ConditionType cond = ltype;
Unit *u = data;
bool trigger, negate;
Condition *c;
@@ -1416,23 +1476,24 @@ static int config_parse_condition_path(
return 0;
}
- if (!(c = condition_new(streq(lvalue, "ConditionPathExists") ? CONDITION_PATH_EXISTS : CONDITION_DIRECTORY_NOT_EMPTY,
- rvalue, trigger, negate)))
+ if (!(c = condition_new(cond, rvalue, trigger, negate)))
return -ENOMEM;
LIST_PREPEND(Condition, conditions, u->meta.conditions, c);
return 0;
}
-static int config_parse_condition_kernel(
+static int config_parse_condition_string(
const char *filename,
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
+ ConditionType cond = ltype;
Unit *u = data;
bool trigger, negate;
Condition *c;
@@ -1448,38 +1509,7 @@ static int config_parse_condition_kernel(
if ((negate = rvalue[0] == '!'))
rvalue++;
- if (!(c = condition_new(CONDITION_KERNEL_COMMAND_LINE, rvalue, trigger, negate)))
- return -ENOMEM;
-
- LIST_PREPEND(Condition, conditions, u->meta.conditions, c);
- 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 trigger, negate;
- Condition *c;
-
- assert(filename);
- assert(lvalue);
- assert(rvalue);
- assert(data);
-
- if ((trigger = rvalue[0] == '|'))
- rvalue++;
-
- if ((negate = rvalue[0] == '!'))
- rvalue++;
-
- if (!(c = condition_new(CONDITION_VIRTUALIZATION, rvalue, trigger, negate)))
+ if (!(c = condition_new(cond, rvalue, trigger, negate)))
return -ENOMEM;
LIST_PREPEND(Condition, conditions, u->meta.conditions, c);
@@ -1491,6 +1521,7 @@ static int config_parse_condition_null(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -1698,9 +1729,8 @@ static void dump_items(FILE *f, const ConfigItem *items) {
{ config_parse_notify_access, "ACCESS" },
{ config_parse_ip_tos, "TOS" },
{ config_parse_condition_path, "CONDITION" },
- { config_parse_condition_kernel, "CONDITION" },
+ { config_parse_condition_string, "CONDITION" },
{ config_parse_condition_null, "CONDITION" },
- { config_parse_condition_virt, "CONDITION" },
};
assert(f);
@@ -1746,178 +1776,180 @@ static int load_from_path(Unit *u, const char *path) {
};
#define EXEC_CONTEXT_CONFIG_ITEMS(context, section) \
- { "WorkingDirectory", config_parse_path, &(context).working_directory, section }, \
- { "RootDirectory", config_parse_path, &(context).root_directory, section }, \
- { "User", config_parse_string_printf, &(context).user, section }, \
- { "Group", config_parse_string_printf, &(context).group, section }, \
- { "SupplementaryGroups", config_parse_strv, &(context).supplementary_groups, section }, \
- { "Nice", config_parse_nice, &(context), section }, \
- { "OOMScoreAdjust", config_parse_oom_score_adjust,&(context), section }, \
- { "IOSchedulingClass", config_parse_io_class, &(context), section }, \
- { "IOSchedulingPriority", config_parse_io_priority, &(context), section }, \
- { "CPUSchedulingPolicy", config_parse_cpu_sched_policy,&(context), section }, \
- { "CPUSchedulingPriority", config_parse_cpu_sched_prio, &(context), section }, \
- { "CPUSchedulingResetOnFork", config_parse_bool, &(context).cpu_sched_reset_on_fork, section }, \
- { "CPUAffinity", config_parse_cpu_affinity, &(context), section }, \
- { "UMask", config_parse_mode, &(context).umask, section }, \
- { "Environment", config_parse_strv, &(context).environment, section }, \
- { "EnvironmentFile", config_parse_env_file, &(context).environment_files, section }, \
- { "StandardInput", config_parse_input, &(context).std_input, section }, \
- { "StandardOutput", 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_printf, &(context).syslog_identifier, section }, \
- { "SyslogFacility", config_parse_facility, &(context).syslog_priority, section }, \
- { "SyslogLevel", config_parse_level, &(context).syslog_priority, section }, \
- { "SyslogLevelPrefix", config_parse_bool, &(context).syslog_level_prefix, section }, \
- { "Capabilities", config_parse_capabilities, &(context), section }, \
- { "SecureBits", config_parse_secure_bits, &(context), section }, \
- { "CapabilityBoundingSetDrop", config_parse_bounding_set, &(context), section }, \
- { "TimerSlackNSec", config_parse_timer_slack_nsec,&(context), section }, \
- { "LimitCPU", config_parse_limit, &(context).rlimit[RLIMIT_CPU], section }, \
- { "LimitFSIZE", config_parse_limit, &(context).rlimit[RLIMIT_FSIZE], section }, \
- { "LimitDATA", config_parse_limit, &(context).rlimit[RLIMIT_DATA], section }, \
- { "LimitSTACK", config_parse_limit, &(context).rlimit[RLIMIT_STACK], section }, \
- { "LimitCORE", config_parse_limit, &(context).rlimit[RLIMIT_CORE], section }, \
- { "LimitRSS", config_parse_limit, &(context).rlimit[RLIMIT_RSS], section }, \
- { "LimitNOFILE", config_parse_limit, &(context).rlimit[RLIMIT_NOFILE], section }, \
- { "LimitAS", config_parse_limit, &(context).rlimit[RLIMIT_AS], section }, \
- { "LimitNPROC", config_parse_limit, &(context).rlimit[RLIMIT_NPROC], section }, \
- { "LimitMEMLOCK", config_parse_limit, &(context).rlimit[RLIMIT_MEMLOCK], section }, \
- { "LimitLOCKS", config_parse_limit, &(context).rlimit[RLIMIT_LOCKS], section }, \
- { "LimitSIGPENDING", config_parse_limit, &(context).rlimit[RLIMIT_SIGPENDING], section }, \
- { "LimitMSGQUEUE", config_parse_limit, &(context).rlimit[RLIMIT_MSGQUEUE], section }, \
- { "LimitNICE", config_parse_limit, &(context).rlimit[RLIMIT_NICE], section }, \
- { "LimitRTPRIO", config_parse_limit, &(context).rlimit[RLIMIT_RTPRIO], section }, \
- { "LimitRTTIME", config_parse_limit, &(context).rlimit[RLIMIT_RTTIME], section }, \
- { "ControlGroup", config_parse_cgroup, u, section }, \
- { "ReadWriteDirectories", config_parse_path_strv, &(context).read_write_dirs, section }, \
- { "ReadOnlyDirectories", config_parse_path_strv, &(context).read_only_dirs, section }, \
- { "InaccessibleDirectories",config_parse_path_strv, &(context).inaccessible_dirs, section }, \
- { "PrivateTmp", config_parse_bool, &(context).private_tmp, section }, \
- { "MountFlags", config_parse_mount_flags, &(context), section }, \
- { "TCPWrapName", config_parse_string_printf, &(context).tcpwrap_name, section }, \
- { "PAMName", config_parse_string_printf, &(context).pam_name, section }, \
- { "KillMode", config_parse_kill_mode, &(context).kill_mode, section }, \
- { "KillSignal", config_parse_kill_signal, &(context).kill_signal, section }, \
- { "SendSIGKILL", config_parse_bool, &(context).send_sigkill, section }, \
- { "UtmpIdentifier", config_parse_string_printf, &(context).utmp_id, section }
+ { "WorkingDirectory", config_parse_path, 0, &(context).working_directory, section }, \
+ { "RootDirectory", config_parse_path, 0, &(context).root_directory, section }, \
+ { "User", config_parse_string_printf, 0, &(context).user, section }, \
+ { "Group", config_parse_string_printf, 0, &(context).group, section }, \
+ { "SupplementaryGroups", config_parse_strv, 0, &(context).supplementary_groups, section }, \
+ { "Nice", config_parse_nice, 0, &(context), section }, \
+ { "OOMScoreAdjust", config_parse_oom_score_adjust,0, &(context), section }, \
+ { "IOSchedulingClass", config_parse_io_class, 0, &(context), section }, \
+ { "IOSchedulingPriority", config_parse_io_priority, 0, &(context), section }, \
+ { "CPUSchedulingPolicy", config_parse_cpu_sched_policy,0, &(context), section }, \
+ { "CPUSchedulingPriority", config_parse_cpu_sched_prio, 0, &(context), section }, \
+ { "CPUSchedulingResetOnFork", config_parse_bool, 0, &(context).cpu_sched_reset_on_fork, section }, \
+ { "CPUAffinity", config_parse_cpu_affinity, 0, &(context), section }, \
+ { "UMask", config_parse_mode, 0, &(context).umask, section }, \
+ { "Environment", config_parse_strv, 0, &(context).environment, section }, \
+ { "EnvironmentFile", config_parse_env_file, 0, &(context).environment_files, section }, \
+ { "StandardInput", config_parse_input, 0, &(context).std_input, section }, \
+ { "StandardOutput", config_parse_output, 0, &(context).std_output, section }, \
+ { "StandardError", config_parse_output, 0, &(context).std_error, section }, \
+ { "TTYPath", config_parse_path, 0, &(context).tty_path, section }, \
+ { "SyslogIdentifier", config_parse_string_printf, 0, &(context).syslog_identifier, section }, \
+ { "SyslogFacility", config_parse_facility, 0, &(context).syslog_priority, section }, \
+ { "SyslogLevel", config_parse_level, 0, &(context).syslog_priority, section }, \
+ { "SyslogLevelPrefix", config_parse_bool, 0, &(context).syslog_level_prefix, section }, \
+ { "Capabilities", config_parse_capabilities, 0, &(context), section }, \
+ { "SecureBits", config_parse_secure_bits, 0, &(context), section }, \
+ { "CapabilityBoundingSet", config_parse_bounding_set, 0, &(context), section }, \
+ { "TimerSlackNSec", config_parse_timer_slack_nsec,0, &(context), section }, \
+ { "LimitCPU", config_parse_limit, 0, &(context).rlimit[RLIMIT_CPU], section }, \
+ { "LimitFSIZE", config_parse_limit, 0, &(context).rlimit[RLIMIT_FSIZE], section }, \
+ { "LimitDATA", config_parse_limit, 0, &(context).rlimit[RLIMIT_DATA], section }, \
+ { "LimitSTACK", config_parse_limit, 0, &(context).rlimit[RLIMIT_STACK], section }, \
+ { "LimitCORE", config_parse_limit, 0, &(context).rlimit[RLIMIT_CORE], section }, \
+ { "LimitRSS", config_parse_limit, 0, &(context).rlimit[RLIMIT_RSS], section }, \
+ { "LimitNOFILE", config_parse_limit, 0, &(context).rlimit[RLIMIT_NOFILE], section }, \
+ { "LimitAS", config_parse_limit, 0, &(context).rlimit[RLIMIT_AS], section }, \
+ { "LimitNPROC", config_parse_limit, 0, &(context).rlimit[RLIMIT_NPROC], section }, \
+ { "LimitMEMLOCK", config_parse_limit, 0, &(context).rlimit[RLIMIT_MEMLOCK], section }, \
+ { "LimitLOCKS", config_parse_limit, 0, &(context).rlimit[RLIMIT_LOCKS], section }, \
+ { "LimitSIGPENDING", config_parse_limit, 0, &(context).rlimit[RLIMIT_SIGPENDING], section }, \
+ { "LimitMSGQUEUE", config_parse_limit, 0, &(context).rlimit[RLIMIT_MSGQUEUE], section }, \
+ { "LimitNICE", config_parse_limit, 0, &(context).rlimit[RLIMIT_NICE], section }, \
+ { "LimitRTPRIO", config_parse_limit, 0, &(context).rlimit[RLIMIT_RTPRIO], section }, \
+ { "LimitRTTIME", config_parse_limit, 0, &(context).rlimit[RLIMIT_RTTIME], section }, \
+ { "ControlGroup", config_parse_cgroup, 0, u, section }, \
+ { "ReadWriteDirectories", config_parse_path_strv, 0, &(context).read_write_dirs, section }, \
+ { "ReadOnlyDirectories", config_parse_path_strv, 0, &(context).read_only_dirs, section }, \
+ { "InaccessibleDirectories",config_parse_path_strv, 0, &(context).inaccessible_dirs, section }, \
+ { "PrivateTmp", config_parse_bool, 0, &(context).private_tmp, section }, \
+ { "MountFlags", config_parse_mount_flags, 0, &(context), section }, \
+ { "TCPWrapName", config_parse_string_printf, 0, &(context).tcpwrap_name, section }, \
+ { "PAMName", config_parse_string_printf, 0, &(context).pam_name, section }, \
+ { "KillMode", config_parse_kill_mode, 0, &(context).kill_mode, section }, \
+ { "KillSignal", config_parse_kill_signal, 0, &(context).kill_signal, section }, \
+ { "SendSIGKILL", config_parse_bool, 0, &(context).send_sigkill, section }, \
+ { "UtmpIdentifier", config_parse_string_printf, 0, &(context).utmp_id, section }
const ConfigItem items[] = {
- { "Names", config_parse_names, u, "Unit" },
- { "Description", config_parse_string_printf, &u->meta.description, "Unit" },
- { "Requires", config_parse_deps, UINT_TO_PTR(UNIT_REQUIRES), "Unit" },
- { "RequiresOverridable", config_parse_deps, UINT_TO_PTR(UNIT_REQUIRES_OVERRIDABLE), "Unit" },
- { "Requisite", config_parse_deps, UINT_TO_PTR(UNIT_REQUISITE), "Unit" },
- { "RequisiteOverridable", config_parse_deps, UINT_TO_PTR(UNIT_REQUISITE_OVERRIDABLE), "Unit" },
- { "Wants", config_parse_deps, UINT_TO_PTR(UNIT_WANTS), "Unit" },
- { "BindTo", config_parse_deps, UINT_TO_PTR(UNIT_BIND_TO), "Unit" },
- { "Conflicts", config_parse_deps, UINT_TO_PTR(UNIT_CONFLICTS), "Unit" },
- { "Before", config_parse_deps, UINT_TO_PTR(UNIT_BEFORE), "Unit" },
- { "After", config_parse_deps, UINT_TO_PTR(UNIT_AFTER), "Unit" },
- { "OnFailure", config_parse_deps, UINT_TO_PTR(UNIT_ON_FAILURE), "Unit" },
- { "StopWhenUnneeded", config_parse_bool, &u->meta.stop_when_unneeded, "Unit" },
- { "RefuseManualStart", config_parse_bool, &u->meta.refuse_manual_start, "Unit" },
- { "RefuseManualStop", config_parse_bool, &u->meta.refuse_manual_stop, "Unit" },
- { "AllowIsolate", config_parse_bool, &u->meta.allow_isolate, "Unit" },
- { "DefaultDependencies", config_parse_bool, &u->meta.default_dependencies, "Unit" },
- { "JobTimeoutSec", config_parse_usec, &u->meta.job_timeout, "Unit" },
- { "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" },
+ { "Names", config_parse_names, 0, u, "Unit" },
+ { "Description", config_parse_string_printf, 0, &u->meta.description, "Unit" },
+ { "Requires", config_parse_deps, 0, UINT_TO_PTR(UNIT_REQUIRES), "Unit" },
+ { "RequiresOverridable", config_parse_deps, 0, UINT_TO_PTR(UNIT_REQUIRES_OVERRIDABLE), "Unit" },
+ { "Requisite", config_parse_deps, 0, UINT_TO_PTR(UNIT_REQUISITE), "Unit" },
+ { "RequisiteOverridable", config_parse_deps, 0, UINT_TO_PTR(UNIT_REQUISITE_OVERRIDABLE), "Unit" },
+ { "Wants", config_parse_deps, 0, UINT_TO_PTR(UNIT_WANTS), "Unit" },
+ { "BindTo", config_parse_deps, 0, UINT_TO_PTR(UNIT_BIND_TO), "Unit" },
+ { "Conflicts", config_parse_deps, 0, UINT_TO_PTR(UNIT_CONFLICTS), "Unit" },
+ { "Before", config_parse_deps, 0, UINT_TO_PTR(UNIT_BEFORE), "Unit" },
+ { "After", config_parse_deps, 0, UINT_TO_PTR(UNIT_AFTER), "Unit" },
+ { "OnFailure", config_parse_deps, 0, UINT_TO_PTR(UNIT_ON_FAILURE), "Unit" },
+ { "StopWhenUnneeded", config_parse_bool, 0, &u->meta.stop_when_unneeded, "Unit" },
+ { "RefuseManualStart", config_parse_bool, 0, &u->meta.refuse_manual_start, "Unit" },
+ { "RefuseManualStop", config_parse_bool, 0, &u->meta.refuse_manual_stop, "Unit" },
+ { "AllowIsolate", config_parse_bool, 0, &u->meta.allow_isolate, "Unit" },
+ { "DefaultDependencies", config_parse_bool, 0, &u->meta.default_dependencies, "Unit" },
+ { "JobTimeoutSec", config_parse_usec, 0, &u->meta.job_timeout, "Unit" },
+ { "ConditionPathExists", config_parse_condition_path, CONDITION_PATH_EXISTS, u, "Unit" },
+ { "ConditionPathIsDirectory", config_parse_condition_path, CONDITION_PATH_IS_DIRECTORY, u, "Unit" },
+ { "ConditionDirectoryNotEmpty", config_parse_condition_path, CONDITION_DIRECTORY_NOT_EMPTY, u, "Unit" },
+ { "ConditionKernelCommandLine", config_parse_condition_string, CONDITION_KERNEL_COMMAND_LINE, u, "Unit" },
+ { "ConditionVirtualization", config_parse_condition_string, CONDITION_VIRTUALIZATION, u, "Unit" },
+ { "ConditionSecurity", config_parse_condition_string, CONDITION_SECURITY, u, "Unit" },
+ { "ConditionNull", config_parse_condition_null, 0, u, "Unit" },
- { "PIDFile", config_parse_path, &u->service.pid_file, "Service" },
- { "ExecStartPre", config_parse_exec, u->service.exec_command+SERVICE_EXEC_START_PRE, "Service" },
- { "ExecStart", config_parse_exec, u->service.exec_command+SERVICE_EXEC_START, "Service" },
- { "ExecStartPost", config_parse_exec, u->service.exec_command+SERVICE_EXEC_START_POST, "Service" },
- { "ExecReload", config_parse_exec, u->service.exec_command+SERVICE_EXEC_RELOAD, "Service" },
- { "ExecStop", config_parse_exec, u->service.exec_command+SERVICE_EXEC_STOP, "Service" },
- { "ExecStopPost", config_parse_exec, u->service.exec_command+SERVICE_EXEC_STOP_POST, "Service" },
- { "RestartSec", config_parse_usec, &u->service.restart_usec, "Service" },
- { "TimeoutSec", config_parse_usec, &u->service.timeout_usec, "Service" },
- { "Type", config_parse_service_type, &u->service.type, "Service" },
- { "Restart", config_parse_service_restart, &u->service.restart, "Service" },
- { "PermissionsStartOnly", config_parse_bool, &u->service.permissions_start_only, "Service" },
- { "RootDirectoryStartOnly", config_parse_bool, &u->service.root_directory_start_only, "Service" },
- { "RemainAfterExit", config_parse_bool, &u->service.remain_after_exit, "Service" },
- { "GuessMainPID", config_parse_bool, &u->service.guess_main_pid, "Service" },
+ { "PIDFile", config_parse_path, 0, &u->service.pid_file, "Service" },
+ { "ExecStartPre", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START_PRE, "Service" },
+ { "ExecStart", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START, "Service" },
+ { "ExecStartPost", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_START_POST, "Service" },
+ { "ExecReload", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_RELOAD, "Service" },
+ { "ExecStop", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_STOP, "Service" },
+ { "ExecStopPost", config_parse_exec, 0, u->service.exec_command+SERVICE_EXEC_STOP_POST, "Service" },
+ { "RestartSec", config_parse_usec, 0, &u->service.restart_usec, "Service" },
+ { "TimeoutSec", config_parse_usec, 0, &u->service.timeout_usec, "Service" },
+ { "Type", config_parse_service_type, 0, &u->service.type, "Service" },
+ { "Restart", config_parse_service_restart, 0, &u->service.restart, "Service" },
+ { "PermissionsStartOnly", config_parse_bool, 0, &u->service.permissions_start_only, "Service" },
+ { "RootDirectoryStartOnly", config_parse_bool, 0, &u->service.root_directory_start_only, "Service" },
+ { "RemainAfterExit", config_parse_bool, 0, &u->service.remain_after_exit, "Service" },
+ { "GuessMainPID", config_parse_bool, 0, &u->service.guess_main_pid, "Service" },
#ifdef HAVE_SYSV_COMPAT
- { "SysVStartPriority", config_parse_sysv_priority, &u->service.sysv_start_priority, "Service" },
+ { "SysVStartPriority", config_parse_sysv_priority, 0, &u->service.sysv_start_priority, "Service" },
#else
- { "SysVStartPriority", config_parse_warn_compat, NULL, "Service" },
+ { "SysVStartPriority", config_parse_warn_compat, 0, NULL, "Service" },
#endif
- { "NonBlocking", config_parse_bool, &u->service.exec_context.non_blocking, "Service" },
- { "BusName", config_parse_string_printf, &u->service.bus_name, "Service" },
- { "NotifyAccess", config_parse_notify_access, &u->service.notify_access, "Service" },
- { "Sockets", config_parse_service_sockets, &u->service, "Service" },
- { "FsckPassNo", config_parse_fsck_passno, &u->service.fsck_passno, "Service" },
+ { "NonBlocking", config_parse_bool, 0, &u->service.exec_context.non_blocking, "Service" },
+ { "BusName", config_parse_string_printf, 0, &u->service.bus_name, "Service" },
+ { "NotifyAccess", config_parse_notify_access, 0, &u->service.notify_access, "Service" },
+ { "Sockets", config_parse_service_sockets, 0, &u->service, "Service" },
+ { "FsckPassNo", config_parse_fsck_passno, 0, &u->service.fsck_passno, "Service" },
EXEC_CONTEXT_CONFIG_ITEMS(u->service.exec_context, "Service"),
- { "ListenStream", config_parse_listen, &u->socket, "Socket" },
- { "ListenDatagram", config_parse_listen, &u->socket, "Socket" },
- { "ListenSequentialPacket", config_parse_listen, &u->socket, "Socket" },
- { "ListenFIFO", config_parse_listen, &u->socket, "Socket" },
- { "BindIPv6Only", config_parse_socket_bind, &u->socket, "Socket" },
- { "Backlog", config_parse_unsigned, &u->socket.backlog, "Socket" },
- { "BindToDevice", config_parse_bindtodevice, &u->socket, "Socket" },
- { "ExecStartPre", config_parse_exec, u->socket.exec_command+SOCKET_EXEC_START_PRE, "Socket" },
- { "ExecStartPost", config_parse_exec, u->socket.exec_command+SOCKET_EXEC_START_POST, "Socket" },
- { "ExecStopPre", config_parse_exec, u->socket.exec_command+SOCKET_EXEC_STOP_PRE, "Socket" },
- { "ExecStopPost", config_parse_exec, u->socket.exec_command+SOCKET_EXEC_STOP_POST, "Socket" },
- { "TimeoutSec", config_parse_usec, &u->socket.timeout_usec, "Socket" },
- { "DirectoryMode", config_parse_mode, &u->socket.directory_mode, "Socket" },
- { "SocketMode", config_parse_mode, &u->socket.socket_mode, "Socket" },
- { "Accept", config_parse_bool, &u->socket.accept, "Socket" },
- { "MaxConnections", config_parse_unsigned, &u->socket.max_connections, "Socket" },
- { "KeepAlive", config_parse_bool, &u->socket.keep_alive, "Socket" },
- { "Priority", config_parse_int, &u->socket.priority, "Socket" },
- { "ReceiveBuffer", config_parse_size, &u->socket.receive_buffer, "Socket" },
- { "SendBuffer", config_parse_size, &u->socket.send_buffer, "Socket" },
- { "IPTOS", config_parse_ip_tos, &u->socket.ip_tos, "Socket" },
- { "IPTTL", config_parse_int, &u->socket.ip_ttl, "Socket" },
- { "Mark", config_parse_int, &u->socket.mark, "Socket" },
- { "PipeSize", config_parse_size, &u->socket.pipe_size, "Socket" },
- { "FreeBind", config_parse_bool, &u->socket.free_bind, "Socket" },
- { "TCPCongestion", config_parse_string, &u->socket.tcp_congestion, "Socket" },
- { "Service", config_parse_socket_service, &u->socket, "Socket" },
+ { "ListenStream", config_parse_listen, 0, &u->socket, "Socket" },
+ { "ListenDatagram", config_parse_listen, 0, &u->socket, "Socket" },
+ { "ListenSequentialPacket", config_parse_listen, 0, &u->socket, "Socket" },
+ { "ListenFIFO", config_parse_listen, 0, &u->socket, "Socket" },
+ { "BindIPv6Only", config_parse_socket_bind, 0, &u->socket, "Socket" },
+ { "Backlog", config_parse_unsigned, 0, &u->socket.backlog, "Socket" },
+ { "BindToDevice", config_parse_bindtodevice, 0, &u->socket, "Socket" },
+ { "ExecStartPre", config_parse_exec, 0, u->socket.exec_command+SOCKET_EXEC_START_PRE, "Socket" },
+ { "ExecStartPost", config_parse_exec, 0, u->socket.exec_command+SOCKET_EXEC_START_POST, "Socket" },
+ { "ExecStopPre", config_parse_exec, 0, u->socket.exec_command+SOCKET_EXEC_STOP_PRE, "Socket" },
+ { "ExecStopPost", config_parse_exec, 0, u->socket.exec_command+SOCKET_EXEC_STOP_POST, "Socket" },
+ { "TimeoutSec", config_parse_usec, 0, &u->socket.timeout_usec, "Socket" },
+ { "DirectoryMode", config_parse_mode, 0, &u->socket.directory_mode, "Socket" },
+ { "SocketMode", config_parse_mode, 0, &u->socket.socket_mode, "Socket" },
+ { "Accept", config_parse_bool, 0, &u->socket.accept, "Socket" },
+ { "MaxConnections", config_parse_unsigned, 0, &u->socket.max_connections, "Socket" },
+ { "KeepAlive", config_parse_bool, 0, &u->socket.keep_alive, "Socket" },
+ { "Priority", config_parse_int, 0, &u->socket.priority, "Socket" },
+ { "ReceiveBuffer", config_parse_size, 0, &u->socket.receive_buffer, "Socket" },
+ { "SendBuffer", config_parse_size, 0, &u->socket.send_buffer, "Socket" },
+ { "IPTOS", config_parse_ip_tos, 0, &u->socket.ip_tos, "Socket" },
+ { "IPTTL", config_parse_int, 0, &u->socket.ip_ttl, "Socket" },
+ { "Mark", config_parse_int, 0, &u->socket.mark, "Socket" },
+ { "PipeSize", config_parse_size, 0, &u->socket.pipe_size, "Socket" },
+ { "FreeBind", config_parse_bool, 0, &u->socket.free_bind, "Socket" },
+ { "TCPCongestion", config_parse_string, 0, &u->socket.tcp_congestion, "Socket" },
+ { "Service", config_parse_socket_service, 0, &u->socket, "Socket" },
EXEC_CONTEXT_CONFIG_ITEMS(u->socket.exec_context, "Socket"),
- { "What", config_parse_string, &u->mount.parameters_fragment.what, "Mount" },
- { "Where", config_parse_path, &u->mount.where, "Mount" },
- { "Options", config_parse_string, &u->mount.parameters_fragment.options, "Mount" },
- { "Type", config_parse_string, &u->mount.parameters_fragment.fstype, "Mount" },
- { "TimeoutSec", config_parse_usec, &u->mount.timeout_usec, "Mount" },
- { "DirectoryMode", config_parse_mode, &u->mount.directory_mode, "Mount" },
+ { "What", config_parse_string, 0, &u->mount.parameters_fragment.what, "Mount" },
+ { "Where", config_parse_path, 0, &u->mount.where, "Mount" },
+ { "Options", config_parse_string, 0, &u->mount.parameters_fragment.options, "Mount" },
+ { "Type", config_parse_string, 0, &u->mount.parameters_fragment.fstype, "Mount" },
+ { "TimeoutSec", config_parse_usec, 0, &u->mount.timeout_usec, "Mount" },
+ { "DirectoryMode", config_parse_mode, 0, &u->mount.directory_mode, "Mount" },
EXEC_CONTEXT_CONFIG_ITEMS(u->mount.exec_context, "Mount"),
- { "Where", config_parse_path, &u->automount.where, "Automount" },
- { "DirectoryMode", config_parse_mode, &u->automount.directory_mode, "Automount" },
+ { "Where", config_parse_path, 0, &u->automount.where, "Automount" },
+ { "DirectoryMode", config_parse_mode, 0, &u->automount.directory_mode, "Automount" },
- { "What", config_parse_path, &u->swap.parameters_fragment.what, "Swap" },
- { "Priority", config_parse_int, &u->swap.parameters_fragment.priority, "Swap" },
- { "TimeoutSec", config_parse_usec, &u->swap.timeout_usec, "Swap" },
+ { "What", config_parse_path, 0, &u->swap.parameters_fragment.what, "Swap" },
+ { "Priority", config_parse_int, 0, &u->swap.parameters_fragment.priority, "Swap" },
+ { "TimeoutSec", config_parse_usec, 0, &u->swap.timeout_usec, "Swap" },
EXEC_CONTEXT_CONFIG_ITEMS(u->swap.exec_context, "Swap"),
- { "OnActiveSec", config_parse_timer, &u->timer, "Timer" },
- { "OnBootSec", config_parse_timer, &u->timer, "Timer" },
- { "OnStartupSec", config_parse_timer, &u->timer, "Timer" },
- { "OnUnitActiveSec", config_parse_timer, &u->timer, "Timer" },
- { "OnUnitInactiveSec", config_parse_timer, &u->timer, "Timer" },
- { "Unit", config_parse_timer_unit, &u->timer, "Timer" },
+ { "OnActiveSec", config_parse_timer, 0, &u->timer, "Timer" },
+ { "OnBootSec", config_parse_timer, 0, &u->timer, "Timer" },
+ { "OnStartupSec", config_parse_timer, 0, &u->timer, "Timer" },
+ { "OnUnitActiveSec", config_parse_timer, 0, &u->timer, "Timer" },
+ { "OnUnitInactiveSec", config_parse_timer, 0, &u->timer, "Timer" },
+ { "Unit", config_parse_timer_unit, 0, &u->timer, "Timer" },
- { "PathExists", config_parse_path_spec, &u->path, "Path" },
- { "PathChanged", config_parse_path_spec, &u->path, "Path" },
- { "DirectoryNotEmpty", config_parse_path_spec, &u->path, "Path" },
- { "Unit", config_parse_path_unit, &u->path, "Path" },
+ { "PathExists", config_parse_path_spec, 0, &u->path, "Path" },
+ { "PathChanged", config_parse_path_spec, 0, &u->path, "Path" },
+ { "DirectoryNotEmpty", config_parse_path_spec, 0, &u->path, "Path" },
+ { "Unit", config_parse_path_unit, 0, &u->path, "Path" },
/* The [Install] section is ignored here. */
- { "Alias", NULL, NULL, "Install" },
- { "WantedBy", NULL, NULL, "Install" },
- { "Also", NULL, NULL, "Install" },
+ { "Alias", NULL, 0, NULL, "Install" },
+ { "WantedBy", NULL, 0, NULL, "Install" },
+ { "Also", NULL, 0, NULL, "Install" },
- { NULL, NULL, NULL, NULL }
+ { NULL, NULL, 0, NULL, NULL }
};
#undef EXEC_CONTEXT_CONFIG_ITEMS
diff --git a/src/locale-setup.c b/src/locale-setup.c
index 7684681cc..08e289d4e 100644
--- a/src/locale-setup.c
+++ b/src/locale-setup.c
@@ -54,7 +54,7 @@ static const char * const variable_names[_VARIABLE_MAX] = {
[VARIABLE_LC_TIME] = "LC_TIME",
[VARIABLE_LC_COLLATE] = "LC_COLLATE",
[VARIABLE_LC_MONETARY] = "LC_MONETARY",
- [VARIABLE_LC_MESSAGES] = "LC_MESSAGE",
+ [VARIABLE_LC_MESSAGES] = "LC_MESSAGES",
[VARIABLE_LC_PAPER] = "LC_PAPER",
[VARIABLE_LC_NAME] = "LC_NAME",
[VARIABLE_LC_ADDRESS] = "LC_ADDRESS",
@@ -65,32 +65,33 @@ static const char * const variable_names[_VARIABLE_MAX] = {
int locale_setup(void) {
char *variables[_VARIABLE_MAX];
- int r, i;
+ int r = 0, i;
zero(variables);
- if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
+ if (detect_container(NULL) <= 0)
+ if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
#ifdef TARGET_FEDORA
- "LANG", &variables[VARIABLE_LANG],
+ "LANG", &variables[VARIABLE_LANG],
#endif
- "locale.LANG", &variables[VARIABLE_LANG],
- "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
- "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
- "locale.LC_TIME", &variables[VARIABLE_LC_TIME],
- "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
- "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
- "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
- "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER],
- "locale.LC_NAME", &variables[VARIABLE_LC_NAME],
- "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
- "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
- "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
- "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
- NULL)) < 0) {
+ "locale.LANG", &variables[VARIABLE_LANG],
+ "locale.LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
+ "locale.LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
+ "locale.LC_TIME", &variables[VARIABLE_LC_TIME],
+ "locale.LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
+ "locale.LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
+ "locale.LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
+ "locale.LC_PAPER", &variables[VARIABLE_LC_PAPER],
+ "locale.LC_NAME", &variables[VARIABLE_LC_NAME],
+ "locale.LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
+ "locale.LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
+ "locale.LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
+ "locale.LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
+ NULL)) < 0) {
- if (r != -ENOENT)
- log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
- }
+ if (r != -ENOENT)
+ log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
+ }
/* Hmm, nothing set on the kernel cmd line? Then let's
* try /etc/locale.conf */
@@ -138,7 +139,19 @@ int locale_setup(void) {
#elif defined(TARGET_DEBIAN) || defined(TARGET_UBUNTU)
if (r <= 0 &&
(r = parse_env_file("/etc/default/locale", NEWLINE,
- "LANG", &variables[VARIABLE_LANG],
+ "LANG", &variables[VARIABLE_LANG],
+ "LC_CTYPE", &variables[VARIABLE_LC_CTYPE],
+ "LC_NUMERIC", &variables[VARIABLE_LC_NUMERIC],
+ "LC_TIME", &variables[VARIABLE_LC_TIME],
+ "LC_COLLATE", &variables[VARIABLE_LC_COLLATE],
+ "LC_MONETARY", &variables[VARIABLE_LC_MONETARY],
+ "LC_MESSAGES", &variables[VARIABLE_LC_MESSAGES],
+ "LC_PAPER", &variables[VARIABLE_LC_PAPER],
+ "LC_NAME", &variables[VARIABLE_LC_NAME],
+ "LC_ADDRESS", &variables[VARIABLE_LC_ADDRESS],
+ "LC_TELEPHONE", &variables[VARIABLE_LC_TELEPHONE],
+ "LC_MEASUREMENT", &variables[VARIABLE_LC_MEASUREMENT],
+ "LC_IDENTIFICATION", &variables[VARIABLE_LC_IDENTIFICATION],
NULL)) < 0) {
if (r != -ENOENT)
diff --git a/src/log.c b/src/log.c
index b6d4bf9c1..95c27656b 100644
--- a/src/log.c
+++ b/src/log.c
@@ -289,7 +289,7 @@ static int write_to_syslog(
if (syslog_fd < 0)
return 0;
- snprintf(header_priority, sizeof(header_priority), "<%i>", LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(level)));
+ snprintf(header_priority, sizeof(header_priority), "<%i>", level);
char_array_0(header_priority);
t = (time_t) (now(CLOCK_REALTIME) / USEC_PER_SEC);
@@ -346,7 +346,7 @@ static int write_to_kmsg(
if (kmsg_fd < 0)
return 0;
- snprintf(header_priority, sizeof(header_priority), "<%i>", LOG_PRI(level));
+ snprintf(header_priority, sizeof(header_priority), "<%i>", level);
char_array_0(header_priority);
snprintf(header_pid, sizeof(header_pid), "[%lu]: ", (unsigned long) getpid());
@@ -377,6 +377,10 @@ static int log_dispatch(
if (log_target == LOG_TARGET_NULL)
return 0;
+ /* Patch in LOG_DAEMON facility if necessary */
+ if ((level & LOG_FACMASK) == 0)
+ level = LOG_DAEMON | LOG_PRI(level);
+
do {
char *e;
int k = 0;
diff --git a/src/logger.c b/src/logger.c
index 104d7c385..faa6c9721 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -104,20 +104,16 @@ static int stream_log(Stream *s, char *p, usec_t ts) {
priority = s->priority;
- if (s->prefix &&
- p[0] == '<' &&
- p[1] >= '0' && p[1] <= '7' &&
- p[2] == '>') {
-
- /* Detected priority prefix */
- priority = LOG_MAKEPRI(LOG_FAC(priority), (p[1] - '0'));
-
- p += 3;
- }
+ if (s->prefix)
+ parse_syslog_priority(&p, &priority);
if (*p == 0)
return 0;
+ /* Patch in LOG_USER facility if necessary */
+ if ((priority & LOG_FACMASK) == 0)
+ priority = LOG_USER | LOG_PRI(priority);
+
/*
* The format glibc uses to talk to the syslog daemon is:
*
@@ -130,8 +126,7 @@ static int stream_log(Stream *s, char *p, usec_t ts) {
* We extend the latter to include the process name and pid.
*/
- snprintf(header_priority, sizeof(header_priority), "<%i>",
- s->target == STREAM_SYSLOG ? priority : LOG_PRI(priority));
+ snprintf(header_priority, sizeof(header_priority), "<%i>", priority);
char_array_0(header_priority);
if (s->target == STREAM_SYSLOG) {
diff --git a/src/loopback-setup.c b/src/loopback-setup.c
index a579060d8..b6359def7 100644
--- a/src/loopback-setup.c
+++ b/src/loopback-setup.c
@@ -265,7 +265,7 @@ int loopback_setup(void) {
finish:
if (r < 0)
- log_error("Failed to configure loopback device: %s", strerror(-r));
+ log_warning("Failed to configure loopback device: %s", strerror(-r));
if (fd >= 0)
close_nointr_nofail(fd);
diff --git a/src/machine-id-setup.c b/src/machine-id-setup.c
index 65792e9b8..98e288e1b 100644
--- a/src/machine-id-setup.c
+++ b/src/machine-id-setup.c
@@ -142,20 +142,20 @@ int machine_id_setup(void) {
fd = -1;
/* Hmm, we couldn't write it? So let's write it to
- * /dev/.systemd/machine-id as a replacement */
+ * /run/systemd/machine-id as a replacement */
- mkdir_p("/dev/.systemd", 0755);
+ mkdir_p("/run/systemd", 0755);
- if ((r = write_one_line_file("/dev/.systemd/machine-id", id)) < 0) {
- log_error("Cannot write /dev/.systemd/machine-id: %s", strerror(-r));
+ if ((r = write_one_line_file("/run/systemd/machine-id", id)) < 0) {
+ log_error("Cannot write /run/systemd/machine-id: %s", strerror(-r));
- unlink("/dev/.systemd/machine-id");
+ unlink("/run/systemd/machine-id");
goto finish;
}
/* And now, let's mount it over */
- r = mount("/dev/.systemd/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0;
- unlink("/dev/.systemd/machine-id");
+ r = mount("/run/systemd/machine-id", "/etc/machine-id", "bind", MS_BIND|MS_RDONLY, NULL) < 0 ? -errno : 0;
+ unlink("/run/systemd/machine-id");
if (r < 0)
log_error("Failed to mount /etc/machine-id: %s", strerror(-r));
diff --git a/src/macro.h b/src/macro.h
index 996b7c2ed..e7a4d2cde 100644
--- a/src/macro.h
+++ b/src/macro.h
@@ -27,8 +27,6 @@
#include
#include
-#define PAGE_SIZE 4096
-
#define _printf_attr_(a,b) __attribute__ ((format (printf, a, b)))
#define _sentinel_ __attribute__ ((sentinel))
#define _noreturn_ __attribute__((noreturn))
@@ -51,12 +49,9 @@
#define STRINGIFY(x) XSTRINGIFY(x)
/* Rounds up */
-static inline size_t ALIGN(size_t l) {
- return ((l + sizeof(void*) - 1) & ~(sizeof(void*) - 1));
-}
-
-static inline size_t PAGE_ALIGN(size_t l) {
- return ((l + PAGE_SIZE - 1) & ~(PAGE_SIZE -1));
+#define ALIGN(l) ALIGN_TO((l), sizeof(void*))
+static inline size_t ALIGN_TO(size_t l, size_t ali) {
+ return ((l + ali - 1) & ~(ali - 1));
}
#define ELEMENTSOF(x) (sizeof(x)/sizeof((x)[0]))
diff --git a/src/main.c b/src/main.c
index a041a22ed..b43d8eca9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -51,6 +51,7 @@
#include "label.h"
#include "build.h"
#include "strv.h"
+#include "def.h"
static enum {
ACTION_RUN,
@@ -226,6 +227,7 @@ static int parse_proc_cmdline_word(const char *word) {
static const char * const rlmap[] = {
"emergency", SPECIAL_EMERGENCY_TARGET,
+ "-b", SPECIAL_EMERGENCY_TARGET,
"single", SPECIAL_RESCUE_TARGET,
"-s", SPECIAL_RESCUE_TARGET,
"s", SPECIAL_RESCUE_TARGET,
@@ -371,6 +373,7 @@ static int config_parse_level(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -388,6 +391,7 @@ static int config_parse_target(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -405,6 +409,7 @@ static int config_parse_color(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -422,6 +427,7 @@ static int config_parse_location(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -439,6 +445,7 @@ static int config_parse_cpu_affinity(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -492,24 +499,24 @@ static DEFINE_CONFIG_PARSE_ENUM(config_parse_output, exec_output, ExecOutput, "F
static int parse_config_file(void) {
const ConfigItem items[] = {
- { "LogLevel", config_parse_level, NULL, "Manager" },
- { "LogTarget", config_parse_target, NULL, "Manager" },
- { "LogColor", config_parse_color, NULL, "Manager" },
- { "LogLocation", config_parse_location, NULL, "Manager" },
- { "DumpCore", config_parse_bool, &arg_dump_core, "Manager" },
- { "CrashShell", config_parse_bool, &arg_crash_shell, "Manager" },
- { "ShowStatus", config_parse_bool, &arg_show_status, "Manager" },
+ { "LogLevel", config_parse_level, 0, NULL, "Manager" },
+ { "LogTarget", config_parse_target, 0, NULL, "Manager" },
+ { "LogColor", config_parse_color, 0, NULL, "Manager" },
+ { "LogLocation", config_parse_location, 0, NULL, "Manager" },
+ { "DumpCore", config_parse_bool, 0, &arg_dump_core, "Manager" },
+ { "CrashShell", config_parse_bool, 0, &arg_crash_shell, "Manager" },
+ { "ShowStatus", config_parse_bool, 0, &arg_show_status, "Manager" },
#ifdef HAVE_SYSV_COMPAT
- { "SysVConsole", config_parse_bool, &arg_sysv_console, "Manager" },
+ { "SysVConsole", config_parse_bool, 0, &arg_sysv_console, "Manager" },
#endif
- { "CrashChVT", config_parse_int, &arg_crash_chvt, "Manager" },
- { "CPUAffinity", config_parse_cpu_affinity, NULL, "Manager" },
- { "MountAuto", config_parse_bool, &arg_mount_auto, "Manager" },
- { "SwapAuto", config_parse_bool, &arg_swap_auto, "Manager" },
- { "DefaultControllers", config_parse_strv, &arg_default_controllers, "Manager" },
- { "DefaultStandardOutput", config_parse_output, &arg_default_std_output, "Manager" },
- { "DefaultStandardError", config_parse_output, &arg_default_std_error, "Manager" },
- { NULL, NULL, NULL, NULL }
+ { "CrashChVT", config_parse_int, 0, &arg_crash_chvt, "Manager" },
+ { "CPUAffinity", config_parse_cpu_affinity, 0, NULL, "Manager" },
+ { "MountAuto", config_parse_bool, 0, &arg_mount_auto, "Manager" },
+ { "SwapAuto", config_parse_bool, 0, &arg_swap_auto, "Manager" },
+ { "DefaultControllers", config_parse_strv, 0, &arg_default_controllers, "Manager" },
+ { "DefaultStandardOutput", config_parse_output, 0, &arg_default_std_output, "Manager" },
+ { "DefaultStandardError", config_parse_output, 0, &arg_default_std_error, "Manager" },
+ { NULL, NULL, 0, NULL, NULL }
};
static const char * const sections[] = {
@@ -544,6 +551,11 @@ static int parse_proc_cmdline(void) {
int r;
size_t l;
+ /* Don't read /proc/cmdline if we are in a container, since
+ * that is only relevant for the host system */
+ if (detect_container(NULL) > 0)
+ return 0;
+
if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
return 0;
@@ -624,7 +636,10 @@ static int parse_argv(int argc, char *argv[]) {
assert(argc >= 1);
assert(argv);
- while ((c = getopt_long(argc, argv, "hD", options, NULL)) >= 0)
+ if (getpid() == 1)
+ opterr = 0;
+
+ while ((c = getopt_long(argc, argv, "hDbsz:", options, NULL)) >= 0)
switch (c) {
@@ -800,23 +815,48 @@ static int parse_argv(int argc, char *argv[]) {
log_set_max_level(LOG_DEBUG);
break;
- case '?':
- return -EINVAL;
+ case 'b':
+ case 's':
+ case 'z':
+ /* Just to eat away the sysvinit kernel
+ * cmdline args without getopt() error
+ * messages that we'll parse in
+ * parse_proc_cmdline_word() or ignore. */
+ case '?':
default:
- log_error("Unknown option code %c", c);
- return -EINVAL;
+ if (getpid() != 1) {
+ log_error("Unknown option code %c", c);
+ return -EINVAL;
+ }
+
+ break;
}
- /* PID 1 will get the kernel arguments as parameters, which we
- * ignore and unconditionally read from
- * /proc/cmdline. However, we need to ignore those arguments
- * here. */
- if (arg_running_as != MANAGER_SYSTEM && optind < argc) {
+ if (optind < argc && getpid() != 1) {
+ /* Hmm, when we aren't run as init system
+ * let's complain about excess arguments */
+
log_error("Excess arguments.");
return -EINVAL;
}
+ if (detect_container(NULL) > 0) {
+ char **a;
+
+ /* All /proc/cmdline arguments the kernel didn't
+ * understand it passed to us. We're not really
+ * interested in that usually since /proc/cmdline is
+ * more interesting and complete. With one exception:
+ * if we are run in a container /proc/cmdline is not
+ * relevant for the container, hence we rely on argv[]
+ * instead. */
+
+ for (a = argv; a < argv + argc; a++)
+ if ((r = parse_proc_cmdline_word(*a)) < 0)
+ return r;
+ }
+
return 0;
}
@@ -942,20 +982,10 @@ static void test_mtab(void) {
}
static void test_usr(void) {
- bool separate = false;
/* Check that /usr is not a separate fs */
- if (path_is_mount_point("/usr") > 0)
- separate = 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)
- separate = true;
-
- if (!separate)
+ if (dir_is_empty("/usr") <= 0)
return;
log_warning("/usr appears to be on a different file system than /. This is not supported anymore. "
@@ -963,6 +993,20 @@ static void test_usr(void) {
"Consult http://freedesktop.org/wiki/Software/systemd/separate-usr-is-broken for more information.");
}
+static void test_cgroups(void) {
+
+ if (access("/proc/cgroups", F_OK) >= 0)
+ return;
+
+ log_warning("CONFIG_CGROUPS was not set when your kernel was compiled. "
+ "Systems without control groups are not supported. "
+ "We will now sleep for 10s, and then continue boot-up. "
+ "Expect breakage and please do not file bugs. "
+ "Instead fix your kernel and enable CONFIG_CGROUPS." );
+
+ sleep(10);
+}
+
int main(int argc, char *argv[]) {
Manager *m = NULL;
int r, retval = EXIT_FAILURE;
@@ -996,7 +1040,7 @@ int main(int argc, char *argv[]) {
if (getpid() == 1) {
arg_running_as = MANAGER_SYSTEM;
- log_set_target(LOG_TARGET_SYSLOG_OR_KMSG);
+ log_set_target(detect_container(NULL) > 0 ? LOG_TARGET_CONSOLE : LOG_TARGET_SYSLOG_OR_KMSG);
/* This might actually not return, but cause a
* reexecution */
@@ -1042,10 +1086,12 @@ int main(int argc, char *argv[]) {
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)
- arg_show_status = true;
+ if (arg_running_as == MANAGER_SYSTEM &&
+ arg_action == ACTION_RUN &&
+ running_in_chroot() > 0) {
+ log_error("Cannot be run in a chroot() environment.");
+ goto finish;
+ }
if (arg_action == ACTION_HELP) {
retval = help();
@@ -1086,6 +1132,9 @@ int main(int argc, char *argv[]) {
* kernel that don't really make sense for us. */
unsetenv("HOME");
unsetenv("TERM");
+
+ /* All other variables are left as is, so that clients
+ * can still read them via /proc/1/environ */
}
/* Move out of the way, so that we won't block unmounts */
@@ -1123,7 +1172,7 @@ int main(int argc, char *argv[]) {
if (arg_running_as == MANAGER_SYSTEM && !serialization) {
locale_setup();
- if (arg_show_status)
+ if (arg_show_status || plymouth_running())
status_welcome();
kmod_setup();
@@ -1131,10 +1180,9 @@ int main(int argc, char *argv[]) {
machine_id_setup();
loopback_setup();
- mkdir_p("/dev/.systemd/ask-password/", 0755);
-
test_mtab();
test_usr();
+ test_cgroups();
}
if ((r = manager_new(arg_running_as, &m)) < 0) {
diff --git a/src/manager.c b/src/manager.c
index 194ad66a0..9b561c4ce 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -66,7 +66,8 @@
#define GC_QUEUE_USEC_MAX (10*USEC_PER_SEC)
/* Where clients shall send notification messages to */
-#define NOTIFY_SOCKET "/org/freedesktop/systemd1/notify"
+#define NOTIFY_SOCKET_SYSTEM "/run/systemd/notify"
+#define NOTIFY_SOCKET_USER "@/org/freedesktop/systemd1/notify"
static int manager_setup_notify(Manager *m) {
union {
@@ -88,9 +89,14 @@ static int manager_setup_notify(Manager *m) {
sa.sa.sa_family = AF_UNIX;
if (getpid() != 1)
- snprintf(sa.un.sun_path+1, sizeof(sa.un.sun_path)-1, NOTIFY_SOCKET "/%llu", random_ull());
- else
- strncpy(sa.un.sun_path+1, NOTIFY_SOCKET, sizeof(sa.un.sun_path)-1);
+ snprintf(sa.un.sun_path, sizeof(sa.un.sun_path), NOTIFY_SOCKET_USER "/%llu", random_ull());
+ else {
+ unlink(NOTIFY_SOCKET_SYSTEM);
+ strncpy(sa.un.sun_path, NOTIFY_SOCKET_SYSTEM, sizeof(sa.un.sun_path));
+ }
+
+ if (sa.un.sun_path[0] == '@')
+ sa.un.sun_path[0] = 0;
if (bind(m->notify_watch.fd, &sa.sa, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(sa.un.sun_path+1)) < 0) {
log_error("bind() failed: %m");
@@ -109,7 +115,10 @@ static int manager_setup_notify(Manager *m) {
if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->notify_watch.fd, &ev) < 0)
return -errno;
- if (!(m->notify_socket = strdup(sa.un.sun_path+1)))
+ if (sa.un.sun_path[0] == 0)
+ sa.un.sun_path[0] = '@';
+
+ if (!(m->notify_socket = strdup(sa.un.sun_path)))
return -ENOMEM;
log_debug("Using notification socket %s", m->notify_socket);
@@ -118,7 +127,7 @@ static int manager_setup_notify(Manager *m) {
}
static int enable_special_signals(Manager *m) {
- char fd;
+ int fd;
assert(m);
@@ -269,6 +278,8 @@ int manager_new(ManagerRunningAs running_as, Manager **_m) {
log_error("Failed to connect to audit log: %m");
#endif
+ m->taint_usr = dir_is_empty("/usr") > 0;
+
*_m = m;
return 0;
@@ -1412,7 +1423,8 @@ static int transaction_add_job_and_dependencies(
bool matters,
bool override,
bool conflicts,
- bool ignore_deps,
+ bool ignore_requirements,
+ bool ignore_order,
DBusError *e,
Job **_ret) {
Job *ret;
@@ -1460,20 +1472,20 @@ static int transaction_add_job_and_dependencies(
if (!(ret = transaction_add_one_job(m, type, unit, override, &is_new)))
return -ENOMEM;
- ret->ignore_deps = ret->ignore_deps || ignore_deps;
+ ret->ignore_order = ret->ignore_order || ignore_order;
/* Then, add a link to the job. */
if (!job_dependency_new(by, ret, matters, conflicts))
return -ENOMEM;
- if (is_new && !ignore_deps) {
+ if (is_new && !ignore_requirements) {
Set *following;
/* If we are following some other unit, make sure we
* add all dependencies of everybody following. */
if (unit_following_set(ret->unit, &following) > 0) {
SET_FOREACH(dep, following, i)
- if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, false, override, false, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) {
log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
if (e)
@@ -1486,7 +1498,7 @@ static int transaction_add_job_and_dependencies(
/* Finally, recursively add in all dependencies. */
if (type == JOB_START || type == JOB_RELOAD_OR_START) {
SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES], i)
- if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
if (r != -EBADR)
goto fail;
@@ -1495,7 +1507,7 @@ static int transaction_add_job_and_dependencies(
}
SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_BIND_TO], i)
- if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
if (r != -EBADR)
goto fail;
@@ -1505,7 +1517,7 @@ static int transaction_add_job_and_dependencies(
}
SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRES_OVERRIDABLE], i)
- if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) {
log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
if (e)
@@ -1513,7 +1525,7 @@ static int transaction_add_job_and_dependencies(
}
SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_WANTS], i)
- if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, JOB_START, dep, ret, false, false, false, false, ignore_order, e, NULL)) < 0) {
log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
if (e)
@@ -1521,7 +1533,7 @@ static int transaction_add_job_and_dependencies(
}
SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE], i)
- if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
if (r != -EBADR)
goto fail;
@@ -1531,7 +1543,7 @@ static int transaction_add_job_and_dependencies(
}
SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUISITE_OVERRIDABLE], i)
- if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e, NULL)) < 0) {
log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
if (e)
@@ -1539,7 +1551,7 @@ static int transaction_add_job_and_dependencies(
}
SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTS], i)
- if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e, NULL)) < 0) {
if (r != -EBADR)
goto fail;
@@ -1549,7 +1561,7 @@ static int transaction_add_job_and_dependencies(
}
SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_CONFLICTED_BY], i)
- if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e, NULL)) < 0) {
log_warning("Cannot add dependency job for unit %s, ignoring: %s", dep->meta.id, bus_error(e, r));
if (e)
@@ -1559,7 +1571,7 @@ static int transaction_add_job_and_dependencies(
} else if (type == JOB_STOP || type == JOB_RESTART || type == JOB_TRY_RESTART) {
SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_REQUIRED_BY], i)
- if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
if (r != -EBADR)
goto fail;
@@ -1569,7 +1581,7 @@ static int transaction_add_job_and_dependencies(
}
SET_FOREACH(dep, ret->unit->meta.dependencies[UNIT_BOUND_BY], i)
- if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, e, NULL)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, type, dep, ret, true, override, false, false, ignore_order, e, NULL)) < 0) {
if (r != -EBADR)
goto fail;
@@ -1616,7 +1628,7 @@ static int transaction_add_isolate_jobs(Manager *m) {
if (hashmap_get(m->transaction_jobs, u))
continue;
- if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, false, false, NULL, NULL)) < 0)
+ if ((r = transaction_add_job_and_dependencies(m, JOB_STOP, u, NULL, true, false, false, false, false, NULL, NULL)) < 0)
log_warning("Cannot add isolate job for unit %s, ignoring: %s", u->meta.id, strerror(-r));
}
@@ -1644,7 +1656,9 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
log_debug("Trying to enqueue job %s/%s/%s", unit->meta.id, job_type_to_string(type), job_mode_to_string(mode));
- if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false, mode == JOB_IGNORE_DEPENDENCIES, e, &ret)) < 0) {
+ if ((r = transaction_add_job_and_dependencies(m, type, unit, NULL, true, override, false,
+ mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
+ mode == JOB_IGNORE_DEPENDENCIES, e, &ret)) < 0) {
transaction_abort(m);
return r;
}
@@ -2059,7 +2073,17 @@ static int manager_process_signal_fd(Manager *m) {
return -errno;
}
- log_debug("Received SIG%s", strna(signal_to_string(sfsi.ssi_signo)));
+ if (sfsi.ssi_pid > 0) {
+ char *p = NULL;
+
+ get_process_name(sfsi.ssi_pid, &p);
+
+ log_debug("Received SIG%s from PID %lu (%s).",
+ strna(signal_to_string(sfsi.ssi_signo)),
+ (unsigned long) sfsi.ssi_pid, strna(p));
+ free(p);
+ } else
+ log_debug("Received SIG%s.", strna(signal_to_string(sfsi.ssi_signo)));
switch (sfsi.ssi_signo) {
@@ -2309,7 +2333,7 @@ static int process_event(Manager *m, struct epoll_event *ev) {
int manager_loop(Manager *m) {
int r;
- RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 1000);
+ RATELIMIT_DEFINE(rl, 1*USEC_PER_SEC, 50000);
assert(m);
m->exit_code = MANAGER_RUNNING;
@@ -2434,13 +2458,30 @@ void manager_send_unit_audit(Manager *m, Unit *u, int type, bool success) {
if (m->n_deserializing > 0)
return;
+ if (m->running_as != MANAGER_SYSTEM)
+ return;
+
+ if (u->meta.type != UNIT_SERVICE)
+ return;
+
if (!(p = unit_name_to_prefix_and_instance(u->meta.id))) {
log_error("Failed to allocate unit name for audit message: %s", strerror(ENOMEM));
return;
}
- if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0)
- log_error("Failed to send audit message: %m");
+ if (audit_log_user_comm_message(m->audit_fd, type, "", p, NULL, NULL, NULL, success) < 0) {
+ log_warning("Failed to send audit message: %m");
+
+ if (errno == EPERM) {
+ /* We aren't allowed to send audit messages?
+ * Then let's not retry again, to avoid
+ * spamming the user with the same and same
+ * messages over and over. */
+
+ audit_close(m->audit_fd);
+ m->audit_fd = -1;
+ }
+ }
free(p);
#endif
@@ -2550,22 +2591,20 @@ void manager_dispatch_bus_query_pid_done(
}
int manager_open_serialization(Manager *m, FILE **_f) {
- char *path;
+ char *path = NULL;
mode_t saved_umask;
int fd;
FILE *f;
assert(_f);
- if (m->running_as == MANAGER_SYSTEM) {
- mkdir_p("/dev/.systemd", 0755);
+ if (m->running_as == MANAGER_SYSTEM)
+ asprintf(&path, "/run/systemd/dump-%lu-XXXXXX", (unsigned long) getpid());
+ else
+ asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid());
- if (asprintf(&path, "/dev/.systemd/dump-%lu-XXXXXX", (unsigned long) getpid()) < 0)
- return -ENOMEM;
- } else {
- if (asprintf(&path, "/tmp/systemd-dump-%lu-XXXXXX", (unsigned long) getpid()) < 0)
- return -ENOMEM;
- }
+ if (!path)
+ return -ENOMEM;
saved_umask = umask(0077);
fd = mkostemp(path, O_RDWR|O_CLOEXEC);
@@ -2581,7 +2620,7 @@ int manager_open_serialization(Manager *m, FILE **_f) {
log_debug("Serializing state to %s", path);
free(path);
- if (!(f = fdopen(fd, "w+")) < 0)
+ if (!(f = fdopen(fd, "w+")))
return -errno;
*_f = f;
@@ -2817,7 +2856,8 @@ void manager_check_finished(Manager *m) {
dual_timestamp_get(&m->finish_timestamp);
- if (m->running_as == MANAGER_SYSTEM) {
+ if (m->running_as == MANAGER_SYSTEM && detect_container(NULL) <= 0) {
+
if (dual_timestamp_is_set(&m->initrd_timestamp)) {
log_info("Startup finished in %s (kernel) + %s (initrd) + %s (userspace) = %s.",
format_timespan(kernel, sizeof(kernel),
@@ -2862,7 +2902,7 @@ void manager_run_generators(Manager *m) {
if (!m->generator_unit_path) {
char *p;
- char system_path[] = "/dev/.systemd/generator-XXXXXX",
+ char system_path[] = "/run/systemd/generator-XXXXXX",
user_path[] = "/tmp/systemd-generator-XXXXXX";
if (!(p = mkdtemp(m->running_as == MANAGER_SYSTEM ? system_path : user_path))) {
@@ -2938,6 +2978,47 @@ int manager_set_default_controllers(Manager *m, char **controllers) {
return 0;
}
+void manager_recheck_syslog(Manager *m) {
+ Unit *u;
+
+ assert(m);
+
+ if (m->running_as != MANAGER_SYSTEM)
+ return;
+
+ if ((u = manager_get_unit(m, SPECIAL_SYSLOG_SOCKET))) {
+ SocketState state;
+
+ state = SOCKET(u)->state;
+
+ if (state != SOCKET_DEAD &&
+ state != SOCKET_FAILED &&
+ state != SOCKET_RUNNING) {
+
+ /* Hmm, the socket is not set up, or is still
+ * listening, let's better not try to use
+ * it. Note that we have no problem if the
+ * socket is completely down, since there
+ * might be a foreign /dev/log socket around
+ * and we want to make use of that.
+ */
+
+ log_close_syslog();
+ return;
+ }
+ }
+
+ if ((u = manager_get_unit(m, SPECIAL_SYSLOG_TARGET)))
+ if (TARGET(u)->state != TARGET_ACTIVE) {
+ log_close_syslog();
+ return;
+ }
+
+ /* Hmm, OK, so the socket is either fully up, or fully down,
+ * and the target is up, then let's make use of the socket */
+ log_open();
+}
+
static const char* const manager_running_as_table[_MANAGER_RUNNING_AS_MAX] = {
[MANAGER_SYSTEM] = "system",
[MANAGER_USER] = "user"
diff --git a/src/manager.h b/src/manager.h
index efca4ff7f..4b405d61c 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -211,6 +211,8 @@ struct Manager {
bool dispatching_run_queue:1;
bool dispatching_dbus_queue:1;
+ bool taint_usr:1;
+
bool show_status;
bool confirm_spawn;
#ifdef HAVE_SYSV_COMPAT
@@ -285,6 +287,8 @@ void manager_check_finished(Manager *m);
void manager_run_generators(Manager *m);
void manager_undo_generators(Manager *m);
+void manager_recheck_syslog(Manager *m);
+
const char *manager_running_as_to_string(ManagerRunningAs i);
ManagerRunningAs manager_running_as_from_string(const char *s);
diff --git a/src/missing.h b/src/missing.h
index ff5dcb409..35e209fba 100644
--- a/src/missing.h
+++ b/src/missing.h
@@ -36,6 +36,10 @@
#include "macro.h"
+#ifdef ARCH_MIPS
+#include
+#endif
+
#ifndef RLIMIT_RTTIME
#define RLIMIT_RTTIME 15
#endif
@@ -77,19 +81,42 @@ static inline int pivot_root(const char *new_root, const char *put_old) {
}
#ifdef __x86_64__
-#ifndef __NR_fanotify_init
-#define __NR_fanotify_init 300
-#endif
-#ifndef __NR_fanotify_mark
-#define __NR_fanotify_mark 301
-#endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 300
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 301
+# endif
+#elif defined _MIPS_SIM
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 4336
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 4337
+# endif
+# elif _MIPS_SIM == _MIPS_SIM_NABI32
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 6300
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 6301
+# endif
+# elif _MIPS_SIM == _MIPS_SIM_ABI64
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 5295
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 5296
+# endif
+# endif
#else
-#ifndef __NR_fanotify_init
-#define __NR_fanotify_init 338
-#endif
-#ifndef __NR_fanotify_mark
-#define __NR_fanotify_mark 339
-#endif
+# ifndef __NR_fanotify_init
+# define __NR_fanotify_init 338
+# endif
+# ifndef __NR_fanotify_mark
+# define __NR_fanotify_mark 339
+# endif
#endif
static inline int fanotify_init(unsigned int flags, unsigned int event_f_flags) {
@@ -122,4 +149,8 @@ struct btrfs_ioctl_vol_args {
#define BTRFS_SUPER_MAGIC 0x9123683E
#endif
+#ifndef MS_MOVE
+#define MS_MOVE 8192
+#endif
+
#endif
diff --git a/src/modules-load.c b/src/modules-load.c
index 2dd432695..3824b57de 100644
--- a/src/modules-load.c
+++ b/src/modules-load.c
@@ -99,17 +99,21 @@ int main(int argc, char *argv[]) {
}
f = fopen(fn, "re");
- free(fn);
if (!f) {
- if (errno == ENOENT)
+ if (errno == ENOENT) {
+ free(fn);
continue;
+ }
log_error("Failed to open %s: %m", fn);
+ free(fn);
r = EXIT_FAILURE;
continue;
}
+ free(fn);
+
for (;;) {
char line[LINE_MAX], *l, *t;
diff --git a/src/mount-setup.c b/src/mount-setup.c
index 5cbaee6be..a42ed4395 100644
--- a/src/mount-setup.c
+++ b/src/mount-setup.c
@@ -54,6 +54,7 @@ static const MountPoint mount_table[] = {
{ "devtmpfs", "/dev", "devtmpfs", "mode=755", MS_NOSUID, true },
{ "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV, true },
{ "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC, false },
+ { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
{ "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
{ "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
};
@@ -100,7 +101,7 @@ static int mount_one(const MountPoint *p) {
return r;
if (r > 0)
- return 0;
+ goto finish;
/* The access mode here doesn't really matter too much, since
* the mounted file system will take precedence anyway. */
@@ -121,6 +122,7 @@ static int mount_one(const MountPoint *p) {
return p->fatal ? -errno : 0;
}
+finish:
label_fix(p->where, false);
return 0;
@@ -227,8 +229,7 @@ int mount_setup(void) {
"/proc/self/fd\0" "/dev/fd\0"
"/proc/self/fd/0\0" "/dev/stdin\0"
"/proc/self/fd/1\0" "/dev/stdout\0"
- "/proc/self/fd/2\0" "/dev/stderr\0"
- "\0";
+ "/proc/self/fd/2\0" "/dev/stderr\0";
int r;
unsigned i;
@@ -242,8 +243,10 @@ int mount_setup(void) {
* appropriate labels, after mounting. The other virtual API
* file systems do not need. */
- if (unlink("/dev/.systemd/relabel-devtmpfs") >= 0)
+ if (unlink("/dev/.systemd-relabel-run-dev") >= 0) {
nftw("/dev", nftw_cb, 64, FTW_MOUNT|FTW_PHYS);
+ nftw("/run", nftw_cb, 64, FTW_MOUNT|FTW_PHYS);
+ }
/* Create a few default symlinks, which are normally created
* bei udevd, but some scripts might need them before we start
@@ -252,5 +255,9 @@ int mount_setup(void) {
NULSTR_FOREACH_PAIR(j, k, symlinks)
symlink_and_label(j, k);
+ /* Create a few directories we always want around */
+ mkdir("/run/systemd", 0755);
+ mkdir("/run/systemd/ask-password", 0755);
+
return mount_cgroup_controllers();
}
diff --git a/src/mount.c b/src/mount.c
index 00780101a..49bfd079a 100644
--- a/src/mount.c
+++ b/src/mount.c
@@ -37,6 +37,7 @@
#include "special.h"
#include "bus-errors.h"
#include "exit-status.h"
+#include "def.h"
static const UnitActiveState state_translation_table[_MOUNT_STATE_MAX] = {
[MOUNT_DEAD] = UNIT_INACTIVE,
@@ -127,6 +128,26 @@ static void mount_done(Unit *u) {
unit_unwatch_timer(u, &m->timer_watch);
}
+static MountParameters* get_mount_parameters_configured(Mount *m) {
+ assert(m);
+
+ if (m->from_fragment)
+ return &m->parameters_fragment;
+ else if (m->from_etc_fstab)
+ return &m->parameters_etc_fstab;
+
+ return NULL;
+}
+
+static MountParameters* get_mount_parameters(Mount *m) {
+ assert(m);
+
+ if (m->from_proc_self_mountinfo)
+ return &m->parameters_proc_self_mountinfo;
+
+ return get_mount_parameters_configured(m);
+}
+
static int mount_add_mount_links(Mount *m) {
Meta *other;
int r;
@@ -134,12 +155,7 @@ static int mount_add_mount_links(Mount *m) {
assert(m);
- if (m->from_fragment)
- pm = &m->parameters_fragment;
- else if (m->from_etc_fstab)
- pm = &m->parameters_etc_fstab;
- else
- pm = NULL;
+ pm = get_mount_parameters_configured(m);
/* Adds in links to other mount points that might lie below or
* above us in the hierarchy */
@@ -154,19 +170,14 @@ static int mount_add_mount_links(Mount *m) {
if (n->meta.load_state != UNIT_LOADED)
continue;
- if (n->from_fragment)
- pn = &n->parameters_fragment;
- else if (n->from_etc_fstab)
- pn = &n->parameters_etc_fstab;
- else
- pn = NULL;
+ pn = get_mount_parameters_configured(n);
if (path_startswith(m->where, n->where)) {
if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
return r;
- if (n->from_etc_fstab || n->from_fragment)
+ if (pn)
if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
return r;
@@ -175,7 +186,7 @@ static int mount_add_mount_links(Mount *m) {
if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0)
return r;
- if (m->from_etc_fstab || m->from_fragment)
+ if (pm)
if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
return r;
@@ -184,18 +195,16 @@ static int mount_add_mount_links(Mount *m) {
if ((r = unit_add_dependency(UNIT(m), UNIT_AFTER, UNIT(n), true)) < 0)
return r;
- if (m->from_etc_fstab || m->from_fragment)
- if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
- return r;
+ if ((r = unit_add_dependency(UNIT(m), UNIT_REQUIRES, UNIT(n), true)) < 0)
+ return r;
} else if (pn && path_startswith(pn->what, m->where)) {
if ((r = unit_add_dependency(UNIT(n), UNIT_AFTER, UNIT(m), true)) < 0)
return r;
- if (n->from_etc_fstab || n->from_fragment)
- if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
- return r;
+ if ((r = unit_add_dependency(UNIT(n), UNIT_REQUIRES, UNIT(m), true)) < 0)
+ return r;
}
}
@@ -271,6 +280,43 @@ static char* mount_test_option(const char *haystack, const char *needle) {
return hasmntopt(&me, needle);
}
+static bool mount_is_network(MountParameters *p) {
+ assert(p);
+
+ if (mount_test_option(p->options, "_netdev"))
+ return true;
+
+ if (p->fstype && fstype_is_network(p->fstype))
+ return true;
+
+ return false;
+}
+
+static bool mount_is_bind(MountParameters *p) {
+ assert(p);
+
+ if (mount_test_option(p->options, "bind"))
+ return true;
+
+ if (p->fstype && streq(p->fstype, "bind"))
+ return true;
+
+ return false;
+}
+
+static bool needs_quota(MountParameters *p) {
+ assert(p);
+
+ if (mount_is_network(p))
+ return false;
+
+ if (mount_is_bind(p))
+ return false;
+
+ return mount_test_option(p->options, "usrquota") ||
+ mount_test_option(p->options, "grpquota");
+}
+
static int mount_add_target_links(Mount *m) {
const char *target, *after = NULL;
MountParameters *p;
@@ -280,11 +326,7 @@ static int mount_add_target_links(Mount *m) {
assert(m);
- if (m->from_fragment)
- p = &m->parameters_fragment;
- else if (m->from_etc_fstab)
- p = &m->parameters_etc_fstab;
- else
+ if (!(p = get_mount_parameters_configured(m)))
return 0;
noauto = !!mount_test_option(p->options, MNTOPT_NOAUTO);
@@ -297,8 +339,7 @@ static int mount_add_target_links(Mount *m) {
mount_test_option(p->options, "comment=systemd.automount") ||
mount_test_option(p->options, "x-systemd-automount");
- if (mount_test_option(p->options, "_netdev") ||
- (p->fstype && fstype_is_network(p->fstype))) {
+ if (mount_is_network(p)) {
target = SPECIAL_REMOTE_FS_TARGET;
if (m->meta.manager->running_as == MANAGER_SYSTEM)
@@ -336,29 +377,13 @@ static int mount_add_target_links(Mount *m) {
}
}
-static bool mount_is_bind(MountParameters *p) {
- assert(p);
-
- if (p->fstype && streq(p->fstype, "bind"))
- return true;
-
- if (mount_test_option(p->options, "bind"))
- return true;
-
- return false;
-}
-
static int mount_add_device_links(Mount *m) {
MountParameters *p;
int r;
assert(m);
- if (m->from_fragment)
- p = &m->parameters_fragment;
- else if (m->from_etc_fstab)
- p = &m->parameters_etc_fstab;
- else
+ if (!(p = get_mount_parameters_configured(m)))
return 0;
if (!p->what)
@@ -412,9 +437,15 @@ static int mount_add_default_dependencies(Mount *m) {
if (m->meta.manager->running_as == MANAGER_SYSTEM &&
!path_equal(m->where, "/")) {
+ MountParameters *p;
- if ((r = unit_add_dependency_by_name(UNIT(m), UNIT_BEFORE, SPECIAL_QUOTACHECK_SERVICE, NULL, true)) < 0)
- return r;
+ p = get_mount_parameters_configured(m);
+
+ if (p && needs_quota(p)) {
+ if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTACHECK_SERVICE, NULL, true)) < 0 ||
+ (r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_WANTS, SPECIAL_QUOTAON_SERVICE, NULL, true)) < 0)
+ return r;
+ }
if ((r = unit_add_two_dependencies_by_name(UNIT(m), UNIT_BEFORE, UNIT_CONFLICTS, SPECIAL_UMOUNT_TARGET, NULL, true)) < 0)
return r;
@@ -445,6 +476,11 @@ static int mount_verify(Mount *m) {
return -EINVAL;
}
+ if (mount_point_is_api(m->where) || mount_point_ignore(m->where)) {
+ log_error("Cannot create mount unit for API file system %s. Refusing.", m->where);
+ return -EINVAL;
+ }
+
if (m->meta.fragment_path && !m->parameters_fragment.what) {
log_error("%s's What setting is missing. Refusing.", m->meta.id);
return -EBADMSG;
@@ -626,12 +662,7 @@ static void mount_dump(Unit *u, FILE *f, const char *prefix) {
assert(m);
assert(f);
- if (m->from_proc_self_mountinfo)
- p = &m->parameters_proc_self_mountinfo;
- else if (m->from_fragment)
- p = &m->parameters_fragment;
- else
- p = &m->parameters_etc_fstab;
+ p = get_mount_parameters(m);
fprintf(f,
"%sMount State: %s\n"
@@ -733,9 +764,7 @@ static void mount_enter_signal(Mount *m, MountState state, bool success) {
state == MOUNT_REMOUNTING_SIGTERM) ? m->exec_context.kill_signal : SIGKILL;
if (m->control_pid > 0) {
- if (kill_and_sigcont(m->exec_context.kill_mode == KILL_PROCESS_GROUP ?
- -m->control_pid :
- m->control_pid, sig) < 0 && errno != ESRCH)
+ if (kill_and_sigcont(m->control_pid, sig) < 0 && errno != ESRCH)
log_warning("Failed to kill control process %li: %m", (long) m->control_pid);
else
@@ -761,6 +790,7 @@ static void mount_enter_signal(Mount *m, MountState state, bool success) {
wait_for_exit = true;
set_free(pid_set);
+ pid_set = NULL;
}
}
@@ -822,6 +852,7 @@ fail:
static void mount_enter_mounting(Mount *m) {
int r;
+ MountParameters *p;
assert(m);
@@ -830,6 +861,11 @@ static void mount_enter_mounting(Mount *m) {
mkdir_p(m->where, m->directory_mode);
+ /* Create the source directory for bind-mounts if needed */
+ p = get_mount_parameters_configured(m);
+ if (p && mount_is_bind(p))
+ mkdir_p(p->what, m->directory_mode);
+
if (m->from_fragment)
r = exec_command_set(
m->control_command,
@@ -1269,9 +1305,7 @@ static int mount_add_one(
/* Ignore API mount points. They should never be referenced in
* dependencies ever. */
- if (mount_point_is_api(where))
- return 0;
- if (mount_point_ignore(where))
+ if (mount_point_is_api(where) || mount_point_ignore(where))
return 0;
if (streq(fstype, "autofs"))
@@ -1666,7 +1700,7 @@ static int mount_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError
}
if (m->control_pid > 0)
- if (kill(mode == KILL_PROCESS_GROUP ? -m->control_pid : m->control_pid, signo) < 0)
+ if (kill(m->control_pid, signo) < 0)
r = -errno;
if (mode == KILL_CONTROL_GROUP) {
diff --git a/src/nspawn.c b/src/nspawn.c
new file mode 100644
index 000000000..6b0ba4e57
--- /dev/null
+++ b/src/nspawn.c
@@ -0,0 +1,800 @@
+/*-*- 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 .
+***/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "log.h"
+#include "util.h"
+#include "missing.h"
+#include "cgroup-util.h"
+#include "sd-daemon.h"
+#include "strv.h"
+
+static char *arg_directory = NULL;
+
+static int help(void) {
+
+ printf("%s [OPTIONS...] [PATH] [ARGUMENTS...]\n\n"
+ "Spawn a minimal namespace container for debugging, testing and building.\n\n"
+ " -h --help Show this help\n"
+ " -D --directory=NAME Root directory for the container\n",
+ program_invocation_short_name);
+
+ return 0;
+}
+
+static int parse_argv(int argc, char *argv[]) {
+
+ static const struct option options[] = {
+ { "help", no_argument, NULL, 'h' },
+ { "directory", required_argument, NULL, 'D' },
+ { NULL, 0, NULL, 0 }
+ };
+
+ int c;
+
+ assert(argc >= 0);
+ assert(argv);
+
+ while ((c = getopt_long(argc, argv, "+hD:", options, NULL)) >= 0) {
+
+ switch (c) {
+
+ case 'h':
+ help();
+ return 0;
+
+ case 'D':
+ free(arg_directory);
+ if (!(arg_directory = strdup(optarg))) {
+ log_error("Failed to duplicate root directory.");
+ return -ENOMEM;
+ }
+
+ break;
+
+ case '?':
+ return -EINVAL;
+
+ default:
+ log_error("Unknown option code %c", c);
+ return -EINVAL;
+ }
+ }
+
+ return 1;
+}
+
+static int mount_all(const char *dest) {
+
+ typedef struct MountPoint {
+ const char *what;
+ const char *where;
+ const char *type;
+ const char *options;
+ unsigned long flags;
+ bool fatal;
+ } MountPoint;
+
+ static const MountPoint mount_table[] = {
+ { "proc", "/proc", "proc", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+ { "/proc/sys", "/proc/sys", "bind", NULL, MS_BIND, true }, /* Bind mount first */
+ { "/proc/sys", "/proc/sys", "bind", NULL, MS_BIND|MS_RDONLY|MS_REMOUNT, true }, /* Then, make it r/o */
+ { "sysfs", "/sys", "sysfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, true },
+ { "tmpfs", "/dev", "tmpfs", "mode=755", MS_NOSUID, true },
+ { "/dev/pts", "/dev/pts", "bind", NULL, MS_BIND, true },
+ { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV, true },
+#ifdef HAVE_SELINUX
+ { "selinux", "/selinux", "selinuxfs", NULL, MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_RDONLY, false },
+#endif
+ };
+
+ unsigned k;
+ int r = 0;
+ char *where;
+
+ for (k = 0; k < ELEMENTSOF(mount_table); k++) {
+ int t;
+
+ if (asprintf(&where, "%s/%s", dest, mount_table[k].where) < 0) {
+ log_error("Out of memory");
+
+ if (r == 0)
+ r = -ENOMEM;
+
+ break;
+ }
+
+ if ((t = path_is_mount_point(where)) < 0) {
+ log_error("Failed to detect whether %s is a mount point: %s", where, strerror(-t));
+ free(where);
+
+ if (r == 0)
+ r = t;
+
+ continue;
+ }
+
+ mkdir_p(where, 0755);
+
+ if (mount(mount_table[k].what,
+ where,
+ mount_table[k].type,
+ mount_table[k].flags,
+ mount_table[k].options) < 0 &&
+ mount_table[k].fatal) {
+
+ log_error("mount(%s) failed: %m", where);
+
+ if (r == 0)
+ r = -errno;
+ }
+
+ free(where);
+ }
+
+ /* Fix the timezone, if possible */
+ if (asprintf(&where, "%s/%s", dest, "/etc/localtime") >= 0) {
+ mount("/etc/localtime", where, "bind", MS_BIND, NULL);
+ mount("/etc/localtime", where, "bind", MS_BIND|MS_REMOUNT|MS_RDONLY, NULL);
+ free(where);
+ }
+
+ return r;
+}
+
+static int copy_devnodes(const char *dest, const char *console) {
+
+ static const char devnodes[] =
+ "null\0"
+ "zero\0"
+ "full\0"
+ "random\0"
+ "urandom\0"
+ "tty\0"
+ "ptmx\0"
+ "kmsg\0"
+ "rtc0\0";
+
+ const char *d;
+ int r = 0, k;
+ mode_t u;
+ struct stat st;
+ char *from = NULL, *to = NULL;
+
+ assert(dest);
+ assert(console);
+
+ u = umask(0000);
+
+ NULSTR_FOREACH(d, devnodes) {
+ from = to = NULL;
+
+ asprintf(&from, "/dev/%s", d);
+ asprintf(&to, "%s/dev/%s", dest, d);
+
+ if (!from || !to) {
+ log_error("Failed to allocate devnode path");
+
+ free(from);
+ free(to);
+
+ from = to = NULL;
+
+ if (r == 0)
+ r = -ENOMEM;
+
+ break;
+ }
+
+ if (stat(from, &st) < 0) {
+
+ if (errno != ENOENT) {
+ log_error("Failed to stat %s: %m", from);
+ if (r == 0)
+ r = -errno;
+ }
+
+ } else if (!S_ISCHR(st.st_mode) && !S_ISBLK(st.st_mode)) {
+
+ log_error("%s is not a char or block device, cannot copy.", from);
+ if (r == 0)
+ r = -EIO;
+
+ } else if (mknod(to, st.st_mode, st.st_rdev) < 0) {
+
+ log_error("mknod(%s) failed: %m", dest);
+ if (r == 0)
+ r = -errno;
+ }
+
+ free(from);
+ free(to);
+ }
+
+ if (stat(console, &st) < 0) {
+
+ log_error("Failed to stat %s: %m", console);
+ if (r == 0)
+ r = -errno;
+
+ goto finish;
+
+ } else if (!S_ISCHR(st.st_mode)) {
+
+ log_error("/dev/console is not a char device.");
+ if (r == 0)
+ r = -EIO;
+
+ goto finish;
+ }
+
+ if (asprintf(&to, "%s/dev/console", dest) < 0) {
+
+ log_error("Out of memory");
+ if (r == 0)
+ r = -ENOMEM;
+
+ goto finish;
+ }
+
+ /* We need to bind mount the right tty to /dev/console since
+ * ptys can only exist on pts file systems. To have something
+ * to bind mount things on we create a device node first, that
+ * has the right major/minor (note that the major minor
+ * doesn't actually matter here, since we mount it over
+ * anyway). */
+
+ if (mknod(to, (st.st_mode & ~07777) | 0600, st.st_rdev) < 0)
+ log_error("mknod for /dev/console failed: %m");
+
+ if (mount(console, to, "bind", MS_BIND, NULL) < 0) {
+ log_error("bind mount for /dev/console failed: %m");
+
+ if (r == 0)
+ r = -errno;
+ }
+
+ free(to);
+
+ if ((k = chmod_and_chown(console, 0600, 0, 0)) < 0) {
+ log_error("Failed to correct access mode for TTY: %s", strerror(-k));
+
+ if (r == 0)
+ r = k;
+ }
+
+finish:
+
+ umask(u);
+
+ return r;
+}
+
+static int drop_capabilities(void) {
+ static const unsigned long retain[] = {
+ CAP_CHOWN,
+ CAP_DAC_OVERRIDE,
+ CAP_DAC_READ_SEARCH,
+ CAP_FOWNER,
+ CAP_FSETID,
+ CAP_IPC_OWNER,
+ CAP_KILL,
+ CAP_LEASE,
+ CAP_LINUX_IMMUTABLE,
+ CAP_NET_BIND_SERVICE,
+ CAP_NET_BROADCAST,
+ CAP_NET_RAW,
+ CAP_SETGID,
+ CAP_SETFCAP,
+ CAP_SETPCAP,
+ CAP_SETUID,
+ CAP_SYS_ADMIN,
+ CAP_SYS_CHROOT,
+ CAP_SYS_NICE,
+ CAP_SYS_PTRACE,
+ CAP_SYS_TTY_CONFIG
+ };
+
+ unsigned long l;
+
+ for (l = 0; l <= MAX(63LU, (unsigned long) CAP_LAST_CAP); l ++) {
+ unsigned i;
+
+ for (i = 0; i < ELEMENTSOF(retain); i++)
+ if (retain[i] == l)
+ break;
+
+ if (i < ELEMENTSOF(retain))
+ continue;
+
+ if (prctl(PR_CAPBSET_DROP, l) < 0) {
+
+ /* If this capability is not known, EINVAL
+ * will be returned, let's ignore this. */
+ if (errno == EINVAL)
+ continue;
+
+ log_error("PR_CAPBSET_DROP failed: %m");
+ return -errno;
+ }
+ }
+
+ return 0;
+}
+
+static int is_os_tree(const char *path) {
+ int r;
+ char *p;
+ /* We use /bin/sh as flag file if something is an OS */
+
+ if (asprintf(&p, "%s/bin/sh", path) < 0)
+ return -ENOMEM;
+
+ r = access(p, F_OK);
+ free(p);
+
+ return r < 0 ? 0 : 1;
+}
+
+#define BUFFER_SIZE 1024
+
+static int process_pty(int master, sigset_t *mask) {
+ char in_buffer[BUFFER_SIZE], out_buffer[BUFFER_SIZE];
+ size_t in_buffer_full = 0, out_buffer_full = 0;
+ struct epoll_event stdin_ev, stdout_ev, master_ev, signal_ev;
+ bool stdin_readable = false, stdout_writable = false, master_readable = false, master_writable = false;
+ int ep = -1, signal_fd = -1, r;
+
+ fd_nonblock(STDIN_FILENO, 1);
+ fd_nonblock(STDOUT_FILENO, 1);
+ fd_nonblock(master, 1);
+
+ if ((signal_fd = signalfd(-1, mask, SFD_NONBLOCK|SFD_CLOEXEC)) < 0) {
+ log_error("signalfd(): %m");
+ r = -errno;
+ goto finish;
+ }
+
+ if ((ep = epoll_create1(EPOLL_CLOEXEC)) < 0) {
+ log_error("Failed to create epoll: %m");
+ r = -errno;
+ goto finish;
+ }
+
+ zero(stdin_ev);
+ stdin_ev.events = EPOLLIN|EPOLLET;
+ stdin_ev.data.fd = STDIN_FILENO;
+
+ zero(stdout_ev);
+ stdout_ev.events = EPOLLOUT|EPOLLET;
+ stdout_ev.data.fd = STDOUT_FILENO;
+
+ zero(master_ev);
+ master_ev.events = EPOLLIN|EPOLLOUT|EPOLLET;
+ master_ev.data.fd = master;
+
+ zero(signal_ev);
+ signal_ev.events = EPOLLIN;
+ signal_ev.data.fd = signal_fd;
+
+ if (epoll_ctl(ep, EPOLL_CTL_ADD, STDIN_FILENO, &stdin_ev) < 0 ||
+ epoll_ctl(ep, EPOLL_CTL_ADD, STDOUT_FILENO, &stdout_ev) < 0 ||
+ epoll_ctl(ep, EPOLL_CTL_ADD, master, &master_ev) < 0 ||
+ epoll_ctl(ep, EPOLL_CTL_ADD, signal_fd, &signal_ev) < 0) {
+ log_error("Failed to regiser fds in epoll: %m");
+ r = -errno;
+ goto finish;
+ }
+
+ for (;;) {
+ struct epoll_event ev[16];
+ ssize_t k;
+ int i, nfds;
+
+ if ((nfds = epoll_wait(ep, ev, ELEMENTSOF(ev), -1)) < 0) {
+
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+
+ log_error("epoll_wait(): %m");
+ r = -errno;
+ goto finish;
+ }
+
+ assert(nfds >= 1);
+
+ for (i = 0; i < nfds; i++) {
+ if (ev[i].data.fd == STDIN_FILENO) {
+
+ if (ev[i].events & (EPOLLIN|EPOLLHUP))
+ stdin_readable = true;
+
+ } else if (ev[i].data.fd == STDOUT_FILENO) {
+
+ if (ev[i].events & (EPOLLOUT|EPOLLHUP))
+ stdout_writable = true;
+
+ } else if (ev[i].data.fd == master) {
+
+ if (ev[i].events & (EPOLLIN|EPOLLHUP))
+ master_readable = true;
+
+ if (ev[i].events & (EPOLLOUT|EPOLLHUP))
+ master_writable = true;
+
+ } else if (ev[i].data.fd == signal_fd) {
+ struct signalfd_siginfo sfsi;
+ ssize_t n;
+
+ if ((n = read(signal_fd, &sfsi, sizeof(sfsi))) != sizeof(sfsi)) {
+
+ if (n >= 0) {
+ r = -EIO;
+ goto finish;
+ }
+
+ if (errno != EINTR && errno != EAGAIN) {
+ r = -errno;
+ goto finish;
+ }
+ } else {
+
+ if (sfsi.ssi_signo == SIGWINCH) {
+ struct winsize ws;
+
+ /* The window size changed, let's forward that. */
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
+ ioctl(master, TIOCSWINSZ, &ws);
+ } else {
+ r = -EINTR;
+ goto finish;
+ }
+ }
+ }
+ }
+
+ while ((stdin_readable && in_buffer_full <= 0) ||
+ (master_writable && in_buffer_full > 0) ||
+ (master_readable && out_buffer_full <= 0) ||
+ (stdout_writable && out_buffer_full > 0)) {
+
+ if (stdin_readable && in_buffer_full < BUFFER_SIZE) {
+
+ if ((k = read(STDIN_FILENO, in_buffer + in_buffer_full, BUFFER_SIZE - in_buffer_full)) < 0) {
+
+ if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
+ stdin_readable = false;
+ else {
+ log_error("read(): %m");
+ goto finish;
+ }
+ } else
+ in_buffer_full += (size_t) k;
+ }
+
+ if (master_writable && in_buffer_full > 0) {
+
+ if ((k = write(master, in_buffer, in_buffer_full)) < 0) {
+
+ if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
+ master_writable = false;
+ else {
+ log_error("write(): %m");
+ goto finish;
+ }
+
+ } else {
+ assert(in_buffer_full >= (size_t) k);
+ memmove(in_buffer, in_buffer + k, in_buffer_full - k);
+ in_buffer_full -= k;
+ }
+ }
+
+ if (master_readable && out_buffer_full < BUFFER_SIZE) {
+
+ if ((k = read(master, out_buffer + out_buffer_full, BUFFER_SIZE - out_buffer_full)) < 0) {
+
+ if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
+ master_readable = false;
+ else {
+ log_error("read(): %m");
+ goto finish;
+ }
+ } else
+ out_buffer_full += (size_t) k;
+ }
+
+ if (stdout_writable && out_buffer_full > 0) {
+
+ if ((k = write(STDOUT_FILENO, out_buffer, out_buffer_full)) < 0) {
+
+ if (errno == EAGAIN || errno == EPIPE || errno == ECONNRESET || errno == EIO)
+ stdout_writable = false;
+ else {
+ log_error("write(): %m");
+ goto finish;
+ }
+
+ } else {
+ assert(out_buffer_full >= (size_t) k);
+ memmove(out_buffer, out_buffer + k, out_buffer_full - k);
+ out_buffer_full -= k;
+ }
+ }
+ }
+ }
+
+finish:
+ if (ep >= 0)
+ close_nointr_nofail(ep);
+
+ if (signal_fd >= 0)
+ close_nointr_nofail(signal_fd);
+
+ return r;
+}
+
+int main(int argc, char *argv[]) {
+ pid_t pid = 0;
+ int r = EXIT_FAILURE, k;
+ char *oldcg = NULL, *newcg = NULL;
+ int master = -1;
+ const char *console = NULL;
+ struct termios saved_attr, raw_attr;
+ sigset_t mask;
+ bool saved_attr_valid = false;
+ struct winsize ws;
+
+ log_parse_environment();
+ log_open();
+
+ if ((r = parse_argv(argc, argv)) <= 0)
+ goto finish;
+
+ if (arg_directory) {
+ char *p;
+
+ p = path_make_absolute_cwd(arg_directory);
+ free(arg_directory);
+ arg_directory = p;
+ } else
+ arg_directory = get_current_dir_name();
+
+ if (!arg_directory) {
+ log_error("Failed to determine path");
+ goto finish;
+ }
+
+ path_kill_slashes(arg_directory);
+
+ if (geteuid() != 0) {
+ log_error("Need to be root.");
+ goto finish;
+ }
+
+ if (sd_booted() <= 0) {
+ log_error("Not running on a systemd system.");
+ goto finish;
+ }
+
+ if (path_equal(arg_directory, "/")) {
+ log_error("Spawning container on root directory not supported.");
+ goto finish;
+ }
+
+ if (is_os_tree(arg_directory) <= 0) {
+ log_error("Directory %s doesn't look like an OS root directory. Refusing.", arg_directory);
+ goto finish;
+ }
+
+ if ((k = cg_get_by_pid(SYSTEMD_CGROUP_CONTROLLER, 0, &oldcg)) < 0) {
+ log_error("Failed to determine current cgroup: %s", strerror(-k));
+ goto finish;
+ }
+
+ if (asprintf(&newcg, "%s/nspawn-%lu", oldcg, (unsigned long) getpid()) < 0) {
+ log_error("Failed to allocate cgroup path.");
+ goto finish;
+ }
+
+ if ((k = cg_create_and_attach(SYSTEMD_CGROUP_CONTROLLER, newcg, 0)) < 0) {
+ log_error("Failed to create cgroup: %s", strerror(-k));
+ goto finish;
+ }
+
+ if ((master = posix_openpt(O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY)) < 0) {
+ log_error("Failed to acquire pseudo tty: %m");
+ goto finish;
+ }
+
+ if (!(console = ptsname(master))) {
+ log_error("Failed to determine tty name: %m");
+ goto finish;
+ }
+
+ log_info("Spawning namespace container on %s (console is %s).", arg_directory, console);
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) >= 0)
+ ioctl(master, TIOCSWINSZ, &ws);
+
+ if (unlockpt(master) < 0) {
+ log_error("Failed to unlock tty: %m");
+ goto finish;
+ }
+
+ if (tcgetattr(STDIN_FILENO, &saved_attr) < 0) {
+ log_error("Failed to get terminal attributes: %m");
+ goto finish;
+ }
+
+ saved_attr_valid = true;
+
+ raw_attr = saved_attr;
+ cfmakeraw(&raw_attr);
+ raw_attr.c_lflag &= ~ECHO;
+
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &raw_attr) < 0) {
+ log_error("Failed to set terminal attributes: %m");
+ goto finish;
+ }
+
+ assert_se(sigemptyset(&mask) == 0);
+ sigset_add_many(&mask, SIGCHLD, SIGWINCH, SIGTERM, SIGINT, -1);
+ assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
+
+ if ((pid = syscall(__NR_clone, SIGCHLD|CLONE_NEWIPC|CLONE_NEWNS|CLONE_NEWPID|CLONE_NEWUTS, NULL)) < 0) {
+ log_error("clone() failed: %m");
+ goto finish;
+ }
+
+ if (pid == 0) {
+ /* child */
+
+ const char *hn;
+ const char *envp[] = {
+ "HOME=/root",
+ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
+ NULL,
+ NULL
+ };
+
+ envp[2] = strv_find_prefix(environ, "TERM=");
+
+ close_nointr_nofail(master);
+
+ close_nointr(STDIN_FILENO);
+ close_nointr(STDOUT_FILENO);
+ close_nointr(STDERR_FILENO);
+
+ close_all_fds(NULL, 0);
+
+ reset_all_signal_handlers();
+
+ assert_se(sigemptyset(&mask) == 0);
+ assert_se(sigprocmask(SIG_SETMASK, &mask, NULL) == 0);
+
+ if (setsid() < 0)
+ goto child_fail;
+
+ if (prctl(PR_SET_PDEATHSIG, SIGKILL) < 0)
+ goto child_fail;
+
+ if (mount_all(arg_directory) < 0)
+ goto child_fail;
+
+ if (copy_devnodes(arg_directory, console) < 0)
+ goto child_fail;
+
+ if (chdir(arg_directory) < 0) {
+ log_error("chdir(%s) failed: %m", arg_directory);
+ goto child_fail;
+ }
+
+ if (open_terminal("dev/console", O_RDWR) != STDIN_FILENO ||
+ dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO ||
+ dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO)
+ goto child_fail;
+
+ if (mount(arg_directory, "/", "bind", MS_BIND|MS_MOVE, NULL) < 0) {
+ log_error("mount(MS_MOVE) failed: %m");
+ goto child_fail;
+ }
+
+ if (chroot(".") < 0) {
+ log_error("chroot() failed: %m");
+ goto child_fail;
+ }
+
+ if (chdir("/") < 0) {
+ log_error("chdir() failed: %m");
+ goto child_fail;
+ }
+
+ umask(0002);
+
+ if (drop_capabilities() < 0)
+ goto child_fail;
+
+ if ((hn = file_name_from_path(arg_directory)))
+ sethostname(hn, strlen(hn));
+
+ if (argc > optind)
+ execvpe(argv[optind], argv + optind, (char**) envp);
+ else {
+ chdir("/root");
+ execle("/bin/bash", "-bash", NULL, (char**) envp);
+ }
+
+ log_error("execv() failed: %m");
+
+ child_fail:
+ _exit(EXIT_FAILURE);
+ }
+
+ if (process_pty(master, &mask) < 0)
+ goto finish;
+
+ if (saved_attr_valid) {
+ tcsetattr(STDIN_FILENO, TCSANOW, &saved_attr);
+ saved_attr_valid = false;
+ }
+
+ r = wait_for_terminate_and_warn(argc > optind ? argv[optind] : "bash", pid);
+
+ if (r < 0)
+ r = EXIT_FAILURE;
+
+finish:
+ if (saved_attr_valid)
+ tcsetattr(STDIN_FILENO, TCSANOW, &saved_attr);
+
+ if (master >= 0)
+ close_nointr_nofail(master);
+
+ if (oldcg)
+ cg_attach(SYSTEMD_CGROUP_CONTROLLER, oldcg, 0);
+
+ if (newcg)
+ cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, newcg, true);
+
+ free(arg_directory);
+ free(oldcg);
+ free(newcg);
+
+ return r;
+}
diff --git a/src/org.freedesktop.systemd1.conf b/src/org.freedesktop.systemd1.conf
index 6db71e2c8..8008f0f4b 100644
--- a/src/org.freedesktop.systemd1.conf
+++ b/src/org.freedesktop.systemd1.conf
@@ -50,6 +50,10 @@
send_interface="org.freedesktop.systemd1.Manager"
send_member="GetUnitByPID"/>
+
+
diff --git a/src/org.freedesktop.systemd1.policy b/src/org.freedesktop.systemd1.policy.in
similarity index 64%
rename from src/org.freedesktop.systemd1.policy
rename to src/org.freedesktop.systemd1.policy.in
index bb07b827f..b8b354726 100644
--- a/src/org.freedesktop.systemd1.policy
+++ b/src/org.freedesktop.systemd1.policy.in
@@ -24,7 +24,18 @@
no
auth_admin_keep
- /lib/systemd/systemd-reply-password
+ @rootlibexecdir@/systemd-reply-password
+
+
+
+ Privileged system and service manager access
+ Authentication is required to access the system and service manager.
+
+ no
+ no
+ auth_admin_keep
+
+ @bindir@/systemd-stdio-bridge
diff --git a/src/pam-module.c b/src/pam-module.c
index 7f9158470..6486546e6 100644
--- a/src/pam-module.c
+++ b/src/pam-module.c
@@ -198,8 +198,10 @@ static int open_file_and_lock(const char *fn) {
* as the filesystems in question should be local, and only
* locally accessible, and most likely even tmpfs. */
- if (flock(fd, LOCK_EX) < 0)
+ if (flock(fd, LOCK_EX) < 0) {
+ close_nointr_nofail(fd);
return -errno;
+ }
return fd;
}
@@ -237,11 +239,10 @@ static uint64_t get_session_id(int *mode) {
ssize_t r;
/* We do a bit of endianess swapping here, just to be
- * sure. /var should be machine specific anyway, and
- * /var/run even mounted from tmpfs, so this
- * byteswapping should really not be necessary. But
- * then again, you never know, so let's avoid any
- * risk. */
+ * sure. /run should be machine specific anyway, and
+ * even mounted from tmpfs, so this byteswapping
+ * should really not be necessary. But then again, you
+ * never know, so let's avoid any risk. */
if (loop_read(fd, &counter, sizeof(counter), false) != sizeof(counter))
counter = 1;
@@ -271,6 +272,7 @@ static uint64_t get_session_id(int *mode) {
/* Last attempt, pick a random value */
return (uint64_t) random_ull();
}
+
static int get_user_data(
pam_handle_t *handle,
const char **ret_username,
@@ -394,6 +396,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
int lock_fd = -1;
bool create_session = true;
char **controllers = NULL, **reset_controllers = NULL, **c;
+ char *cgroup_user_tree = NULL;
assert(handle);
@@ -413,6 +416,12 @@ _public_ PAM_EXTERN int pam_sm_open_session(
if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
goto finish;
+ if ((r = cg_get_user_path(&cgroup_user_tree)) < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to determine user cgroup tree: %s", strerror(-r));
+ r = PAM_SYSTEM_ERR;
+ goto finish;
+ }
+
if (safe_mkdir(RUNTIME_DIR "/user", 0755, 0, 0) < 0) {
pam_syslog(handle, LOG_ERR, "Failed to create runtime directory: %m");
r = PAM_SYSTEM_ERR;
@@ -425,7 +434,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
goto finish;
}
- /* Create /var/run/$USER */
+ /* Create /run/user/$USER */
free(buf);
if (asprintf(&buf, RUNTIME_DIR "/user/%s", username) < 0) {
r = PAM_BUF_ERR;
@@ -476,9 +485,9 @@ _public_ PAM_EXTERN int pam_sm_open_session(
}
}
- r = asprintf(&buf, "/user/%s/%s", username, id);
+ r = asprintf(&buf, "%s/%s/%s", cgroup_user_tree, username, id);
} else
- r = asprintf(&buf, "/user/%s/master", username);
+ r = asprintf(&buf, "%s/%s/master", cgroup_user_tree, username);
if (r < 0) {
r = PAM_BUF_ERR;
@@ -509,6 +518,8 @@ finish:
strv_free(controllers);
strv_free(reset_controllers);
+ free(cgroup_user_tree);
+
return r;
}
@@ -600,6 +611,7 @@ _public_ PAM_EXTERN int pam_sm_close_session(
struct passwd *pw;
const void *created = NULL;
char **controllers = NULL, **c, **kill_only_users = NULL, **kill_exclude_users = NULL;
+ char *cgroup_user_tree = NULL;
assert(handle);
@@ -617,6 +629,12 @@ _public_ PAM_EXTERN int pam_sm_close_session(
if ((r = get_user_data(handle, &username, &pw)) != PAM_SUCCESS)
goto finish;
+ if ((r = cg_get_user_path(&cgroup_user_tree)) < 0) {
+ pam_syslog(handle, LOG_ERR, "Failed to determine user cgroup tree: %s", strerror(-r));
+ r = PAM_SYSTEM_ERR;
+ goto finish;
+ }
+
if ((lock_fd = open_file_and_lock(RUNTIME_DIR "/user/.pam-systemd-lock")) < 0) {
pam_syslog(handle, LOG_ERR, "Failed to lock runtime directory: %m");
r = PAM_SYSTEM_ERR;
@@ -624,14 +642,14 @@ _public_ PAM_EXTERN int pam_sm_close_session(
}
/* We are probably still in some session/user dir. Move ourselves out of the way as first step */
- if ((r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, "/user", 0)) < 0)
+ if ((r = cg_attach(SYSTEMD_CGROUP_CONTROLLER, cgroup_user_tree, 0)) < 0)
pam_syslog(handle, LOG_ERR, "Failed to move us away: %s", strerror(-r));
STRV_FOREACH(c, controllers)
- if ((r = cg_attach(*c, "/user", 0)) < 0)
+ if ((r = cg_attach(*c, cgroup_user_tree, 0)) < 0)
pam_syslog(handle, LOG_ERR, "Failed to move us away in %s hierarchy: %s", *c, strerror(-r));
- if (asprintf(&user_path, "/user/%s", username) < 0) {
+ if (asprintf(&user_path, "%s/%s", cgroup_user_tree, username) < 0) {
r = PAM_BUF_ERR;
goto finish;
}
@@ -640,8 +658,8 @@ _public_ PAM_EXTERN int pam_sm_close_session(
if ((id = pam_getenv(handle, "XDG_SESSION_ID")) && created) {
- if (asprintf(&session_path, "/user/%s/%s", username, id) < 0 ||
- asprintf(&nosession_path, "/user/%s/master", username) < 0) {
+ if (asprintf(&session_path, "%s/%s/%s", cgroup_user_tree, username, id) < 0 ||
+ asprintf(&nosession_path, "%s/%s/master", cgroup_user_tree, username) < 0) {
r = PAM_BUF_ERR;
goto finish;
}
@@ -727,5 +745,7 @@ finish:
strv_free(kill_exclude_users);
strv_free(kill_only_users);
+ free(cgroup_user_tree);
+
return r;
}
diff --git a/src/path-lookup.c b/src/path-lookup.c
index f094969ad..b39ce8b69 100644
--- a/src/path-lookup.c
+++ b/src/path-lookup.c
@@ -102,7 +102,11 @@ static char** user_dirs(void) {
if ((e = getenv("XDG_DATA_DIRS")))
data_dirs = strv_split(e, ":");
else
- data_dirs = strv_new("/usr/local/share", "/usr/share", NULL);
+ data_dirs = strv_new("/usr/local/share",
+ "/usr/local/lib",
+ "/usr/share",
+ "/usr/lib",
+ NULL);
if (!data_dirs)
goto fail;
@@ -181,11 +185,15 @@ int lookup_paths_init(LookupPaths *p, ManagerRunningAs running_as) {
return -ENOMEM;
} else
if (!(p->unit_path = strv_new(
- "/dev/.systemd/system",
+ /* If you modify this you also want to modify
+ * systemdsystemunitpath= in systemd.pc.in! */
+ "/run/systemd/system",
SYSTEM_CONFIG_UNIT_PATH,
"/etc/systemd/system",
"/usr/local/share/systemd/system",
+ "/usr/local/lib/systemd/system",
"/usr/share/systemd/system",
+ "/usr/lib/systemd/system",
"/lib/systemd/system",
SYSTEM_DATA_UNIT_PATH,
NULL)))
diff --git a/src/quotacheck.c b/src/quotacheck.c
index 5ced93318..ba12b27ca 100644
--- a/src/quotacheck.c
+++ b/src/quotacheck.c
@@ -35,6 +35,9 @@ static int parse_proc_cmdline(void) {
int r;
size_t l;
+ if (detect_container(NULL) > 0)
+ return 0;
+
if ((r = read_one_line_file("/proc/cmdline", &line)) < 0) {
log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
return 0;
@@ -94,7 +97,7 @@ int main(int argc, char *argv[]) {
if (arg_skip)
return 0;
- if (access("/dev/.systemd/quotacheck", F_OK) < 0)
+ if (access("/run/systemd/quotacheck", F_OK) < 0)
return 0;
}
@@ -107,7 +110,7 @@ int main(int argc, char *argv[]) {
_exit(1); /* Operational error */
}
- r = wait_for_terminate_and_warn("quotacheck", pid) >= 0 ? EXIT_SUCCESS : EXIT_FAILURE;
+ r = wait_for_terminate_and_warn("quotacheck", pid) == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
finish:
return r;
diff --git a/src/random-seed.c b/src/random-seed.c
index 8eab2b4e1..054233e66 100644
--- a/src/random-seed.c
+++ b/src/random-seed.c
@@ -86,9 +86,11 @@ int main(int argc, char *argv[]) {
}
}
- if ((r = loop_read(seed_fd, buf, buf_size, false)) <= 0)
- log_error("Failed to read seed file: %s", r < 0 ? strerror(errno) : "EOF");
- else {
+ if ((r = loop_read(seed_fd, buf, buf_size, false)) <= 0) {
+
+ if (r != 0)
+ log_error("Failed to read seed file: %m");
+ } else {
lseek(seed_fd, 0, SEEK_SET);
if ((r = loop_write(random_fd, buf, (size_t) r, false)) <= 0)
diff --git a/src/readahead-collect.c b/src/readahead-collect.c
index 0970b5841..3c48a02fc 100644
--- a/src/readahead-collect.c
+++ b/src/readahead-collect.c
@@ -119,9 +119,10 @@ static int pack_file(FILE *pack, const char *fn, bool on_btrfs) {
goto finish;
}
- pages = l / PAGE_SIZE;
+ pages = l / page_size();
vec = alloca(pages);
+ memset(vec, 0, pages);
if (mincore(start, l, vec) < 0) {
log_warning("mincore(%s) failed: %m", fn);
r = -errno;
@@ -289,13 +290,13 @@ static int collect(const char *root) {
log_debug("Collecting...");
- if (access("/dev/.systemd/readahead/cancel", F_OK) >= 0) {
+ if (access("/run/systemd/readahead/cancel", F_OK) >= 0) {
log_debug("Collection canceled");
r = -ECANCELED;
goto finish;
}
- if (access("/dev/.systemd/readahead/done", F_OK) >= 0) {
+ if (access("/run/systemd/readahead/done", F_OK) >= 0) {
log_debug("Got termination request");
goto done;
}
diff --git a/src/readahead-common.c b/src/readahead-common.c
index e991dfd05..fc49a3310 100644
--- a/src/readahead-common.c
+++ b/src/readahead-common.c
@@ -167,11 +167,11 @@ int open_inotify(void) {
return -errno;
}
- mkdir("/dev/.systemd", 0755);
- mkdir("/dev/.systemd/readahead", 0755);
+ mkdir("/run/systemd", 0755);
+ mkdir("/run/systemd/readahead", 0755);
- if (inotify_add_watch(fd, "/dev/.systemd/readahead", IN_CREATE) < 0) {
- log_error("Failed to watch /dev/.systemd/readahead: %m");
+ if (inotify_add_watch(fd, "/run/systemd/readahead", IN_CREATE) < 0) {
+ log_error("Failed to watch /run/systemd/readahead: %m");
close_nointr_nofail(fd);
return -errno;
}
@@ -183,10 +183,10 @@ ReadaheadShared *shared_get(void) {
int fd;
ReadaheadShared *m = NULL;
- mkdir("/dev/.systemd", 0755);
- mkdir("/dev/.systemd/readahead", 0755);
+ mkdir("/run/systemd", 0755);
+ mkdir("/run/systemd/readahead", 0755);
- if ((fd = open("/dev/.systemd/readahead/shared", O_CREAT|O_RDWR|O_CLOEXEC, 0644)) < 0) {
+ if ((fd = open("/run/systemd/readahead/shared", O_CREAT|O_RDWR|O_CLOEXEC, 0644)) < 0) {
log_error("Failed to create shared memory segment: %m");
goto finish;
}
diff --git a/src/readahead-replay.c b/src/readahead-replay.c
index 3bea9295f..0b84528b0 100644
--- a/src/readahead-replay.c
+++ b/src/readahead-replay.c
@@ -94,7 +94,7 @@ static int unpack_file(FILE *pack) {
any = true;
if (fd >= 0)
- if (posix_fadvise(fd, b * PAGE_SIZE, (c - b) * PAGE_SIZE, POSIX_FADV_WILLNEED) < 0) {
+ if (posix_fadvise(fd, b * page_size(), (c - b) * page_size(), POSIX_FADV_WILLNEED) < 0) {
log_warning("posix_fadvise() failed: %m");
goto finish;
}
@@ -122,7 +122,8 @@ static int replay(const char *root) {
FILE *pack = NULL;
char line[LINE_MAX];
int r = 0;
- char *pack_fn = NULL, c;
+ char *pack_fn = NULL;
+ int c;
bool on_ssd, ready = false;
int prio;
int inotify_fd = -1;
@@ -192,7 +193,7 @@ static int replay(const char *root) {
log_debug("Replaying...");
- if (access("/dev/.systemd/readahead/noreplay", F_OK) >= 0) {
+ if (access("/run/systemd/readahead/noreplay", F_OK) >= 0) {
log_debug("Got termination request");
goto done;
}
diff --git a/src/sd-readahead.c b/src/sd-readahead.c
index 41e6d3d20..c5cfe6710 100644
--- a/src/sd-readahead.c
+++ b/src/sd-readahead.c
@@ -42,8 +42,8 @@ static int touch(const char *path) {
#if !defined(DISABLE_SYSTEMD) && defined(__linux__)
int fd;
- mkdir("/dev/.systemd", 0755);
- mkdir("/dev/.systemd/readahead", 0755);
+ mkdir("/run/systemd", 0755);
+ mkdir("/run/systemd/readahead", 0755);
if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0666)) < 0)
return -errno;
@@ -66,11 +66,11 @@ int sd_readahead(const char *action) {
return -EINVAL;
if (strcmp(action, "cancel") == 0)
- return touch("/dev/.systemd/readahead/cancel");
+ return touch("/run/systemd/readahead/cancel");
else if (strcmp(action, "done") == 0)
- return touch("/dev/.systemd/readahead/done");
+ return touch("/run/systemd/readahead/done");
else if (strcmp(action, "noreplay") == 0)
- return touch("/dev/.systemd/readahead/noreplay");
+ return touch("/run/systemd/readahead/noreplay");
return -EINVAL;
}
diff --git a/src/selinux-setup.c b/src/selinux-setup.c
index b2beb33d1..c32c7ad8d 100644
--- a/src/selinux-setup.c
+++ b/src/selinux-setup.c
@@ -43,10 +43,9 @@ int selinux_setup(char *const argv[]) {
return 0;
/* Before we load the policy we create a flag file to ensure
- * that after the reexec we iterate through /dev to relabel
- * things. */
- mkdir_p("/dev/.systemd", 0755);
- touch("/dev/.systemd/relabel-devtmpfs");
+ * that after the reexec we iterate through /run and /dev to
+ * relabel things. */
+ touch("/dev/.systemd-relabel-run-dev");
if (selinux_init_load_policy(&enforce) == 0) {
log_debug("Successfully loaded SELinux policy, reexecuting.");
@@ -59,9 +58,9 @@ int selinux_setup(char *const argv[]) {
return -errno;
} else {
- log_full(enforce > 0 ? LOG_ERR : LOG_DEBUG, "Failed to load SELinux policy.");
+ log_full(enforce > 0 ? LOG_ERR : LOG_WARNING, "Failed to load SELinux policy.");
- unlink("/dev/.systemd/relabel-devtmpfs");
+ unlink("/dev/.systemd-relabel-run-dev");
if (enforce > 0)
return -EIO;
diff --git a/src/service.c b/src/service.c
index 70999f354..7f8d005f0 100644
--- a/src/service.c
+++ b/src/service.c
@@ -35,13 +35,12 @@
#include "special.h"
#include "bus-errors.h"
#include "exit-status.h"
-
-#define COMMENTS "#;\n"
-#define NEWLINES "\n\r"
+#include "def.h"
+#include "util.h"
#ifdef HAVE_SYSV_COMPAT
-#define DEFAULT_SYSV_TIMEOUT_USEC (3*USEC_PER_MINUTE)
+#define DEFAULT_SYSV_TIMEOUT_USEC (5*USEC_PER_MINUTE)
typedef enum RunlevelType {
RUNLEVEL_UP,
@@ -116,6 +115,7 @@ static void service_init(Unit *u) {
s->timer_watch.type = WATCH_INVALID;
#ifdef HAVE_SYSV_COMPAT
s->sysv_start_priority = -1;
+ s->sysv_start_priority_from_rcnd = -1;
#endif
s->socket_fd = -1;
s->guess_main_pid = true;
@@ -286,7 +286,7 @@ static int sysv_translate_facility(const char *name, const char *filename, char
"portmap", SPECIAL_RPCBIND_TARGET,
"remote_fs", SPECIAL_REMOTE_FS_TARGET,
"syslog", SPECIAL_SYSLOG_TARGET,
- "time", SPECIAL_RTC_SET_TARGET,
+ "time", SPECIAL_TIME_SYNC_TARGET,
/* common extensions */
"mail-transfer-agent", SPECIAL_MAIL_TRANSFER_AGENT_TARGET,
@@ -406,7 +406,7 @@ static int sysv_fix_order(Service *s) {
/* FIXME: Maybe we should compare the name here lexicographically? */
- if (!(r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
+ if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
return r;
}
@@ -538,7 +538,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
* data from the LSB header. */
if (start_priority < 0 || start_priority > 99)
log_warning("[%s:%u] Start priority out of range. Ignoring.", path, line);
- else if (s->sysv_start_priority < 0)
+ else
s->sysv_start_priority = start_priority;
char_array_0(runlevels);
@@ -656,16 +656,21 @@ static int service_load_sysv_path(Service *s, const char *path) {
if (unit_name_to_type(m) == UNIT_SERVICE)
r = unit_add_name(u, m);
- else {
- r = unit_add_dependency_by_name(u, UNIT_BEFORE, m, NULL, true);
-
- if (s->sysv_enabled) {
- int k;
-
- if ((k = unit_add_dependency_by_name_inverse(u, UNIT_WANTS, m, NULL, true)) < 0)
- r = k;
- }
- }
+ else
+ /* NB: SysV targets
+ * which are provided
+ * by a service are
+ * pulled in by the
+ * services, as an
+ * indication that the
+ * generic service is
+ * now available. This
+ * is strictly
+ * one-way. The
+ * targets do NOT pull
+ * in the SysV
+ * services! */
+ r = unit_add_two_dependencies_by_name(u, UNIT_BEFORE, UNIT_WANTS, m, NULL, true);
if (r < 0)
log_error("[%s:%u] Failed to add LSB Provides name %s, ignoring: %s", path, line, m, strerror(-r));
@@ -824,7 +829,7 @@ static int service_load_sysv_path(Service *s, const char *path) {
s->exec_context.std_output =
(s->meta.manager->sysv_console || s->exec_context.std_input == EXEC_INPUT_TTY)
? EXEC_OUTPUT_TTY : s->meta.manager->default_std_output;
- s->exec_context.kill_mode = KILL_PROCESS_GROUP;
+ s->exec_context.kill_mode = KILL_PROCESS;
/* We use the long description only if
* no short description is set. */
@@ -849,6 +854,12 @@ static int service_load_sysv_path(Service *s, const char *path) {
u->meta.description = d;
}
+ /* The priority that has been set in /etc/rcN.d/ hierarchies
+ * takes precedence over what is stored as default in the LSB
+ * header */
+ if (s->sysv_start_priority_from_rcnd >= 0)
+ s->sysv_start_priority = s->sysv_start_priority_from_rcnd;
+
u->meta.load_state = UNIT_LOADED;
r = 0;
@@ -1013,7 +1024,7 @@ static int fsck_fix_order(Service *s) {
else
continue;
- if (!(r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
+ if ((r = unit_add_dependency(UNIT(s), d, UNIT(t), true)) < 0)
return r;
}
@@ -1130,7 +1141,7 @@ static int service_load(Unit *u) {
s->notify_access = NOTIFY_MAIN;
if (s->type == SERVICE_DBUS || s->bus_name)
- if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_TARGET, NULL, true)) < 0)
+ if ((r = unit_add_two_dependencies_by_name(u, UNIT_AFTER, UNIT_REQUIRES, SPECIAL_DBUS_SOCKET, NULL, true)) < 0)
return r;
if (s->meta.default_dependencies)
@@ -1581,8 +1592,8 @@ static int service_collect_fds(Service *s, int **fds, unsigned *n_fds) {
goto fail;
}
- memcpy(t, rfds, rn_fds);
- memcpy(t+rn_fds, cfds, cn_fds);
+ memcpy(t, rfds, rn_fds * sizeof(int));
+ memcpy(t+rn_fds, cfds, cn_fds * sizeof(int));
free(rfds);
free(cfds);
@@ -1659,7 +1670,7 @@ static int service_spawn(
}
if (set_notify_socket)
- if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=@%s", s->meta.manager->notify_socket) < 0) {
+ if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", s->meta.manager->notify_socket) < 0) {
r = -ENOMEM;
goto fail;
}
@@ -1834,19 +1845,14 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) {
int sig = (state == SERVICE_STOP_SIGTERM || state == SERVICE_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
if (s->main_pid > 0) {
- if (kill_and_sigcont(s->exec_context.kill_mode == KILL_PROCESS_GROUP ?
- -s->main_pid :
- s->main_pid, sig) < 0 && errno != ESRCH)
-
+ if (kill_and_sigcont(s->main_pid, sig) < 0 && errno != ESRCH)
log_warning("Failed to kill main process %li: %m", (long) s->main_pid);
else
wait_for_exit = true;
}
if (s->control_pid > 0) {
- if (kill_and_sigcont(s->exec_context.kill_mode == KILL_PROCESS_GROUP ?
- -s->control_pid :
- s->control_pid, sig) < 0 && errno != ESRCH)
+ if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
else
@@ -1876,6 +1882,7 @@ static void service_enter_signal(Service *s, ServiceState state, bool success) {
wait_for_exit = true;
set_free(pid_set);
+ pid_set = NULL;
}
}
@@ -3010,8 +3017,8 @@ static int service_enumerate(Manager *m) {
if (de->d_name[0] == 'S') {
if (rcnd_table[i].type == RUNLEVEL_UP || rcnd_table[i].type == RUNLEVEL_SYSINIT) {
- SERVICE(service)->sysv_start_priority =
- MAX(a*10 + b, SERVICE(service)->sysv_start_priority);
+ SERVICE(service)->sysv_start_priority_from_rcnd =
+ MAX(a*10 + b, SERVICE(service)->sysv_start_priority_from_rcnd);
SERVICE(service)->sysv_enabled = true;
}
@@ -3208,11 +3215,11 @@ static int service_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusErro
}
if (s->control_pid > 0)
- if (kill(mode == KILL_PROCESS_GROUP ? -s->control_pid : s->control_pid, signo) < 0)
+ if (kill(s->control_pid, signo) < 0)
r = -errno;
if (s->main_pid > 0)
- if (kill(mode == KILL_PROCESS_GROUP ? -s->main_pid : s->main_pid, signo) < 0)
+ if (kill(s->main_pid, signo) < 0)
r = -errno;
if (mode == KILL_CONTROL_GROUP) {
diff --git a/src/service.h b/src/service.h
index 627b356e2..e3cb431cf 100644
--- a/src/service.h
+++ b/src/service.h
@@ -138,6 +138,7 @@ struct Service {
#ifdef HAVE_SYSV_COMPAT
bool sysv_has_lsb:1;
bool sysv_enabled:1;
+ int sysv_start_priority_from_rcnd;
int sysv_start_priority;
char *sysv_path;
diff --git a/src/shutdown.c b/src/shutdown.c
index 5c082cf4a..a2f3b539b 100644
--- a/src/shutdown.c
+++ b/src/shutdown.c
@@ -96,125 +96,107 @@ static int killall(int sign) {
return n_processes;
}
-static int send_signal(int sign) {
- sigset_t mask, oldmask;
+static void wait_for_children(int n_processes, sigset_t *mask) {
usec_t until;
+
+ assert(mask);
+
+ until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC;
+ for (;;) {
+ struct timespec ts;
+ int k;
+ usec_t n;
+
+ for (;;) {
+ pid_t pid = waitpid(-1, NULL, WNOHANG);
+
+ if (pid == 0)
+ break;
+
+ if (pid < 0 && errno == ECHILD)
+ return;
+
+ if (n_processes > 0)
+ if (--n_processes == 0)
+ return;
+ }
+
+ n = now(CLOCK_MONOTONIC);
+ if (n >= until)
+ return;
+
+ timespec_store(&ts, until - n);
+
+ if ((k = sigtimedwait(mask, NULL, &ts)) != SIGCHLD) {
+
+ if (k < 0 && errno != EAGAIN) {
+ log_error("sigtimedwait() failed: %m");
+ return;
+ }
+
+ if (k >= 0)
+ log_warning("sigtimedwait() returned unexpected signal.");
+ }
+ }
+}
+
+static void send_signal(int sign) {
+ sigset_t mask, oldmask;
int n_processes;
- struct timespec ts;
assert_se(sigemptyset(&mask) == 0);
assert_se(sigaddset(&mask, SIGCHLD) == 0);
- if (sigprocmask(SIG_BLOCK, &mask, &oldmask) != 0)
- return -errno;
+ assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
- if (kill(-1, SIGSTOP) < 0)
+ if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
log_warning("kill(-1, SIGSTOP) failed: %m");
n_processes = killall(sign);
- if (kill(-1, SIGCONT) < 0)
+ if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
log_warning("kill(-1, SIGCONT) failed: %m");
if (n_processes <= 0)
goto finish;
- until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC;
- for (;;) {
- int k;
- usec_t n = now(CLOCK_MONOTONIC);
-
- for (;;) {
- pid_t pid = waitpid(-1, NULL, WNOHANG);
-
- if (pid == 0)
- break;
- else if (pid < 0 && errno == ECHILD) {
- n_processes = 0;
- goto finish;
- }
-
- if (--n_processes == 0)
- goto finish;
- }
-
- if (n >= until)
- goto finish;
-
- timespec_store(&ts, until - n);
- if ((k = sigtimedwait(&mask, NULL, &ts)) != SIGCHLD) {
- if (k >= 0)
- log_warning("sigtimedwait() returned unexpected signal.");
- if (k < 0 && errno != EAGAIN)
- log_warning("sigtimedwait() failed: %m");
- }
- }
+ wait_for_children(n_processes, &mask);
finish:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
-
- return n_processes;
}
-static int rescue_send_signal(int sign) {
+static void ultimate_send_signal(int sign) {
sigset_t mask, oldmask;
- usec_t until;
- struct timespec ts;
int r;
- sigemptyset(&mask);
- sigaddset(&mask, SIGCHLD);
- if (sigprocmask(SIG_BLOCK, &mask, &oldmask) != 0)
- return -errno;
+ assert_se(sigemptyset(&mask) == 0);
+ assert_se(sigaddset(&mask, SIGCHLD) == 0);
+ assert_se(sigprocmask(SIG_BLOCK, &mask, &oldmask) == 0);
- if (kill(-1, SIGSTOP) < 0)
+ if (kill(-1, SIGSTOP) < 0 && errno != ESRCH)
log_warning("kill(-1, SIGSTOP) failed: %m");
r = kill(-1, sign);
- if (r < 0)
- log_warning("kill(-1, %d) failed: %m", sign);
+ if (r < 0 && errno != ESRCH)
+ log_warning("kill(-1, %s) failed: %m", signal_to_string(sign));
- if (kill(-1, SIGCONT) < 0)
+ if (kill(-1, SIGCONT) < 0 && errno != ESRCH)
log_warning("kill(-1, SIGCONT) failed: %m");
if (r < 0)
goto finish;
- until = now(CLOCK_MONOTONIC) + TIMEOUT_USEC;
- for (;;) {
- int k;
- usec_t n = now(CLOCK_MONOTONIC);
-
- for (;;) {
- pid_t pid = waitpid(-1, NULL, WNOHANG);
- if (pid == 0)
- break;
- else if (pid < 0 && errno == ECHILD)
- goto finish;
- }
-
- if (n >= until)
- goto finish;
-
- timespec_store(&ts, until - n);
- if ((k = sigtimedwait(&mask, NULL, &ts)) != SIGCHLD) {
- if (k >= 0)
- log_warning("sigtimedwait() returned unexpected signal.");
- if (k < 0 && errno != EAGAIN)
- log_warning("sigtimedwait() failed: %m");
- }
- }
+ wait_for_children(0, &mask);
finish:
sigprocmask(SIG_SETMASK, &oldmask, NULL);
-
- return r;
}
int main(int argc, char *argv[]) {
int cmd, r;
unsigned retries;
bool need_umount = true, need_swapoff = true, need_loop_detach = true, need_dm_detach = true;
- bool killed_everbody = false;
+ bool killed_everbody = false, in_container;
log_parse_environment();
log_set_target(LOG_TARGET_CONSOLE); /* syslog will die if not gone yet */
@@ -232,6 +214,8 @@ int main(int argc, char *argv[]) {
goto error;
}
+ in_container = detect_container(NULL) > 0;
+
if (streq(argv[1], "reboot"))
cmd = RB_AUTOBOOT;
else if (streq(argv[1], "poweroff"))
@@ -251,14 +235,13 @@ int main(int argc, char *argv[]) {
log_warning("Cannot lock process memory: %m");
log_info("Sending SIGTERM to remaining processes...");
- r = send_signal(SIGTERM);
- if (r < 0)
- log_warning("Failed to send SIGTERM to remaining processes: %s", strerror(r));
+ send_signal(SIGTERM);
log_info("Sending SIGKILL to remaining processes...");
- r = send_signal(SIGKILL);
- if (r < 0)
- log_warning("Failed to send SIGKILL to remaining processes: %s", strerror(r));
+ send_signal(SIGKILL);
+
+ if (in_container)
+ need_swapoff = false;
/* Unmount all mountpoints, swaps, and loopback devices */
for (retries = 0; retries < FINALIZE_ATTEMPTS; retries++) {
@@ -325,8 +308,8 @@ int main(int argc, char *argv[]) {
}
log_warning("Cannot finalize remaining file systems and devices, trying to kill remaining processes.");
- rescue_send_signal(SIGTERM);
- rescue_send_signal(SIGKILL);
+ ultimate_send_signal(SIGTERM);
+ ultimate_send_signal(SIGKILL);
killed_everbody = true;
}
@@ -338,6 +321,13 @@ int main(int argc, char *argv[]) {
execute_directory(SYSTEM_SHUTDOWN_PATH, NULL, NULL);
+ /* If we are in a container, just exit, this will kill our
+ * container for good. */
+ if (in_container) {
+ log_error("Exiting container.");
+ exit(0);
+ }
+
sync();
if (cmd == LINUX_REBOOT_CMD_KEXEC) {
diff --git a/src/shutdownd.c b/src/shutdownd.c
index 143fa8d82..8f765b451 100644
--- a/src/shutdownd.c
+++ b/src/shutdownd.c
@@ -227,7 +227,7 @@ int main(int argc, char *argv[]) {
if ((pollfd[i].fd = timerfd_create(CLOCK_REALTIME, TFD_NONBLOCK|TFD_CLOEXEC)) < 0) {
log_error("timerfd_create(): %m");
- failed = false;
+ failed = true;
}
}
@@ -318,10 +318,10 @@ int main(int argc, char *argv[]) {
if (pollfd[FD_NOLOGIN_TIMER].revents) {
int e;
- log_info("Creating /var/run/nologin, blocking further logins...");
+ log_info("Creating /run/nologin, blocking further logins...");
- if ((e = write_one_line_file("/var/run/nologin", "System is going down.")) < 0)
- log_error("Failed to create /var/run/nologin: %s", strerror(-e));
+ if ((e = write_one_line_file("/run/nologin", "System is going down.")) < 0)
+ log_error("Failed to create /run/nologin: %s", strerror(-e));
else
unlink_nologin = true;
@@ -346,7 +346,7 @@ finish:
close_nointr_nofail(pollfd[i].fd);
if (unlink_nologin)
- unlink("/var/run/nologin");
+ unlink("/run/nologin");
if (exec_shutdown) {
char sw[3];
diff --git a/src/socket.c b/src/socket.c
index 77bbe43ee..beb328657 100644
--- a/src/socket.c
+++ b/src/socket.c
@@ -42,6 +42,7 @@
#include "bus-errors.h"
#include "label.h"
#include "exit-status.h"
+#include "def.h"
static const UnitActiveState state_translation_table[_SOCKET_STATE_MAX] = {
[SOCKET_DEAD] = UNIT_INACTIVE,
@@ -67,7 +68,7 @@ static void socket_init(Unit *u) {
s->backlog = SOMAXCONN;
s->timeout_usec = DEFAULT_TIMEOUT_USEC;
s->directory_mode = 0755;
- s->socket_mode = 0666;
+ s->socket_mode = 0777;
s->max_connections = 64;
@@ -1039,9 +1040,7 @@ static void socket_enter_signal(Socket *s, SocketState state, bool success) {
int sig = (state == SOCKET_STOP_PRE_SIGTERM || state == SOCKET_FINAL_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
if (s->control_pid > 0) {
- if (kill_and_sigcont(s->exec_context.kill_mode == KILL_PROCESS_GROUP ?
- -s->control_pid :
- s->control_pid, sig) < 0 && errno != ESRCH)
+ if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
else
@@ -1067,6 +1066,7 @@ static void socket_enter_signal(Socket *s, SocketState state, bool success) {
wait_for_exit = true;
set_free(pid_set);
+ pid_set = NULL;
}
}
@@ -1696,6 +1696,7 @@ static void socket_timer_event(Unit *u, uint64_t elapsed, Watch *w) {
case SOCKET_START_PRE:
log_warning("%s starting timed out. Terminating.", u->meta.id);
socket_enter_signal(s, SOCKET_FINAL_SIGTERM, false);
+ break;
case SOCKET_START_POST:
log_warning("%s starting timed out. Stopping.", u->meta.id);
@@ -1836,7 +1837,7 @@ static int socket_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError
}
if (s->control_pid > 0)
- if (kill(mode == KILL_PROCESS_GROUP ? -s->control_pid : s->control_pid, signo) < 0)
+ if (kill(s->control_pid, signo) < 0)
r = -errno;
if (mode == KILL_CONTROL_GROUP) {
diff --git a/src/special.h b/src/special.h
index df1e1fa41..08dae11a2 100644
--- a/src/special.h
+++ b/src/special.h
@@ -24,52 +24,57 @@
#define SPECIAL_DEFAULT_TARGET "default.target"
+/* Shutdown targets */
+#define SPECIAL_UMOUNT_TARGET "umount.target"
/* This is not really intended to be started by directly. This is
* mostly so that other targets (reboot/halt/poweroff) can depend on
* it to bring all services down that want to be brought down on
* system shutdown. */
#define SPECIAL_SHUTDOWN_TARGET "shutdown.target"
-#define SPECIAL_UMOUNT_TARGET "umount.target"
-
-#define SPECIAL_LOGGER_SOCKET "systemd-logger.socket"
-
-#define SPECIAL_KBREQUEST_TARGET "kbrequest.target"
-#define SPECIAL_SIGPWR_TARGET "sigpwr.target"
-#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target"
-
-#define SPECIAL_LOCAL_FS_TARGET "local-fs.target" /* LSB's $local_fs */
-#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target" /* LSB's $remote_fs */
-#define SPECIAL_SWAP_TARGET "swap.target"
-#define SPECIAL_NETWORK_TARGET "network.target" /* LSB's $network */
-#define SPECIAL_NSS_LOOKUP_TARGET "nss-lookup.target" /* LSB's $named */
-#define SPECIAL_RPCBIND_TARGET "rpcbind.target" /* LSB's $portmap */
-#define SPECIAL_SYSLOG_TARGET "syslog.target" /* LSB's $syslog; Should pull in syslog.socket or syslog.service */
-#define SPECIAL_RTC_SET_TARGET "rtc-set.target" /* LSB's $time */
-#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_HTTP_DAEMON_TARGET "http-daemon.target"
-#define SPECIAL_DBUS_TARGET "dbus.target"
-#define SPECIAL_BASIC_TARGET "basic.target"
-#define SPECIAL_SOCKETS_TARGET "sockets.target"
-#define SPECIAL_SYSINIT_TARGET "sysinit.target"
-#define SPECIAL_FSCK_SERVICE "fsck@.service"
-#define SPECIAL_QUOTACHECK_SERVICE "quotacheck.service"
-#define SPECIAL_RESCUE_TARGET "rescue.target"
-#define SPECIAL_EXIT_TARGET "exit.target"
-#define SPECIAL_EMERGENCY_TARGET "emergency.target"
#define SPECIAL_HALT_TARGET "halt.target"
#define SPECIAL_POWEROFF_TARGET "poweroff.target"
#define SPECIAL_REBOOT_TARGET "reboot.target"
#define SPECIAL_KEXEC_TARGET "kexec.target"
-#define SPECIAL_DBUS_SERVICE "dbus.service"
-#define SPECIAL_DBUS_SOCKET "dbus.socket"
-#define SPECIAL_GETTY_TARGET "getty.target"
-#define SPECIAL_SERIAL_GETTY_SERVICE "serial-getty@.service"
+#define SPECIAL_EXIT_TARGET "exit.target"
+
+/* Special boot targets */
+#define SPECIAL_RESCUE_TARGET "rescue.target"
+#define SPECIAL_EMERGENCY_TARGET "emergency.target"
+
+/* Early boot targets */
+#define SPECIAL_SYSINIT_TARGET "sysinit.target"
+#define SPECIAL_SOCKETS_TARGET "sockets.target"
+#define SPECIAL_LOCAL_FS_TARGET "local-fs.target" /* LSB's $local_fs */
+#define SPECIAL_REMOTE_FS_TARGET "remote-fs.target" /* LSB's $remote_fs */
+#define SPECIAL_SWAP_TARGET "swap.target"
+#define SPECIAL_BASIC_TARGET "basic.target"
+
+/* LSB compatibility */
+#define SPECIAL_NETWORK_TARGET "network.target" /* LSB's $network */
+#define SPECIAL_NSS_LOOKUP_TARGET "nss-lookup.target" /* LSB's $named */
+#define SPECIAL_RPCBIND_TARGET "rpcbind.target" /* LSB's $portmap */
+#define SPECIAL_SYSLOG_TARGET "syslog.target" /* LSB's $syslog; Should pull in syslog.socket or syslog.service */
+#define SPECIAL_TIME_SYNC_TARGET "time-sync.target" /* LSB's $time */
+#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_HTTP_DAEMON_TARGET "http-daemon.target"
+
+/* Magic early boot services */
+#define SPECIAL_FSCK_SERVICE "fsck@.service"
+#define SPECIAL_QUOTACHECK_SERVICE "quotacheck.service"
+#define SPECIAL_QUOTAON_SERVICE "quotaon.service"
#define SPECIAL_REMOUNT_ROOTFS_SERVICE "remount-rootfs.service"
-#ifndef SPECIAL_SYSLOG_SERVICE
-#define SPECIAL_SYSLOG_SERVICE "syslog.service"
-#endif
+/* Services systemd relies on */
+#define SPECIAL_DBUS_SERVICE "dbus.service"
+#define SPECIAL_DBUS_SOCKET "dbus.socket"
+#define SPECIAL_LOGGER_SOCKET "systemd-logger.socket"
+#define SPECIAL_SYSLOG_SOCKET "syslog.socket"
+
+/* Magic init signals */
+#define SPECIAL_KBREQUEST_TARGET "kbrequest.target"
+#define SPECIAL_SIGPWR_TARGET "sigpwr.target"
+#define SPECIAL_CTRL_ALT_DEL_TARGET "ctrl-alt-del.target"
/* For SysV compatibility. Usually an alias for a saner target. On
* SysV-free systems this doesn't exist. */
diff --git a/src/strv.c b/src/strv.c
index c8ff5745e..c5f8df06d 100644
--- a/src/strv.c
+++ b/src/strv.c
@@ -78,9 +78,11 @@ char **strv_copy(char **l) {
return r;
fail:
- for (k--, l--; k >= r; k--, l--)
+ for (k--; k >= r; k--)
free(*k);
+ free(r);
+
return NULL;
}
@@ -435,6 +437,8 @@ char **strv_env_merge(unsigned n_lists, ...) {
return r;
fail:
+ va_end(ap);
+
for (k--; k >= r; k--)
free(*k);
diff --git a/src/swap.c b/src/swap.c
index f59b0fb18..c32f60810 100644
--- a/src/swap.c
+++ b/src/swap.c
@@ -37,6 +37,7 @@
#include "special.h"
#include "bus-errors.h"
#include "exit-status.h"
+#include "def.h"
static const UnitActiveState state_translation_table[_SWAP_STATE_MAX] = {
[SWAP_DEAD] = UNIT_INACTIVE,
@@ -660,9 +661,7 @@ static void swap_enter_signal(Swap *s, SwapState state, bool success) {
state == SWAP_DEACTIVATING_SIGTERM) ? s->exec_context.kill_signal : SIGKILL;
if (s->control_pid > 0) {
- if (kill_and_sigcont(s->exec_context.kill_mode == KILL_PROCESS_GROUP ?
- -s->control_pid :
- s->control_pid, sig) < 0 && errno != ESRCH)
+ if (kill_and_sigcont(s->control_pid, sig) < 0 && errno != ESRCH)
log_warning("Failed to kill control process %li: %m", (long) s->control_pid);
else
@@ -688,6 +687,7 @@ static void swap_enter_signal(Swap *s, SwapState state, bool success) {
wait_for_exit = true;
set_free(pid_set);
+ pid_set = NULL;
}
}
@@ -1285,7 +1285,7 @@ static int swap_kill(Unit *u, KillWho who, KillMode mode, int signo, DBusError *
}
if (s->control_pid > 0)
- if (kill(mode == KILL_PROCESS_GROUP ? -s->control_pid : s->control_pid, signo) < 0)
+ if (kill(s->control_pid, signo) < 0)
r = -errno;
if (mode == KILL_CONTROL_GROUP) {
diff --git a/src/systemctl-bash-completion.sh b/src/systemctl-bash-completion.sh
index f3420217b..ae0ecb7b7 100644
--- a/src/systemctl-bash-completion.sh
+++ b/src/systemctl-bash-completion.sh
@@ -60,7 +60,7 @@ _systemctl () {
comps='all control main'
;;
--kill-mode)
- comps='control-group process process-group'
+ comps='control-group process'
;;
--property|-p)
comps=''
diff --git a/src/systemctl.c b/src/systemctl.c
index 63e74d904..00db47f12 100644
--- a/src/systemctl.c
+++ b/src/systemctl.c
@@ -108,6 +108,12 @@ static enum dot {
DOT_ORDER,
DOT_REQUIRE
} arg_dot = DOT_ALL;
+static enum transport {
+ TRANSPORT_NORMAL,
+ TRANSPORT_SSH,
+ TRANSPORT_POLKIT
+} arg_transport = TRANSPORT_NORMAL;
+static const char *arg_host = NULL;
static bool private_bus = false;
@@ -381,7 +387,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
if (on_tty()) {
printf("%-25s %-6s %-*s %-*s %-*s", "UNIT", "LOAD",
active_len, "ACTIVE", sub_len, "SUB", job_len, "JOB");
- if (columns() >= 80+12 || arg_full)
+ if (columns() >= 80+12 || arg_full || !arg_no_pager)
printf(" %s\n", "DESCRIPTION");
else
printf("\n");
@@ -434,7 +440,7 @@ static void output_units_list(const struct unit_info *unit_infos, unsigned c) {
if (u->job_id == 0)
printf(" %-*s", job_len, "");
- if (arg_full)
+ if (arg_full || !arg_no_pager)
printf(" %s", u->description);
else
printf(" %.*s", columns() - a - b - 1, u->description);
@@ -1414,7 +1420,8 @@ static int start_unit(DBusConnection *bus, char **args, unsigned n) {
if (arg_action == ACTION_SYSTEMCTL) {
method =
- streq(args[0], "stop") ? "StopUnit" :
+ streq(args[0], "stop") ||
+ streq(args[0], "condstop") ? "StopUnit" :
streq(args[0], "reload") ? "ReloadUnit" :
streq(args[0], "restart") ? "RestartUnit" :
@@ -1831,6 +1838,9 @@ typedef struct UnitStatusInfo {
int exit_code, exit_status;
+ usec_t condition_timestamp;
+ bool condition_result;
+
/* Socket */
unsigned n_accepted;
unsigned n_connections;
@@ -1922,6 +1932,16 @@ static void print_status_info(UnitStatusInfo *i) {
else
printf("\n");
+ if (!i->condition_result && i->condition_timestamp > 0) {
+ s1 = format_timestamp_pretty(since1, sizeof(since1), i->condition_timestamp);
+ s2 = format_timestamp(since2, sizeof(since2), i->condition_timestamp);
+
+ if (s1)
+ printf("\t start condition failed at %s; %s\n", s2, s1);
+ else if (s2)
+ printf("\t start condition failed at %s\n", s2);
+ }
+
if (i->sysfs_path)
printf("\t Device: %s\n", i->sysfs_path);
if (i->where)
@@ -2048,12 +2068,14 @@ static void print_status_info(UnitStatusInfo *i) {
printf("\t CGroup: %s\n", i->default_control_group);
- if ((c = columns()) > 18)
- c -= 18;
- else
- c = 0;
+ if (arg_transport != TRANSPORT_SSH) {
+ if ((c = columns()) > 18)
+ c -= 18;
+ else
+ c = 0;
- show_cgroup_by_path(i->default_control_group, "\t\t ", c);
+ show_cgroup_by_path(i->default_control_group, "\t\t ", c);
+ }
}
if (i->need_daemon_reload)
@@ -2117,6 +2139,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
i->accept = b;
else if (streq(name, "NeedDaemonReload"))
i->need_daemon_reload = b;
+ else if (streq(name, "ConditionResult"))
+ i->condition_result = b;
break;
}
@@ -2174,6 +2198,8 @@ static int status_property(const char *name, DBusMessageIter *iter, UnitStatusIn
i->inactive_exit_timestamp = (usec_t) u;
else if (streq(name, "ActiveExitTimestamp"))
i->active_exit_timestamp = (usec_t) u;
+ else if (streq(name, "ConditionTimestamp"))
+ i->condition_timestamp = (usec_t) u;
break;
}
@@ -2814,8 +2840,20 @@ static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage
else
printf("Unit %s removed.\n", id);
- } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew") ||
- dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
+ } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobNew")) {
+ uint32_t id;
+ const char *path;
+
+ if (!dbus_message_get_args(message, &error,
+ DBUS_TYPE_UINT32, &id,
+ DBUS_TYPE_OBJECT_PATH, &path,
+ DBUS_TYPE_INVALID))
+ log_error("Failed to parse message: %s", bus_error_message(&error));
+ else
+ printf("Job %u added.\n", id);
+
+
+ } else if (dbus_message_is_signal(message, "org.freedesktop.systemd1.Manager", "JobRemoved")) {
uint32_t id;
const char *path, *result;
@@ -2825,10 +2863,8 @@ static DBusHandlerResult monitor_filter(DBusConnection *connection, DBusMessage
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"))
- printf("Job %u added.\n", id);
else
- printf("Job %u removed.\n", id);
+ printf("Job %u removed (result=%s).\n", id, result);
} else if (dbus_message_is_signal(message, "org.freedesktop.DBus.Properties", "PropertiesChanged")) {
@@ -3583,6 +3619,7 @@ static int config_parse_also(
unsigned line,
const char *section,
const char *lvalue,
+ int ltype,
const char *rvalue,
void *data,
void *userdata) {
@@ -3997,11 +4034,11 @@ finish:
static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo *i, const char *config_path) {
const ConfigItem items[] = {
- { "Alias", config_parse_strv, &i->aliases, "Install" },
- { "WantedBy", config_parse_strv, &i->wanted_by, "Install" },
- { "Also", config_parse_also, NULL, "Install" },
+ { "Alias", config_parse_strv, 0, &i->aliases, "Install" },
+ { "WantedBy", config_parse_strv, 0, &i->wanted_by, "Install" },
+ { "Also", config_parse_also, 0, NULL, "Install" },
- { NULL, NULL, NULL, NULL }
+ { NULL, NULL, 0, NULL, NULL }
};
char **p;
@@ -4072,7 +4109,7 @@ static int install_info_apply(const char *verb, LookupPaths *paths, InstallInfo
argv[1] = file_name_from_path(sysv);
argv[2] =
streq(verb, "enable") ? "on" :
- streq(verb, "disable") ? "off" : "--level=3";
+ streq(verb, "disable") ? "off" : "--level=5";
log_info("Executing %s %s %s", argv[0], argv[1], strempty(argv[2]));
@@ -4273,22 +4310,25 @@ static int systemctl_help(void) {
" pending\n"
" --ignore-dependencies\n"
" When queueing a new job, ignore all its dependencies\n"
- " -q --quiet Suppress output\n"
- " --no-block Do not wait until operation finished\n"
- " --no-pager Do not pipe output into a pager.\n"
- " --system Connect to system manager\n"
- " --user Connect to user service manager\n"
- " --order When generating graph for dot, show only order\n"
- " --require When generating graph for dot, show only requirement\n"
- " --no-wall Don't send wall message before halt/power-off/reboot\n"
- " --global Enable/disable unit files globally\n"
- " --no-reload When enabling/disabling unit files, don't reload daemon\n"
- " configuration\n"
- " --no-ask-password\n"
- " Do not ask for system passwords\n"
" --kill-mode=MODE How to send signal\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
+ " -H --host=[user@]host\n"
+ " Show information for remote host\n"
+ " -P --privileged Acquire privileges before execution\n"
+ " -q --quiet Suppress output\n"
+ " --no-block Do not wait until operation finished\n"
+ " --no-wall Don't send wall message before halt/power-off/reboot\n"
+ " --no-reload When enabling/disabling unit files, don't reload daemon\n"
+ " configuration\n"
+ " --no-pager Do not pipe output into a pager.\n"
+ " --no-ask-password\n"
+ " Do not ask for system passwords\n"
+ " --order When generating graph for dot, show only order\n"
+ " --require When generating graph for dot, show only requirement\n"
+ " --system Connect to system manager\n"
+ " --user Connect to user service manager\n"
+ " --global Enable/disable unit files globally\n"
" -f --force When enabling unit files, override existing symlinks\n"
" When shutting down, execute action immediately\n"
" --defaults When disabling unit files, remove default symlinks only\n\n"
@@ -4455,6 +4495,8 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
{ "kill-who", required_argument, NULL, ARG_KILL_WHO },
{ "signal", required_argument, NULL, 's' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
+ { "host", required_argument, NULL, 'H' },
+ { "privileged",no_argument, NULL, 'P' },
{ NULL, 0, NULL, 0 }
};
@@ -4466,7 +4508,7 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
/* Only when running as systemctl we ask for passwords */
arg_ask_password = true;
- while ((c = getopt_long(argc, argv, "ht:p:aqfs:", options, NULL)) >= 0) {
+ while ((c = getopt_long(argc, argv, "ht:p:aqfs:H:P", options, NULL)) >= 0) {
switch (c) {
@@ -4588,6 +4630,15 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
arg_ask_password = false;
break;
+ case 'P':
+ arg_transport = TRANSPORT_POLKIT;
+ break;
+
+ case 'H':
+ arg_transport = TRANSPORT_SSH;
+ arg_host = optarg;
+ break;
+
case '?':
return -EINVAL;
@@ -4597,6 +4648,11 @@ static int systemctl_parse_argv(int argc, char *argv[]) {
}
}
+ if (arg_transport != TRANSPORT_NORMAL && arg_user) {
+ log_error("Cannot access user instance remotely.");
+ return -EINVAL;
+ }
+
return 1;
}
@@ -5191,6 +5247,7 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
{ "cancel", MORE, 2, cancel_job },
{ "start", MORE, 2, start_unit },
{ "stop", MORE, 2, start_unit },
+ { "condstop", MORE, 2, start_unit }, /* For compatibility with ALTLinux */
{ "reload", MORE, 2, start_unit },
{ "restart", MORE, 2, start_unit },
{ "try-restart", MORE, 2, start_unit },
@@ -5289,11 +5346,17 @@ static int systemctl_main(DBusConnection *bus, int argc, char *argv[], DBusError
/* Require a bus connection for all operations but
* enable/disable */
- if (!streq(verbs[i].verb, "enable") &&
- !streq(verbs[i].verb, "disable") &&
- !bus) {
- log_error("Failed to get D-Bus connection: %s", error->message);
- return -EIO;
+ if (!streq(verbs[i].verb, "enable") && !streq(verbs[i].verb, "disable")) {
+
+ if (running_in_chroot() > 0) {
+ log_info("Running in chroot, ignoring request.");
+ return 0;
+ }
+
+ if (!bus) {
+ log_error("Failed to get D-Bus connection: %s", error->message);
+ return -EIO;
+ }
}
return verbs[i].dispatch(bus, argv + optind, left);
@@ -5320,7 +5383,7 @@ static int send_shutdownd(usec_t t, char mode, bool warn, const char *message) {
zero(sockaddr);
sockaddr.sa.sa_family = AF_UNIX;
sockaddr.un.sun_path[0] = 0;
- strncpy(sockaddr.un.sun_path+1, "/org/freedesktop/systemd1/shutdownd", sizeof(sockaddr.un.sun_path)-1);
+ strncpy(sockaddr.un.sun_path, "/run/systemd/shutdownd", sizeof(sockaddr.un.sun_path));
zero(iovec);
iovec.iov_base = (char*) &c;
@@ -5328,7 +5391,7 @@ static int send_shutdownd(usec_t t, char mode, bool warn, const char *message) {
zero(msghdr);
msghdr.msg_name = &sockaddr;
- msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + 1 + sizeof("/org/freedesktop/systemd1/shutdownd") - 1;
+ msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) + sizeof("/run/systemd/shutdownd") - 1;
msghdr.msg_iov = &iovec;
msghdr.msg_iovlen = 1;
@@ -5605,7 +5668,22 @@ int main(int argc, char*argv[]) {
goto finish;
}
- bus_connect(arg_user ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
+ if (running_in_chroot() > 0 && arg_action != ACTION_SYSTEMCTL) {
+ log_info("Running in chroot, ignoring request.");
+ retval = 0;
+ goto finish;
+ }
+
+ if (arg_transport == TRANSPORT_NORMAL)
+ bus_connect(arg_user ? DBUS_BUS_SESSION : DBUS_BUS_SYSTEM, &bus, &private_bus, &error);
+ else if (arg_transport == TRANSPORT_POLKIT) {
+ bus_connect_system_polkit(&bus, &error);
+ private_bus = false;
+ } else if (arg_transport == TRANSPORT_SSH) {
+ bus_connect_system_ssh(NULL, arg_host, &bus, &error);
+ private_bus = false;
+ } else
+ assert_not_reached("Uh, invalid transport...");
switch (arg_action) {
diff --git a/src/systemd-analyze b/src/systemd-analyze
new file mode 100755
index 000000000..5e3a087e9
--- /dev/null
+++ b/src/systemd-analyze
@@ -0,0 +1,206 @@
+#!/usr/bin/python
+
+import dbus, sys
+
+def acquire_time_data():
+
+ manager = dbus.Interface(bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1'), 'org.freedesktop.systemd1.Manager')
+ units = manager.ListUnits()
+
+ l = []
+
+ for i in units:
+ if i[5] != "":
+ continue
+
+ properties = dbus.Interface(bus.get_object('org.freedesktop.systemd1', i[6]), 'org.freedesktop.DBus.Properties')
+
+ ixt = int(properties.Get('org.freedesktop.systemd1.Unit', 'InactiveExitTimestamp'))
+ aet = int(properties.Get('org.freedesktop.systemd1.Unit', 'ActiveEnterTimestamp'))
+ axt = int(properties.Get('org.freedesktop.systemd1.Unit', 'ActiveExitTimestamp'))
+ iet = int(properties.Get('org.freedesktop.systemd1.Unit', 'InactiveEnterTimestamp'))
+
+ l.append((str(i[0]), ixt, aet, axt, iet))
+
+ return l
+
+def acquire_start_time():
+ properties = dbus.Interface(bus.get_object('org.freedesktop.systemd1', '/org/freedesktop/systemd1'), 'org.freedesktop.DBus.Properties')
+
+ startup_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'StartupTimestamp'))
+ finish_time = int(properties.Get('org.freedesktop.systemd1.Manager', 'FinishTimestamp'))
+
+ assert startup_time <= finish_time
+
+ return startup_time, finish_time
+
+def draw_box(context, j, k, l, m, r = 0, g = 0, b = 0):
+ context.save()
+ context.set_source_rgb(r, g, b)
+ context.rectangle(j, k, l, m)
+ context.fill()
+ context.restore()
+
+def draw_text(context, x, y, text, size = 12, r = 0, g = 0, b = 0, vcenter = 0.5, hcenter = 0.5):
+ context.save()
+
+ context.set_source_rgb(r, g, b)
+ context.select_font_face("Sans", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL)
+ context.set_font_size(size)
+
+ if vcenter or hcenter:
+ x_bearing, y_bearing, width, height = context.text_extents(text)[:4]
+
+ if hcenter:
+ x = x - width*hcenter - x_bearing
+
+ if vcenter:
+ y = y - height*vcenter - y_bearing
+
+ context.move_to(x, y)
+ context.show_text(text)
+
+ context.restore()
+
+def help():
+ sys.stdout.write("""systemd-analyze blame
+systemd-analyze plot
+
+Process systemd profiling information
+
+ -h --help Show this help
+""")
+
+
+bus = dbus.SystemBus()
+
+if len(sys.argv) <= 1 or sys.argv[1] == 'blame':
+
+ data = acquire_time_data()
+ s = sorted(data, key = lambda i: i[2] - i[1], reverse = True)
+
+ for name, ixt, aet, axt, iet in s:
+
+ if ixt <= 0 or aet <= 0:
+ continue
+
+ if aet <= ixt:
+ continue
+
+ sys.stdout.write("%6lums %s\n" % ((aet - ixt) / 1000, name))
+
+elif sys.argv[1] == 'plot':
+ import cairo
+
+ start_time, finish_time = acquire_start_time()
+ data = acquire_time_data()
+ s = sorted(data, key = lambda i: i[1])
+
+ count = 0
+
+ for name, ixt, aet, axt, iet in s:
+
+ if (ixt >= start_time and ixt <= finish_time) or \
+ (aet >= start_time and aet <= finish_time) or \
+ (axt >= start_time and axt <= finish_time):
+ count += 1
+
+ border = 100
+ bar_height = 20
+ bar_space = bar_height * 0.1
+
+ # 1000px = 10s, 1px = 10ms
+ width = (finish_time - start_time)/10000 + border*2
+ height = count * (bar_height + bar_space) + border * 2
+
+ if width < 1000:
+ width = 1000
+
+ surface = cairo.SVGSurface(sys.stdout, width, height)
+ context = cairo.Context(surface)
+
+ draw_box(context, 0, 0, width, height, 1, 1, 1)
+
+ context.translate(border + 0.5, border + 0.5)
+
+ context.save()
+ context.set_line_width(1)
+ context.set_source_rgb(0.7, 0.7, 0.7)
+
+ for x in range(0, (finish_time - start_time)/10000, 100):
+ context.move_to(x, 0)
+ context.line_to(x, height-border*2)
+
+ context.move_to(0, 0)
+ context.line_to(width-border*2, 0)
+
+ context.move_to(0, height-border*2)
+ context.line_to(width-border*2, height-border*2)
+
+ context.stroke()
+ context.restore()
+
+ for x in range(0, (finish_time - start_time)/10000, 100):
+ draw_text(context, x, -5, "%lus" % (x/100), vcenter = 0, hcenter = 0)
+
+ y = 0
+
+ for name, ixt, aet, axt, iet in s:
+
+ drawn = False
+ left = -1
+
+ if ixt >= start_time and ixt <= finish_time:
+
+ # Activating
+ a = ixt - start_time
+ b = min(filter(lambda x: x >= ixt, (aet, axt, iet, finish_time))) - ixt
+
+ draw_box(context, a/10000, y, b/10000, bar_height, 1, 0, 0)
+ drawn = True
+
+ if left < 0:
+ left = a
+
+ if aet >= start_time and aet <= finish_time:
+
+ # Active
+ a = aet - start_time
+ b = min(filter(lambda x: x >= aet, (axt, iet, finish_time))) - aet
+
+ draw_box(context, a/10000, y, b/10000, bar_height, .8, .6, .6)
+ drawn = True
+
+ if left < 0:
+ left = a
+
+ if axt >= start_time and axt <= finish_time:
+
+ # Deactivating
+ a = axt - start_time
+ b = min(filter(lambda x: x >= axt, (iet, finish_time))) - axt
+
+ draw_box(context, a/10000, y, b/10000, bar_height, .6, .4, .4)
+ drawn = True
+
+ if left < 0:
+ left = a
+
+ if drawn:
+ x = left/10000
+
+ if x < width/2-border:
+ draw_text(context, x + 10, y + bar_height/2, name, hcenter = 0)
+ else:
+ draw_text(context, x - 10, y + bar_height/2, name, hcenter = 1)
+
+ y += bar_height + bar_space
+
+ draw_text(context, 0, height-border*2, "Legend: Red = Activating; Pink = Active; Dark Pink = Deactivating", hcenter = 0, vcenter = -1)
+
+ surface.finish()
+elif sys.argv[1] in ("help", "--help", "-h"):
+ help()
+else:
+ sys.stderr.write("Unknown verb '%s'.\n" % sys.argv[1])
+ sys.exit(1)
diff --git a/src/target.c b/src/target.c
index e61255c12..54c34daa0 100644
--- a/src/target.c
+++ b/src/target.c
@@ -83,67 +83,6 @@ static int target_add_default_dependencies(Target *t) {
return unit_add_dependency_by_name(UNIT(t), UNIT_CONFLICTS, SPECIAL_SHUTDOWN_TARGET, NULL, true);
}
-static int target_add_getty_dependencies(Target *t) {
- char *n, *active;
- int r;
-
- assert(t);
-
- if (!unit_has_name(UNIT(t), SPECIAL_GETTY_TARGET))
- return 0;
-
- if (read_one_line_file("/sys/class/tty/console/active", &active) >= 0) {
- const char *tty;
-
- truncate_nl(active);
- if ((tty = strrchr(active, ' ')))
- tty ++;
- else
- tty = active;
-
- /* Automatically add in a serial getty on the kernel
- * console */
- if (!tty_is_vc(tty)) {
-
- /* We assume that gettys on virtual terminals are
- * started via manual configuration and do this magic
- * only for non-VC terminals. */
-
- log_debug("Automatically adding serial getty for /dev/%s", tty);
- if (!(n = unit_name_replace_instance(SPECIAL_SERIAL_GETTY_SERVICE, tty))) {
- free(active);
- return -ENOMEM;
- }
-
- r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_WANTS, n, NULL, true);
- free(n);
-
- if (r < 0) {
- free(active);
- return r;
- }
- }
-
- free(active);
- }
-
- /* Automatically add in a serial getty on the first
- * virtualizer console */
- if (access("/sys/class/tty/hvc0", F_OK) == 0) {
- log_debug("Automatic adding serial getty for hvc0");
- if (!(n = unit_name_replace_instance(SPECIAL_SERIAL_GETTY_SERVICE, "hvc0")))
- return -ENOMEM;
-
- r = unit_add_two_dependencies_by_name(UNIT(t), UNIT_AFTER, UNIT_WANTS, n, NULL, true);
- free(n);
-
- if (r < 0)
- return r;
- }
-
- return 0;
-}
-
static int target_load(Unit *u) {
Target *t = TARGET(u);
int r;
@@ -158,9 +97,6 @@ static int target_load(Unit *u) {
if (u->meta.default_dependencies)
if ((r = target_add_default_dependencies(t)) < 0)
return r;
-
- if ((r = target_add_getty_dependencies(t)) < 0)
- return r;
}
return 0;
diff --git a/src/tmpfiles.c b/src/tmpfiles.c
index 68af37aab..b21df95a7 100644
--- a/src/tmpfiles.c
+++ b/src/tmpfiles.c
@@ -47,9 +47,8 @@
/* This reads all files listed in /etc/tmpfiles.d/?*.conf and creates
* them in the file system. This is intended to be used to create
- * properly owned directories beneath /tmp, /var/tmp, /var/run and
- * /var/lock which are volatile and hence need to be recreated on
- * bootup. */
+ * properly owned directories beneath /tmp, /var/tmp, /run, which are
+ * volatile and hence need to be recreated on bootup. */
enum {
/* These ones take file names */
@@ -466,6 +465,7 @@ static int create_item(Item *i) {
case CREATE_DIRECTORY:
u = umask(0);
+ mkdir_parents(i->path, 0755);
r = mkdir(i->path, i->mode);
umask(u);
diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c
index 35e4d63a8..dcf4b332b 100644
--- a/src/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent.c
@@ -251,12 +251,12 @@ static int parse_password(const char *filename, char **wall) {
bool accept_cached = false;
const ConfigItem items[] = {
- { "Socket", config_parse_string, &socket_name, "Ask" },
- { "NotAfter", config_parse_uint64, ¬_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 }
+ { "Socket", config_parse_string, 0, &socket_name, "Ask" },
+ { "NotAfter", config_parse_uint64, 0, ¬_after, "Ask" },
+ { "Message", config_parse_string, 0, &message, "Ask" },
+ { "PID", config_parse_unsigned, 0, &pid, "Ask" },
+ { "AcceptCached", config_parse_bool, 0, &accept_cached, "Ask" },
+ { NULL, NULL, 0, NULL, NULL }
};
FILE *f;
@@ -431,7 +431,7 @@ static int wall_tty_block(void) {
if ((r = get_ctty_devnr(&devnr)) < 0)
return -r;
- if (asprintf(&p, "/dev/.systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0)
+ if (asprintf(&p, "/run/systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0)
return -ENOMEM;
mkdir_parents(p, 0700);
@@ -475,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/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0)
+ if (asprintf(&p, "/run/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);
@@ -494,7 +494,7 @@ static int show_passwords(void) {
struct dirent *de;
int r = 0;
- if (!(d = opendir("/dev/.systemd/ask-password"))) {
+ if (!(d = opendir("/run/systemd/ask-password"))) {
if (errno == ENOENT)
return 0;
@@ -519,7 +519,7 @@ static int show_passwords(void) {
if (!startswith(de->d_name, "ask."))
continue;
- if (!(p = strappend("/dev/.systemd/ask-password/", de->d_name))) {
+ if (!(p = strappend("/run/systemd/ask-password/", de->d_name))) {
log_error("Out of memory");
r = -ENOMEM;
goto finish;
@@ -558,14 +558,14 @@ static int watch_passwords(void) {
tty_block_fd = wall_tty_block();
- mkdir_p("/dev/.systemd/ask-password", 0755);
+ mkdir_p("/run/systemd/ask-password", 0755);
if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
r = -errno;
goto finish;
}
- if (inotify_add_watch(notify, "/dev/.systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) {
+ if (inotify_add_watch(notify, "/run/systemd/ask-password", IN_CLOSE_WRITE|IN_MOVED_TO) < 0) {
r = -errno;
goto finish;
}
diff --git a/src/umount.c b/src/umount.c
index 4fd6b22ad..3d328e0da 100644
--- a/src/umount.c
+++ b/src/umount.c
@@ -37,6 +37,7 @@
typedef struct MountPoint {
char *path;
dev_t devnum;
+ bool skip_ro;
LIST_FIELDS (struct MountPoint, mount_point);
} MountPoint;
@@ -71,6 +72,8 @@ static int mount_points_list_get(MountPoint **head) {
for (i = 1;; i++) {
int k;
MountPoint *m;
+ char *root;
+ bool skip_ro;
path = p = NULL;
@@ -78,7 +81,7 @@ static int mount_points_list_get(MountPoint **head) {
"%*s " /* (1) mount id */
"%*s " /* (2) parent id */
"%*s " /* (3) major:minor */
- "%*s " /* (4) root */
+ "%ms " /* (4) root */
"%ms " /* (5) mount point */
"%*s" /* (6) mount options */
"%*[^-]" /* (7) optional fields */
@@ -87,7 +90,8 @@ static int mount_points_list_get(MountPoint **head) {
"%*s" /* (10) mount source */
"%*s" /* (11) mount options 2 */
"%*[^\n]", /* some rubbish at the end */
- &path)) != 1) {
+ &root,
+ &path)) != 2) {
if (k == EOF)
break;
@@ -97,6 +101,11 @@ static int mount_points_list_get(MountPoint **head) {
continue;
}
+ /* If we encounter a bind mount, don't try to remount
+ * the source dir too early */
+ skip_ro = !streq(root, "/");
+ free(root);
+
p = cunescape(path);
free(path);
@@ -117,6 +126,7 @@ static int mount_points_list_get(MountPoint **head) {
}
m->path = p;
+ m->skip_ro = skip_ro;
LIST_PREPEND(MountPoint, mount_point, *head, m);
}
@@ -355,7 +365,7 @@ static int delete_loopback(const char *device) {
int fd, r;
if ((fd = open(device, O_RDONLY|O_CLOEXEC)) < 0)
- return -errno;
+ return errno == ENOENT ? 0 : -errno;
r = ioctl(fd, LOOP_CLR_FD, 0);
close_nointr_nofail(fd);
@@ -428,6 +438,11 @@ static int mount_points_list_remount_read_only(MountPoint **head, bool *changed)
LIST_FOREACH_SAFE(mount_point, m, n, *head) {
+ if (m->skip_ro) {
+ n_failed++;
+ continue;
+ }
+
/* Trying to remount read-only */
if (mount(NULL, m->path, NULL, MS_MGC_VAL|MS_REMOUNT|MS_RDONLY, NULL) == 0) {
if (changed)
diff --git a/src/unit.c b/src/unit.c
index 450b190c0..e4345aeff 100644
--- a/src/unit.c
+++ b/src/unit.c
@@ -647,6 +647,13 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
condition_dump_list(u->meta.conditions, f, prefix);
+ if (dual_timestamp_is_set(&u->meta.condition_timestamp))
+ fprintf(f,
+ "%s\tCondition Timestamp: %s\n"
+ "%s\tCondition Result: %s\n",
+ prefix, strna(format_timestamp(timestamp1, sizeof(timestamp1), u->meta.condition_timestamp.realtime)),
+ prefix, yes_no(u->meta.condition_result));
+
for (d = 0; d < _UNIT_DEPENDENCY_MAX; d++) {
Unit *other;
@@ -825,6 +832,15 @@ fail:
return r;
}
+bool unit_condition_test(Unit *u) {
+ assert(u);
+
+ dual_timestamp_get(&u->meta.condition_timestamp);
+ u->meta.condition_result = condition_test_list(u->meta.conditions);
+
+ return u->meta.condition_result;
+}
+
/* Errors:
* -EBADR: This unit type does not support starting.
* -EALREADY: Unit is already started.
@@ -849,7 +865,7 @@ int unit_start(Unit *u) {
return -EALREADY;
/* If the conditions failed, don't do anything at all */
- if (!condition_test_list(u->meta.conditions)) {
+ if (!unit_condition_test(u)) {
log_debug("Starting of %s requested but condition failed. Ignoring.", u->meta.id);
return -EALREADY;
}
@@ -1085,7 +1101,6 @@ void unit_trigger_on_failure(Unit *u) {
}
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) {
- dual_timestamp ts;
bool unexpected;
assert(u);
@@ -1098,24 +1113,28 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
* behaviour here. For example: if a mount point is remounted
* this function will be called too! */
- dual_timestamp_get(&ts);
+ if (u->meta.manager->n_deserializing <= 0) {
+ dual_timestamp ts;
- if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
- u->meta.inactive_exit_timestamp = ts;
- else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns))
- u->meta.inactive_enter_timestamp = ts;
+ dual_timestamp_get(&ts);
- if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
- u->meta.active_enter_timestamp = ts;
- else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
- u->meta.active_exit_timestamp = ts;
+ if (UNIT_IS_INACTIVE_OR_FAILED(os) && !UNIT_IS_INACTIVE_OR_FAILED(ns))
+ u->meta.inactive_exit_timestamp = ts;
+ else if (!UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_INACTIVE_OR_FAILED(ns))
+ u->meta.inactive_enter_timestamp = ts;
+
+ if (!UNIT_IS_ACTIVE_OR_RELOADING(os) && UNIT_IS_ACTIVE_OR_RELOADING(ns))
+ u->meta.active_enter_timestamp = ts;
+ else if (UNIT_IS_ACTIVE_OR_RELOADING(os) && !UNIT_IS_ACTIVE_OR_RELOADING(ns))
+ u->meta.active_exit_timestamp = ts;
+
+ timer_unit_notify(u, ns);
+ path_unit_notify(u, ns);
+ }
if (UNIT_IS_INACTIVE_OR_FAILED(ns))
cgroup_bonding_trim_list(u->meta.cgroup_bondings, true);
- timer_unit_notify(u, ns);
- path_unit_notify(u, ns);
-
if (u->meta.job) {
unexpected = false;
@@ -1182,40 +1201,40 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
} else
unexpected = true;
- /* If this state change happened without being requested by a
- * job, then let's retroactively start or stop
- * dependencies. We skip that step when deserializing, since
- * we don't want to create any additional jobs just because
- * something is already activated. */
+ if (u->meta.manager->n_deserializing <= 0) {
- if (unexpected && u->meta.manager->n_deserializing <= 0) {
- if (UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns))
- retroactively_start_dependencies(u);
- else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
- retroactively_stop_dependencies(u);
- }
+ /* If this state change happened without being
+ * requested by a job, then let's retroactively start
+ * or stop dependencies. We skip that step when
+ * deserializing, since we don't want to create any
+ * additional jobs just because something is already
+ * activated. */
- if (ns != os && ns == UNIT_FAILED) {
- log_notice("Unit %s entered failed state.", u->meta.id);
- unit_trigger_on_failure(u);
+ if (unexpected) {
+ if (UNIT_IS_INACTIVE_OR_FAILED(os) && UNIT_IS_ACTIVE_OR_ACTIVATING(ns))
+ retroactively_start_dependencies(u);
+ else if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
+ retroactively_stop_dependencies(u);
+ }
+
+ if (ns != os && ns == UNIT_FAILED) {
+ log_notice("Unit %s entered failed state.", u->meta.id);
+ unit_trigger_on_failure(u);
+ }
}
/* Some names are special */
if (UNIT_IS_ACTIVE_OR_RELOADING(ns)) {
+
if (unit_has_name(u, SPECIAL_DBUS_SERVICE))
/* The bus just might have become available,
* hence try to connect to it, if we aren't
* yet connected. */
bus_init(u->meta.manager, true);
- if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE))
- /* The syslog daemon just might have become
- * available, hence try to connect to it, if
- * we aren't yet connected. */
- log_open();
-
if (u->meta.type == UNIT_SERVICE &&
- !UNIT_IS_ACTIVE_OR_RELOADING(os)) {
+ !UNIT_IS_ACTIVE_OR_RELOADING(os) &&
+ u->meta.manager->n_deserializing <= 0) {
/* Write audit record if we have just finished starting up */
manager_send_unit_audit(u->meta.manager, u, AUDIT_SERVICE_START, true);
u->meta.in_audit = true;
@@ -1226,18 +1245,13 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
} else {
- if (unit_has_name(u, SPECIAL_SYSLOG_SERVICE))
- /* The syslog daemon might just have
- * terminated, hence try to disconnect from
- * it. */
- log_close_syslog();
-
/* We don't care about D-Bus here, since we'll get an
* asynchronous notification for it anyway. */
if (u->meta.type == UNIT_SERVICE &&
UNIT_IS_INACTIVE_OR_FAILED(ns) &&
- !UNIT_IS_INACTIVE_OR_FAILED(os)) {
+ !UNIT_IS_INACTIVE_OR_FAILED(os) &&
+ u->meta.manager->n_deserializing <= 0) {
/* Hmm, if there was no start record written
* write it now, so that we always have a nice
@@ -1255,6 +1269,8 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
}
}
+ manager_recheck_syslog(u->meta.manager);
+
/* Maybe we finished startup and are now ready for being
* stopped because unneeded? */
unit_check_unneeded(u);
@@ -2019,8 +2035,7 @@ char **unit_full_printf_strv(Unit *u, char **l) {
return r;
fail:
- j--;
- while (j >= r)
+ for (j--; j >= r; j--)
free(*j);
free(r);
@@ -2071,6 +2086,10 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds) {
dual_timestamp_serialize(f, "active-enter-timestamp", &u->meta.active_enter_timestamp);
dual_timestamp_serialize(f, "active-exit-timestamp", &u->meta.active_exit_timestamp);
dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->meta.inactive_enter_timestamp);
+ dual_timestamp_serialize(f, "condition-timestamp", &u->meta.condition_timestamp);
+
+ if (dual_timestamp_is_set(&u->meta.condition_timestamp))
+ unit_serialize_item(u, f, "condition-result", yes_no(u->meta.condition_result));
/* End marker */
fputc('\n', f);
@@ -2160,6 +2179,18 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
} else if (streq(l, "inactive-enter-timestamp")) {
dual_timestamp_deserialize(v, &u->meta.inactive_enter_timestamp);
continue;
+ } else if (streq(l, "condition-timestamp")) {
+ dual_timestamp_deserialize(v, &u->meta.condition_timestamp);
+ continue;
+ } else if (streq(l, "condition-result")) {
+ int b;
+
+ if ((b = parse_boolean(v)) < 0)
+ log_debug("Failed to parse condition result value %s", v);
+ else
+ u->meta.condition_result = b;
+
+ continue;
}
if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0)
@@ -2211,7 +2242,7 @@ int unit_coldplug(Unit *u) {
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, NULL)) < 0)
+ if ((r = manager_add_job(u->meta.manager, u->meta.deserialized_job, u, JOB_IGNORE_REQUIREMENTS, false, NULL, NULL)) < 0)
return r;
u->meta.deserialized_job = _JOB_TYPE_INVALID;
@@ -2232,7 +2263,10 @@ void unit_status_printf(Unit *u, const char *format, ...) {
if (u->meta.manager->running_as != MANAGER_SYSTEM)
return;
- if (!u->meta.manager->show_status)
+ /* If Plymouth is running make sure we show the status, so
+ * that there's something nice to see when people press Esc */
+
+ if (!u->meta.manager->show_status && !plymouth_running())
return;
if (!manager_is_booting_or_shutting_down(u->meta.manager))
diff --git a/src/unit.h b/src/unit.h
index 5f55a89da..4245f3cf1 100644
--- a/src/unit.h
+++ b/src/unit.h
@@ -40,9 +40,6 @@ typedef enum UnitDependency UnitDependency;
#include "execute.h"
#include "condition.h"
-#define DEFAULT_TIMEOUT_USEC (3*USEC_PER_MINUTE)
-#define DEFAULT_RESTART_USEC (100*USEC_PER_MSEC)
-
enum UnitType {
UNIT_SERVICE = 0,
UNIT_SOCKET,
@@ -160,6 +157,8 @@ struct Meta {
/* Conditions to check */
LIST_HEAD(Condition, conditions);
+ dual_timestamp condition_timestamp;
+
dual_timestamp inactive_exit_timestamp;
dual_timestamp active_enter_timestamp;
dual_timestamp active_exit_timestamp;
@@ -208,6 +207,9 @@ struct Meta {
/* Allow isolation requests */
bool allow_isolate;
+ /* Did the last condition check suceed? */
+ bool condition_result;
+
bool in_load_queue:1;
bool in_dbus_queue:1;
bool in_cleanup_queue:1;
@@ -513,6 +515,8 @@ bool unit_name_is_valid(const char *n, bool template_ok);
void unit_trigger_on_failure(Unit *u);
+bool unit_condition_test(Unit *u);
+
const char *unit_load_state_to_string(UnitLoadState i);
UnitLoadState unit_load_state_from_string(const char *s);
diff --git a/src/user-sessions.c b/src/user-sessions.c
index 802696156..4518d953e 100644
--- a/src/user-sessions.c
+++ b/src/user-sessions.c
@@ -42,8 +42,8 @@ int main(int argc, char*argv[]) {
if (streq(argv[1], "start")) {
int q = 0, r = 0;
- if (unlink("/var/run/nologin") < 0 && errno != ENOENT) {
- log_error("Failed to remove /var/run/nologin file: %m");
+ if (unlink("/run/nologin") < 0 && errno != ENOENT) {
+ log_error("Failed to remove /run/nologin file: %m");
r = -errno;
}
@@ -57,14 +57,25 @@ int main(int argc, char*argv[]) {
} else if (streq(argv[1], "stop")) {
int r, q;
+ char *cgroup_user_tree = NULL;
- if ((r = write_one_line_file("/var/run/nologin", "System is going down.")) < 0)
- log_error("Failed to create /var/run/nologin: %s", strerror(-r));
+ if ((r = write_one_line_file("/run/nologin", "System is going down.")) < 0)
+ log_error("Failed to create /run/nologin: %s", strerror(-r));
- if ((q = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, "/user", true)) < 0)
+ if ((q = cg_get_user_path(&cgroup_user_tree)) < 0) {
+ log_error("Failed to determine use path: %s", strerror(-q));
+ goto finish;
+ }
+
+ q = cg_kill_recursive_and_wait(SYSTEMD_CGROUP_CONTROLLER, cgroup_user_tree, true);
+ free(cgroup_user_tree);
+
+ if (q < 0) {
log_error("Failed to kill sessions: %s", strerror(-q));
+ goto finish;
+ }
- if (r < 0 || q < 0)
+ if (r < 0)
goto finish;
} else {
diff --git a/src/util.c b/src/util.c
index 96cf6605f..5daafdf7c 100644
--- a/src/util.c
+++ b/src/util.c
@@ -61,6 +61,20 @@
#include "exit-status.h"
#include "hashmap.h"
+size_t page_size(void) {
+ static __thread size_t pgsz = 0;
+ long r;
+
+ if (pgsz)
+ return pgsz;
+
+ assert_se((r = sysconf(_SC_PAGESIZE)) > 0);
+
+ pgsz = (size_t) r;
+
+ return pgsz;
+}
+
bool streq_ptr(const char *a, const char *b) {
/* Like streq(), but tries to make sense of NULL pointers */
@@ -499,7 +513,16 @@ int write_one_line_file(const char *fn, const char *line) {
if (!endswith(line, "\n"))
fputc('\n', f);
- r = 0;
+ fflush(f);
+
+ if (ferror(f)) {
+ if (errno != 0)
+ r = -errno;
+ else
+ r = -EIO;
+ } else
+ r = 0;
+
finish:
fclose(f);
return r;
@@ -1815,8 +1838,9 @@ int close_all_fds(const int except[], unsigned n_except) {
if (ignore_file(de->d_name))
continue;
- if ((r = safe_atoi(de->d_name, &fd)) < 0)
- goto finish;
+ if (safe_atoi(de->d_name, &fd) < 0)
+ /* Let's better ignore this, just in case */
+ continue;
if (fd < 3)
continue;
@@ -1839,16 +1863,13 @@ int close_all_fds(const int except[], unsigned n_except) {
continue;
}
- if ((r = close_nointr(fd)) < 0) {
+ if (close_nointr(fd) < 0) {
/* Valgrind has its own FD and doesn't want to have it closed */
- if (errno != EBADF)
- goto finish;
+ if (errno != EBADF && r == 0)
+ r = -errno;
}
}
- r = 0;
-
-finish:
closedir(d);
return r;
}
@@ -2867,7 +2888,7 @@ int getttyname_harder(int fd, char **r) {
if (streq(s, "tty")) {
free(s);
- return get_ctty(r);
+ return get_ctty(r, NULL);
}
*r = s;
@@ -2909,7 +2930,7 @@ int get_ctty_devnr(dev_t *d) {
return 0;
}
-int get_ctty(char **r) {
+int get_ctty(char **r, dev_t *_devnr) {
int k;
char fn[128], *s, *b, *p;
dev_t devnr;
@@ -2927,6 +2948,18 @@ int get_ctty(char **r) {
if (k != -ENOENT)
return k;
+ /* This is an ugly hack */
+ if (major(devnr) == 136) {
+ if (asprintf(&b, "pts/%lu", (unsigned long) minor(devnr)) < 0)
+ return -ENOMEM;
+
+ *r = b;
+ if (_devnr)
+ *_devnr = devnr;
+
+ return 0;
+ }
+
/* Probably something like the ptys which have no
* symlink in /dev/char. Let's return something
* vaguely useful. */
@@ -2935,6 +2968,9 @@ int get_ctty(char **r) {
return -ENOMEM;
*r = b;
+ if (_devnr)
+ *_devnr = devnr;
+
return 0;
}
@@ -2952,6 +2988,9 @@ int get_ctty(char **r) {
return -ENOMEM;
*r = b;
+ if (_devnr)
+ *_devnr = devnr;
+
return 0;
}
@@ -3508,7 +3547,7 @@ int touch(const char *path) {
assert(path);
- if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0666)) < 0)
+ if ((fd = open(path, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY, 0644)) < 0)
return -errno;
close_nointr_nofail(fd);
@@ -3552,7 +3591,6 @@ char *normalize_env_assignment(const char *s) {
free(p);
if (!value) {
- free(p);
free(name);
return NULL;
}
@@ -3600,7 +3638,7 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid) {
if (status.si_code == CLD_EXITED) {
if (status.si_status != 0) {
log_warning("%s failed with error code %i.", name, status.si_status);
- return -EPROTO;
+ return status.si_status;
}
log_debug("%s succeeded.", name);
@@ -3619,6 +3657,10 @@ int wait_for_terminate_and_warn(const char *name, pid_t pid) {
}
void freeze(void) {
+
+ /* Make sure nobody waits for us on a socket anymore */
+ close_all_fds(NULL, 0);
+
sync();
for (;;)
@@ -3820,8 +3862,7 @@ int detect_vm(const char **id) {
"Microsoft Corporation\0" "microsoft\0"
"innotek GmbH\0" "oracle\0"
"Xen\0" "xen\0"
- "Bochs\0" "bochs\0"
- "\0";
+ "Bochs\0" "bochs\0";
static const char cpuid_vendor_table[] =
"XenVMMXenVMM\0" "xen\0"
@@ -3829,8 +3870,7 @@ int detect_vm(const char **id) {
/* 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";
+ "Microsoft Hv\0" "microsoft\0";
uint32_t eax, ecx;
union {
@@ -3927,20 +3967,21 @@ int detect_vm(const char **id) {
return 0;
}
-/* Returns a short identifier for the various VM/container implementations */
-int detect_virtualization(const char **id) {
- int r;
+int detect_container(const char **id) {
+ FILE *f;
- /* Unfortunately most of these operations require root access
+ /* Unfortunately many of these operations require root access
* in one way or another */
+
if (geteuid() != 0)
return -EPERM;
- if ((r = running_in_chroot()) > 0) {
+ if (running_in_chroot() > 0) {
+
if (id)
*id = "chroot";
- return r;
+ return 1;
}
/* /proc/vz exists in container and outside of the container,
@@ -3954,7 +3995,68 @@ int detect_virtualization(const char **id) {
return 1;
}
- return detect_vm(id);
+ if ((f = fopen("/proc/self/cgroup", "r"))) {
+
+ for (;;) {
+ char line[LINE_MAX], *p;
+
+ if (!fgets(line, sizeof(line), f))
+ break;
+
+ if (!(p = strchr(strstrip(line), ':')))
+ continue;
+
+ if (strncmp(p, ":ns:", 4))
+ continue;
+
+ if (!streq(p, ":ns:/")) {
+ fclose(f);
+
+ if (id)
+ *id = "pidns";
+
+ return 1;
+ }
+ }
+
+ fclose(f);
+ }
+
+ return 0;
+}
+
+/* Returns a short identifier for the various VM/container implementations */
+int detect_virtualization(const char **id) {
+ static __thread const char *cached_id = NULL;
+ const char *_id;
+ int r;
+
+ if (cached_id) {
+
+ if (cached_id == (const char*) -1)
+ return 0;
+
+ if (id)
+ *id = cached_id;
+
+ return 1;
+ }
+
+ if ((r = detect_container(&_id)) != 0)
+ goto finish;
+
+ r = detect_vm(&_id);
+
+finish:
+ if (r > 0) {
+ cached_id = _id;
+
+ if (id)
+ *id = _id;
+ } else if (r == 0)
+ cached_id = (const char*) -1;
+
+ return r;
}
void execute_directory(const char *directory, DIR *d, char *argv[]) {
@@ -4081,6 +4183,59 @@ int kill_and_sigcont(pid_t pid, int sig) {
return r;
}
+bool nulstr_contains(const char*nulstr, const char *needle) {
+ const char *i;
+
+ if (!nulstr)
+ return false;
+
+ NULSTR_FOREACH(i, nulstr)
+ if (streq(i, needle))
+ return true;
+
+ return false;
+}
+
+bool plymouth_running(void) {
+ return access("/run/plymouth/pid", F_OK) >= 0;
+}
+
+void parse_syslog_priority(char **p, int *priority) {
+ int a = 0, b = 0, c = 0;
+ int k;
+
+ assert(p);
+ assert(*p);
+ assert(priority);
+
+ if ((*p)[0] != '<')
+ return;
+
+ if (!strchr(*p, '>'))
+ return;
+
+ if ((*p)[2] == '>') {
+ c = undecchar((*p)[1]);
+ k = 3;
+ } else if ((*p)[3] == '>') {
+ b = undecchar((*p)[1]);
+ c = undecchar((*p)[2]);
+ k = 4;
+ } else if ((*p)[4] == '>') {
+ a = undecchar((*p)[1]);
+ b = undecchar((*p)[2]);
+ c = undecchar((*p)[3]);
+ k = 5;
+ } else
+ return;
+
+ if (a < 0 || b < 0 || c < 0)
+ return;
+
+ *priority = a*100+b*10+c;
+ *p += k;
+}
+
static const char *const ioprio_class_table[] = {
[IOPRIO_CLASS_NONE] = "none",
[IOPRIO_CLASS_RT] = "realtime",
@@ -4101,7 +4256,7 @@ static const char *const sigchld_code_table[] = {
DEFINE_STRING_TABLE_LOOKUP(sigchld_code, int);
-static const char *const log_facility_table[LOG_NFACILITIES] = {
+static const char *const log_facility_unshifted_table[LOG_NFACILITIES] = {
[LOG_FAC(LOG_KERN)] = "kern",
[LOG_FAC(LOG_USER)] = "user",
[LOG_FAC(LOG_MAIL)] = "mail",
@@ -4124,7 +4279,7 @@ static const char *const log_facility_table[LOG_NFACILITIES] = {
[LOG_FAC(LOG_LOCAL7)] = "local7"
};
-DEFINE_STRING_TABLE_LOOKUP(log_facility, int);
+DEFINE_STRING_TABLE_LOOKUP(log_facility_unshifted, int);
static const char *const log_level_table[] = {
[LOG_EMERG] = "emerg",
diff --git a/src/util.h b/src/util.h
index a2e3b9443..ff38b3580 100644
--- a/src/util.h
+++ b/src/util.h
@@ -83,6 +83,9 @@ struct timespec *timespec_store(struct timespec *ts, usec_t u);
usec_t timeval_load(const struct timeval *tv);
struct timeval *timeval_store(struct timeval *tv, usec_t u);
+size_t page_size(void);
+#define PAGE_ALIGN(l) ALIGN_TO((l), page_size())
+
#define streq(a,b) (strcmp((a),(b)) == 0)
#define strneq(a, b, n) (strncmp((a), (b), (n)) == 0)
@@ -337,7 +340,7 @@ 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 get_ctty(char **r, dev_t *_devnr);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
@@ -380,12 +383,19 @@ bool tty_is_vc(const char *tty);
const char *default_term_for_tty(const char *tty);
int detect_vm(const char **id);
+int detect_container(const char **id);
int detect_virtualization(const char **id);
void execute_directory(const char *directory, DIR *_d, char *argv[]);
int kill_and_sigcont(pid_t pid, int sig);
+bool nulstr_contains(const char*nulstr, const char *needle);
+
+bool plymouth_running(void);
+
+void parse_syslog_priority(char **p, int *priority);
+
#define NULSTR_FOREACH(i, l) \
for ((i) = (l); (i) && *(i); (i) = strchr((i), 0)+1)
@@ -398,8 +408,8 @@ int ioprio_class_from_string(const char *s);
const char *sigchld_code_to_string(int i);
int sigchld_code_from_string(const char *s);
-const char *log_facility_to_string(int i);
-int log_facility_from_string(const char *s);
+const char *log_facility_unshifted_to_string(int i);
+int log_facility_unshifted_from_string(const char *s);
const char *log_level_to_string(int i);
int log_level_from_string(const char *s);
diff --git a/src/vconsole-setup.c b/src/vconsole-setup.c
index 5b977126f..67fb7b610 100644
--- a/src/vconsole-setup.c
+++ b/src/vconsole-setup.c
@@ -176,21 +176,22 @@ int main(int argc, char **argv) {
utf8 = is_locale_utf8();
- if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
+ if (detect_container(NULL) <= 0)
+ if ((r = parse_env_file("/proc/cmdline", WHITESPACE,
#ifdef TARGET_FEDORA
- "SYSFONT", &vc_font,
- "KEYTABLE", &vc_keymap,
+ "SYSFONT", &vc_font,
+ "KEYTABLE", &vc_keymap,
#endif
- "vconsole.keymap", &vc_keymap,
- "vconsole.keymap.toggle", &vc_keymap_toggle,
- "vconsole.font", &vc_font,
- "vconsole.font.map", &vc_font_map,
- "vconsole.font.unimap", &vc_font_unimap,
- NULL)) < 0) {
+ "vconsole.keymap", &vc_keymap,
+ "vconsole.keymap.toggle", &vc_keymap_toggle,
+ "vconsole.font", &vc_font,
+ "vconsole.font.map", &vc_font_map,
+ "vconsole.font.unimap", &vc_font_unimap,
+ NULL)) < 0) {
- if (r != -ENOENT)
- log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
- }
+ if (r != -ENOENT)
+ log_warning("Failed to read /proc/cmdline: %s", strerror(-r));
+ }
/* Hmm, nothing set on the kernel cmd line? Then let's
* try /etc/vconsole.conf */
diff --git a/systemd.pc.in b/systemd.pc.in
index 204991309..2e2217ec4 100644
--- a/systemd.pc.in
+++ b/systemd.pc.in
@@ -8,9 +8,11 @@
prefix=@prefix@
exec_prefix=${prefix}
systemdsystemunitdir=@systemunitdir@
-systemduserunitdir=@pkgdatadir@/user
+systemduserunitdir=@userunitdir@
systemdsystemconfdir=@pkgsysconfdir@/system
systemduserconfdir=@pkgsysconfdir@/user
+systemdsystemunitpath=/run/systemd/system:${systemdsystemconfdir}:/etc/systemd/system:/usr/local/share/systemd/system:/usr/local/lib/systemd/system:/usr/share/systemd/system:/usr/lib/systemd/system:/lib/systemd/system:${systemdsystemunitdir}
+systemduserunitpath=${systemduserconfdir}:/etc/systemd/user:/usr/local/share/systemd/user:/usr/local/lib/systemd/user:/usr/share/systemd/user:/usr/lib/systemd/user:${systemduserunitdir}
Name: systemd
Description: systemd System and Service Manager
diff --git a/tmpfiles.d/legacy.conf b/tmpfiles.d/legacy.conf
new file mode 100644
index 000000000..9198e89dd
--- /dev/null
+++ b/tmpfiles.d/legacy.conf
@@ -0,0 +1,22 @@
+# 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.
+
+# See tmpfiles.d(5) for details
+
+# These files are considered legacy and are unnecessary on legacy-free
+# systems. /run/lock/subsys is used for serializing SysV service
+# execution, and hence without use on SysV-less systems.
+#
+# /run/lock/lockdev is used to serialize access to tty devices via
+# LCK..xxx style lock files, For more information see:
+# http://lists.freedesktop.org/archives/systemd-devel/2011-March/001823.html
+# On modern systems a BSD file lock is a better choice if
+# serialization is needed on those devices.
+
+d /run/lock 0755 root root -
+d /run/lock/subsys 0755 root root -
+d /run/lock/lockdev 0775 root lock -
diff --git a/tmpfiles.d/systemd.conf b/tmpfiles.d/systemd.conf
index 880a6ed7d..2ab8e2bba 100644
--- a/tmpfiles.d/systemd.conf
+++ b/tmpfiles.d/systemd.conf
@@ -7,9 +7,9 @@
# See tmpfiles.d(5) for details
-d /var/lock/subsys 0755 root root -
-d /var/run/user 0755 root root 10d
-F /var/run/utmp 0664 root utmp -
+d /run/user 0755 root root 10d
+F /run/utmp 0664 root utmp -
+
f /var/log/wtmp 0664 root utmp -
f /var/log/btmp 0600 root utmp -
diff --git a/units/.gitignore b/units/.gitignore
index 008446d4b..cbf9f255f 100644
--- a/units/.gitignore
+++ b/units/.gitignore
@@ -1,3 +1,4 @@
+console-shell.service
systemd-sysctl.service
systemd-ask-password-console.service
rescue.service
@@ -28,11 +29,9 @@ systemd-random-seed-load.service
systemd-random-seed-save.service
systemd-initctl.service
systemd-logger.service
-syslog.target
-graphical.target
-multi-user.target
getty@.service
remote-fs.target
systemd-update-utmp-runlevel.service
systemd-update-utmp-shutdown.service
test-env-replace
+systemd-binfmt.service
diff --git a/units/console-shell.service.m4 b/units/console-shell.service.m4
new file mode 100644
index 000000000..cce2d5a5a
--- /dev/null
+++ b/units/console-shell.service.m4
@@ -0,0 +1,41 @@
+# 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=Console Shell
+After=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
+m4_ifdef(`TARGET_MANDRIVA',
+After=rc-local.service
+)m4_dnl
+Before=getty.target
+
+[Service]
+Environment=HOME=/root
+WorkingDirectory=/root
+ExecStart=-/sbin/sulogin
+ExecStopPost=-/bin/systemctl poweroff
+StandardInput=tty-force
+KillMode=process
+
+# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
+# terminates cleanly.
+KillSignal=SIGHUP
+
+[Install]
+WantedBy=getty.target
diff --git a/units/emergency.service b/units/emergency.service
index cb28a7838..a97ec5e38 100644
--- a/units/emergency.service
+++ b/units/emergency.service
@@ -21,7 +21,7 @@ ExecStartPre=-/bin/echo 'Welcome to emergency mode. Use "systemctl default" or ^
ExecStart=-/sbin/sulogin
ExecStopPost=/bin/systemctl --fail default
StandardInput=tty-force
-KillMode=process-group
+KillMode=process
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
# terminates cleanly.
diff --git a/units/frugalware/display-manager.service b/units/frugalware/display-manager.service
new file mode 100644
index 000000000..a092c56de
--- /dev/null
+++ b/units/frugalware/display-manager.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=Display Manager
+After=syslog.target local.service systemd-user-sessions.service
+
+Conflicts=splashy-quit.service
+After=splashy-quit.service
+
+[Service]
+EnvironmentFile=/etc/sysconfig/desktop
+ExecStart=/bin/bash -c "exec ${desktop}"
+Restart=always
+RestartSec=0
diff --git a/units/fsck-root.service.in b/units/fsck-root.service.in
index 290c8453c..8f4adc48e 100644
--- a/units/fsck-root.service.in
+++ b/units/fsck-root.service.in
@@ -12,7 +12,7 @@ After=systemd-readahead-collect.service systemd-readahead-replay.service
Before=local-fs.target shutdown.target remount-rootfs.service quotacheck.service
# Dracut informs us with this flag file if the root fsck was already run
-ConditionPathExists=!/dev/.initramfs/fsck
+ConditionPathExists=!/run/initramfs/root-fsck
[Service]
Type=oneshot
diff --git a/units/getty@.service.m4 b/units/getty@.service.m4
index 8e1f250ad..a9733a60d 100644
--- a/units/getty@.service.m4
+++ b/units/getty@.service.m4
@@ -36,11 +36,11 @@ ExecStart=-/sbin/agetty %I 38400
Restart=always
RestartSec=0
UtmpIdentifier=%I
-KillMode=process-group
+KillMode=process
# Unset locale for the console getty since the console has problems
# displaying some internationalized messages.
-Environment=LANG= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGE= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION=
+Environment=LANG= LC_CTYPE= LC_NUMERIC= LC_TIME= LC_COLLATE= LC_MONETARY= LC_MESSAGES= LC_PAPER= LC_NAME= LC_ADDRESS= LC_TELEPHONE= LC_MEASUREMENT= LC_IDENTIFICATION=
# Some login implementations ignore SIGTERM, so we send SIGHUP
# instead, to ensure that login terminates cleanly.
diff --git a/units/graphical.target.m4 b/units/graphical.target
similarity index 63%
rename from units/graphical.target.m4
rename to units/graphical.target
index 1931d7f98..f2e30341d 100644
--- a/units/graphical.target.m4
+++ b/units/graphical.target
@@ -12,20 +12,6 @@ Description=Graphical Interface
Requires=multi-user.target
After=multi-user.target
Conflicts=rescue.target
-m4_dnl
-m4_ifdef(`TARGET_FEDORA',
-# On Fedora Runlevel 5 is graphical login
-Names=runlevel5.target
-)m4_dnl
-m4_ifdef(`TARGET_SUSE',
-Names=runlevel5.target
-)m4_dnl
-m4_ifdef(`TARGET_ALTLINUX',
-Names=runlevel5.target
-)m4_dnl
-m4_ifdef(`TARGET_MANDRIVA',
-Names=runlevel5.target
-)m4_dnl
AllowIsolate=yes
[Install]
diff --git a/units/http-daemon.target b/units/http-daemon.target
index bd7a1ef0d..45f10182e 100644
--- a/units/http-daemon.target
+++ b/units/http-daemon.target
@@ -7,5 +7,8 @@
# See systemd.special(7) for details
+# This exists mostly for compatibility with SysV/LSB units, and
+# implementations lacking socket/bus activation.
+
[Unit]
Description=Web Server
diff --git a/units/hwclock-load.service b/units/hwclock-load.service
index 51f255e2a..f278a671a 100644
--- a/units/hwclock-load.service
+++ b/units/hwclock-load.service
@@ -8,9 +8,10 @@
[Unit]
Description=Apply System Clock UTC Offset
DefaultDependencies=no
+Wants=time-sync.target
Conflicts=shutdown.target
After=systemd-readahead-collect.service systemd-readahead-replay.service
-Before=sysinit.target shutdown.target udev.service
+Before=sysinit.target shutdown.target udev.service time-sync.target
[Service]
Type=oneshot
diff --git a/units/mail-transfer-agent.target b/units/mail-transfer-agent.target
index 2640076d6..ebb1ea125 100644
--- a/units/mail-transfer-agent.target
+++ b/units/mail-transfer-agent.target
@@ -7,5 +7,8 @@
# See systemd.special(7) for details
+# This exists mostly for compatibility with SysV/LSB units, and
+# implementations lacking socket/bus activation.
+
[Unit]
Description=Mail Transfer Agent
diff --git a/units/mandriva/prefdm.service b/units/mandriva/prefdm.service
index 43b505db8..d0c7f99c6 100644
--- a/units/mandriva/prefdm.service
+++ b/units/mandriva/prefdm.service
@@ -14,9 +14,6 @@ After=network.target acpid.service fs.service haldaemon.service
Conflicts=plymouth-quit.service
After=plymouth-quit.service
-# Hide SysV script
-Names=dm.service
-
[Service]
ExecStart=/etc/X11/prefdm
Type=forking
diff --git a/units/syslog.target.in b/units/multi-user.target
similarity index 54%
rename from units/syslog.target.in
rename to units/multi-user.target
index 37d5de368..66f1a950f 100644
--- a/units/syslog.target.in
+++ b/units/multi-user.target
@@ -8,10 +8,11 @@
# See systemd.special(7) for details
[Unit]
-Description=Syslog
+Description=Multi-User
+Requires=basic.target
+Conflicts=rescue.service rescue.target
+After=basic.target rescue.service rescue.target
+AllowIsolate=yes
-# As soon as all syslog services have native unit files this explicit
-# dependency should be dropped, and replaced by alias symlinks in the
-# .wants/ directory, to either the .service or .socket unit of the
-# syslog service.
-After=@SPECIAL_SYSLOG_SERVICE@
+[Install]
+Alias=default.target
diff --git a/units/multi-user.target.m4 b/units/multi-user.target.m4
deleted file mode 100644
index 51e7b6664..000000000
--- a/units/multi-user.target.m4
+++ /dev/null
@@ -1,38 +0,0 @@
-# This file is part of systemd.
-#
-# systemd is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-
-# See systemd.special(7) for details
-
-[Unit]
-Description=Multi-User
-Requires=basic.target
-Conflicts=rescue.service rescue.target
-After=basic.target rescue.service rescue.target
-m4_dnl
-m4_ifdef(`TARGET_FEDORA',
-m4_dnl On Fedora Runlevel 3 is multi-user
-Names=runlevel3.target
-)m4_dnl
-m4_ifdef(`TARGET_SUSE',
-Names=runlevel3.target
-)m4_dnl
-m4_ifdef(`TARGET_ALTLINUX',
-Names=runlevel3.target
-)m4_dnl
-m4_ifdef(`TARGET_DEBIAN',
-m4_ifdef(`TARGET_UBUNTU',
-m4_dnl On Debian/Ubuntu Runlevel 2, 3, 4 and 5 are multi-user
-Names=runlevel2.target runlevel3.target runlevel4.target runlevel5.target
-)m4_dnl
-)m4_dnl
-m4_ifdef(`TARGET_MANDRIVA',
-Names=runlevel3.target
-)m4_dnl
-AllowIsolate=yes
-
-[Install]
-Alias=default.target
diff --git a/units/nss-lookup.target b/units/nss-lookup.target
index 3158441b2..bdca03cd8 100644
--- a/units/nss-lookup.target
+++ b/units/nss-lookup.target
@@ -7,7 +7,9 @@
# See systemd.special(7) for details
+# This exists mostly for compatibility with SysV/LSB units, and
+# implementations lacking socket/bus activation.
+
[Unit]
Description=Name Lookups
-Wants=network.target
After=network.target
diff --git a/units/plymouth-halt.service b/units/plymouth-halt.service
index fa1a20a46..962d829ff 100644
--- a/units/plymouth-halt.service
+++ b/units/plymouth-halt.service
@@ -14,5 +14,4 @@ DefaultDependencies=no
[Service]
ExecStart=/sbin/plymouthd --mode=shutdown
ExecStartPost=-/bin/plymouth --show-splash
-ExecStartPost=-/bin/plymouth message '--text=Halting...'
Type=forking
diff --git a/units/plymouth-kexec.service b/units/plymouth-kexec.service
index 61c6376a7..0d7450fee 100644
--- a/units/plymouth-kexec.service
+++ b/units/plymouth-kexec.service
@@ -14,5 +14,4 @@ DefaultDependencies=no
[Service]
ExecStart=/sbin/plymouthd --mode=shutdown
ExecStartPost=-/bin/plymouth --show-splash
-ExecStartPost=-/bin/plymouth message '--text=Rebooting with kexec...'
Type=forking
diff --git a/units/plymouth-poweroff.service b/units/plymouth-poweroff.service
index c1eebb5ac..d4979df1e 100644
--- a/units/plymouth-poweroff.service
+++ b/units/plymouth-poweroff.service
@@ -14,5 +14,4 @@ DefaultDependencies=no
[Service]
ExecStart=/sbin/plymouthd --mode=shutdown
ExecStartPost=-/bin/plymouth --show-splash
-ExecStartPost=-/bin/plymouth message '--text=Powering Off...'
Type=forking
diff --git a/units/plymouth-reboot.service b/units/plymouth-reboot.service
index 974db31d6..7304a5fba 100644
--- a/units/plymouth-reboot.service
+++ b/units/plymouth-reboot.service
@@ -14,5 +14,4 @@ DefaultDependencies=no
[Service]
ExecStart=/sbin/plymouthd --mode=shutdown
ExecStartPost=-/bin/plymouth --show-splash
-ExecStartPost=-/bin/plymouth message '--text=Rebooting...'
Type=forking
diff --git a/units/plymouth-start.service b/units/plymouth-start.service
index c3c101eb8..10d03c6c6 100644
--- a/units/plymouth-start.service
+++ b/units/plymouth-start.service
@@ -13,12 +13,9 @@ After=systemd-vconsole-setup.service udev-settle.service
Before=systemd-ask-password-plymouth.service
# Dracut informs us with this flag file if plymouth is already running
-ConditionPathExists=!/dev/.systemd/plymouth
+ConditionPathExists=!/run/plymouth/pid
[Service]
-ExecStart=/sbin/plymouthd --mode=boot
+ExecStart=/sbin/plymouthd --mode=boot --pid-file=/run/plymouth/pid
ExecStartPost=-/bin/plymouth --show-splash
Type=forking
-
-# Send SIGRTMIN+20 to systemd, i.e. enable status messages
-ExecStartPost=-/usr/bin/kill -54 1
diff --git a/units/poweroff.target b/units/poweroff.target
index 975b08896..d2ccf4b2c 100644
--- a/units/poweroff.target
+++ b/units/poweroff.target
@@ -10,7 +10,6 @@
[Unit]
Description=Power-Off
DefaultDependencies=no
-Names=runlevel0.target
Requires=poweroff.service
After=poweroff.service
AllowIsolate=yes
diff --git a/units/quotacheck.service.in b/units/quotacheck.service.in
index d46a33564..ed1ddc558 100644
--- a/units/quotacheck.service.in
+++ b/units/quotacheck.service.in
@@ -18,6 +18,3 @@ RemainAfterExit=yes
ExecStart=@rootlibexecdir@/systemd-quotacheck
StandardOutput=syslog
TimeoutSec=0
-
-[Install]
-WantedBy=local-fs.target
diff --git a/units/quotaon.service b/units/quotaon.service
index ddb51284d..2c7b36b4f 100644
--- a/units/quotaon.service
+++ b/units/quotaon.service
@@ -17,6 +17,3 @@ Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/quotaon -aug
StandardOutput=syslog
-
-[Install]
-WantedBy=local-fs.target
diff --git a/units/reboot.target b/units/reboot.target
index 2cd46a062..41e133cb7 100644
--- a/units/reboot.target
+++ b/units/reboot.target
@@ -10,7 +10,6 @@
[Unit]
Description=Reboot
DefaultDependencies=no
-Names=runlevel6.target
Requires=reboot.service
After=reboot.service
AllowIsolate=yes
diff --git a/units/remote-fs.target.m4 b/units/remote-fs.target.m4
index fc1fd2bec..c11ffbffa 100644
--- a/units/remote-fs.target.m4
+++ b/units/remote-fs.target.m4
@@ -12,7 +12,6 @@ Description=Remote File Systems
m4_dnl
m4_ifdef(`FOR_SYSTEM',
m4_dnl When running in system mode we need the network up
-Requires=network.target
After=network.target local-fs.target
)m4_dnl
diff --git a/units/rescue.service.m4 b/units/rescue.service.m4
index 8b42e9f69..241c75071 100644
--- a/units/rescue.service.m4
+++ b/units/rescue.service.m4
@@ -13,9 +13,6 @@ DefaultDependencies=no
Conflicts=shutdown.target
After=basic.target
Before=shutdown.target
-m4_ifdef(`TARGET_MANDRIVA',
-`# Hide SysV script
-Names=single.service')
[Service]
Environment=HOME=/root
@@ -31,7 +28,7 @@ ExecStart=-/bin/bash -c "exec ${SINGLE}"',
`ExecStart=-/sbin/sulogin'))
ExecStopPost=-/bin/systemctl --fail default
StandardInput=tty-force
-KillMode=process-group
+KillMode=process
# Bash ignores SIGTERM, so we send SIGHUP instead, to ensure that bash
# terminates cleanly.
diff --git a/units/rescue.target b/units/rescue.target
index ff3aef033..5bf3f8e8e 100644
--- a/units/rescue.target
+++ b/units/rescue.target
@@ -11,7 +11,6 @@
Description=Rescue Mode
Requires=basic.target rescue.service
After=basic.target rescue.service
-Names=runlevel1.target
AllowIsolate=yes
[Install]
diff --git a/units/rpcbind.target b/units/rpcbind.target
index 41eb3a507..a5cea8c57 100644
--- a/units/rpcbind.target
+++ b/units/rpcbind.target
@@ -7,5 +7,8 @@
# See systemd.special(7) for details
+# This exists mostly for compatibility with SysV/LSB units, and
+# implementations lacking socket/bus activation.
+
[Unit]
Description=RPC Port Mapper
diff --git a/units/serial-getty@.service.m4 b/units/serial-getty@.service.m4
index d42330a1a..8b4f0fb9d 100644
--- a/units/serial-getty@.service.m4
+++ b/units/serial-getty@.service.m4
@@ -36,7 +36,7 @@ ExecStart=-/sbin/agetty -s %I 115200,38400,9600
Restart=always
RestartSec=0
UtmpIdentifier=%I
-KillMode=process-group
+KillMode=process
# Some login implementations ignore SIGTERM, so we send SIGHUP
# instead, to ensure that login terminates cleanly.
diff --git a/units/suse/Makefile b/units/suse/Makefile
deleted file mode 120000
index 50be21181..000000000
--- a/units/suse/Makefile
+++ /dev/null
@@ -1 +0,0 @@
-../../src/Makefile
\ No newline at end of file
diff --git a/units/syslog.socket b/units/syslog.socket
index d4bbc4d9f..500bb7c31 100644
--- a/units/syslog.socket
+++ b/units/syslog.socket
@@ -12,6 +12,9 @@ Description=Syslog Socket
DefaultDependencies=no
Before=sockets.target syslog.target
+# Pull in syslog.target to tell people that /dev/log is now accessible
+Wants=syslog.target
+
[Socket]
ListenDatagram=/dev/log
SocketMode=0666
diff --git a/units/rtc-set.target b/units/syslog.target
similarity index 71%
rename from units/rtc-set.target
rename to units/syslog.target
index eabdaf458..8b1626ed5 100644
--- a/units/rtc-set.target
+++ b/units/syslog.target
@@ -7,5 +7,8 @@
# See systemd.special(7) for details
+# This exists mostly for compatibility with SysV/LSB units, and
+# implementations lacking socket/bus activation.
+
[Unit]
-Description=RTC Set
+Description=Syslog
diff --git a/units/systemd-ask-password-console.path b/units/systemd-ask-password-console.path
index 9d3d80d5a..4005a2773 100644
--- a/units/systemd-ask-password-console.path
+++ b/units/systemd-ask-password-console.path
@@ -12,4 +12,4 @@ Conflicts=shutdown.target
Before=basic.target shutdown.target
[Path]
-DirectoryNotEmpty=/dev/.systemd/ask-password
+DirectoryNotEmpty=/run/systemd/ask-password
diff --git a/units/systemd-ask-password-plymouth.path b/units/systemd-ask-password-plymouth.path
index 1d09223f7..a2aec4412 100644
--- a/units/systemd-ask-password-plymouth.path
+++ b/units/systemd-ask-password-plymouth.path
@@ -12,4 +12,4 @@ Conflicts=shutdown.target systemd-ask-password-console.path systemd-ask-password
Before=basic.target shutdown.target
[Path]
-DirectoryNotEmpty=/dev/.systemd/ask-password
+DirectoryNotEmpty=/run/systemd/ask-password
diff --git a/units/systemd-ask-password-wall.path b/units/systemd-ask-password-wall.path
index 9c4b1d3d2..7a883d5af 100644
--- a/units/systemd-ask-password-wall.path
+++ b/units/systemd-ask-password-wall.path
@@ -12,4 +12,4 @@ Conflicts=shutdown.target
Before=basic.target shutdown.target
[Path]
-DirectoryNotEmpty=/dev/.systemd/ask-password
+DirectoryNotEmpty=/run/systemd/ask-password
diff --git a/units/systemd-binfmt.service.in b/units/systemd-binfmt.service.in
new file mode 100644
index 000000000..0bf6df201
--- /dev/null
+++ b/units/systemd-binfmt.service.in
@@ -0,0 +1,19 @@
+# This file is part of systemd.
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+
+[Unit]
+Description=Set Up Additional Binary Formats
+DefaultDependencies=no
+Conflicts=shutdown.target
+After=systemd-readahead-collect.service systemd-readahead-replay.service proc-sys-fs-binfmt_misc.automount
+Before=sysinit.target shutdown.target
+ConditionDirectoryNotEmpty=/etc/binfmt.d
+
+[Service]
+Type=oneshot
+RemainAfterExit=yes
+ExecStart=@rootlibexecdir@/systemd-binfmt
diff --git a/units/systemd-initctl.socket b/units/systemd-initctl.socket
index 403b322c3..7a3a0236e 100644
--- a/units/systemd-initctl.socket
+++ b/units/systemd-initctl.socket
@@ -8,7 +8,7 @@
# See systemd.special(7) for details
[Unit]
-Description=/dev/initctl Compatibility Socket
+Description=/dev/initctl Compatibility Named Pipe
DefaultDependencies=no
Before=sockets.target
diff --git a/units/systemd-kmsg-syslogd.service.in b/units/systemd-kmsg-syslogd.service.in
index adb375021..b81e4a306 100644
--- a/units/systemd-kmsg-syslogd.service.in
+++ b/units/systemd-kmsg-syslogd.service.in
@@ -8,7 +8,7 @@
# See systemd.special(7) for details
[Unit]
-Description=systemd Syslog Kernel Log Buffer Bridge
+Description=Syslog Kernel Log Buffer Bridge
DefaultDependencies=no
[Service]
diff --git a/units/systemd-logger.service.in b/units/systemd-logger.service.in
index ff7a1316c..f82db15ac 100644
--- a/units/systemd-logger.service.in
+++ b/units/systemd-logger.service.in
@@ -8,7 +8,7 @@
# See systemd.special(7) for details
[Unit]
-Description=Logging Daemon
+Description=Stdio Syslog Bridge
DefaultDependencies=no
After=syslog.socket
diff --git a/units/systemd-logger.socket b/units/systemd-logger.socket
index 57244a287..389b507d2 100644
--- a/units/systemd-logger.socket
+++ b/units/systemd-logger.socket
@@ -8,9 +8,9 @@
# See systemd.special(7) for details
[Unit]
-Description=Logging Socket
+Description=Stream Logging Socket
DefaultDependencies=no
Before=sockets.target
[Socket]
-ListenStream=@/org/freedesktop/systemd1/logger
+ListenStream=/run/systemd/logger
diff --git a/units/systemd-shutdownd.socket b/units/systemd-shutdownd.socket
index 0df24cff7..b30a6657c 100644
--- a/units/systemd-shutdownd.socket
+++ b/units/systemd-shutdownd.socket
@@ -13,4 +13,4 @@ DefaultDependencies=no
Before=sockets.target
[Socket]
-ListenDatagram=@/org/freedesktop/systemd1/shutdownd
+ListenDatagram=/run/systemd/shutdownd
diff --git a/units/dbus.target b/units/time-sync.target
similarity index 68%
rename from units/dbus.target
rename to units/time-sync.target
index 63897685c..aa34ecb5f 100644
--- a/units/dbus.target
+++ b/units/time-sync.target
@@ -7,5 +7,8 @@
# See systemd.special(7) for details
+# This exists mostly for compatibility with SysV/LSB units, and
+# implementations lacking socket/bus activation.
+
[Unit]
-Description=D-Bus
+Description=System Time Synchronized
diff --git a/units/var-lock.mount b/units/var-lock.mount
index 0ea2599b7..80e1bab26 100644
--- a/units/var-lock.mount
+++ b/units/var-lock.mount
@@ -8,9 +8,11 @@
[Unit]
Description=Lock Directory
Before=local-fs.target
+# skip mounting if the directory does not exist or is a symlink
+ConditionPathIsDirectory=/var/lock
[Mount]
-What=tmpfs
+What=/run/lock
Where=/var/lock
-Type=tmpfs
-Options=mode=775,gid=lock,nosuid,nodev,noexec
+Type=bind
+Options=bind
diff --git a/units/var-run.mount b/units/var-run.mount
index 8ccb4bb28..c513dfecd 100644
--- a/units/var-run.mount
+++ b/units/var-run.mount
@@ -8,9 +8,11 @@
[Unit]
Description=Runtime Directory
Before=local-fs.target
+# skip mounting if the directory does not exist or is a symlink
+ConditionPathIsDirectory=/var/run
[Mount]
-What=tmpfs
+What=/run
Where=/var/run
-Type=tmpfs
-Options=mode=755,nosuid,nodev,noexec
+Type=bind
+Options=bind