create_container() {
# Create autopkgtest LXC image; this sometimes fails with "Unable to fetch
# GPG key from keyserver", so retry a few times with different keyservers.
- for keyserver in "" "keys.gnupg.net" "keys.openpgp.org" "keyserver.ubuntu.com"; do
+ for keyserver in "keys.openpgp.org" "" "keyserver.ubuntu.com" "keys.gnupg.net"; do
for retry in {1..5}; do
sudo lxc-create -n "$CONTAINER" -t download -- -d "$DISTRO" -r "$RELEASE" -a "$ARCH" ${keyserver:+--keyserver "$keyserver"} && break 2
sleep $((retry*retry))
# enable source repositories so that apt-get build-dep works
sudo lxc-attach -n "$CONTAINER" -- sh -ex <<EOF
sed 's/^deb/deb-src/' /etc/apt/sources.list >> /etc/apt/sources.list.d/sources.list
-# wait until online
-while [ -z "\$(ip route list 0/0)" ]; do sleep 1; done
+# We might attach the console too soon
+while ! systemctl --quiet --wait is-system-running; do sleep 1; done
+# Manpages database trigger takes a lot of time and is not useful in a CI
+echo 'man-db man-db/auto-update boolean false' | debconf-set-selections
+# Speed up dpkg, image is thrown away after the test
+mkdir -p /etc/dpkg/dpkg.cfg.d/
+echo 'force-unsafe-io' > /etc/dpkg/dpkg.cfg.d/unsafe_io
+# For some reason, it is necessary to run this manually or the interface won't be configured
+# Note that we avoid networkd, as some of the tests will break it later on
+dhclient
apt-get -q --allow-releaseinfo-change update
apt-get -y dist-upgrade
apt-get install -y eatmydata
rm -rf debian/patches
# disable autopkgtests which are not for upstream
sed -i '/# NOUPSTREAM/ q' debian/tests/control
+ # TODO: rebooting via autopkgtest-reboot seems to be broken, disable these tests for now
+ sed -i -n '1,/Tests: boot-and-services/p;/Tests: udev/,$p' debian/tests/control
+ sed -i '/Tests: boot-and-services/d' debian/tests/control
+ sed -i '/Tests: boot-smoke/,$d' debian/tests/control
# enable more unit tests
sed -i '/^CONFFLAGS =/ s/=/= --werror -Dtests=unsafe -Dsplit-usr=true -Dslow-tests=true -Dfuzz-tests=true -Dman=true /' debian/rules
# no orig tarball
agent:
machine:
type: e1-standard-2
- os_image: ubuntu1804
+ os_image: ubuntu2004
# Cancel any running or queued job for the same ref
auto_cancel:
LGPL-2.1-or-later for all code, exceptions noted in LICENSES/README.md
REQUIREMENTS:
- Linux kernel >= 3.15
- Linux kernel >= 4.2 for unified cgroup hierarchy support
- Linux kernel >= 4.10 for cgroup-bpf egress and ingress hooks
- Linux kernel >= 4.15 for cgroup-bpf device hook
- Linux kernel >= 4.17 for cgroup-bpf socket address hooks
- Linux kernel >= 5.3 for bounded-loops in BPF program
- Linux kernel >= 5.4 for signed Verity images support
- Linux kernel >= 5.7 for BPF links and the BPF LSM hook
+ Linux kernel ≥ 3.15
+ ≥ 4.5 for pids controller in cgroup v2
+ ≥ 4.6 for cgroup namespaces
+ ≥ 4.9 for RENAME_NOREPLACE support in vfat
+ ≥ 4.10 for cgroup-bpf egress and ingress hooks
+ ≥ 4.15 for cgroup-bpf device hook and cpu controller in cgroup v2
+ ≥ 4.17 for cgroup-bpf socket address hooks
+ ≥ 5.3 for bounded loops in BPF program
+ ≥ 5.4 for signed Verity images
+ ≥ 5.7 for BPF links and the BPF LSM hook
+
+ Kernel versions below 4.15 have significant gaps in functionality and
+ are not recommended for use with this version of systemd. Taint flag
+ 'old-kernel' will be set. Systemd will most likely still function, but
+ upstream support and testing are limited.
Kernel Config Options:
CONFIG_DEVTMPFS
Please see src/systemctl/systemd-sysv-install.SKELETON for how this
needs to look like, and provide an implementation at the marked places.
-WARNINGS:
+WARNINGS and TAINT FLAGS:
systemd will warn during early boot if /usr is not already mounted at
this point (that means: either located on the same file system as / or
already mounted in the initrd). While in systemd itself very little
- will break if /usr is on a separate, late-mounted partition, many of
- its dependencies very likely will break sooner or later in one form or
+ will break if /usr is on a separate late-mounted partition, many of its
+ dependencies very likely will break sooner or later in one form or
another. For example, udev rules tend to refer to binaries in /usr,
binaries that link to libraries in /usr or binaries that refer to data
files in /usr. Since these breakages are not always directly visible,
- systemd will warn about this, since this kind of file system setup is
- not really supported anymore by the basic set of Linux OS components.
-
- systemd requires that the /run mount point exists. systemd also
- requires that /var/run is a symlink to /run.
+ systemd will warn about this. Such setups are not really supported by
+ the basic set of Linux OS components. Taint flag 'split-usr' will be
+ set when this condition is detected.
For more information on this issue consult
https://www.freedesktop.org/wiki/Software/systemd/separate-usr-is-broken
+ systemd requires that the /run mount point exists. systemd also
+ requires that /var/run is a symlink to /run. Taint flag 'var-run-bad'
+ will be set when this condition is detected.
+
+ Systemd will also warn when the cgroup support is unavailable in the
+ kernel (taint flag 'cgroups-missing'), the system is using the old
+ cgroup hierarchy (taint flag 'cgroupsv1'), the hardware clock is
+ running in non-UTC mode (taint flag 'local-hwclock'), the kernel
+ overflow UID or GID are not 65534 (taint flags 'overflowuid-not-65534'
+ and 'overflowgid-not-65534'), the UID or GID range assigned to the
+ running systemd instance covers less than 0…65534 (taint flags
+ 'short-uid-range' and 'short-gid-range').
+
+ Taint conditions are logged during boot, but may also be checked at any
+ time with:
+
+ busctl get-property org.freedesktop.systemd1 /org/freedesktop/systemd1 org.freedesktop.systemd1.Manager Tainted
+
+VALGRIND:
To run systemd under valgrind, compile with meson option
-Dvalgrind=true and have valgrind development headers installed
(i.e. valgrind-devel or equivalent). Otherwise, false positives will be
'README',
input : 'README.in',
output : 'README',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : conf.get('HAVE_SYSV_COMPAT') == 1,
install_dir : sysvinit_path)
'locale.conf',
input : 'locale.conf.in',
output : 'locale.conf',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : true,
install_dir : factory_etc_dir)
</varlistentry>
<xi:include href="standard-options.xml" xpointer="help" />
+ <xi:include href="standard-options.xml" xpointer="version" />
</variablelist>
</refsect1>
'custom-entities.ent',
input : 'custom-entities.ent.in',
output : 'custom-entities.ent',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'])
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'])
man_pages = []
html_pages = []
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><constant>v251</constant></term>
+
+ <listitem><para>Since version <constant>v247</constant> we no longer set
+ <varname>ID_NET_NAME_SLOT</varname> if we detect that a PCI device associated with a slot is a PCI
+ bridge as that would create naming conflict when there are more child devices on that bridge. Now,
+ this is relaxed and we will use slot information to generate the name based on it but only if
+ the PCI device has multiple functions. This is safe because distinct function number is a part of
+ the device name for multifunction devices.</para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
<para>Note that <constant>latest</constant> may be used to denote the latest scheme known (to this
add_project_arguments('-include', 'config.h', language : 'c')
+jinja2_cmdline = [meson_render_jinja2, config_h, version_h]
+
############################################################
# binaries that have --help and are intended for use by humans,
############################################################
-dbus_programs += executable(
+exe = executable(
'systemd',
systemd_sources,
include_directories : includes,
install_rpath : rootlibexecdir,
install : true,
install_dir : rootlibexecdir)
+dbus_programs += exe
+public_programs += exe
meson.add_install_script(meson_make_symlink,
rootlibexecdir / 'systemd',
install : true,
install_dir : systemgeneratordir)
- executable(
+ public_programs += executable(
'systemd-cryptenroll',
systemd_cryptenroll_sources,
include_directories : includes,
endif
if conf.get('ENABLE_FIRSTBOOT') == 1
- executable(
+ public_programs += executable(
'systemd-firstboot',
'src/firstboot/firstboot.c',
include_directories : includes,
install : true,
install_dir : rootlibexecdir)
- executable(
+ public_programs += executable(
'systemd-networkd-wait-online',
systemd_networkd_wait_online_sources,
include_directories : includes,
install : true,
install_dir : rootlibexecdir)
+public_programs += custom_target(
+ 'kernel-install',
+ input : kernel_install_in,
+ output : 'kernel-install',
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
+ install : want_kernel_install,
+ install_mode : 'rwxr-xr-x',
+ install_dir : bindir)
+
############################################################
runtest_env = custom_target(
############################################################
check_help = find_program('tools/check-help.sh')
+check_version = find_program('tools/check-version.sh')
foreach exec : public_programs
name = exec.full_path().split('/')[-1]
check_help,
args : exec.full_path(),
depends: exec)
+
+ test('check-version-' + name,
+ check_version,
+ args : [exec.full_path(),
+ meson.project_version()],
+ depends: exec)
endif
endforeach
file,
input : file + '.in',
output: file,
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : true,
install_dir : udevrulesdir)
endforeach
'systemctl',
input : 'systemctl.in',
output : 'systemctl',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : bashcompletiondir != 'no',
install_dir : bashcompletiondir)
'_systemctl',
input : '_systemctl.in',
output : '_systemctl',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : zshcompletiondir != 'no',
install_dir : zshcompletiondir)
/* Path where systemd-oomd listens for varlink connections from user managers to report changes in ManagedOOM settings. */
#define VARLINK_ADDR_PATH_MANAGED_OOM_USER "/run/systemd/oom/io.system.ManagedOOM"
-#define KERNEL_BASELINE_VERSION "3.15"
+#define KERNEL_BASELINE_VERSION "4.15"
" -h --help Show this help\n"
" --version Show version\n"
" --test Determine initial transaction, dump it and exit\n"
- " --system In combination with --test: operate as system service manager\n"
- " --user In combination with --test: operate as per-user service manager\n"
- " --no-pager Do not pipe output into a pager\n"
+ " --system Combined with --test: operate in system mode\n"
+ " --user Combined with --test: operate in user mode\n"
" --dump-configuration-items Dump understood unit configuration items\n"
" --dump-bus-properties Dump exposed bus properties\n"
" --bus-introspect=PATH Write XML introspection data\n"
" --crash-reboot[=BOOL] Reboot on crash\n"
" --crash-shell[=BOOL] Run shell on crash\n"
" --confirm-spawn[=BOOL] Ask for confirmation when spawning processes\n"
- " --show-status[=BOOL] Show status updates on the console during bootup\n"
- " --log-target=TARGET Set log target (console, journal, kmsg, journal-or-kmsg, null)\n"
- " --log-level=LEVEL Set log level (debug, info, notice, warning, err, crit, alert, emerg)\n"
+ " --show-status[=BOOL] Show status updates on the console during boot\n"
+ " --log-target=TARGET Set log target (console, journal, kmsg,\n"
+ " journal-or-kmsg, null)\n"
+ " --log-level=LEVEL Set log level (debug, info, notice, warning,\n"
+ " err, crit, alert, emerg)\n"
" --log-color[=BOOL] Highlight important log messages\n"
" --log-location[=BOOL] Include code location in log messages\n"
" --log-time[=BOOL] Prefix log messages with current time\n"
" --default-standard-output= Set default standard output for services\n"
" --default-standard-error= Set default standard error output for services\n"
+ " --no-pager Do not pipe output into a pager\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
ansi_highlight(),
buf = new(char, sizeof("split-usr:"
"cgroups-missing:"
- "cgrousv1:"
+ "cgroupsv1:"
"local-hwclock:"
"var-run-bad:"
"overflowuid-not-65534:"
'load-fragment-gperf.gperf',
input : 'load-fragment-gperf.gperf.in',
output: 'load-fragment-gperf.gperf',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'])
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'])
load_fragment_gperf_c = custom_target(
'load-fragment-gperf.c',
file,
input : file + '.in',
output: file,
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : (dir == pkgsysconfdir) ? install_sysconfdir_samples : (dir != 'no'),
install_dir : dir)
endforeach
printf("%s [OPTIONS...]\n\n"
"Configures basic settings of the system.\n\n"
- " -h --help Show this help\n"
- " --version Show package version\n"
- " --root=PATH Operate on an alternate filesystem root\n"
- " --image=PATH Operate on an alternate filesystem image\n"
- " --locale=LOCALE Set primary locale (LANG=)\n"
- " --locale-messages=LOCALE Set message locale (LC_MESSAGES=)\n"
- " --keymap=KEYMAP Set keymap\n"
- " --timezone=TIMEZONE Set timezone\n"
- " --hostname=NAME Set hostname\n"
- " --machine-ID=ID Set machine ID\n"
- " --root-password=PASSWORD Set root password from plaintext password\n"
- " --root-password-file=FILE Set root password from file\n"
- " --root-password-hashed=HASHED_PASSWORD Set root password from hashed password\n"
- " --root-shell=SHELL Set root shell\n"
- " --prompt-locale Prompt the user for locale settings\n"
- " --prompt-keymap Prompt the user for keymap settings\n"
- " --prompt-timezone Prompt the user for timezone\n"
- " --prompt-hostname Prompt the user for hostname\n"
- " --prompt-root-password Prompt the user for root password\n"
- " --prompt-root-shell Prompt the user for root shell\n"
- " --prompt Prompt for all of the above\n"
- " --copy-locale Copy locale from host\n"
- " --copy-keymap Copy keymap from host\n"
- " --copy-timezone Copy timezone from host\n"
- " --copy-root-password Copy root password from host\n"
- " --copy-root-shell Copy root shell from host\n"
- " --copy Copy locale, keymap, timezone, root password\n"
- " --setup-machine-id Generate a new random machine ID\n"
- " --force Overwrite existing files\n"
- " --delete-root-password Delete root password\n"
- " --welcome=no Disable the welcome text\n"
+ " -h --help Show this help\n"
+ " --version Show package version\n"
+ " --root=PATH Operate on an alternate filesystem root\n"
+ " --image=PATH Operate on an alternate filesystem image\n"
+ " --locale=LOCALE Set primary locale (LANG=)\n"
+ " --locale-messages=LOCALE Set message locale (LC_MESSAGES=)\n"
+ " --keymap=KEYMAP Set keymap\n"
+ " --timezone=TIMEZONE Set timezone\n"
+ " --hostname=NAME Set hostname\n"
+ " --machine-ID=ID Set machine ID\n"
+ " --root-password=PASSWORD Set root password from plaintext password\n"
+ " --root-password-file=FILE Set root password from file\n"
+ " --root-password-hashed=HASH Set root password from hashed password\n"
+ " --root-shell=SHELL Set root shell\n"
+ " --prompt-locale Prompt the user for locale settings\n"
+ " --prompt-keymap Prompt the user for keymap settings\n"
+ " --prompt-timezone Prompt the user for timezone\n"
+ " --prompt-hostname Prompt the user for hostname\n"
+ " --prompt-root-password Prompt the user for root password\n"
+ " --prompt-root-shell Prompt the user for root shell\n"
+ " --prompt Prompt for all of the above\n"
+ " --copy-locale Copy locale from host\n"
+ " --copy-keymap Copy keymap from host\n"
+ " --copy-timezone Copy timezone from host\n"
+ " --copy-root-password Copy root password from host\n"
+ " --copy-root-shell Copy root shell from host\n"
+ " --copy Copy locale, keymap, timezone, root password\n"
+ " --setup-machine-id Generate a new random machine ID\n"
+ " --force Overwrite existing files\n"
+ " --delete-root-password Delete root password\n"
+ " --welcome=no Disable the welcome text\n"
"\nSee the %s for details.\n",
program_invocation_short_name,
link);
assert(argc >= 0);
assert(argv);
- while ((c = getopt_long(argc, argv, "ust:r:h", options, NULL)) >= 0)
+ while ((c = getopt_long(argc, argv, "sr:h", options, NULL)) >= 0)
switch (c) {
case 'h':
file,
input : file + '.in',
output: file,
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : tuple[1],
install_dir : pkgsysconfdir)
endforeach
usage()
{
echo "Usage:"
- echo " $0 [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE ...]"
- echo " $0 [OPTIONS...] remove KERNEL-VERSION"
- echo " $0 [OPTIONS...] inspect"
+ echo " kernel-install [OPTIONS...] add KERNEL-VERSION KERNEL-IMAGE [INITRD-FILE...]"
+ echo " kernel-install [OPTIONS...] remove KERNEL-VERSION"
+ echo " kernel-install [OPTIONS...] inspect"
echo "Options:"
- echo " -h, --help Print this help"
+ echo " -h, --help Print this help and exit"
+ echo " --version Print version string and exit"
echo " -v, --verbose Increase verbosity"
}
fi
done
+for i; do
+ if [ "$i" = "--version" ]; then
+ echo "kernel-install {{PROJECT_VERSION}} ({{GIT_VERSION}})"
+ exit 0
+ fi
+done
+
export KERNEL_INSTALL_VERBOSE=0
if [ "$1" = "--verbose" ] || [ "$1" = "-v" ]; then
shift
# SPDX-License-Identifier: LGPL-2.1-or-later
-if want_kernel_install
- install_data('kernel-install',
- install_mode : 'rwxr-xr-x',
- install_dir : bindir)
+kernel_install_in = files('kernel-install.in')
+if want_kernel_install
install_data('50-depmod.install',
'90-loaderentry.install',
install_mode : 'rwxr-xr-x',
'libsystemd.pc',
input : 'libsystemd.pc.in',
output : 'libsystemd.pc',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : pkgconfiglibdir != 'no',
install_dir : pkgconfiglibdir)
'libudev.pc',
input : 'libudev.pc.in',
output : 'libudev.pc',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : pkgconfiglibdir != 'no',
install_dir : pkgconfiglibdir)
file,
input : file + '.in',
output: file,
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : tuple[2] and install,
install_dir : dir)
endforeach
'resolved.conf',
input : 'resolved.conf.in',
output : 'resolved.conf',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : conf.get('ENABLE_RESOLVE') == 1 and install_sysconfdir_samples,
install_dir : pkgsysconfdir)
file,
input : file + '.in',
output : file,
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : tuple[1],
install_dir : tuple.length() > 2 ? tuple[2] : '',
build_by_default : true)
{ "v247", NAMING_V247 },
{ "v249", NAMING_V249 },
{ "v250", NAMING_V250 },
+ { "v251", NAMING_V251 },
/* … add more schemes here, as the logic to name devices is updated … */
EXTRA_NET_NAMING_MAP
* OS versions, but not fully stabilize them. */
typedef enum NamingSchemeFlags {
/* First, the individual features */
- NAMING_SR_IOV_V = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a */
- NAMING_NPAR_ARI = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6ea */
- NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df */
- NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Use zero acpi_index field, see d81186ef4f6a */
- NAMING_ALLOW_RERENAMES = 1 << 4, /* Allow re-renaming of devices, see #9006 */
- NAMING_STABLE_VIRTUAL_MACS = 1 << 5, /* Use device name to generate MAC, see 6d3646406560 */
- NAMING_NETDEVSIM = 1 << 6, /* Generate names for netdevsim devices, see eaa9d507d855 */
- NAMING_LABEL_NOPREFIX = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */
- NAMING_NSPAWN_LONG_HASH = 1 << 8, /* Shorten nspawn interfaces by including 24bit hash, instead of simple truncation */
- NAMING_BRIDGE_NO_SLOT = 1 << 9, /* Don't use PCI hotplug slot information if the corresponding device is a PCI bridge */
- NAMING_SLOT_FUNCTION_ID = 1 << 10, /* Use function_id if present to identify PCI hotplug slots */
- NAMING_16BIT_INDEX = 1 << 11, /* Allow full 16-bit for the onboard index */
- NAMING_REPLACE_STRICTLY = 1 << 12, /* Use udev_replace_ifname() for NAME= rule */
- NAMING_XEN_VIF = 1 << 13, /* GEnerate names for Xen netfront devices */
+ NAMING_SR_IOV_V = 1 << 0, /* Use "v" suffix for SR-IOV, see 609948c7043a */
+ NAMING_NPAR_ARI = 1 << 1, /* Use NPAR "ARI", see 6bc04997b6ea */
+ NAMING_INFINIBAND = 1 << 2, /* Use "ib" prefix for infiniband, see 938d30aa98df */
+ NAMING_ZERO_ACPI_INDEX = 1 << 3, /* Use zero acpi_index field, see d81186ef4f6a */
+ NAMING_ALLOW_RERENAMES = 1 << 4, /* Allow re-renaming of devices, see #9006 */
+ NAMING_STABLE_VIRTUAL_MACS = 1 << 5, /* Use device name to generate MAC, see 6d3646406560 */
+ NAMING_NETDEVSIM = 1 << 6, /* Generate names for netdevsim devices, see eaa9d507d855 */
+ NAMING_LABEL_NOPREFIX = 1 << 7, /* Don't prepend ID_NET_LABEL_ONBOARD with interface type prefix */
+ NAMING_NSPAWN_LONG_HASH = 1 << 8, /* Shorten nspawn interfaces by including 24bit hash, instead of simple truncation */
+ NAMING_BRIDGE_NO_SLOT = 1 << 9, /* Don't use PCI hotplug slot information if the corresponding device is a PCI bridge */
+ NAMING_SLOT_FUNCTION_ID = 1 << 10, /* Use function_id if present to identify PCI hotplug slots */
+ NAMING_16BIT_INDEX = 1 << 11, /* Allow full 16-bit for the onboard index */
+ NAMING_REPLACE_STRICTLY = 1 << 12, /* Use udev_replace_ifname() for NAME= rule */
+ NAMING_XEN_VIF = 1 << 13, /* Generate names for Xen netfront devices */
+ NAMING_BRIDGE_MULTIFUNCTION_SLOT = 1 << 14, /* Use PCI hotplug slot information associated with bridge, but only if PCI device is multifunction */
/* And now the masks that combine the features above */
NAMING_V238 = 0,
NAMING_V247 = NAMING_V245 | NAMING_BRIDGE_NO_SLOT,
NAMING_V249 = NAMING_V247 | NAMING_SLOT_FUNCTION_ID | NAMING_16BIT_INDEX | NAMING_REPLACE_STRICTLY,
NAMING_V250 = NAMING_V249 | NAMING_XEN_VIF,
+ NAMING_V251 = NAMING_V250 | NAMING_BRIDGE_MULTIFUNCTION_SLOT,
EXTRA_NET_NAMING_SCHEMES
'timesyncd.conf',
input : 'timesyncd.conf.in',
output : 'timesyncd.conf',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : conf.get('ENABLE_TIMESYNCD') == 1 and install_sysconfdir_samples,
install_dir : pkgsysconfdir)
'udev.pc',
input : 'udev.pc.in',
output : 'udev.pc',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : pkgconfigdatadir != 'no',
install_dir : pkgconfigdatadir)
* devices that will try to claim the same index and that would create name
* collision. */
if (naming_scheme_has(NAMING_BRIDGE_NO_SLOT) && is_pci_bridge(hotplug_slot_dev)) {
- log_device_debug(dev, "Not using slot information because the PCI device is a bridge.");
- return 0;
+ if (naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT) && !is_pci_multifunction(names->pcidev)) {
+ log_device_debug(dev, "Not using slot information because the PCI device associated with the hotplug slot is a bridge and the PCI device has single function.");
+ return 0;
+ }
+
+ if (!naming_scheme_has(NAMING_BRIDGE_MULTIFUNCTION_SLOT)) {
+ log_device_debug(dev, "Not using slot information because the PCI device is a bridge.");
+ return 0;
+ }
}
break;
if (r < 0 && r != -ENOENT)
return log_device_error_errno(dev, r, "Failed to get devnode mode: %m");
}
- if (event->mode == MODE_INVALID && gid_is_valid(event->gid) && event->gid > 0)
- /* If group is set, but mode is not set, "upgrade" mode for the group. */
- event->mode = 0660;
bool apply_mac = device_for_action(dev, SD_DEVICE_ADD);
#include "device-private.h"
#include "device-util.h"
#include "dirent-util.h"
+#include "escape.h"
#include "fd-util.h"
#include "format-util.h"
#include "fs-util.h"
return 0;
}
-int udev_node_apply_permissions(
- sd_device *dev,
+static int udev_node_apply_permissions_impl(
+ sd_device *dev, /* can be NULL, only used for logging. */
+ int node_fd,
+ const char *devnode,
bool apply_mac,
mode_t mode,
uid_t uid,
gid_t gid,
OrderedHashmap *seclabel_list) {
- const char *devnode, *subsystem;
bool apply_mode, apply_uid, apply_gid;
- _cleanup_close_ int node_fd = -1;
struct stat stats;
- dev_t devnum;
int r;
- assert(dev);
-
- r = sd_device_get_devname(dev, &devnode);
- if (r < 0)
- return log_device_debug_errno(dev, r, "Failed to get devname: %m");
- r = sd_device_get_subsystem(dev, &subsystem);
- if (r < 0)
- return log_device_debug_errno(dev, r, "Failed to get subsystem: %m");
- r = sd_device_get_devnum(dev, &devnum);
- if (r < 0)
- return log_device_debug_errno(dev, r, "Failed to get devnum: %m");
-
- if (streq(subsystem, "block"))
- mode |= S_IFBLK;
- else
- mode |= S_IFCHR;
-
- node_fd = sd_device_open(dev, O_PATH|O_CLOEXEC);
- if (node_fd < 0) {
- if (ERRNO_IS_DEVICE_ABSENT(node_fd)) {
- log_device_debug_errno(dev, node_fd, "Device node %s is missing, skipping handling.", devnode);
- return 0; /* This is necessarily racey, so ignore missing the device */
- }
-
- return log_device_debug_errno(dev, node_fd, "Cannot open node %s: %m", devnode);
- }
+ assert(node_fd >= 0);
+ assert(devnode);
if (fstat(node_fd, &stats) < 0)
return log_device_debug_errno(dev, errno, "cannot stat() node %s: %m", devnode);
+ /* If group is set, but mode is not set, "upgrade" mode for the group. */
+ if (mode == MODE_INVALID && gid_is_valid(gid) && gid > 0)
+ mode = 0660;
+
apply_mode = mode != MODE_INVALID && (stats.st_mode & 0777) != (mode & 0777);
apply_uid = uid_is_valid(uid) && stats.st_uid != uid;
apply_gid = gid_is_valid(gid) && stats.st_gid != gid;
return 0;
}
+
+int udev_node_apply_permissions(
+ sd_device *dev,
+ bool apply_mac,
+ mode_t mode,
+ uid_t uid,
+ gid_t gid,
+ OrderedHashmap *seclabel_list) {
+
+ const char *devnode;
+ _cleanup_close_ int node_fd = -1;
+ int r;
+
+ assert(dev);
+
+ r = sd_device_get_devname(dev, &devnode);
+ if (r < 0)
+ return log_device_debug_errno(dev, r, "Failed to get devname: %m");
+
+ node_fd = sd_device_open(dev, O_PATH|O_CLOEXEC);
+ if (node_fd < 0) {
+ if (ERRNO_IS_DEVICE_ABSENT(node_fd)) {
+ log_device_debug_errno(dev, node_fd, "Device node %s is missing, skipping handling.", devnode);
+ return 0; /* This is necessarily racey, so ignore missing the device */
+ }
+
+ return log_device_debug_errno(dev, node_fd, "Cannot open node %s: %m", devnode);
+ }
+
+ return udev_node_apply_permissions_impl(dev, node_fd, devnode, apply_mac, mode, uid, gid, seclabel_list);
+}
+
+int static_node_apply_permissions(
+ const char *name,
+ mode_t mode,
+ uid_t uid,
+ gid_t gid,
+ char **tags) {
+
+ _cleanup_free_ char *unescaped_filename = NULL;
+ _cleanup_close_ int node_fd = -1;
+ const char *devnode;
+ struct stat stats;
+ int r;
+
+ assert(name);
+
+ if (uid == UID_INVALID && gid == GID_INVALID && mode == MODE_INVALID && !tags)
+ return 0;
+
+ devnode = strjoina("/dev/", name);
+
+ node_fd = open(devnode, O_PATH|O_CLOEXEC);
+ if (node_fd < 0) {
+ if (errno != ENOENT)
+ return log_error_errno(errno, "Failed to open %s: %m", devnode);
+ return 0;
+ }
+
+ if (fstat(node_fd, &stats) < 0)
+ return log_error_errno(errno, "Failed to stat %s: %m", devnode);
+
+ if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode)) {
+ log_warning("%s is neither block nor character device, ignoring.", devnode);
+ return 0;
+ }
+
+ if (!strv_isempty(tags)) {
+ unescaped_filename = xescape(name, "/.");
+ if (!unescaped_filename)
+ return log_oom();
+ }
+
+ /* export the tags to a directory as symlinks, allowing otherwise dead nodes to be tagged */
+ STRV_FOREACH(t, tags) {
+ _cleanup_free_ char *p = NULL;
+
+ p = path_join("/run/udev/static_node-tags/", *t, unescaped_filename);
+ if (!p)
+ return log_oom();
+
+ r = mkdir_parents(p, 0755);
+ if (r < 0)
+ return log_error_errno(r, "Failed to create parent directory for %s: %m", p);
+
+ r = symlink(devnode, p);
+ if (r < 0 && errno != EEXIST)
+ return log_error_errno(errno, "Failed to create symlink %s -> %s: %m", p, devnode);
+ }
+
+ return udev_node_apply_permissions_impl(NULL, node_fd, devnode, false, mode, uid, gid, NULL);
+}
uid_t uid,
gid_t gid,
OrderedHashmap *seclabel_list);
+int static_node_apply_permissions(
+ const char *name,
+ mode_t mode,
+ uid_t uid,
+ gid_t gid,
+ char **tags);
+
int udev_node_remove(sd_device *dev);
int udev_node_update(sd_device *dev, sd_device *dev_old);
#include "device-private.h"
#include "device-util.h"
#include "dirent-util.h"
-#include "escape.h"
#include "fd-util.h"
#include "fileio.h"
#include "format-util.h"
#include "udev-builtin.h"
#include "udev-event.h"
#include "udev-netlink.h"
+#include "udev-node.h"
#include "udev-rules.h"
#include "udev-util.h"
#include "user-util.h"
return 0;
}
-static int apply_static_dev_perms(const char *devnode, uid_t uid, gid_t gid, mode_t mode, char **tags) {
- char device_node[UDEV_PATH_SIZE], tags_dir[UDEV_PATH_SIZE], tag_symlink[UDEV_PATH_SIZE];
- _cleanup_free_ char *unescaped_filename = NULL;
- struct stat stats;
- int r;
-
- assert(devnode);
-
- if (uid == UID_INVALID && gid == GID_INVALID && mode == MODE_INVALID && !tags)
- return 0;
-
- strscpyl(device_node, sizeof(device_node), "/dev/", devnode, NULL);
- if (stat(device_node, &stats) < 0) {
- if (errno != ENOENT)
- return log_error_errno(errno, "Failed to stat %s: %m", device_node);
- return 0;
- }
-
- if (!S_ISBLK(stats.st_mode) && !S_ISCHR(stats.st_mode)) {
- log_warning("%s is neither block nor character device, ignoring.", device_node);
- return 0;
- }
-
- if (!strv_isempty(tags)) {
- unescaped_filename = xescape(devnode, "/.");
- if (!unescaped_filename)
- return log_oom();
- }
-
- /* export the tags to a directory as symlinks, allowing otherwise dead nodes to be tagged */
- STRV_FOREACH(t, tags) {
- strscpyl(tags_dir, sizeof(tags_dir), "/run/udev/static_node-tags/", *t, "/", NULL);
- r = mkdir_p(tags_dir, 0755);
- if (r < 0)
- return log_error_errno(r, "Failed to create %s: %m", tags_dir);
-
- strscpyl(tag_symlink, sizeof(tag_symlink), tags_dir, unescaped_filename, NULL);
- r = symlink(device_node, tag_symlink);
- if (r < 0 && errno != EEXIST)
- return log_error_errno(errno, "Failed to create symlink %s -> %s: %m",
- tag_symlink, device_node);
- }
-
- /* don't touch the permissions if only the tags were set */
- if (uid == UID_INVALID && gid == GID_INVALID && mode == MODE_INVALID)
- return 0;
-
- if (mode == MODE_INVALID)
- mode = gid_is_valid(gid) ? 0660 : 0600;
- if (!uid_is_valid(uid))
- uid = 0;
- if (!gid_is_valid(gid))
- gid = 0;
-
- r = chmod_and_chown(device_node, mode, uid, gid);
- if (r == -ENOENT)
- return 0;
- if (r < 0)
- return log_error_errno(r, "Failed to chown '%s' %u %u: %m", device_node, uid, gid);
- else
- log_debug("chown '%s' %u:%u with mode %#o", device_node, uid, gid, mode);
-
- (void) utimensat(AT_FDCWD, device_node, NULL, 0);
- return 0;
-}
-
static int udev_rule_line_apply_static_dev_perms(UdevRuleLine *rule_line) {
_cleanup_strv_free_ char **tags = NULL;
uid_t uid = UID_INVALID;
if (r < 0)
return log_oom();
} else if (token->type == TK_A_OPTIONS_STATIC_NODE) {
- r = apply_static_dev_perms(token->value, uid, gid, mode, tags);
+ r = static_node_apply_permissions(token->value, mode, uid, gid, tags);
if (r < 0)
return r;
}
const char *device,
bool backing) {
+ _cleanup_close_ int fd = -1;
dev_t devt, whole_devt;
struct stat st;
int r;
assert(*devnos || *n_devnos == 0);
assert(device);
- if (stat(device, &st) < 0)
+ fd = open(device, O_CLOEXEC|O_PATH);
+ if (fd < 0)
+ return log_error_errno(errno, "Failed to open '%s': %m", device);
+
+ if (fstat(fd, &st) < 0)
return log_error_errno(errno, "Failed to stat '%s': %m", device);
if (S_ISBLK(st.st_mode))
devt = st.st_dev;
else {
_cleanup_close_ int regfd = -1;
- struct stat st2;
/* If major(st.st_dev) is zero, this might mean we are backed by btrfs, which needs special
* handing, to get the backing device node. */
- regfd = open(device, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
+ regfd = fd_reopen(fd, O_RDONLY|O_CLOEXEC|O_NONBLOCK);
if (regfd < 0)
- return log_error_errno(errno, "Failed to open '%s': %m", device);
-
- /* Extra safety: let's check we are still looking at the same file */
- if (fstat(regfd, &st2) < 0)
- return log_error_errno(errno, "Failed to stat '%s': %m", device);
- if (!stat_inode_same(&st, &st2))
- return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "File '%s' was replaced while we were looking at it.", device);
+ return log_error_errno(regfd, "Failed to open '%s': %m", device);
r = btrfs_get_block_device_fd(regfd, &devt);
if (r == -ENOTTY)
if (r < 0)
return log_device_debug_errno(dev, r, "Failed to get sysname: %m");
+ /* Exclude the following devices:
+ * For "dm-", see the comment added by e918a1b5a94f270186dca59156354acd2a596494.
+ * For "md", see the commit message of 2e5b17d01347d3c3118be2b8ad63d20415dbb1f0,
+ * but not sure the assumption is still valid even when partitions are created on the md
+ * devices, surprisingly which seems to be possible, see PR #22973.
+ * For "drbd", see the commit message of fee854ee8ccde0cd28e0f925dea18cce35f3993d. */
if (STARTSWITH_SET(val, "dm-", "md", "drbd"))
goto irrelevant;
'90-vconsole.rules',
input : '90-vconsole.rules.in',
output : '90-vconsole.rules',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : conf.get('ENABLE_VCONSOLE') == 1,
install_dir : udevrulesdir)
'50-coredump.conf',
input : '50-coredump.conf.in',
output : '50-coredump.conf',
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : conf.get('ENABLE_COREDUMP') == 1,
install_dir : sysctldir)
file,
input : file + '.in',
output: file,
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : tuple[1],
install_dir : sysusersdir)
endforeach
'25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
'25-veth.netdev', '25-ip6tnl-slaac.network', '25-ipv6-prefix.network',
'25-ip6tnl-tunnel-local-slaac.netdev', '25-ip6tnl-tunnel-local-slaac.network',
- '25-ip6tnl-external.netdev', '26-netdev-link-local-addressing-yes.network')
+ '25-ip6tnl-tunnel-external.netdev', '26-netdev-link-local-addressing-yes.network')
start_networkd()
self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable',
'ip6tnl-slaac:degraded', 'ip6tnl-external:degraded',
pair[0],
input : pair[0] + '.in',
output: pair[0],
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : enable_tmpfiles,
install_dir : tmpfilesdir)
else
set -eu
set -o pipefail
-# Note: `grep ... >/dev/null` instead of just `grep -q` is used intentionally
-# here, since `grep -q` exits on the first match causing SIGPIPE being
+# Note: 'grep ... >/dev/null' instead of just 'grep -q' is used intentionally
+# here, since 'grep -q' exits on the first match causing SIGPIPE being
# sent to the sender.
BINARY="${1:?}"
# --help prints something. Also catches case where args are ignored.
if ! "$BINARY" --help | grep . >/dev/null; then
- echo "$(basename "$BINARY") --help output is empty."
+ echo "$(basename "$BINARY") --help output is empty"
exit 2
fi
-# no --help output to stdout
+# no --help output to stderr
if "$BINARY" --help 2>&1 1>/dev/null | grep .; then
echo "$(basename "$BINARY") --help prints to stderr"
exit 3
echo "$(basename "$BINARY") with an unknown parameter does not print to stderr"
exit 4
fi
+
+# --help and -h are equivalent
+if ! diff <("$BINARY" -h) <("$BINARY" --help); then
+ echo "$(basename "$BINARY") --help and -h are not identical"
+ exit 5
+fi
--- /dev/null
+#!/usr/bin/env bash
+# SPDX-License-Identifier: LGPL-2.1-or-later
+set -eu
+set -o pipefail
+
+# Note: 'grep ... >/dev/null' instead of just 'grep -q' is used intentionally
+# here, since 'grep -q' exits on the first match causing SIGPIPE being
+# sent to the sender.
+
+BINARY="${1:?}"
+VERSION="${2:?}"
+export SYSTEMD_LOG_LEVEL=info
+
+if [[ ! -x "$BINARY" ]]; then
+ echo "$BINARY is not an executable"
+ exit 1
+fi
+
+# --version prints something. Also catches case where args are ignored.
+if ! "$BINARY" --version | grep . >/dev/null; then
+ echo "$(basename "$BINARY") --version output is empty"
+ exit 2
+fi
+
+# no --version output to stderr
+if "$BINARY" --version 2>&1 1>/dev/null | grep .; then
+ echo "$(basename "$BINARY") --version prints to stderr"
+ exit 3
+fi
+
+# project version appears in version output
+out="$("$BINARY" --version)"
+if ! grep -F "$VERSION" >/dev/null <<<"$out"; then
+ echo "$(basename "$BINARY") --version output does not match '$VERSION': $out"
+ exit 4
+fi
if __name__ == '__main__':
defines = parse_config_h(sys.argv[1])
- output = render(sys.argv[2], defines)
- with open(sys.argv[3], 'w') as f:
+ defines.update(parse_config_h(sys.argv[2]))
+ output = render(sys.argv[3], defines)
+ with open(sys.argv[4], 'w') as f:
f.write(output)
f.write('\n')
- info = os.stat(sys.argv[2])
- os.chmod(sys.argv[3], info.st_mode)
+ info = os.stat(sys.argv[3])
+ os.chmod(sys.argv[4], info.st_mode)
file,
input : file + '.in',
output : file,
- command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
+ command : [jinja2_cmdline, '@INPUT@', '@OUTPUT@'],
install : install,
install_dir : systemunitdir)