mirror of
https://git.proxmox.com/git/systemd
synced 2026-01-14 18:36:46 +00:00
Merge commit 'v24'
Conflicts: units/remote-fs.target.m4
This commit is contained in:
commit
015f26d4fd
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,7 @@
|
||||
systemd-binfmt
|
||||
systemd-getty-generator
|
||||
systemd-nspawn
|
||||
systemd-stdio-bridge
|
||||
systemd-machine-id-setup
|
||||
systemd-detect-virt
|
||||
systemd-sysctl
|
||||
|
||||
153
Makefile.am
153
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) \
|
||||
|
||||
146
TODO
146
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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
45
configure.ac
45
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}
|
||||
|
||||
103
man/binfmt.d.xml
Normal file
103
man/binfmt.d.xml
Normal file
@ -0,0 +1,103 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<refentry id="binfmt.d">
|
||||
|
||||
<refentryinfo>
|
||||
<title>binfmt.d</title>
|
||||
<productname>systemd</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Lennart</firstname>
|
||||
<surname>Poettering</surname>
|
||||
<email>lennart@poettering.net</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>binfmt.d</refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>binfmt.d</refname>
|
||||
<refpurpose>Configure additional binary formats at boot</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>/etc/binfmt.d/*.conf</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd</command> uses
|
||||
<filename>/etc/binfmt.d/</filename> to configure
|
||||
additional binary formats to register during boot in
|
||||
the kernel. Each configuration file is named in the
|
||||
style of
|
||||
<filename>/etc/binfmt.d/<program>.conf</filename>.</para>
|
||||
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Configuration Format</title>
|
||||
|
||||
<para>Each file contains a list of binfmt_misc kernel
|
||||
binary format rules. Consult <ulink
|
||||
url="http://www.kernel.org/doc/Documentation/binfmt_misc.txt">binfmt_misc.txt</ulink>
|
||||
for more information on registration of additional
|
||||
binary formats and how to write rules.</para>
|
||||
|
||||
<para>Empty lines and lines beginning with ; and # are
|
||||
ignored. Note that this means you may not use ; and #
|
||||
as delimiter in binary format rules.</para>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Example</title>
|
||||
<example>
|
||||
<title>/etc/binfmt.d/wine.conf example:</title>
|
||||
|
||||
<programlisting># Start WINE on Windows executables
|
||||
:DOSWin:M::MZ::/usr/bin/wine:</programlisting>
|
||||
</example>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>wine</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@ -128,7 +128,7 @@
|
||||
<para><filename>/etc/locale.conf:</filename></para>
|
||||
|
||||
<programlisting>LANG=de_DE.UTF-8
|
||||
LC_MESSAGE=C</programlisting>
|
||||
LC_MESSAGES=C</programlisting>
|
||||
</example>
|
||||
|
||||
</refsect1>
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Brandon Philips
|
||||
Copyright 2011 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
|
||||
@ -77,10 +77,10 @@
|
||||
<refsect1>
|
||||
<title>Example</title>
|
||||
<example>
|
||||
<title>/etc/modules-load.d/uinput.conf example:</title>
|
||||
<title>/etc/modules-load.d/virtio-net.conf example:</title>
|
||||
|
||||
<programlisting># Load uinput.ko at boot
|
||||
uinput</programlisting>
|
||||
<programlisting># Load virtio-net.ko at boot
|
||||
virtio-net</programlisting>
|
||||
</example>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@
|
||||
<orderedlist>
|
||||
<listitem><para>If it does not exist yet, the
|
||||
user runtime directory
|
||||
<filename>/var/run/user/$USER</filename> is
|
||||
<filename>/run/user/$USER</filename> is
|
||||
created and its ownership changed to the user
|
||||
that is logging in.</para></listitem>
|
||||
|
||||
@ -284,7 +284,6 @@
|
||||
<option>create-session=1</option>,
|
||||
<option>kill-session=0</option>,
|
||||
<option>kill-user=0</option>,
|
||||
<option>keep-root=1</option>,
|
||||
<option>reset-controllers=cpu</option>,
|
||||
<option>kill-only-users=</option>,
|
||||
<option>kill-exclude-users=root</option>.</para>
|
||||
|
||||
@ -123,7 +123,7 @@
|
||||
reference implementation.</para>
|
||||
|
||||
<para>Internally, this function creates a file in
|
||||
<filename>/dev/.systemd/readahead/</filename> which is
|
||||
<filename>/run/systemd/readahead/</filename> which is
|
||||
then used as flag file to notify the read-ahead
|
||||
subsystem.</para>
|
||||
|
||||
|
||||
95
man/sysctl.d.xml
Normal file
95
man/sysctl.d.xml
Normal file
@ -0,0 +1,95 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2011 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<refentry id="sysctl.d">
|
||||
|
||||
<refentryinfo>
|
||||
<title>sysctl.d</title>
|
||||
<productname>systemd</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Lennart</firstname>
|
||||
<surname>Poettering</surname>
|
||||
<email>lennart@poettering.net</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>sysctl.d</refentrytitle>
|
||||
<manvolnum>5</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>sysctl.d</refname>
|
||||
<refpurpose>Configure kernel parameters at boot</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<para><filename>/etc/sysctl.d/*.conf</filename></para>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd</command> uses
|
||||
<filename>/etc/sysctl.d/</filename> to configure
|
||||
<citerefentry><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
kernel parameters to load during boot. Each
|
||||
configuration file is named in the style of
|
||||
<filename>/etc/sysctl.d/<program>.conf</filename>.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Configuration Format</title>
|
||||
|
||||
<para>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.</para>
|
||||
|
||||
<para>Note that both / and . are accepted as
|
||||
separators in sysctl variable names.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Example</title>
|
||||
<example>
|
||||
<title>/etc/sysctl.d/domain-name.conf example:</title>
|
||||
|
||||
<programlisting># Set kernel YP domain name
|
||||
kernel.domainname=example.com</programlisting>
|
||||
</example>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sysctl</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>sysctl.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@ -304,13 +304,11 @@
|
||||
<command>kill</command>, choose the
|
||||
mode how to kill the selected
|
||||
processes. Must be one of
|
||||
<option>control-group</option>,
|
||||
<option>process-group</option> or
|
||||
<option>control-group</option> or
|
||||
<option>process</option> 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
|
||||
<option>control-group</option> if
|
||||
<option>--kill-who=all</option> is
|
||||
set, or <option>process</option>
|
||||
@ -382,6 +380,27 @@
|
||||
file that shall be
|
||||
disabled.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-H</option></term>
|
||||
<term><option>--host</option></term>
|
||||
|
||||
<listitem><para>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.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>-P</option></term>
|
||||
<term><option>--privileged</option></term>
|
||||
|
||||
<listitem><para>Acquire privileges via
|
||||
PolicyKit before executing the
|
||||
operation.</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>The following commands are understood:</para>
|
||||
@ -447,9 +466,9 @@
|
||||
|
||||
<listitem><para>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
|
||||
<command>condrestart</command> is
|
||||
equivalent to this command.</para></listitem>
|
||||
@ -468,12 +487,13 @@
|
||||
|
||||
<listitem><para>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
|
||||
<command>force-reload</command> is
|
||||
equivalent to this command.</para></listitem>
|
||||
equivalent to this
|
||||
command.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><command>isolate [NAME]</command></term>
|
||||
|
||||
190
man/systemd-nspawn.xml
Normal file
190
man/systemd-nspawn.xml
Normal file
@ -0,0 +1,190 @@
|
||||
<?xml version='1.0'?> <!--*-nxml-*-->
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
|
||||
|
||||
<!--
|
||||
This file is part of systemd.
|
||||
|
||||
Copyright 2010 Lennart Poettering
|
||||
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
|
||||
<refentry id="systemd-nspawn">
|
||||
|
||||
<refentryinfo>
|
||||
<title>systemd-nspawn</title>
|
||||
<productname>systemd</productname>
|
||||
|
||||
<authorgroup>
|
||||
<author>
|
||||
<contrib>Developer</contrib>
|
||||
<firstname>Lennart</firstname>
|
||||
<surname>Poettering</surname>
|
||||
<email>lennart@poettering.net</email>
|
||||
</author>
|
||||
</authorgroup>
|
||||
</refentryinfo>
|
||||
|
||||
<refmeta>
|
||||
<refentrytitle>systemd-nspawn</refentrytitle>
|
||||
<manvolnum>1</manvolnum>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>systemd-nspawn</refname>
|
||||
<refpurpose>Spawn a namespace container for debugging, testing and building</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<cmdsynopsis>
|
||||
<command>systemd-nspawn <arg choice="opt" rep="repeat">OPTIONS</arg> <arg choice="opt">COMMAND</arg> <arg choice="opt" rep="repeat">ARGS</arg></command>
|
||||
</cmdsynopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1>
|
||||
<title>Description</title>
|
||||
|
||||
<para><command>systemd-nspawn</command> may be used to
|
||||
run a command or OS in a light-weight namespace
|
||||
container. In many ways it is similar to
|
||||
<citerefentry><refentrytitle>chroot</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
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.</para>
|
||||
|
||||
<para><command>systemd-nspawn</command> limits access
|
||||
to various kernel interfaces in the container to
|
||||
read-only, such as <filename>/sys</filename>,
|
||||
<filename>/proc/sys</filename> or
|
||||
<filename>/selinux</filename>. 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.</para>
|
||||
|
||||
<para>Note that even though these security precautions
|
||||
are taken <command>systemd-nspawn</command> 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.</para>
|
||||
|
||||
<para>In contrast to
|
||||
<citerefentry><refentrytitle>chroot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
<command>systemd-nspawn</command> may be used to boot
|
||||
full Linux-based operating systems in a
|
||||
container.</para>
|
||||
|
||||
<para>Use a tool like
|
||||
<citerefentry><refentrytitle>debootstrap</refentrytitle><manvolnum>8</manvolnum></citerefentry> or <citerefentry><refentrytitle>mock</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
to set up an OS directory tree suitable as file system
|
||||
hierarchy for <command>systemd-nspawn</command> containers.</para>
|
||||
|
||||
<para>Note that <command>systemd-nspawn</command> will
|
||||
mount file systems private to the container to
|
||||
<filename>/dev</filename>,
|
||||
<filename>/run</filename> and similar. These will
|
||||
not be visible outside of the container, and their
|
||||
contents will be lost when the container exits.</para>
|
||||
|
||||
<para>Note that running two
|
||||
<command>systemd-nspawn</command> 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.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Options</title>
|
||||
|
||||
<para>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:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><option>--help</option></term>
|
||||
|
||||
<listitem><para>Prints a short help
|
||||
text and exits.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--directory=</option></term>
|
||||
<term><option>--D</option></term>
|
||||
|
||||
<listitem><para>Directory to use as
|
||||
file system root for the namespace
|
||||
container. If omitted the current
|
||||
directory will be
|
||||
used.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Example 1</title>
|
||||
|
||||
<programlisting># debootstrap --arch=amd64 unstable debian-tree/
|
||||
# systemd-nspawn -D debian-tree/</programlisting>
|
||||
|
||||
<para>This installs a minimal Debian unstable
|
||||
distribution into the directory
|
||||
<filename>debian-tree/</filename> and then spawns a
|
||||
shell in a namespace container in it.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Example 2</title>
|
||||
|
||||
<programlisting># mock --init
|
||||
# systemd-nspawn -D /var/lib/mock/fedora-rawhide-x86_64/root/ /bin/systemd systemd.log_level=debug</programlisting>
|
||||
|
||||
<para>This installs a minimal Fedora distribution into
|
||||
a subdirectory of <filename>/var/lib/mock/</filename>
|
||||
and then boots an OS in a namespace container in it,
|
||||
with systemd as init system, configured for debug
|
||||
logging.</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Exit status</title>
|
||||
|
||||
<para>The exit code of the program executed in the
|
||||
container is returned.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
<para>
|
||||
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>chroot</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
|
||||
<citerefentry><refentrytitle>debootstrap</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
<citerefentry><refentrytitle>mock</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
@ -558,7 +558,10 @@
|
||||
various resource limits for executed
|
||||
processes. See
|
||||
<citerefentry><refentrytitle>setrlimit</refentrytitle><manvolnum>2</manvolnum></citerefentry>
|
||||
for details.</para></listitem>
|
||||
for details. Use the string
|
||||
<varname>infinity</varname> to
|
||||
configure no limit on a specific
|
||||
resource.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -597,16 +600,34 @@
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Capabilities=</varname></term>
|
||||
<listitem><para>Controls the
|
||||
<term><varname>CapabilityBoundingSet=</varname></term>
|
||||
|
||||
<listitem><para>Controls which
|
||||
capabilities to include in the
|
||||
capability bounding set for the
|
||||
executed process. See
|
||||
<citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
set for the executed process. Take a
|
||||
capability string as described in
|
||||
<citerefentry><refentrytitle>cap_from_text</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
||||
Note that this capability set is
|
||||
usually influenced by the capabilities
|
||||
attached to the executed
|
||||
file.</para></listitem>
|
||||
for details. Takes a whitespace
|
||||
seperated list of capability names as
|
||||
read by
|
||||
<citerefentry><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
||||
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
|
||||
<varname>Capabilities=</varname> 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.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -625,16 +646,21 @@
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>CapabilityBoundingSetDrop=</varname></term>
|
||||
|
||||
<term><varname>Capabilities=</varname></term>
|
||||
<listitem><para>Controls the
|
||||
capability bounding set drop set for
|
||||
the executed process. See
|
||||
<citerefentry><refentrytitle>capabilities</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
for details. Takes a list of
|
||||
capability names as read by
|
||||
<citerefentry><refentrytitle>cap_from_name</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
||||
</para></listitem>
|
||||
set for the executed process. Take a
|
||||
capability string describing the
|
||||
effective, permitted and inherited
|
||||
capability sets as documented in
|
||||
<citerefentry><refentrytitle>cap_from_text</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
|
||||
Note that these capability sets are
|
||||
usually influenced by the capabilities
|
||||
attached to the executed file. Due to
|
||||
that
|
||||
<varname>CapabilityBoundingSet=</varname>
|
||||
is probably the much more useful
|
||||
setting.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
|
||||
@ -221,7 +221,6 @@
|
||||
processes of this mount shall be
|
||||
killed. One of
|
||||
<option>control-group</option>,
|
||||
<option>process-group</option>,
|
||||
<option>process</option>,
|
||||
<option>none</option>.</para>
|
||||
|
||||
|
||||
@ -180,7 +180,7 @@
|
||||
acquired. Service units with this
|
||||
option configured implicitly gain
|
||||
dependencies on the
|
||||
<filename>dbus.target</filename>
|
||||
<filename>dbus.socket</filename>
|
||||
unit.</para>
|
||||
|
||||
<para>Behaviour of
|
||||
@ -558,7 +558,6 @@
|
||||
processes of this service shall be
|
||||
killed. One of
|
||||
<option>control-group</option>,
|
||||
<option>process-group</option>,
|
||||
<option>process</option>,
|
||||
<option>none</option>.</para>
|
||||
|
||||
@ -570,10 +569,6 @@
|
||||
stop command (as configured with
|
||||
<varname>ExecStop=</varname>) is
|
||||
executed. If set to
|
||||
<option>process-group</option> only
|
||||
the members of the process group of
|
||||
the main service process are
|
||||
killed. If set to
|
||||
<option>process</option> only the main
|
||||
process itself is killed. If set to
|
||||
<option>none</option> no process is
|
||||
|
||||
@ -519,7 +519,6 @@
|
||||
processes of this socket unit shall be
|
||||
killed. One of
|
||||
<option>control-group</option>,
|
||||
<option>process-group</option>,
|
||||
<option>process</option>,
|
||||
<option>none</option>.</para>
|
||||
|
||||
|
||||
@ -51,7 +51,6 @@
|
||||
<para><filename>basic.target</filename>,
|
||||
<filename>ctrl-alt-del.target</filename>,
|
||||
<filename>dbus.service</filename>,
|
||||
<filename>dbus.target</filename>,
|
||||
<filename>default.target</filename>,
|
||||
<filename>display-manager.service</filename>,
|
||||
<filename>emergency.target</filename>,
|
||||
@ -69,7 +68,7 @@
|
||||
<filename>remote-fs.target</filename>,
|
||||
<filename>rescue.target</filename>,
|
||||
<filename>rpcbind.target</filename>,
|
||||
<filename>rtc-set.target</filename>,
|
||||
<filename>time-sync.target</filename>,
|
||||
<filename>runlevel2.target</filename>,
|
||||
<filename>runlevel3.target</filename>,
|
||||
<filename>runlevel4.target</filename>,
|
||||
@ -79,7 +78,6 @@
|
||||
<filename>sockets.target</filename>,
|
||||
<filename>swap.target</filename>,
|
||||
<filename>sysinit.target</filename>,
|
||||
<filename>@SPECIAL_SYSLOG_SERVICE@</filename>,
|
||||
<filename>syslog.target</filename>,
|
||||
<filename>systemd-initctl.service</filename>,
|
||||
<filename>systemd-initctl.socket</filename>,
|
||||
@ -143,28 +141,6 @@
|
||||
up systemd will connect to it
|
||||
and register its
|
||||
service.</para>
|
||||
|
||||
<para>Units should generally
|
||||
avoid depending on this unit
|
||||
directly and instead refer to
|
||||
the
|
||||
<filename>dbus.target</filename>
|
||||
unit instead, which pulls this
|
||||
one in directly or indirectly
|
||||
via socket-based activation.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>dbus.target</filename></term>
|
||||
<listitem>
|
||||
<para>Administrators should
|
||||
ensure that this target pulls
|
||||
in a service unit with the
|
||||
name or alias of
|
||||
<filename>dbus.service</filename>
|
||||
(or a socket unit that
|
||||
activates this
|
||||
service).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
@ -180,7 +156,7 @@
|
||||
<para>The default unit systemd
|
||||
starts at bootup can be
|
||||
overriden with the
|
||||
<varname>systemd.default=</varname>
|
||||
<varname>systemd.unit=</varname>
|
||||
kernel command line option.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
@ -213,7 +189,7 @@
|
||||
console. This unit is supposed
|
||||
to be used with the kernel
|
||||
command line option
|
||||
<varname>systemd.default=</varname>
|
||||
<varname>systemd.unit=</varname>
|
||||
and has otherwise little use.
|
||||
</para>
|
||||
</listitem>
|
||||
@ -423,7 +399,7 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>rtc-set.target</filename></term>
|
||||
<term><filename>time-sync.target</filename></term>
|
||||
<listitem>
|
||||
<para>systemd automatically
|
||||
adds dependencies of type
|
||||
@ -565,27 +541,6 @@
|
||||
or b.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>@SPECIAL_SYSLOG_SERVICE@</filename></term>
|
||||
<listitem>
|
||||
<para>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.</para>
|
||||
|
||||
<para>Units should generally
|
||||
avoid depending on this unit
|
||||
directly and instead refer to
|
||||
the
|
||||
<filename>syslog.target</filename>
|
||||
unit instead, which pulls this
|
||||
one in directly or indirectly
|
||||
via socket-based activation.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><filename>syslog.target</filename></term>
|
||||
<listitem>
|
||||
@ -597,15 +552,6 @@
|
||||
referring to the
|
||||
<literal>$syslog</literal>
|
||||
facility.</para>
|
||||
|
||||
<para>Administrators should
|
||||
ensure that this target pulls
|
||||
in a service unit with the
|
||||
name or alias of
|
||||
<filename>@SPECIAL_SYSLOG_SERVICE@</filename>
|
||||
(or a socket unit that
|
||||
activates this
|
||||
service).</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
|
||||
@ -68,13 +68,23 @@
|
||||
specific configuration options are configured in the
|
||||
[Swap] section.</para>
|
||||
|
||||
<para>Swap units must be named after the devices they
|
||||
control. Example: the swap device
|
||||
<para>Swap units must be named after the devices
|
||||
(resp. files) they control. Example: the swap device
|
||||
<filename>/dev/sda5</filename> must be configured in a
|
||||
unit file <filename>dev-sda5.swap</filename>. For
|
||||
details about the escaping logic used to convert a
|
||||
file system path to a unit name see
|
||||
<citerefentry><refentrytitle>systemd.unit</refentrytitle><manvolnum>5</manvolnum></citerefentry>.</para>
|
||||
|
||||
<para>All swap units automatically get the appropriate
|
||||
dependencies on the devices (resp. on the mount points
|
||||
of the files) they are actived from.</para>
|
||||
|
||||
<para>Swap units with
|
||||
<varname>DefaultDependencies=</varname> enabled
|
||||
implicitly acquire a conflicting dependency to
|
||||
<filename>umount.target</filename> so that they are
|
||||
deactivated at shutdown.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -88,6 +98,13 @@
|
||||
<para>If a swap device or file is configured in both
|
||||
<filename>/etc/fstab</filename> and a unit file the
|
||||
configuration in the latter takes precedence.</para>
|
||||
|
||||
<para>Unless the <option>noauto</option> option is set
|
||||
for them all swap units configured in
|
||||
<filename>/etc/fstab</filename> are also added as
|
||||
requirements to <filename>swap.target</filename>, so
|
||||
that they are waited for and activated during
|
||||
boot.</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
@ -149,7 +166,7 @@
|
||||
a time span value such as "5min
|
||||
20s". Pass 0 to disable the timeout
|
||||
logic. Defaults to
|
||||
60s.</para></listitem>
|
||||
3min.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
@ -158,7 +175,6 @@
|
||||
processes of this swap shall be
|
||||
killed. One of
|
||||
<option>control-group</option>,
|
||||
<option>process-group</option>,
|
||||
<option>process</option>,
|
||||
<option>none</option>.</para>
|
||||
|
||||
|
||||
@ -83,14 +83,15 @@
|
||||
<citerefentry><refentrytitle>systemd.special</refentrytitle><manvolnum>7</manvolnum></citerefentry>
|
||||
for details).</para>
|
||||
|
||||
<para>Unless
|
||||
<varname>DefaultDependencies=</varname> is set to
|
||||
<option>false</option>, target units will
|
||||
implicitly complement all configured dependencies of type
|
||||
<varname>Wants=</varname>,
|
||||
<para>Unless <varname>DefaultDependencies=</varname>
|
||||
is set to <option>false</option>, target units will
|
||||
implicitly complement all configured dependencies of
|
||||
type <varname>Wants=</varname>,
|
||||
<varname>Requires=</varname>,
|
||||
<varname>RequiresOverridable=</varname> with
|
||||
dependencies of type <varname>After=</varname>.
|
||||
dependencies of type <varname>After=</varname> if the
|
||||
units in question also have
|
||||
<varname>DefaultDependencies=true</varname>.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
|
||||
@ -139,7 +139,10 @@
|
||||
with the <command>enable</command> command of the
|
||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
tool which reads information from the [Install]
|
||||
section of unit files. (See below.)</para>
|
||||
section of unit files. (See below.) A similar
|
||||
functionality exists for <varname>Requires=</varname>
|
||||
type dependencies as well, the directory suffix is
|
||||
<filename>.requires/</filename> in this case.</para>
|
||||
|
||||
<para>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:</para>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><varname>Names=</varname></term>
|
||||
|
||||
<listitem><para>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
|
||||
<varname>Alias=</varname> option from
|
||||
the [Install] section mentioned
|
||||
below. See below for details.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Description=</varname></term>
|
||||
@ -573,9 +561,11 @@
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>ConditionPathExists=</varname></term>
|
||||
<term><varname>ConditionPathIsDirectory=</varname></term>
|
||||
<term><varname>ConditionDirectoryNotEmpty=</varname></term>
|
||||
<term><varname>ConditionKernelCommandLine=</varname></term>
|
||||
<term><varname>ConditionVirtualization=</varname></term>
|
||||
<term><varname>ConditionSecurity=</varname></term>
|
||||
<term><varname>ConditionNull=</varname></term>
|
||||
|
||||
<listitem><para>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. <varname>ConditionDirectoryNotEmpty=</varname>
|
||||
exist. <varname>ConditionPathIsDirectory=</varname>
|
||||
is similar to
|
||||
<varname>ConditionPathExists=</varname>
|
||||
but verifies whether a certain path is
|
||||
but verifies whether a certain path
|
||||
exists and is a directory.
|
||||
<varname>ConditionDirectoryNotEmpty=</varname>
|
||||
is similar to
|
||||
<varname>ConditionPathExists=</varname>
|
||||
but verifies whether a certain path
|
||||
exists and is a non-empty
|
||||
directory. Similarly
|
||||
<varname>ConditionKernelCommandLine=</varname>
|
||||
@ -630,9 +625,17 @@
|
||||
<varname>microsoft</varname>,
|
||||
<varname>oracle</varname>,
|
||||
<varname>xen</varname>,
|
||||
<varname>pidns</varname>,
|
||||
<varname>openvz</varname> to test
|
||||
against a specific implementation. The
|
||||
test may be negated by prepending an
|
||||
exclamation mark.
|
||||
<varname>ConditionSecurity=</varname>
|
||||
may be used to check whether the given security
|
||||
module is enabled on the system.
|
||||
Currently the only recognized value is
|
||||
<varname>selinux</varname>.
|
||||
The test may be negated by prepending an
|
||||
exclamation mark. Finally,
|
||||
<varname>ConditionNull=</varname> may
|
||||
be used to add a constant condition
|
||||
@ -657,6 +660,35 @@
|
||||
pipe symbol must be passed first, the
|
||||
exclamation second.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><varname>Names=</varname></term>
|
||||
|
||||
<listitem><para>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
|
||||
<varname>Alias=</varname> 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.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>Unit file may include a [Install] section, which
|
||||
|
||||
@ -269,7 +269,7 @@
|
||||
<option>syslog</option>,
|
||||
<option>syslog+console</option>,
|
||||
<option>kmsg</option>,
|
||||
<option>kmsg-console</option>. If the
|
||||
<option>kmsg+console</option>. If the
|
||||
argument is omitted it defaults to
|
||||
<option>inherit</option>.</para></listitem>
|
||||
</varlistentry>
|
||||
@ -1024,20 +1024,19 @@
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><filename>@/org/freedesktop/systemd1/notify</filename></term>
|
||||
<term><filename>/run/systemd/notify</filename></term>
|
||||
|
||||
<listitem><para>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
|
||||
<citerefentry><refentrytitle>sd_notify</refentrytitle><manvolnum>3</manvolnum></citerefentry>.</para></listitem>
|
||||
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><filename>@/org/freedesktop/systemd1/logger</filename></term>
|
||||
<term><filename>/run/systemd/logger</filename></term>
|
||||
|
||||
<listitem><para>Used internally by the
|
||||
<filename>systemd-logger.service</filename>
|
||||
@ -1045,32 +1044,30 @@
|
||||
of spawned processes to
|
||||
<citerefentry><refentrytitle>syslog</refentrytitle><manvolnum>3</manvolnum></citerefentry>
|
||||
or the kernel log buffer. This is an
|
||||
AF_UNIX stream socket in the Linux
|
||||
abstract namespace.</para></listitem>
|
||||
AF_UNIX stream
|
||||
socket.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><filename>@/org/freedesktop/systemd1/shutdown</filename></term>
|
||||
<term><filename>/run/systemd/shutdownd</filename></term>
|
||||
|
||||
<listitem><para>Used internally by the
|
||||
<citerefentry><refentrytitle>shutdown</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
tool to implement delayed
|
||||
shutdowns. This is an AF_UNIX datagram
|
||||
socket in the Linux abstract
|
||||
namespace.</para></listitem>
|
||||
socket.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><filename>@/org/freedesktop/systemd1/private</filename></term>
|
||||
<term><filename>/run/systemd/private</filename></term>
|
||||
|
||||
<listitem><para>Used internally as
|
||||
communication channel between
|
||||
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
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.</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
<filename>/etc/tmpfiles.d/</filename> to describe the
|
||||
creation, cleaning and removal of volatile and
|
||||
temporary files and directories which usually reside
|
||||
in directories such as <filename>/var/run</filename>
|
||||
in directories such as <filename>/run</filename>
|
||||
or <filename>/tmp</filename>. Each configuration file
|
||||
is named in the style of
|
||||
<filename>/etc/tmpfiles.d/<program>.conf</filename>.</para>
|
||||
@ -72,7 +72,7 @@
|
||||
fields:</para>
|
||||
|
||||
<programlisting>Type Path Mode UID GID Age
|
||||
d /var/run/user 0755 root root 10d</programlisting>
|
||||
d /run/user 0755 root root 10d</programlisting>
|
||||
|
||||
<refsect2>
|
||||
<title>Type</title>
|
||||
|
||||
1
src/.gitignore
vendored
1
src/.gitignore
vendored
@ -1,3 +1,4 @@
|
||||
org.freedesktop.systemd1.policy
|
||||
gnome-ask-password-agent.c
|
||||
systemd-interfaces.c
|
||||
systemadm.c
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with systemd; If not, see <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/poll.h>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
187
src/binfmt.c
Normal file
187
src/binfmt.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
367
src/bridge.c
Normal file
367
src/bridge.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
18
src/cgls.c
18
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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -27,8 +27,7 @@
|
||||
#include <dirent.h>
|
||||
|
||||
#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
|
||||
|
||||
10
src/cgroup.c
10
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;
|
||||
}
|
||||
|
||||
@ -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.");
|
||||
|
||||
@ -24,13 +24,19 @@
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifdef HAVE_SELINUX
|
||||
#include <selinux/selinux.h>
|
||||
#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"
|
||||
};
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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) { \
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -38,6 +38,10 @@
|
||||
BUS_INTROSPECTABLE_INTERFACE \
|
||||
"</node>\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);
|
||||
}
|
||||
|
||||
@ -23,10 +23,14 @@
|
||||
#include <sys/socket.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <dbus/dbus.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -37,11 +37,14 @@
|
||||
BUS_INTROSPECTABLE_INTERFACE \
|
||||
"</node>\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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
***/
|
||||
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "dbus.h"
|
||||
#include "log.h"
|
||||
@ -206,6 +207,10 @@
|
||||
#define INTROSPECTION_END \
|
||||
"</node>\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:
|
||||
|
||||
@ -50,6 +50,10 @@
|
||||
BUS_INTROSPECTABLE_INTERFACE \
|
||||
"</node>\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);
|
||||
}
|
||||
|
||||
@ -41,6 +41,10 @@
|
||||
BUS_INTROSPECTABLE_INTERFACE \
|
||||
"</node>\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);
|
||||
}
|
||||
|
||||
@ -26,34 +26,14 @@
|
||||
#include "dbus-service.h"
|
||||
|
||||
#ifdef HAVE_SYSV_COMPAT
|
||||
#define BUS_SERVICE_INTERFACE \
|
||||
" <interface name=\"org.freedesktop.systemd1.Service\">\n" \
|
||||
" <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"Restart\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"PIDFile\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"NotifyAccess\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"RestartUSec\" type=\"t\" access=\"read\"/>\n" \
|
||||
" <property name=\"TimeoutUSec\" type=\"t\" access=\"read\"/>\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 \
|
||||
" <property name=\"PermissionsStartOnly\" type=\"b\" access=\"read\"/>\n" \
|
||||
" <property name=\"RootDirectoryStartOnly\" type=\"b\" access=\"read\"/>\n" \
|
||||
" <property name=\"RemainAfterExit\" type=\"b\" access=\"read\"/>\n" \
|
||||
BUS_EXEC_STATUS_INTERFACE("ExecMain") \
|
||||
" <property name=\"MainPID\" type=\"u\" access=\"read\"/>\n" \
|
||||
" <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
|
||||
#define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT \
|
||||
" <property name=\"SysVStartPriority\" type=\"i\" access=\"read\"/>\n" \
|
||||
" <property name=\"SysVRunLevels\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"SysVPath\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"BusName\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \
|
||||
" </interface>\n"
|
||||
" <property name=\"SysVPath\" type=\"s\" access=\"read\"/>\n"
|
||||
#else
|
||||
#define BUS_SERVICE_SYSV_INTERFACE_FRAGMENT ""
|
||||
#endif
|
||||
|
||||
#define BUS_SERVICE_INTERFACE \
|
||||
" <interface name=\"org.freedesktop.systemd1.Service\">\n" \
|
||||
" <property name=\"Type\" type=\"s\" access=\"read\"/>\n" \
|
||||
@ -77,8 +57,10 @@
|
||||
" <property name=\"ControlPID\" type=\"u\" access=\"read\"/>\n" \
|
||||
" <property name=\"BusName\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"StatusText\" type=\"s\" access=\"read\"/>\n" \
|
||||
" <property name=\"FsckPassNo\" type=\"i\" access=\"read\"/>\n" \
|
||||
" <property name=\"Sockets\" type=\"as\" access=\"read\"/>\n" \
|
||||
BUS_SERVICE_SYSV_INTERFACE_FRAGMENT \
|
||||
" </interface>\n"
|
||||
#endif
|
||||
|
||||
#define INTROSPECTION \
|
||||
DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
|
||||
@ -90,6 +72,10 @@
|
||||
BUS_INTROSPECTABLE_INTERFACE \
|
||||
"</node>\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);
|
||||
}
|
||||
|
||||
@ -38,6 +38,10 @@
|
||||
BUS_INTROSPECTABLE_INTERFACE \
|
||||
"</node>\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))
|
||||
|
||||
@ -64,6 +64,10 @@
|
||||
BUS_INTROSPECTABLE_INTERFACE \
|
||||
"</node>\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);
|
||||
}
|
||||
|
||||
@ -47,6 +47,10 @@
|
||||
BUS_INTROSPECTABLE_INTERFACE \
|
||||
"</node>\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);
|
||||
}
|
||||
|
||||
@ -38,6 +38,10 @@
|
||||
BUS_INTROSPECTABLE_INTERFACE \
|
||||
"</node>\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);
|
||||
}
|
||||
|
||||
@ -42,12 +42,15 @@
|
||||
BUS_INTROSPECTABLE_INTERFACE \
|
||||
"</node>\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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -102,8 +102,14 @@
|
||||
" <property name=\"ControlGroup\" type=\"as\" access=\"read\"/>\n" \
|
||||
" <property name=\"NeedDaemonReload\" type=\"b\" access=\"read\"/>\n" \
|
||||
" <property name=\"JobTimeoutUSec\" type=\"t\" access=\"read\"/>\n" \
|
||||
" <property name=\"ConditionTimestamp\" type=\"t\" access=\"read\"/>\n" \
|
||||
" <property name=\"ConditionResult\" type=\"b\" access=\"read\"/>\n" \
|
||||
" </interface>\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);
|
||||
|
||||
48
src/dbus.c
48
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) {
|
||||
|
||||
15
src/dbus.h
15
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 {
|
||||
" </method>\n" \
|
||||
"</interface>\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);
|
||||
|
||||
35
src/def.h
Normal file
35
src/def.h
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#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
|
||||
@ -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,
|
||||
|
||||
@ -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"
|
||||
};
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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)
|
||||
|
||||
127
src/getty-generator.c
Normal file
127
src/getty-generator.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
11
src/job.h
11
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);
|
||||
|
||||
@ -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 */
|
||||
|
||||
@ -30,6 +30,8 @@
|
||||
#include <sys/mount.h>
|
||||
#include <linux/fs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
|
||||
#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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
|
||||
19
src/logger.c
19
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) {
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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));
|
||||
|
||||
11
src/macro.h
11
src/macro.h
@ -27,8 +27,6 @@
|
||||
#include <sys/uio.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#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]))
|
||||
|
||||
138
src/main.c
138
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) {
|
||||
|
||||
157
src/manager.c
157
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"
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -36,6 +36,10 @@
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
#ifdef ARCH_MIPS
|
||||
#include <asm/sgidefs.h>
|
||||
#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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
152
src/mount.c
152
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) {
|
||||
|
||||
800
src/nspawn.c
Normal file
800
src/nspawn.c
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <signal.h>
|
||||
#include <sched.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/wait.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/capability.h>
|
||||
#include <getopt.h>
|
||||
#include <sys/epoll.h>
|
||||
#include <termios.h>
|
||||
#include <sys/signalfd.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
@ -50,6 +50,10 @@
|
||||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="GetUnitByPID"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.systemd1"
|
||||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="LoadUnit"/>
|
||||
|
||||
<allow send_destination="org.freedesktop.systemd1"
|
||||
send_interface="org.freedesktop.systemd1.Manager"
|
||||
send_member="GetJob"/>
|
||||
|
||||
@ -24,7 +24,18 @@
|
||||
<allow_inactive>no</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
<annotate key="org.freedesktop.policykit.exec.path">/lib/systemd/systemd-reply-password</annotate>
|
||||
<annotate key="org.freedesktop.policykit.exec.path">@rootlibexecdir@/systemd-reply-password</annotate>
|
||||
</action>
|
||||
|
||||
<action id="org.freedesktop.systemd1.BusAccess">
|
||||
<description>Privileged system and service manager access</description>
|
||||
<message>Authentication is required to access the system and service manager.</message>
|
||||
<defaults>
|
||||
<allow_any>no</allow_any>
|
||||
<allow_inactive>no</allow_inactive>
|
||||
<allow_active>auth_admin_keep</allow_active>
|
||||
</defaults>
|
||||
<annotate key="org.freedesktop.policykit.exec.path">@bindir@/systemd-stdio-bridge</annotate>
|
||||
</action>
|
||||
|
||||
</policyconfig>
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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)))
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
160
src/shutdown.c
160
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) {
|
||||
|
||||
@ -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];
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user