mirror of
https://github.com/systemd/systemd
synced 2026-04-11 09:34:51 +02:00
Compare commits
39 Commits
cbf8fc90d5
...
3e7bf8535f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3e7bf8535f | ||
|
|
61d99ab9fb | ||
|
|
1de6d117ef | ||
|
|
8585b7ca65 | ||
|
|
ff254eea8f | ||
|
|
a2b0cd3f5a | ||
|
|
4287c85589 | ||
|
|
b0c01c9846 | ||
|
|
567c19a62c | ||
|
|
6b6e471a32 | ||
|
|
7056adbf16 | ||
|
|
f6caab8995 | ||
|
|
648a799fc9 | ||
|
|
e70151c94d | ||
|
|
2588920059 | ||
|
|
37057fe93e | ||
|
|
7c4bd9ac98 | ||
|
|
402b81ffd8 | ||
|
|
7726526cc6 | ||
|
|
d3d6b38f46 | ||
|
|
61cdbd8d76 | ||
|
|
298cff6171 | ||
|
|
7b55f29797 | ||
|
|
e4e44a0107 | ||
|
|
8e85924fd6 | ||
|
|
3f871f1205 | ||
|
|
65dcf9f9a0 | ||
|
|
623370e643 | ||
|
|
ccadf9ac0d | ||
|
|
f9da11ef1e | ||
|
|
b1d9c504d3 | ||
|
|
03e1b6664c | ||
|
|
6fc2da644a | ||
|
|
cdebedb4d4 | ||
|
|
da7d684825 | ||
|
|
2be25d7557 | ||
|
|
6d1b59cec4 | ||
|
|
562729d744 | ||
|
|
54cd4bb7c7 |
6
.github/workflows/build_test.sh
vendored
6
.github/workflows/build_test.sh
vendored
@ -9,9 +9,8 @@ success() { echo >&2 -e "\033[32;1m$1\033[0m"; }
|
|||||||
|
|
||||||
ARGS=(
|
ARGS=(
|
||||||
"--optimization=0"
|
"--optimization=0"
|
||||||
"--optimization=2"
|
|
||||||
"--optimization=s"
|
"--optimization=s"
|
||||||
"--optimization=3 -Db_lto=true"
|
"--optimization=3 -Db_lto=true -Ddns-over-tls=false"
|
||||||
"--optimization=3 -Db_lto=false"
|
"--optimization=3 -Db_lto=false"
|
||||||
"--optimization=3 -Ddns-over-tls=openssl"
|
"--optimization=3 -Ddns-over-tls=openssl"
|
||||||
"--optimization=3 -Dfexecve=true -Dstandalone-binaries=true -Dstatic-libsystemd=true -Dstatic-libudev=true"
|
"--optimization=3 -Dfexecve=true -Dstandalone-binaries=true -Dstatic-libsystemd=true -Dstatic-libudev=true"
|
||||||
@ -63,6 +62,7 @@ PACKAGES=(
|
|||||||
COMPILER="${COMPILER:?}"
|
COMPILER="${COMPILER:?}"
|
||||||
COMPILER_VERSION="${COMPILER_VERSION:?}"
|
COMPILER_VERSION="${COMPILER_VERSION:?}"
|
||||||
LINKER="${LINKER:?}"
|
LINKER="${LINKER:?}"
|
||||||
|
CRYPTOLIB="${CRYPTOLIB:?}"
|
||||||
RELEASE="$(lsb_release -cs)"
|
RELEASE="$(lsb_release -cs)"
|
||||||
|
|
||||||
bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse' >>/etc/apt/sources.list"
|
bash -c "echo 'deb-src http://archive.ubuntu.com/ubuntu/ $RELEASE main restricted universe multiverse' >>/etc/apt/sources.list"
|
||||||
@ -122,7 +122,7 @@ for args in "${ARGS[@]}"; do
|
|||||||
CC="$CC" CC_LD="$LINKER" CFLAGS="-Werror" \
|
CC="$CC" CC_LD="$LINKER" CFLAGS="-Werror" \
|
||||||
CXX="$CXX" CXX_LD="$LINKER" CXXFLAGS="-Werror" \
|
CXX="$CXX" CXX_LD="$LINKER" CXXFLAGS="-Werror" \
|
||||||
meson -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true --werror \
|
meson -Dtests=unsafe -Dslow-tests=true -Dfuzz-tests=true --werror \
|
||||||
$args build; then
|
-Dcryptolib="${CRYPTOLIB:?}" $args build; then
|
||||||
|
|
||||||
fatal "meson failed with $args"
|
fatal "meson failed with $args"
|
||||||
fi
|
fi
|
||||||
|
|||||||
14
.github/workflows/build_test.yml
vendored
14
.github/workflows/build_test.yml
vendored
@ -19,20 +19,20 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-20.04
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ matrix.env.COMPILER }}-${{ matrix.env.COMPILER_VERSION }}-${{ matrix.env.LINKER }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ toJSON(matrix.env) }}-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
env:
|
env:
|
||||||
- { COMPILER: "gcc", COMPILER_VERSION: "10", LINKER: "bfd" }
|
- { COMPILER: "gcc", COMPILER_VERSION: "10", LINKER: "bfd", CRYPTOLIB: "gcrypt" }
|
||||||
- { COMPILER: "gcc", COMPILER_VERSION: "11", LINKER: "gold" }
|
- { COMPILER: "gcc", COMPILER_VERSION: "11", LINKER: "gold", CRYPTOLIB: "openssl" }
|
||||||
- { COMPILER: "clang", COMPILER_VERSION: "11", LINKER: "bfd" }
|
- { COMPILER: "clang", COMPILER_VERSION: "11", LINKER: "bfd", CRYPTOLIB: "auto" }
|
||||||
- { COMPILER: "clang", COMPILER_VERSION: "12", LINKER: "gold" }
|
- { COMPILER: "clang", COMPILER_VERSION: "12", LINKER: "gold", CRYPTOLIB: "gcrypt" }
|
||||||
- { COMPILER: "clang", COMPILER_VERSION: "13", LINKER: "lld" }
|
- { COMPILER: "clang", COMPILER_VERSION: "13", LINKER: "lld", CRYPTOLIB: "openssl" }
|
||||||
env: ${{ matrix.env }}
|
env: ${{ matrix.env }}
|
||||||
steps:
|
steps:
|
||||||
- name: Repository checkout
|
- name: Repository checkout
|
||||||
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
|
uses: actions/checkout@ec3a7ce113134d7a93b817d10a8272cb61118579
|
||||||
- name: Build check (${{ env.COMPILER }}-${{ env.COMPILER_VERSION }}-${{ env.LINKER }})
|
- name: ${{ format('Build check ({0}-{1}-{2}-{3})', env.COMPILER, env.COMPILER_VERSION, env.LINKER, env.CRYPTOLIB) }}
|
||||||
run: sudo -E .github/workflows/build_test.sh
|
run: sudo -E .github/workflows/build_test.sh
|
||||||
|
|||||||
3
factory/templates/locale.conf.in
Normal file
3
factory/templates/locale.conf.in
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
# This is the fallback locale configuration provided by systemd.
|
||||||
|
|
||||||
|
LANG="{{ SYSTEMD_DEFAULT_LOCALE }}"
|
||||||
11
factory/templates/meson.build
Normal file
11
factory/templates/meson.build
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
|
||||||
|
factory_etc_dir = factorydir / 'etc'
|
||||||
|
|
||||||
|
custom_target(
|
||||||
|
'locale.conf',
|
||||||
|
input : 'locale.conf.in',
|
||||||
|
output : 'locale.conf',
|
||||||
|
command : [meson_render_jinja2, config_h, '@INPUT@', '@OUTPUT@'],
|
||||||
|
install : true,
|
||||||
|
install_dir : factory_etc_dir)
|
||||||
@ -78,10 +78,10 @@
|
|||||||
<term><command>capture</command> <arg choice="opt" rep="repeat"><replaceable>SERVICE</replaceable></arg></term>
|
<term><command>capture</command> <arg choice="opt" rep="repeat"><replaceable>SERVICE</replaceable></arg></term>
|
||||||
|
|
||||||
<listitem><para>Similar to <command>monitor</command> but
|
<listitem><para>Similar to <command>monitor</command> but
|
||||||
writes the output in pcap format (for details, see the <ulink
|
writes the output in pcapng format (for details, see
|
||||||
url="https://wiki.wireshark.org/Development/LibpcapFileFormat">Libpcap
|
<ulink url="https://github.com/pcapng/pcapng/">
|
||||||
File Format</ulink> description). Make sure to redirect
|
PCAP Next Generation (pcapng) Capture File Format</ulink>).
|
||||||
standard output to a file. Tools like
|
Make sure to redirect standard output to a file or pipe. Tools like
|
||||||
<citerefentry project='die-net'><refentrytitle>wireshark</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
<citerefentry project='die-net'><refentrytitle>wireshark</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||||
may be used to dissect and view the resulting
|
may be used to dissect and view the resulting
|
||||||
files.</para></listitem>
|
files.</para></listitem>
|
||||||
|
|||||||
@ -32,7 +32,8 @@
|
|||||||
|
|
||||||
<para>The basic file format of <filename>locale.conf</filename> is
|
<para>The basic file format of <filename>locale.conf</filename> is
|
||||||
a newline-separated list of environment-like shell-compatible
|
a newline-separated list of environment-like shell-compatible
|
||||||
variable assignments. It is possible to source the configuration
|
variable assignments, ignoring comments and empty lines.
|
||||||
|
It is possible to source the configuration
|
||||||
from shell scripts, however, beyond mere variable assignments, no
|
from shell scripts, however, beyond mere variable assignments, no
|
||||||
shell features are supported, allowing applications to read the
|
shell features are supported, allowing applications to read the
|
||||||
file without implementing a shell compatible execution
|
file without implementing a shell compatible execution
|
||||||
@ -64,14 +65,14 @@
|
|||||||
might be checked for locale configuration as well, however only as
|
might be checked for locale configuration as well, however only as
|
||||||
fallback.</para>
|
fallback.</para>
|
||||||
|
|
||||||
<para><filename>/etc/locale.conf</filename> is usually created and updated
|
<para><filename>/etc/locale.conf</filename> can be updated
|
||||||
using
|
using
|
||||||
<citerefentry><refentrytitle>systemd-localed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
|
<citerefentry><refentrytitle>systemd-localed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>.
|
||||||
<citerefentry project='man-pages'><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
<citerefentry project='man-pages'><refentrytitle>localectl</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||||
may be used to alter the settings in this file during runtime from
|
may be used to alter the settings in this file during runtime from
|
||||||
the command line. Use
|
the command line. Use
|
||||||
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
<citerefentry><refentrytitle>systemd-firstboot</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||||
to initialize them on mounted (but not booted) system images.</para>
|
to customize them on mounted (but not booted) system images.</para>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
@ -107,7 +108,9 @@
|
|||||||
|
|
||||||
<para><filename>/etc/locale.conf</filename>:</para>
|
<para><filename>/etc/locale.conf</filename>:</para>
|
||||||
|
|
||||||
<programlisting>LANG=de_DE.UTF-8
|
<programlisting># Custom settings
|
||||||
|
|
||||||
|
LANG=de_DE.UTF-8
|
||||||
LC_MESSAGES=en_US.UTF-8</programlisting>
|
LC_MESSAGES=en_US.UTF-8</programlisting>
|
||||||
</example>
|
</example>
|
||||||
|
|
||||||
|
|||||||
@ -3546,6 +3546,41 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
|
|||||||
</table></listitem>
|
</table></listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
|
|
||||||
|
<varlistentry>
|
||||||
|
<term><varname>$MONITOR_METADATA</varname></term>
|
||||||
|
|
||||||
|
<listitem><para>Only defined for the service unit type, this environment variable is passed to all
|
||||||
|
<varname>ExecStart=</varname> and <varname>ExecStartPre=</varname> processes which run in services
|
||||||
|
triggered by <varname>OnFailure=</varname> or <varname>OnSuccess=</varname> dependencies.</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The contents of this variable consists of a semi-colon separated list of metadata fields associated with the triggering
|
||||||
|
service. For each service which triggered the <varname>OnFailure=</varname> or <varname>OnSuccess=</varname>
|
||||||
|
dependency the following fields will be set:
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<itemizedlist>
|
||||||
|
<listitem><para><constant>SERVICE_RESULT</constant></para></listitem>
|
||||||
|
<listitem><para><constant>EXIT_CODE</constant></para></listitem>
|
||||||
|
<listitem><para><constant>EXIT_STATUS</constant></para></listitem>
|
||||||
|
<listitem><para><constant>INVOCATION_ID</constant></para></listitem>
|
||||||
|
<listitem><para><constant>UNIT</constant></para></listitem>
|
||||||
|
</itemizedlist>
|
||||||
|
|
||||||
|
<para>The fields <constant>SERVICE_RESULT</constant>, <constant>EXIT_CODE</constant> and
|
||||||
|
<constant>EXIT_STATUS</constant> may take the same values that are allowed when set for
|
||||||
|
<varname>ExecStop=</varname> and <varname>ExecStopPost=</varname> processes. The fields
|
||||||
|
<constant>INVOCATION_ID</constant> and <constant>UNIT</constant> are the invocaton id and unit
|
||||||
|
name of the service which triggered the dependency. Each field is comma separated, i.e.</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
SERVICE_RESULT=result-string,EXIT_CODE=exit-code,EXIT_STATUS=exit-status,INVOCATION_ID=invocation-id,UNIT=triggering.service
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
</listitem>
|
||||||
|
|
||||||
|
</varlistentry>
|
||||||
|
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>$PIDFILE</varname></term>
|
<term><varname>$PIDFILE</varname></term>
|
||||||
|
|
||||||
@ -3983,6 +4018,77 @@ StandardInputData=SWNrIHNpdHplIGRhIHVuJyBlc3NlIEtsb3BzLAp1ZmYgZWVtYWwga2xvcHAncy
|
|||||||
</table>
|
</table>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
<refsect1>
|
||||||
|
<title>Examples</title>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title><varname>$MONITOR_METADATA</varname> usage</title>
|
||||||
|
|
||||||
|
<para>A service <filename index="false">myfailer.service</filename> which can trigger an
|
||||||
|
<varname>OnFailure=</varname> dependency.</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
[Unit]
|
||||||
|
Description=Service which can trigger an OnFailure= dependency
|
||||||
|
OnFailure=myhandler.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/myprogram
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>A service <filename index="false">mysuccess.service</filename> which can trigger an
|
||||||
|
<varname>OnSuccess=</varname> dependency.</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
[Unit]
|
||||||
|
Description=Service which can trigger an OnSuccess= dependency
|
||||||
|
OnSuccess=myhandler.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/mysecondprogram
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>A service <filename index="false">myhandler.service</filename> which can be triggered
|
||||||
|
by any of the above services.</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
[Unit]
|
||||||
|
Description=Acts on service failing or succeeding
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/bash -c "echo $MONITOR_METADATA"
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>If <filename index="false">myfailer.service</filename> were to run and exit in failure,
|
||||||
|
then <filename index="false">myhandler.service</filename> would be triggered and the
|
||||||
|
<varname>$MONITOR_METADATA</varname> variable would be set as follows:</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
MONITOR_METADATA=SERVICE_RESULT=result-string,EXIT_CODE=exit-code,EXIT_STATUS=exit-status,INVOCATION_ID=invocation-id,UNIT=myfailer.service
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>If <filename index="false">mysuccess.service</filename> were to run and exit in success,
|
||||||
|
then <filename index="false">myhandler.service</filename> would be triggered and the
|
||||||
|
<varname>$MONITOR_METADATA</varname> variable would be set as follows:</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
MONITOR_METADATA=SERVICE_RESULT=result-string,EXIT_CODE=exit-code,EXIT_STATUS=exit-status,INVOCATION_ID=invocation-id,UNIT=mysuccess.service
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
<para>If <filename index="false">myfailer.service</filename> and <filename index="false">mysuccess.service</filename> were to run and exit,
|
||||||
|
there is a chance that the triggered dependency start job might be merged. Thus only a single invocation of
|
||||||
|
<filename index="false">myhandler.service</filename> would be triggered. In this case the <varname>$MONITOR_METADATA</varname> variable
|
||||||
|
would be a list containing exit metadata for both of <filename index="false">myfailer.service</filename>
|
||||||
|
and <filename index="false">mysuccess.service</filename>.</para>
|
||||||
|
|
||||||
|
<programlisting>
|
||||||
|
MONITOR_METADATA=SERVICE_RESULT=result-string,EXIT_CODE=exit-code,EXIT_STATUS=exit-status,INVOCATION_ID=invocation-id,UNIT=myfailer.service;SERVICE_RESULT=result-string,EXIT_CODE=exit-code,EXIT_STATUS=exit-status,INVOCATION_ID=invocation-id,UNIT=mysuccess.service
|
||||||
|
</programlisting>
|
||||||
|
|
||||||
|
</example>
|
||||||
|
|
||||||
|
</refsect1>
|
||||||
|
|
||||||
<refsect1>
|
<refsect1>
|
||||||
<title>See Also</title>
|
<title>See Also</title>
|
||||||
<para>
|
<para>
|
||||||
|
|||||||
@ -1148,8 +1148,13 @@
|
|||||||
<varlistentry>
|
<varlistentry>
|
||||||
<term><varname>Local=</varname></term>
|
<term><varname>Local=</varname></term>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>A static local address for tunneled packets. It must be an address on another interface of
|
<para>A static local address for tunneled packets. It must be an address on another interface
|
||||||
this host, or the special value <literal>any</literal>.</para>
|
of this host, or one of the special values <literal>any</literal>,
|
||||||
|
<literal>ipv4_link_local</literal>, <literal>ipv6_link_local</literal>,
|
||||||
|
<literal>dhcp4</literal>, <literal>dhcp6</literal>, and <literal>slaac</literal>. If one
|
||||||
|
of the special values except for <literal>any</literal> is specified, an address which
|
||||||
|
matches the corresponding type on the underlying interface will be used. Defaults to
|
||||||
|
<literal>any</literal>.</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</varlistentry>
|
||||||
<varlistentry>
|
<varlistentry>
|
||||||
|
|||||||
38
meson.build
38
meson.build
@ -43,6 +43,10 @@ endif
|
|||||||
skip_deps = want_ossfuzz or want_libfuzzer
|
skip_deps = want_ossfuzz or want_libfuzzer
|
||||||
fuzzer_build = want_ossfuzz or want_libfuzzer
|
fuzzer_build = want_ossfuzz or want_libfuzzer
|
||||||
|
|
||||||
|
# Create a title-less summary section early, so it ends up first in the output.
|
||||||
|
# More items are added later after they have been detected.
|
||||||
|
summary({'build mode' : get_option('mode')})
|
||||||
|
|
||||||
#####################################################################
|
#####################################################################
|
||||||
|
|
||||||
# Try to install the git pre-commit hook
|
# Try to install the git pre-commit hook
|
||||||
@ -595,6 +599,11 @@ endif
|
|||||||
|
|
||||||
versiondep = declare_dependency(sources: version_h)
|
versiondep = declare_dependency(sources: version_h)
|
||||||
|
|
||||||
|
shared_lib_tag = get_option('shared-lib-tag')
|
||||||
|
if shared_lib_tag == ''
|
||||||
|
shared_lib_tag = meson.project_version()
|
||||||
|
endif
|
||||||
|
|
||||||
sh = find_program('sh')
|
sh = find_program('sh')
|
||||||
echo = find_program('echo')
|
echo = find_program('echo')
|
||||||
sed = find_program('sed')
|
sed = find_program('sed')
|
||||||
@ -2017,12 +2026,7 @@ dbus_programs += executable(
|
|||||||
link_with : [libcore,
|
link_with : [libcore,
|
||||||
libshared],
|
libshared],
|
||||||
dependencies : [versiondep,
|
dependencies : [versiondep,
|
||||||
threads,
|
libseccomp],
|
||||||
librt,
|
|
||||||
libseccomp,
|
|
||||||
libselinux,
|
|
||||||
libmount,
|
|
||||||
libblkid],
|
|
||||||
install_rpath : rootlibexecdir,
|
install_rpath : rootlibexecdir,
|
||||||
install : true,
|
install : true,
|
||||||
install_dir : rootlibexecdir)
|
install_dir : rootlibexecdir)
|
||||||
@ -2038,12 +2042,7 @@ public_programs += executable(
|
|||||||
link_with : [libcore,
|
link_with : [libcore,
|
||||||
libshared],
|
libshared],
|
||||||
dependencies : [versiondep,
|
dependencies : [versiondep,
|
||||||
threads,
|
libseccomp],
|
||||||
librt,
|
|
||||||
libseccomp,
|
|
||||||
libselinux,
|
|
||||||
libmount,
|
|
||||||
libblkid],
|
|
||||||
install_rpath : rootlibexecdir,
|
install_rpath : rootlibexecdir,
|
||||||
install : conf.get('ENABLE_ANALYZE'))
|
install : conf.get('ENABLE_ANALYZE'))
|
||||||
|
|
||||||
@ -3263,6 +3262,7 @@ public_programs += executable(
|
|||||||
busctl_sources,
|
busctl_sources,
|
||||||
include_directories : includes,
|
include_directories : includes,
|
||||||
link_with : [libshared],
|
link_with : [libshared],
|
||||||
|
dependencies : [versiondep],
|
||||||
install_rpath : rootlibexecdir,
|
install_rpath : rootlibexecdir,
|
||||||
install : true)
|
install : true)
|
||||||
|
|
||||||
@ -3706,6 +3706,7 @@ subdir('docs/var-log')
|
|||||||
|
|
||||||
install_subdir('factory/etc',
|
install_subdir('factory/etc',
|
||||||
install_dir : factorydir)
|
install_dir : factorydir)
|
||||||
|
subdir('factory/templates')
|
||||||
|
|
||||||
if install_sysconfdir
|
if install_sysconfdir
|
||||||
install_data('xorg/50-systemd-user.sh',
|
install_data('xorg/50-systemd-user.sh',
|
||||||
@ -3886,7 +3887,6 @@ alt_time_epoch = run_command('date', '-Is', '-u', '-d', '@@0@'.format(time_epoch
|
|||||||
check : true).stdout().strip()
|
check : true).stdout().strip()
|
||||||
|
|
||||||
summary({
|
summary({
|
||||||
'build mode' : get_option('mode'),
|
|
||||||
'split /usr' : split_usr,
|
'split /usr' : split_usr,
|
||||||
'split bin-sbin' : split_bin,
|
'split bin-sbin' : split_bin,
|
||||||
'prefix directory' : prefixdir,
|
'prefix directory' : prefixdir,
|
||||||
@ -3907,6 +3907,7 @@ summary({
|
|||||||
'D-Bus system directory' : dbussystemservicedir,
|
'D-Bus system directory' : dbussystemservicedir,
|
||||||
'bash completions directory' : bashcompletiondir,
|
'bash completions directory' : bashcompletiondir,
|
||||||
'zsh completions directory' : zshcompletiondir,
|
'zsh completions directory' : zshcompletiondir,
|
||||||
|
'private shared lib version tag' : shared_lib_tag,
|
||||||
'extra start script' : get_option('rc-local'),
|
'extra start script' : get_option('rc-local'),
|
||||||
'debug shell' : '@0@ @ @1@'.format(get_option('debug-shell'),
|
'debug shell' : '@0@ @ @1@'.format(get_option('debug-shell'),
|
||||||
get_option('debug-tty')),
|
get_option('debug-tty')),
|
||||||
@ -3944,17 +3945,6 @@ summary({
|
|||||||
# CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
|
# CPPFLAGS: ${OUR_CPPFLAGS} ${CPPFLAGS}
|
||||||
# LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS}
|
# LDFLAGS: ${OUR_LDFLAGS} ${LDFLAGS}
|
||||||
|
|
||||||
if conf.get('ENABLE_EFI') == 1 and conf.get('HAVE_GNU_EFI') == 1
|
|
||||||
summary({
|
|
||||||
'EFI machine type' : efi_arch[0],
|
|
||||||
'EFI CC' : '@0@'.format(' '.join(efi_cc)),
|
|
||||||
'EFI LD' : efi_ld,
|
|
||||||
'EFI lds' : efi_lds,
|
|
||||||
'EFI crt0' : efi_crt0,
|
|
||||||
'EFI include directory' : efi_incdir},
|
|
||||||
section : 'Extensible Firmware Interface')
|
|
||||||
endif
|
|
||||||
|
|
||||||
found = []
|
found = []
|
||||||
missing = []
|
missing = []
|
||||||
|
|
||||||
|
|||||||
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
option('version-tag', type : 'string',
|
option('version-tag', type : 'string',
|
||||||
description : 'override the git version string')
|
description : 'override the git version string')
|
||||||
|
option('shared-lib-tag', type : 'string',
|
||||||
|
description : 'override the private shared library version tag (defaults to project version)')
|
||||||
|
|
||||||
option('mode', type : 'combo', choices : ['developer', 'release'],
|
option('mode', type : 'combo', choices : ['developer', 'release'],
|
||||||
description : 'autoenable features suitable for systemd development/release builds')
|
description : 'autoenable features suitable for systemd development/release builds')
|
||||||
|
|||||||
@ -25,7 +25,7 @@
|
|||||||
"list:List bus names"
|
"list:List bus names"
|
||||||
"status:Show bus service, process or bus owner credentials"
|
"status:Show bus service, process or bus owner credentials"
|
||||||
"monitor:Show bus traffic"
|
"monitor:Show bus traffic"
|
||||||
"capture:Capture bus traffix as pcap"
|
"capture:Capture bus traffic"
|
||||||
"tree:Show object tree of service"
|
"tree:Show object tree of service"
|
||||||
"introspect:Introspect object"
|
"introspect:Introspect object"
|
||||||
"call:Call a method"
|
"call:Call a method"
|
||||||
|
|||||||
115
src/basic/pcapng.h
Normal file
115
src/basic/pcapng.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For details about the file format see RFC:
|
||||||
|
* https://www.ietf.org/id/draft-tuexen-opsawg-pcapng-03.html
|
||||||
|
* and
|
||||||
|
* https://github.com/pcapng/pcapng/
|
||||||
|
*/
|
||||||
|
enum pcapng_block_types {
|
||||||
|
PCAPNG_INTERFACE_BLOCK = 1,
|
||||||
|
PCAPNG_PACKET_BLOCK, /* Obsolete */
|
||||||
|
PCAPNG_SIMPLE_PACKET_BLOCK,
|
||||||
|
PCAPNG_NAME_RESOLUTION_BLOCK,
|
||||||
|
PCAPNG_INTERFACE_STATS_BLOCK,
|
||||||
|
PCAPNG_ENHANCED_PACKET_BLOCK,
|
||||||
|
|
||||||
|
PCAPNG_SECTION_BLOCK = 0x0A0D0D0A,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pcapng_option {
|
||||||
|
uint16_t code;
|
||||||
|
uint16_t length;
|
||||||
|
uint8_t data[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PCAPNG_BYTE_ORDER_MAGIC 0x1A2B3C4D
|
||||||
|
#define PCAPNG_MAJOR_VERS 1
|
||||||
|
#define PCAPNG_MINOR_VERS 0
|
||||||
|
|
||||||
|
enum pcapng_opt {
|
||||||
|
PCAPNG_OPT_END = 0,
|
||||||
|
PCAPNG_OPT_COMMENT = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pcapng_section {
|
||||||
|
uint32_t block_type;
|
||||||
|
uint32_t block_length;
|
||||||
|
uint32_t byte_order_magic;
|
||||||
|
uint16_t major_version;
|
||||||
|
uint16_t minor_version;
|
||||||
|
uint64_t section_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum pcapng_section_opt {
|
||||||
|
PCAPNG_SHB_HARDWARE = 2,
|
||||||
|
PCAPNG_SHB_OS = 3,
|
||||||
|
PCAPNG_SHB_USERAPPL = 4,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pcapng_interface_block {
|
||||||
|
uint32_t block_type; /* 1 */
|
||||||
|
uint32_t block_length;
|
||||||
|
uint16_t link_type;
|
||||||
|
uint16_t reserved;
|
||||||
|
uint32_t snap_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum pcapng_interface_options {
|
||||||
|
PCAPNG_IFB_NAME = 2,
|
||||||
|
PCAPNG_IFB_DESCRIPTION,
|
||||||
|
PCAPNG_IFB_IPV4ADDR,
|
||||||
|
PCAPNG_IFB_IPV6ADDR,
|
||||||
|
PCAPNG_IFB_MACADDR,
|
||||||
|
PCAPNG_IFB_EUIADDR,
|
||||||
|
PCAPNG_IFB_SPEED,
|
||||||
|
PCAPNG_IFB_TSRESOL,
|
||||||
|
PCAPNG_IFB_TZONE,
|
||||||
|
PCAPNG_IFB_FILTER,
|
||||||
|
PCAPNG_IFB_OS,
|
||||||
|
PCAPNG_IFB_FCSLEN,
|
||||||
|
PCAPNG_IFB_TSOFFSET,
|
||||||
|
PCAPNG_IFB_HARDWARE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pcapng_enhance_packet_block {
|
||||||
|
uint32_t block_type; /* 6 */
|
||||||
|
uint32_t block_length;
|
||||||
|
uint32_t interface_id;
|
||||||
|
uint32_t timestamp_hi;
|
||||||
|
uint32_t timestamp_lo;
|
||||||
|
uint32_t capture_length;
|
||||||
|
uint32_t original_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Flags values */
|
||||||
|
#define PCAPNG_IFB_INBOUND 0b01
|
||||||
|
#define PCAPNG_IFB_OUTBOUND 0b10
|
||||||
|
|
||||||
|
enum pcapng_epb_options {
|
||||||
|
PCAPNG_EPB_FLAGS = 2,
|
||||||
|
PCAPNG_EPB_HASH,
|
||||||
|
PCAPNG_EPB_DROPCOUNT,
|
||||||
|
PCAPNG_EPB_PACKETID,
|
||||||
|
PCAPNG_EPB_QUEUE,
|
||||||
|
PCAPNG_EPB_VERDICT,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct pcapng_statistics_block {
|
||||||
|
uint32_t block_type; /* 5 */
|
||||||
|
uint32_t block_length;
|
||||||
|
uint32_t interface_id;
|
||||||
|
uint32_t timestamp_hi;
|
||||||
|
uint32_t timestamp_lo;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum pcapng_isb_options {
|
||||||
|
PCAPNG_ISB_STARTTIME = 2,
|
||||||
|
PCAPNG_ISB_ENDTIME,
|
||||||
|
PCAPNG_ISB_IFRECV,
|
||||||
|
PCAPNG_ISB_IFDROP,
|
||||||
|
PCAPNG_ISB_FILTERACCEPT,
|
||||||
|
PCAPNG_ISB_OSDROP,
|
||||||
|
PCAPNG_ISB_USRDELIV,
|
||||||
|
};
|
||||||
@ -15,57 +15,73 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "string-util.h"
|
||||||
#include "strxcpyx.h"
|
#include "strxcpyx.h"
|
||||||
|
|
||||||
size_t strnpcpy(char **dest, size_t size, const char *src, size_t len) {
|
size_t strnpcpy_full(char **dest, size_t size, const char *src, size_t len, bool *ret_truncated) {
|
||||||
|
bool truncated = false;
|
||||||
|
|
||||||
assert(dest);
|
assert(dest);
|
||||||
assert(src);
|
assert(src);
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0) {
|
||||||
|
if (ret_truncated)
|
||||||
|
*ret_truncated = len > 0;
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (len >= size) {
|
if (len >= size) {
|
||||||
if (size > 1)
|
if (size > 1)
|
||||||
*dest = mempcpy(*dest, src, size-1);
|
*dest = mempcpy(*dest, src, size-1);
|
||||||
size = 0;
|
size = 0;
|
||||||
|
truncated = true;
|
||||||
} else if (len > 0) {
|
} else if (len > 0) {
|
||||||
*dest = mempcpy(*dest, src, len);
|
*dest = mempcpy(*dest, src, len);
|
||||||
size -= len;
|
size -= len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret_truncated)
|
||||||
|
*ret_truncated = truncated;
|
||||||
|
|
||||||
*dest[0] = '\0';
|
*dest[0] = '\0';
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t strpcpy(char **dest, size_t size, const char *src) {
|
size_t strpcpy_full(char **dest, size_t size, const char *src, bool *ret_truncated) {
|
||||||
assert(dest);
|
assert(dest);
|
||||||
assert(src);
|
assert(src);
|
||||||
|
|
||||||
return strnpcpy(dest, size, src, strlen(src));
|
return strnpcpy_full(dest, size, src, strlen(src), ret_truncated);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t strpcpyf(char **dest, size_t size, const char *src, ...) {
|
size_t strpcpyf_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) {
|
||||||
|
bool truncated = false;
|
||||||
va_list va;
|
va_list va;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
assert(dest);
|
assert(dest);
|
||||||
assert(src);
|
assert(src);
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
va_start(va, src);
|
va_start(va, src);
|
||||||
i = vsnprintf(*dest, size, src, va);
|
i = vsnprintf(*dest, size, src, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
if (i < (int) size) {
|
if (i < (int) size) {
|
||||||
*dest += i;
|
*dest += i;
|
||||||
size -= i;
|
size -= i;
|
||||||
} else
|
} else {
|
||||||
size = 0;
|
size = 0;
|
||||||
va_end(va);
|
truncated = i > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret_truncated)
|
||||||
|
*ret_truncated = truncated;
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t strpcpyl(char **dest, size_t size, const char *src, ...) {
|
size_t strpcpyl_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) {
|
||||||
|
bool truncated = false;
|
||||||
va_list va;
|
va_list va;
|
||||||
|
|
||||||
assert(dest);
|
assert(dest);
|
||||||
@ -73,31 +89,38 @@ size_t strpcpyl(char **dest, size_t size, const char *src, ...) {
|
|||||||
|
|
||||||
va_start(va, src);
|
va_start(va, src);
|
||||||
do {
|
do {
|
||||||
size = strpcpy(dest, size, src);
|
bool t;
|
||||||
|
|
||||||
|
size = strpcpy_full(dest, size, src, &t);
|
||||||
|
truncated = truncated || t;
|
||||||
src = va_arg(va, char *);
|
src = va_arg(va, char *);
|
||||||
} while (src);
|
} while (src);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
|
if (ret_truncated)
|
||||||
|
*ret_truncated = truncated;
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t strnscpy(char *dest, size_t size, const char *src, size_t len) {
|
size_t strnscpy_full(char *dest, size_t size, const char *src, size_t len, bool *ret_truncated) {
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
assert(dest);
|
assert(dest);
|
||||||
assert(src);
|
assert(src);
|
||||||
|
|
||||||
s = dest;
|
s = dest;
|
||||||
return strnpcpy(&s, size, src, len);
|
return strnpcpy_full(&s, size, src, len, ret_truncated);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t strscpy(char *dest, size_t size, const char *src) {
|
size_t strscpy_full(char *dest, size_t size, const char *src, bool *ret_truncated) {
|
||||||
assert(dest);
|
assert(dest);
|
||||||
assert(src);
|
assert(src);
|
||||||
|
|
||||||
return strnscpy(dest, size, src, strlen(src));
|
return strnscpy_full(dest, size, src, strlen(src), ret_truncated);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t strscpyl(char *dest, size_t size, const char *src, ...) {
|
size_t strscpyl_full(char *dest, size_t size, bool *ret_truncated, const char *src, ...) {
|
||||||
|
bool truncated = false;
|
||||||
va_list va;
|
va_list va;
|
||||||
char *s;
|
char *s;
|
||||||
|
|
||||||
@ -107,10 +130,16 @@ size_t strscpyl(char *dest, size_t size, const char *src, ...) {
|
|||||||
va_start(va, src);
|
va_start(va, src);
|
||||||
s = dest;
|
s = dest;
|
||||||
do {
|
do {
|
||||||
size = strpcpy(&s, size, src);
|
bool t;
|
||||||
|
|
||||||
|
size = strpcpy_full(&s, size, src, &t);
|
||||||
|
truncated = truncated || t;
|
||||||
src = va_arg(va, char *);
|
src = va_arg(va, char *);
|
||||||
} while (src);
|
} while (src);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
|
||||||
|
if (ret_truncated)
|
||||||
|
*ret_truncated = truncated;
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,33 @@
|
|||||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
|
||||||
size_t strnpcpy(char **dest, size_t size, const char *src, size_t len);
|
size_t strnpcpy_full(char **dest, size_t size, const char *src, size_t len, bool *ret_truncated);
|
||||||
size_t strpcpy(char **dest, size_t size, const char *src);
|
static inline size_t strnpcpy(char **dest, size_t size, const char *src, size_t len) {
|
||||||
size_t strpcpyf(char **dest, size_t size, const char *src, ...) _printf_(3, 4);
|
return strnpcpy_full(dest, size, src, len, NULL);
|
||||||
size_t strpcpyl(char **dest, size_t size, const char *src, ...) _sentinel_;
|
}
|
||||||
size_t strnscpy(char *dest, size_t size, const char *src, size_t len);
|
size_t strpcpy_full(char **dest, size_t size, const char *src, bool *ret_truncated);
|
||||||
size_t strscpy(char *dest, size_t size, const char *src);
|
static inline size_t strpcpy(char **dest, size_t size, const char *src) {
|
||||||
size_t strscpyl(char *dest, size_t size, const char *src, ...) _sentinel_;
|
return strpcpy_full(dest, size, src, NULL);
|
||||||
|
}
|
||||||
|
size_t strpcpyf_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) _printf_(4, 5);
|
||||||
|
#define strpcpyf(dest, size, src, ...) \
|
||||||
|
strpcpyf_full((dest), (size), NULL, (src), ##__VA_ARGS__)
|
||||||
|
size_t strpcpyl_full(char **dest, size_t size, bool *ret_truncated, const char *src, ...) _sentinel_;
|
||||||
|
#define strpcpyl(dest, size, src, ...) \
|
||||||
|
strpcpyl_full((dest), (size), NULL, (src), ##__VA_ARGS__)
|
||||||
|
size_t strnscpy_full(char *dest, size_t size, const char *src, size_t len, bool *ret_truncated);
|
||||||
|
static inline size_t strnscpy(char *dest, size_t size, const char *src, size_t len) {
|
||||||
|
return strnscpy_full(dest, size, src, len, NULL);
|
||||||
|
}
|
||||||
|
size_t strscpy_full(char *dest, size_t size, const char *src, bool *ret_truncated);
|
||||||
|
static inline size_t strscpy(char *dest, size_t size, const char *src) {
|
||||||
|
return strscpy_full(dest, size, src, NULL);
|
||||||
|
}
|
||||||
|
size_t strscpyl_full(char *dest, size_t size, bool *ret_truncated, const char *src, ...) _sentinel_;
|
||||||
|
#define strscpyl(dest, size, src, ...) \
|
||||||
|
strscpyl_full(dest, size, NULL, src, ##__VA_ARGS__)
|
||||||
|
|||||||
@ -32,7 +32,7 @@ static inline void EventClosep(EFI_EVENT *event) {
|
|||||||
* Also, multiple input protocols can be backed by the same device, but they can be out of
|
* Also, multiple input protocols can be backed by the same device, but they can be out of
|
||||||
* sync. Falling back on a different protocol can end up with double input.
|
* sync. Falling back on a different protocol can end up with double input.
|
||||||
*
|
*
|
||||||
* Therefore, we will perferrably use TextInputEx for ConIn if that is available. Additionally,
|
* Therefore, we will preferably use TextInputEx for ConIn if that is available. Additionally,
|
||||||
* we look for the first TextInputEx device the firmware gives us as a fallback option. It
|
* we look for the first TextInputEx device the firmware gives us as a fallback option. It
|
||||||
* will replace ConInEx permanently if it ever reports a key press.
|
* will replace ConInEx permanently if it ever reports a key press.
|
||||||
* Lastly, a timer event allows us to provide a input timeout without having to call into
|
* Lastly, a timer event allows us to provide a input timeout without having to call into
|
||||||
|
|||||||
@ -99,59 +99,6 @@ if efi_lds == ''
|
|||||||
subdir_done()
|
subdir_done()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
efi_headers = files('''
|
|
||||||
bcd.h
|
|
||||||
console.h
|
|
||||||
cpio.h
|
|
||||||
devicetree.h
|
|
||||||
disk.h
|
|
||||||
drivers.h
|
|
||||||
graphics.h
|
|
||||||
linux.h
|
|
||||||
measure.h
|
|
||||||
missing_efi.h
|
|
||||||
pe.h
|
|
||||||
random-seed.h
|
|
||||||
shim.h
|
|
||||||
splash.h
|
|
||||||
util.h
|
|
||||||
xbootldr.h
|
|
||||||
'''.split())
|
|
||||||
|
|
||||||
common_sources = '''
|
|
||||||
assert.c
|
|
||||||
devicetree.c
|
|
||||||
disk.c
|
|
||||||
graphics.c
|
|
||||||
measure.c
|
|
||||||
pe.c
|
|
||||||
secure-boot.c
|
|
||||||
util.c
|
|
||||||
'''.split()
|
|
||||||
|
|
||||||
systemd_boot_sources = '''
|
|
||||||
bcd.c
|
|
||||||
boot.c
|
|
||||||
console.c
|
|
||||||
drivers.c
|
|
||||||
random-seed.c
|
|
||||||
shim.c
|
|
||||||
xbootldr.c
|
|
||||||
'''.split()
|
|
||||||
|
|
||||||
stub_sources = '''
|
|
||||||
cpio.c
|
|
||||||
initrd.c
|
|
||||||
splash.c
|
|
||||||
stub.c
|
|
||||||
'''.split()
|
|
||||||
|
|
||||||
if efi_arch[1] in ['ia32', 'x86_64']
|
|
||||||
stub_sources += 'linux_x86.c'
|
|
||||||
else
|
|
||||||
stub_sources += 'linux.c'
|
|
||||||
endif
|
|
||||||
|
|
||||||
conf.set10('HAVE_GNU_EFI', true)
|
conf.set10('HAVE_GNU_EFI', true)
|
||||||
conf.set_quoted('EFI_MACHINE_TYPE_NAME', efi_arch[0])
|
conf.set_quoted('EFI_MACHINE_TYPE_NAME', efi_arch[0])
|
||||||
|
|
||||||
@ -183,7 +130,6 @@ elif get_option('sbat-distro') != ''
|
|||||||
if (value == '' or value == 'auto') and not meson.is_cross_build()
|
if (value == '' or value == 'auto') and not meson.is_cross_build()
|
||||||
cmd = 'if [ -e /etc/os-release ]; then . /etc/os-release; else . /usr/lib/os-release; fi; echo $@0@'.format(sbatvar[1])
|
cmd = 'if [ -e /etc/os-release ]; then . /etc/os-release; else . /usr/lib/os-release; fi; echo $@0@'.format(sbatvar[1])
|
||||||
value = run_command(sh, '-c', cmd).stdout().strip()
|
value = run_command(sh, '-c', cmd).stdout().strip()
|
||||||
message('@0@ (from @1@): @2@'.format(sbatvar[0], sbatvar[1], value))
|
|
||||||
endif
|
endif
|
||||||
if value == ''
|
if value == ''
|
||||||
error('Required @0@ option not set and autodetection failed'.format(sbatvar[0]))
|
error('Required @0@ option not set and autodetection failed'.format(sbatvar[0]))
|
||||||
@ -200,8 +146,11 @@ elif get_option('sbat-distro') != ''
|
|||||||
pkgver = get_option('sbat-distro-version')
|
pkgver = get_option('sbat-distro-version')
|
||||||
if pkgver == ''
|
if pkgver == ''
|
||||||
efi_conf.set('SBAT_DISTRO_VERSION', 'GIT_VERSION')
|
efi_conf.set('SBAT_DISTRO_VERSION', 'GIT_VERSION')
|
||||||
|
# This is determined during build, not configuration, so we can't display it yet.
|
||||||
|
sbat_distro_version_display = '(git version)'
|
||||||
else
|
else
|
||||||
efi_conf.set_quoted('SBAT_DISTRO_VERSION', pkgver)
|
efi_conf.set_quoted('SBAT_DISTRO_VERSION', pkgver)
|
||||||
|
sbat_distro_version_display = pkgver
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -332,6 +281,76 @@ if efi_cc_version.contains('clang') and efi_cc_version.split('.')[0].split(' ')[
|
|||||||
efi_ldflags += ['-Wl,-T,' + efi_lds, '-Wno-unused-command-line-argument']
|
efi_ldflags += ['-Wl,-T,' + efi_lds, '-Wno-unused-command-line-argument']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
summary({
|
||||||
|
'EFI machine type' : efi_arch[0],
|
||||||
|
'EFI CC' : '@0@'.format(' '.join(efi_cc)),
|
||||||
|
'EFI LD' : efi_ld,
|
||||||
|
'EFI lds' : efi_lds,
|
||||||
|
'EFI crt0' : efi_crt0,
|
||||||
|
'EFI include directory' : efi_incdir},
|
||||||
|
section : 'Extensible Firmware Interface')
|
||||||
|
|
||||||
|
if efi_conf.get('SBAT_DISTRO', '') != ''
|
||||||
|
summary({
|
||||||
|
'SBAT distro': efi_conf.get('SBAT_DISTRO'),
|
||||||
|
'SBAT distro generation': efi_conf.get('SBAT_DISTRO_GENERATION'),
|
||||||
|
'SBAT distro version': sbat_distro_version_display,
|
||||||
|
'SBAT distro summary': efi_conf.get('SBAT_DISTRO_SUMMARY'),
|
||||||
|
'SBAT distro URL': efi_conf.get('SBAT_DISTRO_URL')},
|
||||||
|
section : 'Extensible Firmware Interface')
|
||||||
|
endif
|
||||||
|
|
||||||
|
############################################################
|
||||||
|
|
||||||
|
efi_headers = files(
|
||||||
|
'bcd.h',
|
||||||
|
'console.h',
|
||||||
|
'cpio.h',
|
||||||
|
'devicetree.h',
|
||||||
|
'disk.h',
|
||||||
|
'drivers.h',
|
||||||
|
'graphics.h',
|
||||||
|
'linux.h',
|
||||||
|
'measure.h',
|
||||||
|
'missing_efi.h',
|
||||||
|
'pe.h',
|
||||||
|
'random-seed.h',
|
||||||
|
'shim.h',
|
||||||
|
'splash.h',
|
||||||
|
'util.h',
|
||||||
|
'xbootldr.h')
|
||||||
|
|
||||||
|
common_sources = [
|
||||||
|
'assert.c',
|
||||||
|
'devicetree.c',
|
||||||
|
'disk.c',
|
||||||
|
'graphics.c',
|
||||||
|
'measure.c',
|
||||||
|
'pe.c',
|
||||||
|
'secure-boot.c',
|
||||||
|
'util.c']
|
||||||
|
|
||||||
|
systemd_boot_sources = [
|
||||||
|
'bcd.c',
|
||||||
|
'boot.c',
|
||||||
|
'console.c',
|
||||||
|
'drivers.c',
|
||||||
|
'random-seed.c',
|
||||||
|
'shim.c',
|
||||||
|
'xbootldr.c']
|
||||||
|
|
||||||
|
stub_sources = [
|
||||||
|
'cpio.c',
|
||||||
|
'initrd.c',
|
||||||
|
'splash.c',
|
||||||
|
'stub.c']
|
||||||
|
|
||||||
|
if efi_arch[1] in ['ia32', 'x86_64']
|
||||||
|
stub_sources += 'linux_x86.c'
|
||||||
|
else
|
||||||
|
stub_sources += 'linux.c'
|
||||||
|
endif
|
||||||
|
|
||||||
systemd_boot_objects = []
|
systemd_boot_objects = []
|
||||||
stub_objects = []
|
stub_objects = []
|
||||||
foreach file : fundamental_source_paths + common_sources + systemd_boot_sources + stub_sources
|
foreach file : fundamental_source_paths + common_sources + systemd_boot_sources + stub_sources
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
#include "json.h"
|
#include "json.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "main-func.h"
|
#include "main-func.h"
|
||||||
|
#include "os-util.h"
|
||||||
#include "pager.h"
|
#include "pager.h"
|
||||||
#include "parse-argument.h"
|
#include "parse-argument.h"
|
||||||
#include "parse-util.h"
|
#include "parse-util.h"
|
||||||
@ -31,6 +32,7 @@
|
|||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
#include "user-util.h"
|
#include "user-util.h"
|
||||||
#include "verbs.h"
|
#include "verbs.h"
|
||||||
|
#include "version.h"
|
||||||
|
|
||||||
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
static JsonFormatFlags arg_json_format_flags = JSON_FORMAT_OFF;
|
||||||
static PagerFlags arg_pager_flags = 0;
|
static PagerFlags arg_pager_flags = 0;
|
||||||
@ -1329,13 +1331,20 @@ static int verb_monitor(int argc, char **argv, void *userdata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int verb_capture(int argc, char **argv, void *userdata) {
|
static int verb_capture(int argc, char **argv, void *userdata) {
|
||||||
|
_cleanup_free_ char *osname = NULL;
|
||||||
|
static const char info[] =
|
||||||
|
"busctl (systemd) " STRINGIFY(PROJECT_VERSION) " (Git " GIT_VERSION ")";
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
if (isatty(fileno(stdout)) > 0)
|
if (isatty(fileno(stdout)) > 0)
|
||||||
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
|
||||||
"Refusing to write message data to console, please redirect output to a file.");
|
"Refusing to write message data to console, please redirect output to a file.");
|
||||||
|
|
||||||
bus_pcap_header(arg_snaplen, stdout);
|
r = parse_os_release(NULL, "PRETTY_NAME", &osname);
|
||||||
|
if (r < 0)
|
||||||
|
log_full_errno(r == -ENOENT ? LOG_DEBUG : LOG_INFO, r,
|
||||||
|
"Failed to read os-release file, ignoring: %m");
|
||||||
|
bus_pcap_header(arg_snaplen, osname, info, stdout);
|
||||||
|
|
||||||
r = monitor(argc, argv, message_pcap);
|
r = monitor(argc, argv, message_pcap);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
@ -385,6 +385,7 @@ typedef enum ExecFlags {
|
|||||||
EXEC_PASS_FDS = 1 << 10,
|
EXEC_PASS_FDS = 1 << 10,
|
||||||
EXEC_SETENV_RESULT = 1 << 11,
|
EXEC_SETENV_RESULT = 1 << 11,
|
||||||
EXEC_SET_WATCHDOG = 1 << 12,
|
EXEC_SET_WATCHDOG = 1 << 12,
|
||||||
|
EXEC_SETENV_MONITOR_RESULT = 1 << 13, /* Pass exit status to OnFailure= and OnSuccess= dependencies. */
|
||||||
} ExecFlags;
|
} ExecFlags;
|
||||||
|
|
||||||
/* Parameters for a specific invocation of a command. This structure is put together right before a command is
|
/* Parameters for a specific invocation of a command. This structure is put together right before a command is
|
||||||
|
|||||||
@ -99,6 +99,13 @@ Job* job_free(Job *j) {
|
|||||||
assert(!j->subject_list);
|
assert(!j->subject_list);
|
||||||
assert(!j->object_list);
|
assert(!j->object_list);
|
||||||
|
|
||||||
|
do {
|
||||||
|
Unit *tu = NULL;
|
||||||
|
|
||||||
|
LIST_FOREACH(triggered_by, tu, j->triggered_by)
|
||||||
|
LIST_REMOVE(triggered_by, j->triggered_by, tu);
|
||||||
|
} while (!LIST_IS_EMPTY(j->triggered_by));
|
||||||
|
|
||||||
job_unlink(j);
|
job_unlink(j);
|
||||||
|
|
||||||
sd_bus_track_unref(j->bus_track);
|
sd_bus_track_unref(j->bus_track);
|
||||||
@ -107,6 +114,13 @@ Job* job_free(Job *j) {
|
|||||||
return mfree(j);
|
return mfree(j);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void job_add_triggering_unit(Job *j, Unit *u) {
|
||||||
|
assert(j);
|
||||||
|
assert(u);
|
||||||
|
|
||||||
|
LIST_APPEND(triggered_by, j->triggered_by, u);
|
||||||
|
}
|
||||||
|
|
||||||
static void job_set_state(Job *j, JobState state) {
|
static void job_set_state(Job *j, JobState state) {
|
||||||
assert(j);
|
assert(j);
|
||||||
assert(state >= 0);
|
assert(state >= 0);
|
||||||
@ -187,6 +201,8 @@ static void job_merge_into_installed(Job *j, Job *other) {
|
|||||||
|
|
||||||
j->irreversible = j->irreversible || other->irreversible;
|
j->irreversible = j->irreversible || other->irreversible;
|
||||||
j->ignore_order = j->ignore_order || other->ignore_order;
|
j->ignore_order = j->ignore_order || other->ignore_order;
|
||||||
|
if (other->triggered_by)
|
||||||
|
LIST_JOIN(triggered_by, j->triggered_by, other->triggered_by);
|
||||||
}
|
}
|
||||||
|
|
||||||
Job* job_install(Job *j) {
|
Job* job_install(Job *j) {
|
||||||
|
|||||||
@ -124,6 +124,8 @@ struct Job {
|
|||||||
LIST_HEAD(JobDependency, subject_list);
|
LIST_HEAD(JobDependency, subject_list);
|
||||||
LIST_HEAD(JobDependency, object_list);
|
LIST_HEAD(JobDependency, object_list);
|
||||||
|
|
||||||
|
LIST_HEAD(Unit, triggered_by);
|
||||||
|
|
||||||
/* Used for graph algs as a "I have been here" marker */
|
/* Used for graph algs as a "I have been here" marker */
|
||||||
Job* marker;
|
Job* marker;
|
||||||
unsigned generation;
|
unsigned generation;
|
||||||
@ -244,3 +246,5 @@ JobResult job_result_from_string(const char *s) _pure_;
|
|||||||
const char* job_type_to_access_method(JobType t);
|
const char* job_type_to_access_method(JobType t);
|
||||||
|
|
||||||
int job_compare(Job *a, Job *b, UnitDependencyAtom assume_dep);
|
int job_compare(Job *a, Job *b, UnitDependencyAtom assume_dep);
|
||||||
|
|
||||||
|
void job_add_triggering_unit(Job *j, Unit *u);
|
||||||
|
|||||||
@ -167,12 +167,18 @@ load_fragment_gperf_nulstr_c = custom_target(
|
|||||||
command : [awk, '-f', '@INPUT0@', '@INPUT1@'],
|
command : [awk, '-f', '@INPUT0@', '@INPUT1@'],
|
||||||
capture : true)
|
capture : true)
|
||||||
|
|
||||||
libcore = static_library(
|
libcore_name = 'systemd-core-@0@'.format(shared_lib_tag)
|
||||||
'core',
|
|
||||||
|
libcore = shared_library(
|
||||||
|
libcore_name,
|
||||||
libcore_sources,
|
libcore_sources,
|
||||||
load_fragment_gperf_c,
|
load_fragment_gperf_c,
|
||||||
load_fragment_gperf_nulstr_c,
|
load_fragment_gperf_nulstr_c,
|
||||||
include_directories : includes,
|
include_directories : includes,
|
||||||
|
c_args : ['-fvisibility=default'],
|
||||||
|
link_args : ['-shared',
|
||||||
|
'-Wl,--version-script=' + libshared_sym_path],
|
||||||
|
link_with : libshared,
|
||||||
dependencies : [versiondep,
|
dependencies : [versiondep,
|
||||||
threads,
|
threads,
|
||||||
libdl,
|
libdl,
|
||||||
@ -184,8 +190,10 @@ libcore = static_library(
|
|||||||
libapparmor,
|
libapparmor,
|
||||||
libselinux,
|
libselinux,
|
||||||
libmount,
|
libmount,
|
||||||
|
libblkid,
|
||||||
libacl],
|
libacl],
|
||||||
build_by_default : false)
|
install : true,
|
||||||
|
install_dir : rootlibexecdir)
|
||||||
|
|
||||||
core_includes = [includes, include_directories('.')]
|
core_includes = [includes, include_directories('.')]
|
||||||
|
|
||||||
|
|||||||
@ -1440,6 +1440,93 @@ static bool service_exec_needs_notify_socket(Service *s, ExecFlags flags) {
|
|||||||
return s->notify_access != NOTIFY_NONE;
|
return s->notify_access != NOTIFY_NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int service_create_monitor_md_env(Job *j, char **ret) {
|
||||||
|
_cleanup_free_ char *var = NULL;
|
||||||
|
const char *list_delim = ";";
|
||||||
|
bool first = true;
|
||||||
|
Unit *tu;
|
||||||
|
|
||||||
|
assert(j);
|
||||||
|
assert(ret);
|
||||||
|
|
||||||
|
/* Create an environment variable 'MONITOR_METADATA', if creation is successful
|
||||||
|
* a pointer to it is returned via ret.
|
||||||
|
*
|
||||||
|
* This variable contains a space separated set of fields which relate to
|
||||||
|
* the service(s) which triggered job 'j'. Job 'j' is the JOB_START job for
|
||||||
|
* an OnFailure= or OnSuccess= dependency. Format of the MONITOR_METADATA
|
||||||
|
* variable is as follows:
|
||||||
|
*
|
||||||
|
* MONITOR_METADATA="SERVICE_RESULT=<result-string0>,EXIT_CODE=<exit-code0>,EXIT_STATUS=<exit-status0>,
|
||||||
|
* INVOCATION_ID=<id>,UNIT=<triggering-unit0.service>;
|
||||||
|
* SERVICE_RESULT=<result-stringN>,EXIT_CODE=<exit-codeN>,EXIT_STATUS=<exit-statusN>,
|
||||||
|
* INVOCATION_ID=<id>,UNIT=<triggering-unitN.service>"
|
||||||
|
*
|
||||||
|
* Multiple results may be passed as in the above example if jobs are merged, i.e.
|
||||||
|
* some services a and b contain an OnFailure= or OnSuccess= dependency on the same
|
||||||
|
* service.
|
||||||
|
*
|
||||||
|
* For example:
|
||||||
|
*
|
||||||
|
* MONITOR_METADATA="SERVICE_RESULT=exit-code,EXIT_CODE=exited,EXIT_STATUS=1,INVOCATION_ID=02dd868af2f344b18edaf74b618b2f90,UNIT=failure.service;
|
||||||
|
* SERVICE_RESULT=exit-code,EXIT_CODE=exited,EXIT_STATUS=1,INVOCATION_ID=80cb228bd7344f77a090eda603a3cfe2,UNIT=failure2.service"
|
||||||
|
*/
|
||||||
|
|
||||||
|
LIST_FOREACH(triggered_by, tu, j->triggered_by) {
|
||||||
|
Service *env_source = SERVICE(tu);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (!env_source)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (first) {
|
||||||
|
/* Add the environment variable name first. */
|
||||||
|
r = strextendf(&var, "MONITOR_METADATA=");
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
r = strextendf(&var, "%sSERVICE_RESULT=%s",
|
||||||
|
!first ? list_delim : "", service_result_to_string(env_source->result));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
first = false;
|
||||||
|
|
||||||
|
if (env_source->main_exec_status.pid > 0 &&
|
||||||
|
dual_timestamp_is_set(&env_source->main_exec_status.exit_timestamp)) {
|
||||||
|
r = strextendf(&var, ",EXIT_CODE=%s",
|
||||||
|
sigchld_code_to_string(env_source->main_exec_status.code));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
if (env_source->main_exec_status.code == CLD_EXITED)
|
||||||
|
r = strextendf(&var, ",EXIT_STATUS=%i",
|
||||||
|
env_source->main_exec_status.status);
|
||||||
|
else
|
||||||
|
r = strextendf(&var, ",EXIT_STATUS=%s",
|
||||||
|
signal_to_string(env_source->main_exec_status.status));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!sd_id128_is_null(UNIT(env_source)->invocation_id)) {
|
||||||
|
r = strextendf(&var, ",INVOCATION_ID=" SD_ID128_FORMAT_STR,
|
||||||
|
SD_ID128_FORMAT_VAL(UNIT(env_source)->invocation_id));
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = strextendf(&var, ",UNIT=%s", UNIT(env_source)->id);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ret = TAKE_PTR(var);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int service_spawn(
|
static int service_spawn(
|
||||||
Service *s,
|
Service *s,
|
||||||
ExecCommand *c,
|
ExecCommand *c,
|
||||||
@ -1574,9 +1661,18 @@ static int service_spawn(
|
|||||||
r = asprintf(our_env + n_env++, "EXIT_STATUS=%i", s->main_exec_status.status);
|
r = asprintf(our_env + n_env++, "EXIT_STATUS=%i", s->main_exec_status.status);
|
||||||
else
|
else
|
||||||
r = asprintf(our_env + n_env++, "EXIT_STATUS=%s", signal_to_string(s->main_exec_status.status));
|
r = asprintf(our_env + n_env++, "EXIT_STATUS=%s", signal_to_string(s->main_exec_status.status));
|
||||||
|
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} else if (flags & EXEC_SETENV_MONITOR_RESULT) {
|
||||||
|
Job *j = UNIT(s)->job;
|
||||||
|
if (j) {
|
||||||
|
r = service_create_monitor_md_env(j, our_env + n_env++);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
r = unit_set_exec_params(UNIT(s), &exec_params);
|
r = unit_set_exec_params(UNIT(s), &exec_params);
|
||||||
@ -2164,7 +2260,7 @@ static void service_enter_start(Service *s) {
|
|||||||
r = service_spawn(s,
|
r = service_spawn(s,
|
||||||
c,
|
c,
|
||||||
timeout,
|
timeout,
|
||||||
EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_WRITE_CREDENTIALS,
|
EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_WRITE_CREDENTIALS|EXEC_SETENV_MONITOR_RESULT,
|
||||||
&pid);
|
&pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
@ -2222,7 +2318,7 @@ static void service_enter_start_pre(Service *s) {
|
|||||||
r = service_spawn(s,
|
r = service_spawn(s,
|
||||||
s->control_command,
|
s->control_command,
|
||||||
s->timeout_start_usec,
|
s->timeout_start_usec,
|
||||||
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN,
|
EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN|EXEC_SETENV_MONITOR_RESULT,
|
||||||
&s->control_pid);
|
&s->control_pid);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|||||||
@ -82,11 +82,15 @@ static const UnitDependencyAtom atom_map[_UNIT_DEPENDENCY_MAX] = {
|
|||||||
[UNIT_PROPAGATES_STOP_TO] = UNIT_ATOM_RETROACTIVE_STOP_ON_STOP |
|
[UNIT_PROPAGATES_STOP_TO] = UNIT_ATOM_RETROACTIVE_STOP_ON_STOP |
|
||||||
UNIT_ATOM_PROPAGATE_STOP,
|
UNIT_ATOM_PROPAGATE_STOP,
|
||||||
|
|
||||||
|
[UNIT_ON_FAILURE] = UNIT_ATOM_ON_FAILURE |
|
||||||
|
UNIT_ATOM_BACK_REFERENCE_IMPLIED,
|
||||||
|
|
||||||
|
[UNIT_ON_SUCCESS] = UNIT_ATOM_ON_SUCCESS |
|
||||||
|
UNIT_ATOM_BACK_REFERENCE_IMPLIED,
|
||||||
|
|
||||||
/* These are simple dependency types: they consist of a single atom only */
|
/* These are simple dependency types: they consist of a single atom only */
|
||||||
[UNIT_BEFORE] = UNIT_ATOM_BEFORE,
|
[UNIT_BEFORE] = UNIT_ATOM_BEFORE,
|
||||||
[UNIT_AFTER] = UNIT_ATOM_AFTER,
|
[UNIT_AFTER] = UNIT_ATOM_AFTER,
|
||||||
[UNIT_ON_SUCCESS] = UNIT_ATOM_ON_SUCCESS,
|
|
||||||
[UNIT_ON_FAILURE] = UNIT_ATOM_ON_FAILURE,
|
|
||||||
[UNIT_TRIGGERS] = UNIT_ATOM_TRIGGERS,
|
[UNIT_TRIGGERS] = UNIT_ATOM_TRIGGERS,
|
||||||
[UNIT_TRIGGERED_BY] = UNIT_ATOM_TRIGGERED_BY,
|
[UNIT_TRIGGERED_BY] = UNIT_ATOM_TRIGGERED_BY,
|
||||||
[UNIT_PROPAGATES_RELOAD_TO] = UNIT_ATOM_PROPAGATES_RELOAD_TO,
|
[UNIT_PROPAGATES_RELOAD_TO] = UNIT_ATOM_PROPAGATES_RELOAD_TO,
|
||||||
@ -196,6 +200,16 @@ UnitDependency unit_dependency_from_unique_atom(UnitDependencyAtom atom) {
|
|||||||
case UNIT_ATOM_PROPAGATE_STOP_FAILURE:
|
case UNIT_ATOM_PROPAGATE_STOP_FAILURE:
|
||||||
return UNIT_CONFLICTED_BY;
|
return UNIT_CONFLICTED_BY;
|
||||||
|
|
||||||
|
case UNIT_ATOM_ON_FAILURE |
|
||||||
|
UNIT_ATOM_BACK_REFERENCE_IMPLIED:
|
||||||
|
case UNIT_ATOM_ON_FAILURE:
|
||||||
|
return UNIT_ON_FAILURE;
|
||||||
|
|
||||||
|
case UNIT_ATOM_ON_SUCCESS |
|
||||||
|
UNIT_ATOM_BACK_REFERENCE_IMPLIED:
|
||||||
|
case UNIT_ATOM_ON_SUCCESS:
|
||||||
|
return UNIT_ON_SUCCESS;
|
||||||
|
|
||||||
/* And now, the simple ones */
|
/* And now, the simple ones */
|
||||||
|
|
||||||
case UNIT_ATOM_BEFORE:
|
case UNIT_ATOM_BEFORE:
|
||||||
@ -204,12 +218,6 @@ UnitDependency unit_dependency_from_unique_atom(UnitDependencyAtom atom) {
|
|||||||
case UNIT_ATOM_AFTER:
|
case UNIT_ATOM_AFTER:
|
||||||
return UNIT_AFTER;
|
return UNIT_AFTER;
|
||||||
|
|
||||||
case UNIT_ATOM_ON_SUCCESS:
|
|
||||||
return UNIT_ON_SUCCESS;
|
|
||||||
|
|
||||||
case UNIT_ATOM_ON_FAILURE:
|
|
||||||
return UNIT_ON_FAILURE;
|
|
||||||
|
|
||||||
case UNIT_ATOM_TRIGGERS:
|
case UNIT_ATOM_TRIGGERS:
|
||||||
return UNIT_TRIGGERS;
|
return UNIT_TRIGGERS;
|
||||||
|
|
||||||
|
|||||||
@ -66,20 +66,27 @@ typedef enum UnitDependencyAtom {
|
|||||||
/* Recheck default target deps on other units (which are target units) */
|
/* Recheck default target deps on other units (which are target units) */
|
||||||
UNIT_ATOM_DEFAULT_TARGET_DEPENDENCIES = UINT64_C(1) << 21,
|
UNIT_ATOM_DEFAULT_TARGET_DEPENDENCIES = UINT64_C(1) << 21,
|
||||||
|
|
||||||
|
/* Dependencies which include this atom automatically get a reverse
|
||||||
|
* REFERENCES/REFERENCED_BY dependency. */
|
||||||
|
UNIT_ATOM_BACK_REFERENCE_IMPLIED = UINT64_C(1) << 22,
|
||||||
|
|
||||||
|
/* Trigger a dependency on successful service exit. */
|
||||||
|
UNIT_ATOM_ON_SUCCESS = UINT64_C(1) << 23,
|
||||||
|
/* Trigger a dependency on unsuccessful service exit. */
|
||||||
|
UNIT_ATOM_ON_FAILURE = UINT64_C(1) << 24,
|
||||||
|
|
||||||
/* The remaining atoms map 1:1 to the equally named high-level deps */
|
/* The remaining atoms map 1:1 to the equally named high-level deps */
|
||||||
UNIT_ATOM_BEFORE = UINT64_C(1) << 22,
|
UNIT_ATOM_BEFORE = UINT64_C(1) << 25,
|
||||||
UNIT_ATOM_AFTER = UINT64_C(1) << 23,
|
UNIT_ATOM_AFTER = UINT64_C(1) << 26,
|
||||||
UNIT_ATOM_ON_SUCCESS = UINT64_C(1) << 24,
|
UNIT_ATOM_TRIGGERS = UINT64_C(1) << 27,
|
||||||
UNIT_ATOM_ON_FAILURE = UINT64_C(1) << 25,
|
UNIT_ATOM_TRIGGERED_BY = UINT64_C(1) << 28,
|
||||||
UNIT_ATOM_TRIGGERS = UINT64_C(1) << 26,
|
UNIT_ATOM_PROPAGATES_RELOAD_TO = UINT64_C(1) << 29,
|
||||||
UNIT_ATOM_TRIGGERED_BY = UINT64_C(1) << 27,
|
UNIT_ATOM_JOINS_NAMESPACE_OF = UINT64_C(1) << 30,
|
||||||
UNIT_ATOM_PROPAGATES_RELOAD_TO = UINT64_C(1) << 28,
|
UNIT_ATOM_REFERENCES = UINT64_C(1) << 31,
|
||||||
UNIT_ATOM_JOINS_NAMESPACE_OF = UINT64_C(1) << 29,
|
UNIT_ATOM_REFERENCED_BY = UINT64_C(1) << 32,
|
||||||
UNIT_ATOM_REFERENCES = UINT64_C(1) << 30,
|
UNIT_ATOM_IN_SLICE = UINT64_C(1) << 33,
|
||||||
UNIT_ATOM_REFERENCED_BY = UINT64_C(1) << 31,
|
UNIT_ATOM_SLICE_OF = UINT64_C(1) << 34,
|
||||||
UNIT_ATOM_IN_SLICE = UINT64_C(1) << 32,
|
_UNIT_DEPENDENCY_ATOM_MAX = (UINT64_C(1) << 35) - 1,
|
||||||
UNIT_ATOM_SLICE_OF = UINT64_C(1) << 33,
|
|
||||||
_UNIT_DEPENDENCY_ATOM_MAX = (UINT64_C(1) << 34) - 1,
|
|
||||||
_UNIT_DEPENDENCY_ATOM_INVALID = -EINVAL,
|
_UNIT_DEPENDENCY_ATOM_INVALID = -EINVAL,
|
||||||
} UnitDependencyAtom;
|
} UnitDependencyAtom;
|
||||||
|
|
||||||
|
|||||||
@ -2222,17 +2222,24 @@ void unit_start_on_failure(
|
|||||||
|
|
||||||
UNIT_FOREACH_DEPENDENCY(other, u, atom) {
|
UNIT_FOREACH_DEPENDENCY(other, u, atom) {
|
||||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||||
|
Job *job = NULL;
|
||||||
|
|
||||||
if (!logged) {
|
if (!logged) {
|
||||||
log_unit_info(u, "Triggering %s dependencies.", dependency_name);
|
log_unit_info(u, "Triggering %s dependencies.", dependency_name);
|
||||||
logged = true;
|
logged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = manager_add_job(u->manager, JOB_START, other, job_mode, NULL, &error, NULL);
|
r = manager_add_job(u->manager, JOB_START, other, job_mode, NULL, &error, &job);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_unit_warning_errno(
|
log_unit_warning_errno(
|
||||||
u, r, "Failed to enqueue %s job, ignoring: %s",
|
u, r, "Failed to enqueue %s job, ignoring: %s",
|
||||||
dependency_name, bus_error_message(&error, r));
|
dependency_name, bus_error_message(&error, r));
|
||||||
|
else if (job)
|
||||||
|
/* u will be kept pinned since both UNIT_ON_FAILURE and UNIT_ON_SUCCESS includes
|
||||||
|
* UNIT_ATOM_BACK_REFERENCE_IMPLIED. We save the triggering unit here since we
|
||||||
|
* want to be able to reference it when we come to run the OnFailure= or OnSuccess=
|
||||||
|
* dependency. */
|
||||||
|
job_add_triggering_unit(job, u);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (logged)
|
if (logged)
|
||||||
@ -3114,6 +3121,20 @@ int unit_add_dependency(
|
|||||||
noop = false;
|
noop = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (FLAGS_SET(a, UNIT_ATOM_BACK_REFERENCE_IMPLIED)) {
|
||||||
|
r = unit_add_dependency_hashmap(&other->dependencies, UNIT_REFERENCES, u, 0, mask);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r)
|
||||||
|
noop = false;
|
||||||
|
|
||||||
|
r = unit_add_dependency_hashmap(&u->dependencies, UNIT_REFERENCED_BY, other, 0, mask);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
if (r)
|
||||||
|
noop = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (add_reference) {
|
if (add_reference) {
|
||||||
r = unit_add_dependency_hashmap(&u->dependencies, UNIT_REFERENCES, other, mask, 0);
|
r = unit_add_dependency_hashmap(&u->dependencies, UNIT_REFERENCES, other, mask, 0);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
|
|||||||
@ -242,6 +242,9 @@ typedef struct Unit {
|
|||||||
/* Queue of units that have a BindTo= dependency on some other unit, and should possibly be shut down */
|
/* Queue of units that have a BindTo= dependency on some other unit, and should possibly be shut down */
|
||||||
LIST_FIELDS(Unit, stop_when_bound_queue);
|
LIST_FIELDS(Unit, stop_when_bound_queue);
|
||||||
|
|
||||||
|
/* Queue of units which have triggered an OnFailure= or OnSuccess= dependency job. */
|
||||||
|
LIST_FIELDS(Unit, triggered_by);
|
||||||
|
|
||||||
/* PIDs we keep an eye on. Note that a unit might have many
|
/* PIDs we keep an eye on. Note that a unit might have many
|
||||||
* more, but these are the ones we care enough about to
|
* more, but these are the ones we care enough about to
|
||||||
* process SIGCHLD for */
|
* process SIGCHLD for */
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "glyph-util.h"
|
#include "glyph-util.h"
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "pcapng.h"
|
||||||
#include "string-util.h"
|
#include "string-util.h"
|
||||||
#include "strv.h"
|
#include "strv.h"
|
||||||
#include "terminal-util.h"
|
#include "terminal-util.h"
|
||||||
@ -502,57 +503,99 @@ int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static uint16_t pcapng_optlen(size_t len) {
|
||||||
* For details about the file format, see:
|
return ALIGN4(len + sizeof(struct pcapng_option));
|
||||||
*
|
}
|
||||||
* http://wiki.wireshark.org/Development/LibpcapFileFormat
|
|
||||||
*/
|
|
||||||
|
|
||||||
typedef struct _packed_ pcap_hdr_s {
|
static void pcapng_putopt(FILE *f, uint16_t code, const void *data, size_t len) {
|
||||||
uint32_t magic_number; /* magic number */
|
struct pcapng_option opt = {
|
||||||
uint16_t version_major; /* major version number */
|
.code = code,
|
||||||
uint16_t version_minor; /* minor version number */
|
.length = len,
|
||||||
int32_t thiszone; /* GMT to local correction */
|
|
||||||
uint32_t sigfigs; /* accuracy of timestamps */
|
|
||||||
uint32_t snaplen; /* max length of captured packets, in octets */
|
|
||||||
uint32_t network; /* data link type */
|
|
||||||
} pcap_hdr_t ;
|
|
||||||
|
|
||||||
typedef struct _packed_ pcaprec_hdr_s {
|
|
||||||
uint32_t ts_sec; /* timestamp seconds */
|
|
||||||
uint32_t ts_usec; /* timestamp microseconds */
|
|
||||||
uint32_t incl_len; /* number of octets of packet saved in file */
|
|
||||||
uint32_t orig_len; /* actual length of packet */
|
|
||||||
} pcaprec_hdr_t;
|
|
||||||
|
|
||||||
int bus_pcap_header(size_t snaplen, FILE *f) {
|
|
||||||
|
|
||||||
pcap_hdr_t hdr = {
|
|
||||||
.magic_number = 0xa1b2c3d4U,
|
|
||||||
.version_major = 2,
|
|
||||||
.version_minor = 4,
|
|
||||||
.thiszone = 0, /* UTC */
|
|
||||||
.sigfigs = 0,
|
|
||||||
.network = 231, /* D-Bus */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!f)
|
assert(f);
|
||||||
f = stdout;
|
assert((uint16_t) len == len);
|
||||||
|
assert(data || len == 0);
|
||||||
|
|
||||||
|
fwrite(&opt, 1, sizeof(opt), f);
|
||||||
|
if (len > 0) {
|
||||||
|
size_t pad = ALIGN4(len) - len;
|
||||||
|
|
||||||
|
fwrite(data, 1, len, f);
|
||||||
|
|
||||||
|
assert(pad < sizeof(uint32_t));
|
||||||
|
while (pad-- > 0)
|
||||||
|
fputc('\0', f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pcapng_section_header(FILE *f, const char *os, const char *app) {
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
assert(f);
|
||||||
|
|
||||||
|
/* determine length of section header and options */
|
||||||
|
len = sizeof(struct pcapng_section);
|
||||||
|
if (os)
|
||||||
|
len += pcapng_optlen(strlen(os));
|
||||||
|
if (app)
|
||||||
|
len += pcapng_optlen(strlen(app));
|
||||||
|
len += pcapng_optlen(0); /* OPT_END */
|
||||||
|
len += sizeof(uint32_t); /* trailer length */
|
||||||
|
|
||||||
|
struct pcapng_section hdr = {
|
||||||
|
.block_type = PCAPNG_SECTION_BLOCK,
|
||||||
|
.block_length = len,
|
||||||
|
.byte_order_magic = PCAPNG_BYTE_ORDER_MAGIC,
|
||||||
|
.major_version = PCAPNG_MAJOR_VERS,
|
||||||
|
.minor_version = PCAPNG_MINOR_VERS,
|
||||||
|
.section_length = UINT64_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
fwrite(&hdr, 1, sizeof(hdr), f);
|
||||||
|
if (os)
|
||||||
|
pcapng_putopt(f, PCAPNG_SHB_OS, os, strlen(os));
|
||||||
|
if (app)
|
||||||
|
pcapng_putopt(f, PCAPNG_SHB_USERAPPL, app, strlen(app));
|
||||||
|
pcapng_putopt(f, PCAPNG_OPT_END, NULL, 0);
|
||||||
|
fwrite(&len, 1, sizeof(uint32_t), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Only have a single instance of dbus pseudo interface */
|
||||||
|
static void pcapng_interface_header(FILE *f, size_t snaplen) {
|
||||||
|
uint32_t len;
|
||||||
|
|
||||||
|
assert(f);
|
||||||
assert(snaplen > 0);
|
assert(snaplen > 0);
|
||||||
assert((size_t) (uint32_t) snaplen == snaplen);
|
assert((size_t) (uint32_t) snaplen == snaplen);
|
||||||
|
|
||||||
hdr.snaplen = (uint32_t) snaplen;
|
/* no options (yet) */
|
||||||
|
len = sizeof(struct pcapng_interface_block) + sizeof(uint32_t);
|
||||||
|
struct pcapng_interface_block hdr = {
|
||||||
|
.block_type = PCAPNG_INTERFACE_BLOCK,
|
||||||
|
.block_length = len,
|
||||||
|
.link_type = 231, /* D-Bus */
|
||||||
|
.snap_len = snaplen,
|
||||||
|
};
|
||||||
|
|
||||||
fwrite(&hdr, 1, sizeof(hdr), f);
|
fwrite(&hdr, 1, sizeof(hdr), f);
|
||||||
|
fwrite(&len, 1, sizeof(uint32_t), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int bus_pcap_header(size_t snaplen, const char *os, const char *info, FILE *f) {
|
||||||
|
if (!f)
|
||||||
|
f = stdout;
|
||||||
|
|
||||||
|
pcapng_section_header(f, os, info);
|
||||||
|
pcapng_interface_header(f, snaplen);
|
||||||
return fflush_and_check(f);
|
return fflush_and_check(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
|
int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
|
||||||
struct bus_body_part *part;
|
struct bus_body_part *part;
|
||||||
pcaprec_hdr_t hdr = {};
|
size_t msglen, caplen, pad;
|
||||||
struct timeval tv;
|
uint32_t length;
|
||||||
|
uint64_t ts;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
size_t w;
|
size_t w;
|
||||||
|
|
||||||
@ -563,18 +606,27 @@ int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
|
|||||||
assert(snaplen > 0);
|
assert(snaplen > 0);
|
||||||
assert((size_t) (uint32_t) snaplen == snaplen);
|
assert((size_t) (uint32_t) snaplen == snaplen);
|
||||||
|
|
||||||
if (m->realtime != 0)
|
ts = m->realtime ?: now(CLOCK_REALTIME);
|
||||||
timeval_store(&tv, m->realtime);
|
msglen = BUS_MESSAGE_SIZE(m);
|
||||||
else
|
caplen = MIN(msglen, snaplen);
|
||||||
assert_se(gettimeofday(&tv, NULL) >= 0);
|
pad = ALIGN4(caplen) - caplen;
|
||||||
|
|
||||||
hdr.ts_sec = tv.tv_sec;
|
/* packet block has no options */
|
||||||
hdr.ts_usec = tv.tv_usec;
|
length = sizeof(struct pcapng_enhance_packet_block)
|
||||||
hdr.orig_len = BUS_MESSAGE_SIZE(m);
|
+ caplen + pad + sizeof(uint32_t);
|
||||||
hdr.incl_len = MIN(hdr.orig_len, snaplen);
|
|
||||||
|
|
||||||
/* write the pcap header */
|
struct pcapng_enhance_packet_block epb = {
|
||||||
fwrite(&hdr, 1, sizeof(hdr), f);
|
.block_type = PCAPNG_ENHANCED_PACKET_BLOCK,
|
||||||
|
.block_length = length,
|
||||||
|
.interface_id = 0,
|
||||||
|
.timestamp_hi = (uint32_t)(ts >> 32),
|
||||||
|
.timestamp_lo = (uint32_t)ts,
|
||||||
|
.original_length = msglen,
|
||||||
|
.capture_length = caplen,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* write the pcapng enhanced packet block header */
|
||||||
|
fwrite(&epb, 1, sizeof(epb), f);
|
||||||
|
|
||||||
/* write the dbus header */
|
/* write the dbus header */
|
||||||
w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
|
w = MIN(BUS_MESSAGE_BODY_BEGIN(m), snaplen);
|
||||||
@ -591,5 +643,11 @@ int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f) {
|
|||||||
snaplen -= w;
|
snaplen -= w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (pad-- > 0)
|
||||||
|
fputc('\0', f);
|
||||||
|
|
||||||
|
/* trailing block length */
|
||||||
|
fwrite(&length, 1, sizeof(uint32_t), f);
|
||||||
|
|
||||||
return fflush_and_check(f);
|
return fflush_and_check(f);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,5 +8,5 @@
|
|||||||
|
|
||||||
int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse);
|
int bus_creds_dump(sd_bus_creds *c, FILE *f, bool terse);
|
||||||
|
|
||||||
int bus_pcap_header(size_t snaplen, FILE *f);
|
int bus_pcap_header(size_t snaplen, const char *os, const char *app, FILE *f);
|
||||||
int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f);
|
int bus_message_pcap_frame(sd_bus_message *m, size_t snaplen, FILE *f);
|
||||||
|
|||||||
@ -20,6 +20,8 @@ sources = files('''
|
|||||||
netdev/macvlan.c
|
netdev/macvlan.c
|
||||||
netdev/macvlan.h
|
netdev/macvlan.h
|
||||||
netdev/netdev.c
|
netdev/netdev.c
|
||||||
|
netdev/netdev-util.c
|
||||||
|
netdev/netdev-util.h
|
||||||
netdev/netdev.h
|
netdev/netdev.h
|
||||||
netdev/nlmon.c
|
netdev/nlmon.c
|
||||||
netdev/nlmon.h
|
netdev/nlmon.h
|
||||||
|
|||||||
@ -68,8 +68,8 @@ IPVLAN.Mode, config_parse_ipvlan_mode,
|
|||||||
IPVLAN.Flags, config_parse_ipvlan_flags, 0, offsetof(IPVlan, flags)
|
IPVLAN.Flags, config_parse_ipvlan_flags, 0, offsetof(IPVlan, flags)
|
||||||
IPVTAP.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode)
|
IPVTAP.Mode, config_parse_ipvlan_mode, 0, offsetof(IPVlan, mode)
|
||||||
IPVTAP.Flags, config_parse_ipvlan_flags, 0, offsetof(IPVlan, flags)
|
IPVTAP.Flags, config_parse_ipvlan_flags, 0, offsetof(IPVlan, flags)
|
||||||
Tunnel.Local, config_parse_tunnel_address, 0, offsetof(Tunnel, local)
|
Tunnel.Local, config_parse_tunnel_local_address, 0, 0
|
||||||
Tunnel.Remote, config_parse_tunnel_address, 0, offsetof(Tunnel, remote)
|
Tunnel.Remote, config_parse_tunnel_remote_address, 0, 0
|
||||||
Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos)
|
Tunnel.TOS, config_parse_unsigned, 0, offsetof(Tunnel, tos)
|
||||||
Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl)
|
Tunnel.TTL, config_parse_unsigned, 0, offsetof(Tunnel, ttl)
|
||||||
Tunnel.Key, config_parse_tunnel_key, 0, offsetof(Tunnel, key)
|
Tunnel.Key, config_parse_tunnel_key, 0, offsetof(Tunnel, key)
|
||||||
|
|||||||
97
src/network/netdev/netdev-util.c
Normal file
97
src/network/netdev/netdev-util.c
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
|
||||||
|
#include "netdev-util.h"
|
||||||
|
#include "networkd-address.h"
|
||||||
|
#include "networkd-link.h"
|
||||||
|
#include "string-table.h"
|
||||||
|
|
||||||
|
static const char * const netdev_local_address_type_table[_NETDEV_LOCAL_ADDRESS_TYPE_MAX] = {
|
||||||
|
[NETDEV_LOCAL_ADDRESS_IPV4LL] = "ipv4_link_local",
|
||||||
|
[NETDEV_LOCAL_ADDRESS_IPV6LL] = "ipv6_link_local",
|
||||||
|
[NETDEV_LOCAL_ADDRESS_DHCP4] = "dhcp4",
|
||||||
|
[NETDEV_LOCAL_ADDRESS_DHCP6] = "dhcp6",
|
||||||
|
[NETDEV_LOCAL_ADDRESS_SLAAC] = "slaac",
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFINE_STRING_TABLE_LOOKUP(netdev_local_address_type, NetDevLocalAddressType);
|
||||||
|
|
||||||
|
int link_get_local_address(
|
||||||
|
Link *link,
|
||||||
|
NetDevLocalAddressType type,
|
||||||
|
int family,
|
||||||
|
int *ret_family,
|
||||||
|
union in_addr_union *ret_address) {
|
||||||
|
|
||||||
|
Address *a;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case NETDEV_LOCAL_ADDRESS_IPV4LL:
|
||||||
|
assert(IN_SET(family, AF_UNSPEC, AF_INET));
|
||||||
|
family = AF_INET;
|
||||||
|
break;
|
||||||
|
case NETDEV_LOCAL_ADDRESS_IPV6LL:
|
||||||
|
assert(IN_SET(family, AF_UNSPEC, AF_INET6));
|
||||||
|
family = AF_INET6;
|
||||||
|
break;
|
||||||
|
case NETDEV_LOCAL_ADDRESS_DHCP4:
|
||||||
|
assert(IN_SET(family, AF_UNSPEC, AF_INET));
|
||||||
|
family = AF_INET;
|
||||||
|
break;
|
||||||
|
case NETDEV_LOCAL_ADDRESS_DHCP6:
|
||||||
|
assert(IN_SET(family, AF_UNSPEC, AF_INET6));
|
||||||
|
family = AF_INET6;
|
||||||
|
break;
|
||||||
|
case NETDEV_LOCAL_ADDRESS_SLAAC:
|
||||||
|
assert(IN_SET(family, AF_UNSPEC, AF_INET6));
|
||||||
|
family = AF_INET6;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
SET_FOREACH(a, link->addresses) {
|
||||||
|
if (!address_exists(a))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (a->family != family)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (in_addr_is_set(a->family, &a->in_addr_peer))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case NETDEV_LOCAL_ADDRESS_IPV4LL:
|
||||||
|
if (a->source != NETWORK_CONFIG_SOURCE_IPV4LL)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case NETDEV_LOCAL_ADDRESS_IPV6LL:
|
||||||
|
if (!in6_addr_is_link_local(&a->in_addr.in6))
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case NETDEV_LOCAL_ADDRESS_DHCP4:
|
||||||
|
if (a->source != NETWORK_CONFIG_SOURCE_DHCP4)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case NETDEV_LOCAL_ADDRESS_DHCP6:
|
||||||
|
if (a->source != NETWORK_CONFIG_SOURCE_DHCP6)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
case NETDEV_LOCAL_ADDRESS_SLAAC:
|
||||||
|
if (a->source != NETWORK_CONFIG_SOURCE_NDISC)
|
||||||
|
continue;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
assert_not_reached();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret_family)
|
||||||
|
*ret_family = a->family;
|
||||||
|
if (ret_address)
|
||||||
|
*ret_address = a->in_addr;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -ENXIO;
|
||||||
|
}
|
||||||
27
src/network/netdev/netdev-util.h
Normal file
27
src/network/netdev/netdev-util.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "in-addr-util.h"
|
||||||
|
#include "macro.h"
|
||||||
|
|
||||||
|
typedef struct Link Link;
|
||||||
|
|
||||||
|
typedef enum NetDevLocalAddressType {
|
||||||
|
NETDEV_LOCAL_ADDRESS_IPV4LL,
|
||||||
|
NETDEV_LOCAL_ADDRESS_IPV6LL,
|
||||||
|
NETDEV_LOCAL_ADDRESS_DHCP4,
|
||||||
|
NETDEV_LOCAL_ADDRESS_DHCP6,
|
||||||
|
NETDEV_LOCAL_ADDRESS_SLAAC,
|
||||||
|
_NETDEV_LOCAL_ADDRESS_TYPE_MAX,
|
||||||
|
_NETDEV_LOCAL_ADDRESS_TYPE_INVALID = -EINVAL,
|
||||||
|
} NetDevLocalAddressType;
|
||||||
|
|
||||||
|
const char *netdev_local_address_type_to_string(NetDevLocalAddressType t) _const_;
|
||||||
|
NetDevLocalAddressType netdev_local_address_type_from_string(const char *s) _pure_;
|
||||||
|
|
||||||
|
int link_get_local_address(
|
||||||
|
Link *link,
|
||||||
|
NetDevLocalAddressType type,
|
||||||
|
int family,
|
||||||
|
int *ret_family,
|
||||||
|
union in_addr_union *ret_address);
|
||||||
@ -628,6 +628,9 @@ static bool netdev_is_ready_to_create(NetDev *netdev, Link *link) {
|
|||||||
if (link->set_link_messages > 0)
|
if (link->set_link_messages > 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (NETDEV_VTABLE(netdev)->is_ready_to_create)
|
||||||
|
return NETDEV_VTABLE(netdev)->is_ready_to_create(netdev, link);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -153,6 +153,9 @@ typedef struct NetDevVTable {
|
|||||||
/* specifies if netdev is independent, or a master device or a stacked device */
|
/* specifies if netdev is independent, or a master device or a stacked device */
|
||||||
NetDevCreateType create_type;
|
NetDevCreateType create_type;
|
||||||
|
|
||||||
|
/* This is used for stacked netdev. Return true when the underlying link is ready. */
|
||||||
|
int (*is_ready_to_create)(NetDev *netdev, Link *link);
|
||||||
|
|
||||||
/* create netdev, if not done via rtnl */
|
/* create netdev, if not done via rtnl */
|
||||||
int (*create)(NetDev *netdev);
|
int (*create)(NetDev *netdev);
|
||||||
|
|
||||||
|
|||||||
@ -168,7 +168,20 @@ int dhcp4_pd_create_6rd_tunnel(Link *link, link_netlink_message_handler_t callba
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tunnel_get_local_address(Tunnel *t, Link *link, union in_addr_union *ret) {
|
||||||
|
assert(t);
|
||||||
|
|
||||||
|
if (t->local_type < 0) {
|
||||||
|
if (ret)
|
||||||
|
*ret = t->local;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return link_get_local_address(link, t->local_type, t->family, NULL, ret);
|
||||||
|
}
|
||||||
|
|
||||||
static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||||
|
union in_addr_union local;
|
||||||
Tunnel *t;
|
Tunnel *t;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -188,7 +201,11 @@ static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_ne
|
|||||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
|
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &t->local.in);
|
r = tunnel_get_local_address(t, link, &local);
|
||||||
|
if (r < 0)
|
||||||
|
return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
|
||||||
|
|
||||||
|
r = sd_netlink_message_append_in_addr(m, IFLA_IPTUN_LOCAL, &local.in);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
|
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
|
||||||
|
|
||||||
@ -247,6 +264,7 @@ static int netdev_ipip_sit_fill_message_create(NetDev *netdev, Link *link, sd_ne
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||||
|
union in_addr_union local;
|
||||||
uint32_t ikey = 0;
|
uint32_t ikey = 0;
|
||||||
uint32_t okey = 0;
|
uint32_t okey = 0;
|
||||||
uint16_t iflags = 0;
|
uint16_t iflags = 0;
|
||||||
@ -285,7 +303,11 @@ static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_
|
|||||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ERSPAN_INDEX attribute: %m");
|
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_ERSPAN_INDEX attribute: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &t->local.in);
|
r = tunnel_get_local_address(t, link, &local);
|
||||||
|
if (r < 0)
|
||||||
|
return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
|
||||||
|
|
||||||
|
r = sd_netlink_message_append_in_addr(m, IFLA_GRE_LOCAL, &local.in);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
|
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
|
||||||
|
|
||||||
@ -363,6 +385,7 @@ static int netdev_gre_erspan_fill_message_create(NetDev *netdev, Link *link, sd_
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||||
|
union in_addr_union local;
|
||||||
uint32_t ikey = 0;
|
uint32_t ikey = 0;
|
||||||
uint32_t okey = 0;
|
uint32_t okey = 0;
|
||||||
uint16_t iflags = 0;
|
uint16_t iflags = 0;
|
||||||
@ -386,7 +409,11 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl
|
|||||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
|
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LINK attribute: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &t->local.in6);
|
r = tunnel_get_local_address(t, link, &local);
|
||||||
|
if (r < 0)
|
||||||
|
return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
|
||||||
|
|
||||||
|
r = sd_netlink_message_append_in6_addr(m, IFLA_GRE_LOCAL, &local.in6);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
|
return log_netdev_error_errno(netdev, r, "Could not append IFLA_GRE_LOCAL attribute: %m");
|
||||||
|
|
||||||
@ -444,6 +471,7 @@ static int netdev_ip6gre_fill_message_create(NetDev *netdev, Link *link, sd_netl
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||||
|
union in_addr_union local;
|
||||||
uint32_t ikey, okey;
|
uint32_t ikey, okey;
|
||||||
Tunnel *t;
|
Tunnel *t;
|
||||||
int r;
|
int r;
|
||||||
@ -479,7 +507,11 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_OKEY attribute: %m");
|
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_OKEY attribute: %m");
|
||||||
|
|
||||||
r = netlink_message_append_in_addr_union(m, IFLA_VTI_LOCAL, t->family, &t->local);
|
r = tunnel_get_local_address(t, link, &local);
|
||||||
|
if (r < 0)
|
||||||
|
return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
|
||||||
|
|
||||||
|
r = netlink_message_append_in_addr_union(m, IFLA_VTI_LOCAL, t->family, &local);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_LOCAL attribute: %m");
|
return log_netdev_error_errno(netdev, r, "Could not append IFLA_VTI_LOCAL attribute: %m");
|
||||||
|
|
||||||
@ -491,6 +523,7 @@ static int netdev_vti_fill_message_create(NetDev *netdev, Link *link, sd_netlink
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netlink_message *m) {
|
||||||
|
union in_addr_union local;
|
||||||
uint8_t proto;
|
uint8_t proto;
|
||||||
Tunnel *t;
|
Tunnel *t;
|
||||||
int r;
|
int r;
|
||||||
@ -508,7 +541,11 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl
|
|||||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
|
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LINK attribute: %m");
|
||||||
}
|
}
|
||||||
|
|
||||||
r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &t->local.in6);
|
r = tunnel_get_local_address(t, link, &local);
|
||||||
|
if (r < 0)
|
||||||
|
return log_netdev_error_errno(netdev, r, "Could not find local address: %m");
|
||||||
|
|
||||||
|
r = sd_netlink_message_append_in6_addr(m, IFLA_IPTUN_LOCAL, &local.in6);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
|
return log_netdev_error_errno(netdev, r, "Could not append IFLA_IPTUN_LOCAL attribute: %m");
|
||||||
|
|
||||||
@ -562,6 +599,19 @@ static int netdev_ip6tnl_fill_message_create(NetDev *netdev, Link *link, sd_netl
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int netdev_tunnel_is_ready_to_create(NetDev *netdev, Link *link) {
|
||||||
|
Tunnel *t;
|
||||||
|
|
||||||
|
assert(netdev);
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
t = TUNNEL(netdev);
|
||||||
|
|
||||||
|
assert(t);
|
||||||
|
|
||||||
|
return tunnel_get_local_address(t, link, NULL) >= 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
|
static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
|
||||||
Tunnel *t;
|
Tunnel *t;
|
||||||
|
|
||||||
@ -611,10 +661,15 @@ static int netdev_tunnel_verify(NetDev *netdev, const char *filename) {
|
|||||||
if (t->assign_to_loopback)
|
if (t->assign_to_loopback)
|
||||||
t->independent = true;
|
t->independent = true;
|
||||||
|
|
||||||
|
if (t->independent && t->local_type >= 0)
|
||||||
|
return log_netdev_error_errno(netdev, SYNTHETIC_ERRNO(EINVAL),
|
||||||
|
"The local address cannot be '%s' when Independent= or AssignToLoopback= is enabled, ignoring.",
|
||||||
|
strna(netdev_local_address_type_to_string(t->local_type)));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_parse_tunnel_address(
|
int config_parse_tunnel_local_address(
|
||||||
const char *unit,
|
const char *unit,
|
||||||
const char *filename,
|
const char *filename,
|
||||||
unsigned line,
|
unsigned line,
|
||||||
@ -626,28 +681,82 @@ int config_parse_tunnel_address(
|
|||||||
void *data,
|
void *data,
|
||||||
void *userdata) {
|
void *userdata) {
|
||||||
|
|
||||||
|
union in_addr_union buffer = IN_ADDR_NULL;
|
||||||
|
NetDevLocalAddressType type;
|
||||||
Tunnel *t = userdata;
|
Tunnel *t = userdata;
|
||||||
union in_addr_union *addr = data, buffer;
|
|
||||||
int r, f;
|
int r, f;
|
||||||
|
|
||||||
assert(filename);
|
assert(filename);
|
||||||
assert(lvalue);
|
assert(lvalue);
|
||||||
assert(rvalue);
|
assert(rvalue);
|
||||||
assert(data);
|
assert(userdata);
|
||||||
|
|
||||||
/* This is used to parse addresses on both local and remote ends of the tunnel.
|
if (isempty(rvalue) || streq(rvalue, "any")) {
|
||||||
* Address families must match.
|
/* Unset the previous assignment. */
|
||||||
*
|
t->local = IN_ADDR_NULL;
|
||||||
* "any" is a special value which means that the address is unspecified.
|
t->local_type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
|
||||||
*/
|
|
||||||
|
|
||||||
if (streq(rvalue, "any")) {
|
/* If the remote address is not specified, also clear the address family. */
|
||||||
*addr = IN_ADDR_NULL;
|
if (!in_addr_is_set(t->family, &t->remote))
|
||||||
|
t->family = AF_UNSPEC;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* As a special case, if both the local and remote addresses are
|
type = netdev_local_address_type_from_string(rvalue);
|
||||||
* unspecified, also clear the address family. */
|
if (IN_SET(type, NETDEV_LOCAL_ADDRESS_IPV4LL, NETDEV_LOCAL_ADDRESS_DHCP4))
|
||||||
if (!in_addr_is_set(t->family, &t->local) &&
|
f = AF_INET;
|
||||||
!in_addr_is_set(t->family, &t->remote))
|
else if (IN_SET(type, NETDEV_LOCAL_ADDRESS_IPV6LL, NETDEV_LOCAL_ADDRESS_DHCP6, NETDEV_LOCAL_ADDRESS_SLAAC))
|
||||||
|
f = AF_INET6;
|
||||||
|
else {
|
||||||
|
type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
|
||||||
|
r = in_addr_from_string_auto(rvalue, &f, &buffer);
|
||||||
|
if (r < 0) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, r,
|
||||||
|
"Tunnel address \"%s\" invalid, ignoring assignment: %m", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (t->family != AF_UNSPEC && t->family != f) {
|
||||||
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||||
|
"Address family does not match the previous assignment, ignoring assignment: %s", rvalue);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
t->family = f;
|
||||||
|
t->local = buffer;
|
||||||
|
t->local_type = type;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int config_parse_tunnel_remote_address(
|
||||||
|
const char *unit,
|
||||||
|
const char *filename,
|
||||||
|
unsigned line,
|
||||||
|
const char *section,
|
||||||
|
unsigned section_line,
|
||||||
|
const char *lvalue,
|
||||||
|
int ltype,
|
||||||
|
const char *rvalue,
|
||||||
|
void *data,
|
||||||
|
void *userdata) {
|
||||||
|
|
||||||
|
union in_addr_union buffer;
|
||||||
|
Tunnel *t = userdata;
|
||||||
|
int r, f;
|
||||||
|
|
||||||
|
assert(filename);
|
||||||
|
assert(lvalue);
|
||||||
|
assert(rvalue);
|
||||||
|
assert(userdata);
|
||||||
|
|
||||||
|
if (isempty(rvalue) || streq(rvalue, "any")) {
|
||||||
|
/* Unset the previous assignment. */
|
||||||
|
t->remote = IN_ADDR_NULL;
|
||||||
|
|
||||||
|
/* If the local address is not specified, also clear the address family. */
|
||||||
|
if (t->local_type == _NETDEV_LOCAL_ADDRESS_TYPE_INVALID &&
|
||||||
|
!in_addr_is_set(t->family, &t->local))
|
||||||
t->family = AF_UNSPEC;
|
t->family = AF_UNSPEC;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -661,12 +770,12 @@ int config_parse_tunnel_address(
|
|||||||
|
|
||||||
if (t->family != AF_UNSPEC && t->family != f) {
|
if (t->family != AF_UNSPEC && t->family != f) {
|
||||||
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
log_syntax(unit, LOG_WARNING, filename, line, 0,
|
||||||
"Tunnel addresses incompatible, ignoring assignment: %s", rvalue);
|
"Address family does not match the previous assignment, ignoring assignment: %s", rvalue);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
t->family = f;
|
t->family = f;
|
||||||
*addr = buffer;
|
t->remote = buffer;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -840,6 +949,7 @@ static void netdev_tunnel_init(NetDev *netdev) {
|
|||||||
|
|
||||||
assert(t);
|
assert(t);
|
||||||
|
|
||||||
|
t->local_type = _NETDEV_LOCAL_ADDRESS_TYPE_INVALID;
|
||||||
t->pmtudisc = true;
|
t->pmtudisc = true;
|
||||||
t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT;
|
t->fou_encap_type = NETDEV_FOO_OVER_UDP_ENCAP_DIRECT;
|
||||||
t->isatap = -1;
|
t->isatap = -1;
|
||||||
@ -859,6 +969,7 @@ const NetDevVTable ipip_vtable = {
|
|||||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||||
.fill_message_create = netdev_ipip_sit_fill_message_create,
|
.fill_message_create = netdev_ipip_sit_fill_message_create,
|
||||||
.create_type = NETDEV_CREATE_STACKED,
|
.create_type = NETDEV_CREATE_STACKED,
|
||||||
|
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||||
.config_verify = netdev_tunnel_verify,
|
.config_verify = netdev_tunnel_verify,
|
||||||
.iftype = ARPHRD_TUNNEL,
|
.iftype = ARPHRD_TUNNEL,
|
||||||
};
|
};
|
||||||
@ -869,6 +980,7 @@ const NetDevVTable sit_vtable = {
|
|||||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||||
.fill_message_create = netdev_ipip_sit_fill_message_create,
|
.fill_message_create = netdev_ipip_sit_fill_message_create,
|
||||||
.create_type = NETDEV_CREATE_STACKED,
|
.create_type = NETDEV_CREATE_STACKED,
|
||||||
|
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||||
.config_verify = netdev_tunnel_verify,
|
.config_verify = netdev_tunnel_verify,
|
||||||
.iftype = ARPHRD_SIT,
|
.iftype = ARPHRD_SIT,
|
||||||
};
|
};
|
||||||
@ -879,6 +991,7 @@ const NetDevVTable vti_vtable = {
|
|||||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||||
.fill_message_create = netdev_vti_fill_message_create,
|
.fill_message_create = netdev_vti_fill_message_create,
|
||||||
.create_type = NETDEV_CREATE_STACKED,
|
.create_type = NETDEV_CREATE_STACKED,
|
||||||
|
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||||
.config_verify = netdev_tunnel_verify,
|
.config_verify = netdev_tunnel_verify,
|
||||||
.iftype = ARPHRD_TUNNEL,
|
.iftype = ARPHRD_TUNNEL,
|
||||||
};
|
};
|
||||||
@ -889,6 +1002,7 @@ const NetDevVTable vti6_vtable = {
|
|||||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||||
.fill_message_create = netdev_vti_fill_message_create,
|
.fill_message_create = netdev_vti_fill_message_create,
|
||||||
.create_type = NETDEV_CREATE_STACKED,
|
.create_type = NETDEV_CREATE_STACKED,
|
||||||
|
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||||
.config_verify = netdev_tunnel_verify,
|
.config_verify = netdev_tunnel_verify,
|
||||||
.iftype = ARPHRD_TUNNEL6,
|
.iftype = ARPHRD_TUNNEL6,
|
||||||
};
|
};
|
||||||
@ -899,6 +1013,7 @@ const NetDevVTable gre_vtable = {
|
|||||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||||
.fill_message_create = netdev_gre_erspan_fill_message_create,
|
.fill_message_create = netdev_gre_erspan_fill_message_create,
|
||||||
.create_type = NETDEV_CREATE_STACKED,
|
.create_type = NETDEV_CREATE_STACKED,
|
||||||
|
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||||
.config_verify = netdev_tunnel_verify,
|
.config_verify = netdev_tunnel_verify,
|
||||||
.iftype = ARPHRD_IPGRE,
|
.iftype = ARPHRD_IPGRE,
|
||||||
};
|
};
|
||||||
@ -909,6 +1024,7 @@ const NetDevVTable gretap_vtable = {
|
|||||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||||
.fill_message_create = netdev_gre_erspan_fill_message_create,
|
.fill_message_create = netdev_gre_erspan_fill_message_create,
|
||||||
.create_type = NETDEV_CREATE_STACKED,
|
.create_type = NETDEV_CREATE_STACKED,
|
||||||
|
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||||
.config_verify = netdev_tunnel_verify,
|
.config_verify = netdev_tunnel_verify,
|
||||||
.iftype = ARPHRD_ETHER,
|
.iftype = ARPHRD_ETHER,
|
||||||
.generate_mac = true,
|
.generate_mac = true,
|
||||||
@ -920,6 +1036,7 @@ const NetDevVTable ip6gre_vtable = {
|
|||||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||||
.fill_message_create = netdev_ip6gre_fill_message_create,
|
.fill_message_create = netdev_ip6gre_fill_message_create,
|
||||||
.create_type = NETDEV_CREATE_STACKED,
|
.create_type = NETDEV_CREATE_STACKED,
|
||||||
|
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||||
.config_verify = netdev_tunnel_verify,
|
.config_verify = netdev_tunnel_verify,
|
||||||
.iftype = ARPHRD_IP6GRE,
|
.iftype = ARPHRD_IP6GRE,
|
||||||
};
|
};
|
||||||
@ -930,6 +1047,7 @@ const NetDevVTable ip6gretap_vtable = {
|
|||||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||||
.fill_message_create = netdev_ip6gre_fill_message_create,
|
.fill_message_create = netdev_ip6gre_fill_message_create,
|
||||||
.create_type = NETDEV_CREATE_STACKED,
|
.create_type = NETDEV_CREATE_STACKED,
|
||||||
|
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||||
.config_verify = netdev_tunnel_verify,
|
.config_verify = netdev_tunnel_verify,
|
||||||
.iftype = ARPHRD_ETHER,
|
.iftype = ARPHRD_ETHER,
|
||||||
.generate_mac = true,
|
.generate_mac = true,
|
||||||
@ -941,6 +1059,7 @@ const NetDevVTable ip6tnl_vtable = {
|
|||||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||||
.fill_message_create = netdev_ip6tnl_fill_message_create,
|
.fill_message_create = netdev_ip6tnl_fill_message_create,
|
||||||
.create_type = NETDEV_CREATE_STACKED,
|
.create_type = NETDEV_CREATE_STACKED,
|
||||||
|
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||||
.config_verify = netdev_tunnel_verify,
|
.config_verify = netdev_tunnel_verify,
|
||||||
.iftype = ARPHRD_TUNNEL6,
|
.iftype = ARPHRD_TUNNEL6,
|
||||||
};
|
};
|
||||||
@ -951,6 +1070,7 @@ const NetDevVTable erspan_vtable = {
|
|||||||
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
.sections = NETDEV_COMMON_SECTIONS "Tunnel\0",
|
||||||
.fill_message_create = netdev_gre_erspan_fill_message_create,
|
.fill_message_create = netdev_gre_erspan_fill_message_create,
|
||||||
.create_type = NETDEV_CREATE_STACKED,
|
.create_type = NETDEV_CREATE_STACKED,
|
||||||
|
.is_ready_to_create = netdev_tunnel_is_ready_to_create,
|
||||||
.config_verify = netdev_tunnel_verify,
|
.config_verify = netdev_tunnel_verify,
|
||||||
.iftype = ARPHRD_ETHER,
|
.iftype = ARPHRD_ETHER,
|
||||||
.generate_mac = true,
|
.generate_mac = true,
|
||||||
|
|||||||
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include "conf-parser.h"
|
#include "conf-parser.h"
|
||||||
#include "fou-tunnel.h"
|
#include "fou-tunnel.h"
|
||||||
|
#include "netdev-util.h"
|
||||||
#include "netdev.h"
|
#include "netdev.h"
|
||||||
#include "networkd-link.h"
|
#include "networkd-link.h"
|
||||||
|
|
||||||
@ -42,6 +43,7 @@ typedef struct Tunnel {
|
|||||||
uint32_t okey;
|
uint32_t okey;
|
||||||
uint32_t erspan_index;
|
uint32_t erspan_index;
|
||||||
|
|
||||||
|
NetDevLocalAddressType local_type;
|
||||||
union in_addr_union local;
|
union in_addr_union local;
|
||||||
union in_addr_union remote;
|
union in_addr_union remote;
|
||||||
|
|
||||||
@ -119,7 +121,8 @@ const char *ip6tnl_mode_to_string(Ip6TnlMode d) _const_;
|
|||||||
Ip6TnlMode ip6tnl_mode_from_string(const char *d) _pure_;
|
Ip6TnlMode ip6tnl_mode_from_string(const char *d) _pure_;
|
||||||
|
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_ip6tnl_mode);
|
CONFIG_PARSER_PROTOTYPE(config_parse_ip6tnl_mode);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_tunnel_address);
|
CONFIG_PARSER_PROTOTYPE(config_parse_tunnel_local_address);
|
||||||
|
CONFIG_PARSER_PROTOTYPE(config_parse_tunnel_remote_address);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_flowlabel);
|
CONFIG_PARSER_PROTOTYPE(config_parse_ipv6_flowlabel);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_encap_limit);
|
CONFIG_PARSER_PROTOTYPE(config_parse_encap_limit);
|
||||||
CONFIG_PARSER_PROTOTYPE(config_parse_tunnel_key);
|
CONFIG_PARSER_PROTOTYPE(config_parse_tunnel_key);
|
||||||
|
|||||||
@ -2550,6 +2550,23 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_link_debug_errno(link, r, "Failed to get driver, continuing without: %m");
|
log_link_debug_errno(link, r, "Failed to get driver, continuing without: %m");
|
||||||
|
|
||||||
|
if (streq_ptr(link->driver, "dsa")) {
|
||||||
|
uint32_t dsa_master_ifindex;
|
||||||
|
|
||||||
|
r = sd_netlink_message_read_u32(message, IFLA_LINK, &dsa_master_ifindex);
|
||||||
|
if (r < 0) {
|
||||||
|
dsa_master_ifindex = 0;
|
||||||
|
if (r != -ENODATA)
|
||||||
|
log_link_warning_errno(link, r, "rtnl: failed to read ifindex of the DSA master interface, ignoring: %m");
|
||||||
|
} else if (dsa_master_ifindex > INT_MAX) {
|
||||||
|
dsa_master_ifindex = 0;
|
||||||
|
log_link_warning(link, "rtnl: received too large DSA master ifindex (%"PRIu32" > INT_MAX), ignoring.",
|
||||||
|
dsa_master_ifindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
link->dsa_master_ifindex = (int) dsa_master_ifindex;
|
||||||
|
}
|
||||||
|
|
||||||
*ret = TAKE_PTR(link);
|
*ret = TAKE_PTR(link);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,6 +48,7 @@ typedef struct Link {
|
|||||||
|
|
||||||
int ifindex;
|
int ifindex;
|
||||||
int master_ifindex;
|
int master_ifindex;
|
||||||
|
int dsa_master_ifindex;
|
||||||
char *ifname;
|
char *ifname;
|
||||||
char **alternative_names;
|
char **alternative_names;
|
||||||
char *kind;
|
char *kind;
|
||||||
|
|||||||
@ -948,7 +948,42 @@ int link_configure_mtu(Link *link) {
|
|||||||
return link_request_to_set_mtu(link, mtu);
|
return link_request_to_set_mtu(link, mtu);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool up, bool check_ready) {
|
static int link_up_dsa_slave(Link *link) {
|
||||||
|
Link *master;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
assert(link);
|
||||||
|
|
||||||
|
/* For older kernels (specifically, older than 9d5ef190e5615a7b63af89f88c4106a5bc127974, kernel-5.12),
|
||||||
|
* it is necessary to bring up a DSA slave that its master interface is already up. And bringing up
|
||||||
|
* the slave fails with -ENETDOWN. So, let's bring up the master even if it is not managed by us,
|
||||||
|
* and try to bring up the slave after the master becomes up. */
|
||||||
|
|
||||||
|
if (link->dsa_master_ifindex <= 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!streq_ptr(link->driver, "dsa"))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (link_get_by_index(link->manager, link->dsa_master_ifindex, &master) < 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (master->state == LINK_STATE_UNMANAGED) {
|
||||||
|
/* If the DSA master interface is unmanaged, then it will never become up.
|
||||||
|
* Let's request to bring up the master. */
|
||||||
|
r = link_request_to_bring_up_or_down(master, /* up = */ true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = link_request_to_bring_up_or_down(link, /* up = */ true);
|
||||||
|
if (r < 0)
|
||||||
|
return r;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, bool up, bool on_activate) {
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
assert(m);
|
assert(m);
|
||||||
@ -958,10 +993,19 @@ static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message
|
|||||||
goto on_error;
|
goto on_error;
|
||||||
|
|
||||||
r = sd_netlink_message_get_errno(m);
|
r = sd_netlink_message_get_errno(m);
|
||||||
if (r < 0)
|
if (r == -ENETDOWN && up && link_up_dsa_slave(link) > 0)
|
||||||
log_link_message_warning_errno(link, m, r, up ?
|
log_link_message_debug_errno(link, m, r, "Could not bring up dsa slave, retrying again after dsa master becomes up");
|
||||||
"Could not bring up interface, ignoring" :
|
else if (r < 0) {
|
||||||
"Could not bring down interface, ignoring");
|
const char *error_msg;
|
||||||
|
|
||||||
|
error_msg = up ?
|
||||||
|
(on_activate ? "Could not bring up interface" : "Could not bring up interface, ignoring") :
|
||||||
|
(on_activate ? "Could not bring down interface" : "Could not bring down interface, ignoring");
|
||||||
|
|
||||||
|
log_link_message_warning_errno(link, m, r, error_msg);
|
||||||
|
if (on_activate)
|
||||||
|
goto on_error;
|
||||||
|
}
|
||||||
|
|
||||||
r = link_call_getlink(link, get_link_update_flag_handler);
|
r = link_call_getlink(link, get_link_update_flag_handler);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
@ -969,7 +1013,7 @@ static int link_up_or_down_handler_internal(sd_netlink *rtnl, sd_netlink_message
|
|||||||
goto on_error;
|
goto on_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (check_ready) {
|
if (on_activate) {
|
||||||
link->activated = true;
|
link->activated = true;
|
||||||
link_check_ready(link);
|
link_check_ready(link);
|
||||||
}
|
}
|
||||||
@ -984,19 +1028,19 @@ on_error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int link_activate_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
static int link_activate_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
return link_up_or_down_handler_internal(rtnl, m, link, true, true);
|
return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ true, /* on_activate = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_activate_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
static int link_activate_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
return link_up_or_down_handler_internal(rtnl, m, link, false, true);
|
return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ false, /* on_activate = */ true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
static int link_up_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
return link_up_or_down_handler_internal(rtnl, m, link, true, false);
|
return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ true, /* on_activate = */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
static int link_down_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
|
||||||
return link_up_or_down_handler_internal(rtnl, m, link, false, false);
|
return link_up_or_down_handler_internal(rtnl, m, link, /* up = */ false, /* on_activate = */ false);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *up_or_down(bool up) {
|
static const char *up_or_down(bool up) {
|
||||||
@ -1123,9 +1167,21 @@ int link_request_to_activate(Link *link) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool link_is_ready_to_bring_up_or_down(Link *link) {
|
static bool link_is_ready_to_bring_up_or_down(Link *link, bool up) {
|
||||||
assert(link);
|
assert(link);
|
||||||
|
|
||||||
|
if (up && link->dsa_master_ifindex > 0) {
|
||||||
|
Link *master;
|
||||||
|
|
||||||
|
/* The master interface must be up. See comments in link_up_dsa_slave(). */
|
||||||
|
|
||||||
|
if (link_get_by_index(link->manager, link->dsa_master_ifindex, &master) < 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!FLAGS_SET(master->flags, IFF_UP))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (link->state == LINK_STATE_UNMANAGED)
|
if (link->state == LINK_STATE_UNMANAGED)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -1153,7 +1209,7 @@ int request_process_link_up_or_down(Request *req) {
|
|||||||
link = req->link;
|
link = req->link;
|
||||||
up = PTR_TO_INT(req->userdata);
|
up = PTR_TO_INT(req->userdata);
|
||||||
|
|
||||||
if (!link_is_ready_to_bring_up_or_down(link))
|
if (!link_is_ready_to_bring_up_or_down(link, up))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
r = link_up_or_down(link, up, req->netlink_handler);
|
r = link_up_or_down(link, up, req->netlink_handler);
|
||||||
|
|||||||
@ -430,7 +430,7 @@ target2 = custom_target(
|
|||||||
shared_generated_gperf_headers = [target1, target2]
|
shared_generated_gperf_headers = [target1, target2]
|
||||||
shared_sources += shared_generated_gperf_headers
|
shared_sources += shared_generated_gperf_headers
|
||||||
|
|
||||||
libshared_name = 'systemd-shared-@0@'.format(meson.project_version())
|
libshared_name = 'systemd-shared-@0@'.format(shared_lib_tag)
|
||||||
|
|
||||||
libshared_deps = [threads,
|
libshared_deps = [threads,
|
||||||
libacl,
|
libacl,
|
||||||
@ -465,13 +465,13 @@ libshared_static = static_library(
|
|||||||
libshared = shared_library(
|
libshared = shared_library(
|
||||||
libshared_name,
|
libshared_name,
|
||||||
include_directories : includes,
|
include_directories : includes,
|
||||||
|
c_args : ['-fvisibility=default'],
|
||||||
link_args : ['-shared',
|
link_args : ['-shared',
|
||||||
'-Wl,--version-script=' + libshared_sym_path],
|
'-Wl,--version-script=' + libshared_sym_path],
|
||||||
link_whole : [libshared_static,
|
link_whole : [libshared_static,
|
||||||
libbasic,
|
libbasic,
|
||||||
libbasic_gcrypt,
|
libbasic_gcrypt,
|
||||||
libsystemd_static],
|
libsystemd_static],
|
||||||
c_args : ['-fvisibility=default'],
|
|
||||||
dependencies : libshared_deps,
|
dependencies : libshared_deps,
|
||||||
install : true,
|
install : true,
|
||||||
install_dir : rootlibexecdir)
|
install_dir : rootlibexecdir)
|
||||||
|
|||||||
@ -419,7 +419,8 @@ tests += [
|
|||||||
libmount,
|
libmount,
|
||||||
libxz,
|
libxz,
|
||||||
liblz4,
|
liblz4,
|
||||||
libblkid],
|
libblkid,
|
||||||
|
libselinux],
|
||||||
[core_includes, journal_includes, udev_includes]],
|
[core_includes, journal_includes, udev_includes]],
|
||||||
|
|
||||||
[['src/test/test-prioq.c']],
|
[['src/test/test-prioq.c']],
|
||||||
|
|||||||
@ -11,34 +11,86 @@ TEST(strpcpy) {
|
|||||||
char target[25];
|
char target[25];
|
||||||
char *s = target;
|
char *s = target;
|
||||||
size_t space_left;
|
size_t space_left;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
space_left = sizeof(target);
|
space_left = sizeof(target);
|
||||||
space_left = strpcpy(&s, space_left, "12345");
|
space_left = strpcpy_full(&s, space_left, "12345", &truncated);
|
||||||
space_left = strpcpy(&s, space_left, "hey hey hey");
|
assert_se(!truncated);
|
||||||
space_left = strpcpy(&s, space_left, "waldo");
|
space_left = strpcpy_full(&s, space_left, "hey hey hey", &truncated);
|
||||||
space_left = strpcpy(&s, space_left, "ba");
|
assert_se(!truncated);
|
||||||
space_left = strpcpy(&s, space_left, "r");
|
space_left = strpcpy_full(&s, space_left, "waldo", &truncated);
|
||||||
space_left = strpcpy(&s, space_left, "foo");
|
assert_se(!truncated);
|
||||||
|
space_left = strpcpy_full(&s, space_left, "ba", &truncated);
|
||||||
|
assert_se(!truncated);
|
||||||
|
space_left = strpcpy_full(&s, space_left, "r", &truncated);
|
||||||
|
assert_se(!truncated);
|
||||||
|
assert_se(space_left == 1);
|
||||||
assert_se(streq(target, "12345hey hey heywaldobar"));
|
assert_se(streq(target, "12345hey hey heywaldobar"));
|
||||||
|
|
||||||
|
space_left = strpcpy_full(&s, space_left, "", &truncated);
|
||||||
|
assert_se(!truncated);
|
||||||
|
assert_se(space_left == 1);
|
||||||
|
assert_se(streq(target, "12345hey hey heywaldobar"));
|
||||||
|
|
||||||
|
space_left = strpcpy_full(&s, space_left, "f", &truncated);
|
||||||
|
assert_se(truncated);
|
||||||
assert_se(space_left == 0);
|
assert_se(space_left == 0);
|
||||||
|
assert_se(streq(target, "12345hey hey heywaldobar"));
|
||||||
|
|
||||||
|
space_left = strpcpy_full(&s, space_left, "", &truncated);
|
||||||
|
assert_se(!truncated);
|
||||||
|
assert_se(space_left == 0);
|
||||||
|
assert_se(streq(target, "12345hey hey heywaldobar"));
|
||||||
|
|
||||||
|
space_left = strpcpy_full(&s, space_left, "foo", &truncated);
|
||||||
|
assert_se(truncated);
|
||||||
|
assert_se(space_left == 0);
|
||||||
|
assert_se(streq(target, "12345hey hey heywaldobar"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(strpcpyf) {
|
TEST(strpcpyf) {
|
||||||
char target[25];
|
char target[25];
|
||||||
char *s = target;
|
char *s = target;
|
||||||
size_t space_left;
|
size_t space_left;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
space_left = sizeof(target);
|
space_left = sizeof(target);
|
||||||
space_left = strpcpyf(&s, space_left, "space left: %zu. ", space_left);
|
space_left = strpcpyf_full(&s, space_left, &truncated, "space left: %zu. ", space_left);
|
||||||
space_left = strpcpyf(&s, space_left, "foo%s", "bar");
|
assert_se(!truncated);
|
||||||
|
space_left = strpcpyf_full(&s, space_left, &truncated, "foo%s", "bar");
|
||||||
assert_se(streq(target, "space left: 25. foobar"));
|
assert_se(!truncated);
|
||||||
assert_se(space_left == 3);
|
assert_se(space_left == 3);
|
||||||
|
assert_se(streq(target, "space left: 25. foobar"));
|
||||||
|
|
||||||
|
space_left = strpcpyf_full(&s, space_left, &truncated, "%i", 42);
|
||||||
|
assert_se(!truncated);
|
||||||
|
assert_se(space_left == 1);
|
||||||
|
assert_se(streq(target, "space left: 25. foobar42"));
|
||||||
|
|
||||||
|
space_left = strpcpyf_full(&s, space_left, &truncated, "%s", "");
|
||||||
|
assert_se(!truncated);
|
||||||
|
assert_se(space_left == 1);
|
||||||
|
assert_se(streq(target, "space left: 25. foobar42"));
|
||||||
|
|
||||||
|
space_left = strpcpyf_full(&s, space_left, &truncated, "%c", 'x');
|
||||||
|
assert_se(truncated);
|
||||||
|
assert_se(space_left == 0);
|
||||||
|
assert_se(streq(target, "space left: 25. foobar42"));
|
||||||
|
|
||||||
|
space_left = strpcpyf_full(&s, space_left, &truncated, "%s", "");
|
||||||
|
assert_se(!truncated);
|
||||||
|
assert_se(space_left == 0);
|
||||||
|
assert_se(streq(target, "space left: 25. foobar42"));
|
||||||
|
|
||||||
|
space_left = strpcpyf_full(&s, space_left, &truncated, "abc%s", "hoge");
|
||||||
|
assert_se(truncated);
|
||||||
|
assert_se(space_left == 0);
|
||||||
|
assert_se(streq(target, "space left: 25. foobar42"));
|
||||||
|
|
||||||
/* test overflow */
|
/* test overflow */
|
||||||
s = target;
|
s = target;
|
||||||
space_left = strpcpyf(&s, 12, "00 left: %i. ", 999);
|
space_left = strpcpyf_full(&s, 12, &truncated, "00 left: %i. ", 999);
|
||||||
|
assert_se(truncated);
|
||||||
assert_se(streq(target, "00 left: 99"));
|
assert_se(streq(target, "00 left: 99"));
|
||||||
assert_se(space_left == 0);
|
assert_se(space_left == 0);
|
||||||
assert_se(target[12] == '2');
|
assert_se(target[12] == '2');
|
||||||
@ -48,21 +100,40 @@ TEST(strpcpyl) {
|
|||||||
char target[25];
|
char target[25];
|
||||||
char *s = target;
|
char *s = target;
|
||||||
size_t space_left;
|
size_t space_left;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
space_left = sizeof(target);
|
space_left = sizeof(target);
|
||||||
space_left = strpcpyl(&s, space_left, "waldo", " test", " waldo. ", NULL);
|
space_left = strpcpyl_full(&s, space_left, &truncated, "waldo", " test", " waldo. ", NULL);
|
||||||
space_left = strpcpyl(&s, space_left, "Banana", NULL);
|
assert_se(!truncated);
|
||||||
|
space_left = strpcpyl_full(&s, space_left, &truncated, "Banana", NULL);
|
||||||
assert_se(streq(target, "waldo test waldo. Banana"));
|
assert_se(!truncated);
|
||||||
assert_se(space_left == 1);
|
assert_se(space_left == 1);
|
||||||
|
assert_se(streq(target, "waldo test waldo. Banana"));
|
||||||
|
|
||||||
|
space_left = strpcpyl_full(&s, space_left, &truncated, "", "", "", NULL);
|
||||||
|
assert_se(!truncated);
|
||||||
|
assert_se(space_left == 1);
|
||||||
|
assert_se(streq(target, "waldo test waldo. Banana"));
|
||||||
|
|
||||||
|
space_left = strpcpyl_full(&s, space_left, &truncated, "", "x", "", NULL);
|
||||||
|
assert_se(truncated);
|
||||||
|
assert_se(space_left == 0);
|
||||||
|
assert_se(streq(target, "waldo test waldo. Banana"));
|
||||||
|
|
||||||
|
space_left = strpcpyl_full(&s, space_left, &truncated, "hoge", NULL);
|
||||||
|
assert_se(truncated);
|
||||||
|
assert_se(space_left == 0);
|
||||||
|
assert_se(streq(target, "waldo test waldo. Banana"));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(strscpy) {
|
TEST(strscpy) {
|
||||||
char target[25];
|
char target[25];
|
||||||
size_t space_left;
|
size_t space_left;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
space_left = sizeof(target);
|
space_left = sizeof(target);
|
||||||
space_left = strscpy(target, space_left, "12345");
|
space_left = strscpy_full(target, space_left, "12345", &truncated);
|
||||||
|
assert_se(!truncated);
|
||||||
|
|
||||||
assert_se(streq(target, "12345"));
|
assert_se(streq(target, "12345"));
|
||||||
assert_se(space_left == 20);
|
assert_se(space_left == 20);
|
||||||
@ -71,9 +142,11 @@ TEST(strscpy) {
|
|||||||
TEST(strscpyl) {
|
TEST(strscpyl) {
|
||||||
char target[25];
|
char target[25];
|
||||||
size_t space_left;
|
size_t space_left;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
space_left = sizeof(target);
|
space_left = sizeof(target);
|
||||||
space_left = strscpyl(target, space_left, "12345", "waldo", "waldo", NULL);
|
space_left = strscpyl_full(target, space_left, &truncated, "12345", "waldo", "waldo", NULL);
|
||||||
|
assert_se(!truncated);
|
||||||
|
|
||||||
assert_se(streq(target, "12345waldowaldo"));
|
assert_se(streq(target, "12345waldowaldo"));
|
||||||
assert_se(space_left == 10);
|
assert_se(space_left == 10);
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#define BUF_SIZE 1024
|
#define BUF_SIZE 1024
|
||||||
|
|
||||||
static void test_event_spawn_core(bool with_pidfd, const char *cmd, char result_buf[BUF_SIZE]) {
|
static void test_event_spawn_core(bool with_pidfd, const char *cmd, char *result_buf, size_t buf_size) {
|
||||||
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
_cleanup_(sd_device_unrefp) sd_device *dev = NULL;
|
||||||
_cleanup_(udev_event_freep) UdevEvent *event = NULL;
|
_cleanup_(udev_event_freep) UdevEvent *event = NULL;
|
||||||
|
|
||||||
@ -17,12 +17,12 @@ static void test_event_spawn_core(bool with_pidfd, const char *cmd, char result_
|
|||||||
|
|
||||||
assert_se(sd_device_new_from_syspath(&dev, "/sys/class/net/lo") >= 0);
|
assert_se(sd_device_new_from_syspath(&dev, "/sys/class/net/lo") >= 0);
|
||||||
assert_se(event = udev_event_new(dev, 0, NULL, LOG_DEBUG));
|
assert_se(event = udev_event_new(dev, 0, NULL, LOG_DEBUG));
|
||||||
assert_se(udev_event_spawn(event, 5 * USEC_PER_SEC, SIGKILL, false, cmd, result_buf, BUF_SIZE) == 0);
|
assert_se(udev_event_spawn(event, 5 * USEC_PER_SEC, SIGKILL, false, cmd, result_buf, buf_size, NULL) == 0);
|
||||||
|
|
||||||
assert_se(unsetenv("SYSTEMD_PIDFD") >= 0);
|
assert_se(unsetenv("SYSTEMD_PIDFD") >= 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_event_spawn_cat(bool with_pidfd) {
|
static void test_event_spawn_cat(bool with_pidfd, size_t buf_size) {
|
||||||
_cleanup_strv_free_ char **lines = NULL;
|
_cleanup_strv_free_ char **lines = NULL;
|
||||||
_cleanup_free_ char *cmd = NULL;
|
_cleanup_free_ char *cmd = NULL;
|
||||||
char result_buf[BUF_SIZE];
|
char result_buf[BUF_SIZE];
|
||||||
@ -32,14 +32,17 @@ static void test_event_spawn_cat(bool with_pidfd) {
|
|||||||
assert_se(find_executable("cat", &cmd) >= 0);
|
assert_se(find_executable("cat", &cmd) >= 0);
|
||||||
assert_se(strextend_with_separator(&cmd, " ", "/sys/class/net/lo/uevent"));
|
assert_se(strextend_with_separator(&cmd, " ", "/sys/class/net/lo/uevent"));
|
||||||
|
|
||||||
test_event_spawn_core(with_pidfd, cmd, result_buf);
|
test_event_spawn_core(with_pidfd, cmd, result_buf,
|
||||||
|
buf_size >= BUF_SIZE ? BUF_SIZE : buf_size);
|
||||||
|
|
||||||
assert_se(lines = strv_split_newlines(result_buf));
|
assert_se(lines = strv_split_newlines(result_buf));
|
||||||
strv_print(lines);
|
strv_print(lines);
|
||||||
|
|
||||||
|
if (buf_size >= BUF_SIZE) {
|
||||||
assert_se(strv_contains(lines, "INTERFACE=lo"));
|
assert_se(strv_contains(lines, "INTERFACE=lo"));
|
||||||
assert_se(strv_contains(lines, "IFINDEX=1"));
|
assert_se(strv_contains(lines, "IFINDEX=1"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void test_event_spawn_self(const char *self, const char *arg, bool with_pidfd) {
|
static void test_event_spawn_self(const char *self, const char *arg, bool with_pidfd) {
|
||||||
_cleanup_strv_free_ char **lines = NULL;
|
_cleanup_strv_free_ char **lines = NULL;
|
||||||
@ -50,7 +53,7 @@ static void test_event_spawn_self(const char *self, const char *arg, bool with_p
|
|||||||
|
|
||||||
assert_se(cmd = strjoin(self, " ", arg));
|
assert_se(cmd = strjoin(self, " ", arg));
|
||||||
|
|
||||||
test_event_spawn_core(with_pidfd, cmd, result_buf);
|
test_event_spawn_core(with_pidfd, cmd, result_buf, BUF_SIZE);
|
||||||
|
|
||||||
assert_se(lines = strv_split_newlines(result_buf));
|
assert_se(lines = strv_split_newlines(result_buf));
|
||||||
strv_print(lines);
|
strv_print(lines);
|
||||||
@ -92,8 +95,10 @@ int main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
|
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
|
||||||
|
|
||||||
test_event_spawn_cat(true);
|
test_event_spawn_cat(true, SIZE_MAX);
|
||||||
test_event_spawn_cat(false);
|
test_event_spawn_cat(false, SIZE_MAX);
|
||||||
|
test_event_spawn_cat(true, 5);
|
||||||
|
test_event_spawn_cat(false, 5);
|
||||||
|
|
||||||
assert_se(path_make_absolute_cwd(argv[0], &self) >= 0);
|
assert_se(path_make_absolute_cwd(argv[0], &self) >= 0);
|
||||||
path_simplify(self);
|
path_simplify(self);
|
||||||
|
|||||||
@ -12,6 +12,7 @@
|
|||||||
|
|
||||||
#include "alloc-util.h"
|
#include "alloc-util.h"
|
||||||
#include "errno-util.h"
|
#include "errno-util.h"
|
||||||
|
#include "event-util.h"
|
||||||
#include "fd-util.h"
|
#include "fd-util.h"
|
||||||
#include "format-util.h"
|
#include "format-util.h"
|
||||||
#include "io-util.h"
|
#include "io-util.h"
|
||||||
@ -105,6 +106,13 @@ static void udev_ctrl_disconnect(UdevCtrl *uctrl) {
|
|||||||
uctrl->sock_connect = safe_close(uctrl->sock_connect);
|
uctrl->sock_connect = safe_close(uctrl->sock_connect);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int udev_ctrl_is_connected(UdevCtrl *uctrl) {
|
||||||
|
if (!uctrl)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return event_source_is_enabled(uctrl->event_source_connect);
|
||||||
|
}
|
||||||
|
|
||||||
static UdevCtrl *udev_ctrl_free(UdevCtrl *uctrl) {
|
static UdevCtrl *udev_ctrl_free(UdevCtrl *uctrl) {
|
||||||
assert(uctrl);
|
assert(uctrl);
|
||||||
|
|
||||||
@ -291,7 +299,7 @@ int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdat
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf) {
|
int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, const void *data) {
|
||||||
UdevCtrlMessageWire ctrl_msg_wire = {
|
UdevCtrlMessageWire ctrl_msg_wire = {
|
||||||
.version = "udev-" STRINGIFY(PROJECT_VERSION),
|
.version = "udev-" STRINGIFY(PROJECT_VERSION),
|
||||||
.magic = UDEV_CTRL_MAGIC,
|
.magic = UDEV_CTRL_MAGIC,
|
||||||
@ -301,10 +309,13 @@ int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const
|
|||||||
if (uctrl->maybe_disconnected)
|
if (uctrl->maybe_disconnected)
|
||||||
return -ENOANO; /* to distinguish this from other errors. */
|
return -ENOANO; /* to distinguish this from other errors. */
|
||||||
|
|
||||||
if (buf)
|
if (type == UDEV_CTRL_SET_ENV) {
|
||||||
strscpy(ctrl_msg_wire.value.buf, sizeof(ctrl_msg_wire.value.buf), buf);
|
assert(data);
|
||||||
else
|
strscpy(ctrl_msg_wire.value.buf, sizeof(ctrl_msg_wire.value.buf), data);
|
||||||
ctrl_msg_wire.value.intval = intval;
|
} else if (IN_SET(type, UDEV_CTRL_SET_LOG_LEVEL, UDEV_CTRL_SET_CHILDREN_MAX))
|
||||||
|
ctrl_msg_wire.value.intval = PTR_TO_INT(data);
|
||||||
|
else if (type == UDEV_CTRL_SENDER_PID)
|
||||||
|
ctrl_msg_wire.value.pid = PTR_TO_PID(data);
|
||||||
|
|
||||||
if (!uctrl->connected) {
|
if (!uctrl->connected) {
|
||||||
if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0)
|
if (connect(uctrl->sock, &uctrl->saddr.sa, uctrl->addrlen) < 0)
|
||||||
@ -333,7 +344,7 @@ int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout) {
|
|||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (!uctrl->maybe_disconnected) {
|
if (!uctrl->maybe_disconnected) {
|
||||||
r = udev_ctrl_send(uctrl, _UDEV_CTRL_END_MESSAGES, 0, NULL);
|
r = udev_ctrl_send(uctrl, _UDEV_CTRL_END_MESSAGES, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@
|
|||||||
#include "sd-event.h"
|
#include "sd-event.h"
|
||||||
|
|
||||||
#include "macro.h"
|
#include "macro.h"
|
||||||
|
#include "process-util.h"
|
||||||
#include "time-util.h"
|
#include "time-util.h"
|
||||||
|
|
||||||
typedef struct UdevCtrl UdevCtrl;
|
typedef struct UdevCtrl UdevCtrl;
|
||||||
@ -18,10 +19,12 @@ typedef enum UdevCtrlMessageType {
|
|||||||
UDEV_CTRL_SET_CHILDREN_MAX,
|
UDEV_CTRL_SET_CHILDREN_MAX,
|
||||||
UDEV_CTRL_PING,
|
UDEV_CTRL_PING,
|
||||||
UDEV_CTRL_EXIT,
|
UDEV_CTRL_EXIT,
|
||||||
|
UDEV_CTRL_SENDER_PID,
|
||||||
} UdevCtrlMessageType;
|
} UdevCtrlMessageType;
|
||||||
|
|
||||||
typedef union UdevCtrlMessageValue {
|
typedef union UdevCtrlMessageValue {
|
||||||
int intval;
|
int intval;
|
||||||
|
pid_t pid;
|
||||||
char buf[256];
|
char buf[256];
|
||||||
} UdevCtrlMessageValue;
|
} UdevCtrlMessageValue;
|
||||||
|
|
||||||
@ -39,40 +42,45 @@ UdevCtrl *udev_ctrl_unref(UdevCtrl *uctrl);
|
|||||||
int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event);
|
int udev_ctrl_attach_event(UdevCtrl *uctrl, sd_event *event);
|
||||||
int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata);
|
int udev_ctrl_start(UdevCtrl *uctrl, udev_ctrl_handler_t callback, void *userdata);
|
||||||
sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl);
|
sd_event_source *udev_ctrl_get_event_source(UdevCtrl *uctrl);
|
||||||
|
int udev_ctrl_is_connected(UdevCtrl *uctrl);
|
||||||
|
|
||||||
int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout);
|
int udev_ctrl_wait(UdevCtrl *uctrl, usec_t timeout);
|
||||||
|
|
||||||
int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, int intval, const char *buf);
|
int udev_ctrl_send(UdevCtrl *uctrl, UdevCtrlMessageType type, const void *data);
|
||||||
static inline int udev_ctrl_send_set_log_level(UdevCtrl *uctrl, int priority) {
|
static inline int udev_ctrl_send_set_log_level(UdevCtrl *uctrl, int priority) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, priority, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_LOG_LEVEL, INT_TO_PTR(priority));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_stop_exec_queue(UdevCtrl *uctrl) {
|
static inline int udev_ctrl_send_stop_exec_queue(UdevCtrl *uctrl) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, 0, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_STOP_EXEC_QUEUE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_start_exec_queue(UdevCtrl *uctrl) {
|
static inline int udev_ctrl_send_start_exec_queue(UdevCtrl *uctrl) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, 0, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_START_EXEC_QUEUE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_reload(UdevCtrl *uctrl) {
|
static inline int udev_ctrl_send_reload(UdevCtrl *uctrl) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, 0, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_RELOAD, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_set_env(UdevCtrl *uctrl, const char *key) {
|
static inline int udev_ctrl_send_set_env(UdevCtrl *uctrl, const char *key) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, 0, key);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_ENV, key);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_set_children_max(UdevCtrl *uctrl, int count) {
|
static inline int udev_ctrl_send_set_children_max(UdevCtrl *uctrl, int count) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, count, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_SET_CHILDREN_MAX, INT_TO_PTR(count));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_ping(UdevCtrl *uctrl) {
|
static inline int udev_ctrl_send_ping(UdevCtrl *uctrl) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_PING, 0, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_PING, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int udev_ctrl_send_exit(UdevCtrl *uctrl) {
|
static inline int udev_ctrl_send_exit(UdevCtrl *uctrl) {
|
||||||
return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, 0, NULL);
|
return udev_ctrl_send(uctrl, UDEV_CTRL_EXIT, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int udev_ctrl_send_pid(UdevCtrl *uctrl) {
|
||||||
|
return udev_ctrl_send(uctrl, UDEV_CTRL_SENDER_PID, PID_TO_PTR(getpid_cached()));
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevCtrl*, udev_ctrl_unref);
|
DEFINE_TRIVIAL_CLEANUP_FUNC(UdevCtrl*, udev_ctrl_unref);
|
||||||
|
|||||||
@ -50,6 +50,7 @@ typedef struct Spawn {
|
|||||||
char *result;
|
char *result;
|
||||||
size_t result_size;
|
size_t result_size;
|
||||||
size_t result_len;
|
size_t result_len;
|
||||||
|
bool truncated;
|
||||||
} Spawn;
|
} Spawn;
|
||||||
|
|
||||||
UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl, int log_level) {
|
UdevEvent *udev_event_new(sd_device *dev, usec_t exec_delay_usec, sd_netlink *rtnl, int log_level) {
|
||||||
@ -237,9 +238,12 @@ static ssize_t udev_event_subst_format(
|
|||||||
FormatSubstitutionType type,
|
FormatSubstitutionType type,
|
||||||
const char *attr,
|
const char *attr,
|
||||||
char *dest,
|
char *dest,
|
||||||
size_t l) {
|
size_t l,
|
||||||
|
bool *ret_truncated) {
|
||||||
|
|
||||||
sd_device *parent, *dev = event->dev;
|
sd_device *parent, *dev = event->dev;
|
||||||
const char *val = NULL;
|
const char *val = NULL;
|
||||||
|
bool truncated = false;
|
||||||
char *s = dest;
|
char *s = dest;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -248,13 +252,13 @@ static ssize_t udev_event_subst_format(
|
|||||||
r = sd_device_get_devpath(dev, &val);
|
r = sd_device_get_devpath(dev, &val);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
strpcpy(&s, l, val);
|
strpcpy_full(&s, l, val, &truncated);
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_KERNEL:
|
case FORMAT_SUBST_KERNEL:
|
||||||
r = sd_device_get_sysname(dev, &val);
|
r = sd_device_get_sysname(dev, &val);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
strpcpy(&s, l, val);
|
strpcpy_full(&s, l, val, &truncated);
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_KERNEL_NUMBER:
|
case FORMAT_SUBST_KERNEL_NUMBER:
|
||||||
r = sd_device_get_sysnum(dev, &val);
|
r = sd_device_get_sysnum(dev, &val);
|
||||||
@ -262,7 +266,7 @@ static ssize_t udev_event_subst_format(
|
|||||||
goto null_terminate;
|
goto null_terminate;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
strpcpy(&s, l, val);
|
strpcpy_full(&s, l, val, &truncated);
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_ID:
|
case FORMAT_SUBST_ID:
|
||||||
if (!event->dev_parent)
|
if (!event->dev_parent)
|
||||||
@ -270,7 +274,7 @@ static ssize_t udev_event_subst_format(
|
|||||||
r = sd_device_get_sysname(event->dev_parent, &val);
|
r = sd_device_get_sysname(event->dev_parent, &val);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
strpcpy(&s, l, val);
|
strpcpy_full(&s, l, val, &truncated);
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_DRIVER:
|
case FORMAT_SUBST_DRIVER:
|
||||||
if (!event->dev_parent)
|
if (!event->dev_parent)
|
||||||
@ -280,7 +284,7 @@ static ssize_t udev_event_subst_format(
|
|||||||
goto null_terminate;
|
goto null_terminate;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
strpcpy(&s, l, val);
|
strpcpy_full(&s, l, val, &truncated);
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_MAJOR:
|
case FORMAT_SUBST_MAJOR:
|
||||||
case FORMAT_SUBST_MINOR: {
|
case FORMAT_SUBST_MINOR: {
|
||||||
@ -289,7 +293,7 @@ static ssize_t udev_event_subst_format(
|
|||||||
r = sd_device_get_devnum(dev, &devnum);
|
r = sd_device_get_devnum(dev, &devnum);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
return r;
|
return r;
|
||||||
strpcpyf(&s, l, "%u", r < 0 ? 0 : type == FORMAT_SUBST_MAJOR ? major(devnum) : minor(devnum));
|
strpcpyf_full(&s, l, &truncated, "%u", r < 0 ? 0 : type == FORMAT_SUBST_MAJOR ? major(devnum) : minor(devnum));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FORMAT_SUBST_RESULT: {
|
case FORMAT_SUBST_RESULT: {
|
||||||
@ -308,7 +312,7 @@ static ssize_t udev_event_subst_format(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (index == 0)
|
if (index == 0)
|
||||||
strpcpy(&s, l, event->program_result);
|
strpcpy_full(&s, l, event->program_result, &truncated);
|
||||||
else {
|
else {
|
||||||
const char *start, *p;
|
const char *start, *p;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
@ -330,11 +334,11 @@ static ssize_t udev_event_subst_format(
|
|||||||
start = p;
|
start = p;
|
||||||
/* %c{2+} copies the whole string from the second part on */
|
/* %c{2+} copies the whole string from the second part on */
|
||||||
if (has_plus)
|
if (has_plus)
|
||||||
strpcpy(&s, l, start);
|
strpcpy_full(&s, l, start, &truncated);
|
||||||
else {
|
else {
|
||||||
while (*p && !strchr(WHITESPACE, *p))
|
while (*p && !strchr(WHITESPACE, *p))
|
||||||
p++;
|
p++;
|
||||||
strnpcpy(&s, l, start, p - start);
|
strnpcpy_full(&s, l, start, p - start, &truncated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -342,6 +346,7 @@ static ssize_t udev_event_subst_format(
|
|||||||
case FORMAT_SUBST_ATTR: {
|
case FORMAT_SUBST_ATTR: {
|
||||||
char vbuf[UDEV_NAME_SIZE];
|
char vbuf[UDEV_NAME_SIZE];
|
||||||
int count;
|
int count;
|
||||||
|
bool t;
|
||||||
|
|
||||||
if (isempty(attr))
|
if (isempty(attr))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@ -363,12 +368,13 @@ static ssize_t udev_event_subst_format(
|
|||||||
|
|
||||||
/* strip trailing whitespace, and replace unwanted characters */
|
/* strip trailing whitespace, and replace unwanted characters */
|
||||||
if (val != vbuf)
|
if (val != vbuf)
|
||||||
strscpy(vbuf, sizeof(vbuf), val);
|
strscpy_full(vbuf, sizeof(vbuf), val, &truncated);
|
||||||
delete_trailing_chars(vbuf, NULL);
|
delete_trailing_chars(vbuf, NULL);
|
||||||
count = udev_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT);
|
count = udev_replace_chars(vbuf, UDEV_ALLOWED_CHARS_INPUT);
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
log_device_debug(dev, "%i character(s) replaced", count);
|
log_device_debug(dev, "%i character(s) replaced", count);
|
||||||
strpcpy(&s, l, vbuf);
|
strpcpy_full(&s, l, vbuf, &t);
|
||||||
|
truncated = truncated || t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FORMAT_SUBST_PARENT:
|
case FORMAT_SUBST_PARENT:
|
||||||
@ -382,7 +388,7 @@ static ssize_t udev_event_subst_format(
|
|||||||
goto null_terminate;
|
goto null_terminate;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
strpcpy(&s, l, val + STRLEN("/dev/"));
|
strpcpy_full(&s, l, val + STRLEN("/dev/"), &truncated);
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_DEVNODE:
|
case FORMAT_SUBST_DEVNODE:
|
||||||
r = sd_device_get_devname(dev, &val);
|
r = sd_device_get_devname(dev, &val);
|
||||||
@ -390,34 +396,37 @@ static ssize_t udev_event_subst_format(
|
|||||||
goto null_terminate;
|
goto null_terminate;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
strpcpy(&s, l, val);
|
strpcpy_full(&s, l, val, &truncated);
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_NAME:
|
case FORMAT_SUBST_NAME:
|
||||||
if (event->name)
|
if (event->name)
|
||||||
strpcpy(&s, l, event->name);
|
strpcpy_full(&s, l, event->name, &truncated);
|
||||||
else if (sd_device_get_devname(dev, &val) >= 0)
|
else if (sd_device_get_devname(dev, &val) >= 0)
|
||||||
strpcpy(&s, l, val + STRLEN("/dev/"));
|
strpcpy_full(&s, l, val + STRLEN("/dev/"), &truncated);
|
||||||
else {
|
else {
|
||||||
r = sd_device_get_sysname(dev, &val);
|
r = sd_device_get_sysname(dev, &val);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
strpcpy(&s, l, val);
|
strpcpy_full(&s, l, val, &truncated);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_LINKS:
|
case FORMAT_SUBST_LINKS:
|
||||||
FOREACH_DEVICE_DEVLINK(dev, val)
|
FOREACH_DEVICE_DEVLINK(dev, val) {
|
||||||
if (s == dest)
|
if (s == dest)
|
||||||
strpcpy(&s, l, val + STRLEN("/dev/"));
|
strpcpy_full(&s, l, val + STRLEN("/dev/"), &truncated);
|
||||||
else
|
else
|
||||||
strpcpyl(&s, l, " ", val + STRLEN("/dev/"), NULL);
|
strpcpyl_full(&s, l, &truncated, " ", val + STRLEN("/dev/"), NULL);
|
||||||
|
if (truncated)
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (s == dest)
|
if (s == dest)
|
||||||
goto null_terminate;
|
goto null_terminate;
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_ROOT:
|
case FORMAT_SUBST_ROOT:
|
||||||
strpcpy(&s, l, "/dev");
|
strpcpy_full(&s, l, "/dev", &truncated);
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_SYS:
|
case FORMAT_SUBST_SYS:
|
||||||
strpcpy(&s, l, "/sys");
|
strpcpy_full(&s, l, "/sys", &truncated);
|
||||||
break;
|
break;
|
||||||
case FORMAT_SUBST_ENV:
|
case FORMAT_SUBST_ENV:
|
||||||
if (isempty(attr))
|
if (isempty(attr))
|
||||||
@ -427,22 +436,34 @@ static ssize_t udev_event_subst_format(
|
|||||||
goto null_terminate;
|
goto null_terminate;
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return r;
|
return r;
|
||||||
strpcpy(&s, l, val);
|
strpcpy_full(&s, l, val, &truncated);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
assert_not_reached();
|
assert_not_reached();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret_truncated)
|
||||||
|
*ret_truncated = truncated;
|
||||||
|
|
||||||
return s - dest;
|
return s - dest;
|
||||||
|
|
||||||
null_terminate:
|
null_terminate:
|
||||||
|
if (ret_truncated)
|
||||||
|
*ret_truncated = truncated;
|
||||||
|
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t udev_event_apply_format(UdevEvent *event,
|
size_t udev_event_apply_format(
|
||||||
const char *src, char *dest, size_t size,
|
UdevEvent *event,
|
||||||
bool replace_whitespace) {
|
const char *src,
|
||||||
|
char *dest,
|
||||||
|
size_t size,
|
||||||
|
bool replace_whitespace,
|
||||||
|
bool *ret_truncated) {
|
||||||
|
|
||||||
|
bool truncated = false;
|
||||||
const char *s = src;
|
const char *s = src;
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
@ -456,20 +477,24 @@ size_t udev_event_apply_format(UdevEvent *event,
|
|||||||
FormatSubstitutionType type;
|
FormatSubstitutionType type;
|
||||||
char attr[UDEV_PATH_SIZE];
|
char attr[UDEV_PATH_SIZE];
|
||||||
ssize_t subst_len;
|
ssize_t subst_len;
|
||||||
|
bool t;
|
||||||
|
|
||||||
r = get_subst_type(&s, false, &type, attr);
|
r = get_subst_type(&s, false, &type, attr);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_device_warning_errno(event->dev, r, "Invalid format string, ignoring: %s", src);
|
log_device_warning_errno(event->dev, r, "Invalid format string, ignoring: %s", src);
|
||||||
break;
|
break;
|
||||||
} else if (r == 0) {
|
} else if (r == 0) {
|
||||||
if (size < 2) /* need space for this char and the terminating NUL */
|
if (size < 2) {
|
||||||
|
/* need space for this char and the terminating NUL */
|
||||||
|
truncated = true;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
*dest++ = *s++;
|
*dest++ = *s++;
|
||||||
size--;
|
size--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
subst_len = udev_event_subst_format(event, type, attr, dest, size);
|
subst_len = udev_event_subst_format(event, type, attr, dest, size, &t);
|
||||||
if (subst_len < 0) {
|
if (subst_len < 0) {
|
||||||
log_device_warning_errno(event->dev, subst_len,
|
log_device_warning_errno(event->dev, subst_len,
|
||||||
"Failed to substitute variable '$%s' or apply format '%%%c', ignoring: %m",
|
"Failed to substitute variable '$%s' or apply format '%%%c', ignoring: %m",
|
||||||
@ -477,6 +502,8 @@ size_t udev_event_apply_format(UdevEvent *event,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
truncated = truncated || t;
|
||||||
|
|
||||||
/* FORMAT_SUBST_RESULT handles spaces itself */
|
/* FORMAT_SUBST_RESULT handles spaces itself */
|
||||||
if (replace_whitespace && type != FORMAT_SUBST_RESULT)
|
if (replace_whitespace && type != FORMAT_SUBST_RESULT)
|
||||||
/* udev_replace_whitespace can replace in-place,
|
/* udev_replace_whitespace can replace in-place,
|
||||||
@ -488,6 +515,10 @@ size_t udev_event_apply_format(UdevEvent *event,
|
|||||||
}
|
}
|
||||||
|
|
||||||
assert(size >= 1);
|
assert(size >= 1);
|
||||||
|
|
||||||
|
if (ret_truncated)
|
||||||
|
*ret_truncated = truncated;
|
||||||
|
|
||||||
*dest = '\0';
|
*dest = '\0';
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
@ -555,7 +586,7 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd
|
|||||||
size = sizeof(buf);
|
size = sizeof(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
l = read(fd, p, size - 1);
|
l = read(fd, p, size - (p == buf));
|
||||||
if (l < 0) {
|
if (l < 0) {
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
goto reenable;
|
goto reenable;
|
||||||
@ -566,6 +597,13 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((size_t) l == size) {
|
||||||
|
log_device_warning(spawn->device, "Truncating stdout of '%s' up to %zu byte.",
|
||||||
|
spawn->cmd, spawn->result_size);
|
||||||
|
l--;
|
||||||
|
spawn->truncated = true;
|
||||||
|
}
|
||||||
|
|
||||||
p[l] = '\0';
|
p[l] = '\0';
|
||||||
if (fd == spawn->fd_stdout && spawn->result)
|
if (fd == spawn->fd_stdout && spawn->result)
|
||||||
spawn->result_len += l;
|
spawn->result_len += l;
|
||||||
@ -586,7 +624,7 @@ static int on_spawn_io(sd_event_source *s, int fd, uint32_t revents, void *userd
|
|||||||
fd == spawn->fd_stdout ? "out" : "err", *q);
|
fd == spawn->fd_stdout ? "out" : "err", *q);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l == 0)
|
if (l == 0 || spawn->truncated)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
reenable:
|
reenable:
|
||||||
@ -725,12 +763,16 @@ static int spawn_wait(Spawn *spawn) {
|
|||||||
return sd_event_loop(e);
|
return sd_event_loop(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
int udev_event_spawn(UdevEvent *event,
|
int udev_event_spawn(
|
||||||
|
UdevEvent *event,
|
||||||
usec_t timeout_usec,
|
usec_t timeout_usec,
|
||||||
int timeout_signal,
|
int timeout_signal,
|
||||||
bool accept_failure,
|
bool accept_failure,
|
||||||
const char *cmd,
|
const char *cmd,
|
||||||
char *result, size_t ressize) {
|
char *result,
|
||||||
|
size_t ressize,
|
||||||
|
bool *ret_truncated) {
|
||||||
|
|
||||||
_cleanup_close_pair_ int outpipe[2] = {-1, -1}, errpipe[2] = {-1, -1};
|
_cleanup_close_pair_ int outpipe[2] = {-1, -1}, errpipe[2] = {-1, -1};
|
||||||
_cleanup_strv_free_ char **argv = NULL;
|
_cleanup_strv_free_ char **argv = NULL;
|
||||||
char **envp = NULL;
|
char **envp = NULL;
|
||||||
@ -821,6 +863,9 @@ int udev_event_spawn(UdevEvent *event,
|
|||||||
if (result)
|
if (result)
|
||||||
result[spawn.result_len] = '\0';
|
result[spawn.result_len] = '\0';
|
||||||
|
|
||||||
|
if (ret_truncated)
|
||||||
|
*ret_truncated = spawn.truncated;
|
||||||
|
|
||||||
return r; /* 0 for success, and positive if the program failed */
|
return r; /* 0 for success, and positive if the program failed */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1095,7 +1140,7 @@ void udev_event_execute_run(UdevEvent *event, usec_t timeout_usec, int timeout_s
|
|||||||
|
|
||||||
log_device_debug(event->dev, "Running command \"%s\"", command);
|
log_device_debug(event->dev, "Running command \"%s\"", command);
|
||||||
|
|
||||||
r = udev_event_spawn(event, timeout_usec, timeout_signal, false, command, NULL, 0);
|
r = udev_event_spawn(event, timeout_usec, timeout_signal, false, command, NULL, 0, NULL);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_device_warning_errno(event->dev, r, "Failed to execute '%s', ignoring: %m", command);
|
log_device_warning_errno(event->dev, r, "Failed to execute '%s', ignoring: %m", command);
|
||||||
else if (r > 0) /* returned value is positive when program fails */
|
else if (r > 0) /* returned value is positive when program fails */
|
||||||
|
|||||||
@ -56,7 +56,8 @@ size_t udev_event_apply_format(
|
|||||||
const char *src,
|
const char *src,
|
||||||
char *dest,
|
char *dest,
|
||||||
size_t size,
|
size_t size,
|
||||||
bool replace_whitespace);
|
bool replace_whitespace,
|
||||||
|
bool *ret_truncated);
|
||||||
int udev_check_format(const char *value, size_t *offset, const char **hint);
|
int udev_check_format(const char *value, size_t *offset, const char **hint);
|
||||||
int udev_event_spawn(
|
int udev_event_spawn(
|
||||||
UdevEvent *event,
|
UdevEvent *event,
|
||||||
@ -65,7 +66,8 @@ int udev_event_spawn(
|
|||||||
bool accept_failure,
|
bool accept_failure,
|
||||||
const char *cmd,
|
const char *cmd,
|
||||||
char *result,
|
char *result,
|
||||||
size_t ressize);
|
size_t ressize,
|
||||||
|
bool *ret_truncated);
|
||||||
int udev_event_execute_rules(
|
int udev_event_execute_rules(
|
||||||
UdevEvent *event,
|
UdevEvent *event,
|
||||||
int inotify_fd,
|
int inotify_fd,
|
||||||
|
|||||||
@ -1381,11 +1381,14 @@ static bool token_match_string(UdevRuleToken *token, const char *str) {
|
|||||||
return token->op == (match ? OP_MATCH : OP_NOMATCH);
|
return token->op == (match ? OP_MATCH : OP_NOMATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *event) {
|
static bool token_match_attr(UdevRules *rules, UdevRuleToken *token, sd_device *dev, UdevEvent *event) {
|
||||||
char nbuf[UDEV_NAME_SIZE], vbuf[UDEV_NAME_SIZE];
|
char nbuf[UDEV_NAME_SIZE], vbuf[UDEV_NAME_SIZE];
|
||||||
const char *name, *value;
|
const char *name, *value;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
|
assert(rules);
|
||||||
assert(token);
|
assert(token);
|
||||||
|
assert(IN_SET(token->type, TK_M_ATTR, TK_M_PARENTS_ATTR));
|
||||||
assert(dev);
|
assert(dev);
|
||||||
assert(event);
|
assert(event);
|
||||||
|
|
||||||
@ -1393,7 +1396,15 @@ static bool token_match_attr(UdevRuleToken *token, sd_device *dev, UdevEvent *ev
|
|||||||
|
|
||||||
switch (token->attr_subst_type) {
|
switch (token->attr_subst_type) {
|
||||||
case SUBST_TYPE_FORMAT:
|
case SUBST_TYPE_FORMAT:
|
||||||
(void) udev_event_apply_format(event, name, nbuf, sizeof(nbuf), false);
|
(void) udev_event_apply_format(event, name, nbuf, sizeof(nbuf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_debug(dev, rules,
|
||||||
|
"The sysfs attribute name '%s' is truncated while substituting into '%s', "
|
||||||
|
"assuming the %s key does not match.", nbuf, name,
|
||||||
|
token->type == TK_M_ATTR ? "ATTR" : "ATTRS");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
name = nbuf;
|
name = nbuf;
|
||||||
_fallthrough_;
|
_fallthrough_;
|
||||||
case SUBST_TYPE_PLAIN:
|
case SUBST_TYPE_PLAIN:
|
||||||
@ -1497,6 +1508,7 @@ static int attr_subst_subdir(char attr[static UDEV_PATH_SIZE]) {
|
|||||||
char buf[UDEV_PATH_SIZE], *p;
|
char buf[UDEV_PATH_SIZE], *p;
|
||||||
const char *tail;
|
const char *tail;
|
||||||
size_t len, size;
|
size_t len, size;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
assert(attr);
|
assert(attr);
|
||||||
|
|
||||||
@ -1509,7 +1521,9 @@ static int attr_subst_subdir(char attr[static UDEV_PATH_SIZE]) {
|
|||||||
|
|
||||||
p = buf;
|
p = buf;
|
||||||
size = sizeof(buf);
|
size = sizeof(buf);
|
||||||
size -= strnpcpy(&p, size, attr, len);
|
size -= strnpcpy_full(&p, size, attr, len, &truncated);
|
||||||
|
if (truncated)
|
||||||
|
return -ENOENT;
|
||||||
|
|
||||||
dir = opendir(buf);
|
dir = opendir(buf);
|
||||||
if (!dir)
|
if (!dir)
|
||||||
@ -1519,7 +1533,10 @@ static int attr_subst_subdir(char attr[static UDEV_PATH_SIZE]) {
|
|||||||
if (de->d_name[0] == '.')
|
if (de->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
strscpyl(p, size, de->d_name, tail, NULL);
|
strscpyl_full(p, size, &truncated, de->d_name, tail, NULL);
|
||||||
|
if (truncated)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (faccessat(dirfd(dir), p, F_OK, 0) < 0)
|
if (faccessat(dirfd(dir), p, F_OK, 0) < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@ -1645,12 +1662,19 @@ static int udev_rule_apply_token_to_event(
|
|||||||
}
|
}
|
||||||
case TK_M_ATTR:
|
case TK_M_ATTR:
|
||||||
case TK_M_PARENTS_ATTR:
|
case TK_M_PARENTS_ATTR:
|
||||||
return token_match_attr(token, dev, event);
|
return token_match_attr(rules, token, dev, event);
|
||||||
case TK_M_SYSCTL: {
|
case TK_M_SYSCTL: {
|
||||||
_cleanup_free_ char *value = NULL;
|
_cleanup_free_ char *value = NULL;
|
||||||
char buf[UDEV_PATH_SIZE];
|
char buf[UDEV_PATH_SIZE];
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
|
(void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_debug(dev, rules, "The sysctl entry name '%s' is truncated while substituting into '%s', "
|
||||||
|
"assuming the SYSCTL key does not match.", buf, (const char*) token->data);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false);
|
|
||||||
r = sysctl_read(sysctl_normalize(buf), &value);
|
r = sysctl_read(sysctl_normalize(buf), &value);
|
||||||
if (r < 0 && r != -ENOENT)
|
if (r < 0 && r != -ENOENT)
|
||||||
return log_rule_error_errno(dev, rules, r, "Failed to read sysctl '%s': %m", buf);
|
return log_rule_error_errno(dev, rules, r, "Failed to read sysctl '%s': %m", buf);
|
||||||
@ -1661,9 +1685,15 @@ static int udev_rule_apply_token_to_event(
|
|||||||
mode_t mode = PTR_TO_MODE(token->data);
|
mode_t mode = PTR_TO_MODE(token->data);
|
||||||
char buf[UDEV_PATH_SIZE];
|
char buf[UDEV_PATH_SIZE];
|
||||||
struct stat statbuf;
|
struct stat statbuf;
|
||||||
bool match;
|
bool match, truncated;
|
||||||
|
|
||||||
|
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_debug(dev, rules, "The file name '%s' is truncated while substituting into '%s', "
|
||||||
|
"assuming the TEST key does not match", buf, token->value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false);
|
|
||||||
if (!path_is_absolute(buf) &&
|
if (!path_is_absolute(buf) &&
|
||||||
udev_resolve_subsys_kernel(buf, buf, sizeof(buf), false) < 0) {
|
udev_resolve_subsys_kernel(buf, buf, sizeof(buf), false) < 0) {
|
||||||
char tmp[UDEV_PATH_SIZE];
|
char tmp[UDEV_PATH_SIZE];
|
||||||
@ -1673,8 +1703,11 @@ static int udev_rule_apply_token_to_event(
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_rule_error_errno(dev, rules, r, "Failed to get syspath: %m");
|
return log_rule_error_errno(dev, rules, r, "Failed to get syspath: %m");
|
||||||
|
|
||||||
strscpy(tmp, sizeof(tmp), buf);
|
strscpy_full(tmp, sizeof(tmp), buf, &truncated);
|
||||||
strscpyl(buf, sizeof(buf), val, "/", tmp, NULL);
|
assert(!truncated);
|
||||||
|
strscpyl_full(buf, sizeof(buf), &truncated, val, "/", tmp, NULL);
|
||||||
|
if (truncated)
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
r = attr_subst_subdir(buf);
|
r = attr_subst_subdir(buf);
|
||||||
@ -1694,13 +1727,20 @@ static int udev_rule_apply_token_to_event(
|
|||||||
}
|
}
|
||||||
case TK_M_PROGRAM: {
|
case TK_M_PROGRAM: {
|
||||||
char buf[UDEV_PATH_SIZE], result[UDEV_LINE_SIZE];
|
char buf[UDEV_PATH_SIZE], result[UDEV_LINE_SIZE];
|
||||||
|
bool truncated;
|
||||||
size_t count;
|
size_t count;
|
||||||
|
|
||||||
event->program_result = mfree(event->program_result);
|
event->program_result = mfree(event->program_result);
|
||||||
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false);
|
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_debug(dev, rules, "The command '%s' is truncated while substituting into '%s', "
|
||||||
|
"assuming the PROGRAM key does not match.", buf, token->value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
log_rule_debug(dev, rules, "Running PROGRAM '%s'", buf);
|
log_rule_debug(dev, rules, "Running PROGRAM '%s'", buf);
|
||||||
|
|
||||||
r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof(result));
|
r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof(result), NULL);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_rule_warning_errno(dev, rules, r, "Failed to execute \"%s\": %m", buf);
|
log_rule_warning_errno(dev, rules, r, "Failed to execute \"%s\": %m", buf);
|
||||||
@ -1721,8 +1761,15 @@ static int udev_rule_apply_token_to_event(
|
|||||||
case TK_M_IMPORT_FILE: {
|
case TK_M_IMPORT_FILE: {
|
||||||
_cleanup_fclose_ FILE *f = NULL;
|
_cleanup_fclose_ FILE *f = NULL;
|
||||||
char buf[UDEV_PATH_SIZE];
|
char buf[UDEV_PATH_SIZE];
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
|
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_debug(dev, rules, "The file name '%s' to be imported is truncated while substituting into '%s', "
|
||||||
|
"assuming the IMPORT key does not match.", buf, token->value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false);
|
|
||||||
log_rule_debug(dev, rules, "Importing properties from '%s'", buf);
|
log_rule_debug(dev, rules, "Importing properties from '%s'", buf);
|
||||||
|
|
||||||
f = fopen(buf, "re");
|
f = fopen(buf, "re");
|
||||||
@ -1768,11 +1815,18 @@ static int udev_rule_apply_token_to_event(
|
|||||||
case TK_M_IMPORT_PROGRAM: {
|
case TK_M_IMPORT_PROGRAM: {
|
||||||
_cleanup_strv_free_ char **lines = NULL;
|
_cleanup_strv_free_ char **lines = NULL;
|
||||||
char buf[UDEV_PATH_SIZE], result[UDEV_LINE_SIZE], **line;
|
char buf[UDEV_PATH_SIZE], result[UDEV_LINE_SIZE], **line;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
|
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_debug(dev, rules, "The command '%s' is truncated while substituting into '%s', "
|
||||||
|
"assuming the IMPORT key does not match.", buf, token->value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false);
|
|
||||||
log_rule_debug(dev, rules, "Importing properties from results of '%s'", buf);
|
log_rule_debug(dev, rules, "Importing properties from results of '%s'", buf);
|
||||||
|
|
||||||
r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof result);
|
r = udev_event_spawn(event, timeout_usec, timeout_signal, true, buf, result, sizeof result, &truncated);
|
||||||
if (r != 0) {
|
if (r != 0) {
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_rule_warning_errno(dev, rules, r, "Failed to execute '%s', ignoring: %m", buf);
|
log_rule_warning_errno(dev, rules, r, "Failed to execute '%s', ignoring: %m", buf);
|
||||||
@ -1781,10 +1835,26 @@ static int udev_rule_apply_token_to_event(
|
|||||||
return token->op == OP_NOMATCH;
|
return token->op == OP_NOMATCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (truncated) {
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
/* Drop the last line. */
|
||||||
|
for (char *p = buf + strlen(buf) - 1; p >= buf; p--)
|
||||||
|
if (strchr(NEWLINE, *p)) {
|
||||||
|
*p = '\0';
|
||||||
|
found = true;
|
||||||
|
} else if (found)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
r = strv_split_newlines_full(&lines, result, EXTRACT_RETAIN_ESCAPE);
|
r = strv_split_newlines_full(&lines, result, EXTRACT_RETAIN_ESCAPE);
|
||||||
if (r < 0)
|
if (r == -ENOMEM)
|
||||||
|
return log_oom();
|
||||||
|
if (r < 0) {
|
||||||
log_rule_warning_errno(dev, rules, r,
|
log_rule_warning_errno(dev, rules, r,
|
||||||
"Failed to extract lines from result of command \"%s\", ignoring: %m", buf);
|
"Failed to extract lines from result of command \"%s\", ignoring: %m", buf);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
STRV_FOREACH(line, lines) {
|
STRV_FOREACH(line, lines) {
|
||||||
char *key, *value;
|
char *key, *value;
|
||||||
@ -1813,6 +1883,7 @@ static int udev_rule_apply_token_to_event(
|
|||||||
assert(cmd >= 0 && cmd < _UDEV_BUILTIN_MAX);
|
assert(cmd >= 0 && cmd < _UDEV_BUILTIN_MAX);
|
||||||
unsigned mask = 1U << (int) cmd;
|
unsigned mask = 1U << (int) cmd;
|
||||||
char buf[UDEV_PATH_SIZE];
|
char buf[UDEV_PATH_SIZE];
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
if (udev_builtin_run_once(cmd)) {
|
if (udev_builtin_run_once(cmd)) {
|
||||||
/* check if we ran already */
|
/* check if we ran already */
|
||||||
@ -1826,7 +1897,13 @@ static int udev_rule_apply_token_to_event(
|
|||||||
event->builtin_run |= mask;
|
event->builtin_run |= mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false);
|
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_debug(dev, rules, "The builtin command '%s' is truncated while substituting into '%s', "
|
||||||
|
"assuming the IMPORT key does not match", buf, token->value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
log_rule_debug(dev, rules, "Importing properties from results of builtin command '%s'", buf);
|
log_rule_debug(dev, rules, "Importing properties from results of builtin command '%s'", buf);
|
||||||
|
|
||||||
r = udev_builtin_run(dev, &event->rtnl, cmd, buf, false);
|
r = udev_builtin_run(dev, &event->rtnl, cmd, buf, false);
|
||||||
@ -1875,8 +1952,15 @@ static int udev_rule_apply_token_to_event(
|
|||||||
}
|
}
|
||||||
case TK_M_IMPORT_PARENT: {
|
case TK_M_IMPORT_PARENT: {
|
||||||
char buf[UDEV_PATH_SIZE];
|
char buf[UDEV_PATH_SIZE];
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
|
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_debug(dev, rules, "The property name '%s' is truncated while substituting into '%s', "
|
||||||
|
"assuming the IMPORT key does not match.", buf, token->value);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false);
|
|
||||||
r = import_parent_into_properties(dev, buf);
|
r = import_parent_into_properties(dev, buf);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_rule_error_errno(dev, rules, r,
|
return log_rule_error_errno(dev, rules, r,
|
||||||
@ -1925,13 +2009,20 @@ static int udev_rule_apply_token_to_event(
|
|||||||
case TK_A_OWNER: {
|
case TK_A_OWNER: {
|
||||||
char owner[UDEV_NAME_SIZE];
|
char owner[UDEV_NAME_SIZE];
|
||||||
const char *ow = owner;
|
const char *ow = owner;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
if (event->owner_final)
|
if (event->owner_final)
|
||||||
break;
|
break;
|
||||||
if (token->op == OP_ASSIGN_FINAL)
|
if (token->op == OP_ASSIGN_FINAL)
|
||||||
event->owner_final = true;
|
event->owner_final = true;
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, owner, sizeof(owner), false);
|
(void) udev_event_apply_format(event, token->value, owner, sizeof(owner), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The user name '%s' is truncated while substituting into '%s', "
|
||||||
|
"refusing to apply the OWNER key.", owner, token->value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
|
r = get_user_creds(&ow, &event->uid, NULL, NULL, NULL, USER_CREDS_ALLOW_MISSING);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_unknown_owner(dev, rules, r, "user", owner);
|
log_unknown_owner(dev, rules, r, "user", owner);
|
||||||
@ -1942,13 +2033,20 @@ static int udev_rule_apply_token_to_event(
|
|||||||
case TK_A_GROUP: {
|
case TK_A_GROUP: {
|
||||||
char group[UDEV_NAME_SIZE];
|
char group[UDEV_NAME_SIZE];
|
||||||
const char *gr = group;
|
const char *gr = group;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
if (event->group_final)
|
if (event->group_final)
|
||||||
break;
|
break;
|
||||||
if (token->op == OP_ASSIGN_FINAL)
|
if (token->op == OP_ASSIGN_FINAL)
|
||||||
event->group_final = true;
|
event->group_final = true;
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, group, sizeof(group), false);
|
(void) udev_event_apply_format(event, token->value, group, sizeof(group), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The group name '%s' is truncated while substituting into '%s', "
|
||||||
|
"refusing to apply the GROUP key.", group, token->value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
r = get_group_creds(&gr, &event->gid, USER_CREDS_ALLOW_MISSING);
|
r = get_group_creds(&gr, &event->gid, USER_CREDS_ALLOW_MISSING);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_unknown_owner(dev, rules, r, "group", group);
|
log_unknown_owner(dev, rules, r, "group", group);
|
||||||
@ -1958,13 +2056,20 @@ static int udev_rule_apply_token_to_event(
|
|||||||
}
|
}
|
||||||
case TK_A_MODE: {
|
case TK_A_MODE: {
|
||||||
char mode_str[UDEV_NAME_SIZE];
|
char mode_str[UDEV_NAME_SIZE];
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
if (event->mode_final)
|
if (event->mode_final)
|
||||||
break;
|
break;
|
||||||
if (token->op == OP_ASSIGN_FINAL)
|
if (token->op == OP_ASSIGN_FINAL)
|
||||||
event->mode_final = true;
|
event->mode_final = true;
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, mode_str, sizeof(mode_str), false);
|
(void) udev_event_apply_format(event, token->value, mode_str, sizeof(mode_str), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The mode '%s' is truncated while substituting into %s, "
|
||||||
|
"refusing to apply the MODE key.", mode_str, token->value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
r = parse_mode(mode_str, &event->mode);
|
r = parse_mode(mode_str, &event->mode);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
log_rule_error_errno(dev, rules, r, "Failed to parse mode '%s', ignoring: %m", mode_str);
|
log_rule_error_errno(dev, rules, r, "Failed to parse mode '%s', ignoring: %m", mode_str);
|
||||||
@ -2005,12 +2110,19 @@ static int udev_rule_apply_token_to_event(
|
|||||||
case TK_A_SECLABEL: {
|
case TK_A_SECLABEL: {
|
||||||
_cleanup_free_ char *name = NULL, *label = NULL;
|
_cleanup_free_ char *name = NULL, *label = NULL;
|
||||||
char label_str[UDEV_LINE_SIZE] = {};
|
char label_str[UDEV_LINE_SIZE] = {};
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
name = strdup(token->data);
|
name = strdup(token->data);
|
||||||
if (!name)
|
if (!name)
|
||||||
return log_oom();
|
return log_oom();
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, label_str, sizeof(label_str), false);
|
(void) udev_event_apply_format(event, token->value, label_str, sizeof(label_str), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The security label '%s' is truncated while substituting into '%s', "
|
||||||
|
"refusing to apply the SECLABEL key.", label_str, token->value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isempty(label_str))
|
if (!isempty(label_str))
|
||||||
label = strdup(label_str);
|
label = strdup(label_str);
|
||||||
else
|
else
|
||||||
@ -2037,6 +2149,7 @@ static int udev_rule_apply_token_to_event(
|
|||||||
const char *val, *name = token->data;
|
const char *val, *name = token->data;
|
||||||
char value_new[UDEV_NAME_SIZE], *p = value_new;
|
char value_new[UDEV_NAME_SIZE], *p = value_new;
|
||||||
size_t count, l = sizeof(value_new);
|
size_t count, l = sizeof(value_new);
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
if (isempty(token->value)) {
|
if (isempty(token->value)) {
|
||||||
if (token->op == OP_ADD)
|
if (token->op == OP_ADD)
|
||||||
@ -2048,10 +2161,22 @@ static int udev_rule_apply_token_to_event(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (token->op == OP_ADD &&
|
if (token->op == OP_ADD &&
|
||||||
sd_device_get_property_value(dev, name, &val) >= 0)
|
sd_device_get_property_value(dev, name, &val) >= 0) {
|
||||||
l = strpcpyl(&p, l, val, " ", NULL);
|
l = strpcpyl_full(&p, l, &truncated, val, " ", NULL);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The buffer for the property '%s' is full, "
|
||||||
|
"refusing to append the new value '%s'.", name, token->value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) udev_event_apply_format(event, token->value, p, l, false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The property value '%s' is truncated while substituting into '%s', "
|
||||||
|
"refusing to add property '%s'.", p, token->value, name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, p, l, false);
|
|
||||||
if (event->esc == ESCAPE_REPLACE) {
|
if (event->esc == ESCAPE_REPLACE) {
|
||||||
count = udev_replace_chars(p, NULL);
|
count = udev_replace_chars(p, NULL);
|
||||||
if (count > 0)
|
if (count > 0)
|
||||||
@ -2066,8 +2191,16 @@ static int udev_rule_apply_token_to_event(
|
|||||||
}
|
}
|
||||||
case TK_A_TAG: {
|
case TK_A_TAG: {
|
||||||
char buf[UDEV_PATH_SIZE];
|
char buf[UDEV_PATH_SIZE];
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
|
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The tag name '%s' is truncated while substituting into '%s',"
|
||||||
|
"refusing to %s the tag.", buf, token->value,
|
||||||
|
token->op == OP_REMOVE ? "remove" : "add");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false);
|
|
||||||
if (token->op == OP_ASSIGN)
|
if (token->op == OP_ASSIGN)
|
||||||
device_cleanup_tags(dev);
|
device_cleanup_tags(dev);
|
||||||
|
|
||||||
@ -2086,6 +2219,7 @@ static int udev_rule_apply_token_to_event(
|
|||||||
}
|
}
|
||||||
case TK_A_NAME: {
|
case TK_A_NAME: {
|
||||||
char buf[UDEV_PATH_SIZE];
|
char buf[UDEV_PATH_SIZE];
|
||||||
|
bool truncated;
|
||||||
size_t count;
|
size_t count;
|
||||||
|
|
||||||
if (event->name_final)
|
if (event->name_final)
|
||||||
@ -2100,7 +2234,13 @@ static int udev_rule_apply_token_to_event(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false);
|
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The network interface name '%s' is truncated while substituting into '%s', "
|
||||||
|
"refusing to set the name.", buf, token->value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (IN_SET(event->esc, ESCAPE_UNSET, ESCAPE_REPLACE)) {
|
if (IN_SET(event->esc, ESCAPE_UNSET, ESCAPE_REPLACE)) {
|
||||||
if (naming_scheme_has(NAMING_REPLACE_STRICTLY))
|
if (naming_scheme_has(NAMING_REPLACE_STRICTLY))
|
||||||
count = udev_replace_ifname(buf);
|
count = udev_replace_ifname(buf);
|
||||||
@ -2119,6 +2259,7 @@ static int udev_rule_apply_token_to_event(
|
|||||||
}
|
}
|
||||||
case TK_A_DEVLINK: {
|
case TK_A_DEVLINK: {
|
||||||
char buf[UDEV_PATH_SIZE], *p;
|
char buf[UDEV_PATH_SIZE], *p;
|
||||||
|
bool truncated;
|
||||||
size_t count;
|
size_t count;
|
||||||
|
|
||||||
if (event->devlink_final)
|
if (event->devlink_final)
|
||||||
@ -2131,7 +2272,13 @@ static int udev_rule_apply_token_to_event(
|
|||||||
device_cleanup_devlinks(dev);
|
device_cleanup_devlinks(dev);
|
||||||
|
|
||||||
/* allow multiple symlinks separated by spaces */
|
/* allow multiple symlinks separated by spaces */
|
||||||
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), event->esc != ESCAPE_NONE);
|
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), event->esc != ESCAPE_NONE, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The symbolic link path '%s' is truncated while substituting into '%s', "
|
||||||
|
"refusing to add the device symbolic link.", buf, token->value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (event->esc == ESCAPE_UNSET)
|
if (event->esc == ESCAPE_UNSET)
|
||||||
count = udev_replace_chars(buf, "/ ");
|
count = udev_replace_chars(buf, "/ ");
|
||||||
else if (event->esc == ESCAPE_REPLACE)
|
else if (event->esc == ESCAPE_REPLACE)
|
||||||
@ -2152,7 +2299,10 @@ static int udev_rule_apply_token_to_event(
|
|||||||
next = skip_leading_chars(next, NULL);
|
next = skip_leading_chars(next, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
strscpyl(filename, sizeof(filename), "/dev/", p, NULL);
|
strscpyl_full(filename, sizeof(filename), &truncated, "/dev/", p, NULL);
|
||||||
|
if (truncated)
|
||||||
|
continue;
|
||||||
|
|
||||||
r = device_add_devlink(dev, filename);
|
r = device_add_devlink(dev, filename);
|
||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_rule_error_errno(dev, rules, r, "Failed to add devlink '%s': %m", filename);
|
return log_rule_error_errno(dev, rules, r, "Failed to add devlink '%s': %m", filename);
|
||||||
@ -2165,17 +2315,30 @@ static int udev_rule_apply_token_to_event(
|
|||||||
case TK_A_ATTR: {
|
case TK_A_ATTR: {
|
||||||
char buf[UDEV_PATH_SIZE], value[UDEV_NAME_SIZE];
|
char buf[UDEV_PATH_SIZE], value[UDEV_NAME_SIZE];
|
||||||
const char *val, *key_name = token->data;
|
const char *val, *key_name = token->data;
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
if (udev_resolve_subsys_kernel(key_name, buf, sizeof(buf), false) < 0 &&
|
if (udev_resolve_subsys_kernel(key_name, buf, sizeof(buf), false) < 0 &&
|
||||||
sd_device_get_syspath(dev, &val) >= 0)
|
sd_device_get_syspath(dev, &val) >= 0) {
|
||||||
strscpyl(buf, sizeof(buf), val, "/", key_name, NULL);
|
strscpyl_full(buf, sizeof(buf), &truncated, val, "/", key_name, NULL);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules,
|
||||||
|
"The path to the attribute '%s/%s' is too long, refusing to set the attribute.",
|
||||||
|
val, key_name);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
r = attr_subst_subdir(buf);
|
r = attr_subst_subdir(buf);
|
||||||
if (r < 0) {
|
if (r < 0) {
|
||||||
log_rule_error_errno(dev, rules, r, "Could not find file matches '%s', ignoring: %m", buf);
|
log_rule_error_errno(dev, rules, r, "Could not find file matches '%s', ignoring: %m", buf);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
(void) udev_event_apply_format(event, token->value, value, sizeof(value), false);
|
(void) udev_event_apply_format(event, token->value, value, sizeof(value), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The attribute value '%s' is truncated while substituting into '%s', "
|
||||||
|
"refusing to set the attribute '%s'", value, token->value, buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
log_rule_debug(dev, rules, "ATTR '%s' writing '%s'", buf, value);
|
log_rule_debug(dev, rules, "ATTR '%s' writing '%s'", buf, value);
|
||||||
r = write_string_file(buf, value,
|
r = write_string_file(buf, value,
|
||||||
@ -2189,9 +2352,22 @@ static int udev_rule_apply_token_to_event(
|
|||||||
}
|
}
|
||||||
case TK_A_SYSCTL: {
|
case TK_A_SYSCTL: {
|
||||||
char buf[UDEV_PATH_SIZE], value[UDEV_NAME_SIZE];
|
char buf[UDEV_PATH_SIZE], value[UDEV_NAME_SIZE];
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
|
(void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The sysctl entry name '%s' is truncated while substituting into '%s', "
|
||||||
|
"refusing to set the sysctl entry.", buf, (const char*) token->data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) udev_event_apply_format(event, token->value, value, sizeof(value), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The sysctl value '%s' is truncated while substituting into '%s', "
|
||||||
|
"refusing to set the sysctl entry '%s'", value, token->value, buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->data, buf, sizeof(buf), false);
|
|
||||||
(void) udev_event_apply_format(event, token->value, value, sizeof(value), false);
|
|
||||||
sysctl_normalize(buf);
|
sysctl_normalize(buf);
|
||||||
log_rule_debug(dev, rules, "SYSCTL '%s' writing '%s'", buf, value);
|
log_rule_debug(dev, rules, "SYSCTL '%s' writing '%s'", buf, value);
|
||||||
r = sysctl_write(buf, value);
|
r = sysctl_write(buf, value);
|
||||||
@ -2203,6 +2379,7 @@ static int udev_rule_apply_token_to_event(
|
|||||||
case TK_A_RUN_PROGRAM: {
|
case TK_A_RUN_PROGRAM: {
|
||||||
_cleanup_free_ char *cmd = NULL;
|
_cleanup_free_ char *cmd = NULL;
|
||||||
char buf[UDEV_PATH_SIZE];
|
char buf[UDEV_PATH_SIZE];
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
if (event->run_final)
|
if (event->run_final)
|
||||||
break;
|
break;
|
||||||
@ -2212,7 +2389,12 @@ static int udev_rule_apply_token_to_event(
|
|||||||
if (IN_SET(token->op, OP_ASSIGN, OP_ASSIGN_FINAL))
|
if (IN_SET(token->op, OP_ASSIGN, OP_ASSIGN_FINAL))
|
||||||
ordered_hashmap_clear_free_key(event->run_list);
|
ordered_hashmap_clear_free_key(event->run_list);
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false);
|
(void) udev_event_apply_format(event, token->value, buf, sizeof(buf), false, &truncated);
|
||||||
|
if (truncated) {
|
||||||
|
log_rule_warning(dev, rules, "The command '%s' is truncated while substituting into '%s', "
|
||||||
|
"refusing to invoke the command.", buf, token->value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
cmd = strdup(buf);
|
cmd = strdup(buf);
|
||||||
if (!cmd)
|
if (!cmd)
|
||||||
|
|||||||
@ -87,6 +87,11 @@ int control_main(int argc, char *argv[], void *userdata) {
|
|||||||
if (r < 0)
|
if (r < 0)
|
||||||
return log_error_errno(r, "Failed to initialize udev control: %m");
|
return log_error_errno(r, "Failed to initialize udev control: %m");
|
||||||
|
|
||||||
|
/* See comments in on_post() in udevd.c. */
|
||||||
|
r = udev_ctrl_send_pid(uctrl);
|
||||||
|
if (r < 0)
|
||||||
|
return log_error_errno(r, "Failed to send pid of this process: %m");
|
||||||
|
|
||||||
while ((c = getopt_long(argc, argv, "el:sSRp:m:t:Vh", options, NULL)) >= 0)
|
while ((c = getopt_long(argc, argv, "el:sSRp:m:t:Vh", options, NULL)) >= 0)
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'e':
|
case 'e':
|
||||||
|
|||||||
@ -135,8 +135,11 @@ int test_main(int argc, char *argv[], void *userdata) {
|
|||||||
|
|
||||||
ORDERED_HASHMAP_FOREACH_KEY(val, cmd, event->run_list) {
|
ORDERED_HASHMAP_FOREACH_KEY(val, cmd, event->run_list) {
|
||||||
char program[UDEV_PATH_SIZE];
|
char program[UDEV_PATH_SIZE];
|
||||||
|
bool truncated;
|
||||||
|
|
||||||
(void) udev_event_apply_format(event, cmd, program, sizeof(program), false);
|
(void) udev_event_apply_format(event, cmd, program, sizeof(program), false, &truncated);
|
||||||
|
if (truncated)
|
||||||
|
log_warning("The command '%s' is truncated while substituting into '%s'.", program, cmd);
|
||||||
printf("run: '%s'\n", program);
|
printf("run: '%s'\n", program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -108,6 +108,8 @@ typedef struct Manager {
|
|||||||
|
|
||||||
bool stop_exec_queue;
|
bool stop_exec_queue;
|
||||||
bool exit;
|
bool exit;
|
||||||
|
|
||||||
|
pid_t pid_udevadm; /* pid of 'udevadm control' */
|
||||||
} Manager;
|
} Manager;
|
||||||
|
|
||||||
typedef enum EventState {
|
typedef enum EventState {
|
||||||
@ -1215,6 +1217,10 @@ static int on_ctrl_msg(UdevCtrl *uctrl, UdevCtrlMessageType type, const UdevCtrl
|
|||||||
log_debug("Received udev control message (EXIT)");
|
log_debug("Received udev control message (EXIT)");
|
||||||
manager_exit(manager);
|
manager_exit(manager);
|
||||||
break;
|
break;
|
||||||
|
case UDEV_CTRL_SENDER_PID:
|
||||||
|
log_debug("Received udev control message (SENDER_PID)");
|
||||||
|
manager->pid_udevadm = value->pid;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
log_debug("Received unknown udev control message, ignoring");
|
log_debug("Received unknown udev control message, ignoring");
|
||||||
}
|
}
|
||||||
@ -1490,9 +1496,35 @@ static int on_post(sd_event_source *s, void *userdata) {
|
|||||||
if (manager->exit)
|
if (manager->exit)
|
||||||
return sd_event_exit(manager->event, 0);
|
return sd_event_exit(manager->event, 0);
|
||||||
|
|
||||||
if (manager->cgroup)
|
if (!manager->cgroup)
|
||||||
/* cleanup possible left-over processes in our cgroup */
|
return 1;
|
||||||
(void) cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, CGROUP_IGNORE_SELF, NULL, NULL, NULL);
|
|
||||||
|
/* Cleanup possible left-over processes in our cgroup. But do not kill udevadm called by
|
||||||
|
* ExecReload= in systemd-udevd.service. See #16867. To protect it, the following two ways are
|
||||||
|
* introduced:
|
||||||
|
*
|
||||||
|
* 1. After the connection is accepted, but the PID of udevadm is not received, do not call
|
||||||
|
* cg_kill(). So, in this period, unwanted process or threads may exist in our cgroup.
|
||||||
|
* But, it is expected that the PID of the udevadm will be received soon. So, this time
|
||||||
|
* period should be short enough.
|
||||||
|
* 2. After the PID of udevadm is received, check the process is active or not, and if it is
|
||||||
|
* still active, set the PID to the deny list for cg_kill(). Why udev_ctrl_is_connected() is
|
||||||
|
* not enough? Because the udevadm may be still active after the control socket is
|
||||||
|
* disconnected. If the process is not active, then clear the PID for later connections.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (udev_ctrl_is_connected(manager->ctrl) >= 0 && !pid_is_valid(manager->pid_udevadm))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
_cleanup_set_free_ Set *pids = NULL;
|
||||||
|
if (pid_is_valid(manager->pid_udevadm)) {
|
||||||
|
if (pid_is_alive(manager->pid_udevadm))
|
||||||
|
(void) set_ensure_put(&pids, NULL, PID_TO_PTR(manager->pid_udevadm));
|
||||||
|
else
|
||||||
|
manager->pid_udevadm = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void) cg_kill(SYSTEMD_CGROUP_CONTROLLER, manager->cgroup, SIGKILL, CGROUP_IGNORE_SELF, pids, NULL, NULL);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
1
test/TEST-68-PROPAGATE-EXIT-STATUS/Makefile
Symbolic link
1
test/TEST-68-PROPAGATE-EXIT-STATUS/Makefile
Symbolic link
@ -0,0 +1 @@
|
|||||||
|
../TEST-01-BASIC/Makefile
|
||||||
11
test/TEST-68-PROPAGATE-EXIT-STATUS/test.sh
Executable file
11
test/TEST-68-PROPAGATE-EXIT-STATUS/test.sh
Executable file
@ -0,0 +1,11 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
set -e
|
||||||
|
|
||||||
|
TEST_DESCRIPTION="Test propagation of exit status to On{Failure,Success}= dependencies"
|
||||||
|
TEST_NO_QEMU=1
|
||||||
|
|
||||||
|
# shellcheck source=test/test-functions
|
||||||
|
. "$TEST_BASE_DIR/test-functions"
|
||||||
|
|
||||||
|
do_test "$@"
|
||||||
@ -1932,11 +1932,9 @@ inst_libs() {
|
|||||||
|
|
||||||
while read -r line; do
|
while read -r line; do
|
||||||
[[ "$line" = 'not a dynamic executable' ]] && break
|
[[ "$line" = 'not a dynamic executable' ]] && break
|
||||||
# Skip a harmless error when running the tests on a system with a significantly
|
# Ignore errors about our own stuff missing. This is most likely caused
|
||||||
# older systemd version (ldd tries to resolve the unprefixed RPATH for libsystemd.so.0,
|
# by ldd attempting to use the unprefixed RPATH.
|
||||||
# which is in this case older than the already installed libsystemd.so.0 in $initdir).
|
[[ "$line" =~ libsystemd.*\ not\ found ]] && continue
|
||||||
# The issue is triggered by installing test dependencies in install_missing_libraries().
|
|
||||||
[[ "$line" =~ libsystemd.so.*:\ version\ .*\ not\ found ]] && continue
|
|
||||||
|
|
||||||
if [[ "$line" =~ $so_regex ]]; then
|
if [[ "$line" =~ $so_regex ]]; then
|
||||||
file="${BASH_REMATCH[1]}"
|
file="${BASH_REMATCH[1]}"
|
||||||
@ -2309,7 +2307,7 @@ inst_binary() {
|
|||||||
# In certain cases we might attempt to install a binary which is already
|
# In certain cases we might attempt to install a binary which is already
|
||||||
# present in the test image, yet it's missing from the host system.
|
# present in the test image, yet it's missing from the host system.
|
||||||
# In such cases, let's check if the binary indeed exists in the image
|
# In such cases, let's check if the binary indeed exists in the image
|
||||||
# before doing any other chcecks. If it does, immediately return with
|
# before doing any other checks. If it does, immediately return with
|
||||||
# success.
|
# success.
|
||||||
if [[ $# -eq 1 ]]; then
|
if [[ $# -eq 1 ]]; then
|
||||||
for path in "" bin sbin usr/bin usr/sbin; do
|
for path in "" bin sbin usr/bin usr/sbin; do
|
||||||
@ -2328,6 +2326,10 @@ inst_binary() {
|
|||||||
while read -r line; do
|
while read -r line; do
|
||||||
[[ "$line" = 'not a dynamic executable' ]] && break
|
[[ "$line" = 'not a dynamic executable' ]] && break
|
||||||
|
|
||||||
|
# Ignore errors about our own stuff missing. This is most likely caused
|
||||||
|
# by ldd attempting to use the unprefixed RPATH.
|
||||||
|
[[ "$line" =~ libsystemd.*\ not\ found ]] && continue
|
||||||
|
|
||||||
if [[ "$line" =~ $so_regex ]]; then
|
if [[ "$line" =~ $so_regex ]]; then
|
||||||
file="${BASH_REMATCH[1]}"
|
file="${BASH_REMATCH[1]}"
|
||||||
[[ -e "${initdir}/$file" ]] && continue
|
[[ -e "${initdir}/$file" ]] && continue
|
||||||
|
|||||||
@ -0,0 +1,9 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[NetDev]
|
||||||
|
Name=ip6tnl-slaac
|
||||||
|
Kind=ip6tnl
|
||||||
|
|
||||||
|
[Tunnel]
|
||||||
|
Mode=ip6ip6
|
||||||
|
Local=slaac
|
||||||
|
Remote=2001:473:fece:cafe::5179
|
||||||
10
test/test-network/conf/25-ip6tnl-tunnel-local-slaac.network
Normal file
10
test/test-network/conf/25-ip6tnl-tunnel-local-slaac.network
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Match]
|
||||||
|
Name=ip6tnl-slaac
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
IPv6AcceptRA=no
|
||||||
|
LinkLocalAddressing=yes
|
||||||
|
|
||||||
|
[Route]
|
||||||
|
Destination=0.0.0.0/0
|
||||||
10
test/test-network/conf/ip6tnl-slaac.network
Normal file
10
test/test-network/conf/ip6tnl-slaac.network
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Match]
|
||||||
|
Name=veth99
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
IPv6AcceptRA=yes
|
||||||
|
Tunnel=ip6tnl-slaac
|
||||||
|
|
||||||
|
[IPv6AcceptRA]
|
||||||
|
PrefixAllowList=2002:da8:1::/64
|
||||||
@ -900,6 +900,7 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
|
|||||||
'ip6gretun97',
|
'ip6gretun97',
|
||||||
'ip6gretun98',
|
'ip6gretun98',
|
||||||
'ip6gretun99',
|
'ip6gretun99',
|
||||||
|
'ip6tnl-slaac',
|
||||||
'ip6tnl97',
|
'ip6tnl97',
|
||||||
'ip6tnl98',
|
'ip6tnl98',
|
||||||
'ip6tnl99',
|
'ip6tnl99',
|
||||||
@ -986,6 +987,8 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
|
|||||||
'25-ip6gre-tunnel.netdev',
|
'25-ip6gre-tunnel.netdev',
|
||||||
'25-ip6tnl-tunnel-any-any.netdev',
|
'25-ip6tnl-tunnel-any-any.netdev',
|
||||||
'25-ip6tnl-tunnel-local-any.netdev',
|
'25-ip6tnl-tunnel-local-any.netdev',
|
||||||
|
'25-ip6tnl-tunnel-local-slaac.netdev',
|
||||||
|
'25-ip6tnl-tunnel-local-slaac.network',
|
||||||
'25-ip6tnl-tunnel-remote-any.netdev',
|
'25-ip6tnl-tunnel-remote-any.netdev',
|
||||||
'25-ip6tnl-tunnel.netdev',
|
'25-ip6tnl-tunnel.netdev',
|
||||||
'25-ipip-tunnel-any-any.netdev',
|
'25-ipip-tunnel-any-any.netdev',
|
||||||
@ -1044,8 +1047,10 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
|
|||||||
'gretun.network',
|
'gretun.network',
|
||||||
'ip6gretap.network',
|
'ip6gretap.network',
|
||||||
'ip6gretun.network',
|
'ip6gretun.network',
|
||||||
|
'ip6tnl-slaac.network',
|
||||||
'ip6tnl.network',
|
'ip6tnl.network',
|
||||||
'ipip.network',
|
'ipip.network',
|
||||||
|
'ipv6-prefix.network',
|
||||||
'ipvlan.network',
|
'ipvlan.network',
|
||||||
'ipvtap.network',
|
'ipvtap.network',
|
||||||
'isatap.network',
|
'isatap.network',
|
||||||
@ -1664,19 +1669,33 @@ class NetworkdNetDevTests(unittest.TestCase, Utilities):
|
|||||||
copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
|
copy_unit_to_networkd_unit_path('12-dummy.netdev', 'ip6tnl.network',
|
||||||
'25-ip6tnl-tunnel.netdev', '25-tunnel.network',
|
'25-ip6tnl-tunnel.netdev', '25-tunnel.network',
|
||||||
'25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
|
'25-ip6tnl-tunnel-local-any.netdev', '25-tunnel-local-any.network',
|
||||||
'25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network')
|
'25-ip6tnl-tunnel-remote-any.netdev', '25-tunnel-remote-any.network',
|
||||||
|
'25-veth.netdev', 'ip6tnl-slaac.network', 'ipv6-prefix.network',
|
||||||
|
'25-ip6tnl-tunnel-local-slaac.netdev', '25-ip6tnl-tunnel-local-slaac.network')
|
||||||
start_networkd()
|
start_networkd()
|
||||||
self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'dummy98:degraded'])
|
self.wait_online(['ip6tnl99:routable', 'ip6tnl98:routable', 'ip6tnl97:routable', 'ip6tnl-slaac:degraded',
|
||||||
|
'dummy98:degraded', 'veth99:routable', 'veth-peer:degraded'])
|
||||||
|
|
||||||
output = check_output('ip -d link show ip6tnl99')
|
output = check_output('ip -d link show ip6tnl99')
|
||||||
print(output)
|
print(output)
|
||||||
self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98')
|
self.assertIn('ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2a00:ffde:4567:edde::4987 dev dummy98', output)
|
||||||
output = check_output('ip -d link show ip6tnl98')
|
output = check_output('ip -d link show ip6tnl98')
|
||||||
print(output)
|
print(output)
|
||||||
self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
|
self.assertRegex(output, 'ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local (any|::) dev dummy98')
|
||||||
output = check_output('ip -d link show ip6tnl97')
|
output = check_output('ip -d link show ip6tnl97')
|
||||||
print(output)
|
print(output)
|
||||||
self.assertRegex(output, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
|
self.assertRegex(output, 'ip6tnl ip6ip6 remote (any|::) local 2a00:ffde:4567:edde::4987 dev dummy98')
|
||||||
|
output = check_output('ip -d link show ip6tnl-slaac')
|
||||||
|
print(output)
|
||||||
|
self.assertIn('ip6tnl ip6ip6 remote 2001:473:fece:cafe::5179 local 2002:da8:1:0:1034:56ff:fe78:9abc dev veth99', output)
|
||||||
|
|
||||||
|
output = check_output('ip -6 address show veth99')
|
||||||
|
print(output)
|
||||||
|
self.assertIn('inet6 2002:da8:1:0:1034:56ff:fe78:9abc/64 scope global dynamic', output)
|
||||||
|
|
||||||
|
output = check_output('ip -4 route show default')
|
||||||
|
print(output)
|
||||||
|
self.assertIn('default dev ip6tnl-slaac proto static', output)
|
||||||
|
|
||||||
def test_sit_tunnel(self):
|
def test_sit_tunnel(self):
|
||||||
copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
|
copy_unit_to_networkd_unit_path('12-dummy.netdev', 'sit.network',
|
||||||
|
|||||||
7
test/units/testsuite-68.service
Normal file
7
test/units/testsuite-68.service
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
[Unit]
|
||||||
|
Description=TEST-68-PROPAGATE-EXIT-STATUS
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/lib/systemd/tests/testdata/units/%N.sh
|
||||||
230
test/units/testsuite-68.sh
Executable file
230
test/units/testsuite-68.sh
Executable file
@ -0,0 +1,230 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||||
|
set -ex
|
||||||
|
set -o pipefail
|
||||||
|
|
||||||
|
# Wait for a service to enter a state within a timeout period, if it doesn't
|
||||||
|
# enter the desired state within the timeout period then this function will
|
||||||
|
# exit the test case with a non zero exit code.
|
||||||
|
wait_on_state_or_fail () {
|
||||||
|
service=$1
|
||||||
|
expected_state=$2
|
||||||
|
timeout=$3
|
||||||
|
|
||||||
|
state=$(systemctl show "$service" --property=ActiveState --value)
|
||||||
|
while [ "$state" != "$expected_state" ]; do
|
||||||
|
if [ "$timeout" = "0" ]; then
|
||||||
|
systemd-analyze log-level info
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
timeout=$((timeout - 1))
|
||||||
|
sleep 1
|
||||||
|
state=$(systemctl show "$service" --property=ActiveState --value)
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
systemd-analyze log-level debug
|
||||||
|
systemd-analyze log-target console
|
||||||
|
|
||||||
|
# Trigger testservice-failure-exit-handler-68.service
|
||||||
|
cat >/run/systemd/system/testservice-failure-68.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=TEST-68-PROPAGATE-EXIT-STATUS with OnFailure= trigger
|
||||||
|
OnFailure=testservice-failure-exit-handler-68.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/bash -c "exit 1"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Another service which triggers testservice-failure-exit-handler-68.service
|
||||||
|
cat >/run/systemd/system/testservice-failure-68-additional.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=TEST-68-PROPAGATE-EXIT-STATUS Additional service with OnFailure= trigger
|
||||||
|
OnFailure=testservice-failure-exit-handler-68.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/bash -c "exit 1"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Trigger testservice-success-exit-handler-68.service
|
||||||
|
cat >/run/systemd/system/testservice-success-68.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=TEST-68-PROPAGATE-EXIT-STATUS with OnSuccess= trigger
|
||||||
|
OnSuccess=testservice-success-exit-handler-68.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/bash -c "exit 0"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Trigger testservice-success-exit-handler-68.service
|
||||||
|
cat >/run/systemd/system/testservice-success-68-additional.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=TEST-68-PROPAGATE-EXIT-STATUS Addition service with OnSuccess= trigger
|
||||||
|
OnSuccess=testservice-success-exit-handler-68.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStart=/bin/bash -c "exit 0"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Script to check that when an OnSuccess= dependency fires, the correct
|
||||||
|
# MONITOR* env variables are passed. This script handles the case where
|
||||||
|
# multiple services triggered the unit that calls this script. In this
|
||||||
|
# case we need to check the MONITOR_METADATA variable for >= 1 service
|
||||||
|
# details since jobs may merge.
|
||||||
|
cat >/tmp/check_on_success.sh <<EOF
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
echo "MONITOR_METADATA=\$MONITOR_METADATA"
|
||||||
|
|
||||||
|
IFS=';' read -ra ALL_SERVICE_MD <<< "\$MONITOR_METADATA"
|
||||||
|
for SERVICE_MD in "\${ALL_SERVICE_MD[@]}"; do
|
||||||
|
IFS=',' read -ra METADATA <<< "\$SERVICE_MD"
|
||||||
|
IFS='=' read -ra SERVICE_RESULT <<< "\${METADATA[0]}"
|
||||||
|
SERVICE_RESULT=\${SERVICE_RESULT[1]}
|
||||||
|
IFS='=' read -ra EXIT_CODE <<< "\${METADATA[1]}"
|
||||||
|
EXIT_CODE=\${EXIT_CODE[1]}
|
||||||
|
IFS='=' read -ra EXIT_STATUS <<< "\${METADATA[2]}"
|
||||||
|
EXIT_STATUS=\${EXIT_STATUS[1]}
|
||||||
|
IFS='=' read -ra INVOCATION_ID <<< "\${METADATA[3]}"
|
||||||
|
INVOCATION_ID=\${INVOCATION_ID[1]}
|
||||||
|
IFS='=' read -ra UNIT <<< "\${METADATA[4]}"
|
||||||
|
UNIT=\${UNIT[1]}
|
||||||
|
|
||||||
|
if [ "\$SERVICE_RESULT" != "success" ]; then
|
||||||
|
echo 'SERVICE_RESULT was "\$SERVICE_RESULT", expected "success"';
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "\$EXIT_CODE" != "exited" ]; then
|
||||||
|
echo 'EXIT_CODE was "\$EXIT_CODE", expected "exited"';
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "\$EXIT_STATUS" != "0" ]; then
|
||||||
|
echo 'EXIT_STATUS was "\$EXIT_STATUS", expected "0"';
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "\$INVOCATION_ID" ]; then
|
||||||
|
echo 'INVOCATION_ID unset';
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "\$UNIT" != "testservice-success-68.service" && "\$UNIT" != "testservice-success-68-additional.service" && "\$UNIT" != "testservice-transient-success-68.service" ]]; then
|
||||||
|
echo 'UNIT was "\$UNIT", expected "testservice-success-68{-additional,-transient}.service"';
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
EOF
|
||||||
|
chmod +x /tmp/check_on_success.sh
|
||||||
|
|
||||||
|
# Handle testservice-failure-exit-handler-68.service exiting with success.
|
||||||
|
cat >/run/systemd/system/testservice-success-exit-handler-68.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=TEST-68-PROPAGATE-EXIT-STATUS handle service exiting in success
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStartPre=/tmp/check_on_success.sh
|
||||||
|
ExecStart=/tmp/check_on_success.sh
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Script to check that when an OnFailure= dependency fires, the correct
|
||||||
|
# MONITOR* env variables are passed. This script handles the case where
|
||||||
|
# multiple services triggered the unit that calls this script. In this
|
||||||
|
# case we need to check the MONITOR_METADATA variable for >=1 service
|
||||||
|
# details since jobs may merge.
|
||||||
|
cat >/tmp/check_on_failure.sh <<EOF
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -ex
|
||||||
|
|
||||||
|
echo "MONITOR_METADATA=\$MONITOR_METADATA"
|
||||||
|
|
||||||
|
IFS=';' read -ra ALL_SERVICE_MD <<< "\$MONITOR_METADATA"
|
||||||
|
for SERVICE_MD in "\${ALL_SERVICE_MD[@]}"; do
|
||||||
|
IFS=',' read -ra METADATA <<< "\$SERVICE_MD"
|
||||||
|
IFS='=' read -ra SERVICE_RESULT <<< "\${METADATA[0]}"
|
||||||
|
SERVICE_RESULT=\${SERVICE_RESULT[1]}
|
||||||
|
IFS='=' read -ra EXIT_CODE <<< "\${METADATA[1]}"
|
||||||
|
EXIT_CODE=\${EXIT_CODE[1]}
|
||||||
|
IFS='=' read -ra EXIT_STATUS <<< "\${METADATA[2]}"
|
||||||
|
EXIT_STATUS=\${EXIT_STATUS[1]}
|
||||||
|
IFS='=' read -ra INVOCATION_ID <<< "\${METADATA[3]}"
|
||||||
|
INVOCATION_ID=\${INVOCATION_ID[1]}
|
||||||
|
IFS='=' read -ra UNIT <<< "\${METADATA[4]}"
|
||||||
|
UNIT=\${UNIT[1]}
|
||||||
|
|
||||||
|
if [ "\$SERVICE_RESULT" != "exit-code" ]; then
|
||||||
|
echo 'SERVICE_RESULT was "\$SERVICE_RESULT", expected "exit-code"';
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "\$EXIT_CODE" != "exited" ]; then
|
||||||
|
echo 'EXIT_CODE was "\$EXIT_CODE", expected "exited"';
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "\$EXIT_STATUS" != "1" ]; then
|
||||||
|
echo 'EXIT_STATUS was "\$EXIT_STATUS", expected "1"';
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -z "\$INVOCATION_ID" ]; then
|
||||||
|
echo 'INVOCATION_ID unset';
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ "\$UNIT" != "testservice-failure-68.service" && "\$UNIT" != "testservice-failure-68-additional.service" && "\$UNIT" != "testservice-transient-failure-68.service" ]]; then
|
||||||
|
echo 'UNIT was "\$UNIT", expected "testservice-failure-68{-additional,-transient}.service"';
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
exit 0;
|
||||||
|
EOF
|
||||||
|
chmod +x /tmp/check_on_failure.sh
|
||||||
|
|
||||||
|
|
||||||
|
# Handle testservice-failure-exit-handler-68.service exiting with failure.
|
||||||
|
cat >/run/systemd/system/testservice-failure-exit-handler-68.service <<EOF
|
||||||
|
[Unit]
|
||||||
|
Description=TEST-68-PROPAGATE-EXIT-STATUS handle service exiting in failure
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
ExecStartPre=/tmp/check_on_failure.sh
|
||||||
|
ExecStart=/tmp/check_on_failure.sh
|
||||||
|
EOF
|
||||||
|
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
# The running of the OnFailure= and OnSuccess= jobs for all of these services
|
||||||
|
# may result in jobs being merged.
|
||||||
|
systemctl start testservice-failure-68.service
|
||||||
|
wait_on_state_or_fail "testservice-failure-exit-handler-68.service" "inactive" "10"
|
||||||
|
systemctl start testservice-failure-68-additional.service
|
||||||
|
wait_on_state_or_fail "testservice-failure-exit-handler-68.service" "inactive" "10"
|
||||||
|
systemctl start testservice-success-68.service
|
||||||
|
wait_on_state_or_fail "testservice-success-exit-handler-68.service" "inactive" "10"
|
||||||
|
systemctl start testservice-success-68-additional.service
|
||||||
|
wait_on_state_or_fail "testservice-success-exit-handler-68.service" "inactive" "10"
|
||||||
|
|
||||||
|
# Test some transient units since these exit very quickly.
|
||||||
|
systemd-run --unit=testservice-transient-success-68 --property=OnSuccess=testservice-success-exit-handler-68.service /bin/bash -c "exit 0;"
|
||||||
|
wait_on_state_or_fail "testservice-success-exit-handler-68.service" "inactive" "10"
|
||||||
|
systemd-run --unit=testservice-transient-failure-68 --property=OnFailure=testservice-failure-exit-handler-68.service /bin/bash -c "exit 1;"
|
||||||
|
wait_on_state_or_fail "testservice-failure-exit-handler-68.service" "inactive" "10"
|
||||||
|
|
||||||
|
# These yield a higher chance of resulting in jobs merging.
|
||||||
|
systemctl start testservice-failure-68.service testservice-failure-68-additional.service --no-block
|
||||||
|
wait_on_state_or_fail "testservice-failure-exit-handler-68.service" "inactive" "10"
|
||||||
|
systemctl start testservice-success-68.service testservice-success-68-additional.service --no-block
|
||||||
|
wait_on_state_or_fail "testservice-success-exit-handler-68.service" "inactive" "10"
|
||||||
|
|
||||||
|
systemd-analyze log-level info
|
||||||
|
echo OK >/testok
|
||||||
|
|
||||||
|
exit 0
|
||||||
@ -12,6 +12,7 @@ L+ /etc/mtab - - - - ../proc/self/mounts
|
|||||||
{% if HAVE_SMACK_RUN_LABEL %}
|
{% if HAVE_SMACK_RUN_LABEL %}
|
||||||
t /etc/mtab - - - - security.SMACK64=_
|
t /etc/mtab - - - - security.SMACK64=_
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
C! /etc/locale.conf - - - -
|
||||||
C! /etc/nsswitch.conf - - - -
|
C! /etc/nsswitch.conf - - - -
|
||||||
{% if HAVE_PAM %}
|
{% if HAVE_PAM %}
|
||||||
C! /etc/pam.d - - - -
|
C! /etc/pam.d - - - -
|
||||||
|
|||||||
@ -67,7 +67,9 @@ df="$build/dns-fuzzing"
|
|||||||
git clone --depth 1 https://github.com/CZ-NIC/dns-fuzzing "$df"
|
git clone --depth 1 https://github.com/CZ-NIC/dns-fuzzing "$df"
|
||||||
zip -jqr "$OUT/fuzz-dns-packet_seed_corpus.zip" "$df/packet"
|
zip -jqr "$OUT/fuzz-dns-packet_seed_corpus.zip" "$df/packet"
|
||||||
|
|
||||||
install -Dt "$OUT/src/shared/" "$build"/src/shared/libsystemd-shared-*.so
|
install -Dt "$OUT/src/shared/" \
|
||||||
|
"$build"/src/shared/libsystemd-shared-*.so \
|
||||||
|
"$build"/src/core/libsystemd-core-*.so
|
||||||
|
|
||||||
wget -O "$OUT/fuzz-json.dict" https://raw.githubusercontent.com/rc0r/afl-fuzz/master/dictionaries/json.dict
|
wget -O "$OUT/fuzz-json.dict" https://raw.githubusercontent.com/rc0r/afl-fuzz/master/dictionaries/json.dict
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user