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