summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am6
-rw-r--r--TODO20
-rw-r--r--configure.ac22
-rw-r--r--hwdb/60-evdev.hwdb6
-rw-r--r--hwdb/60-keyboard.hwdb51
-rw-r--r--hwdb/70-mouse.hwdb17
-rw-r--r--hwdb/70-pointingstick.hwdb14
-rwxr-xr-xhwdb/parse_hwdb.py183
-rw-r--r--man/localectl.xml2
-rw-r--r--man/networkd.conf.xml2
-rw-r--r--man/nss-systemd.xml4
-rw-r--r--man/sd-journal.xml2
-rw-r--r--man/systemd-journal-gatewayd.service.xml10
-rw-r--r--man/systemd-resolved.service.xml8
-rw-r--r--man/systemd.exec.xml180
-rw-r--r--man/systemd.mount.xml2
-rw-r--r--man/systemd.netdev.xml9
-rw-r--r--man/systemd.offline-updates.xml6
-rw-r--r--man/systemd.service.xml27
-rw-r--r--man/tmpfiles.d.xml4
-rw-r--r--shell-completion/zsh/_journalctl20
-rw-r--r--shell-completion/zsh/_systemctl.in6
-rw-r--r--src/basic/fileio.c17
-rw-r--r--src/basic/fs-util.c98
-rw-r--r--src/basic/fs-util.h3
-rw-r--r--src/core/automount.c2
-rw-r--r--src/core/busname.c6
-rw-r--r--src/core/dbus-execute.c7
-rw-r--r--src/core/execute.c195
-rw-r--r--src/core/execute.h20
-rw-r--r--src/core/load-fragment-gperf.gperf.m43
-rw-r--r--src/core/mount.c20
-rw-r--r--src/core/org.freedesktop.systemd1.conf8
-rw-r--r--src/core/path.c2
-rw-r--r--src/core/scope.c4
-rw-r--r--src/core/service.c121
-rw-r--r--src/core/socket.c22
-rw-r--r--src/core/swap.c20
-rw-r--r--src/core/timer.c2
-rw-r--r--src/coredump/coredump.c8
-rw-r--r--src/coredump/coredumpctl.c9
-rw-r--r--src/journal-remote/journal-gatewayd.c26
-rw-r--r--src/journal/journal-verify.c4
-rw-r--r--src/journal/lookup3.c6
-rw-r--r--src/journal/sd-journal.c2
-rw-r--r--src/machine/machined-dbus.c2
-rw-r--r--src/network/networkd-netdev-bridge.c7
-rw-r--r--src/network/networkd-netdev-bridge.h1
-rw-r--r--src/network/networkd-netdev-gperf.gperf1
-rw-r--r--src/network/networkd-network.c4
-rw-r--r--src/nss-systemd/nss-systemd.c101
-rw-r--r--src/shared/bus-unit-util.c2
-rw-r--r--src/shared/install.c2
-rw-r--r--src/test/test-fs-util.c54
-rw-r--r--src/test/test-id128.c2
-rw-r--r--src/test/test-sigbus.c3
-rw-r--r--units/systemd-random-seed.service.in1
57 files changed, 1063 insertions, 323 deletions
diff --git a/Makefile.am b/Makefile.am
index bf853c8f90..d4e3e9a013 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -3872,7 +3872,8 @@ TESTS += \
if HAVE_PYTHON
TESTS += \
- test/rule-syntax-check.py
+ test/rule-syntax-check.py \
+ hwdb/parse_hwdb.py
if HAVE_SYSV_COMPAT
TESTS += \
@@ -3924,7 +3925,8 @@ EXTRA_DIST += \
test/udev-test.pl \
test/rule-syntax-check.py \
test/sysv-generator-test.py \
- test/mocks/fsck
+ test/mocks/fsck \
+ hwdb/parse_hwdb.py
# ------------------------------------------------------------------------------
ata_id_SOURCES = \
diff --git a/TODO b/TODO
index bb36522bf9..33afe39783 100644
--- a/TODO
+++ b/TODO
@@ -35,27 +35,17 @@ Features:
* RemoveIPC= in unit files for removing POSIX/SysV IPC objects
-* Set SERVICE_RESULT= as env var while running ExecStop=
-
* Introduce ProtectSystem=strict for making the entire OS hierarchy read-only
except for a select few
* nspawn: start UID allocation loop from hash of container name
-* in the DynamicUser=1 nss module, also map "nobody" and "root" statically
-
-* pid1: log about all processes we kill with with SIGKILL or in abandoned scopes, as this should normally not happen
-
* nspawn: support that /proc, /sys/, /dev are pre-mounted
-* nspawn: mount esp, so that bootctl can work
-
* define gpt header bits to select volatility mode
* nspawn: mount loopback filesystems with "discard"
-* Make TasksMax= take percentages, taken relative to the pids_max sysctl and pids.max cgroup limit
-
* ProtectKernelLogs= (drops CAP_SYSLOG, add seccomp for syslog() syscall, and DeviceAllow to /dev/kmsg) in service files
* ProtectClock= (drops CAP_SYS_TIMES, adds seecomp filters for settimeofday, adjtimex), sets DeviceAllow o /dev/rtc
@@ -66,11 +56,10 @@ Features:
* ProtectKeyRing= to take keyring calls away
-* PrivateUsers= which maps the all user ids except root and the one specified
- in User= to nobody
-
* ProtectControlGroups= which mounts all of /sys/fs/cgroup read-only
+* RemoveKeyRing= to remove all keyring entries of the specified user
+
* Add DataDirectory=, CacheDirectory= and LogDirectory= to match
RuntimeDirectory=, and create it as necessary when starting a service, owned by the right user.
@@ -90,6 +79,11 @@ Features:
* expose the "privileged" flag of ExecCommand on the bus, and open it up to
transient units
+* in nss-systemd, if we run inside of RootDirectory= with PrivateUsers= set,
+ find a way to map the User=/Group= of the service to the right name. This way
+ a user/group for a service only has to exist on the host for the right
+ mapping to work.
+
* allow attaching additional journald log fields to cgroups
* rework fopen_temporary() to make use of open_tmpfile_linkable() (problem: the
diff --git a/configure.ac b/configure.ac
index a86deca471..4d1c96606f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -556,12 +556,30 @@ AC_SUBST(CERTIFICATEROOT)
AC_ARG_WITH([support-url],
AS_HELP_STRING([--with-support-url=URL],
- [Specify the supoport URL to show in catalog entries included in systemd]),
+ [Specify the support URL to show in catalog entries included in systemd]),
[SUPPORT_URL="$withval"],
[SUPPORT_URL=http://lists.freedesktop.org/mailman/listinfo/systemd-devel])
AC_SUBST(SUPPORT_URL)
+AC_ARG_WITH([nobody-user],
+ AS_HELP_STRING([--with-nobody-user=NAME],
+ [Specify the name of the nobody user (the one with UID 65534)]),
+ [NOBODY_USER_NAME="$withval"],
+ [NOBODY_USER_NAME=nobody])
+
+AC_SUBST(NOBODY_USER_NAME)
+AC_DEFINE_UNQUOTED(NOBODY_USER_NAME, ["$NOBODY_USER_NAME"], [The name of the nobody user (the one with UID 65534)])
+
+AC_ARG_WITH([nobody-group],
+ AS_HELP_STRING([--with-nobody-group=NAME],
+ [Specify the name of the nobody group (the one with GID 65534)]),
+ [NOBODY_GROUP_NAME="$withval"],
+ [NOBODY_GROUP_NAME=nobody])
+
+AC_SUBST(NOBODY_GROUP_NAME)
+AC_DEFINE_UNQUOTED(NOBODY_GROUP_NAME, ["$NOBODY_GROUP_NAME"], [The name of the nobody group (the one with GID 65534)])
+
# ------------------------------------------------------------------------------
have_xz=no
AC_ARG_ENABLE(xz, AS_HELP_STRING([--disable-xz], [Disable optional XZ support]))
@@ -1677,6 +1695,8 @@ AC_MSG_RESULT([
Maximum System GID: ${SYSTEM_GID_MAX}
Certificate root: ${CERTIFICATEROOT}
Support URL: ${SUPPORT_URL}
+ Nobody User Name: ${NOBODY_USER_NAME}
+ Nobody Group Name: ${NOBODY_GROUP_NAME}
CFLAGS: ${OUR_CFLAGS} ${CFLAGS}
CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
diff --git a/hwdb/60-evdev.hwdb b/hwdb/60-evdev.hwdb
index d4cd61c24d..4d14a6a2f4 100644
--- a/hwdb/60-evdev.hwdb
+++ b/hwdb/60-evdev.hwdb
@@ -76,9 +76,9 @@ evdev:input:b0003v05ACp0254*
EVDEV_ABS_36=::92
# MacbookPro10,1 (unibody, June 2012)
-evdev:input:b0003v05ACp0259*
-evdev:input:b0003v05ACp025A*
-evdev:input:b0003v05ACp025B*
+evdev:input:b0003v05ACp0262*
+evdev:input:b0003v05ACp0263*
+evdev:input:b0003v05ACp0264*
# MacbookPro10,2 (unibody, October 2012)
evdev:input:b0003v05ACp0259*
evdev:input:b0003v05ACp025A*
diff --git a/hwdb/60-keyboard.hwdb b/hwdb/60-keyboard.hwdb
index fd49b03493..25caa60626 100644
--- a/hwdb/60-keyboard.hwdb
+++ b/hwdb/60-keyboard.hwdb
@@ -213,7 +213,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnDell*:pn*
KEYBOARD_KEY_8a=suspend # Fn+F1 hibernate
KEYBOARD_KEY_8b=switchvideomode # Fn+F8 CRT/LCD (high keycode: "displaytoggle")
KEYBOARD_KEY_8c=unknown # Fn+Right Auto Brightness
- KEYBOARD_KEY_8F=switchvideomode # Fn+F7 aspect ratio
+ KEYBOARD_KEY_8f=switchvideomode # Fn+F7 aspect ratio
KEYBOARD_KEY_90=previoussong # Front panel previous song
KEYBOARD_KEY_91=prog1 # Wi-Fi Catcher (Dell-specific)
KEYBOARD_KEY_92=media # MediaDirect button (house icon)
@@ -482,8 +482,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnFalco:pvr*
KEYBOARD_KEY_43=volumedown
KEYBOARD_KEY_44=volumeup
KEYBOARD_KEY_db=search # Same position as caps lock key on most keyboards
-# KEYBOARD_KEY_3e=fullscreen, no defined key sym
-
+ # KEYBOARD_KEY_3e=fullscreen, no defined key sym
# HP EliteBook 725 G2
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnHewlett-Packard*:pnHPLicrice:pvr*
@@ -694,7 +693,7 @@ evdev:input:b0003v046DpC308*
KEYBOARD_KEY_90003=finance # Finance
KEYBOARD_KEY_90004=prog1 # My Sites
KEYBOARD_KEY_90005=prog2 # Community
- KEYBOARD_KEY_C0183=media # Media
+ KEYBOARD_KEY_c0183=media # Media
# Cordless Desktop S510
evdev:input:b0003v046DpC50C*
@@ -759,22 +758,22 @@ evdev:input:b0003v046DpC52D*
# Internet Navigator
evdev:input:b0003v046DpC309*
- KEYBOARD_KEY_90001=chat # Messenger/SMS
- KEYBOARD_KEY_90002=camera # webcam
- KEYBOARD_KEY_90003=prog1 # iTouch
- KEYBOARD_KEY_90004=shop # Shopping
- KEYBOARD_KEY_C0201=new # New (F1)
- KEYBOARD_KEY_C0289=reply # Reply mail (F2)
- KEYBOARD_KEY_C028B=forwardmail # Forward mail (F3)
- KEYBOARD_KEY_C028C=send # Send (F4)
- KEYBOARD_KEY_C021A=undo # Undo (F5).
- KEYBOARD_KEY_C0279=redo # Redo (F6).
- KEYBOARD_KEY_C0208=print # Print (F7)
- KEYBOARD_KEY_C0207=save # Save (F8)
- KEYBOARD_KEY_C0194=file # My Computer (F9)
- KEYBOARD_KEY_C01A7=documents # My Documents (F10)
- KEYBOARD_KEY_C01B6=images # My Pictures (F11) ??
- KEYBOARD_KEY_C01B7=sound # My Music (F12) ??
+ KEYBOARD_KEY_90001=chat # Messenger/SMS
+ KEYBOARD_KEY_90002=camera # webcam
+ KEYBOARD_KEY_90003=prog1 # iTouch
+ KEYBOARD_KEY_90004=shop # Shopping
+ KEYBOARD_KEY_c0201=new # New (F1)
+ KEYBOARD_KEY_c0289=reply # Reply mail (F2)
+ KEYBOARD_KEY_c028b=forwardmail # Forward mail (F3)
+ KEYBOARD_KEY_c028c=send # Send (F4)
+ KEYBOARD_KEY_c021a=undo # Undo (F5)
+ KEYBOARD_KEY_c0279=redo # Redo (F6)
+ KEYBOARD_KEY_c0208=print # Print (F7)
+ KEYBOARD_KEY_c0207=save # Save (F8)
+ KEYBOARD_KEY_c0194=file # My Computer (F9)
+ KEYBOARD_KEY_c01a7=documents # My Documents (F10)
+ KEYBOARD_KEY_c01b6=images # My Pictures (F11) ??
+ KEYBOARD_KEY_c01b7=sound # My Music (F12) ??
###########################################################
@@ -797,6 +796,14 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMAXDATA:pnPro*7000*:pvr*
# Medion
###########################################################
+# Akoya
+evdev:atkbd:dmi:bvn*:bvr*:svnMedion*:pnAkoya*:pvr*
+ KEYBOARD_KEY_a0=!mute
+ KEYBOARD_KEY_ae=!volumedown
+ KEYBOARD_KEY_b0=!volumeup
+ KEYBOARD_KEY_19=!p
+ KEYBOARD_KEY_df=sleep
+
# FID2060
evdev:atkbd:dmi:bvn*:bvr*:bd*:svnMEDION*:pn*FID2060*:pvr*
KEYBOARD_KEY_6b=channeldown # Thottle Down
@@ -889,7 +896,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnOLPC:pnXO:*
KEYBOARD_KEY_c2=f8
KEYBOARD_KEY_c3=f9
KEYBOARD_KEY_c4=f10
- KEYBOARD_KEY_c7=f11
+ # KEYBOARD_KEY_c7=f11 # FIXME!
KEYBOARD_KEY_d8=f12
KEYBOARD_KEY_f7=f13
KEYBOARD_KEY_f6=f14
@@ -909,7 +916,7 @@ evdev:atkbd:dmi:bvn*:bvr*:bd*:svnOLPC:pnXO:*
KEYBOARD_KEY_c9=pageup
KEYBOARD_KEY_d1=pagedown
KEYBOARD_KEY_c7=home
- KEYBOARD_KEY_cF=end
+ KEYBOARD_KEY_cf=end
KEYBOARD_KEY_73=hp
KEYBOARD_KEY_7e=hp
KEYBOARD_KEY_db=leftmeta # left grab
diff --git a/hwdb/70-mouse.hwdb b/hwdb/70-mouse.hwdb
index b68c01066e..d8215a6179 100644
--- a/hwdb/70-mouse.hwdb
+++ b/hwdb/70-mouse.hwdb
@@ -297,7 +297,7 @@ mouse:usb:v046dpc049:name:Logitech USB Gaming Mouse:
mouse:usb:v046dpc24e:name:Logitech G500s Laser Gaming Mouse:
MOUSE_DPI=400@500 *800@500 2000@500
- # Logitech G9
+# Logitech G9
mouse:usb:v046dpc048:name:Logitech G9 Laser Mouse:
MOUSE_DPI=400@1000 800@1000 *1600@1000
@@ -342,8 +342,6 @@ mouse:usb:v046dp402d:name:Logitech M560:
mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:402d:
MOUSE_DPI=1000@125
-# Logitech V220 Cordless Optical Mouse
-mouse:usb:v046dpc51b:name:Logitech USB Receiver:
# Logitech Performance MX
mouse:usb:v046dp101a:name:Logitech Performance MX:
# Logitech MX Master
@@ -373,11 +371,6 @@ mouse:usb:v046dp4027:name:Logitech T620:
mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4027:
MOUSE_DPI=1200@250
-# Logitech LX8 Cordless Laser Mouse
-mouse:usb:v046dpc51b:name:Logitech USB Receiver:
- MOUSE_DPI=1300@125
- MOUSE_WHEEL_CLICK_ANGLE=15
-
# Logitech ZoneTouch Mouse T400
mouse:usb:v046dp4026:name:Logitech T400:
mouse:usb:v046dpc52b:name:Logitech Unifying Device. Wireless PID:4026:
@@ -500,3 +493,11 @@ mouse:usb:v1038p1369:name:SteelSeries Sensei Raw Gaming Mouse:
# Trust illuminated mouse gxt 152
mouse:usb:v145fp01ac:name:HID-compliant Mouse Trust Gaming Mouse:
MOUSE_DPI=*800@528 1200@537 1600@536 2400@521
+
+ ##########################################
+ # Zelotes
+ ##########################################
+
+# Zelotes 5500 DPI 7 Button USB Wired Gaming Mouse
+mouse:usb:v1d57pad17:*
+ MOUSE_DPI=1000@500 1600@500 2400@500 3200@500 5500@500 *1000@1000 1600@1000 2400@1000 3200@1000 5500@1000
diff --git a/hwdb/70-pointingstick.hwdb b/hwdb/70-pointingstick.hwdb
index c0ec8ffbe0..5e2ab393bd 100644
--- a/hwdb/70-pointingstick.hwdb
+++ b/hwdb/70-pointingstick.hwdb
@@ -77,15 +77,15 @@
# Latitude D620
evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeD620*:pvr*
- POINTINGSTICK_CONST_ACCEL=0.5
+ POINTINGSTICK_CONST_ACCEL=0.5
# Latitude E6320
evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6320*:pvr*
- POINTINGSTICK_CONST_ACCEL=2.0
+ POINTINGSTICK_CONST_ACCEL=2.0
# Latitude E6400
evdev:name:*DualPoint Stick:dmi:bvn*:bvr*:bd*:svnDellInc.:pnLatitudeE6400*:pvr*
- POINTINGSTICK_CONST_ACCEL=1.5
+ POINTINGSTICK_CONST_ACCEL=1.5
#########################################
# Lenovo
@@ -108,13 +108,13 @@ evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPad??60
evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX1Carbon3rd:*
# Lenovo Thinkpad X1 Carbon 4th gen
evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX1Carbon4th:*
- POINTINGSTICK_SENSITIVITY=200
- POINTINGSTICK_CONST_ACCEL=1.0
+ POINTINGSTICK_SENSITIVITY=200
+ POINTINGSTICK_CONST_ACCEL=1.0
# Lenovo Thinkpad X200s / X201s
# Note these come with 2 revisions of keyboard, with the trackpoints having a
# different sensitivity in the different revisions. 1.25 is a bit slow for the
# least sensitive revision, but it is better to be a bit slow than too fast.
evdev:name:TPPS/2 IBM TrackPoint:dmi:bvn*:bvr*:bd*:svnLENOVO:pn*:pvrThinkPadX20?s:*
- POINTINGSTICK_SENSITIVITY=200
- POINTINGSTICK_CONST_ACCEL=1.25
+ POINTINGSTICK_SENSITIVITY=200
+ POINTINGSTICK_CONST_ACCEL=1.25
diff --git a/hwdb/parse_hwdb.py b/hwdb/parse_hwdb.py
new file mode 100755
index 0000000000..99d034b4e0
--- /dev/null
+++ b/hwdb/parse_hwdb.py
@@ -0,0 +1,183 @@
+#!/usr/bin/python3
+# -*- Mode: python; coding: utf-8; indent-tabs-mode: nil -*- */
+#
+# This file is part of systemd.
+#
+# Copyright 2016 Zbigniew Jędrzejewski-Szmek
+#
+# systemd is free software; you can redistribute it and/or modify it
+# under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with systemd; If not, see <http://www.gnu.org/licenses/>.
+
+import functools
+import glob
+import string
+import sys
+import os
+
+try:
+ from pyparsing import (Word, White, Literal, ParserElement, Regex,
+ LineStart, LineEnd,
+ ZeroOrMore, OneOrMore, Combine, Or, Optional, Suppress, Group,
+ nums, alphanums, printables,
+ stringEnd, pythonStyleComment,
+ ParseBaseException)
+except ImportError:
+ print('pyparsing is not available')
+ sys.exit(77)
+
+try:
+ from evdev.ecodes import ecodes
+except ImportError:
+ ecodes = None
+ print('WARNING: evdev is not available')
+
+EOL = LineEnd().suppress()
+EMPTYLINE = LineStart() + LineEnd()
+COMMENTLINE = pythonStyleComment + EOL
+INTEGER = Word(nums)
+REAL = Combine((INTEGER + Optional('.' + Optional(INTEGER))) ^ ('.' + INTEGER))
+UDEV_TAG = Word(string.ascii_uppercase, alphanums + '_')
+
+TYPES = {'mouse': ('usb', 'bluetooth', 'ps2', '*'),
+ 'evdev': ('name', 'atkbd', 'input'),
+ 'touchpad': ('i8042', 'rmi', 'bluetooth', 'usb'),
+ 'keyboard': ('name', ),
+ }
+
+@functools.lru_cache()
+def hwdb_grammar():
+ ParserElement.setDefaultWhitespaceChars('')
+
+ prefix = Or(category + ':' + Or(conn) + ':'
+ for category, conn in TYPES.items())
+ matchline = Combine(prefix + Word(printables + ' ' + '®')) + EOL
+ propertyline = (White(' ', exact=1).suppress() +
+ Combine(UDEV_TAG - '=' - Word(alphanums + '_=:@*.! ') - Optional(pythonStyleComment)) +
+ EOL)
+ propertycomment = White(' ', exact=1) + pythonStyleComment + EOL
+
+ group = (OneOrMore(matchline('MATCHES*') ^ COMMENTLINE.suppress()) -
+ OneOrMore(propertyline('PROPERTIES*') ^ propertycomment.suppress()) -
+ (EMPTYLINE ^ stringEnd()).suppress() )
+ commentgroup = OneOrMore(COMMENTLINE).suppress() - EMPTYLINE.suppress()
+
+ grammar = OneOrMore(group('GROUPS*') ^ commentgroup) + stringEnd()
+
+ return grammar
+
+@functools.lru_cache()
+def property_grammar():
+ ParserElement.setDefaultWhitespaceChars(' ')
+
+ setting = Optional('*')('DEFAULT') + INTEGER('DPI') + Suppress('@') + INTEGER('HZ')
+ props = (('MOUSE_DPI', Group(OneOrMore(setting('SETTINGS*')))),
+ ('MOUSE_WHEEL_CLICK_ANGLE', INTEGER),
+ ('ID_INPUT_TRACKBALL', Literal('1')),
+ ('POINTINGSTICK_SENSITIVITY', INTEGER),
+ ('POINTINGSTICK_CONST_ACCEL', REAL),
+ ('ID_INPUT_TOUCHPAD_INTEGRATION', Or(('internal', 'external'))),
+ )
+ fixed_props = [Literal(name)('NAME') - Suppress('=') - val('VALUE')
+ for name, val in props]
+ kbd_props = [Regex(r'KEYBOARD_KEY_[0-9a-f]+')('NAME')
+ - Suppress('=') -
+ ('!' ^ (Optional('!') - Word(alphanums + '_')))('VALUE')
+ ]
+ abs_props = [Regex(r'EVDEV_ABS_[0-9a-f]{2}')('NAME')
+ - Suppress('=') -
+ Word(nums + ':')('VALUE')
+ ]
+
+ grammar = Or(fixed_props + kbd_props + abs_props)
+
+ return grammar
+
+ERROR = False
+def error(fmt, *args, **kwargs):
+ global ERROR
+ ERROR = True
+ print(fmt.format(*args, **kwargs))
+
+def convert_properties(group):
+ matches = [m[0] for m in group.MATCHES]
+ props = [p[0] for p in group.PROPERTIES]
+ return matches, props
+
+def parse(fname):
+ grammar = hwdb_grammar()
+ try:
+ parsed = grammar.parseFile(fname)
+ except ParseBaseException as e:
+ error('Cannot parse {}: {}', fname, e)
+ return []
+ return [convert_properties(g) for g in parsed.GROUPS]
+
+def check_match_uniqueness(groups):
+ matches = sum((group[0] for group in groups), [])
+ matches.sort()
+ prev = None
+ for match in matches:
+ if match == prev:
+ error('Match {!r} is duplicated', match)
+ prev = match
+
+def check_one_default(prop, settings):
+ defaults = [s for s in settings if s.DEFAULT]
+ if len(defaults) > 1:
+ error('More than one star entry: {!r}', prop)
+
+def check_one_keycode(prop, value):
+ if value != '!' and ecodes is not None:
+ key = 'KEY_' + value.upper()
+ if key not in ecodes:
+ error('Keycode {} unknown', key)
+
+def check_properties(groups):
+ grammar = property_grammar()
+ for matches, props in groups:
+ prop_names = set()
+ for prop in props:
+ # print('--', prop)
+ prop = prop.partition('#')[0].rstrip()
+ try:
+ parsed = grammar.parseString(prop)
+ except ParseBaseException as e:
+ error('Failed to parse: {!r}', prop)
+ continue
+ # print('{!r}'.format(parsed))
+ if parsed.NAME in prop_names:
+ error('Property {} is duplicated', parsed.NAME)
+ prop_names.add(parsed.NAME)
+ if parsed.NAME == 'MOUSE_DPI':
+ check_one_default(prop, parsed.VALUE.SETTINGS)
+ elif parsed.NAME.startswith('KEYBOARD_KEY_'):
+ check_one_keycode(prop, parsed.VALUE)
+
+def print_summary(fname, groups):
+ print('{}: {} match groups, {} matches, {} properties'
+ .format(fname,
+ len(groups),
+ sum(len(matches) for matches, props in groups),
+ sum(len(props) for matches, props in groups),
+ ))
+
+if __name__ == '__main__':
+ args = sys.argv[1:] or glob.glob(os.path.dirname(sys.argv[0]) + '/[67]0-*.hwdb')
+
+ for fname in args:
+ groups = parse(fname)
+ print_summary(fname, groups)
+ check_match_uniqueness(groups)
+ check_properties(groups)
+
+ sys.exit(ERROR)
diff --git a/man/localectl.xml b/man/localectl.xml
index 8d2becb5d9..31238272f3 100644
--- a/man/localectl.xml
+++ b/man/localectl.xml
@@ -223,7 +223,7 @@
<citerefentry><refentrytitle>systemctl</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-localed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>mkinitrd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry project='die-net'><refentrytitle>mkinitrd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml
index 4bfc4f773a..57e647a31b 100644
--- a/man/networkd.conf.xml
+++ b/man/networkd.conf.xml
@@ -120,7 +120,7 @@
<para>The DUID value specified here overrides the DUID that systemd-networkd generates using the machine-id
from the <filename>/etc/machine-id</filename> file. To configure DUID per-network, see
- <citerefentry><refentrytitle>systemd.network </refentrytitle><manvolnum>5</manvolnum></citerefentry>.
+ <citerefentry><refentrytitle>systemd.network</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
The configured DHCP DUID should conform to the specification in
<ulink url="http://tools.ietf.org/html/rfc3315#section-9">RFC 3315</ulink>,
<ulink url="http://tools.ietf.org/html/rfc6355">RFC 6355</ulink>. To configure IAID, see
diff --git a/man/nss-systemd.xml b/man/nss-systemd.xml
index 4228372e51..56d26e7d1f 100644
--- a/man/nss-systemd.xml
+++ b/man/nss-systemd.xml
@@ -61,6 +61,10 @@
<citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for details on
this option.</para>
+ <para>This module also ensures that the root and nobody users and groups (i.e. the users/groups with the UIDs/GIDs
+ 0 and 65534) remain resolvable at all times, even if they aren't listed in <filename>/etc/passwd</filename> or
+ <filename>/etc/group</filename>, or if these files are missing.</para>
+
<para>To activate the NSS module, add <literal>systemd</literal> to the lines starting with
<literal>passwd:</literal> and <literal>group:</literal> in <filename>/etc/nsswitch.conf</filename>.</para>
diff --git a/man/sd-journal.xml b/man/sd-journal.xml
index 09747a480c..936a83acf7 100644
--- a/man/sd-journal.xml
+++ b/man/sd-journal.xml
@@ -77,7 +77,6 @@
<citerefentry><refentrytitle>sd_journal_get_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_seek_head</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_journal_query_enumerate</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_enumerate_fields</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_get_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_get_cutoff_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
@@ -113,7 +112,6 @@
<citerefentry><refentrytitle>sd_journal_get_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_seek_head</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>sd_journal_query_enumerate</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_enumerate_fields</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_get_cursor</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_journal_get_cutoff_realtime_usec</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
diff --git a/man/systemd-journal-gatewayd.service.xml b/man/systemd-journal-gatewayd.service.xml
index 9ed85c3950..2cb114f6e3 100644
--- a/man/systemd-journal-gatewayd.service.xml
+++ b/man/systemd-journal-gatewayd.service.xml
@@ -100,6 +100,16 @@
with <option>--cert=</option>.</para></listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>-D <replaceable>DIR</replaceable></option></term>
+ <term><option>--directory=<replaceable>DIR</replaceable></option></term>
+
+ <listitem><para>Takes a directory path as argument. If
+ specified, <command>systemd-journal-gatewayd</command> will serve the
+ specified journal directory <replaceable>DIR</replaceable> instead of
+ the default runtime and system journal paths.</para></listitem>
+ </varlistentry>
+
<xi:include href="standard-options.xml" xpointer="help" />
<xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
diff --git a/man/systemd-resolved.service.xml b/man/systemd-resolved.service.xml
index aa1c2365e5..56f67960ce 100644
--- a/man/systemd-resolved.service.xml
+++ b/man/systemd-resolved.service.xml
@@ -68,12 +68,12 @@
link-local networking).</para></listitem>
<listitem><para>The glibc
- <citerefentry><refentrytitle>getaddrinfo</refentrytitle><manvolnum>3</manvolnum></citerefentry> API as defined
+ <citerefentry project='man-pages'><refentrytitle>getaddrinfo</refentrytitle><manvolnum>3</manvolnum></citerefentry> API as defined
by <ulink url="https://tools.ietf.org/html/rfc3493">RFC3493</ulink> and its related resolver functions,
- including <citerefentry><refentrytitle>gethostbyname</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This
+ including <citerefentry project='man-pages'><refentrytitle>gethostbyname</refentrytitle><manvolnum>3</manvolnum></citerefentry>. This
API is widely supported, including beyond the Linux platform. In its current form it does not expose DNSSEC
validation status information however, and is synchronous only. This API is backed by the glibc Name Service
- Switch (<citerefentry><refentrytitle>nss</refentrytitle><manvolnum>5</manvolnum></citerefentry>). Usage of the
+ Switch (<citerefentry project='man-pages'><refentrytitle>nss</refentrytitle><manvolnum>5</manvolnum></citerefentry>). Usage of the
glibc NSS module <citerefentry><refentrytitle>nss-resolve</refentrytitle><manvolnum>8</manvolnum></citerefentry>
is required in order to allow glibc's NSS resolver functions to resolve host names via
<command>systemd-resolved</command>.</para></listitem>
@@ -164,7 +164,7 @@
<title><filename>/etc/resolv.conf</filename></title>
<para>Three modes of handling <filename>/etc/resolv.conf</filename> (see
- <citerefentry><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>) are
+ <citerefentry project='man-pages'><refentrytitle>resolv.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>) are
supported:</para>
<itemizedlist>
diff --git a/man/systemd.exec.xml b/man/systemd.exec.xml
index 58ba582911..bf82326096 100644
--- a/man/systemd.exec.xml
+++ b/man/systemd.exec.xml
@@ -107,36 +107,29 @@
<varlistentry>
<term><varname>WorkingDirectory=</varname></term>
- <listitem><para>Takes a directory path relative to the service's root
- directory specified by <varname>RootDirectory=</varname>, or the
- special value <literal>~</literal>. Sets the working directory
- for executed processes. If set to <literal>~</literal>, the
- home directory of the user specified in
- <varname>User=</varname> is used. If not set, defaults to the
- root directory when systemd is running as a system instance
- and the respective user's home directory if run as user. If
- the setting is prefixed with the <literal>-</literal>
- character, a missing working directory is not considered
- fatal. If <varname>RootDirectory=</varname> is not set, then
- <varname>WorkingDirectory=</varname> is relative to the root of
- the system running the service manager.
- Note that setting this parameter might result in
- additional dependencies to be added to the unit (see
- above).</para></listitem>
+ <listitem><para>Takes a directory path relative to the service's root directory specified by
+ <varname>RootDirectory=</varname>, or the special value <literal>~</literal>. Sets the working directory for
+ executed processes. If set to <literal>~</literal>, the home directory of the user specified in
+ <varname>User=</varname> is used. If not set, defaults to the root directory when systemd is running as a
+ system instance and the respective user's home directory if run as user. If the setting is prefixed with the
+ <literal>-</literal> character, a missing working directory is not considered fatal. If
+ <varname>RootDirectory=</varname> is not set, then <varname>WorkingDirectory=</varname> is relative to the root
+ of the system running the service manager. Note that setting this parameter might result in additional
+ dependencies to be added to the unit (see above).</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>RootDirectory=</varname></term>
- <listitem><para>Takes a directory path relative to the host's root directory
- (i.e. the root of the system running the service manager). Sets the
- root directory for executed processes, with the <citerefentry
- project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry>
- system call. If this is used, it must be ensured that the
- process binary and all its auxiliary files are available in
- the <function>chroot()</function> jail. Note that setting this
- parameter might result in additional dependencies to be added
- to the unit (see above).</para></listitem>
+ <listitem><para>Takes a directory path relative to the host's root directory (i.e. the root of the system
+ running the service manager). Sets the root directory for executed processes, with the <citerefentry
+ project='man-pages'><refentrytitle>chroot</refentrytitle><manvolnum>2</manvolnum></citerefentry> system
+ call. If this is used, it must be ensured that the process binary and all its auxiliary files are available in
+ the <function>chroot()</function> jail. Note that setting this parameter might result in additional
+ dependencies to be added to the unit (see above).</para>
+
+ <para>The <varname>PrivateUsers=</varname> setting is particularly useful in conjunction with
+ <varname>RootDirectory=</varname>. For details, see below.</para></listitem>
</varlistentry>
<varlistentry>
@@ -999,6 +992,28 @@
</varlistentry>
<varlistentry>
+ <term><varname>PrivateUsers=</varname></term>
+
+ <listitem><para>Takes a boolean argument. If true, sets up a new user namespace for the executed processes and
+ configures a minimal user and group mapping, that maps the <literal>root</literal> user and group as well as
+ the unit's own user and group to themselves and everything else to the <literal>nobody</literal> user and
+ group. This is useful to securely detach the user and group databases used by the unit from the rest of the
+ system, and thus to create an effective sandbox environment. All files, directories, processes, IPC objects and
+ other resources owned by users/groups not equalling <literal>root</literal> or the unit's own will stay visible
+ from within the unit but appear owned by the <literal>nobody</literal> user and group. If this mode is enabled,
+ all unit processes are run without privileges in the host user namespace (regardless if the unit's own
+ user/group is <literal>root</literal> or not). Specifically this means that the process will have zero process
+ capabilities on the host's user namespace, but full capabilities within the service's user namespace. Settings
+ such as <varname>CapabilityBoundingSet=</varname> will affect only the latter, and there's no way to acquire
+ additional capabilities in the host's user namespace. Defaults to off.</para>
+
+ <para>This setting is particularly useful in conjunction with <varname>RootDirectory=</varname>, as the need to
+ synchronize the user and group databases in the root directory and on the host is reduced, as the only users
+ and groups who need to be matched are <literal>root</literal>, <literal>nobody</literal> and the unit's own
+ user and group.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><varname>ProtectSystem=</varname></term>
<listitem><para>Takes a boolean argument or
@@ -1449,7 +1464,7 @@
<listitem><para>Takes a boolean argument. If set, any attempts to enable realtime scheduling in a process of
the unit are refused. This restricts access to realtime task scheduling policies such as
<constant>SCHED_FIFO</constant>, <constant>SCHED_RR</constant> or <constant>SCHED_DEADLINE</constant>. See
- <citerefentry><refentrytitle>sched</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details about
+ <citerefentry project='man-pages'><refentrytitle>sched</refentrytitle><manvolnum>7</manvolnum></citerefentry> for details about
these scheduling policies. Realtime scheduling policies may be used to monopolize CPU time for longer periods
of time, and may hence be used to lock up or otherwise trigger Denial-of-Service situations on the system. It
is hence recommended to restrict access to realtime scheduling to the few programs that actually require
@@ -1602,6 +1617,118 @@
functions) if their standard output or standard error output is connected to the journal anyway, thus enabling
delivery of structured metadata along with logged messages.</para></listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><varname>$SERVICE_RESULT</varname></term>
+
+ <listitem><para>Only defined for the service unit type, this environment variable is passed to all
+ <varname>ExecStop=</varname> and <varname>ExecStopPost=</varname> processes, and encodes the service
+ "result". Currently, the following values are defined: <literal>timeout</literal> (in case of an operation
+ timeout), <literal>exit-code</literal> (if a service process exited with a non-zero exit code; see
+ <varname>$EXIT_STATUS</varname> below for the actual exit status returned), <literal>signal</literal> (if a
+ service process was terminated abnormally by a signal; see <varname>$EXIT_STATUS</varname> below for the actual
+ signal used for the termination), <literal>core-dump</literal> (if a service process terminated abnormally and
+ dumped core), <literal>watchdog</literal> (if the watchdog keep-alive ping was enabled for the service but it
+ missed the deadline), or <literal>resources</literal> (a catch-all condition in case a system operation
+ failed).</para>
+
+ <para>This environment variable is useful to monitor failure or successful termination of a service. Even
+ though this variable is available in both <varname>ExecStop=</varname> and <varname>ExecStopPost=</varname>, it
+ is usually a better choice to place monitoring tools in the latter, as the former is only invoked for services
+ that managed to start up correctly, and the latter covers both services that failed during their start-up and
+ those which failed during their runtime.</para></listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><varname>$EXIT_CODE</varname></term>
+ <term><varname>$EXIT_STATUS</varname></term>
+
+ <listitem><para>Only defined for the service unit type, these environment variables are passed to all
+ <varname>ExecStop=</varname>, <varname>ExecStopPost=</varname> processes and contain exit status/code
+ information of the main process of the service. For the precise definition of the exit code and status, see
+ <citerefentry><refentrytitle>wait</refentrytitle><manvolnum>2</manvolnum></citerefentry>. <varname>$EXIT_CODE</varname>
+ is one of <literal>exited</literal>, <literal>killed</literal>,
+ <literal>dumped</literal>. <varname>$EXIT_STATUS</varname> contains the numeric exit code formatted as string
+ if <varname>$EXIT_CODE</varname> is <literal>exited</literal>, and the signal name in all other cases. Note
+ that these environment variables are only set if the service manager succeeded to start and identify the main
+ process of the service.</para>
+
+ <table>
+ <title>Summary of possible service result variable values</title>
+ <tgroup cols='3'>
+ <colspec colname='result' />
+ <colspec colname='status' />
+ <colspec colname='code' />
+ <thead>
+ <row>
+ <entry><varname>$SERVICE_RESULT</varname></entry>
+ <entry><varname>$EXIT_STATUS</varname></entry>
+ <entry><varname>$EXIT_CODE</varname></entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry morerows="1" valign="top"><literal>timeout</literal></entry>
+ <entry valign="top"><literal>killed</literal></entry>
+ <entry><literal>TERM</literal><sbr/><literal>KILL</literal></entry>
+ </row>
+
+ <row>
+ <entry valign="top"><literal>exited</literal></entry>
+ <entry><literal>0</literal><sbr/><literal>1</literal><sbr/><literal>2</literal><sbr/><literal
+ >3</literal><sbr/>…<sbr/><literal>255</literal></entry>
+ </row>
+
+ <row>
+ <entry valign="top"><literal>exit-code</literal></entry>
+ <entry valign="top"><literal>exited</literal></entry>
+ <entry><literal>0</literal><sbr/><literal>1</literal><sbr/><literal>2</literal><sbr/><literal
+ >3</literal><sbr/>…<sbr/><literal>255</literal></entry>
+ </row>
+
+ <row>
+ <entry valign="top"><literal>signal</literal></entry>
+ <entry valign="top"><literal>killed</literal></entry>
+ <entry><literal>HUP</literal><sbr/><literal>INT</literal><sbr/><literal>KILL</literal><sbr/>…</entry>
+ </row>
+
+ <row>
+ <entry valign="top"><literal>core-dump</literal></entry>
+ <entry valign="top"><literal>dumped</literal></entry>
+ <entry><literal>ABRT</literal><sbr/><literal>SEGV</literal><sbr/><literal>QUIT</literal><sbr/>…</entry>
+ </row>
+
+ <row>
+ <entry morerows="2" valign="top"><literal>watchdog</literal></entry>
+ <entry><literal>dumped</literal></entry>
+ <entry><literal>ABRT</literal></entry>
+ </row>
+ <row>
+ <entry><literal>killed</literal></entry>
+ <entry><literal>TERM</literal><sbr/><literal>KILL</literal></entry>
+ </row>
+ <row>
+ <entry><literal>exited</literal></entry>
+ <entry><literal>0</literal><sbr/><literal>1</literal><sbr/><literal>2</literal><sbr/><literal
+ >3</literal><sbr/>…<sbr/><literal>255</literal></entry>
+ </row>
+
+ <row>
+ <entry><literal>resources</literal></entry>
+ <entry>any of the above</entry>
+ <entry>any of the above</entry>
+ </row>
+
+ <row>
+ <entry namest="results" nameend="code">Note: the process may be also terminated by a signal not sent by systemd. In particular the process may send an arbitrary signal to itself in a handler for any of the non-maskable signals. Nevertheless, in the <literal>timeout</literal> and <literal>watchdog</literal> rows above only the signals that systemd sends have been included.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ </listitem>
+ </varlistentry>
</variablelist>
<para>Additional variables may be configured by the following
@@ -1637,4 +1764,5 @@
</para>
</refsect1>
+
</refentry>
diff --git a/man/systemd.mount.xml b/man/systemd.mount.xml
index 66cddd72e0..a38165f9b9 100644
--- a/man/systemd.mount.xml
+++ b/man/systemd.mount.xml
@@ -160,7 +160,7 @@
for details about the conversion.</para>
<para>The NFS mount option <option>bg</option> for NFS background mounts
- as documented in <citerefentry><refentrytitle>nfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>
+ as documented in <citerefentry project='man-pages'><refentrytitle>nfs</refentrytitle><manvolnum>5</manvolnum></citerefentry>
is not supported in <filename>/etc/fstab</filename> entries. The systemd mount option <option>nofail</option>
provides similar functionality and should be used instead.</para>
diff --git a/man/systemd.netdev.xml b/man/systemd.netdev.xml
index a5c6f0fa40..e56708a648 100644
--- a/man/systemd.netdev.xml
+++ b/man/systemd.netdev.xml
@@ -343,8 +343,15 @@
</para>
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><varname>STP=</varname></term>
+ <listitem>
+ <para>A boolean. This enables the bridge's Spanning Tree Protocol (STP). When unset,
+ the kernel's default setting applies.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
-
</refsect1>
<refsect1>
diff --git a/man/systemd.offline-updates.xml b/man/systemd.offline-updates.xml
index ae53b8552d..f404c8d72f 100644
--- a/man/systemd.offline-updates.xml
+++ b/man/systemd.offline-updates.xml
@@ -77,7 +77,7 @@
<listitem>
<para>Very early in the new boot
- <citerefentry><refentrytitle>systemd-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>systemd-system-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>
checks whether <filename>/system-update</filename> exists. If so, it (temporarily and for
this boot only) redirects (i.e. symlinks) <filename>default.target</filename> to
<filename>system-update.target</filename>, a special target that is pulls in the base system
@@ -162,8 +162,8 @@
<ulink url="http://www.freedesktop.org/wiki/Software/systemd/SystemUpdates/">Implementing Offline System Updates</ulink>,
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>systemd.generator</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>systemd-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
- <citerefentry><refentrytitle>dnf.plugin.system-upgrade</refentrytitle><manvolnum>8</manvolnum></citerefentry>
+ <citerefentry><refentrytitle>systemd-system-update-generator</refentrytitle><manvolnum>8</manvolnum></citerefentry>,
+ <citerefentry project='mankier'><refentrytitle>dnf.plugin.system-upgrade</refentrytitle><manvolnum>8</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>
diff --git a/man/systemd.service.xml b/man/systemd.service.xml
index 875d368fcf..b58e887662 100644
--- a/man/systemd.service.xml
+++ b/man/systemd.service.xml
@@ -276,17 +276,12 @@
below (see section "Command Lines" below).
</para>
- <para>When <varname>Type=</varname> is not
- <option>oneshot</option>, only one command may and must be
- given. When <varname>Type=oneshot</varname> is used, zero or
- more commands may be specified. This can be specified by
- providing multiple command lines in the same directive, or
- alternatively, this directive may be specified more than once
- with the same effect. If the empty string is assigned to this
- option, the list of commands to start is reset, prior
- assignments of this option will have no effect. If no
- <varname>ExecStart=</varname> is specified, then the service
- must have <varname>RemainAfterExit=yes</varname> set.</para>
+ <para>Unless <varname>Type=</varname> is <option>oneshot</option>, exactly one command must be given. When
+ <varname>Type=oneshot</varname> is used, zero or more commands may be specified. Commands may be specified by
+ providing multiple command lines in the same directive, or alternatively, this directive may be specified more
+ than once with the same effect. If the empty string is assigned to this option, the list of commands to start
+ is reset, prior assignments of this option will have no effect. If no <varname>ExecStart=</varname> is
+ specified, then the service must have <varname>RemainAfterExit=yes</varname> set.</para>
<para>For each of the specified commands, the first argument must be an absolute path to an
executable. Optionally, if this file name is prefixed with <literal>@</literal>, the second token will be
@@ -294,7 +289,7 @@
the absolute filename is prefixed with <literal>-</literal>, an exit code of the command normally considered a
failure (i.e. non-zero exit status or abnormal exit due to signal) is ignored and considered success. If the
absolute path is prefixed with <literal>+</literal> then it is executed with full
- privileges. <literal>-</literal>, <literal>@</literal>, and <literal>+</literal> may be used together and they
+ privileges. <literal>@</literal>, <literal>-</literal>, and <literal>+</literal> may be used together and they
can appear in any order.</para>
<para>If more than one command is specified, the commands are
@@ -429,7 +424,13 @@
service failed to start up correctly. Commands configured with this setting need to be able to operate even if
the service failed starting up half-way and left incompletely initialized data around. As the service's
processes have been terminated already when the commands specified with this setting are executed they should
- not attempt to communicate with them.</para></listitem>
+ not attempt to communicate with them.</para>
+
+ <para>Note that all commands that are configured with this setting are invoked with the result code of the
+ service, as well as the main process' exit code and status, set in the <varname>$SERVICE_RESULT</varname>,
+ <varname>$EXIT_CODE</varname> and <varname>$EXIT_STATUS</varname> environment variables, see
+ <citerefentry><refentrytitle>systemd.exec</refentrytitle><manvolnum>5</manvolnum></citerefentry> for
+ details.</para></listitem>
</varlistentry>
<varlistentry>
diff --git a/man/tmpfiles.d.xml b/man/tmpfiles.d.xml
index 957475d2bd..75fb901102 100644
--- a/man/tmpfiles.d.xml
+++ b/man/tmpfiles.d.xml
@@ -626,7 +626,7 @@
<example>
<title>Create directories with specific mode and ownership</title>
<para>
- <citerefentry><refentrytitle>screen</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>screen</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
needs two directories created at boot with specific modes and ownership:</para>
<programlisting># /usr/lib/tmpfiles.d/screen.conf
@@ -652,7 +652,7 @@ t /run/cups - - - - security.SMACK64=printing user.attr-with-spaces="foo bar"
<example>
<title>Create a directory and prevent its contents from cleanup</title>
<para>
- <citerefentry><refentrytitle>abrt</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
+ <citerefentry project='die-net'><refentrytitle>abrt</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
needs a directory created at boot with specific mode and ownership and its content
should be preserved from the automatic cleanup applied to the contents of
<filename>/var/tmp</filename>:</para>
diff --git a/shell-completion/zsh/_journalctl b/shell-completion/zsh/_journalctl
index 2bee23b6d3..e6549e863f 100644
--- a/shell-completion/zsh/_journalctl
+++ b/shell-completion/zsh/_journalctl
@@ -23,7 +23,7 @@ _list_fields() {
_journal_none() {
local -a _commands _files _jrnl_none
# Setting use-cache will slow this down considerably
- _commands=( ${"$(_call_program commands "$service" -F _EXE 2>/dev/null)"} )
+ _commands=( ${"$(_call_program commands "$service $_sys_service_mgr -F _EXE" 2>/dev/null)"} )
_jrnl_none='yes'
_alternative : \
'files:/dev files:_files -W /dev -P /dev/' \
@@ -33,7 +33,7 @@ _journal_none() {
_journal_fields() {
local -a _fields cmd
- cmd=("journalctl" "-F ${@[-1]}" "2>/dev/null" )
+ cmd=("journalctl $_sys_service_mgr" "-F ${@[-1]}" "2>/dev/null" )
_fields=$(_call_program fields $cmd[@])
_fields=${_fields//'\'/'\\'}
_fields=${_fields//':'/'\:'}
@@ -51,6 +51,22 @@ _journal_boots() {
"bootid:boot ids:compadd -a _bootid"
}
+# Build arguments for "journalctl" to be used in completion.
+# Use both --user and --system modes, they are not exclusive.
+local -a _modes; _modes=(--user --system)
+local -a _modes_with_arg; _modes_with_arg=(--directory -D --file -M --machine)
+typeset -a _sys_service_mgr
+local w i=0 n=$#words
+while (( i++ < n )); do
+ w=$words[$i]
+ if (( $_modes[(I)$w] )); then
+ _sys_service_mgr+=($w)
+ else
+ if (( ${_modes_with_arg[(I)$w]} )); then
+ _sys_service_mgr+=($w ${words[((++i))]})
+ fi
+ fi
+done
_arguments -s \
{-h,--help}'[Show this help]' \
'--version[Show package version]' \
diff --git a/shell-completion/zsh/_systemctl.in b/shell-completion/zsh/_systemctl.in
index 44c31b7833..b525286932 100644
--- a/shell-completion/zsh/_systemctl.in
+++ b/shell-completion/zsh/_systemctl.in
@@ -126,7 +126,7 @@ _filter_units_by_property() {
local property=$1 value=$2 ; shift ; shift
local -a units ; units=($*)
local props
- for props in ${(ps:\n\n:)"$(_call_program units "$service show --no-pager --property="Id,$property" -- ${units} 2>/dev/null")"}; do
+ for props in ${(ps:\n\n:)"$(_call_program units "$service $_sys_service_mgr show --no-pager --property="Id,$property" -- ${units} 2>/dev/null")"}; do
props=(${(f)props})
if [[ "${props[2]}" = "$property=$value" ]]; then
echo -E - " ${props[1]#Id=}"
@@ -351,8 +351,10 @@ _job_modes() {
_values -s , "${_modes[@]}"
}
+# Build arguments for "systemctl" to be used in completion.
local -a _modes; _modes=("--user" "--system")
-local _sys_service_mgr=${${words:*_modes}[(R)(${(j.|.)_modes})]:---system}
+# Use the last mode (they are exclusive and the last one is used).
+local _sys_service_mgr=${${words:*_modes}[(R)(${(j.|.)_modes})]}
_arguments -s \
{-h,--help}'[Show help]' \
'--version[Show package version]' \
diff --git a/src/basic/fileio.c b/src/basic/fileio.c
index 588eacd77c..d642f3daea 100644
--- a/src/basic/fileio.c
+++ b/src/basic/fileio.c
@@ -1168,8 +1168,8 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
char *t, *x;
uint64_t u;
unsigned i;
+ int r;
- assert(p);
assert(ret);
/* Turns this:
@@ -1178,6 +1178,12 @@ int tempfn_random_child(const char *p, const char *extra, char **ret) {
* /foo/bar/waldo/.#<extra>3c2b6219aa75d7d0
*/
+ if (!p) {
+ r = tmp_dir(&p);
+ if (r < 0)
+ return r;
+ }
+
if (!extra)
extra = "";
@@ -1264,10 +1270,13 @@ int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space)
int open_tmpfile_unlinkable(const char *directory, int flags) {
char *p;
- int fd;
+ int fd, r;
- if (!directory)
- directory = "/tmp";
+ if (!directory) {
+ r = tmp_dir(&directory);
+ if (r < 0)
+ return r;
+ }
/* Returns an unlinked temporary file that cannot be linked into the file system anymore */
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index f0c6f3265e..ce87257bc1 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -496,34 +496,94 @@ int get_files_in_directory(const char *path, char ***list) {
return n;
}
-int var_tmp(char **ret) {
- const char *tmp_dir = NULL;
- const char *env_tmp_dir = NULL;
- char *c = NULL;
- int r;
+static int getenv_tmp_dir(const char **ret_path) {
+ const char *n;
+ int r, ret = 0;
- assert(ret);
+ assert(ret_path);
- env_tmp_dir = getenv("TMPDIR");
- if (env_tmp_dir != NULL) {
- r = is_dir(env_tmp_dir, true);
- if (r < 0 && r != -ENOENT)
- return r;
- if (r > 0)
- tmp_dir = env_tmp_dir;
+ /* We use the same order of environment variables python uses in tempfile.gettempdir():
+ * https://docs.python.org/3/library/tempfile.html#tempfile.gettempdir */
+ FOREACH_STRING(n, "TMPDIR", "TEMP", "TMP") {
+ const char *e;
+
+ e = secure_getenv(n);
+ if (!e)
+ continue;
+ if (!path_is_absolute(e)) {
+ r = -ENOTDIR;
+ goto next;
+ }
+ if (!path_is_safe(e)) {
+ r = -EPERM;
+ goto next;
+ }
+
+ r = is_dir(e, true);
+ if (r < 0)
+ goto next;
+ if (r == 0) {
+ r = -ENOTDIR;
+ goto next;
+ }
+
+ *ret_path = e;
+ return 1;
+
+ next:
+ /* Remember first error, to make this more debuggable */
+ if (ret >= 0)
+ ret = r;
}
- if (!tmp_dir)
- tmp_dir = "/var/tmp";
+ if (ret < 0)
+ return ret;
- c = strdup(tmp_dir);
- if (!c)
- return -ENOMEM;
- *ret = c;
+ *ret_path = NULL;
+ return ret;
+}
+static int tmp_dir_internal(const char *def, const char **ret) {
+ const char *e;
+ int r, k;
+
+ assert(def);
+ assert(ret);
+
+ r = getenv_tmp_dir(&e);
+ if (r > 0) {
+ *ret = e;
+ return 0;
+ }
+
+ k = is_dir(def, true);
+ if (k == 0)
+ k = -ENOTDIR;
+ if (k < 0)
+ return r < 0 ? r : k;
+
+ *ret = def;
return 0;
}
+int var_tmp_dir(const char **ret) {
+
+ /* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
+ * even might survive a boot: /var/tmp. If $TMPDIR (or related environment variables) are set, its value is
+ * returned preferably however. Note that both this function and tmp_dir() below are affected by $TMPDIR,
+ * making it a variable that overrides all temporary file storage locations. */
+
+ return tmp_dir_internal("/var/tmp", ret);
+}
+
+int tmp_dir(const char **ret) {
+
+ /* Similar to var_tmp_dir() above, but returns the location for "smaller" temporary files, which is usually
+ * backed by an in-memory file system: /tmp. */
+
+ return tmp_dir_internal("/tmp", ret);
+}
+
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
int r;
diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h
index 075e5942b1..2c3b9a1c74 100644
--- a/src/basic/fs-util.h
+++ b/src/basic/fs-util.h
@@ -61,7 +61,8 @@ int mkfifo_atomic(const char *path, mode_t mode);
int get_files_in_directory(const char *path, char ***list);
-int var_tmp(char **ret);
+int tmp_dir(const char **ret);
+int var_tmp_dir(const char **ret);
#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX + 1)
diff --git a/src/core/automount.c b/src/core/automount.c
index 20a73c76f9..00295cf769 100644
--- a/src/core/automount.c
+++ b/src/core/automount.c
@@ -301,7 +301,7 @@ static void automount_dump(Unit *u, FILE *f, const char *prefix) {
static void automount_enter_dead(Automount *a, AutomountResult f) {
assert(a);
- if (f != AUTOMOUNT_SUCCESS)
+ if (a->result == AUTOMOUNT_SUCCESS)
a->result = f;
automount_set_state(a, a->result != AUTOMOUNT_SUCCESS ? AUTOMOUNT_FAILED : AUTOMOUNT_DEAD);
diff --git a/src/core/busname.c b/src/core/busname.c
index 730be2ee14..7952cd31aa 100644
--- a/src/core/busname.c
+++ b/src/core/busname.c
@@ -442,7 +442,7 @@ fail:
static void busname_enter_dead(BusName *n, BusNameResult f) {
assert(n);
- if (f != BUSNAME_SUCCESS)
+ if (n->result == BUSNAME_SUCCESS)
n->result = f;
busname_set_state(n, n->result != BUSNAME_SUCCESS ? BUSNAME_FAILED : BUSNAME_DEAD);
@@ -454,7 +454,7 @@ static void busname_enter_signal(BusName *n, BusNameState state, BusNameResult f
assert(n);
- if (f != BUSNAME_SUCCESS)
+ if (n->result == BUSNAME_SUCCESS)
n->result = f;
kill_context_init(&kill_context);
@@ -882,7 +882,7 @@ static void busname_sigchld_event(Unit *u, pid_t pid, int code, int status) {
log_unit_full(u, f == BUSNAME_SUCCESS ? LOG_DEBUG : LOG_NOTICE, 0,
"Control process exited, code=%s status=%i", sigchld_code_to_string(code), status);
- if (f != BUSNAME_SUCCESS)
+ if (n->result == BUSNAME_SUCCESS)
n->result = f;
switch (n->state) {
diff --git a/src/core/dbus-execute.c b/src/core/dbus-execute.c
index 346c8b973e..e35d3ccd2e 100644
--- a/src/core/dbus-execute.c
+++ b/src/core/dbus-execute.c
@@ -705,8 +705,9 @@ const sd_bus_vtable bus_exec_vtable[] = {
SD_BUS_PROPERTY("InaccessiblePaths", "as", NULL, offsetof(ExecContext, inaccessible_paths), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("MountFlags", "t", bus_property_get_ulong, offsetof(ExecContext, mount_flags), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateTmp", "b", bus_property_get_bool, offsetof(ExecContext, private_tmp), SD_BUS_VTABLE_PROPERTY_CONST),
- SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("PrivateDevices", "b", bus_property_get_bool, offsetof(ExecContext, private_devices), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("PrivateNetwork", "b", bus_property_get_bool, offsetof(ExecContext, private_network), SD_BUS_VTABLE_PROPERTY_CONST),
+ SD_BUS_PROPERTY("PrivateUsers", "b", bus_property_get_bool, offsetof(ExecContext, private_users), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProtectHome", "s", bus_property_get_protect_home, offsetof(ExecContext, protect_home), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("ProtectSystem", "s", bus_property_get_protect_system, offsetof(ExecContext, protect_system), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("SameProcessGroup", "b", bus_property_get_bool, offsetof(ExecContext, same_pgrp), SD_BUS_VTABLE_PROPERTY_CONST),
@@ -1068,7 +1069,7 @@ int bus_exec_context_set_transient_property(
} else if (STR_IN_SET(name,
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset",
- "PrivateTmp", "PrivateDevices", "PrivateNetwork",
+ "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers",
"NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute",
"RestrictRealtime", "DynamicUser")) {
int b;
@@ -1090,6 +1091,8 @@ int bus_exec_context_set_transient_property(
c->private_devices = b;
else if (streq(name, "PrivateNetwork"))
c->private_network = b;
+ else if (streq(name, "PrivateUsers"))
+ c->private_users = b;
else if (streq(name, "NoNewPrivileges"))
c->no_new_privileges = b;
else if (streq(name, "SyslogLevelPrefix"))
diff --git a/src/core/execute.c b/src/core/execute.c
index 77a75245cb..6019df7ea6 100644
--- a/src/core/execute.c
+++ b/src/core/execute.c
@@ -25,6 +25,7 @@
#include <signal.h>
#include <string.h>
#include <sys/capability.h>
+#include <sys/eventfd.h>
#include <sys/mman.h>
#include <sys/personality.h>
#include <sys/prctl.h>
@@ -427,7 +428,7 @@ static int setup_input(
return STDIN_FILENO;
}
- i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
+ i = fixup_input(context->std_input, socket_fd, params->flags & EXEC_APPLY_TTY_STDIN);
switch (i) {
@@ -502,7 +503,7 @@ static int setup_output(
return STDERR_FILENO;
}
- i = fixup_input(context->std_input, socket_fd, params->apply_tty_stdin);
+ i = fixup_input(context->std_input, socket_fd, params->flags & EXEC_APPLY_TTY_STDIN);
o = fixup_output(context->std_output, socket_fd);
if (fileno == STDERR_FILENO) {
@@ -1425,7 +1426,7 @@ static int build_environment(
our_env[n_env++] = x;
}
- if (p->watchdog_usec > 0) {
+ if ((p->flags & EXEC_SET_WATCHDOG) && p->watchdog_usec > 0) {
if (asprintf(&x, "WATCHDOG_PID="PID_FMT, getpid()) < 0)
return -ENOMEM;
our_env[n_env++] = x;
@@ -1552,6 +1553,159 @@ static bool exec_needs_mount_namespace(
return false;
}
+static int setup_private_users(uid_t uid, gid_t gid) {
+ _cleanup_free_ char *uid_map = NULL, *gid_map = NULL;
+ _cleanup_close_pair_ int errno_pipe[2] = { -1, -1 };
+ _cleanup_close_ int unshare_ready_fd = -1;
+ _cleanup_(sigkill_waitp) pid_t pid = 0;
+ uint64_t c = 1;
+ siginfo_t si;
+ ssize_t n;
+ int r;
+
+ /* Set up a user namespace and map root to root, the selected UID/GID to itself, and everything else to
+ * nobody. In order to be able to write this mapping we need CAP_SETUID in the original user namespace, which
+ * we however lack after opening the user namespace. To work around this we fork() a temporary child process,
+ * which waits for the parent to create the new user namespace while staying in the original namespace. The
+ * child then writes the UID mapping, under full privileges. The parent waits for the child to finish and
+ * continues execution normally. */
+
+ if (uid != 0 && uid_is_valid(uid))
+ asprintf(&uid_map,
+ "0 0 1\n" /* Map root → root */
+ UID_FMT " " UID_FMT " 1\n", /* Map $UID → $UID */
+ uid, uid); /* The case where the above is the same */
+ else
+ uid_map = strdup("0 0 1\n");
+ if (!uid_map)
+ return -ENOMEM;
+
+ if (gid != 0 && gid_is_valid(gid))
+ asprintf(&gid_map,
+ "0 0 1\n" /* Map root → root */
+ GID_FMT " " GID_FMT " 1\n", /* Map $GID → $GID */
+ gid, gid);
+ else
+ gid_map = strdup("0 0 1\n"); /* The case where the above is the same */
+ if (!gid_map)
+ return -ENOMEM;
+
+ /* Create a communication channel so that the parent can tell the child when it finished creating the user
+ * namespace. */
+ unshare_ready_fd = eventfd(0, EFD_CLOEXEC);
+ if (unshare_ready_fd < 0)
+ return -errno;
+
+ /* Create a communication channel so that the child can tell the parent a proper error code in case it
+ * failed. */
+ if (pipe2(errno_pipe, O_CLOEXEC) < 0)
+ return -errno;
+
+ pid = fork();
+ if (pid < 0)
+ return -errno;
+
+ if (pid == 0) {
+ _cleanup_close_ int fd = -1;
+ const char *a;
+ pid_t ppid;
+
+ /* Child process, running in the original user namespace. Let's update the parent's UID/GID map from
+ * here, after the parent opened its own user namespace. */
+
+ ppid = getppid();
+ errno_pipe[0] = safe_close(errno_pipe[0]);
+
+ /* Wait until the parent unshared the user namespace */
+ if (read(unshare_ready_fd, &c, sizeof(c)) < 0) {
+ r = -errno;
+ goto child_fail;
+ }
+
+ /* Disable the setgroups() system call in the child user namespace, for good. */
+ a = procfs_file_alloca(ppid, "setgroups");
+ fd = open(a, O_WRONLY|O_CLOEXEC);
+ if (fd < 0) {
+ if (errno != ENOENT) {
+ r = -errno;
+ goto child_fail;
+ }
+
+ /* If the file is missing the kernel is too old, let's continue anyway. */
+ } else {
+ if (write(fd, "deny\n", 5) < 0) {
+ r = -errno;
+ goto child_fail;
+ }
+
+ fd = safe_close(fd);
+ }
+
+ /* First write the GID map */
+ a = procfs_file_alloca(ppid, "gid_map");
+ fd = open(a, O_WRONLY|O_CLOEXEC);
+ if (fd < 0) {
+ r = -errno;
+ goto child_fail;
+ }
+ if (write(fd, gid_map, strlen(gid_map)) < 0) {
+ r = -errno;
+ goto child_fail;
+ }
+ fd = safe_close(fd);
+
+ /* The write the UID map */
+ a = procfs_file_alloca(ppid, "uid_map");
+ fd = open(a, O_WRONLY|O_CLOEXEC);
+ if (fd < 0) {
+ r = -errno;
+ goto child_fail;
+ }
+ if (write(fd, uid_map, strlen(uid_map)) < 0) {
+ r = -errno;
+ goto child_fail;
+ }
+
+ _exit(EXIT_SUCCESS);
+
+ child_fail:
+ (void) write(errno_pipe[1], &r, sizeof(r));
+ _exit(EXIT_FAILURE);
+ }
+
+ errno_pipe[1] = safe_close(errno_pipe[1]);
+
+ if (unshare(CLONE_NEWUSER) < 0)
+ return -errno;
+
+ /* Let the child know that the namespace is ready now */
+ if (write(unshare_ready_fd, &c, sizeof(c)) < 0)
+ return -errno;
+
+ /* Try to read an error code from the child */
+ n = read(errno_pipe[0], &r, sizeof(r));
+ if (n < 0)
+ return -errno;
+ if (n == sizeof(r)) { /* an error code was sent to us */
+ if (r < 0)
+ return r;
+ return -EIO;
+ }
+ if (n != 0) /* on success we should have read 0 bytes */
+ return -EIO;
+
+ r = wait_for_terminate(pid, &si);
+ if (r < 0)
+ return r;
+ pid = 0;
+
+ /* If something strange happened with the child, let's consider this fatal, too */
+ if (si.si_code != CLD_EXITED || si.si_status != 0)
+ return -EIO;
+
+ return 0;
+}
+
static void append_socket_pair(int *array, unsigned *n, int pair[2]) {
assert(array);
assert(n);
@@ -1675,7 +1829,7 @@ static int exec_child(
exec_context_tty_reset(context, params);
- if (params->confirm_spawn) {
+ if (params->flags & EXEC_CONFIRM_SPAWN) {
char response;
r = ask_for_confirmation(&response, argv);
@@ -1940,7 +2094,7 @@ static int exec_child(
umask(context->umask);
- if (params->apply_permissions && !command->privileged) {
+ if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
r = enforce_groups(context, username, gid);
if (r < 0) {
*exit_status = EXIT_GROUP;
@@ -2010,7 +2164,7 @@ static int exec_child(
}
r = setup_namespace(
- params->apply_chroot ? context->root_directory : NULL,
+ (params->flags & EXEC_APPLY_CHROOT) ? context->root_directory : NULL,
context->read_write_paths,
context->read_only_paths,
context->inaccessible_paths,
@@ -2041,7 +2195,7 @@ static int exec_child(
else
wd = "/";
- if (params->apply_chroot) {
+ if (params->flags & EXEC_APPLY_CHROOT) {
if (!needs_mount_namespace && context->root_directory)
if (chroot(context->root_directory) < 0) {
*exit_status = EXIT_CHROOT;
@@ -2065,7 +2219,12 @@ static int exec_child(
}
#ifdef HAVE_SELINUX
- if (params->apply_permissions && mac_selinux_use() && params->selinux_context_net && socket_fd >= 0 && !command->privileged) {
+ if ((params->flags & EXEC_APPLY_PERMISSIONS) &&
+ mac_selinux_use() &&
+ params->selinux_context_net &&
+ socket_fd >= 0 &&
+ !command->privileged) {
+
r = mac_selinux_get_child_mls_label(socket_fd, command->path, context->selinux_context, &mac_selinux_context_net);
if (r < 0) {
*exit_status = EXIT_SELINUX_CONTEXT;
@@ -2074,6 +2233,14 @@ static int exec_child(
}
#endif
+ if ((params->flags & EXEC_APPLY_PERMISSIONS) && context->private_users) {
+ r = setup_private_users(uid, gid);
+ if (r < 0) {
+ *exit_status = EXIT_USER;
+ return r;
+ }
+ }
+
/* We repeat the fd closing here, to make sure that
* nothing is leaked from the PAM modules. Note that
* we are more aggressive this time since socket_fd
@@ -2090,7 +2257,7 @@ static int exec_child(
return r;
}
- if (params->apply_permissions && !command->privileged) {
+ if ((params->flags & EXEC_APPLY_PERMISSIONS) && !command->privileged) {
bool use_address_families = context->address_families_whitelist ||
!set_isempty(context->address_families);
@@ -2635,8 +2802,9 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
"%sRootDirectory: %s\n"
"%sNonBlocking: %s\n"
"%sPrivateTmp: %s\n"
- "%sPrivateNetwork: %s\n"
"%sPrivateDevices: %s\n"
+ "%sPrivateNetwork: %s\n"
+ "%sPrivateUsers: %s\n"
"%sProtectHome: %s\n"
"%sProtectSystem: %s\n"
"%sIgnoreSIGPIPE: %s\n"
@@ -2647,8 +2815,9 @@ void exec_context_dump(ExecContext *c, FILE* f, const char *prefix) {
prefix, c->root_directory ? c->root_directory : "/",
prefix, yes_no(c->non_blocking),
prefix, yes_no(c->private_tmp),
- prefix, yes_no(c->private_network),
prefix, yes_no(c->private_devices),
+ prefix, yes_no(c->private_network),
+ prefix, yes_no(c->private_users),
prefix, protect_home_to_string(c->protect_home),
prefix, protect_system_to_string(c->protect_system),
prefix, yes_no(c->ignore_sigpipe),
@@ -2964,12 +3133,12 @@ void exec_status_dump(ExecStatus *s, FILE *f, const char *prefix) {
"%sPID: "PID_FMT"\n",
prefix, s->pid);
- if (s->start_timestamp.realtime > 0)
+ if (dual_timestamp_is_set(&s->start_timestamp))
fprintf(f,
"%sStart Timestamp: %s\n",
prefix, format_timestamp(buf, sizeof(buf), s->start_timestamp.realtime));
- if (s->exit_timestamp.realtime > 0)
+ if (dual_timestamp_is_set(&s->exit_timestamp))
fprintf(f,
"%sExit Timestamp: %s\n"
"%sExit Code: %s\n"
diff --git a/src/core/execute.h b/src/core/execute.h
index 48cc18fbb3..106154f81a 100644
--- a/src/core/execute.h
+++ b/src/core/execute.h
@@ -171,6 +171,7 @@ struct ExecContext {
bool private_tmp;
bool private_network;
bool private_devices;
+ bool private_users;
ProtectSystem protect_system;
ProtectHome protect_home;
@@ -208,6 +209,19 @@ struct ExecContext {
bool no_new_privileges_set:1;
};
+typedef enum ExecFlags {
+ EXEC_CONFIRM_SPAWN = 1U << 0,
+ EXEC_APPLY_PERMISSIONS = 1U << 1,
+ EXEC_APPLY_CHROOT = 1U << 2,
+ EXEC_APPLY_TTY_STDIN = 1U << 3,
+
+ /* The following are not used by execute.c, but by consumers internally */
+ EXEC_PASS_FDS = 1U << 4,
+ EXEC_IS_CONTROL = 1U << 5,
+ EXEC_SETENV_RESULT = 1U << 6,
+ EXEC_SET_WATCHDOG = 1U << 7,
+} ExecFlags;
+
struct ExecParameters {
char **argv;
char **environment;
@@ -216,11 +230,7 @@ struct ExecParameters {
char **fd_names;
unsigned n_fds;
- bool apply_permissions:1;
- bool apply_chroot:1;
- bool apply_tty_stdin:1;
-
- bool confirm_spawn:1;
+ ExecFlags flags;
bool selinux_context_net:1;
bool cgroup_delegate:1;
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index edcfa6fa1b..05fe0df7e3 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -88,8 +88,9 @@ $1.ReadWritePaths, config_parse_namespace_path_strv, 0,
$1.ReadOnlyPaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.read_only_paths)
$1.InaccessiblePaths, config_parse_namespace_path_strv, 0, offsetof($1, exec_context.inaccessible_paths)
$1.PrivateTmp, config_parse_bool, 0, offsetof($1, exec_context.private_tmp)
-$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network)
$1.PrivateDevices, config_parse_bool, 0, offsetof($1, exec_context.private_devices)
+$1.PrivateNetwork, config_parse_bool, 0, offsetof($1, exec_context.private_network)
+$1.PrivateUsers, config_parse_bool, 0, offsetof($1, exec_context.private_users)
$1.ProtectSystem, config_parse_protect_system, 0, offsetof($1, exec_context)
$1.ProtectHome, config_parse_protect_home, 0, offsetof($1, exec_context)
$1.MountFlags, config_parse_exec_mount_flags, 0, offsetof($1, exec_context)
diff --git a/src/core/mount.c b/src/core/mount.c
index afb20af9e2..f3ccf6d48a 100644
--- a/src/core/mount.c
+++ b/src/core/mount.c
@@ -701,12 +701,10 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
pid_t pid;
int r;
ExecParameters exec_params = {
- .apply_permissions = true,
- .apply_chroot = true,
- .apply_tty_stdin = true,
- .stdin_fd = -1,
- .stdout_fd = -1,
- .stderr_fd = -1,
+ .flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(m);
@@ -732,7 +730,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
return r;
exec_params.environment = UNIT(m)->manager->environment;
- exec_params.confirm_spawn = UNIT(m)->manager->confirm_spawn;
+ exec_params.flags |= UNIT(m)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
exec_params.cgroup_supported = UNIT(m)->manager->cgroup_supported;
exec_params.cgroup_path = UNIT(m)->cgroup_path;
exec_params.cgroup_delegate = m->cgroup_context.delegate;
@@ -761,7 +759,7 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) {
static void mount_enter_dead(Mount *m, MountResult f) {
assert(m);
- if (f != MOUNT_SUCCESS)
+ if (m->result == MOUNT_SUCCESS)
m->result = f;
mount_set_state(m, m->result != MOUNT_SUCCESS ? MOUNT_FAILED : MOUNT_DEAD);
@@ -777,7 +775,7 @@ static void mount_enter_dead(Mount *m, MountResult f) {
static void mount_enter_mounted(Mount *m, MountResult f) {
assert(m);
- if (f != MOUNT_SUCCESS)
+ if (m->result == MOUNT_SUCCESS)
m->result = f;
mount_set_state(m, MOUNT_MOUNTED);
@@ -788,7 +786,7 @@ static void mount_enter_signal(Mount *m, MountState state, MountResult f) {
assert(m);
- if (f != MOUNT_SUCCESS)
+ if (m->result == MOUNT_SUCCESS)
m->result = f;
r = unit_kill_context(
@@ -1160,7 +1158,7 @@ static void mount_sigchld_event(Unit *u, pid_t pid, int code, int status) {
else
assert_not_reached("Unknown code");
- if (f != MOUNT_SUCCESS)
+ if (m->result == MOUNT_SUCCESS)
m->result = f;
if (m->control_command) {
diff --git a/src/core/org.freedesktop.systemd1.conf b/src/core/org.freedesktop.systemd1.conf
index 3c64f20872..14f6aec029 100644
--- a/src/core/org.freedesktop.systemd1.conf
+++ b/src/core/org.freedesktop.systemd1.conf
@@ -108,6 +108,14 @@
send_interface="org.freedesktop.systemd1.Manager"
send_member="GetDefaultTarget"/>
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
+ send_member="LookupDynamicUserByName"/>
+
+ <allow send_destination="org.freedesktop.systemd1"
+ send_interface="org.freedesktop.systemd1.Manager"
+ send_member="LookupDynamicUserByUID"/>
+
<!-- Managed via polkit or other criteria -->
<allow send_destination="org.freedesktop.systemd1"
diff --git a/src/core/path.c b/src/core/path.c
index 0dd0d375d8..10f9b06974 100644
--- a/src/core/path.c
+++ b/src/core/path.c
@@ -454,7 +454,7 @@ static int path_coldplug(Unit *u) {
static void path_enter_dead(Path *p, PathResult f) {
assert(p);
- if (f != PATH_SUCCESS)
+ if (p->result == PATH_SUCCESS)
p->result = f;
path_set_state(p, p->result != PATH_SUCCESS ? PATH_FAILED : PATH_DEAD);
diff --git a/src/core/scope.c b/src/core/scope.c
index b45e238974..b278aed3d6 100644
--- a/src/core/scope.c
+++ b/src/core/scope.c
@@ -221,7 +221,7 @@ static void scope_dump(Unit *u, FILE *f, const char *prefix) {
static void scope_enter_dead(Scope *s, ScopeResult f) {
assert(s);
- if (f != SCOPE_SUCCESS)
+ if (s->result == SCOPE_SUCCESS)
s->result = f;
scope_set_state(s, s->result != SCOPE_SUCCESS ? SCOPE_FAILED : SCOPE_DEAD);
@@ -233,7 +233,7 @@ static void scope_enter_signal(Scope *s, ScopeState state, ScopeResult f) {
assert(s);
- if (f != SCOPE_SUCCESS)
+ if (s->result == SCOPE_SUCCESS)
s->result = f;
unit_watch_all_pids(UNIT(s));
diff --git a/src/core/service.c b/src/core/service.c
index 3c9455a5f8..4a37702f52 100644
--- a/src/core/service.c
+++ b/src/core/service.c
@@ -1171,11 +1171,7 @@ static int service_spawn(
Service *s,
ExecCommand *c,
usec_t timeout,
- bool pass_fds,
- bool apply_permissions,
- bool apply_chroot,
- bool apply_tty_stdin,
- bool is_control,
+ ExecFlags flags,
pid_t *_pid) {
_cleanup_strv_free_ char **argv = NULL, **final_env = NULL, **our_env = NULL, **fd_names = NULL;
@@ -1185,12 +1181,10 @@ static int service_spawn(
pid_t pid;
ExecParameters exec_params = {
- .apply_permissions = apply_permissions,
- .apply_chroot = apply_chroot,
- .apply_tty_stdin = apply_tty_stdin,
- .stdin_fd = -1,
- .stdout_fd = -1,
- .stderr_fd = -1,
+ .flags = flags,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
int r;
@@ -1199,6 +1193,14 @@ static int service_spawn(
assert(c);
assert(_pid);
+ if (flags & EXEC_IS_CONTROL) {
+ /* If this is a control process, mask the permissions/chroot application if this is requested. */
+ if (s->permissions_start_only)
+ exec_params.flags &= ~EXEC_APPLY_PERMISSIONS;
+ if (s->root_directory_start_only)
+ exec_params.flags &= ~EXEC_APPLY_CHROOT;
+ }
+
(void) unit_realize_cgroup(UNIT(s));
if (s->reset_cpu_usage) {
(void) unit_reset_cpu_usage(UNIT(s));
@@ -1213,7 +1215,7 @@ static int service_spawn(
if (r < 0)
return r;
- if (pass_fds ||
+ if ((flags & EXEC_PASS_FDS) ||
s->exec_context.std_input == EXEC_INPUT_SOCKET ||
s->exec_context.std_output == EXEC_OUTPUT_SOCKET ||
s->exec_context.std_error == EXEC_OUTPUT_SOCKET) {
@@ -1233,11 +1235,11 @@ static int service_spawn(
if (r < 0)
return r;
- our_env = new0(char*, 6);
+ our_env = new0(char*, 9);
if (!our_env)
return -ENOMEM;
- if (is_control ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE)
+ if ((flags & EXEC_IS_CONTROL) ? s->notify_access == NOTIFY_ALL : s->notify_access != NOTIFY_NONE)
if (asprintf(our_env + n_env++, "NOTIFY_SOCKET=%s", UNIT(s)->manager->notify_socket) < 0)
return -ENOMEM;
@@ -1245,7 +1247,7 @@ static int service_spawn(
if (asprintf(our_env + n_env++, "MAINPID="PID_FMT, s->main_pid) < 0)
return -ENOMEM;
- if (!MANAGER_IS_SYSTEM(UNIT(s)->manager))
+ if (MANAGER_IS_USER(UNIT(s)->manager))
if (asprintf(our_env + n_env++, "MANAGERPID="PID_FMT, getpid()) < 0)
return -ENOMEM;
@@ -1281,22 +1283,40 @@ static int service_spawn(
}
}
+ if (flags & EXEC_SETENV_RESULT) {
+ if (asprintf(our_env + n_env++, "SERVICE_RESULT=%s", service_result_to_string(s->result)) < 0)
+ return -ENOMEM;
+
+ if (s->main_exec_status.pid > 0 &&
+ dual_timestamp_is_set(&s->main_exec_status.exit_timestamp)) {
+ if (asprintf(our_env + n_env++, "EXIT_CODE=%s", sigchld_code_to_string(s->main_exec_status.code)) < 0)
+ return -ENOMEM;
+
+ if (s->main_exec_status.code == CLD_EXITED)
+ r = asprintf(our_env + n_env++, "EXIT_STATUS=%i", s->main_exec_status.status);
+ else
+ r = asprintf(our_env + n_env++, "EXIT_STATUS=%s", signal_to_string(s->main_exec_status.status));
+ if (r < 0)
+ return -ENOMEM;
+ }
+ }
+
final_env = strv_env_merge(2, UNIT(s)->manager->environment, our_env, NULL);
if (!final_env)
return -ENOMEM;
- if (is_control && UNIT(s)->cgroup_path) {
+ if ((flags & EXEC_IS_CONTROL) && UNIT(s)->cgroup_path) {
path = strjoina(UNIT(s)->cgroup_path, "/control");
(void) cg_create(SYSTEMD_CGROUP_CONTROLLER, path);
} else
path = UNIT(s)->cgroup_path;
exec_params.argv = argv;
+ exec_params.environment = final_env;
exec_params.fds = fds;
exec_params.fd_names = fd_names;
exec_params.n_fds = n_fds;
- exec_params.environment = final_env;
- exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
+ exec_params.flags |= UNIT(s)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
exec_params.cgroup_path = path;
exec_params.cgroup_delegate = s->cgroup_context.delegate;
@@ -1422,7 +1442,7 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
int r;
assert(s);
- if (f != SERVICE_SUCCESS)
+ if (s->result == SERVICE_SUCCESS)
s->result = f;
service_set_state(s, s->result != SERVICE_SUCCESS ? SERVICE_FAILED : SERVICE_DEAD);
@@ -1471,7 +1491,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
int r;
assert(s);
- if (f != SERVICE_SUCCESS)
+ if (s->result == SERVICE_SUCCESS)
s->result = f;
service_unwatch_control_pid(s);
@@ -1484,11 +1504,7 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
r = service_spawn(s,
s->control_command,
s->timeout_stop_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- true,
- true,
+ EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
&s->control_pid);
if (r < 0)
goto fail;
@@ -1528,7 +1544,7 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
assert(s);
- if (f != SERVICE_SUCCESS)
+ if (s->result == SERVICE_SUCCESS)
s->result = f;
unit_watch_all_pids(UNIT(s));
@@ -1586,7 +1602,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
assert(s);
- if (f != SERVICE_SUCCESS)
+ if (s->result == SERVICE_SUCCESS)
s->result = f;
service_unwatch_control_pid(s);
@@ -1599,11 +1615,7 @@ static void service_enter_stop(Service *s, ServiceResult f) {
r = service_spawn(s,
s->control_command,
s->timeout_stop_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- true,
+ EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_SETENV_RESULT,
&s->control_pid);
if (r < 0)
goto fail;
@@ -1642,7 +1654,7 @@ static bool service_good(Service *s) {
static void service_enter_running(Service *s, ServiceResult f) {
assert(s);
- if (f != SERVICE_SUCCESS)
+ if (s->result == SERVICE_SUCCESS)
s->result = f;
service_unwatch_control_pid(s);
@@ -1680,11 +1692,7 @@ static void service_enter_start_post(Service *s) {
r = service_spawn(s,
s->control_command,
s->timeout_start_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- true,
+ EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
&s->control_pid);
if (r < 0)
goto fail;
@@ -1754,11 +1762,7 @@ static void service_enter_start(Service *s) {
r = service_spawn(s,
c,
timeout,
- true,
- true,
- true,
- true,
- false,
+ EXEC_PASS_FDS|EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
&pid);
if (r < 0)
goto fail;
@@ -1817,11 +1821,7 @@ static void service_enter_start_pre(Service *s) {
r = service_spawn(s,
s->control_command,
s->timeout_start_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- true,
- true,
+ EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN,
&s->control_pid);
if (r < 0)
goto fail;
@@ -1896,11 +1896,7 @@ static void service_enter_reload(Service *s) {
r = service_spawn(s,
s->control_command,
s->timeout_start_usec,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- false,
- true,
+ EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL,
&s->control_pid);
if (r < 0)
goto fail;
@@ -1938,12 +1934,9 @@ static void service_run_next_control(Service *s) {
r = service_spawn(s,
s->control_command,
timeout,
- false,
- !s->permissions_start_only,
- !s->root_directory_start_only,
- s->control_command_id == SERVICE_EXEC_START_PRE ||
- s->control_command_id == SERVICE_EXEC_STOP_POST,
- true,
+ EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|
+ (IN_SET(s->control_command_id, SERVICE_EXEC_START_PRE, SERVICE_EXEC_STOP_POST) ? EXEC_APPLY_TTY_STDIN : 0)|
+ (IN_SET(s->control_command_id, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST) ? EXEC_SETENV_RESULT : 0),
&s->control_pid);
if (r < 0)
goto fail;
@@ -1981,11 +1974,7 @@ static void service_run_next_main(Service *s) {
r = service_spawn(s,
s->main_command,
s->timeout_start_usec,
- true,
- true,
- true,
- true,
- false,
+ EXEC_PASS_FDS|EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG,
&pid);
if (r < 0)
goto fail;
@@ -2656,7 +2645,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
"EXIT_STATUS=%i", status,
NULL);
- if (f != SERVICE_SUCCESS)
+ if (s->result == SERVICE_SUCCESS)
s->result = f;
if (s->main_command &&
@@ -2737,7 +2726,7 @@ static void service_sigchld_event(Unit *u, pid_t pid, int code, int status) {
"Control process exited, code=%s status=%i",
sigchld_code_to_string(code), status);
- if (f != SERVICE_SUCCESS)
+ if (s->result == SERVICE_SUCCESS)
s->result = f;
/* Immediately get rid of the cgroup, so that the
diff --git a/src/core/socket.c b/src/core/socket.c
index 7f3f154a16..50872e8366 100644
--- a/src/core/socket.c
+++ b/src/core/socket.c
@@ -1749,12 +1749,10 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
pid_t pid;
int r;
ExecParameters exec_params = {
- .apply_permissions = true,
- .apply_chroot = true,
- .apply_tty_stdin = true,
- .stdin_fd = -1,
- .stdout_fd = -1,
- .stderr_fd = -1,
+ .flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(s);
@@ -1785,7 +1783,7 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) {
exec_params.argv = argv;
exec_params.environment = UNIT(s)->manager->environment;
- exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
+ exec_params.flags |= UNIT(s)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
exec_params.cgroup_path = UNIT(s)->cgroup_path;
exec_params.cgroup_delegate = s->cgroup_context.delegate;
@@ -1897,7 +1895,7 @@ fail:
static void socket_enter_dead(Socket *s, SocketResult f) {
assert(s);
- if (f != SOCKET_SUCCESS)
+ if (s->result == SOCKET_SUCCESS)
s->result = f;
socket_set_state(s, s->result != SOCKET_SUCCESS ? SOCKET_FAILED : SOCKET_DEAD);
@@ -1916,7 +1914,7 @@ static void socket_enter_stop_post(Socket *s, SocketResult f) {
int r;
assert(s);
- if (f != SOCKET_SUCCESS)
+ if (s->result == SOCKET_SUCCESS)
s->result = f;
socket_unwatch_control_pid(s);
@@ -1944,7 +1942,7 @@ static void socket_enter_signal(Socket *s, SocketState state, SocketResult f) {
assert(s);
- if (f != SOCKET_SUCCESS)
+ if (s->result == SOCKET_SUCCESS)
s->result = f;
r = unit_kill_context(
@@ -1988,7 +1986,7 @@ static void socket_enter_stop_pre(Socket *s, SocketResult f) {
int r;
assert(s);
- if (f != SOCKET_SUCCESS)
+ if (s->result == SOCKET_SUCCESS)
s->result = f;
socket_unwatch_control_pid(s);
@@ -2770,7 +2768,7 @@ static void socket_sigchld_event(Unit *u, pid_t pid, int code, int status) {
"Control process exited, code=%s status=%i",
sigchld_code_to_string(code), status);
- if (f != SOCKET_SUCCESS)
+ if (s->result == SOCKET_SUCCESS)
s->result = f;
if (s->control_command &&
diff --git a/src/core/swap.c b/src/core/swap.c
index 66a318d01f..2c802da3b5 100644
--- a/src/core/swap.c
+++ b/src/core/swap.c
@@ -611,12 +611,10 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
pid_t pid;
int r;
ExecParameters exec_params = {
- .apply_permissions = true,
- .apply_chroot = true,
- .apply_tty_stdin = true,
- .stdin_fd = -1,
- .stdout_fd = -1,
- .stderr_fd = -1,
+ .flags = EXEC_APPLY_PERMISSIONS|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN,
+ .stdin_fd = -1,
+ .stdout_fd = -1,
+ .stderr_fd = -1,
};
assert(s);
@@ -642,7 +640,7 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) {
goto fail;
exec_params.environment = UNIT(s)->manager->environment;
- exec_params.confirm_spawn = UNIT(s)->manager->confirm_spawn;
+ exec_params.flags |= UNIT(s)->manager->confirm_spawn ? EXEC_CONFIRM_SPAWN : 0;
exec_params.cgroup_supported = UNIT(s)->manager->cgroup_supported;
exec_params.cgroup_path = UNIT(s)->cgroup_path;
exec_params.cgroup_delegate = s->cgroup_context.delegate;
@@ -675,7 +673,7 @@ fail:
static void swap_enter_dead(Swap *s, SwapResult f) {
assert(s);
- if (f != SWAP_SUCCESS)
+ if (s->result == SWAP_SUCCESS)
s->result = f;
swap_set_state(s, s->result != SWAP_SUCCESS ? SWAP_FAILED : SWAP_DEAD);
@@ -691,7 +689,7 @@ static void swap_enter_dead(Swap *s, SwapResult f) {
static void swap_enter_active(Swap *s, SwapResult f) {
assert(s);
- if (f != SWAP_SUCCESS)
+ if (s->result == SWAP_SUCCESS)
s->result = f;
swap_set_state(s, SWAP_ACTIVE);
@@ -702,7 +700,7 @@ static void swap_enter_signal(Swap *s, SwapState state, SwapResult f) {
assert(s);
- if (f != SWAP_SUCCESS)
+ if (s->result == SWAP_SUCCESS)
s->result = f;
r = unit_kill_context(
@@ -999,7 +997,7 @@ static void swap_sigchld_event(Unit *u, pid_t pid, int code, int status) {
else
assert_not_reached("Unknown code");
- if (f != SWAP_SUCCESS)
+ if (s->result == SWAP_SUCCESS)
s->result = f;
if (s->control_command) {
diff --git a/src/core/timer.c b/src/core/timer.c
index 3206296f09..e2b43f02f8 100644
--- a/src/core/timer.c
+++ b/src/core/timer.c
@@ -291,7 +291,7 @@ static int timer_coldplug(Unit *u) {
static void timer_enter_dead(Timer *t, TimerResult f) {
assert(t);
- if (f != TIMER_SUCCESS)
+ if (t->result == TIMER_SUCCESS)
t->result = f;
timer_set_state(t, t->result != TIMER_SUCCESS ? TIMER_FAILED : TIMER_DEAD);
diff --git a/src/coredump/coredump.c b/src/coredump/coredump.c
index e3d17c864d..be724aed4e 100644
--- a/src/coredump/coredump.c
+++ b/src/coredump/coredump.c
@@ -327,9 +327,11 @@ static int save_external_coredump(
r = safe_atou64(context[CONTEXT_RLIMIT], &rlimit);
if (r < 0)
return log_error_errno(r, "Failed to parse resource limit: %s", context[CONTEXT_RLIMIT]);
- if (rlimit <= 0) {
- /* Is coredumping disabled? Then don't bother saving/processing the coredump */
- log_info("Core Dumping has been disabled for process %s (%s).", context[CONTEXT_PID], context[CONTEXT_COMM]);
+ if (rlimit < page_size()) {
+ /* Is coredumping disabled? Then don't bother saving/processing the coredump.
+ * Anything below PAGE_SIZE cannot give a readable coredump (the kernel uses
+ * ELF_EXEC_PAGESIZE which is not easily accessible, but is usually the same as PAGE_SIZE. */
+ log_info("Core dumping has been disabled for process %s (%s).", context[CONTEXT_PID], context[CONTEXT_COMM]);
return -EBADSLT;
}
diff --git a/src/coredump/coredumpctl.c b/src/coredump/coredumpctl.c
index 27b1e0fb3f..bbf8793e57 100644
--- a/src/coredump/coredumpctl.c
+++ b/src/coredump/coredumpctl.c
@@ -30,6 +30,7 @@
#include "compress.h"
#include "fd-util.h"
#include "fileio.h"
+#include "fs-util.h"
#include "journal-internal.h"
#include "log.h"
#include "macro.h"
@@ -609,7 +610,13 @@ static int save_core(sd_journal *j, int fd, char **path, bool *unlink_temp) {
char *temp = NULL;
if (fd < 0) {
- temp = strdup("/var/tmp/coredump-XXXXXX");
+ const char *vt;
+
+ r = var_tmp_dir(&vt);
+ if (r < 0)
+ return log_error_errno(r, "Failed to acquire temporary directory path: %m");
+
+ temp = strjoin(vt, "/coredump-XXXXXX", NULL);
if (!temp)
return log_oom();
diff --git a/src/journal-remote/journal-gatewayd.c b/src/journal-remote/journal-gatewayd.c
index a1627fab39..c2b5a5f205 100644
--- a/src/journal-remote/journal-gatewayd.c
+++ b/src/journal-remote/journal-gatewayd.c
@@ -45,6 +45,7 @@
static char *arg_key_pem = NULL;
static char *arg_cert_pem = NULL;
static char *arg_trust_pem = NULL;
+static char *arg_directory = NULL;
typedef struct RequestMeta {
sd_journal *journal;
@@ -115,7 +116,10 @@ static int open_journal(RequestMeta *m) {
if (m->journal)
return 0;
- return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM);
+ if (arg_directory)
+ return sd_journal_open_directory(&m->journal, arg_directory, 0);
+ else
+ return sd_journal_open(&m->journal, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM);
}
static int request_meta_ensure_tmp(RequestMeta *m) {
@@ -236,6 +240,9 @@ static ssize_t request_reader_entries(
m->size = (uint64_t) sz;
}
+ if (m->tmp == NULL && m->follow)
+ return 0;
+
if (fseeko(m->tmp, pos, SEEK_SET) < 0) {
log_error_errno(errno, "Failed to seek to position: %m");
return MHD_CONTENT_READER_END_WITH_ERROR;
@@ -878,7 +885,8 @@ static void help(void) {
" --version Show package version\n"
" --cert=CERT.PEM Server certificate in PEM format\n"
" --key=KEY.PEM Server key in PEM format\n"
- " --trust=CERT.PEM Certificat authority certificate in PEM format\n",
+ " --trust=CERT.PEM Certificate authority certificate in PEM format\n"
+ " -D --directory=PATH Serve journal files in directory\n",
program_invocation_short_name);
}
@@ -893,11 +901,12 @@ static int parse_argv(int argc, char *argv[]) {
int r, c;
static const struct option options[] = {
- { "help", no_argument, NULL, 'h' },
- { "version", no_argument, NULL, ARG_VERSION },
- { "key", required_argument, NULL, ARG_KEY },
- { "cert", required_argument, NULL, ARG_CERT },
- { "trust", required_argument, NULL, ARG_TRUST },
+ { "help", no_argument, NULL, 'h' },
+ { "version", no_argument, NULL, ARG_VERSION },
+ { "key", required_argument, NULL, ARG_KEY },
+ { "cert", required_argument, NULL, ARG_CERT },
+ { "trust", required_argument, NULL, ARG_TRUST },
+ { "directory", required_argument, NULL, 'D' },
{}
};
@@ -951,6 +960,9 @@ static int parse_argv(int argc, char *argv[]) {
#else
log_error("Option --trust is not available.");
#endif
+ case 'D':
+ arg_directory = optarg;
+ break;
case '?':
return -EINVAL;
diff --git a/src/journal/journal-verify.c b/src/journal/journal-verify.c
index f61f158e8a..4105abfccc 100644
--- a/src/journal/journal-verify.c
+++ b/src/journal/journal-verify.c
@@ -826,7 +826,7 @@ int journal_file_verify(
int data_fd = -1, entry_fd = -1, entry_array_fd = -1;
unsigned i;
bool found_last = false;
- _cleanup_free_ char *tmp_dir = NULL;
+ const char *tmp_dir = NULL;
#ifdef HAVE_GCRYPT
uint64_t last_tag = 0;
@@ -846,7 +846,7 @@ int journal_file_verify(
} else if (f->seal)
return -ENOKEY;
- r = var_tmp(&tmp_dir);
+ r = var_tmp_dir(&tmp_dir);
if (r < 0) {
log_error_errno(r, "Failed to determine temporary directory: %m");
goto fail;
diff --git a/src/journal/lookup3.c b/src/journal/lookup3.c
index 3d791234f4..d8f1a4977d 100644
--- a/src/journal/lookup3.c
+++ b/src/journal/lookup3.c
@@ -317,7 +317,7 @@ uint32_t jenkins_hashlittle( const void *key, size_t length, uint32_t initval)
* still catch it and complain. The masking trick does make the hash
* noticeably faster for short strings (like English words).
*/
-#ifndef VALGRIND
+#if !defined(VALGRIND) && !defined(__SANITIZE_ADDRESS__)
switch(length)
{
@@ -503,7 +503,7 @@ void jenkins_hashlittle2(
* still catch it and complain. The masking trick does make the hash
* noticeably faster for short strings (like English words).
*/
-#ifndef VALGRIND
+#if !defined(VALGRIND) && !defined(__SANITIZE_ADDRESS__)
switch(length)
{
@@ -681,7 +681,7 @@ uint32_t jenkins_hashbig( const void *key, size_t length, uint32_t initval)
* still catch it and complain. The masking trick does make the hash
* noticeably faster for short strings (like English words).
*/
-#ifndef VALGRIND
+#if !defined(VALGRIND) && !defined(__SANITIZE_ADDRESS__)
switch(length)
{
diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c
index 75a0ffb49b..2a3824d0e8 100644
--- a/src/journal/sd-journal.c
+++ b/src/journal/sd-journal.c
@@ -2290,6 +2290,8 @@ _public_ int sd_journal_get_fd(sd_journal *j) {
* inotify */
if (j->no_new_files)
r = add_current_paths(j);
+ else if (j->flags & SD_JOURNAL_OS_ROOT)
+ r = add_search_paths(j);
else if (j->toplevel_fd >= 0)
r = add_root_directory(j, NULL, false);
else if (j->path)
diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c
index 1923e8b971..5e2462cba2 100644
--- a/src/machine/machined-dbus.c
+++ b/src/machine/machined-dbus.c
@@ -954,7 +954,7 @@ static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_err
/* Create a temporary file we can dump information about deleted images into. We use a temporary file for this
* instead of a pipe or so, since this might grow quit large in theory and we don't want to process this
* continuously */
- result_fd = open_tmpfile_unlinkable("/tmp/", O_RDWR|O_CLOEXEC);
+ result_fd = open_tmpfile_unlinkable(NULL, O_RDWR|O_CLOEXEC);
if (result_fd < 0)
return -errno;
diff --git a/src/network/networkd-netdev-bridge.c b/src/network/networkd-netdev-bridge.c
index a5085d2b19..12b0fe972f 100644
--- a/src/network/networkd-netdev-bridge.c
+++ b/src/network/networkd-netdev-bridge.c
@@ -108,6 +108,12 @@ static int netdev_bridge_post_create(NetDev *netdev, Link *link, sd_netlink_mess
return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_VLAN_FILTERING attribute: %m");
}
+ if (b->stp >= 0) {
+ r = sd_netlink_message_append_u32(req, IFLA_BR_STP_STATE, b->stp);
+ if (r < 0)
+ return log_netdev_error_errno(netdev, r, "Could not append IFLA_BR_STP_STATE attribute: %m");
+ }
+
r = sd_netlink_message_close_container(req);
if (r < 0)
return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
@@ -135,6 +141,7 @@ static void bridge_init(NetDev *n) {
b->mcast_querier = -1;
b->mcast_snooping = -1;
b->vlan_filtering = -1;
+ b->stp = -1;
}
const NetDevVTable bridge_vtable = {
diff --git a/src/network/networkd-netdev-bridge.h b/src/network/networkd-netdev-bridge.h
index a637aea0a3..4ce0fbb6f9 100644
--- a/src/network/networkd-netdev-bridge.h
+++ b/src/network/networkd-netdev-bridge.h
@@ -27,6 +27,7 @@ typedef struct Bridge {
int mcast_querier;
int mcast_snooping;
int vlan_filtering;
+ int stp;
usec_t forward_delay;
usec_t hello_time;
diff --git a/src/network/networkd-netdev-gperf.gperf b/src/network/networkd-netdev-gperf.gperf
index 9d69f61376..a1ca1a3d4e 100644
--- a/src/network/networkd-netdev-gperf.gperf
+++ b/src/network/networkd-netdev-gperf.gperf
@@ -106,4 +106,5 @@ Bridge.ForwardDelaySec, config_parse_sec, 0,
Bridge.MulticastQuerier, config_parse_tristate, 0, offsetof(Bridge, mcast_querier)
Bridge.MulticastSnooping, config_parse_tristate, 0, offsetof(Bridge, mcast_snooping)
Bridge.VLANFiltering, config_parse_tristate, 0, offsetof(Bridge, vlan_filtering)
+Bridge.STP, config_parse_tristate, 0, offsetof(Bridge, stp)
VRF.TableId, config_parse_uint32, 0, offsetof(Vrf, table_id)
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index 17bbe5de9f..49faba5b12 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -395,10 +395,8 @@ int network_apply(Manager *manager, Network *network, Link *link) {
if (!strv_isempty(network->dns) ||
!strv_isempty(network->ntp) ||
!strv_isempty(network->search_domains) ||
- !strv_isempty(network->route_domains)) {
- manager_dirty(manager);
+ !strv_isempty(network->route_domains))
link_dirty(link);
- }
return 0;
}
diff --git a/src/nss-systemd/nss-systemd.c b/src/nss-systemd/nss-systemd.c
index e7a4393bb0..7078c0c50c 100644
--- a/src/nss-systemd/nss-systemd.c
+++ b/src/nss-systemd/nss-systemd.c
@@ -26,9 +26,52 @@
#include "macro.h"
#include "nss-util.h"
#include "signal-util.h"
+#include "string-util.h"
#include "user-util.h"
#include "util.h"
+#ifndef NOBODY_USER_NAME
+#define NOBODY_USER_NAME "nobody"
+#endif
+
+#ifndef NOBODY_GROUP_NAME
+#define NOBODY_GROUP_NAME "nobody"
+#endif
+
+static const struct passwd root_passwd = {
+ .pw_name = (char*) "root",
+ .pw_passwd = (char*) "x", /* see shadow file */
+ .pw_uid = 0,
+ .pw_gid = 0,
+ .pw_gecos = (char*) "Super User",
+ .pw_dir = (char*) "/root",
+ .pw_shell = (char*) "/bin/sh",
+};
+
+static const struct passwd nobody_passwd = {
+ .pw_name = (char*) NOBODY_USER_NAME,
+ .pw_passwd = (char*) "*", /* locked */
+ .pw_uid = 65534,
+ .pw_gid = 65534,
+ .pw_gecos = (char*) "User Nobody",
+ .pw_dir = (char*) "/",
+ .pw_shell = (char*) "/sbin/nologin",
+};
+
+static const struct group root_group = {
+ .gr_name = (char*) "root",
+ .gr_gid = 0,
+ .gr_passwd = (char*) "x", /* see shadow file */
+ .gr_mem = (char*[]) { NULL },
+};
+
+static const struct group nobody_group = {
+ .gr_name = (char*) NOBODY_GROUP_NAME,
+ .gr_gid = 65534,
+ .gr_passwd = (char*) "*", /* locked */
+ .gr_mem = (char*[]) { NULL },
+};
+
NSS_GETPW_PROTOTYPES(systemd);
NSS_GETGR_PROTOTYPES(systemd);
@@ -50,6 +93,23 @@ enum nss_status _nss_systemd_getpwnam_r(
assert(name);
assert(pwd);
+ if (!valid_user_group_name(name)) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ /* Synthesize entries for the root and nobody users, in case they are missing in /etc/passwd */
+ if (streq(name, root_passwd.pw_name)) {
+ *pwd = root_passwd;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+ if (streq(name, nobody_passwd.pw_name)) {
+ *pwd = nobody_passwd;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+
/* Make sure that we don't go in circles when allocating a dynamic UID by checking our own database */
if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
goto not_found;
@@ -126,6 +186,18 @@ enum nss_status _nss_systemd_getpwuid_r(
goto fail;
}
+ /* Synthesize data for the root user and for nobody in case they are missing from /etc/passwd */
+ if (uid == root_passwd.pw_uid) {
+ *pwd = root_passwd;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+ if (uid == nobody_passwd.pw_uid) {
+ *pwd = nobody_passwd;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+
if (uid <= SYSTEM_UID_MAX)
goto not_found;
@@ -202,6 +274,23 @@ enum nss_status _nss_systemd_getgrnam_r(
assert(name);
assert(gr);
+ if (!valid_user_group_name(name)) {
+ r = -EINVAL;
+ goto fail;
+ }
+
+ /* Synthesize records for root and nobody, in case they are missing form /etc/group */
+ if (streq(name, root_group.gr_name)) {
+ *gr = root_group;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+ if (streq(name, nobody_group.gr_name)) {
+ *gr = nobody_group;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+
if (getenv_bool("SYSTEMD_NSS_DYNAMIC_BYPASS") > 0)
goto not_found;
@@ -275,6 +364,18 @@ enum nss_status _nss_systemd_getgrgid_r(
goto fail;
}
+ /* Synthesize records for root and nobody, in case they are missing from /etc/group */
+ if (gid == root_group.gr_gid) {
+ *gr = root_group;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+ if (gid == nobody_group.gr_gid) {
+ *gr = nobody_group;
+ *errnop = 0;
+ return NSS_STATUS_SUCCESS;
+ }
+
if (gid <= SYSTEM_GID_MAX)
goto not_found;
diff --git a/src/shared/bus-unit-util.c b/src/shared/bus-unit-util.c
index bb98951a06..f9e12e0578 100644
--- a/src/shared/bus-unit-util.c
+++ b/src/shared/bus-unit-util.c
@@ -202,7 +202,7 @@ int bus_append_unit_property_assignment(sd_bus_message *m, const char *assignmen
"CPUAccounting", "MemoryAccounting", "IOAccounting", "BlockIOAccounting", "TasksAccounting",
"SendSIGHUP", "SendSIGKILL", "WakeSystem", "DefaultDependencies",
"IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "RemainAfterExit",
- "PrivateTmp", "PrivateDevices", "PrivateNetwork", "NoNewPrivileges",
+ "PrivateTmp", "PrivateDevices", "PrivateNetwork", "PrivateUsers", "NoNewPrivileges",
"SyslogLevelPrefix", "Delegate", "RemainAfterElapse", "MemoryDenyWriteExecute",
"RestrictRealtime", "DynamicUser")) {
diff --git a/src/shared/install.c b/src/shared/install.c
index 7b49e1ece9..e740ef3910 100644
--- a/src/shared/install.c
+++ b/src/shared/install.c
@@ -777,7 +777,7 @@ static int find_symlinks(
assert(config_path);
assert(same_name_link);
- fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC|O_NOFOLLOW);
+ fd = open(config_path, O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC);
if (fd < 0) {
if (IN_SET(errno, ENOENT, ENOTDIR, EACCES))
return 0;
diff --git a/src/test/test-fs-util.c b/src/test/test-fs-util.c
index e0c040f39b..93eec3ef9c 100644
--- a/src/test/test-fs-util.c
+++ b/src/test/test-fs-util.c
@@ -83,47 +83,35 @@ static void test_get_files_in_directory(void) {
}
static void test_var_tmp(void) {
- char *tmp_dir = NULL;
- char *tmpdir_backup = NULL;
- const char *default_var_tmp = NULL;
- const char *var_name;
- bool do_overwrite = true;
-
- default_var_tmp = "/var/tmp";
- var_name = "TMPDIR";
-
- if (getenv(var_name) != NULL) {
- tmpdir_backup = strdup(getenv(var_name));
- assert_se(tmpdir_backup != NULL);
- }
-
- unsetenv(var_name);
+ _cleanup_free_ char *tmpdir_backup = NULL;
+ const char *tmp_dir = NULL, *t;
- var_tmp(&tmp_dir);
- assert_se(!strcmp(tmp_dir, default_var_tmp));
-
- free(tmp_dir);
+ t = getenv("TMPDIR");
+ if (t) {
+ tmpdir_backup = strdup(t);
+ assert_se(tmpdir_backup);
+ }
- setenv(var_name, "/tmp", do_overwrite);
- assert_se(!strcmp(getenv(var_name), "/tmp"));
+ assert(unsetenv("TMPDIR") >= 0);
- var_tmp(&tmp_dir);
- assert_se(!strcmp(tmp_dir, "/tmp"));
+ assert_se(var_tmp_dir(&tmp_dir) >= 0);
+ assert_se(streq(tmp_dir, "/var/tmp"));
- free(tmp_dir);
+ assert_se(setenv("TMPDIR", "/tmp", true) >= 0);
+ assert_se(streq(getenv("TMPDIR"), "/tmp"));
- setenv(var_name, "/88_does_not_exist_88", do_overwrite);
- assert_se(!strcmp(getenv(var_name), "/88_does_not_exist_88"));
+ assert_se(var_tmp_dir(&tmp_dir) >= 0);
+ assert_se(streq(tmp_dir, "/tmp"));
- var_tmp(&tmp_dir);
- assert_se(!strcmp(tmp_dir, default_var_tmp));
+ assert_se(setenv("TMPDIR", "/88_does_not_exist_88", true) >= 0);
+ assert_se(streq(getenv("TMPDIR"), "/88_does_not_exist_88"));
- free(tmp_dir);
+ assert_se(var_tmp_dir(&tmp_dir) >= 0);
+ assert_se(streq(tmp_dir, "/var/tmp"));
- if (tmpdir_backup != NULL) {
- setenv(var_name, tmpdir_backup, do_overwrite);
- assert_se(!strcmp(getenv(var_name), tmpdir_backup));
- free(tmpdir_backup);
+ if (tmpdir_backup) {
+ assert_se(setenv("TMPDIR", tmpdir_backup, true) >= 0);
+ assert_se(streq(getenv("TMPDIR"), tmpdir_backup));
}
}
diff --git a/src/test/test-id128.c b/src/test/test-id128.c
index f01fbdd6b2..1c8e5549da 100644
--- a/src/test/test-id128.c
+++ b/src/test/test-id128.c
@@ -144,7 +144,7 @@ int main(int argc, char *argv[]) {
assert_se(ftruncate(fd, 0) >= 0);
assert_se(sd_id128_randomize(&id) >= 0);
- assert_se(write(fd, id128_to_uuid_string(id, t), 36) == 36);
+ assert_se(write(fd, id128_to_uuid_string(id, q), 36) == 36);
assert_se(lseek(fd, 0, SEEK_SET) == 0);
assert_se(id128_read_fd(fd, ID128_PLAIN, &id2) == -EINVAL);
diff --git a/src/test/test-sigbus.c b/src/test/test-sigbus.c
index 17b81747be..02b8e24308 100644
--- a/src/test/test-sigbus.c
+++ b/src/test/test-sigbus.c
@@ -29,6 +29,9 @@ int main(int argc, char *argv[]) {
void *addr = NULL;
uint8_t *p;
+#ifdef __SANITIZE_ADDRESS__
+ return EXIT_TEST_SKIP;
+#endif
sigbus_install();
assert_se(sigbus_pop(&addr) == 0);
diff --git a/units/systemd-random-seed.service.in b/units/systemd-random-seed.service.in
index 115233268d..b244a8ce43 100644
--- a/units/systemd-random-seed.service.in
+++ b/units/systemd-random-seed.service.in
@@ -13,6 +13,7 @@ RequiresMountsFor=@RANDOM_SEED@
Conflicts=shutdown.target
After=systemd-remount-fs.service
Before=sysinit.target shutdown.target
+ConditionVirtualization=!container
[Service]
Type=oneshot