mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-06 07:58:00 +02:00
release: bump version to 1.47.1 (development)
This commit is contained in:
commit
9920a4b576
152 changed files with 16355 additions and 11930 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -183,6 +183,7 @@ test-*.trs
|
|||
|
||||
/src/nm-online/nm-online
|
||||
|
||||
/m4/build-to-host.m4
|
||||
/m4/codeset.m4
|
||||
/m4/gettext.m4
|
||||
/m4/glibc2.m4
|
||||
|
|
|
|||
|
|
@ -58,9 +58,9 @@ variables:
|
|||
# This is done by running `ci-fairy generate-template` and possibly bumping
|
||||
# ".default_tag".
|
||||
ALPINE_TAG: 'tag-7da44bbacc09'
|
||||
CENTOS_TAG: 'tag-c8090b8a9a6b'
|
||||
CENTOS_TAG: 'tag-df11907da86a'
|
||||
DEBIAN_TAG: 'tag-86a16c2d74d8'
|
||||
FEDORA_TAG: 'tag-c8090b8a9a6b'
|
||||
FEDORA_TAG: 'tag-df11907da86a'
|
||||
UBUNTU_TAG: 'tag-86a16c2d74d8'
|
||||
|
||||
ALPINE_EXEC: 'bash .gitlab-ci/alpine-install.sh'
|
||||
|
|
|
|||
17
Makefile.am
17
Makefile.am
|
|
@ -2353,7 +2353,6 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/sd-adapt-shared/mkdir.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/mountpoint-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/namespace-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/netif-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/nm-sd-adapt-shared.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/nulstr-util.h \
|
||||
src/libnm-systemd-shared/sd-adapt-shared/os-util.h \
|
||||
|
|
@ -2368,7 +2367,9 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/sd-adapt-shared/virt.h \
|
||||
src/libnm-systemd-shared/src/basic/alloc-util.c \
|
||||
src/libnm-systemd-shared/src/basic/alloc-util.h \
|
||||
src/libnm-systemd-shared/src/basic/async.h \
|
||||
src/libnm-systemd-shared/src/basic/arphrd-util.h \
|
||||
src/libnm-systemd-shared/src/basic/btrfs.c \
|
||||
src/libnm-systemd-shared/src/basic/btrfs.h \
|
||||
src/libnm-systemd-shared/src/basic/cgroup-util.h \
|
||||
src/libnm-systemd-shared/src/basic/constants.h \
|
||||
src/libnm-systemd-shared/src/basic/dns-def.h \
|
||||
|
|
@ -2407,6 +2408,7 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/src/basic/inotify-util.h \
|
||||
src/libnm-systemd-shared/src/basic/io-util.c \
|
||||
src/libnm-systemd-shared/src/basic/io-util.h \
|
||||
src/libnm-systemd-shared/src/basic/iovec-util.h \
|
||||
src/libnm-systemd-shared/src/basic/label.c \
|
||||
src/libnm-systemd-shared/src/basic/label.h \
|
||||
src/libnm-systemd-shared/src/basic/list.h \
|
||||
|
|
@ -2426,6 +2428,7 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/src/basic/missing_syscall.h \
|
||||
src/libnm-systemd-shared/src/basic/missing_threads.h \
|
||||
src/libnm-systemd-shared/src/basic/missing_type.h \
|
||||
src/libnm-systemd-shared/src/basic/namespace-util.h \
|
||||
src/libnm-systemd-shared/src/basic/ordered-set.c \
|
||||
src/libnm-systemd-shared/src/basic/ordered-set.h \
|
||||
src/libnm-systemd-shared/src/basic/origin-id.h \
|
||||
|
|
@ -2433,6 +2436,7 @@ src_libnm_systemd_shared_libnm_systemd_shared_la_SOURCES = \
|
|||
src/libnm-systemd-shared/src/basic/parse-util.h \
|
||||
src/libnm-systemd-shared/src/basic/path-util.c \
|
||||
src/libnm-systemd-shared/src/basic/path-util.h \
|
||||
src/libnm-systemd-shared/src/basic/pidref.h \
|
||||
src/libnm-systemd-shared/src/basic/prioq.c \
|
||||
src/libnm-systemd-shared/src/basic/prioq.h \
|
||||
src/libnm-systemd-shared/src/basic/process-util.c \
|
||||
|
|
@ -2512,14 +2516,17 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/sd-adapt-core/condition.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/conf-parser.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/khash.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/netif-util.c \
|
||||
src/libnm-systemd-core/sd-adapt-core/netif-util.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/network-util.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/nm-sd-adapt-core.c \
|
||||
src/libnm-systemd-core/sd-adapt-core/nm-sd-adapt-core.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/sd-daemon.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/sd-messages.h \
|
||||
src/libnm-systemd-core/sd-adapt-core/udev-util.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-duid.c \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp-duid-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp6-client-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp6-lease-internal.h \
|
||||
src/libnm-systemd-core/src/libsystemd-network/dhcp6-network.c \
|
||||
|
|
@ -2541,9 +2548,11 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \
|
|||
src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c \
|
||||
src/libnm-systemd-core/src/systemd/_sd-common.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-device.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp-duid.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-dhcp6-protocol.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-event.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-id128.h \
|
||||
src/libnm-systemd-core/src/systemd/sd-ndisc.h \
|
||||
|
|
|
|||
10
NEWS
10
NEWS
|
|
@ -1,3 +1,13 @@
|
|||
=============================================
|
||||
NetworkManager-1.48
|
||||
Overview of changes since NetworkManager-1.46
|
||||
=============================================
|
||||
|
||||
This is a snapshot of NetworkManager development. The API is
|
||||
subject to change and not guaranteed to be compatible with
|
||||
the later release.
|
||||
USE AT YOUR OWN RISK. NOT RECOMMENDED FOR PRODUCTION USE!
|
||||
|
||||
=============================================
|
||||
NetworkManager-1.46
|
||||
Overview of changes since NetworkManager-1.44
|
||||
|
|
|
|||
11
configure.ac
11
configure.ac
|
|
@ -7,8 +7,8 @@ dnl - add corresponding NM_VERSION_x_y_z macros in
|
|||
dnl "shared/nm-version-macros.h.in"
|
||||
dnl - update number in meson.build
|
||||
m4_define([nm_major_version], [1])
|
||||
m4_define([nm_minor_version], [46])
|
||||
m4_define([nm_micro_version], [0])
|
||||
m4_define([nm_minor_version], [47])
|
||||
m4_define([nm_micro_version], [1])
|
||||
m4_define([nm_version],
|
||||
[nm_major_version.nm_minor_version.nm_micro_version])
|
||||
|
||||
|
|
@ -1157,7 +1157,12 @@ fi
|
|||
|
||||
NM_COMPILER_WARNINGS(AM_CFLAGS, ${more_warnings_default})
|
||||
|
||||
NM_COMPILER_WARNING_FLAG(LIBSYSTEMD_NM_CFLAGS, "-Wno-gnu-variable-sized-type-not-at-end")
|
||||
for w in \
|
||||
-Wno-nonnull-compare \
|
||||
-Wno-calloc-transposed-args \
|
||||
; do
|
||||
NM_COMPILER_WARNING_FLAG(LIBSYSTEMD_NM_CFLAGS, "$w")
|
||||
done
|
||||
AC_SUBST(LIBSYSTEMD_NM_CFLAGS)
|
||||
|
||||
CC_CHECK_FLAGS_APPEND([with_cflags], [CFLAGS], [\
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ install \
|
|||
gtk-doc \
|
||||
iptables \
|
||||
jansson-devel \
|
||||
jq \
|
||||
libcurl-devel \
|
||||
libndp-devel \
|
||||
libselinux-devel \
|
||||
|
|
|
|||
|
|
@ -19,8 +19,9 @@ usage() {
|
|||
echo " -c|--clean: run \`git-clean -fdx :/\` before build"
|
||||
echo " -S|--srpm: only build the SRPM"
|
||||
echo " -g|--git: create tarball from current git HEAD (skips make dist)"
|
||||
echo " -Q|--quick: only run \`make dist\` instead of \`make distcheck\`"
|
||||
echo " -Q|--quick: only create the distribution tarball, without running checks"
|
||||
echo " -N|--no-dist: skip creating the source tarball if you already did \`make dist\`"
|
||||
echo " -m|--meson: use meson to create the source tarball"
|
||||
echo " -w|--with \$OPTION: pass --with \$OPTION to rpmbuild. For example --with debug"
|
||||
echo " -W|--without \$OPTION: pass --without \$OPTION to rpmbuild. For example --without debug"
|
||||
echo " -s|--snapshot TEXT: use TEXT as the snapshot version for the new package (overwrites \$NM_BUILD_SNAPSHOT environment)"
|
||||
|
|
@ -97,6 +98,10 @@ while [[ $# -gt 0 ]]; do
|
|||
IGNORE_DIRTY=1
|
||||
SOURCE_FROM_GIT=1
|
||||
;;
|
||||
-m|--meson)
|
||||
USE_MESON=1
|
||||
WITH_LIST=("${WITH_LIST[@]}" "--with" "meson")
|
||||
;;
|
||||
-Q|--quick)
|
||||
QUICK=1
|
||||
;;
|
||||
|
|
@ -188,45 +193,87 @@ if [[ $IGNORE_DIRTY != 1 ]]; then
|
|||
fi
|
||||
fi
|
||||
|
||||
get_version_meson() {
|
||||
meson introspect "$GITDIR/build" --projectinfo | jq -r .version
|
||||
}
|
||||
|
||||
if [[ $NO_DIST != 1 ]]; then
|
||||
./autogen.sh \
|
||||
--with-runstatedir=/run \
|
||||
--program-prefix= \
|
||||
--prefix=/usr \
|
||||
--exec-prefix=/usr \
|
||||
--bindir=/usr/bin \
|
||||
--sbindir=/usr/sbin \
|
||||
--sysconfdir=/etc \
|
||||
--datadir=/usr/share \
|
||||
--includedir=/usr/include \
|
||||
--libdir=/usr/lib \
|
||||
--libexecdir=/usr/libexec \
|
||||
--localstatedir=/var \
|
||||
--sharedstatedir=/var/lib \
|
||||
--mandir=/usr/share/man \
|
||||
--infodir=/usr/share/info \
|
||||
\
|
||||
--disable-dependency-tracking \
|
||||
--enable-gtk-doc \
|
||||
--enable-introspection \
|
||||
--enable-ifcfg-rh \
|
||||
--enable-ifupdown \
|
||||
--with-config-logging-backend-default=syslog \
|
||||
--with-config-wifi-backend-default=wpa_supplicant \
|
||||
--with-libaudit=yes-disabled-by-default \
|
||||
--enable-polkit=yes \
|
||||
--with-nm-cloud-setup=yes \
|
||||
--with-config-dhcp-default=internal \
|
||||
--with-config-dns-rc-manager-default=auto \
|
||||
\
|
||||
--with-iptables=/usr/sbin/iptables \
|
||||
--with-nft=/usr/sbin/nft \
|
||||
\
|
||||
|| die "Error autogen.sh"
|
||||
if [[ $QUICK == 1 ]]; then
|
||||
make dist -j 7 || die "Error make dist"
|
||||
if [[ $USE_MESON = 1 ]]; then
|
||||
meson setup "$GITDIR/build" \
|
||||
--prefix=/usr \
|
||||
--bindir=/usr/bin \
|
||||
--sbindir=/usr/sbin \
|
||||
--sysconfdir=/etc \
|
||||
--datadir=/usr/share \
|
||||
--includedir=/usr/include \
|
||||
--libdir=/usr/lib \
|
||||
--libexecdir=/usr/libexec \
|
||||
--localstatedir=/var \
|
||||
--sharedstatedir=/var/lib \
|
||||
--mandir=/usr/share/man \
|
||||
--infodir=/usr/share/info \
|
||||
-Ddocs=true \
|
||||
-Dintrospection=true \
|
||||
-Difcfg_rh=true \
|
||||
-Difupdown=true \
|
||||
-Dconfig_logging_backend_default=syslog \
|
||||
-Dconfig_wifi_backend_default=wpa_supplicant \
|
||||
-Dlibaudit=yes-disabled-by-default \
|
||||
-Dpolkit=true \
|
||||
-Dnm_cloud_setup=true \
|
||||
-Dconfig_dhcp_default=internal \
|
||||
-Dconfig_dns_rc_manager_default=auto \
|
||||
-Diptables=/usr/sbin/iptables \
|
||||
-Dnft=/usr/bin/nft \
|
||||
|| die "Error meson setup"
|
||||
|
||||
VERSION="${VERSION:-$(get_version_meson || die "Could not read $VERSION")}"
|
||||
if [[ $QUICK == 1 ]]; then
|
||||
meson dist --allow-dirty -C "$GITDIR/build/" --no-tests || die "Error meson dist"
|
||||
else
|
||||
meson dist --allow-dirty -C "$GITDIR/build/" || die "Error meson dist with tests"
|
||||
fi
|
||||
export SOURCE="$(ls -1 "$GITDIR/build/meson-dist/NetworkManager-${VERSION}.tar.xz" 2>/dev/null | head -n1)"
|
||||
else
|
||||
make distcheck -j 7 || die "Error make distcheck"
|
||||
./autogen.sh \
|
||||
--with-runstatedir=/run \
|
||||
--program-prefix= \
|
||||
--prefix=/usr \
|
||||
--exec-prefix=/usr \
|
||||
--bindir=/usr/bin \
|
||||
--sbindir=/usr/sbin \
|
||||
--sysconfdir=/etc \
|
||||
--datadir=/usr/share \
|
||||
--includedir=/usr/include \
|
||||
--libdir=/usr/lib \
|
||||
--libexecdir=/usr/libexec \
|
||||
--localstatedir=/var \
|
||||
--sharedstatedir=/var/lib \
|
||||
--mandir=/usr/share/man \
|
||||
--infodir=/usr/share/info \
|
||||
\
|
||||
--disable-dependency-tracking \
|
||||
--enable-gtk-doc \
|
||||
--enable-introspection \
|
||||
--enable-ifcfg-rh \
|
||||
--enable-ifupdown \
|
||||
--with-config-logging-backend-default=syslog \
|
||||
--with-config-wifi-backend-default=wpa_supplicant \
|
||||
--with-libaudit=yes-disabled-by-default \
|
||||
--enable-polkit=yes \
|
||||
--with-nm-cloud-setup=yes \
|
||||
--with-config-dhcp-default=internal \
|
||||
--with-config-dns-rc-manager-default=auto \
|
||||
\
|
||||
--with-iptables=/usr/sbin/iptables \
|
||||
--with-nft=/usr/sbin/nft \
|
||||
\
|
||||
|| die "Error autogen.sh"
|
||||
if [[ $QUICK == 1 ]]; then
|
||||
make dist -j 7 || die "Error make dist"
|
||||
else
|
||||
make distcheck -j 7 || die "Error make distcheck"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
|
|
|||
|
|
@ -408,6 +408,10 @@ pushd "$DIRNAME"
|
|||
git remote add origin "https://github.com/firewalld/firewalld.git"
|
||||
elif [[ "$BUILD_TYPE" == "nftables" ]]; then
|
||||
git remote add origin "git://git.netfilter.org/nftables"
|
||||
elif [[ "$BUILD_TYPE" == "ulogd" ]]; then
|
||||
git remote add origin "https://git.netfilter.org/ulogd2"
|
||||
elif [[ "$BUILD_TYPE" == "libnetfilter_log" ]]; then
|
||||
git remote add origin "https://git.netfilter.org/$BUILD_TYPE"
|
||||
fi
|
||||
LOCAL_MIRROR_URL="$(LANG=C git remote -v | sed -n 's/^origin\t*\([^\t].*\) (fetch)/\1/p')"
|
||||
LOCAL_MIRROR="$(get_local_mirror "$LOCAL_MIRROR_URL")"
|
||||
|
|
@ -526,6 +530,13 @@ cc304f05edab6c408a0f061eb1a104f9f06b8587 86ef789876b65c61751ce854835b91d4 init
|
|||
|
||||
# systemd
|
||||
903dd65b5eb63257393955cb79777beb8c71afc1 SHA512 (systemd-253-rc1.tar.gz) = aaf0a6bf21bbc50a42015c9cb17f69d1aaf6cab6cabfba5140a94212fb864e38d638dace9a70447f62b4d2a817a0d3bd6f4ae8d9b3c2e741cdeb1cb332f70b65
|
||||
|
||||
# libnetfilter_log
|
||||
97866a0a7482ca518bad39536c7c667bfb9604b2 2a4bb0654ae675a52d2e8d1c06090b94 libnetfilter_log-1.0.1.tar.bz2
|
||||
b0e4be94c0b8f68d4e912402b93a130063c34e17 SHA512 (libnetfilter_log-1.0.2.tar.bz2) = 6b33718b1dd7f4504bceae14001da3a652cec46a6725a5dee83a7b55028cfa8e768cba917f968a5d5b60fd9ff04edf6040ef271a68e5fb65858bf73f4f9ccf23
|
||||
|
||||
# ulogd
|
||||
79aa980f2df9dda0c097e8f883a62f414b9e5138 SHA512 (ulogd-2.0.8.tar.bz2) = 9f99f6f35bad5da4559d788dc3ba3dae17d4ae972737cae3313ecf68f08eaf5f55514fce6f30503437e4158fd30a06438b9249d5d20f6343964cbf690f87309d
|
||||
EOF
|
||||
)"
|
||||
OLDIFS="$IFS"
|
||||
|
|
@ -583,7 +594,7 @@ EOF
|
|||
if [[ "$REVERT_COUNT" == "" || $REVERT_COUNT -gt 0 ]]; then
|
||||
|
||||
# parse the list of patches
|
||||
IFS=$'\n' read -rd '' -a PATCH_LIST <<<"$(sed -n 's/^Patch\([0-9]\+\): \+\(.*\)$/\1 \2/p' ../"$SPEC" | sort -n)"
|
||||
IFS=$'\n' read -rd '' -a PATCH_LIST <<<"$(sed -n 's/^Patch\([0-9]\+\):[ ]\+\(.*\)$/\1 \2/p' ../"$SPEC" | sort -n)"
|
||||
|
||||
if [[ "$BUILD_TYPE" == "NetworkManager" ]]; then
|
||||
if containsElement idx "123 rh1085015-applet-translations.patch" "${PATCH_LIST[@]}"; then
|
||||
|
|
@ -674,7 +685,7 @@ popd
|
|||
if [[ $LOCAL != 0 ]]; then
|
||||
rm -rf ./.makerepo.git/
|
||||
mv "$DIRNAME/.git" ./.makerepo.git/
|
||||
$FEDPKG $DIST local
|
||||
$FEDPKG $DIST local -- --noclean
|
||||
mv ./.makerepo.git/ "$DIRNAME/.git"
|
||||
pushd "$DIRNAME"
|
||||
git checkout -- .gitignore
|
||||
|
|
|
|||
|
|
@ -823,6 +823,11 @@ domains=ALL
|
|||
and these default values only matter if the per-profile values explicitly indicates
|
||||
to use the default from <literal>NetworkManager.conf</literal>.
|
||||
</para>
|
||||
<para>
|
||||
Note that while nmcli supports various aliases and convenience features for configuring
|
||||
properties, the settings in this section do not. For example, enum values usually only
|
||||
can be configured via their numeric magic number.
|
||||
</para>
|
||||
<para>
|
||||
Example:
|
||||
<programlisting>
|
||||
|
|
@ -868,7 +873,13 @@ ipv6.ip6-privacy=0
|
|||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>connection.mdns</varname></term>
|
||||
<listitem><para>If unspecified, the ultimate default values depends on the DNS plugin. With systemd-resolved the default currently is "no" (0) and for all other plugins also "no" (0).</para></listitem>
|
||||
<listitem><para>
|
||||
Currently only the systemd-resolve DNS plugin supports this setting.
|
||||
If the setting is unspecified both in the profile and in the global
|
||||
default here, then the default is determined by systemd-resolved.
|
||||
See <literal>MulticastDNS=</literal> in
|
||||
<citerefentry><refentrytitle>resolved.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>connection.mptcp-flags</varname></term>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ project(
|
|||
# - add corresponding NM_VERSION_x_y_z macros in
|
||||
# "src/libnm-core-public/nm-version-macros.h.in"
|
||||
# - update number in configure.ac
|
||||
version: '1.46.0',
|
||||
version: '1.47.1',
|
||||
license: 'GPL2+',
|
||||
default_options: [
|
||||
'buildtype=debugoptimized',
|
||||
|
|
|
|||
|
|
@ -67,6 +67,15 @@ G_DEFINE_TYPE(NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
static guint32
|
||||
lifetime_to_uint32(guint64 lft)
|
||||
{
|
||||
if (lft == G_MAXUINT64)
|
||||
return G_MAXUINT32;
|
||||
|
||||
return lft / 1000000;
|
||||
}
|
||||
|
||||
static NML3ConfigData *
|
||||
lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GError **error)
|
||||
{
|
||||
|
|
@ -100,18 +109,19 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro
|
|||
|
||||
if (!config->v6.info_only) {
|
||||
gboolean has_any_addresses = FALSE;
|
||||
uint32_t lft_pref;
|
||||
uint32_t lft_valid;
|
||||
uint64_t lft_pref;
|
||||
uint64_t lft_valid;
|
||||
|
||||
sd_dhcp6_lease_reset_address_iter(lease);
|
||||
sd_dhcp6_lease_address_iterator_reset(lease);
|
||||
nm_gstring_prepare(&str);
|
||||
while (sd_dhcp6_lease_get_address(lease, &tmp_addr, &lft_pref, &lft_valid) >= 0) {
|
||||
const NMPlatformIP6Address address = {
|
||||
while (sd_dhcp6_lease_get_address(lease, &tmp_addr) >= 0
|
||||
&& sd_dhcp6_lease_get_address_lifetime(lease, &lft_pref, &lft_valid) >= 0) {
|
||||
NMPlatformIP6Address address = {
|
||||
.plen = 128,
|
||||
.address = tmp_addr,
|
||||
.timestamp = ts,
|
||||
.lifetime = lft_valid,
|
||||
.preferred = lft_pref,
|
||||
.lifetime = lifetime_to_uint32(lft_valid),
|
||||
.preferred = lifetime_to_uint32(lft_pref),
|
||||
.addr_source = NM_IP_CONFIG_SOURCE_DHCP,
|
||||
};
|
||||
|
||||
|
|
@ -121,6 +131,7 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro
|
|||
g_string_append(nm_gstring_add_space_delimiter(str), addr_str);
|
||||
|
||||
has_any_addresses = TRUE;
|
||||
sd_dhcp6_lease_address_iterator_next(lease);
|
||||
}
|
||||
|
||||
if (str->len) {
|
||||
|
|
@ -160,11 +171,12 @@ lease_to_ip6_config(NMDhcpSystemd *self, sd_dhcp6_lease *lease, gint32 ts, GErro
|
|||
uint8_t prefix_len;
|
||||
|
||||
nm_gstring_prepare(&str);
|
||||
sd_dhcp6_lease_reset_pd_prefix_iter(lease);
|
||||
while (!sd_dhcp6_lease_get_pd(lease, &prefix, &prefix_len, NULL, NULL)) {
|
||||
sd_dhcp6_lease_pd_iterator_reset(lease);
|
||||
while (!sd_dhcp6_lease_get_pd_prefix(lease, &prefix, &prefix_len)) {
|
||||
nm_gstring_add_space_delimiter(str);
|
||||
nm_inet6_ntop(&prefix, addr_str);
|
||||
g_string_append_printf(str, "%s/%u", addr_str, prefix_len);
|
||||
sd_dhcp6_lease_pd_iterator_next(lease);
|
||||
}
|
||||
if (str->len > 0) {
|
||||
nm_dhcp_option_add_option(options,
|
||||
|
|
@ -235,6 +247,8 @@ bound6_handle(NMDhcpSystemd *self)
|
|||
gs_free_error GError *error = NULL;
|
||||
NMPlatformIP6Address prefix = {0};
|
||||
sd_dhcp6_lease *lease = NULL;
|
||||
guint64 lft_valid;
|
||||
guint64 lft_pref;
|
||||
|
||||
if (sd_dhcp6_client_get_lease(priv->client6, &lease) < 0 || !lease) {
|
||||
_LOGW(" no lease!");
|
||||
|
|
@ -254,14 +268,14 @@ bound6_handle(NMDhcpSystemd *self)
|
|||
|
||||
_nm_dhcp_client_notify(NM_DHCP_CLIENT(self), NM_DHCP_CLIENT_EVENT_TYPE_BOUND, l3cd);
|
||||
|
||||
sd_dhcp6_lease_reset_pd_prefix_iter(lease);
|
||||
while (!sd_dhcp6_lease_get_pd(lease,
|
||||
&prefix.address,
|
||||
&prefix.plen,
|
||||
&prefix.preferred,
|
||||
&prefix.lifetime)) {
|
||||
sd_dhcp6_lease_pd_iterator_reset(lease);
|
||||
while (!sd_dhcp6_lease_get_pd_prefix(lease, &prefix.address, &prefix.plen)
|
||||
&& !sd_dhcp6_lease_get_pd_lifetime(lease, &lft_pref, &lft_valid)) {
|
||||
prefix.preferred = lifetime_to_uint32(lft_pref);
|
||||
prefix.lifetime = lifetime_to_uint32(lft_valid);
|
||||
prefix.timestamp = ts;
|
||||
nm_dhcp_client_emit_ipv6_prefix_delegated(NM_DHCP_CLIENT(self), &prefix);
|
||||
sd_dhcp6_lease_pd_iterator_next(lease);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -339,10 +353,10 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
r = sd_dhcp6_client_set_duid(sd_client,
|
||||
unaligned_read_be16(&duid_arr[0]),
|
||||
&duid_arr[2],
|
||||
duid_len - 2);
|
||||
r = sd_dhcp6_client_set_duid_raw(sd_client,
|
||||
unaligned_read_be16(&duid_arr[0]),
|
||||
&duid_arr[2],
|
||||
duid_len - 2);
|
||||
if (r < 0) {
|
||||
nm_utils_error_set_errno(error, r, "failed to set DUID: %s");
|
||||
return FALSE;
|
||||
|
|
|
|||
|
|
@ -185,13 +185,16 @@ nm_audit_log(NMAuditManager *self,
|
|||
priv = NM_AUDIT_MANAGER_GET_PRIVATE(self);
|
||||
|
||||
if (priv->auditd_fd >= 0) {
|
||||
audit_log_user_message(priv->auditd_fd,
|
||||
AUDIT_USYS_CONFIG,
|
||||
build_message(&strbuf, BACKEND_AUDITD, fields),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
success);
|
||||
int r;
|
||||
|
||||
r = audit_log_user_message(priv->auditd_fd,
|
||||
AUDIT_USYS_CONFIG,
|
||||
build_message(&strbuf, BACKEND_AUDITD, fields),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
success);
|
||||
(void) r;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -1076,7 +1076,7 @@ _set_values_intern_atomic_section_2_set(NMConfig *config,
|
|||
g_key_file_set_value(keyfile,
|
||||
NM_CONFIG_KEYFILE_GROUPPREFIX_INTERN "with-whitespace",
|
||||
"key2",
|
||||
" b c\\, d ");
|
||||
" b c\\\\, d ");
|
||||
*out_expected_changes = NM_CONFIG_CHANGE_CAUSE_SET_VALUES | NM_CONFIG_CHANGE_VALUES
|
||||
| NM_CONFIG_CHANGE_VALUES_INTERN;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2099,20 +2099,12 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict
|
|||
NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4))
|
||||
nm_l3_config_data_add_route(l3cd, addr_family, route, NULL);
|
||||
}
|
||||
} else if (IS_IPv4 ? g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, "aau", &var_iter)
|
||||
: g_variant_lookup(dict,
|
||||
NM_VPN_PLUGIN_IP6_CONFIG_ROUTES,
|
||||
"a(ayuayu)",
|
||||
&var_iter)) {
|
||||
_nm_unused nm_auto_free_variant_iter GVariantIter *var_iter_ref_owner = var_iter;
|
||||
NMPlatformIPXRoute route = {};
|
||||
guint32 plen;
|
||||
GVariant *next_hop;
|
||||
GVariant *dest;
|
||||
guint32 prefix;
|
||||
guint32 metric;
|
||||
} else if (IS_IPv4) {
|
||||
if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, "aau", &var_iter)) {
|
||||
_nm_unused nm_auto_free_variant_iter GVariantIter *var_iter_ref_owner = var_iter;
|
||||
NMPlatformIPXRoute route = {};
|
||||
guint32 plen;
|
||||
|
||||
if (IS_IPv4) {
|
||||
while (g_variant_iter_next(var_iter, "@au", &v)) {
|
||||
_nm_unused gs_unref_variant GVariant *v_ref_owner = v;
|
||||
|
||||
|
|
@ -2151,42 +2143,84 @@ _dbus_signal_ip_config_cb(NMVpnConnection *self, int addr_family, GVariant *dict
|
|||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (
|
||||
g_variant_iter_next(var_iter, "(@ayu@ayu)", &dest, &prefix, &next_hop, &metric)) {
|
||||
_nm_unused gs_unref_variant GVariant *next_hop_ref_owner = next_hop;
|
||||
_nm_unused gs_unref_variant GVariant *dest_ref_owner = dest;
|
||||
}
|
||||
} else {
|
||||
_nm_unused nm_auto_free_variant_iter GVariantIter *var_iter_ref_owner = NULL;
|
||||
NMPlatformIPXRoute route = {};
|
||||
guint32 prefix;
|
||||
guint32 metric;
|
||||
NMOptionBool new_signature = NM_OPTION_BOOL_DEFAULT;
|
||||
|
||||
if (prefix > 128)
|
||||
continue;
|
||||
/* IPv6 and no "preserve-routes" */
|
||||
|
||||
route.r6 = (NMPlatformIP6Route){
|
||||
.plen = prefix,
|
||||
.table_any = TRUE,
|
||||
.metric_any = TRUE,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_VPN,
|
||||
};
|
||||
if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &var_iter))
|
||||
new_signature = FALSE;
|
||||
else if (g_variant_lookup(dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayuay)", &var_iter))
|
||||
new_signature = TRUE;
|
||||
else
|
||||
var_iter = NULL;
|
||||
|
||||
if (!nm_ip_addr_set_from_variant(AF_INET6, &route.r6.network, dest, NULL))
|
||||
continue;
|
||||
var_iter_ref_owner = var_iter;
|
||||
|
||||
nm_ip_addr_set_from_variant(AF_INET6, &route.r6.gateway, next_hop, NULL);
|
||||
while (TRUE) {
|
||||
gs_unref_variant GVariant *next_hop = NULL;
|
||||
gs_unref_variant GVariant *dest = NULL;
|
||||
gs_unref_variant GVariant *pref_src = NULL;
|
||||
|
||||
nm_ip6_addr_clear_host_address(&route.r6.network, &route.r6.network, route.r6.plen);
|
||||
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&priv->ip_data_6.gw_external.addr6)
|
||||
&& IN6_ARE_ADDR_EQUAL(&route.r6.network, &priv->ip_data_6.gw_external.addr6)
|
||||
&& route.r6.plen == 128) {
|
||||
/* Ignore host routes to the VPN gateway since NM adds one itself.
|
||||
* Since NM knows more about the routing situation than the VPN
|
||||
* server, we want to use the NM created route instead of whatever
|
||||
* the server provides.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
nm_l3_config_data_add_route_6(l3cd, &route.r6);
|
||||
if (new_signature == NM_OPTION_BOOL_DEFAULT) {
|
||||
break;
|
||||
} else if (new_signature) {
|
||||
if (!g_variant_iter_next(var_iter,
|
||||
"(@ayu@ayu@ay)",
|
||||
&dest,
|
||||
&prefix,
|
||||
&next_hop,
|
||||
&metric,
|
||||
&pref_src))
|
||||
break;
|
||||
} else {
|
||||
if (!g_variant_iter_next(var_iter,
|
||||
"(@ayu@ayu)",
|
||||
&dest,
|
||||
&prefix,
|
||||
&next_hop,
|
||||
&metric))
|
||||
break;
|
||||
}
|
||||
|
||||
if (prefix > 128)
|
||||
continue;
|
||||
|
||||
route.r6 = (NMPlatformIP6Route){
|
||||
.plen = prefix,
|
||||
.table_any = TRUE,
|
||||
.metric_any = TRUE,
|
||||
.rt_source = NM_IP_CONFIG_SOURCE_VPN,
|
||||
};
|
||||
|
||||
if (!nm_ip_addr_set_from_variant(AF_INET6, &route.r6.network, dest, NULL))
|
||||
continue;
|
||||
|
||||
if (pref_src
|
||||
&& !nm_ip_addr_set_from_variant(AF_INET6, &route.r6.pref_src, pref_src, NULL))
|
||||
continue;
|
||||
|
||||
nm_ip_addr_set_from_variant(AF_INET6, &route.r6.gateway, next_hop, NULL);
|
||||
|
||||
nm_ip6_addr_clear_host_address(&route.r6.network, &route.r6.network, route.r6.plen);
|
||||
|
||||
if (!IN6_IS_ADDR_UNSPECIFIED(&priv->ip_data_6.gw_external.addr6)
|
||||
&& IN6_ARE_ADDR_EQUAL(&route.r6.network, &priv->ip_data_6.gw_external.addr6)
|
||||
&& route.r6.plen == 128) {
|
||||
/* Ignore host routes to the VPN gateway since NM adds one itself.
|
||||
* Since NM knows more about the routing situation than the VPN
|
||||
* server, we want to use the NM created route instead of whatever
|
||||
* the server provides.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
nm_l3_config_data_add_route_6(l3cd, &route.r6);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -2852,11 +2852,12 @@ nm_setting_connection_class_init(NMSettingConnectionClass *klass)
|
|||
* for the connection, "no" (0) disable mDNS for the interface, "resolve"
|
||||
* (1) do not register hostname but allow resolving of mDNS host names
|
||||
* and "default" (-1) to allow lookup of a global default in NetworkManager.conf.
|
||||
* If unspecified, "default" ultimately depends on the DNS plugin (which
|
||||
* for systemd-resolved currently means "no").
|
||||
* If unspecified, "default" ultimately depends on the DNS plugin.
|
||||
*
|
||||
* This feature requires a plugin which supports mDNS. Otherwise, the
|
||||
* setting has no effect. One such plugin is dns-systemd-resolved.
|
||||
* setting has no effect. Currently the only supported DNS plugin is
|
||||
* systemd-resolved. For systemd-resolved, the default is configurable via
|
||||
* MulticastDNS= setting in resolved.conf.
|
||||
*
|
||||
* Since: 1.12
|
||||
**/
|
||||
|
|
|
|||
|
|
@ -46,24 +46,24 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMSettingWireless,
|
|||
PROP_AP_ISOLATION, );
|
||||
|
||||
typedef struct {
|
||||
GBytes *ssid;
|
||||
GArray *mac_address_blacklist;
|
||||
GPtrArray *seen_bssids;
|
||||
char *mode;
|
||||
char *band;
|
||||
char *bssid;
|
||||
char *device_mac_address;
|
||||
char *cloned_mac_address;
|
||||
char *generate_mac_address_mask;
|
||||
int ap_isolation;
|
||||
guint32 mac_address_randomization;
|
||||
guint32 channel;
|
||||
guint32 rate;
|
||||
guint32 tx_power;
|
||||
guint32 mtu;
|
||||
guint32 powersave;
|
||||
guint32 wake_on_wlan;
|
||||
bool hidden;
|
||||
GBytes *ssid;
|
||||
GPtrArray *seen_bssids;
|
||||
char *mode;
|
||||
char *band;
|
||||
char *bssid;
|
||||
char *device_mac_address;
|
||||
char *cloned_mac_address;
|
||||
char *generate_mac_address_mask;
|
||||
NMValueStrv mac_address_blacklist;
|
||||
int ap_isolation;
|
||||
guint32 mac_address_randomization;
|
||||
guint32 channel;
|
||||
guint32 rate;
|
||||
guint32 tx_power;
|
||||
guint32 mtu;
|
||||
guint32 powersave;
|
||||
guint32 wake_on_wlan;
|
||||
bool hidden;
|
||||
} NMSettingWirelessPrivate;
|
||||
|
||||
/**
|
||||
|
|
@ -470,12 +470,11 @@ nm_setting_wireless_get_generate_mac_address_mask(NMSettingWireless *setting)
|
|||
const char *const *
|
||||
nm_setting_wireless_get_mac_address_blacklist(NMSettingWireless *setting)
|
||||
{
|
||||
NMSettingWirelessPrivate *priv;
|
||||
|
||||
g_return_val_if_fail(NM_IS_SETTING_WIRELESS(setting), NULL);
|
||||
|
||||
priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
|
||||
return nm_g_array_data(priv->mac_address_blacklist);
|
||||
return nm_strvarray_get_strv_notnull(
|
||||
NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_blacklist.arr,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -489,7 +488,7 @@ nm_setting_wireless_get_num_mac_blacklist_items(NMSettingWireless *setting)
|
|||
{
|
||||
g_return_val_if_fail(NM_IS_SETTING_WIRELESS(setting), 0);
|
||||
|
||||
return NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_blacklist->len;
|
||||
return nm_g_array_len(NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_blacklist.arr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -505,19 +504,11 @@ nm_setting_wireless_get_num_mac_blacklist_items(NMSettingWireless *setting)
|
|||
const char *
|
||||
nm_setting_wireless_get_mac_blacklist_item(NMSettingWireless *setting, guint32 idx)
|
||||
{
|
||||
NMSettingWirelessPrivate *priv;
|
||||
|
||||
g_return_val_if_fail(NM_IS_SETTING_WIRELESS(setting), NULL);
|
||||
|
||||
priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
|
||||
|
||||
if (idx == priv->mac_address_blacklist->len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_return_val_if_fail(idx < priv->mac_address_blacklist->len, NULL);
|
||||
|
||||
return nm_g_array_index(priv->mac_address_blacklist, const char *, idx);
|
||||
return nm_strvarray_get_idxnull_or_greturn(
|
||||
NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_blacklist.arr,
|
||||
idx);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -534,24 +525,28 @@ gboolean
|
|||
nm_setting_wireless_add_mac_blacklist_item(NMSettingWireless *setting, const char *mac)
|
||||
{
|
||||
NMSettingWirelessPrivate *priv;
|
||||
guint8 mac_bin[ETH_ALEN];
|
||||
const char *candidate;
|
||||
int i;
|
||||
guint i;
|
||||
guint len;
|
||||
|
||||
g_return_val_if_fail(NM_IS_SETTING_WIRELESS(setting), FALSE);
|
||||
g_return_val_if_fail(mac != NULL, FALSE);
|
||||
|
||||
if (!nm_utils_hwaddr_valid(mac, ETH_ALEN))
|
||||
if (!_nm_utils_hwaddr_aton_exact(mac, mac_bin, ETH_ALEN))
|
||||
return FALSE;
|
||||
|
||||
priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
|
||||
for (i = 0; i < priv->mac_address_blacklist->len; i++) {
|
||||
candidate = nm_g_array_index(priv->mac_address_blacklist, char *, i);
|
||||
if (nm_utils_hwaddr_matches(mac, -1, candidate, -1))
|
||||
len = nm_g_array_len(priv->mac_address_blacklist.arr);
|
||||
for (i = 0; i < len; i++) {
|
||||
candidate = nm_g_array_index(priv->mac_address_blacklist.arr, char *, i);
|
||||
if (nm_utils_hwaddr_matches(mac_bin, ETH_ALEN, candidate, -1))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mac = nm_utils_hwaddr_canonical(mac, ETH_ALEN);
|
||||
g_array_append_val(priv->mac_address_blacklist, mac);
|
||||
nm_g_array_append_simple(nm_strvarray_ensure(&priv->mac_address_blacklist.arr),
|
||||
nm_utils_hwaddr_ntoa(mac_bin, ETH_ALEN));
|
||||
_notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -571,9 +566,13 @@ nm_setting_wireless_remove_mac_blacklist_item(NMSettingWireless *setting, guint3
|
|||
g_return_if_fail(NM_IS_SETTING_WIRELESS(setting));
|
||||
|
||||
priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
|
||||
g_return_if_fail(idx < priv->mac_address_blacklist->len);
|
||||
if (!priv->mac_address_blacklist.arr) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_array_remove_index(priv->mac_address_blacklist, idx);
|
||||
g_return_if_fail(idx < priv->mac_address_blacklist.arr->len);
|
||||
|
||||
g_array_remove_index(priv->mac_address_blacklist.arr, idx);
|
||||
_notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
|
||||
}
|
||||
|
||||
|
|
@ -591,21 +590,29 @@ gboolean
|
|||
nm_setting_wireless_remove_mac_blacklist_item_by_value(NMSettingWireless *setting, const char *mac)
|
||||
{
|
||||
NMSettingWirelessPrivate *priv;
|
||||
guint8 mac_bin[ETH_ALEN];
|
||||
const char *candidate;
|
||||
int i;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail(NM_IS_SETTING_WIRELESS(setting), FALSE);
|
||||
g_return_val_if_fail(mac != NULL, FALSE);
|
||||
|
||||
if (!_nm_utils_hwaddr_aton_exact(mac, mac_bin, ETH_ALEN))
|
||||
return FALSE;
|
||||
|
||||
priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
|
||||
for (i = 0; i < priv->mac_address_blacklist->len; i++) {
|
||||
candidate = nm_g_array_index(priv->mac_address_blacklist, char *, i);
|
||||
if (nm_utils_hwaddr_matches(mac, -1, candidate, -1)) {
|
||||
g_array_remove_index(priv->mac_address_blacklist, i);
|
||||
_notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
|
||||
return TRUE;
|
||||
|
||||
if (priv->mac_address_blacklist.arr) {
|
||||
for (i = 0; i < priv->mac_address_blacklist.arr->len; i++) {
|
||||
candidate = nm_g_array_index(priv->mac_address_blacklist.arr, char *, i);
|
||||
if (nm_utils_hwaddr_matches(mac_bin, ETH_ALEN, candidate, -1)) {
|
||||
g_array_remove_index(priv->mac_address_blacklist.arr, i);
|
||||
_notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
@ -620,8 +627,8 @@ nm_setting_wireless_clear_mac_blacklist_items(NMSettingWireless *setting)
|
|||
{
|
||||
g_return_if_fail(NM_IS_SETTING_WIRELESS(setting));
|
||||
|
||||
g_array_set_size(NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_blacklist, 0);
|
||||
_notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
|
||||
if (nm_strvarray_clear(&NM_SETTING_WIRELESS_GET_PRIVATE(setting)->mac_address_blacklist.arr))
|
||||
_notify(setting, PROP_MAC_ADDRESS_BLACKLIST);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1041,20 +1048,22 @@ verify(NMSetting *setting, NMConnection *connection, GError **error)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
for (i = 0; i < priv->mac_address_blacklist->len; i++) {
|
||||
const char *mac = nm_g_array_index(priv->mac_address_blacklist, const char *, i);
|
||||
if (priv->mac_address_blacklist.arr) {
|
||||
for (i = 0; i < priv->mac_address_blacklist.arr->len; i++) {
|
||||
const char *mac = nm_g_array_index(priv->mac_address_blacklist.arr, const char *, i);
|
||||
|
||||
if (!nm_utils_hwaddr_valid(mac, ETH_ALEN)) {
|
||||
g_set_error(error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("'%s' is not a valid MAC address"),
|
||||
mac);
|
||||
g_prefix_error(error,
|
||||
"%s.%s: ",
|
||||
NM_SETTING_WIRELESS_SETTING_NAME,
|
||||
NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST);
|
||||
return FALSE;
|
||||
if (!nm_utils_hwaddr_valid(mac, ETH_ALEN)) {
|
||||
g_set_error(error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("'%s' is not a valid MAC address"),
|
||||
mac);
|
||||
g_prefix_error(error,
|
||||
"%s.%s: ",
|
||||
NM_SETTING_WIRELESS_SETTING_NAME,
|
||||
NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1216,12 +1225,6 @@ nm_setting_wireless_get_wake_on_wlan(NMSettingWireless *setting)
|
|||
return NM_SETTING_WIRELESS_GET_PRIVATE(setting)->wake_on_wlan;
|
||||
}
|
||||
|
||||
static void
|
||||
clear_blacklist_item(char **item_p)
|
||||
{
|
||||
g_free(*item_p);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
@ -1234,9 +1237,6 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|||
case PROP_CLONED_MAC_ADDRESS:
|
||||
g_value_set_string(value, nm_setting_wireless_get_cloned_mac_address(setting));
|
||||
break;
|
||||
case PROP_MAC_ADDRESS_BLACKLIST:
|
||||
g_value_set_boxed(value, nm_g_array_data(priv->mac_address_blacklist));
|
||||
break;
|
||||
case PROP_SEEN_BSSIDS:
|
||||
g_value_take_boxed(
|
||||
value,
|
||||
|
|
@ -1255,8 +1255,6 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
|
|||
{
|
||||
NMSettingWireless *self = NM_SETTING_WIRELESS(object);
|
||||
NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE(self);
|
||||
const char *const *blacklist;
|
||||
const char *mac;
|
||||
gboolean bool_val;
|
||||
_PropertyEnums prop1 = PROP_0;
|
||||
_PropertyEnums prop2 = PROP_0;
|
||||
|
|
@ -1281,18 +1279,6 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
|
|||
|
||||
nm_gobject_notify_together(self, prop1, prop2);
|
||||
break;
|
||||
case PROP_MAC_ADDRESS_BLACKLIST:
|
||||
blacklist = g_value_get_boxed(value);
|
||||
g_array_set_size(priv->mac_address_blacklist, 0);
|
||||
if (blacklist && blacklist[0]) {
|
||||
gsize i;
|
||||
|
||||
for (i = 0; blacklist[i]; i++) {
|
||||
mac = _nm_utils_hwaddr_canonical_or_invalid(blacklist[i], ETH_ALEN);
|
||||
g_array_append_val(priv->mac_address_blacklist, mac);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PROP_SEEN_BSSIDS:
|
||||
{
|
||||
gs_unref_ptrarray GPtrArray *arr_old = NULL;
|
||||
|
|
@ -1321,13 +1307,7 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps
|
|||
|
||||
static void
|
||||
nm_setting_wireless_init(NMSettingWireless *setting)
|
||||
{
|
||||
NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
|
||||
|
||||
/* We use GArray rather than GPtrArray so it will automatically be NULL-terminated */
|
||||
priv->mac_address_blacklist = g_array_new(TRUE, FALSE, sizeof(char *));
|
||||
g_array_set_clear_func(priv->mac_address_blacklist, (GDestroyNotify) clear_blacklist_item);
|
||||
}
|
||||
{}
|
||||
|
||||
/**
|
||||
* nm_setting_wireless_new:
|
||||
|
|
@ -1348,7 +1328,6 @@ finalize(GObject *object)
|
|||
NMSettingWirelessPrivate *priv = NM_SETTING_WIRELESS_GET_PRIVATE(object);
|
||||
|
||||
g_free(priv->cloned_mac_address);
|
||||
g_array_unref(priv->mac_address_blacklist);
|
||||
nm_g_ptr_array_unref(priv->seen_bssids);
|
||||
|
||||
G_OBJECT_CLASS(nm_setting_wireless_parent_class)->finalize(object);
|
||||
|
|
@ -1733,11 +1712,15 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
|
|||
* is listed.
|
||||
* ---end---
|
||||
*/
|
||||
_nm_setting_property_define_gprop_strv_oldstyle(properties_override,
|
||||
obj_properties,
|
||||
NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST,
|
||||
PROP_MAC_ADDRESS_BLACKLIST,
|
||||
NM_SETTING_PARAM_FUZZY_IGNORE);
|
||||
_nm_setting_property_define_direct_strv(properties_override,
|
||||
obj_properties,
|
||||
NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST,
|
||||
PROP_MAC_ADDRESS_BLACKLIST,
|
||||
NM_SETTING_PARAM_FUZZY_IGNORE,
|
||||
NMSettingWirelessPrivate,
|
||||
mac_address_blacklist,
|
||||
.direct_set_strv_normalize_hwaddr = TRUE,
|
||||
.direct_strv_not_null = TRUE);
|
||||
|
||||
/**
|
||||
* NMSettingWireless:seen-bssids:
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@
|
|||
|
||||
#include "nm-setting.h"
|
||||
|
||||
#include <linux/if_ether.h>
|
||||
|
||||
#include "libnm-core-intern/nm-core-internal.h"
|
||||
#include "libnm-glib-aux/nm-ref-string.h"
|
||||
#include "libnm-glib-aux/nm-secret-utils.h"
|
||||
|
|
@ -739,10 +741,29 @@ _property_direct_set_strv(const NMSettInfoSetting *sett_info,
|
|||
if (!property_info->direct_strv_preserve_empty && strv && !strv[0])
|
||||
strv = NULL;
|
||||
|
||||
if (nm_strvarray_equal_strv(p_val->arr, strv, -1))
|
||||
return FALSE;
|
||||
if (property_info->direct_set_strv_normalize_hwaddr) {
|
||||
gs_unref_array GArray *arr = NULL;
|
||||
if (strv) {
|
||||
nm_strvarray_ensure(&arr);
|
||||
|
||||
for (; strv[0]; strv++) {
|
||||
nm_strvarray_add_take(arr,
|
||||
_nm_utils_hwaddr_canonical_or_invalid(strv[0], ETH_ALEN));
|
||||
}
|
||||
}
|
||||
|
||||
if (nm_strvarray_equal(p_val->arr, arr))
|
||||
return FALSE;
|
||||
|
||||
NM_SWAP(&p_val->arr, &arr);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (nm_strvarray_equal_strv(p_val->arr, strv, -1)) {
|
||||
return FALSE;
|
||||
}
|
||||
nm_strvarray_set_strv_full(&p_val->arr, strv, property_info->direct_strv_preserve_empty);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
|
@ -844,7 +865,7 @@ _nm_setting_property_get_property_direct(GObject *object,
|
|||
value,
|
||||
nm_strvarray_get_strv_full_dup(p_val->arr,
|
||||
NULL,
|
||||
FALSE,
|
||||
property_info->direct_strv_not_null,
|
||||
property_info->direct_strv_preserve_empty));
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -821,6 +821,10 @@ struct _NMSettInfoProperty {
|
|||
* normalize the string via g_ascii_strdown(). */
|
||||
bool direct_set_string_ascii_strdown : 1;
|
||||
|
||||
/* If TRUE, this is a NM_VALUE_TYPE_STRV direct property holding MAC addresses,
|
||||
* and the setter will normalize them via _nm_utils_hwaddr_canonical_or_invalid(). */
|
||||
bool direct_set_strv_normalize_hwaddr : 1;
|
||||
|
||||
/* If TRUE, this is a NM_VALUE_TYPE_STRING direct property, and the setter will
|
||||
* normalize the string via g_strstrip(). */
|
||||
bool direct_set_string_strip : 1;
|
||||
|
|
@ -870,6 +874,10 @@ struct _NMSettInfoProperty {
|
|||
* an empty array. */
|
||||
bool direct_strv_preserve_empty : 1;
|
||||
|
||||
/* This flag indicates that an empty strv array should be returned
|
||||
* instead of NULL if it hadn't been created yet. */
|
||||
bool direct_strv_not_null : 1;
|
||||
|
||||
/* Usually, properties that are set to the default value for the GParamSpec
|
||||
* are not serialized to GVariant (and NULL is returned by to_dbus_data().
|
||||
* Set this flag to force always converting the property even if the value
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@
|
|||
#define NM_VERSION_1_42 (NM_ENCODE_VERSION(1, 42, 0))
|
||||
#define NM_VERSION_1_44 (NM_ENCODE_VERSION(1, 44, 0))
|
||||
#define NM_VERSION_1_46 (NM_ENCODE_VERSION(1, 46, 0))
|
||||
#define NM_VERSION_1_48 (NM_ENCODE_VERSION(1, 48, 0))
|
||||
|
||||
/* For releases, NM_API_VERSION is equal to NM_VERSION.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -383,6 +383,20 @@
|
|||
#define NM_AVAILABLE_IN_1_46
|
||||
#endif
|
||||
|
||||
#if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_48
|
||||
#define NM_DEPRECATED_IN_1_48 G_DEPRECATED
|
||||
#define NM_DEPRECATED_IN_1_48_FOR(f) G_DEPRECATED_FOR(f)
|
||||
#else
|
||||
#define NM_DEPRECATED_IN_1_48
|
||||
#define NM_DEPRECATED_IN_1_48_FOR(f)
|
||||
#endif
|
||||
|
||||
#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_48
|
||||
#define NM_AVAILABLE_IN_1_48 G_UNAVAILABLE(1, 48)
|
||||
#else
|
||||
#define NM_AVAILABLE_IN_1_48
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Synchronous API for calling D-Bus in libnm is deprecated. See
|
||||
* https://networkmanager.dev/docs/libnm/latest/usage.html#sync-api
|
||||
|
|
|
|||
|
|
@ -648,9 +648,10 @@ nm_lldp_neighbor_tlv_get_oui(NMLldpNeighbor *n, uint8_t oui[static 3], uint8_t *
|
|||
int r;
|
||||
|
||||
g_return_val_if_fail(n, -EINVAL);
|
||||
g_return_val_if_fail(oui, -EINVAL);
|
||||
g_return_val_if_fail(subtype, -EINVAL);
|
||||
|
||||
nm_assert(oui);
|
||||
|
||||
r = nm_lldp_neighbor_tlv_is_type(n, NM_LLDP_TYPE_PRIVATE);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@
|
|||
libnm_systemd_core = static_library(
|
||||
'nm-systemd-core',
|
||||
sources: files(
|
||||
'src/libsystemd-network/dhcp-identifier.c',
|
||||
'src/libsystemd-network/dhcp6-network.c',
|
||||
'src/libsystemd-network/dhcp6-option.c',
|
||||
'src/libsystemd-network/dhcp6-protocol.c',
|
||||
'src/libsystemd-network/network-common.c',
|
||||
'src/libsystemd-network/sd-dhcp-duid.c',
|
||||
'src/libsystemd-network/sd-dhcp6-client.c',
|
||||
'src/libsystemd-network/sd-dhcp6-lease.c',
|
||||
'src/libsystemd/sd-event/event-util.c',
|
||||
|
|
@ -15,6 +15,7 @@ libnm_systemd_core = static_library(
|
|||
'src/libsystemd/sd-id128/id128-util.c',
|
||||
'src/libsystemd/sd-id128/sd-id128.c',
|
||||
'nm-sd.c',
|
||||
'sd-adapt-core/netif-util.c',
|
||||
'sd-adapt-core/nm-sd-adapt-core.c',
|
||||
),
|
||||
include_directories: [
|
||||
|
|
@ -28,6 +29,7 @@ libnm_systemd_core = static_library(
|
|||
top_inc,
|
||||
src_inc,
|
||||
],
|
||||
c_args: libnm_systemd_common_cflags,
|
||||
dependencies: [
|
||||
libnm_systemd_shared_dep_inc,
|
||||
glib_dep,
|
||||
|
|
|
|||
219
src/libnm-systemd-core/sd-adapt-core/netif-util.c
Normal file
219
src/libnm-systemd-core/sd-adapt-core/netif-util.c
Normal file
|
|
@ -0,0 +1,219 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include <linux/if.h>
|
||||
#include <linux/if_arp.h>
|
||||
|
||||
#include "arphrd-util.h"
|
||||
#include "device-util.h"
|
||||
#include "log-link.h"
|
||||
#include "memory-util.h"
|
||||
#include "netif-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "strv.h"
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
bool netif_has_carrier(uint8_t operstate, unsigned flags) {
|
||||
/* see Documentation/networking/operstates.txt in the kernel sources */
|
||||
|
||||
if (operstate == IF_OPER_UP)
|
||||
return true;
|
||||
|
||||
if (operstate != IF_OPER_UNKNOWN)
|
||||
return false;
|
||||
|
||||
/* operstate may not be implemented, so fall back to flags */
|
||||
return FLAGS_SET(flags, IFF_LOWER_UP | IFF_RUNNING) &&
|
||||
!FLAGS_SET(flags, IFF_DORMANT);
|
||||
}
|
||||
|
||||
int net_get_type_string(sd_device *device, uint16_t iftype, char **ret) {
|
||||
const char *t;
|
||||
char *p;
|
||||
|
||||
if (device &&
|
||||
sd_device_get_devtype(device, &t) >= 0 &&
|
||||
!isempty(t)) {
|
||||
p = strdup(t);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = p;
|
||||
return 0;
|
||||
}
|
||||
|
||||
t = arphrd_to_name(iftype);
|
||||
if (!t)
|
||||
return -ENOENT;
|
||||
|
||||
p = strdup(t);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = ascii_strlower(p);
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
const char *
|
||||
net_get_persistent_name(sd_device *device)
|
||||
{
|
||||
assert(device);
|
||||
|
||||
/* fetch some persistent data unique (on this machine) to this device */
|
||||
FOREACH_STRING(field,
|
||||
"ID_NET_NAME_ONBOARD",
|
||||
"ID_NET_NAME_SLOT",
|
||||
"ID_NET_NAME_PATH",
|
||||
"ID_NET_NAME_MAC")
|
||||
{
|
||||
const char *name;
|
||||
|
||||
if (sd_device_get_property_value(device, field, &name) >= 0)
|
||||
return name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
/* Used when generating hardware address by udev, and IPv4LL seed by networkd. */
|
||||
#define HASH_KEY SD_ID128_MAKE(d3, 1e, 48, fa, 90, fe, 4b, 4c, 9d, af, d5, d7, a1, b1, 2e, 8a)
|
||||
|
||||
int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *ret) {
|
||||
const char *name;
|
||||
|
||||
assert(device);
|
||||
assert(ret);
|
||||
|
||||
/* net_get_persistent_name() will return one of the device names based on stable information about
|
||||
* the device. If this is not available, we fall back to using the actual device name. */
|
||||
name = net_get_persistent_name(device);
|
||||
if (!name && use_sysname)
|
||||
(void) sd_device_get_sysname(device, &name);
|
||||
if (!name)
|
||||
return log_device_debug_errno(device, SYNTHETIC_ERRNO(ENODATA),
|
||||
"No stable identifying information found");
|
||||
|
||||
log_device_debug(device, "Using \"%s\" as stable identifying information", name);
|
||||
|
||||
return net_get_unique_predictable_data_from_name(name, &HASH_KEY, ret);
|
||||
}
|
||||
|
||||
int net_get_unique_predictable_data_from_name(
|
||||
const char *name,
|
||||
const sd_id128_t *key,
|
||||
uint64_t *ret) {
|
||||
|
||||
size_t l, sz;
|
||||
uint8_t *v;
|
||||
int r;
|
||||
|
||||
assert(name);
|
||||
assert(key);
|
||||
assert(ret);
|
||||
|
||||
l = strlen(name);
|
||||
sz = sizeof(sd_id128_t) + l;
|
||||
v = newa(uint8_t, sz);
|
||||
|
||||
/* Fetch some persistent data unique to this machine */
|
||||
r = sd_id128_get_machine((sd_id128_t*) v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
memcpy(v + sizeof(sd_id128_t), name, l);
|
||||
|
||||
/* Let's hash the machine ID plus the device name. We use
|
||||
* a fixed, but originally randomly created hash key here. */
|
||||
*ret = htole64(siphash24(v, sz, key->bytes));
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef struct Link {
|
||||
const char *ifname;
|
||||
} Link;
|
||||
|
||||
int net_verify_hardware_address(
|
||||
const char *ifname,
|
||||
bool is_static,
|
||||
uint16_t iftype,
|
||||
const struct hw_addr_data *ib_hw_addr, /* current or parent HW address */
|
||||
struct hw_addr_data *new_hw_addr) {
|
||||
|
||||
Link link = { .ifname = ifname };
|
||||
|
||||
assert(new_hw_addr);
|
||||
|
||||
if (new_hw_addr->length == 0)
|
||||
return 0;
|
||||
|
||||
if (new_hw_addr->length != arphrd_to_hw_addr_len(iftype)) {
|
||||
if (is_static)
|
||||
log_link_warning(&link,
|
||||
"Specified MAC address with invalid length (%zu, expected %zu), refusing.",
|
||||
new_hw_addr->length, arphrd_to_hw_addr_len(iftype));
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (iftype) {
|
||||
case ARPHRD_ETHER:
|
||||
/* see eth_random_addr() in the kernel */
|
||||
|
||||
if (ether_addr_is_null(&new_hw_addr->ether)) {
|
||||
if (is_static)
|
||||
log_link_warning(&link, "Specified MAC address is null, refusing.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ether_addr_is_broadcast(&new_hw_addr->ether)) {
|
||||
if (is_static)
|
||||
log_link_warning(&link, "Specified MAC address is broadcast, refusing.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ether_addr_is_multicast(&new_hw_addr->ether)) {
|
||||
if (is_static)
|
||||
log_link_warning(&link, "Specified MAC address has the multicast bit set, clearing the bit.");
|
||||
|
||||
new_hw_addr->bytes[0] &= 0xfe;
|
||||
}
|
||||
|
||||
if (!is_static && !ether_addr_is_local(&new_hw_addr->ether))
|
||||
/* Adjust local assignment bit when the MAC address is generated randomly. */
|
||||
new_hw_addr->bytes[0] |= 0x02;
|
||||
|
||||
break;
|
||||
|
||||
case ARPHRD_INFINIBAND:
|
||||
/* see ipoib_check_lladdr() in the kernel */
|
||||
|
||||
assert(ib_hw_addr);
|
||||
assert(ib_hw_addr->length == INFINIBAND_ALEN);
|
||||
|
||||
if (is_static &&
|
||||
(!memeqzero(new_hw_addr->bytes, INFINIBAND_ALEN - 8) ||
|
||||
memcmp(new_hw_addr->bytes, ib_hw_addr->bytes, INFINIBAND_ALEN - 8) != 0))
|
||||
log_link_warning(&link, "Only the last 8 bytes of the InifniBand MAC address can be changed, ignoring the first 12 bytes.");
|
||||
|
||||
if (memeqzero(new_hw_addr->bytes + INFINIBAND_ALEN - 8, 8)) {
|
||||
if (is_static)
|
||||
log_link_warning(&link, "The last 8 bytes of the InfiniBand MAC address cannot be null, refusing.");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
memcpy(new_hw_addr->bytes, ib_hw_addr->bytes, INFINIBAND_ALEN - 8);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (is_static)
|
||||
log_link_warning(&link, "Unsupported interface type %s%u to set MAC address, refusing.",
|
||||
strna(arphrd_to_name(iftype)), iftype);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
22
src/libnm-systemd-core/sd-adapt-core/netif-util.h
Normal file
22
src/libnm-systemd-core/sd-adapt-core/netif-util.h
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "ether-addr-util.h"
|
||||
|
||||
bool netif_has_carrier(uint8_t operstate, unsigned flags);
|
||||
int net_get_type_string(sd_device *device, uint16_t iftype, char **ret);
|
||||
const char *net_get_persistent_name(sd_device *device);
|
||||
int net_get_unique_predictable_data(sd_device *device, bool use_sysname, uint64_t *ret);
|
||||
int
|
||||
net_get_unique_predictable_data_from_name(const char *name, const sd_id128_t *key, uint64_t *ret);
|
||||
int net_verify_hardware_address(const char *ifname,
|
||||
bool is_static,
|
||||
uint16_t iftype,
|
||||
const struct hw_addr_data *ib_hw_addr,
|
||||
struct hw_addr_data *new_hw_addr);
|
||||
|
|
@ -12,15 +12,6 @@
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
int
|
||||
asynchronous_close(int fd)
|
||||
{
|
||||
safe_close(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
sd_device *
|
||||
sd_device_ref(sd_device *self)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -86,7 +86,6 @@ sd_notify(int unset_environment, const char *state)
|
|||
|
||||
#include "sd-id128.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "async.h"
|
||||
|
||||
#endif /* (NETWORKMANAGER_COMPILATION) & NM_NETWORKMANAGER_COMPILATION_WITH_SYSTEMD */
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,83 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-dhcp-duid.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "ether-addr-util.h"
|
||||
#include "macro.h"
|
||||
#include "sparse-endian.h"
|
||||
|
||||
#define SYSTEMD_PEN 43793
|
||||
|
||||
typedef enum DUIDType {
|
||||
DUID_TYPE_LLT = SD_DUID_TYPE_LLT,
|
||||
DUID_TYPE_EN = SD_DUID_TYPE_EN,
|
||||
DUID_TYPE_LL = SD_DUID_TYPE_LL,
|
||||
DUID_TYPE_UUID = SD_DUID_TYPE_UUID,
|
||||
_DUID_TYPE_MAX,
|
||||
_DUID_TYPE_INVALID = -EINVAL,
|
||||
} DUIDType;
|
||||
|
||||
/* RFC 8415 section 11.1:
|
||||
* A DUID consists of a 2-octet type code represented in network byte order, followed by a variable number of
|
||||
* octets that make up the actual identifier. The length of the DUID (not including the type code) is at
|
||||
* least 1 octet and at most 128 octets. */
|
||||
#define MIN_DUID_DATA_LEN 1
|
||||
#define MAX_DUID_DATA_LEN 128
|
||||
#define MIN_DUID_LEN (sizeof(be16_t) + MIN_DUID_DATA_LEN)
|
||||
#define MAX_DUID_LEN (sizeof(be16_t) + MAX_DUID_DATA_LEN)
|
||||
|
||||
/* https://tools.ietf.org/html/rfc3315#section-9.1 */
|
||||
struct duid {
|
||||
be16_t type;
|
||||
union {
|
||||
struct {
|
||||
/* DUID_TYPE_LLT */
|
||||
be16_t htype;
|
||||
be32_t time;
|
||||
uint8_t haddr[];
|
||||
} _packed_ llt;
|
||||
struct {
|
||||
/* DUID_TYPE_EN */
|
||||
be32_t pen;
|
||||
uint8_t id[];
|
||||
} _packed_ en;
|
||||
struct {
|
||||
/* DUID_TYPE_LL */
|
||||
be16_t htype;
|
||||
uint8_t haddr[];
|
||||
} _packed_ ll;
|
||||
struct {
|
||||
/* DUID_TYPE_UUID */
|
||||
sd_id128_t uuid;
|
||||
} _packed_ uuid;
|
||||
uint8_t data[MAX_DUID_DATA_LEN];
|
||||
};
|
||||
} _packed_;
|
||||
|
||||
typedef struct sd_dhcp_duid {
|
||||
size_t size;
|
||||
union {
|
||||
struct duid duid;
|
||||
uint8_t raw[MAX_DUID_LEN];
|
||||
};
|
||||
} sd_dhcp_duid;
|
||||
|
||||
static inline bool duid_size_is_valid(size_t size) {
|
||||
return size >= MIN_DUID_LEN && size <= MAX_DUID_LEN;
|
||||
}
|
||||
|
||||
static inline bool duid_data_size_is_valid(size_t size) {
|
||||
return size >= MIN_DUID_DATA_LEN && size <= MAX_DUID_DATA_LEN;
|
||||
}
|
||||
|
||||
const char *duid_type_to_string(DUIDType t) _const_;
|
||||
int dhcp_duid_to_string_internal(uint16_t type, const void *data, size_t data_size, char **ret);
|
||||
|
||||
int dhcp_identifier_set_iaid(
|
||||
sd_device *dev,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
bool legacy_unstable_byteorder,
|
||||
void *ret);
|
||||
|
|
@ -1,252 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include <linux/if_infiniband.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include "dhcp-identifier.h"
|
||||
#include "netif-util.h"
|
||||
#include "siphash24.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "string-table.h"
|
||||
|
||||
#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
|
||||
#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
|
||||
#define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */
|
||||
|
||||
static const char * const duid_type_table[_DUID_TYPE_MAX] = {
|
||||
[DUID_TYPE_LLT] = "DUID-LLT",
|
||||
[DUID_TYPE_EN] = "DUID-EN/Vendor",
|
||||
[DUID_TYPE_LL] = "DUID-LL",
|
||||
[DUID_TYPE_UUID] = "UUID",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(duid_type, DUIDType);
|
||||
|
||||
int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict) {
|
||||
struct duid d;
|
||||
|
||||
assert_cc(sizeof(d.raw) >= MAX_DUID_LEN);
|
||||
if (duid_len > MAX_DUID_LEN)
|
||||
return -EINVAL;
|
||||
|
||||
if (!strict)
|
||||
/* Strict validation is not requested. We only ensure that the
|
||||
* DUID is not too long. */
|
||||
return 0;
|
||||
|
||||
switch (duid_type) {
|
||||
case DUID_TYPE_LLT:
|
||||
if (duid_len <= sizeof(d.llt))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case DUID_TYPE_EN:
|
||||
if (duid_len != sizeof(d.en))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case DUID_TYPE_LL:
|
||||
if (duid_len <= sizeof(d.ll))
|
||||
return -EINVAL;
|
||||
break;
|
||||
case DUID_TYPE_UUID:
|
||||
if (duid_len != sizeof(d.uuid))
|
||||
return -EINVAL;
|
||||
break;
|
||||
default:
|
||||
/* accept unknown type in order to be forward compatible */
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
static int dhcp_identifier_set_duid_llt(
|
||||
const struct hw_addr_data *hw_addr,
|
||||
uint16_t arp_type,
|
||||
usec_t t,
|
||||
struct duid *ret_duid,
|
||||
size_t *ret_len) {
|
||||
|
||||
uint16_t time_from_2000y;
|
||||
|
||||
assert(hw_addr);
|
||||
assert(ret_duid);
|
||||
assert(ret_len);
|
||||
|
||||
if (hw_addr->length == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (arp_type == ARPHRD_ETHER)
|
||||
assert_return(hw_addr->length == ETH_ALEN, -EINVAL);
|
||||
else if (arp_type == ARPHRD_INFINIBAND)
|
||||
assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (t < USEC_2000)
|
||||
time_from_2000y = 0;
|
||||
else
|
||||
time_from_2000y = (uint16_t) (((t - USEC_2000) / USEC_PER_SEC) & 0xffffffff);
|
||||
|
||||
unaligned_write_be16(&ret_duid->type, DUID_TYPE_LLT);
|
||||
unaligned_write_be16(&ret_duid->llt.htype, arp_type);
|
||||
unaligned_write_be32(&ret_duid->llt.time, time_from_2000y);
|
||||
memcpy(ret_duid->llt.haddr, hw_addr->bytes, hw_addr->length);
|
||||
|
||||
*ret_len = offsetof(struct duid, llt.haddr) + hw_addr->length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp_identifier_set_duid_ll(
|
||||
const struct hw_addr_data *hw_addr,
|
||||
uint16_t arp_type,
|
||||
struct duid *ret_duid,
|
||||
size_t *ret_len) {
|
||||
|
||||
assert(hw_addr);
|
||||
assert(ret_duid);
|
||||
assert(ret_len);
|
||||
|
||||
if (hw_addr->length == 0)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (arp_type == ARPHRD_ETHER)
|
||||
assert_return(hw_addr->length == ETH_ALEN, -EINVAL);
|
||||
else if (arp_type == ARPHRD_INFINIBAND)
|
||||
assert_return(hw_addr->length == INFINIBAND_ALEN, -EINVAL);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
unaligned_write_be16(&ret_duid->type, DUID_TYPE_LL);
|
||||
unaligned_write_be16(&ret_duid->ll.htype, arp_type);
|
||||
memcpy(ret_duid->ll.haddr, hw_addr->bytes, hw_addr->length);
|
||||
|
||||
*ret_len = offsetof(struct duid, ll.haddr) + hw_addr->length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *ret_len) {
|
||||
sd_id128_t machine_id;
|
||||
uint64_t hash;
|
||||
int r;
|
||||
|
||||
assert(ret_duid);
|
||||
assert(ret_len);
|
||||
|
||||
if (!test_mode) {
|
||||
r = sd_id128_get_machine(&machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
/* For tests, especially for fuzzers, reproducibility is important.
|
||||
* Hence, use a static and constant machine ID.
|
||||
* See 9216fddc5a8ac2742e6cfa7660f95c20ca4f2193. */
|
||||
machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10);
|
||||
|
||||
unaligned_write_be16(&ret_duid->type, DUID_TYPE_EN);
|
||||
unaligned_write_be32(&ret_duid->en.pen, SYSTEMD_PEN);
|
||||
|
||||
/* a bit of snake-oil perhaps, but no need to expose the machine-id
|
||||
* directly; duid->en.id might not be aligned, so we need to copy */
|
||||
hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes));
|
||||
memcpy(ret_duid->en.id, &hash, sizeof(ret_duid->en.id));
|
||||
|
||||
*ret_len = offsetof(struct duid, en.id) + sizeof(ret_duid->en.id);
|
||||
|
||||
if (test_mode)
|
||||
assert_se(memcmp(ret_duid, (const uint8_t[]) { 0x00, 0x02, 0x00, 0x00, 0xab, 0x11, 0x61, 0x77, 0x40, 0xde, 0x13, 0x42, 0xc3, 0xa2 }, *ret_len) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
static int dhcp_identifier_set_duid_uuid(struct duid *ret_duid, size_t *ret_len) {
|
||||
sd_id128_t machine_id;
|
||||
int r;
|
||||
|
||||
assert(ret_duid);
|
||||
assert(ret_len);
|
||||
|
||||
r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
unaligned_write_be16(&ret_duid->type, DUID_TYPE_UUID);
|
||||
memcpy(&ret_duid->uuid.uuid, &machine_id, sizeof(machine_id));
|
||||
|
||||
*ret_len = offsetof(struct duid, uuid.uuid) + sizeof(machine_id);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_identifier_set_duid(
|
||||
DUIDType duid_type,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
uint16_t arp_type,
|
||||
usec_t llt_time,
|
||||
bool test_mode,
|
||||
struct duid *ret_duid,
|
||||
size_t *ret_len) {
|
||||
|
||||
switch (duid_type) {
|
||||
case DUID_TYPE_LLT:
|
||||
return dhcp_identifier_set_duid_llt(hw_addr, arp_type, llt_time, ret_duid, ret_len);
|
||||
case DUID_TYPE_EN:
|
||||
return dhcp_identifier_set_duid_en(test_mode, ret_duid, ret_len);
|
||||
case DUID_TYPE_LL:
|
||||
return dhcp_identifier_set_duid_ll(hw_addr, arp_type, ret_duid, ret_len);
|
||||
case DUID_TYPE_UUID:
|
||||
return dhcp_identifier_set_duid_uuid(ret_duid, ret_len);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int dhcp_identifier_set_iaid(
|
||||
sd_device *dev,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
bool legacy_unstable_byteorder,
|
||||
void *ret) {
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
||||
const char *name = NULL;
|
||||
uint32_t id32;
|
||||
uint64_t id;
|
||||
|
||||
assert(hw_addr);
|
||||
assert(ret);
|
||||
|
||||
if (dev)
|
||||
name = net_get_persistent_name(dev);
|
||||
if (name)
|
||||
id = siphash24(name, strlen(name), HASH_KEY.bytes);
|
||||
else
|
||||
/* fall back to MAC address if no predictable name available */
|
||||
id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes);
|
||||
|
||||
id32 = (id & 0xffffffff) ^ (id >> 32);
|
||||
|
||||
if (legacy_unstable_byteorder)
|
||||
/* for historical reasons (a bug), the bits were swapped and thus
|
||||
* the result was endianness dependent. Preserve that behavior. */
|
||||
id32 = bswap_32(id32);
|
||||
else
|
||||
/* the fixed behavior returns a stable byte order. Since LE is expected
|
||||
* to be more common, swap the bytes on LE to give the same as legacy
|
||||
* behavior. */
|
||||
id32 = be32toh(id32);
|
||||
|
||||
unaligned_write_ne32(ret, id32);
|
||||
return 0;
|
||||
#else /* NM_IGNORED */
|
||||
/* for NetworkManager, we don't use this function and we should never call here.
|
||||
* This got replaced by nm_utils_create_dhcp_iaid(). */
|
||||
g_return_val_if_reached (-EINVAL);
|
||||
#endif /* NM_IGNORED */
|
||||
}
|
||||
|
|
@ -1,75 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "ether-addr-util.h"
|
||||
#include "macro.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "time-util.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
#define SYSTEMD_PEN 43793
|
||||
|
||||
typedef enum DUIDType {
|
||||
DUID_TYPE_LLT = 1,
|
||||
DUID_TYPE_EN = 2,
|
||||
DUID_TYPE_LL = 3,
|
||||
DUID_TYPE_UUID = 4,
|
||||
_DUID_TYPE_MAX,
|
||||
_DUID_TYPE_INVALID = -EINVAL,
|
||||
} DUIDType;
|
||||
|
||||
/* RFC 3315 section 9.1:
|
||||
* A DUID can be no more than 128 octets long (not including the type code).
|
||||
*/
|
||||
#define MAX_DUID_LEN 128
|
||||
|
||||
/* https://tools.ietf.org/html/rfc3315#section-9.1 */
|
||||
struct duid {
|
||||
be16_t type;
|
||||
union {
|
||||
struct {
|
||||
/* DUID_TYPE_LLT */
|
||||
be16_t htype;
|
||||
be32_t time;
|
||||
uint8_t haddr[0];
|
||||
} _packed_ llt;
|
||||
struct {
|
||||
/* DUID_TYPE_EN */
|
||||
be32_t pen;
|
||||
uint8_t id[8];
|
||||
} _packed_ en;
|
||||
struct {
|
||||
/* DUID_TYPE_LL */
|
||||
be16_t htype;
|
||||
uint8_t haddr[0];
|
||||
} _packed_ ll;
|
||||
struct {
|
||||
/* DUID_TYPE_UUID */
|
||||
sd_id128_t uuid;
|
||||
} _packed_ uuid;
|
||||
struct {
|
||||
uint8_t data[MAX_DUID_LEN];
|
||||
} _packed_ raw;
|
||||
};
|
||||
} _packed_;
|
||||
|
||||
int dhcp_validate_duid_len(DUIDType duid_type, size_t duid_len, bool strict);
|
||||
int dhcp_identifier_set_duid_en(bool test_mode, struct duid *ret_duid, size_t *ret_len);
|
||||
int dhcp_identifier_set_duid(
|
||||
DUIDType duid_type,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
uint16_t arp_type,
|
||||
usec_t llt_time,
|
||||
bool test_mode,
|
||||
struct duid *ret_duid,
|
||||
size_t *ret_len);
|
||||
int dhcp_identifier_set_iaid(
|
||||
sd_device *dev,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
bool legacy_unstable_byteorder,
|
||||
void *ret);
|
||||
|
||||
const char *duid_type_to_string(DUIDType t) _const_;
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include "sd-dhcp6-client.h"
|
||||
|
||||
int dhcp6_client_set_state_callback(
|
||||
sd_dhcp6_client *client,
|
||||
sd_dhcp6_client_callback_t cb,
|
||||
void *userdata);
|
||||
int dhcp6_client_get_state(sd_dhcp6_client *client);
|
||||
|
|
@ -11,7 +11,8 @@
|
|||
#include "sd-event.h"
|
||||
#include "sd-dhcp6-client.h"
|
||||
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "dhcp6-client-internal.h"
|
||||
#include "dhcp6-option.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
#include "ether-addr-util.h"
|
||||
|
|
@ -63,8 +64,7 @@ struct sd_dhcp6_client {
|
|||
DHCP6IA ia_na;
|
||||
DHCP6IA ia_pd;
|
||||
DHCP6RequestIA request_ia;
|
||||
struct duid duid;
|
||||
size_t duid_len;
|
||||
sd_dhcp_duid duid;
|
||||
be16_t *req_opts;
|
||||
size_t n_req_opts;
|
||||
char *fqdn;
|
||||
|
|
@ -79,10 +79,9 @@ struct sd_dhcp6_client {
|
|||
|
||||
sd_dhcp6_client_callback_t callback;
|
||||
void *userdata;
|
||||
sd_dhcp6_client_callback_t state_callback;
|
||||
void *state_userdata;
|
||||
bool send_release;
|
||||
|
||||
/* Ignore machine-ID when generating DUID. See dhcp_identifier_set_duid_en(). */
|
||||
bool test_mode;
|
||||
};
|
||||
|
||||
int dhcp6_network_bind_udp_socket(int ifindex, struct in6_addr *address);
|
||||
|
|
@ -90,7 +89,6 @@ int dhcp6_network_send_udp_socket(int s, struct in6_addr *address,
|
|||
const void *packet, size_t len);
|
||||
|
||||
int dhcp6_client_send_message(sd_dhcp6_client *client);
|
||||
void dhcp6_client_set_test_mode(sd_dhcp6_client *client, bool test_mode);
|
||||
int dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transaction_id);
|
||||
|
||||
#define log_dhcp6_client_errno(client, error, fmt, ...) \
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@
|
|||
#include "sd-dhcp6-lease.h"
|
||||
|
||||
#include "dhcp6-option.h"
|
||||
#include "dhcp6-protocol.h"
|
||||
#include "macro.h"
|
||||
#include "set.h"
|
||||
#include "time-util.h"
|
||||
|
||||
struct sd_dhcp6_lease {
|
||||
|
|
@ -43,9 +45,11 @@ struct sd_dhcp6_lease {
|
|||
struct in6_addr *sntp;
|
||||
size_t sntp_count;
|
||||
char *fqdn;
|
||||
char *captive_portal;
|
||||
struct sd_dhcp6_option **sorted_vendor_options;
|
||||
Set *vendor_options;
|
||||
};
|
||||
|
||||
int dhcp6_lease_get_lifetime(sd_dhcp6_lease *lease, usec_t *ret_t1, usec_t *ret_t2, usec_t *ret_valid);
|
||||
int dhcp6_lease_set_clientid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len);
|
||||
int dhcp6_lease_get_clientid(sd_dhcp6_lease *lease, uint8_t **ret_id, size_t *ret_len);
|
||||
int dhcp6_lease_set_serverid(sd_dhcp6_lease *lease, const uint8_t *id, size_t len);
|
||||
|
|
@ -60,6 +64,7 @@ int dhcp6_lease_add_domains(sd_dhcp6_lease *lease, const uint8_t *optval, size_t
|
|||
int dhcp6_lease_add_ntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
|
||||
int dhcp6_lease_add_sntp(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
|
||||
int dhcp6_lease_set_fqdn(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
|
||||
int dhcp6_lease_set_captive_portal(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen);
|
||||
|
||||
int dhcp6_lease_new(sd_dhcp6_lease **ret);
|
||||
int dhcp6_lease_new_from_message(
|
||||
|
|
@ -69,3 +74,17 @@ int dhcp6_lease_new_from_message(
|
|||
const triple_timestamp *timestamp,
|
||||
const struct in6_addr *server_address,
|
||||
sd_dhcp6_lease **ret);
|
||||
|
||||
#define _FOREACH_DHCP6_ADDRESS(lease, it) \
|
||||
for (int it = sd_dhcp6_lease_address_iterator_reset(lease); \
|
||||
it > 0; \
|
||||
it = sd_dhcp6_lease_address_iterator_next(lease))
|
||||
#define FOREACH_DHCP6_ADDRESS(lease) \
|
||||
_FOREACH_DHCP6_ADDRESS(lease, UNIQ_T(i, UNIQ))
|
||||
|
||||
#define _FOREACH_DHCP6_PD_PREFIX(lease, it) \
|
||||
for (int it = sd_dhcp6_lease_pd_iterator_reset(lease); \
|
||||
it > 0; \
|
||||
it = sd_dhcp6_lease_pd_iterator_next(lease))
|
||||
#define FOREACH_DHCP6_PD_PREFIX(lease) \
|
||||
_FOREACH_DHCP6_PD_PREFIX(lease, UNIQ_T(i, UNIQ))
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include "dns-domain.h"
|
||||
#include "escape.h"
|
||||
#include "memory-util.h"
|
||||
#include "network-common.h"
|
||||
#include "strv.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
|
|
@ -526,6 +527,26 @@ int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_s
|
|||
return status;
|
||||
}
|
||||
|
||||
/* parse a string from dhcp option field. *ret must be initialized */
|
||||
int dhcp6_option_parse_string(const uint8_t *data, size_t data_len, char **ret) {
|
||||
_cleanup_free_ char *string = NULL;
|
||||
int r;
|
||||
|
||||
assert(data || data_len == 0);
|
||||
assert(ret);
|
||||
|
||||
if (data_len <= 0) {
|
||||
*ret = mfree(*ret);
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = make_cstring((const char *) data, data_len, MAKE_CSTRING_REFUSE_TRAILING_NUL, &string);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return free_and_replace(*ret, string);
|
||||
}
|
||||
|
||||
static int dhcp6_option_parse_ia_options(sd_dhcp6_client *client, const uint8_t *buf, size_t buflen) {
|
||||
int r;
|
||||
|
||||
|
|
@ -567,7 +588,7 @@ static int dhcp6_option_parse_ia_options(sd_dhcp6_client *client, const uint8_t
|
|||
|
||||
static int dhcp6_option_parse_ia_address(sd_dhcp6_client *client, DHCP6IA *ia, const uint8_t *data, size_t len) {
|
||||
_cleanup_free_ DHCP6Address *a = NULL;
|
||||
uint32_t lt_valid, lt_pref;
|
||||
usec_t lt_valid, lt_pref;
|
||||
int r;
|
||||
|
||||
assert(ia);
|
||||
|
|
@ -586,17 +607,18 @@ static int dhcp6_option_parse_ia_address(sd_dhcp6_client *client, DHCP6IA *ia, c
|
|||
|
||||
memcpy(&a->iaaddr, data, sizeof(struct iaaddr));
|
||||
|
||||
lt_valid = be32toh(a->iaaddr.lifetime_valid);
|
||||
lt_pref = be32toh(a->iaaddr.lifetime_preferred);
|
||||
lt_valid = be32_sec_to_usec(a->iaaddr.lifetime_valid, /* max_as_infinity = */ true);
|
||||
lt_pref = be32_sec_to_usec(a->iaaddr.lifetime_preferred, /* max_as_infinity = */ true);
|
||||
|
||||
if (lt_valid == 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Received an IA address with zero valid lifetime, ignoring.");
|
||||
if (lt_pref > lt_valid)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Received an IA address with preferred lifetime %"PRIu32
|
||||
" larger than valid lifetime %"PRIu32", ignoring.",
|
||||
lt_pref, lt_valid);
|
||||
"Received an IA address with preferred lifetime %s "
|
||||
"larger than valid lifetime %s, ignoring.",
|
||||
FORMAT_TIMESPAN(lt_pref, USEC_PER_SEC),
|
||||
FORMAT_TIMESPAN(lt_valid, USEC_PER_SEC));
|
||||
|
||||
if (len > sizeof(struct iaaddr)) {
|
||||
r = dhcp6_option_parse_ia_options(client, data + sizeof(struct iaaddr), len - sizeof(struct iaaddr));
|
||||
|
|
@ -610,7 +632,7 @@ static int dhcp6_option_parse_ia_address(sd_dhcp6_client *client, DHCP6IA *ia, c
|
|||
|
||||
static int dhcp6_option_parse_ia_pdprefix(sd_dhcp6_client *client, DHCP6IA *ia, const uint8_t *data, size_t len) {
|
||||
_cleanup_free_ DHCP6Address *a = NULL;
|
||||
uint32_t lt_valid, lt_pref;
|
||||
usec_t lt_valid, lt_pref;
|
||||
int r;
|
||||
|
||||
assert(ia);
|
||||
|
|
@ -629,17 +651,18 @@ static int dhcp6_option_parse_ia_pdprefix(sd_dhcp6_client *client, DHCP6IA *ia,
|
|||
|
||||
memcpy(&a->iapdprefix, data, sizeof(struct iapdprefix));
|
||||
|
||||
lt_valid = be32toh(a->iapdprefix.lifetime_valid);
|
||||
lt_pref = be32toh(a->iapdprefix.lifetime_preferred);
|
||||
lt_valid = be32_sec_to_usec(a->iapdprefix.lifetime_valid, /* max_as_infinity = */ true);
|
||||
lt_pref = be32_sec_to_usec(a->iapdprefix.lifetime_preferred, /* max_as_infinity = */ true);
|
||||
|
||||
if (lt_valid == 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Received a PD prefix with zero valid lifetime, ignoring.");
|
||||
if (lt_pref > lt_valid)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Received a PD prefix with preferred lifetime %"PRIu32
|
||||
" larger than valid lifetime %"PRIu32", ignoring.",
|
||||
lt_pref, lt_valid);
|
||||
"Received a PD prefix with preferred lifetime %s "
|
||||
"larger than valid lifetime %s, ignoring.",
|
||||
FORMAT_TIMESPAN(lt_pref, USEC_PER_SEC),
|
||||
FORMAT_TIMESPAN(lt_valid, USEC_PER_SEC));
|
||||
|
||||
if (len > sizeof(struct iapdprefix)) {
|
||||
r = dhcp6_option_parse_ia_options(client, data + sizeof(struct iapdprefix), len - sizeof(struct iapdprefix));
|
||||
|
|
@ -660,7 +683,7 @@ int dhcp6_option_parse_ia(
|
|||
DHCP6IA **ret) {
|
||||
|
||||
_cleanup_(dhcp6_ia_freep) DHCP6IA *ia = NULL;
|
||||
uint32_t lt_t1, lt_t2;
|
||||
usec_t lt_t1, lt_t2;
|
||||
size_t header_len;
|
||||
int r;
|
||||
|
||||
|
|
@ -710,17 +733,18 @@ int dhcp6_option_parse_ia(
|
|||
"from the one chosen by the client, ignoring.");
|
||||
|
||||
/* It is not necessary to check if the lifetime_t2 is zero here, as in that case it will be updated later. */
|
||||
lt_t1 = be32toh(ia->header.lifetime_t1);
|
||||
lt_t2 = be32toh(ia->header.lifetime_t2);
|
||||
lt_t1 = be32_sec_to_usec(ia->header.lifetime_t1, /* max_as_infinity = */ true);
|
||||
lt_t2 = be32_sec_to_usec(ia->header.lifetime_t2, /* max_as_infinity = */ true);
|
||||
|
||||
if (lt_t1 > lt_t2)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Received an IA option with T1 %"PRIu32"sec > T2 %"PRIu32"sec, ignoring.",
|
||||
lt_t1, lt_t2);
|
||||
"Received an IA option with T1 %s > T2 %s, ignoring.",
|
||||
FORMAT_TIMESPAN(lt_t1, USEC_PER_SEC),
|
||||
FORMAT_TIMESPAN(lt_t2, USEC_PER_SEC));
|
||||
if (lt_t1 == 0 && lt_t2 > 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Received an IA option with zero T1 and non-zero T2 (%"PRIu32"sec), ignoring.",
|
||||
lt_t2);
|
||||
"Received an IA option with zero T1 and non-zero T2 (%s), ignoring.",
|
||||
FORMAT_TIMESPAN(lt_t2, USEC_PER_SEC));
|
||||
|
||||
for (size_t offset = header_len; offset < option_data_len;) {
|
||||
const uint8_t *subdata;
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ int dhcp6_option_parse(
|
|||
size_t *ret_option_data_len,
|
||||
const uint8_t **ret_option_data);
|
||||
int dhcp6_option_parse_status(const uint8_t *data, size_t data_len, char **ret_status_message);
|
||||
int dhcp6_option_parse_string(const uint8_t *data, size_t data_len, char **ret);
|
||||
int dhcp6_option_parse_ia(
|
||||
sd_dhcp6_client *client,
|
||||
be32_t iaid,
|
||||
|
|
|
|||
|
|
@ -2,8 +2,11 @@
|
|||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include "env-util.h"
|
||||
#include "format-util.h"
|
||||
#include "network-common.h"
|
||||
#include "socket-util.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
int get_ifname(int ifindex, char **ifname) {
|
||||
assert(ifname);
|
||||
|
|
@ -15,3 +18,111 @@ int get_ifname(int ifindex, char **ifname) {
|
|||
|
||||
return format_ifname_alloc(ifindex, ifname);
|
||||
}
|
||||
|
||||
usec_t unaligned_be32_sec_to_usec(const void *p, bool max_as_infinity) {
|
||||
uint32_t s = unaligned_read_be32(ASSERT_PTR(p));
|
||||
|
||||
if (s == UINT32_MAX && max_as_infinity)
|
||||
return USEC_INFINITY;
|
||||
|
||||
return s * USEC_PER_SEC;
|
||||
}
|
||||
|
||||
usec_t be32_sec_to_usec(be32_t t, bool max_as_infinity) {
|
||||
uint32_t s = be32toh(t);
|
||||
|
||||
if (s == UINT32_MAX && max_as_infinity)
|
||||
return USEC_INFINITY;
|
||||
|
||||
return s * USEC_PER_SEC;
|
||||
}
|
||||
|
||||
usec_t be32_msec_to_usec(be32_t t, bool max_as_infinity) {
|
||||
uint32_t s = be32toh(t);
|
||||
|
||||
if (s == UINT32_MAX && max_as_infinity)
|
||||
return USEC_INFINITY;
|
||||
|
||||
return s * USEC_PER_MSEC;
|
||||
}
|
||||
|
||||
usec_t be16_sec_to_usec(be16_t t, bool max_as_infinity) {
|
||||
uint16_t s = be16toh(t);
|
||||
|
||||
if (s == UINT16_MAX && max_as_infinity)
|
||||
return USEC_INFINITY;
|
||||
|
||||
return s * USEC_PER_SEC;
|
||||
}
|
||||
|
||||
be32_t usec_to_be32_sec(usec_t t) {
|
||||
if (t == USEC_INFINITY)
|
||||
/* Some settings, e.g. a lifetime of an address, UINT32_MAX is handled as infinity. so let's
|
||||
* map USEC_INFINITY to UINT32_MAX. */
|
||||
return htobe32(UINT32_MAX);
|
||||
|
||||
if (t >= (UINT32_MAX - 1) * USEC_PER_SEC)
|
||||
/* Finite but too large. Let's use the largest (or off-by-one from the largest) finite value. */
|
||||
return htobe32(UINT32_MAX - 1);
|
||||
|
||||
return htobe32((uint32_t) DIV_ROUND_UP(t, USEC_PER_SEC));
|
||||
}
|
||||
|
||||
be32_t usec_to_be32_msec(usec_t t) {
|
||||
if (t == USEC_INFINITY)
|
||||
return htobe32(UINT32_MAX);
|
||||
|
||||
if (t >= (UINT32_MAX - 1) * USEC_PER_MSEC)
|
||||
return htobe32(UINT32_MAX - 1);
|
||||
|
||||
return htobe32((uint32_t) DIV_ROUND_UP(t, USEC_PER_MSEC));
|
||||
}
|
||||
|
||||
be16_t usec_to_be16_sec(usec_t t) {
|
||||
if (t == USEC_INFINITY)
|
||||
return htobe16(UINT16_MAX);
|
||||
|
||||
if (t >= (UINT16_MAX - 1) * USEC_PER_SEC)
|
||||
return htobe16(UINT16_MAX - 1);
|
||||
|
||||
return htobe16((uint16_t) DIV_ROUND_UP(t, USEC_PER_SEC));
|
||||
}
|
||||
|
||||
usec_t time_span_to_stamp(usec_t span, usec_t base) {
|
||||
/* Typically, 0 lifetime (timespan) indicates the corresponding configuration (address or so) must be
|
||||
* dropped. So, when the timespan is zero, here we return 0 rather than 'base'. This makes the caller
|
||||
* easily understand that the configuration needs to be dropped immediately. */
|
||||
if (span == 0)
|
||||
return 0;
|
||||
|
||||
return usec_add(base, span);
|
||||
}
|
||||
|
||||
bool network_test_mode_enabled(void) {
|
||||
static int test_mode = -1;
|
||||
int r;
|
||||
|
||||
if (test_mode < 0) {
|
||||
r = getenv_bool("SYSTEMD_NETWORK_TEST_MODE");
|
||||
if (r < 0) {
|
||||
if (r != -ENXIO)
|
||||
log_debug_errno(r, "Failed to parse $SYSTEMD_NETWORK_TEST_MODE environment variable, ignoring: %m");
|
||||
|
||||
test_mode = false;
|
||||
} else
|
||||
test_mode = r;
|
||||
}
|
||||
|
||||
return test_mode;
|
||||
}
|
||||
|
||||
triple_timestamp* triple_timestamp_from_cmsg(triple_timestamp *t, struct msghdr *mh) {
|
||||
assert(t);
|
||||
assert(mh);
|
||||
|
||||
struct timeval *tv = CMSG_FIND_AND_COPY_DATA(mh, SOL_SOCKET, SCM_TIMESTAMP, struct timeval);
|
||||
if (tv)
|
||||
return triple_timestamp_from_realtime(t, timeval_load(tv));
|
||||
|
||||
return triple_timestamp_now(t);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "log-link.h"
|
||||
#include "sparse-endian.h"
|
||||
#include "time-util.h"
|
||||
|
||||
#define log_interface_prefix_full_errno_zerook(prefix, type, val, error, fmt, ...) \
|
||||
({ \
|
||||
|
|
@ -28,3 +32,18 @@
|
|||
})
|
||||
|
||||
int get_ifname(int ifindex, char **ifname);
|
||||
|
||||
usec_t unaligned_be32_sec_to_usec(const void *p, bool max_as_infinity);
|
||||
usec_t be32_sec_to_usec(be32_t t, bool max_as_infinity);
|
||||
usec_t be32_msec_to_usec(be32_t t, bool max_as_infinity);
|
||||
usec_t be16_sec_to_usec(be16_t t, bool max_as_infinity);
|
||||
be32_t usec_to_be32_sec(usec_t t);
|
||||
be32_t usec_to_be32_msec(usec_t t);
|
||||
be16_t usec_to_be16_sec(usec_t t);
|
||||
usec_t time_span_to_stamp(usec_t span, usec_t base);
|
||||
|
||||
bool network_test_mode_enabled(void);
|
||||
|
||||
triple_timestamp* triple_timestamp_from_cmsg(triple_timestamp *t, struct msghdr *mh);
|
||||
#define TRIPLE_TIMESTAMP_FROM_CMSG(mh) \
|
||||
triple_timestamp_from_cmsg(&(triple_timestamp) {}, mh)
|
||||
|
|
|
|||
290
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-duid.c
Normal file
290
src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-duid.c
Normal file
|
|
@ -0,0 +1,290 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "nm-sd-adapt-core.h"
|
||||
|
||||
#include <linux/if_infiniband.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if_arp.h>
|
||||
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "netif-util.h"
|
||||
#include "network-common.h"
|
||||
#include "siphash24.h"
|
||||
#include "string-table.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
#define HASH_KEY SD_ID128_MAKE(80,11,8c,c2,fe,4a,03,ee,3e,d6,0c,6f,36,39,14,09)
|
||||
#define APPLICATION_ID SD_ID128_MAKE(a5,0a,d1,12,bf,60,45,77,a2,fb,74,1a,b1,95,5b,03)
|
||||
#define USEC_2000 ((usec_t) 946684800000000) /* 2000-01-01 00:00:00 UTC */
|
||||
|
||||
static const char * const duid_type_table[_DUID_TYPE_MAX] = {
|
||||
[DUID_TYPE_LLT] = "DUID-LLT",
|
||||
[DUID_TYPE_EN] = "DUID-EN/Vendor",
|
||||
[DUID_TYPE_LL] = "DUID-LL",
|
||||
[DUID_TYPE_UUID] = "UUID",
|
||||
};
|
||||
|
||||
DEFINE_STRING_TABLE_LOOKUP_TO_STRING(duid_type, DUIDType);
|
||||
|
||||
int sd_dhcp_duid_clear(sd_dhcp_duid *duid) {
|
||||
assert_return(duid, -EINVAL);
|
||||
|
||||
*duid = (sd_dhcp_duid) {};
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_is_set(const sd_dhcp_duid *duid) {
|
||||
if (!duid)
|
||||
return false;
|
||||
|
||||
return duid_size_is_valid(duid->size);
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_get(const sd_dhcp_duid *duid, uint16_t *ret_type, const void **ret_data, size_t *ret_size) {
|
||||
assert_return(sd_dhcp_duid_is_set(duid), -EINVAL);
|
||||
assert_return(ret_type, -EINVAL);
|
||||
assert_return(ret_data, -EINVAL);
|
||||
assert_return(ret_size, -EINVAL);
|
||||
|
||||
*ret_type = be16toh(duid->duid.type);
|
||||
*ret_data = duid->duid.data;
|
||||
*ret_size = duid->size - offsetof(struct duid, data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_get_raw(const sd_dhcp_duid *duid, const void **ret_data, size_t *ret_size) {
|
||||
assert_return(sd_dhcp_duid_is_set(duid), -EINVAL);
|
||||
assert_return(ret_data, -EINVAL);
|
||||
assert_return(ret_size, -EINVAL);
|
||||
|
||||
/* Unlike sd_dhcp_duid_get(), this returns whole DUID including its type. */
|
||||
|
||||
*ret_data = duid->raw;
|
||||
*ret_size = duid->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set(
|
||||
sd_dhcp_duid *duid,
|
||||
uint16_t duid_type,
|
||||
const void *data,
|
||||
size_t data_size) {
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
assert_return(data, -EINVAL);
|
||||
|
||||
if (!duid_data_size_is_valid(data_size))
|
||||
return -EINVAL;
|
||||
|
||||
unaligned_write_be16(&duid->duid.type, duid_type);
|
||||
memcpy(duid->duid.data, data, data_size);
|
||||
|
||||
duid->size = offsetof(struct duid, data) + data_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set_raw(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *data,
|
||||
size_t data_size) {
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
assert_return(data, -EINVAL);
|
||||
|
||||
/* Unlike sd_dhcp_duid_set(), this takes whole DUID including its type. */
|
||||
|
||||
if (!duid_size_is_valid(data_size))
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(duid->raw, data, data_size);
|
||||
|
||||
duid->size = data_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set_llt(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *hw_addr,
|
||||
size_t hw_addr_size,
|
||||
uint16_t arp_type,
|
||||
uint64_t usec) {
|
||||
|
||||
uint16_t time_from_2000y;
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
assert_return(hw_addr, -EINVAL);
|
||||
|
||||
if (arp_type == ARPHRD_ETHER)
|
||||
assert_return(hw_addr_size == ETH_ALEN, -EINVAL);
|
||||
else if (arp_type == ARPHRD_INFINIBAND)
|
||||
assert_return(hw_addr_size == INFINIBAND_ALEN, -EINVAL);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
time_from_2000y = (uint16_t) ((usec_sub_unsigned(usec, USEC_2000) / USEC_PER_SEC) & 0xffffffff);
|
||||
|
||||
unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_LLT);
|
||||
unaligned_write_be16(&duid->duid.llt.htype, arp_type);
|
||||
unaligned_write_be32(&duid->duid.llt.time, time_from_2000y);
|
||||
memcpy(duid->duid.llt.haddr, hw_addr, hw_addr_size);
|
||||
|
||||
duid->size = offsetof(struct duid, llt.haddr) + hw_addr_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set_ll(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *hw_addr,
|
||||
size_t hw_addr_size,
|
||||
uint16_t arp_type) {
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
assert_return(hw_addr, -EINVAL);
|
||||
|
||||
if (arp_type == ARPHRD_ETHER)
|
||||
assert_return(hw_addr_size == ETH_ALEN, -EINVAL);
|
||||
else if (arp_type == ARPHRD_INFINIBAND)
|
||||
assert_return(hw_addr_size == INFINIBAND_ALEN, -EINVAL);
|
||||
else
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_LL);
|
||||
unaligned_write_be16(&duid->duid.ll.htype, arp_type);
|
||||
memcpy(duid->duid.ll.haddr, hw_addr, hw_addr_size);
|
||||
|
||||
duid->size = offsetof(struct duid, ll.haddr) + hw_addr_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set_en(sd_dhcp_duid *duid) {
|
||||
sd_id128_t machine_id;
|
||||
bool test_mode;
|
||||
uint64_t hash;
|
||||
int r;
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
|
||||
test_mode = network_test_mode_enabled();
|
||||
|
||||
if (!test_mode) {
|
||||
r = sd_id128_get_machine(&machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else
|
||||
/* For tests, especially for fuzzers, reproducibility is important.
|
||||
* Hence, use a static and constant machine ID.
|
||||
* See 9216fddc5a8ac2742e6cfa7660f95c20ca4f2193. */
|
||||
machine_id = SD_ID128_MAKE(01, 02, 03, 04, 05, 06, 07, 08, 09, 0a, 0b, 0c, 0d, 0e, 0f, 10);
|
||||
|
||||
unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_EN);
|
||||
unaligned_write_be32(&duid->duid.en.pen, SYSTEMD_PEN);
|
||||
|
||||
/* a bit of snake-oil perhaps, but no need to expose the machine-id
|
||||
* directly; duid->en.id might not be aligned, so we need to copy */
|
||||
hash = htole64(siphash24(&machine_id, sizeof(machine_id), HASH_KEY.bytes));
|
||||
memcpy(duid->duid.en.id, &hash, sizeof(hash));
|
||||
|
||||
duid->size = offsetof(struct duid, en.id) + sizeof(hash);
|
||||
|
||||
if (test_mode)
|
||||
assert_se(memcmp(&duid->duid, (const uint8_t[]) { 0x00, 0x02, 0x00, 0x00, 0xab, 0x11, 0x61, 0x77, 0x40, 0xde, 0x13, 0x42, 0xc3, 0xa2 }, duid->size) == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_set_uuid(sd_dhcp_duid *duid) {
|
||||
sd_id128_t machine_id;
|
||||
int r;
|
||||
|
||||
assert_return(duid, -EINVAL);
|
||||
|
||||
r = sd_id128_get_machine_app_specific(APPLICATION_ID, &machine_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
unaligned_write_be16(&duid->duid.type, SD_DUID_TYPE_UUID);
|
||||
memcpy(&duid->duid.uuid.uuid, &machine_id, sizeof(machine_id));
|
||||
|
||||
duid->size = offsetof(struct duid, uuid.uuid) + sizeof(machine_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dhcp_duid_to_string_internal(uint16_t type, const void *data, size_t data_size, char **ret) {
|
||||
_cleanup_free_ char *p = NULL, *x = NULL;
|
||||
const char *t;
|
||||
|
||||
assert(data);
|
||||
assert(ret);
|
||||
|
||||
if (!duid_data_size_is_valid(data_size))
|
||||
return -EINVAL;
|
||||
|
||||
x = hexmem(data, data_size);
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
|
||||
t = duid_type_to_string(type);
|
||||
if (!t)
|
||||
return asprintf(ret, "%04x:%s", htobe16(type), x);
|
||||
|
||||
p = strjoin(t, ":", x);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = TAKE_PTR(p);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp_duid_to_string(const sd_dhcp_duid *duid, char **ret) {
|
||||
uint16_t type;
|
||||
const void *data;
|
||||
size_t data_size;
|
||||
int r;
|
||||
|
||||
assert_return(sd_dhcp_duid_is_set(duid), -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
r = sd_dhcp_duid_get(duid, &type, &data, &data_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return dhcp_duid_to_string_internal(type, data, data_size, ret);
|
||||
}
|
||||
|
||||
int dhcp_identifier_set_iaid(
|
||||
sd_device *dev,
|
||||
const struct hw_addr_data *hw_addr,
|
||||
bool legacy_unstable_byteorder,
|
||||
void *ret) {
|
||||
|
||||
const char *name = NULL;
|
||||
uint32_t id32;
|
||||
uint64_t id;
|
||||
|
||||
assert(hw_addr);
|
||||
assert(ret);
|
||||
|
||||
if (dev)
|
||||
name = net_get_persistent_name(dev);
|
||||
if (name)
|
||||
id = siphash24(name, strlen(name), HASH_KEY.bytes);
|
||||
else
|
||||
/* fall back to MAC address if no predictable name available */
|
||||
id = siphash24(hw_addr->bytes, hw_addr->length, HASH_KEY.bytes);
|
||||
|
||||
id32 = (id & 0xffffffff) ^ (id >> 32);
|
||||
|
||||
if (legacy_unstable_byteorder)
|
||||
/* for historical reasons (a bug), the bits were swapped and thus
|
||||
* the result was endianness dependent. Preserve that behavior. */
|
||||
id32 = bswap_32(id32);
|
||||
else
|
||||
/* the fixed behavior returns a stable byte order. Since LE is expected
|
||||
* to be more common, swap the bytes on LE to give the same as legacy
|
||||
* behavior. */
|
||||
id32 = be32toh(id32);
|
||||
|
||||
unaligned_write_ne32(ret, id32);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -7,27 +7,22 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#if 0 /* NM_IGNORED */
|
||||
#include <linux/if_arp.h>
|
||||
#else /* NM_IGNORED */
|
||||
#include <net/if_arp.h>
|
||||
#endif /* NM_IGNORED */
|
||||
#include <linux/if_infiniband.h>
|
||||
|
||||
#include "sd-dhcp6-client.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "device-util.h"
|
||||
#include "dhcp-identifier.h"
|
||||
#include "dhcp-duid-internal.h"
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-lease-internal.h"
|
||||
#include "dns-domain.h"
|
||||
#include "event-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "hexdecoct.h"
|
||||
#include "hostname-util.h"
|
||||
#include "in-addr-util.h"
|
||||
#include "io-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "random-util.h"
|
||||
#include "socket-util.h"
|
||||
#include "sort-util.h"
|
||||
|
|
@ -52,6 +47,19 @@ int sd_dhcp6_client_set_callback(
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_client_set_state_callback(
|
||||
sd_dhcp6_client *client,
|
||||
sd_dhcp6_client_callback_t cb,
|
||||
void *userdata) {
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
client->state_callback = cb;
|
||||
client->state_userdata = userdata;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_ifindex(sd_dhcp6_client *client, int ifindex) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
|
@ -184,10 +192,10 @@ int sd_dhcp6_client_add_vendor_option(sd_dhcp6_client *client, sd_dhcp6_option *
|
|||
static int client_ensure_duid(sd_dhcp6_client *client) {
|
||||
assert(client);
|
||||
|
||||
if (client->duid_len != 0)
|
||||
if (sd_dhcp_duid_is_set(&client->duid))
|
||||
return 0;
|
||||
|
||||
return dhcp_identifier_set_duid_en(client->test_mode, &client->duid, &client->duid_len);
|
||||
return sd_dhcp6_client_set_duid_en(client);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -195,101 +203,102 @@ static int client_ensure_duid(sd_dhcp6_client *client) {
|
|||
* without further modification. Otherwise, if duid_type is supported, DUID
|
||||
* is set based on that type. Otherwise, an error is returned.
|
||||
*/
|
||||
static int dhcp6_client_set_duid_internal(
|
||||
sd_dhcp6_client *client,
|
||||
DUIDType duid_type,
|
||||
const void *duid,
|
||||
size_t duid_len,
|
||||
usec_t llt_time) {
|
||||
int sd_dhcp6_client_set_duid_llt(sd_dhcp6_client *client, uint64_t llt_time) {
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
assert_return(duid_len == 0 || duid, -EINVAL);
|
||||
|
||||
if (duid) {
|
||||
r = dhcp_validate_duid_len(duid_type, duid_len, true);
|
||||
if (r < 0) {
|
||||
r = dhcp_validate_duid_len(duid_type, duid_len, false);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to validate length of DUID: %m");
|
||||
|
||||
log_dhcp6_client(client, "Using DUID of type %i of incorrect length, proceeding.", duid_type);
|
||||
}
|
||||
|
||||
client->duid.type = htobe16(duid_type);
|
||||
memcpy(&client->duid.raw.data, duid, duid_len);
|
||||
client->duid_len = sizeof(client->duid.type) + duid_len;
|
||||
|
||||
} else {
|
||||
#if 0 /* NM_IGNORED */
|
||||
r = dhcp_identifier_set_duid(duid_type, &client->hw_addr, client->arp_type, llt_time,
|
||||
client->test_mode, &client->duid, &client->duid_len);
|
||||
if (r == -EOPNOTSUPP)
|
||||
return log_dhcp6_client_errno(client, r,
|
||||
"Failed to set %s. MAC address is not set or "
|
||||
"interface type is not supported.",
|
||||
duid_type_to_string(duid_type));
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set %s: %m",
|
||||
duid_type_to_string(duid_type));
|
||||
#else /* NM_IGNORED */
|
||||
g_return_val_if_reached (-EINVAL);
|
||||
#endif /* NM_IGNORED */
|
||||
}
|
||||
r = sd_dhcp_duid_set_llt(&client->duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type, llt_time);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set DUID-LLT: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_duid(
|
||||
sd_dhcp6_client *client,
|
||||
uint16_t duid_type,
|
||||
const void *duid,
|
||||
size_t duid_len) {
|
||||
return dhcp6_client_set_duid_internal(client, duid_type, duid, duid_len, 0);
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_duid_llt(
|
||||
sd_dhcp6_client *client,
|
||||
usec_t llt_time) {
|
||||
return dhcp6_client_set_duid_internal(client, DUID_TYPE_LLT, NULL, 0, llt_time);
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_duid_as_string(
|
||||
sd_dhcp6_client *client,
|
||||
char **duid) {
|
||||
_cleanup_free_ char *p = NULL, *s = NULL, *t = NULL;
|
||||
const char *v;
|
||||
int sd_dhcp6_client_set_duid_ll(sd_dhcp6_client *client) {
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(client->duid_len > 0, -ENODATA);
|
||||
assert_return(duid, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
||||
v = duid_type_to_string(be16toh(client->duid.type));
|
||||
if (v) {
|
||||
s = strdup(v);
|
||||
if (!s)
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
r = asprintf(&s, "%0x", client->duid.type);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
t = hexmem(&client->duid.raw.data, client->duid_len);
|
||||
if (!t)
|
||||
return -ENOMEM;
|
||||
|
||||
p = strjoin(s, ":", t);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*duid = TAKE_PTR(p);
|
||||
r = sd_dhcp_duid_set_ll(&client->duid, client->hw_addr.bytes, client->hw_addr.length, client->arp_type);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set DUID-LL: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_duid_en(sd_dhcp6_client *client) {
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
||||
r = sd_dhcp_duid_set_en(&client->duid);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set DUID-EN: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_duid_uuid(sd_dhcp6_client *client) {
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
||||
r = sd_dhcp_duid_set_uuid(&client->duid);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set DUID-UUID: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_duid_raw(sd_dhcp6_client *client, uint16_t duid_type, const uint8_t *duid, size_t duid_len) {
|
||||
int r;
|
||||
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
assert_return(duid || duid_len == 0, -EINVAL);
|
||||
|
||||
r = sd_dhcp_duid_set(&client->duid, duid_type, duid, duid_len);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r, "Failed to set DUID: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, const sd_dhcp_duid *duid) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
assert_return(sd_dhcp_duid_is_set(duid), -EINVAL);
|
||||
|
||||
client->duid = *duid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_get_duid(sd_dhcp6_client *client, const sd_dhcp_duid **ret) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!sd_dhcp_duid_is_set(&client->duid))
|
||||
return -ENODATA;
|
||||
|
||||
*ret = &client->duid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_get_duid_as_string(sd_dhcp6_client *client, char **ret) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!sd_dhcp_duid_is_set(&client->duid))
|
||||
return -ENODATA;
|
||||
|
||||
return sd_dhcp_duid_to_string(&client->duid, ret);
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_iaid(sd_dhcp6_client *client, uint32_t iaid) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
|
@ -335,12 +344,6 @@ int sd_dhcp6_client_get_iaid(sd_dhcp6_client *client, uint32_t *iaid) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void dhcp6_client_set_test_mode(sd_dhcp6_client *client, bool test_mode) {
|
||||
assert(client);
|
||||
|
||||
client->test_mode = test_mode;
|
||||
}
|
||||
|
||||
int sd_dhcp6_client_set_fqdn(
|
||||
sd_dhcp6_client *client,
|
||||
const char *fqdn) {
|
||||
|
|
@ -491,7 +494,7 @@ int sd_dhcp6_client_set_address_request(sd_dhcp6_client *client, int request) {
|
|||
|
||||
int dhcp6_client_set_transaction_id(sd_dhcp6_client *client, uint32_t transaction_id) {
|
||||
assert(client);
|
||||
assert(client->test_mode);
|
||||
assert_se(network_test_mode_enabled());
|
||||
|
||||
/* This is for tests or fuzzers. */
|
||||
|
||||
|
|
@ -510,7 +513,6 @@ int sd_dhcp6_client_set_rapid_commit(sd_dhcp6_client *client, int enable) {
|
|||
|
||||
int sd_dhcp6_client_set_send_release(sd_dhcp6_client *client, int enable) {
|
||||
assert_return(client, -EINVAL);
|
||||
assert_return(!sd_dhcp6_client_is_running(client), -EBUSY);
|
||||
|
||||
client->send_release = enable;
|
||||
return 0;
|
||||
|
|
@ -552,6 +554,15 @@ static void client_set_state(sd_dhcp6_client *client, DHCP6State state) {
|
|||
dhcp6_state_to_string(client->state), dhcp6_state_to_string(state));
|
||||
|
||||
client->state = state;
|
||||
|
||||
if (client->state_callback)
|
||||
client->state_callback(client, state, client->state_userdata);
|
||||
}
|
||||
|
||||
int dhcp6_client_get_state(sd_dhcp6_client *client) {
|
||||
assert_return(client, -EINVAL);
|
||||
|
||||
return client->state;
|
||||
}
|
||||
|
||||
static void client_notify(sd_dhcp6_client *client, int event) {
|
||||
|
|
@ -809,9 +820,9 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
assert(client->duid_len > 0);
|
||||
assert(sd_dhcp_duid_is_set(&client->duid));
|
||||
r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_CLIENTID,
|
||||
client->duid_len, &client->duid);
|
||||
client->duid.size, &client->duid.duid);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
@ -824,7 +835,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) {
|
|||
/* RFC 8415 Section 21.9.
|
||||
* A client MUST include an Elapsed Time option in messages to indicate how long the client has
|
||||
* been trying to complete a DHCP message exchange. */
|
||||
elapsed_usec = NM_MIN(usec_sub_unsigned(time_now, client->transaction_start) / USEC_PER_MSEC / 10, (usec_t) UINT16_MAX);
|
||||
elapsed_usec = MIN(usec_sub_unsigned(time_now, client->transaction_start) / USEC_PER_MSEC / 10, (usec_t) UINT16_MAX);
|
||||
elapsed_time = htobe16(elapsed_usec);
|
||||
r = dhcp6_option_append(&buf, &offset, SD_DHCP6_OPTION_ELAPSED_TIME, sizeof(elapsed_time), &elapsed_time);
|
||||
if (r < 0)
|
||||
|
|
@ -1047,12 +1058,20 @@ static int client_enter_bound_state(sd_dhcp6_client *client) {
|
|||
(void) event_source_disable(client->receive_message);
|
||||
(void) event_source_disable(client->timeout_resend);
|
||||
|
||||
r = dhcp6_lease_get_lifetime(client->lease, &lifetime_t1, &lifetime_t2, &lifetime_valid);
|
||||
r = sd_dhcp6_lease_get_t1(client->lease, &lifetime_t1);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_dhcp6_lease_get_t2(client->lease, &lifetime_t2);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
r = sd_dhcp6_lease_get_valid_lifetime(client->lease, &lifetime_valid);
|
||||
if (r < 0)
|
||||
goto error;
|
||||
|
||||
lifetime_t2 = client_timeout_compute_random(lifetime_t2);
|
||||
lifetime_t1 = client_timeout_compute_random(NM_MIN(lifetime_t1, lifetime_t2));
|
||||
lifetime_t1 = client_timeout_compute_random(MIN(lifetime_t1, lifetime_t2));
|
||||
|
||||
if (lifetime_t1 == USEC_INFINITY) {
|
||||
log_dhcp6_client(client, "Infinite T1");
|
||||
|
|
@ -1286,16 +1305,15 @@ static int client_receive_message(
|
|||
.msg_control = &control,
|
||||
.msg_controllen = sizeof(control),
|
||||
};
|
||||
triple_timestamp t = {};
|
||||
triple_timestamp t;
|
||||
_cleanup_free_ DHCP6Message *message = NULL;
|
||||
struct in6_addr *server_address = NULL;
|
||||
ssize_t buflen, len;
|
||||
|
||||
buflen = next_datagram_size_fd(fd);
|
||||
if (ERRNO_IS_NEG_TRANSIENT(buflen) || ERRNO_IS_NEG_DISCONNECT(buflen))
|
||||
return 0;
|
||||
if (buflen < 0) {
|
||||
if (ERRNO_IS_TRANSIENT(buflen) || ERRNO_IS_DISCONNECT(buflen))
|
||||
return 0;
|
||||
|
||||
log_dhcp6_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1307,10 +1325,9 @@ static int client_receive_message(
|
|||
iov = IOVEC_MAKE(message, buflen);
|
||||
|
||||
len = recvmsg_safe(fd, &msg, MSG_DONTWAIT);
|
||||
if (ERRNO_IS_NEG_TRANSIENT(len) || ERRNO_IS_NEG_DISCONNECT(len))
|
||||
return 0;
|
||||
if (len < 0) {
|
||||
if (ERRNO_IS_TRANSIENT(len) || ERRNO_IS_DISCONNECT(len))
|
||||
return 0;
|
||||
|
||||
log_dhcp6_client_errno(client, len, "Could not receive message from UDP socket, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1329,9 +1346,7 @@ static int client_receive_message(
|
|||
server_address = &sa.in6.sin6_addr;
|
||||
}
|
||||
|
||||
struct timeval *tv = CMSG_FIND_AND_COPY_DATA(&msg, SOL_SOCKET, SCM_TIMESTAMP, struct timeval);
|
||||
if (tv)
|
||||
triple_timestamp_from_realtime(&t, timeval_load(tv));
|
||||
triple_timestamp_from_cmsg(&t, &msg);
|
||||
|
||||
if (client->transaction_id != (message->transaction_id & htobe32(0x00ffffff)))
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,9 @@
|
|||
#include "alloc-util.h"
|
||||
#include "dhcp6-internal.h"
|
||||
#include "dhcp6-lease-internal.h"
|
||||
#include "network-common.h"
|
||||
#include "strv.h"
|
||||
#include "unaligned.h"
|
||||
|
||||
#define IRT_DEFAULT (1 * USEC_PER_DAY)
|
||||
#define IRT_MINIMUM (600 * USEC_PER_SEC)
|
||||
|
|
@ -21,7 +23,7 @@ static void dhcp6_lease_set_timestamp(sd_dhcp6_lease *lease, const triple_timest
|
|||
if (timestamp && triple_timestamp_is_set(timestamp))
|
||||
lease->timestamp = *timestamp;
|
||||
else
|
||||
triple_timestamp_get(&lease->timestamp);
|
||||
triple_timestamp_now(&lease->timestamp);
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret) {
|
||||
|
|
@ -37,30 +39,26 @@ int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_
|
|||
return 0;
|
||||
}
|
||||
|
||||
static usec_t sec2usec(uint32_t sec) {
|
||||
return sec == UINT32_MAX ? USEC_INFINITY : sec * USEC_PER_SEC;
|
||||
}
|
||||
|
||||
static void dhcp6_lease_set_lifetime(sd_dhcp6_lease *lease) {
|
||||
uint32_t t1 = UINT32_MAX, t2 = UINT32_MAX, min_valid_lt = UINT32_MAX;
|
||||
usec_t t1 = USEC_INFINITY, t2 = USEC_INFINITY, min_valid_lt = USEC_INFINITY;
|
||||
|
||||
assert(lease);
|
||||
assert(lease->ia_na || lease->ia_pd);
|
||||
|
||||
if (lease->ia_na) {
|
||||
t1 = MIN(t1, be32toh(lease->ia_na->header.lifetime_t1));
|
||||
t2 = MIN(t2, be32toh(lease->ia_na->header.lifetime_t2));
|
||||
t1 = MIN(t1, be32_sec_to_usec(lease->ia_na->header.lifetime_t1, /* max_as_infinity = */ true));
|
||||
t2 = MIN(t2, be32_sec_to_usec(lease->ia_na->header.lifetime_t2, /* max_as_infinity = */ true));
|
||||
|
||||
LIST_FOREACH(addresses, a, lease->ia_na->addresses)
|
||||
min_valid_lt = MIN(min_valid_lt, be32toh(a->iaaddr.lifetime_valid));
|
||||
min_valid_lt = MIN(min_valid_lt, be32_sec_to_usec(a->iaaddr.lifetime_valid, /* max_as_infinity = */ true));
|
||||
}
|
||||
|
||||
if (lease->ia_pd) {
|
||||
t1 = MIN(t1, be32toh(lease->ia_pd->header.lifetime_t1));
|
||||
t2 = MIN(t2, be32toh(lease->ia_pd->header.lifetime_t2));
|
||||
t1 = MIN(t1, be32_sec_to_usec(lease->ia_pd->header.lifetime_t1, /* max_as_infinity = */ true));
|
||||
t2 = MIN(t2, be32_sec_to_usec(lease->ia_pd->header.lifetime_t2, /* max_as_infinity = */ true));
|
||||
|
||||
LIST_FOREACH(addresses, a, lease->ia_pd->addresses)
|
||||
min_valid_lt = MIN(min_valid_lt, be32toh(a->iapdprefix.lifetime_valid));
|
||||
min_valid_lt = MIN(min_valid_lt, be32_sec_to_usec(a->iapdprefix.lifetime_valid, /* max_as_infinity = */ true));
|
||||
}
|
||||
|
||||
if (t2 == 0 || t2 > min_valid_lt) {
|
||||
|
|
@ -70,25 +68,52 @@ static void dhcp6_lease_set_lifetime(sd_dhcp6_lease *lease) {
|
|||
t2 = min_valid_lt / 10 * 8;
|
||||
}
|
||||
|
||||
lease->lifetime_valid = sec2usec(min_valid_lt);
|
||||
lease->lifetime_t1 = sec2usec(t1);
|
||||
lease->lifetime_t2 = sec2usec(t2);
|
||||
lease->lifetime_valid = min_valid_lt;
|
||||
lease->lifetime_t1 = t1;
|
||||
lease->lifetime_t2 = t2;
|
||||
}
|
||||
|
||||
int dhcp6_lease_get_lifetime(sd_dhcp6_lease *lease, usec_t *ret_t1, usec_t *ret_t2, usec_t *ret_valid) {
|
||||
assert(lease);
|
||||
#define DEFINE_GET_TIME_FUNCTIONS(name, val) \
|
||||
int sd_dhcp6_lease_get_##name( \
|
||||
sd_dhcp6_lease *lease, \
|
||||
uint64_t *ret) { \
|
||||
\
|
||||
assert_return(lease, -EINVAL); \
|
||||
\
|
||||
if (!lease->ia_na && !lease->ia_pd) \
|
||||
return -ENODATA; \
|
||||
\
|
||||
if (ret) \
|
||||
*ret = lease->val; \
|
||||
return 0; \
|
||||
} \
|
||||
\
|
||||
int sd_dhcp6_lease_get_##name##_timestamp( \
|
||||
sd_dhcp6_lease *lease, \
|
||||
clockid_t clock, \
|
||||
uint64_t *ret) { \
|
||||
\
|
||||
usec_t s, t; \
|
||||
int r; \
|
||||
\
|
||||
assert_return(lease, -EINVAL); \
|
||||
\
|
||||
r = sd_dhcp6_lease_get_##name(lease, &s); \
|
||||
if (r < 0) \
|
||||
return r; \
|
||||
\
|
||||
r = sd_dhcp6_lease_get_timestamp(lease, clock, &t); \
|
||||
if (r < 0) \
|
||||
return r; \
|
||||
\
|
||||
if (ret) \
|
||||
*ret = time_span_to_stamp(s, t); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
if (!lease->ia_na && !lease->ia_pd)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret_t1)
|
||||
*ret_t1 = lease->lifetime_t1;
|
||||
if (ret_t2)
|
||||
*ret_t2 = lease->lifetime_t2;
|
||||
if (ret_valid)
|
||||
*ret_valid = lease->lifetime_valid;
|
||||
return 0;
|
||||
}
|
||||
DEFINE_GET_TIME_FUNCTIONS(t1, lifetime_t1);
|
||||
DEFINE_GET_TIME_FUNCTIONS(t2, lifetime_t1);
|
||||
DEFINE_GET_TIME_FUNCTIONS(valid_lifetime, lifetime_valid);
|
||||
|
||||
static void dhcp6_lease_set_server_address(sd_dhcp6_lease *lease, const struct in6_addr *server_address) {
|
||||
assert(lease);
|
||||
|
|
@ -218,61 +243,151 @@ int dhcp6_lease_get_rapid_commit(sd_dhcp6_lease *lease, bool *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_address(
|
||||
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease, struct in6_addr *ret) {
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
if (!lease->addr_iter)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret)
|
||||
*ret = lease->addr_iter->iaaddr.address;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_address_lifetime(
|
||||
sd_dhcp6_lease *lease,
|
||||
struct in6_addr *ret_addr,
|
||||
uint32_t *ret_lifetime_preferred,
|
||||
uint32_t *ret_lifetime_valid) {
|
||||
usec_t *ret_lifetime_preferred,
|
||||
usec_t *ret_lifetime_valid) {
|
||||
|
||||
const struct iaaddr *a;
|
||||
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
if (!lease->addr_iter)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret_addr)
|
||||
*ret_addr = lease->addr_iter->iaaddr.address;
|
||||
if (ret_lifetime_preferred)
|
||||
*ret_lifetime_preferred = be32toh(lease->addr_iter->iaaddr.lifetime_preferred);
|
||||
if (ret_lifetime_valid)
|
||||
*ret_lifetime_valid = be32toh(lease->addr_iter->iaaddr.lifetime_valid);
|
||||
a = &lease->addr_iter->iaaddr;
|
||||
|
||||
lease->addr_iter = lease->addr_iter->addresses_next;
|
||||
if (ret_lifetime_preferred)
|
||||
*ret_lifetime_preferred = be32_sec_to_usec(a->lifetime_preferred, /* max_as_infinity = */ true);
|
||||
if (ret_lifetime_valid)
|
||||
*ret_lifetime_valid = be32_sec_to_usec(a->lifetime_valid, /* max_as_infinity = */ true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease) {
|
||||
if (lease)
|
||||
lease->addr_iter = lease->ia_na ? lease->ia_na->addresses : NULL;
|
||||
int sd_dhcp6_lease_address_iterator_reset(sd_dhcp6_lease *lease) {
|
||||
if (!lease)
|
||||
return false;
|
||||
|
||||
lease->addr_iter = lease->ia_na ? lease->ia_na->addresses : NULL;
|
||||
return !!lease->addr_iter;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_pd(
|
||||
int sd_dhcp6_lease_address_iterator_next(sd_dhcp6_lease *lease) {
|
||||
if (!lease || !lease->addr_iter)
|
||||
return false;
|
||||
|
||||
lease->addr_iter = lease->addr_iter->addresses_next;
|
||||
return !!lease->addr_iter;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_has_address(sd_dhcp6_lease *lease) {
|
||||
return lease && lease->ia_na;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_pd_prefix(
|
||||
sd_dhcp6_lease *lease,
|
||||
struct in6_addr *ret_prefix,
|
||||
uint8_t *ret_prefix_len,
|
||||
uint32_t *ret_lifetime_preferred,
|
||||
uint32_t *ret_lifetime_valid) {
|
||||
uint8_t *ret_prefix_len) {
|
||||
|
||||
const struct iapdprefix *a;
|
||||
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
if (!lease->prefix_iter)
|
||||
return -ENODATA;
|
||||
|
||||
if (ret_prefix)
|
||||
*ret_prefix = lease->prefix_iter->iapdprefix.address;
|
||||
if (ret_prefix_len)
|
||||
*ret_prefix_len = lease->prefix_iter->iapdprefix.prefixlen;
|
||||
if (ret_lifetime_preferred)
|
||||
*ret_lifetime_preferred = be32toh(lease->prefix_iter->iapdprefix.lifetime_preferred);
|
||||
if (ret_lifetime_valid)
|
||||
*ret_lifetime_valid = be32toh(lease->prefix_iter->iapdprefix.lifetime_valid);
|
||||
a = &lease->prefix_iter->iapdprefix;
|
||||
|
||||
lease->prefix_iter = lease->prefix_iter->addresses_next;
|
||||
if (ret_prefix)
|
||||
*ret_prefix = a->address;
|
||||
if (ret_prefix_len)
|
||||
*ret_prefix_len = a->prefixlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease) {
|
||||
if (lease)
|
||||
lease->prefix_iter = lease->ia_pd ? lease->ia_pd->addresses : NULL;
|
||||
int sd_dhcp6_lease_get_pd_lifetime(
|
||||
sd_dhcp6_lease *lease,
|
||||
uint64_t *ret_lifetime_preferred,
|
||||
uint64_t *ret_lifetime_valid) {
|
||||
|
||||
const struct iapdprefix *a;
|
||||
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
if (!lease->prefix_iter)
|
||||
return -ENODATA;
|
||||
|
||||
a = &lease->prefix_iter->iapdprefix;
|
||||
|
||||
if (ret_lifetime_preferred)
|
||||
*ret_lifetime_preferred = be32_sec_to_usec(a->lifetime_preferred, /* max_as_infinity = */ true);
|
||||
if (ret_lifetime_valid)
|
||||
*ret_lifetime_valid = be32_sec_to_usec(a->lifetime_valid, /* max_as_infinity = */ true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_pd_iterator_reset(sd_dhcp6_lease *lease) {
|
||||
if (!lease)
|
||||
return false;
|
||||
|
||||
lease->prefix_iter = lease->ia_pd ? lease->ia_pd->addresses : NULL;
|
||||
return !!lease->prefix_iter;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_pd_iterator_next(sd_dhcp6_lease *lease) {
|
||||
if (!lease || !lease->prefix_iter)
|
||||
return false;
|
||||
|
||||
lease->prefix_iter = lease->prefix_iter->addresses_next;
|
||||
return !!lease->prefix_iter;
|
||||
}
|
||||
|
||||
#define DEFINE_GET_TIMESTAMP2(name) \
|
||||
int sd_dhcp6_lease_get_##name##_lifetime_timestamp( \
|
||||
sd_dhcp6_lease *lease, \
|
||||
clockid_t clock, \
|
||||
uint64_t *ret_lifetime_preferred, \
|
||||
uint64_t *ret_lifetime_valid) { \
|
||||
\
|
||||
usec_t t, p, v; \
|
||||
int r; \
|
||||
\
|
||||
assert_return(lease, -EINVAL); \
|
||||
\
|
||||
r = sd_dhcp6_lease_get_##name##_lifetime( \
|
||||
lease, \
|
||||
ret_lifetime_preferred ? &p : NULL, \
|
||||
ret_lifetime_valid ? &v : NULL); \
|
||||
if (r < 0) \
|
||||
return r; \
|
||||
\
|
||||
r = sd_dhcp6_lease_get_timestamp(lease, clock, &t); \
|
||||
if (r < 0) \
|
||||
return r; \
|
||||
\
|
||||
if (ret_lifetime_preferred) \
|
||||
*ret_lifetime_preferred = time_span_to_stamp(p, t); \
|
||||
if (ret_lifetime_valid) \
|
||||
*ret_lifetime_valid = time_span_to_stamp(v, t); \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
DEFINE_GET_TIMESTAMP2(address);
|
||||
DEFINE_GET_TIMESTAMP2(pd);
|
||||
|
||||
int sd_dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease) {
|
||||
return lease && lease->ia_pd;
|
||||
}
|
||||
|
||||
int dhcp6_lease_add_dns(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
|
||||
|
|
@ -447,6 +562,111 @@ int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int dhcp6_lease_set_captive_portal(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
|
||||
_cleanup_free_ char *uri = NULL;
|
||||
int r;
|
||||
|
||||
assert(lease);
|
||||
assert(optval || optlen == 0);
|
||||
|
||||
r = dhcp6_option_parse_string(optval, optlen, &uri);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (uri && !in_charset(uri, URI_VALID))
|
||||
return -EINVAL;
|
||||
|
||||
return free_and_replace(lease->captive_portal, uri);
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_captive_portal(sd_dhcp6_lease *lease, const char **ret) {
|
||||
assert_return(lease, -EINVAL);
|
||||
assert_return(ret, -EINVAL);
|
||||
|
||||
if (!lease->captive_portal)
|
||||
return -ENODATA;
|
||||
|
||||
*ret = lease->captive_portal;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sd_dhcp6_lease_get_vendor_options(sd_dhcp6_lease *lease, sd_dhcp6_option ***ret) {
|
||||
int r;
|
||||
|
||||
assert_return(lease, -EINVAL);
|
||||
|
||||
if (set_isempty(lease->vendor_options))
|
||||
return -ENODATA;
|
||||
|
||||
if (ret) {
|
||||
if (!lease->sorted_vendor_options) {
|
||||
r = set_dump_sorted(lease->vendor_options, (void***) &lease->sorted_vendor_options, NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
*ret = lease->sorted_vendor_options;
|
||||
}
|
||||
|
||||
return set_size(lease->vendor_options);
|
||||
}
|
||||
|
||||
static int dhcp6_lease_insert_vendor_option(
|
||||
sd_dhcp6_lease *lease,
|
||||
uint16_t option_code,
|
||||
const void *data,
|
||||
size_t len,
|
||||
uint32_t enterprise_id) {
|
||||
|
||||
_cleanup_(sd_dhcp6_option_unrefp) sd_dhcp6_option *option = NULL;
|
||||
|
||||
assert(lease);
|
||||
|
||||
option = new(sd_dhcp6_option, 1);
|
||||
if (!option)
|
||||
return -ENOMEM;
|
||||
|
||||
*option = (sd_dhcp6_option) {
|
||||
.n_ref = 1,
|
||||
.enterprise_identifier = enterprise_id,
|
||||
.option = option_code,
|
||||
.length = len,
|
||||
};
|
||||
option->data = memdup_suffix0(data, len);
|
||||
if (!option->data)
|
||||
return -ENOMEM;
|
||||
|
||||
return set_ensure_consume(&lease->vendor_options, &dhcp6_option_hash_ops, TAKE_PTR(option));
|
||||
}
|
||||
|
||||
static int dhcp6_lease_add_vendor_option(sd_dhcp6_lease *lease, const uint8_t *optval, size_t optlen) {
|
||||
int r;
|
||||
uint32_t enterprise_id;
|
||||
|
||||
assert(lease);
|
||||
assert(optval || optlen == 0);
|
||||
|
||||
if (optlen < sizeof(be32_t))
|
||||
return -EBADMSG;
|
||||
|
||||
enterprise_id = unaligned_read_be32(optval);
|
||||
|
||||
for (size_t offset = 4; offset < optlen;) {
|
||||
const uint8_t *subval;
|
||||
size_t sublen;
|
||||
uint16_t subopt;
|
||||
|
||||
r = dhcp6_option_parse(optval, optlen, &offset, &subopt, &sublen, &subval);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = dhcp6_lease_insert_vendor_option(lease, subopt, subval, sublen, enterprise_id);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dhcp6_lease_parse_message(
|
||||
sd_dhcp6_client *client,
|
||||
sd_dhcp6_lease *lease,
|
||||
|
|
@ -467,6 +687,11 @@ static int dhcp6_lease_parse_message(
|
|||
size_t optlen;
|
||||
const uint8_t *optval;
|
||||
|
||||
if (len - offset < offsetof(DHCP6Option, data)) {
|
||||
log_dhcp6_client(client, "Ignoring %zu invalid byte(s) at the end of the packet", len - offset);
|
||||
break;
|
||||
}
|
||||
|
||||
r = dhcp6_option_parse(message->options, len, &offset, &optcode, &optlen, &optval);
|
||||
if (r < 0)
|
||||
return log_dhcp6_client_errno(client, r,
|
||||
|
|
@ -607,6 +832,12 @@ static int dhcp6_lease_parse_message(
|
|||
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_CAPTIVE_PORTAL:
|
||||
r = dhcp6_lease_set_captive_portal(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
log_dhcp6_client_errno(client, r, "Failed to parse captive portal option, ignoring: %m");
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_CLIENT_FQDN:
|
||||
r = dhcp6_lease_set_fqdn(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
|
|
@ -619,7 +850,14 @@ static int dhcp6_lease_parse_message(
|
|||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"Received information refresh time option with an invalid length (%zu).", optlen);
|
||||
|
||||
irt = unaligned_read_be32(optval) * USEC_PER_SEC;
|
||||
irt = unaligned_be32_sec_to_usec(optval, /* max_as_infinity = */ false);
|
||||
break;
|
||||
|
||||
case SD_DHCP6_OPTION_VENDOR_OPTS:
|
||||
r = dhcp6_lease_add_vendor_option(lease, optval, optlen);
|
||||
if (r < 0)
|
||||
log_dhcp6_client_errno(client, r, "Failed to parse vendor option, ignoring: %m");
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -631,7 +869,7 @@ static int dhcp6_lease_parse_message(
|
|||
"%s message does not contain client ID. Ignoring.",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
|
||||
if (memcmp_nn(clientid, clientid_len, &client->duid, client->duid_len) != 0)
|
||||
if (memcmp_nn(clientid, clientid_len, &client->duid.duid, client->duid.size) != 0)
|
||||
return log_dhcp6_client_errno(client, SYNTHETIC_ERRNO(EINVAL),
|
||||
"The client ID in %s message does not match. Ignoring.",
|
||||
dhcp6_message_type_to_string(message->type));
|
||||
|
|
@ -661,12 +899,15 @@ static sd_dhcp6_lease *dhcp6_lease_free(sd_dhcp6_lease *lease) {
|
|||
if (!lease)
|
||||
return NULL;
|
||||
|
||||
set_free(lease->vendor_options);
|
||||
free(lease->sorted_vendor_options);
|
||||
free(lease->clientid);
|
||||
free(lease->serverid);
|
||||
dhcp6_ia_free(lease->ia_na);
|
||||
dhcp6_ia_free(lease->ia_pd);
|
||||
free(lease->dns);
|
||||
free(lease->fqdn);
|
||||
free(lease->captive_portal);
|
||||
strv_free(lease->domains);
|
||||
free(lease->ntp);
|
||||
strv_free(lease->ntp_fqdn);
|
||||
|
|
|
|||
|
|
@ -7,39 +7,41 @@
|
|||
|
||||
#include "sd-device.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "log.h"
|
||||
#include "macro.h"
|
||||
#include "strv.h"
|
||||
|
||||
#define device_unref_and_replace(a, b) \
|
||||
unref_and_replace_full(a, b, sd_device_ref, sd_device_unref)
|
||||
|
||||
#define FOREACH_DEVICE_PROPERTY(device, key, value) \
|
||||
for (key = sd_device_get_property_first(device, &(value)); \
|
||||
key; \
|
||||
key = sd_device_get_property_next(device, &(value)))
|
||||
#define FOREACH_DEVICE_PROPERTY(device, key, value) \
|
||||
for (const char *value, *key = sd_device_get_property_first(device, &value); \
|
||||
key; \
|
||||
key = sd_device_get_property_next(device, &value))
|
||||
|
||||
#define FOREACH_DEVICE_TAG(device, tag) \
|
||||
for (tag = sd_device_get_tag_first(device); \
|
||||
tag; \
|
||||
#define FOREACH_DEVICE_TAG(device, tag) \
|
||||
for (const char *tag = sd_device_get_tag_first(device); \
|
||||
tag; \
|
||||
tag = sd_device_get_tag_next(device))
|
||||
|
||||
#define FOREACH_DEVICE_CURRENT_TAG(device, tag) \
|
||||
for (tag = sd_device_get_current_tag_first(device); \
|
||||
tag; \
|
||||
#define FOREACH_DEVICE_CURRENT_TAG(device, tag) \
|
||||
for (const char *tag = sd_device_get_current_tag_first(device); \
|
||||
tag; \
|
||||
tag = sd_device_get_current_tag_next(device))
|
||||
|
||||
#define FOREACH_DEVICE_SYSATTR(device, attr) \
|
||||
for (attr = sd_device_get_sysattr_first(device); \
|
||||
attr; \
|
||||
#define FOREACH_DEVICE_SYSATTR(device, attr) \
|
||||
for (const char *attr = sd_device_get_sysattr_first(device); \
|
||||
attr; \
|
||||
attr = sd_device_get_sysattr_next(device))
|
||||
|
||||
#define FOREACH_DEVICE_DEVLINK(device, devlink) \
|
||||
for (devlink = sd_device_get_devlink_first(device); \
|
||||
devlink; \
|
||||
#define FOREACH_DEVICE_DEVLINK(device, devlink) \
|
||||
for (const char *devlink = sd_device_get_devlink_first(device); \
|
||||
devlink; \
|
||||
devlink = sd_device_get_devlink_next(device))
|
||||
|
||||
#define _FOREACH_DEVICE_CHILD(device, child, suffix_ptr) \
|
||||
for (child = sd_device_get_child_first(device, suffix_ptr); \
|
||||
for (sd_device *child = sd_device_get_child_first(device, suffix_ptr); \
|
||||
child; \
|
||||
child = sd_device_get_child_next(device, suffix_ptr))
|
||||
|
||||
|
|
@ -49,14 +51,14 @@
|
|||
#define FOREACH_DEVICE_CHILD_WITH_SUFFIX(device, child, suffix) \
|
||||
_FOREACH_DEVICE_CHILD(device, child, &suffix)
|
||||
|
||||
#define FOREACH_DEVICE(enumerator, device) \
|
||||
for (device = sd_device_enumerator_get_device_first(enumerator); \
|
||||
device; \
|
||||
#define FOREACH_DEVICE(enumerator, device) \
|
||||
for (sd_device *device = sd_device_enumerator_get_device_first(enumerator); \
|
||||
device; \
|
||||
device = sd_device_enumerator_get_device_next(enumerator))
|
||||
|
||||
#define FOREACH_SUBSYSTEM(enumerator, device) \
|
||||
for (device = sd_device_enumerator_get_subsystem_first(enumerator); \
|
||||
device; \
|
||||
#define FOREACH_SUBSYSTEM(enumerator, device) \
|
||||
for (sd_device *device = sd_device_enumerator_get_subsystem_first(enumerator); \
|
||||
device; \
|
||||
device = sd_device_enumerator_get_subsystem_next(enumerator))
|
||||
|
||||
#define log_device_full_errno_zerook(device, level, error, ...) \
|
||||
|
|
@ -81,17 +83,17 @@
|
|||
|
||||
#define log_device_full(device, level, ...) (void) log_device_full_errno_zerook(device, level, 0, __VA_ARGS__)
|
||||
|
||||
#define log_device_debug(device, ...) log_device_full(device, LOG_DEBUG, __VA_ARGS__)
|
||||
#define log_device_info(device, ...) log_device_full(device, LOG_INFO, __VA_ARGS__)
|
||||
#define log_device_notice(device, ...) log_device_full(device, LOG_NOTICE, __VA_ARGS__)
|
||||
#define log_device_debug(device, ...) log_device_full(device, LOG_DEBUG, __VA_ARGS__)
|
||||
#define log_device_info(device, ...) log_device_full(device, LOG_INFO, __VA_ARGS__)
|
||||
#define log_device_notice(device, ...) log_device_full(device, LOG_NOTICE, __VA_ARGS__)
|
||||
#define log_device_warning(device, ...) log_device_full(device, LOG_WARNING, __VA_ARGS__)
|
||||
#define log_device_error(device, ...) log_device_full(device, LOG_ERR, __VA_ARGS__)
|
||||
#define log_device_error(device, ...) log_device_full(device, LOG_ERR, __VA_ARGS__)
|
||||
|
||||
#define log_device_debug_errno(device, error, ...) log_device_full_errno(device, LOG_DEBUG, error, __VA_ARGS__)
|
||||
#define log_device_info_errno(device, error, ...) log_device_full_errno(device, LOG_INFO, error, __VA_ARGS__)
|
||||
#define log_device_notice_errno(device, error, ...) log_device_full_errno(device, LOG_NOTICE, error, __VA_ARGS__)
|
||||
#define log_device_debug_errno(device, error, ...) log_device_full_errno(device, LOG_DEBUG, error, __VA_ARGS__)
|
||||
#define log_device_info_errno(device, error, ...) log_device_full_errno(device, LOG_INFO, error, __VA_ARGS__)
|
||||
#define log_device_notice_errno(device, error, ...) log_device_full_errno(device, LOG_NOTICE, error, __VA_ARGS__)
|
||||
#define log_device_warning_errno(device, error, ...) log_device_full_errno(device, LOG_WARNING, error, __VA_ARGS__)
|
||||
#define log_device_error_errno(device, error, ...) log_device_full_errno(device, LOG_ERR, error, __VA_ARGS__)
|
||||
#define log_device_error_errno(device, error, ...) log_device_full_errno(device, LOG_ERR, error, __VA_ARGS__)
|
||||
|
||||
int devname_from_devnum(mode_t mode, dev_t devnum, char **ret);
|
||||
static inline int devname_from_stat_rdev(const struct stat *st, char **ret) {
|
||||
|
|
@ -101,3 +103,13 @@ static inline int devname_from_stat_rdev(const struct stat *st, char **ret) {
|
|||
int device_open_from_devnum(mode_t mode, dev_t devnum, int flags, char **ret);
|
||||
|
||||
char** device_make_log_fields(sd_device *device);
|
||||
|
||||
bool device_in_subsystem(sd_device *device, const char *subsystem);
|
||||
bool device_is_devtype(sd_device *device, const char *devtype);
|
||||
|
||||
static inline bool device_property_can_set(const char *property) {
|
||||
return property &&
|
||||
!STR_IN_SET(property,
|
||||
"ACTION", "DEVLINKS", "DEVNAME", "DEVPATH", "DEVTYPE", "DRIVER",
|
||||
"IFINDEX", "MAJOR", "MINOR", "SEQNUM", "SUBSYSTEM", "TAGS");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -99,16 +99,21 @@ int event_reset_time_relative(
|
|||
const char *description,
|
||||
bool force_reset) {
|
||||
|
||||
usec_t usec_now;
|
||||
int r;
|
||||
|
||||
assert(e);
|
||||
|
||||
r = sd_event_now(e, clock, &usec_now);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "sd-event: Failed to get the current time: %m");
|
||||
if (usec > 0) {
|
||||
usec_t usec_now;
|
||||
|
||||
return event_reset_time(e, s, clock, usec_add(usec_now, usec), accuracy, callback, userdata, priority, description, force_reset);
|
||||
r = sd_event_now(e, clock, &usec_now);
|
||||
if (r < 0)
|
||||
return log_debug_errno(r, "sd-event: Failed to get the current time: %m");
|
||||
|
||||
usec = usec_add(usec_now, usec);
|
||||
}
|
||||
|
||||
return event_reset_time(e, s, clock, usec, accuracy, callback, userdata, priority, description, force_reset);
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
@ -149,4 +154,21 @@ int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handle
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int event_add_child_pidref(
|
||||
sd_event *e,
|
||||
sd_event_source **s,
|
||||
const PidRef *pid,
|
||||
int options,
|
||||
sd_event_child_handler_t callback,
|
||||
void *userdata) {
|
||||
|
||||
if (!pidref_is_set(pid))
|
||||
return -ESRCH;
|
||||
|
||||
if (pid->fd >= 0)
|
||||
return sd_event_add_child_pidfd(e, s, pid->fd, options, callback, userdata);
|
||||
|
||||
return sd_event_add_child(e, s, pid->pid, options, callback, userdata);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@
|
|||
|
||||
#include "sd-event.h"
|
||||
|
||||
#include "pidref.h"
|
||||
|
||||
int event_reset_time(
|
||||
sd_event *e,
|
||||
sd_event_source **s,
|
||||
|
|
@ -32,3 +34,7 @@ static inline int event_source_disable(sd_event_source *s) {
|
|||
}
|
||||
|
||||
int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata);
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int event_add_child_pidref(sd_event *e, sd_event_source **s, const PidRef *pid, int options, sd_event_child_handler_t callback, void *userdata);
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -1169,10 +1169,10 @@ static int source_set_pending(sd_event_source *s, bool b) {
|
|||
assert(s->inotify.inode_data->inotify_data);
|
||||
|
||||
if (b)
|
||||
s->inotify.inode_data->inotify_data->n_pending ++;
|
||||
s->inotify.inode_data->inotify_data->n_pending++;
|
||||
else {
|
||||
assert(s->inotify.inode_data->inotify_data->n_pending > 0);
|
||||
s->inotify.inode_data->inotify_data->n_pending --;
|
||||
s->inotify.inode_data->inotify_data->n_pending--;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1983,7 +1983,7 @@ _public_ int sd_event_add_memory_pressure(
|
|||
|
||||
env = secure_getenv("MEMORY_PRESSURE_WRITE");
|
||||
if (env) {
|
||||
r = unbase64mem(env, SIZE_MAX, &write_buffer, &write_buffer_size);
|
||||
r = unbase64mem(env, &write_buffer, &write_buffer_size);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
|
@ -2239,8 +2239,8 @@ static int inode_data_compare(const struct inode_data *x, const struct inode_dat
|
|||
static void inode_data_hash_func(const struct inode_data *d, struct siphash *state) {
|
||||
assert(d);
|
||||
|
||||
siphash24_compress(&d->dev, sizeof(d->dev), state);
|
||||
siphash24_compress(&d->ino, sizeof(d->ino), state);
|
||||
siphash24_compress_typesafe(d->dev, state);
|
||||
siphash24_compress_typesafe(d->ino, state);
|
||||
}
|
||||
|
||||
DEFINE_PRIVATE_HASH_OPS(inode_data_hash_ops, struct inode_data, inode_data_hash_func, inode_data_compare);
|
||||
|
|
@ -4008,7 +4008,7 @@ static int process_inotify(sd_event *e) {
|
|||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0)
|
||||
done ++;
|
||||
done++;
|
||||
}
|
||||
|
||||
return done;
|
||||
|
|
@ -4620,7 +4620,7 @@ static int process_epoll(sd_event *e, usec_t timeout, int64_t threshold, int64_t
|
|||
|
||||
/* Set timestamp only when this is called first time. */
|
||||
if (threshold == INT64_MAX)
|
||||
triple_timestamp_get(&e->timestamp);
|
||||
triple_timestamp_now(&e->timestamp);
|
||||
|
||||
for (size_t i = 0; i < m; i++) {
|
||||
|
||||
|
|
@ -5047,7 +5047,7 @@ _public_ int sd_event_set_watchdog(sd_event *e, int b) {
|
|||
}
|
||||
}
|
||||
|
||||
e->watchdog = !!b;
|
||||
e->watchdog = b;
|
||||
return e->watchdog;
|
||||
|
||||
fail:
|
||||
|
|
|
|||
|
|
@ -11,9 +11,29 @@
|
|||
#include "hexdecoct.h"
|
||||
#include "id128-util.h"
|
||||
#include "io-util.h"
|
||||
#include "sha256.h"
|
||||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
#include "sync-util.h"
|
||||
#include "virt.h"
|
||||
|
||||
int id128_from_string_nonzero(const char *s, sd_id128_t *ret) {
|
||||
sd_id128_t t;
|
||||
int r;
|
||||
|
||||
assert(ret);
|
||||
|
||||
r = sd_id128_from_string(ASSERT_PTR(s), &t);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (sd_id128_is_null(t))
|
||||
return -ENXIO;
|
||||
|
||||
*ret = t;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
bool id128_is_valid(const char *s) {
|
||||
|
|
@ -24,7 +44,7 @@ bool id128_is_valid(const char *s) {
|
|||
l = strlen(s);
|
||||
|
||||
if (l == SD_ID128_STRING_MAX - 1)
|
||||
/* Plain formatted 128bit hex string */
|
||||
/* Plain formatted 128-bit hex string */
|
||||
return in_charset(s, HEXDIGITS);
|
||||
|
||||
if (l == SD_ID128_UUID_STRING_MAX - 1) {
|
||||
|
|
@ -53,7 +73,7 @@ int id128_read_fd(int fd, Id128Flag f, sd_id128_t *ret) {
|
|||
|
||||
assert(fd >= 0);
|
||||
|
||||
/* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
|
||||
/* Reads an 128-bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
|
||||
* optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
|
||||
* aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
|
||||
* accept".
|
||||
|
|
@ -151,7 +171,7 @@ int id128_write_fd(int fd, Id128Flag f, sd_id128_t id) {
|
|||
}
|
||||
|
||||
buffer[sz - 1] = '\n';
|
||||
r = loop_write(fd, buffer, sz, false);
|
||||
r = loop_write(fd, buffer, sz);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
@ -178,11 +198,11 @@ int id128_write_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t id) {
|
|||
}
|
||||
|
||||
void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
|
||||
siphash24_compress(p, sizeof(sd_id128_t), state);
|
||||
siphash24_compress_typesafe(*p, state);
|
||||
}
|
||||
|
||||
int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
|
||||
return memcmp(a, b, 16);
|
||||
return memcmp(a, b, sizeof(sd_id128_t));
|
||||
}
|
||||
|
||||
sd_id128_t id128_make_v4_uuid(sd_id128_t id) {
|
||||
|
|
@ -210,9 +230,22 @@ int id128_get_product(sd_id128_t *ret) {
|
|||
/* Reads the systems product UUID from DMI or devicetree (where it is located on POWER). This is
|
||||
* particularly relevant in VM environments, where VM managers typically place a VM uuid there. */
|
||||
|
||||
r = id128_read("/sys/class/dmi/id/product_uuid", ID128_FORMAT_UUID, &uuid);
|
||||
if (r == -ENOENT)
|
||||
r = id128_read("/proc/device-tree/vm,uuid", ID128_FORMAT_UUID, &uuid);
|
||||
r = detect_container();
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r > 0) /* Refuse returning this in containers, as this is not a property of our system then, but
|
||||
* of the host */
|
||||
return -ENOENT;
|
||||
|
||||
FOREACH_STRING(i,
|
||||
"/sys/class/dmi/id/product_uuid", /* KVM */
|
||||
"/proc/device-tree/vm,uuid", /* Device tree */
|
||||
"/sys/hypervisor/uuid") { /* Xen */
|
||||
|
||||
r = id128_read(i, ID128_FORMAT_UUID, &uuid);
|
||||
if (r != -ENOENT)
|
||||
break;
|
||||
}
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
|
|
@ -222,4 +255,22 @@ int id128_get_product(sd_id128_t *ret) {
|
|||
*ret = uuid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
sd_id128_t id128_digest(const void *data, size_t size) {
|
||||
assert(data || size == 0);
|
||||
|
||||
/* Hashes a UUID from some arbitrary data */
|
||||
|
||||
if (size == SIZE_MAX)
|
||||
size = strlen(data);
|
||||
|
||||
uint8_t h[SHA256_DIGEST_SIZE];
|
||||
sd_id128_t id;
|
||||
|
||||
/* Take the first half of the SHA256 result */
|
||||
assert_cc(sizeof(h) >= sizeof(id.bytes));
|
||||
memcpy(id.bytes, sha256_direct(data, size, h), sizeof(id.bytes));
|
||||
|
||||
return id128_make_v4_uuid(id);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "sd-id128.h"
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "hash-funcs.h"
|
||||
#include "macro.h"
|
||||
|
||||
|
|
@ -20,6 +21,8 @@ typedef enum Id128Flag {
|
|||
ID128_REFUSE_NULL = 1 << 3, /* Refuse all zero ID with -ENOMEDIUM. */
|
||||
} Id128Flag;
|
||||
|
||||
int id128_from_string_nonzero(const char *s, sd_id128_t *ret);
|
||||
|
||||
int id128_read_fd(int fd, Id128Flag f, sd_id128_t *ret);
|
||||
int id128_read_at(int dir_fd, const char *path, Id128Flag f, sd_id128_t *ret);
|
||||
static inline int id128_read(const char *path, Id128Flag f, sd_id128_t *ret) {
|
||||
|
|
@ -44,9 +47,12 @@ sd_id128_t id128_make_v4_uuid(sd_id128_t id);
|
|||
|
||||
int id128_get_product(sd_id128_t *ret);
|
||||
|
||||
sd_id128_t id128_digest(const void *data, size_t size);
|
||||
|
||||
/* A helper to check for the three relevant cases of "machine ID not initialized" */
|
||||
#define ERRNO_IS_MACHINE_ID_UNSET(r) \
|
||||
IN_SET(abs(r), \
|
||||
ENOENT, \
|
||||
ENOMEDIUM, \
|
||||
ENOPKG)
|
||||
#define ERRNO_IS_NEG_MACHINE_ID_UNSET(r) \
|
||||
IN_SET(r, \
|
||||
-ENOENT, \
|
||||
-ENOMEDIUM, \
|
||||
-ENOPKG)
|
||||
_DEFINE_ABS_WRAPPER(MACHINE_ID_UNSET);
|
||||
|
|
|
|||
|
|
@ -345,18 +345,20 @@ _public_ int sd_id128_randomize(sd_id128_t *ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) {
|
||||
uint8_t hmac[SHA256_DIGEST_SIZE];
|
||||
sd_id128_t result;
|
||||
_public_ int sd_id128_get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret) {
|
||||
assert_cc(sizeof(sd_id128_t) < SHA256_DIGEST_SIZE); /* Check that we don't need to pad with zeros. */
|
||||
union {
|
||||
uint8_t hmac[SHA256_DIGEST_SIZE];
|
||||
sd_id128_t result;
|
||||
} buf;
|
||||
|
||||
assert(ret);
|
||||
assert_return(ret, -EINVAL);
|
||||
assert_return(!sd_id128_is_null(app_id), -ENXIO);
|
||||
|
||||
hmac_sha256(&base, sizeof(base), &app_id, sizeof(app_id), hmac);
|
||||
hmac_sha256(&base, sizeof(base), &app_id, sizeof(app_id), buf.hmac);
|
||||
|
||||
/* Take only the first half. */
|
||||
memcpy(&result, hmac, MIN(sizeof(hmac), sizeof(result)));
|
||||
|
||||
*ret = id128_make_v4_uuid(result);
|
||||
*ret = id128_make_v4_uuid(buf.result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -370,7 +372,7 @@ _public_ int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *re
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return get_app_specific(id, app_id, ret);
|
||||
return sd_id128_get_app_specific(id, app_id, ret);
|
||||
}
|
||||
|
||||
_public_ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret) {
|
||||
|
|
@ -383,6 +385,6 @@ _public_ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret)
|
|||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return get_app_specific(id, app_id, ret);
|
||||
return sd_id128_get_app_specific(id, app_id, ret);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ typedef void (*_sd_destroy_t)(void *userdata);
|
|||
} \
|
||||
struct _sd_useless_struct_to_allow_trailing_semicolon_
|
||||
|
||||
/* The following macro should be used in all public enums, to force 64bit wideness on them, so that we can
|
||||
/* The following macro should be used in all public enums, to force 64-bit wideness on them, so that we can
|
||||
* freely extend them later on, without breaking compatibility. */
|
||||
#define _SD_ENUM_FORCE_S64(id) \
|
||||
_SD_##id##_INT64_MIN = INT64_MIN, \
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ sd_device *sd_device_enumerator_get_subsystem_next(sd_device_enumerator *enumera
|
|||
int sd_device_enumerator_add_match_subsystem(sd_device_enumerator *enumerator, const char *subsystem, int match);
|
||||
int sd_device_enumerator_add_match_sysattr(sd_device_enumerator *enumerator, const char *sysattr, const char *value, int match);
|
||||
int sd_device_enumerator_add_match_property(sd_device_enumerator *enumerator, const char *property, const char *value);
|
||||
int sd_device_enumerator_add_match_property_required(sd_device_enumerator *enumerator, const char *property, const char *value);
|
||||
int sd_device_enumerator_add_match_sysname(sd_device_enumerator *enumerator, const char *sysname);
|
||||
int sd_device_enumerator_add_nomatch_sysname(sd_device_enumerator *enumerator, const char *sysname);
|
||||
int sd_device_enumerator_add_match_tag(sd_device_enumerator *enumerator, const char *tag);
|
||||
|
|
|
|||
71
src/libnm-systemd-core/src/systemd/sd-dhcp-duid.h
Normal file
71
src/libnm-systemd-core/src/systemd/sd-dhcp-duid.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddhcpduidhfoo
|
||||
#define foosddhcpduidhfoo
|
||||
|
||||
/***
|
||||
Copyright © 2013 Intel Corporation. All rights reserved.
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
enum {
|
||||
SD_DUID_TYPE_LLT = 1,
|
||||
SD_DUID_TYPE_EN = 2,
|
||||
SD_DUID_TYPE_LL = 3,
|
||||
SD_DUID_TYPE_UUID = 4
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp_duid sd_dhcp_duid;
|
||||
|
||||
int sd_dhcp_duid_clear(sd_dhcp_duid *duid);
|
||||
|
||||
int sd_dhcp_duid_is_set(const sd_dhcp_duid *duid);
|
||||
|
||||
int sd_dhcp_duid_get(const sd_dhcp_duid *duid, uint16_t *ret_type, const void **ret_data, size_t *ret_size);
|
||||
int sd_dhcp_duid_get_raw(const sd_dhcp_duid *duid, const void **ret_data, size_t *ret_size);
|
||||
|
||||
int sd_dhcp_duid_set(
|
||||
sd_dhcp_duid *duid,
|
||||
uint16_t duid_type,
|
||||
const void *data,
|
||||
size_t data_size);
|
||||
int sd_dhcp_duid_set_raw(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *data,
|
||||
size_t data_size);
|
||||
int sd_dhcp_duid_set_llt(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *hw_addr,
|
||||
size_t hw_addr_size,
|
||||
uint16_t arp_type,
|
||||
uint64_t usec);
|
||||
int sd_dhcp_duid_set_ll(
|
||||
sd_dhcp_duid *duid,
|
||||
const void *hw_addr,
|
||||
size_t hw_addr_size,
|
||||
uint16_t arp_type);
|
||||
int sd_dhcp_duid_set_en(sd_dhcp_duid *duid);
|
||||
int sd_dhcp_duid_set_uuid(sd_dhcp_duid *duid);
|
||||
|
||||
int sd_dhcp_duid_to_string(const sd_dhcp_duid *duid, char **ret);
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include "sd-device.h"
|
||||
#include "sd-dhcp-duid.h"
|
||||
#include "sd-dhcp6-lease.h"
|
||||
#include "sd-dhcp6-option.h"
|
||||
#include "sd-event.h"
|
||||
|
|
@ -40,154 +41,6 @@ enum {
|
|||
SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13
|
||||
};
|
||||
|
||||
/* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */
|
||||
enum {
|
||||
SD_DHCP6_OPTION_CLIENTID = 1, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_SERVERID = 2, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_IA_NA = 3, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_IA_TA = 4, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_IAADDR = 5, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_ORO = 6, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_PREFERENCE = 7, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_ELAPSED_TIME = 8, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RELAY_MSG = 9, /* RFC 8415 */
|
||||
/* option code 10 is unassigned */
|
||||
SD_DHCP6_OPTION_AUTH = 11, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_UNICAST = 12, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_STATUS_CODE = 13, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RAPID_COMMIT = 14, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_USER_CLASS = 15, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_VENDOR_CLASS = 16, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_VENDOR_OPTS = 17, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_INTERFACE_ID = 18, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RECONF_MSG = 19, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RECONF_ACCEPT = 20, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME = 21, /* RFC 3319 */
|
||||
SD_DHCP6_OPTION_SIP_SERVER_ADDRESS = 22, /* RFC 3319 */
|
||||
SD_DHCP6_OPTION_DNS_SERVER = 23, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_DOMAIN = 24, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, RFC 8415 */
|
||||
SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, RFC 8415 */
|
||||
SD_DHCP6_OPTION_NIS_SERVER = 27, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NISP_SERVER = 28, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NIS_DOMAIN_NAME = 29, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NISP_DOMAIN_NAME = 30, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_SNTP_SERVER = 31, /* RFC 4075, deprecated */
|
||||
SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 4242, 8415, sec. 21.23 */
|
||||
SD_DHCP6_OPTION_BCMCS_SERVER_D = 33, /* RFC 4280 */
|
||||
SD_DHCP6_OPTION_BCMCS_SERVER_A = 34, /* RFC 4280 */
|
||||
/* option code 35 is unassigned */
|
||||
SD_DHCP6_OPTION_GEOCONF_CIVIC = 36, /* RFC 4776 */
|
||||
SD_DHCP6_OPTION_REMOTE_ID = 37, /* RFC 4649 */
|
||||
SD_DHCP6_OPTION_SUBSCRIBER_ID = 38, /* RFC 4580 */
|
||||
SD_DHCP6_OPTION_CLIENT_FQDN = 39, /* RFC 4704 */
|
||||
SD_DHCP6_OPTION_PANA_AGENT = 40, /* RFC 5192 */
|
||||
SD_DHCP6_OPTION_POSIX_TIMEZONE = 41, /* RFC 4833 */
|
||||
SD_DHCP6_OPTION_TZDB_TIMEZONE = 42, /* RFC 4833 */
|
||||
SD_DHCP6_OPTION_ERO = 43, /* RFC 4994 */
|
||||
SD_DHCP6_OPTION_LQ_QUERY = 44, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_CLIENT_DATA = 45, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_CLT_TIME = 46, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_LQ_RELAY_DATA = 47, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_LQ_CLIENT_LINK = 48, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_MIP6_HNIDF = 49, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_VDINF = 50, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_V6_LOST = 51, /* RFC 5223 */
|
||||
SD_DHCP6_OPTION_CAPWAP_AC_V6 = 52, /* RFC 5417 */
|
||||
SD_DHCP6_OPTION_RELAY_ID = 53, /* RFC 5460 */
|
||||
SD_DHCP6_OPTION_IPV6_ADDRESS_MOS = 54, /* RFC 5678 */
|
||||
SD_DHCP6_OPTION_IPV6_FQDN_MOS = 55, /* RFC 5678 */
|
||||
SD_DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */
|
||||
SD_DHCP6_OPTION_V6_ACCESS_DOMAIN = 57, /* RFC 5986 */
|
||||
SD_DHCP6_OPTION_SIP_UA_CS_LIST = 58, /* RFC 6011 */
|
||||
SD_DHCP6_OPTION_BOOTFILE_URL = 59, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_BOOTFILE_PARAM = 60, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_CLIENT_ARCH_TYPE = 61, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_NII = 62, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_GEOLOCATION = 63, /* RFC 6225 */
|
||||
SD_DHCP6_OPTION_AFTR_NAME = 64, /* RFC 6334 */
|
||||
SD_DHCP6_OPTION_ERP_LOCAL_DOMAIN_NAME = 65, /* RFC 6440 */
|
||||
SD_DHCP6_OPTION_RSOO = 66, /* RFC 6422 */
|
||||
SD_DHCP6_OPTION_PD_EXCLUDE = 67, /* RFC 6603 */
|
||||
SD_DHCP6_OPTION_VSS = 68, /* RFC 6607 */
|
||||
SD_DHCP6_OPTION_MIP6_IDINF = 69, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_UDINF = 70, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_HNP = 71, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_HAA = 72, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_HAF = 73, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_RDNSS_SELECTION = 74, /* RFC 6731 */
|
||||
SD_DHCP6_OPTION_KRB_PRINCIPAL_NAME = 75, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_KRB_REALM_NAME = 76, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_KRB_DEFAULT_REALM_NAME = 77, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_KRB_KDC = 78, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_CLIENT_LINKLAYER_ADDR = 79, /* RFC 6939 */
|
||||
SD_DHCP6_OPTION_LINK_ADDRESS = 80, /* RFC 6977 */
|
||||
SD_DHCP6_OPTION_RADIUS = 81, /* RFC 7037 */
|
||||
SD_DHCP6_OPTION_SOL_MAX_RT = 82, /* RFC 7083, RFC 8415 */
|
||||
SD_DHCP6_OPTION_INF_MAX_RT = 83, /* RFC 7083, RFC 8415 */
|
||||
SD_DHCP6_OPTION_ADDRSEL = 84, /* RFC 7078 */
|
||||
SD_DHCP6_OPTION_ADDRSEL_TABLE = 85, /* RFC 7078 */
|
||||
SD_DHCP6_OPTION_V6_PCP_SERVER = 86, /* RFC 7291 */
|
||||
SD_DHCP6_OPTION_DHCPV4_MSG = 87, /* RFC 7341 */
|
||||
SD_DHCP6_OPTION_DHCP4_O_DHCP6_SERVER = 88, /* RFC 7341 */
|
||||
SD_DHCP6_OPTION_S46_RULE = 89, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_BR = 90, /* RFC 7598, RFC 8539 */
|
||||
SD_DHCP6_OPTION_S46_DMR = 91, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_V4V6BIND = 92, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_PORTPARAMS = 93, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_CONT_MAPE = 94, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_CONT_MAPT = 95, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_CONT_LW = 96, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_4RD = 97, /* RFC 7600 */
|
||||
SD_DHCP6_OPTION_4RD_MAP_RULE = 98, /* RFC 7600 */
|
||||
SD_DHCP6_OPTION_4RD_NON_MAP_RULE = 99, /* RFC 7600 */
|
||||
SD_DHCP6_OPTION_LQ_BASE_TIME = 100, /* RFC 7653 */
|
||||
SD_DHCP6_OPTION_LQ_START_TIME = 101, /* RFC 7653 */
|
||||
SD_DHCP6_OPTION_LQ_END_TIME = 102, /* RFC 7653 */
|
||||
SD_DHCP6_OPTION_CAPTIVE_PORTAL = 103, /* RFC 8910 */
|
||||
SD_DHCP6_OPTION_MPL_PARAMETERS = 104, /* RFC 7774 */
|
||||
SD_DHCP6_OPTION_ANI_ATT = 105, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_NETWORK_NAME = 106, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_AP_NAME = 107, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_AP_BSSID = 108, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_OPERATOR_ID = 109, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_OPERATOR_REALM = 110, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_S46_PRIORITY = 111, /* RFC 8026 */
|
||||
SD_DHCP6_OPTION_MUD_URL_V6 = 112, /* RFC 8520 */
|
||||
SD_DHCP6_OPTION_V6_PREFIX64 = 113, /* RFC 8115 */
|
||||
SD_DHCP6_OPTION_F_BINDING_STATUS = 114, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_CONNECT_FLAGS = 115, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_REMOVAL_INFO = 116, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_HOST_NAME = 117, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_ZONE_NAME = 118, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_FLAGS = 119, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_EXPIRATION_TIME = 120, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_MAX_UNACKED_BNDUPD = 121, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_MCLT = 122, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_LIFETIME = 123, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_LIFETIME_SENT = 124, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_DOWN_TIME = 125, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_RAW_CLT_TIME = 126, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PROTOCOL_VERSION = 127, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_KEEPALIVE_TIME = 128, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_RECONFIGURE_DATA = 129, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_RELATIONSHIP_NAME = 130, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_SERVER_FLAGS = 131, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_SERVER_STATE = 132, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_START_TIME_OF_STATE = 133, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_STATE_EXPIRATION_TIME = 134, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_RELAY_PORT = 135, /* RFC 8357 */
|
||||
SD_DHCP6_OPTION_V6_SZTP_REDIRECT = 136, /* RFC 8572 */
|
||||
SD_DHCP6_OPTION_S46_BIND_IPV6_PREFIX = 137, /* RFC 8539 */
|
||||
SD_DHCP6_OPTION_IA_LL = 138, /* RFC 8947 */
|
||||
SD_DHCP6_OPTION_LLADDR = 139, /* RFC 8947 */
|
||||
SD_DHCP6_OPTION_SLAP_QUAD = 140, /* RFC 8948 */
|
||||
SD_DHCP6_OPTION_V6_DOTS_RI = 141, /* RFC 8973 */
|
||||
SD_DHCP6_OPTION_V6_DOTS_ADDRESS = 142, /* RFC 8973 */
|
||||
SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143 /* RFC 6153 */
|
||||
/* option codes 144-65535 are unassigned */
|
||||
};
|
||||
|
||||
typedef struct sd_dhcp6_client sd_dhcp6_client;
|
||||
|
||||
typedef void (*sd_dhcp6_client_callback_t)(sd_dhcp6_client *client, int event, void *userdata);
|
||||
|
|
@ -211,23 +64,20 @@ int sd_dhcp6_client_set_mac(
|
|||
const uint8_t *addr,
|
||||
size_t addr_len,
|
||||
uint16_t arp_type);
|
||||
int sd_dhcp6_client_set_duid(
|
||||
sd_dhcp6_client *client,
|
||||
uint16_t duid_type,
|
||||
const void *duid,
|
||||
size_t duid_len);
|
||||
int sd_dhcp6_client_set_duid_llt(
|
||||
sd_dhcp6_client *client,
|
||||
uint64_t llt_time);
|
||||
int sd_dhcp6_client_set_duid_llt(sd_dhcp6_client *client, uint64_t llt_time);
|
||||
int sd_dhcp6_client_set_duid_ll(sd_dhcp6_client *client);
|
||||
int sd_dhcp6_client_set_duid_en(sd_dhcp6_client *client);
|
||||
int sd_dhcp6_client_set_duid_uuid(sd_dhcp6_client *client);
|
||||
int sd_dhcp6_client_set_duid_raw(sd_dhcp6_client *client, uint16_t duid_type, const uint8_t *duid, size_t duid_len);
|
||||
int sd_dhcp6_client_set_duid(sd_dhcp6_client *client, const sd_dhcp_duid *duid);
|
||||
int sd_dhcp6_client_get_duid(sd_dhcp6_client *client, const sd_dhcp_duid **ret);
|
||||
int sd_dhcp6_client_get_duid_as_string(sd_dhcp6_client *client, char **ret);
|
||||
int sd_dhcp6_client_set_iaid(
|
||||
sd_dhcp6_client *client,
|
||||
uint32_t iaid);
|
||||
int sd_dhcp6_client_get_iaid(
|
||||
sd_dhcp6_client *client,
|
||||
uint32_t *iaid);
|
||||
int sd_dhcp6_client_duid_as_string(
|
||||
sd_dhcp6_client *client,
|
||||
char **duid);
|
||||
int sd_dhcp6_client_set_fqdn(
|
||||
sd_dhcp6_client *client,
|
||||
const char *fqdn);
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@
|
|||
#include <netinet/in.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-dhcp6-option.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
|
@ -30,24 +32,54 @@ _SD_BEGIN_DECLARATIONS;
|
|||
typedef struct sd_dhcp6_lease sd_dhcp6_lease;
|
||||
|
||||
int sd_dhcp6_lease_get_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret);
|
||||
int sd_dhcp6_lease_get_t1(sd_dhcp6_lease *lease, uint64_t *ret);
|
||||
int sd_dhcp6_lease_get_t1_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret);
|
||||
int sd_dhcp6_lease_get_t2(sd_dhcp6_lease *lease, uint64_t *ret);
|
||||
int sd_dhcp6_lease_get_t2_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret);
|
||||
int sd_dhcp6_lease_get_valid_lifetime(sd_dhcp6_lease *lease, uint64_t *ret);
|
||||
int sd_dhcp6_lease_get_valid_lifetime_timestamp(sd_dhcp6_lease *lease, clockid_t clock, uint64_t *ret);
|
||||
int sd_dhcp6_lease_get_server_address(sd_dhcp6_lease *lease, struct in6_addr *ret);
|
||||
|
||||
void sd_dhcp6_lease_reset_address_iter(sd_dhcp6_lease *lease);
|
||||
int sd_dhcp6_lease_get_address(sd_dhcp6_lease *lease,
|
||||
struct in6_addr *addr,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid);
|
||||
void sd_dhcp6_lease_reset_pd_prefix_iter(sd_dhcp6_lease *lease);
|
||||
int sd_dhcp6_lease_get_pd(sd_dhcp6_lease *lease, struct in6_addr *prefix,
|
||||
uint8_t *prefix_len,
|
||||
uint32_t *lifetime_preferred,
|
||||
uint32_t *lifetime_valid);
|
||||
int sd_dhcp6_lease_address_iterator_reset(sd_dhcp6_lease *lease);
|
||||
int sd_dhcp6_lease_address_iterator_next(sd_dhcp6_lease *lease);
|
||||
int sd_dhcp6_lease_get_address(
|
||||
sd_dhcp6_lease *lease,
|
||||
struct in6_addr *ret);
|
||||
int sd_dhcp6_lease_get_address_lifetime(
|
||||
sd_dhcp6_lease *lease,
|
||||
uint64_t *ret_lifetime_preferred,
|
||||
uint64_t *ret_lifetime_valid);
|
||||
int sd_dhcp6_lease_get_address_lifetime_timestamp(
|
||||
sd_dhcp6_lease *lease,
|
||||
clockid_t clock,
|
||||
uint64_t *ret_lifetime_preferred,
|
||||
uint64_t *ret_lifetime_valid);
|
||||
int sd_dhcp6_lease_has_address(sd_dhcp6_lease *lease);
|
||||
|
||||
int sd_dhcp6_lease_pd_iterator_reset(sd_dhcp6_lease *lease);
|
||||
int sd_dhcp6_lease_pd_iterator_next(sd_dhcp6_lease *lease);
|
||||
int sd_dhcp6_lease_get_pd_prefix(
|
||||
sd_dhcp6_lease *lease,
|
||||
struct in6_addr *ret_prefix,
|
||||
uint8_t *ret_prefix_length);
|
||||
int sd_dhcp6_lease_get_pd_lifetime(
|
||||
sd_dhcp6_lease *lease,
|
||||
uint64_t *ret_lifetime_preferred,
|
||||
uint64_t *ret_lifetime_valid);
|
||||
int sd_dhcp6_lease_get_pd_lifetime_timestamp(
|
||||
sd_dhcp6_lease *lease,
|
||||
clockid_t clock,
|
||||
uint64_t *ret_lifetime_preferred,
|
||||
uint64_t *ret_lifetime_valid);
|
||||
int sd_dhcp6_lease_has_pd_prefix(sd_dhcp6_lease *lease);
|
||||
|
||||
int sd_dhcp6_lease_get_dns(sd_dhcp6_lease *lease, const struct in6_addr **ret);
|
||||
int sd_dhcp6_lease_get_domains(sd_dhcp6_lease *lease, char ***ret);
|
||||
int sd_dhcp6_lease_get_ntp_addrs(sd_dhcp6_lease *lease, const struct in6_addr **ret);
|
||||
int sd_dhcp6_lease_get_ntp_fqdn(sd_dhcp6_lease *lease, char ***ret);
|
||||
int sd_dhcp6_lease_get_fqdn(sd_dhcp6_lease *lease, const char **ret);
|
||||
int sd_dhcp6_lease_get_captive_portal(sd_dhcp6_lease *lease, const char **ret);
|
||||
int sd_dhcp6_lease_get_vendor_options(sd_dhcp6_lease *lease, sd_dhcp6_option ***ret);
|
||||
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_ref(sd_dhcp6_lease *lease);
|
||||
sd_dhcp6_lease *sd_dhcp6_lease_unref(sd_dhcp6_lease *lease);
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@
|
|||
#include <inttypes.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "sd-dhcp6-protocol.h"
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
|
|
|||
174
src/libnm-systemd-core/src/systemd/sd-dhcp6-protocol.h
Normal file
174
src/libnm-systemd-core/src/systemd/sd-dhcp6-protocol.h
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#ifndef foosddhcp6protocolhfoo
|
||||
#define foosddhcp6protocolhfoo
|
||||
|
||||
/***
|
||||
systemd is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 2.1 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
systemd is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with systemd; If not, see <https://www.gnu.org/licenses/>.
|
||||
***/
|
||||
|
||||
#include "_sd-common.h"
|
||||
|
||||
_SD_BEGIN_DECLARATIONS;
|
||||
|
||||
/* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */
|
||||
enum {
|
||||
SD_DHCP6_OPTION_CLIENTID = 1, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_SERVERID = 2, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_IA_NA = 3, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_IA_TA = 4, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_IAADDR = 5, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_ORO = 6, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_PREFERENCE = 7, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_ELAPSED_TIME = 8, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RELAY_MSG = 9, /* RFC 8415 */
|
||||
/* option code 10 is unassigned */
|
||||
SD_DHCP6_OPTION_AUTH = 11, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_UNICAST = 12, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_STATUS_CODE = 13, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RAPID_COMMIT = 14, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_USER_CLASS = 15, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_VENDOR_CLASS = 16, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_VENDOR_OPTS = 17, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_INTERFACE_ID = 18, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RECONF_MSG = 19, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_RECONF_ACCEPT = 20, /* RFC 8415 */
|
||||
SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME = 21, /* RFC 3319 */
|
||||
SD_DHCP6_OPTION_SIP_SERVER_ADDRESS = 22, /* RFC 3319 */
|
||||
SD_DHCP6_OPTION_DNS_SERVER = 23, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_DOMAIN = 24, /* RFC 3646 */
|
||||
SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, RFC 8415 */
|
||||
SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, RFC 8415 */
|
||||
SD_DHCP6_OPTION_NIS_SERVER = 27, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NISP_SERVER = 28, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NIS_DOMAIN_NAME = 29, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_NISP_DOMAIN_NAME = 30, /* RFC 3898 */
|
||||
SD_DHCP6_OPTION_SNTP_SERVER = 31, /* RFC 4075, deprecated */
|
||||
SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 4242, 8415, sec. 21.23 */
|
||||
SD_DHCP6_OPTION_BCMCS_SERVER_D = 33, /* RFC 4280 */
|
||||
SD_DHCP6_OPTION_BCMCS_SERVER_A = 34, /* RFC 4280 */
|
||||
/* option code 35 is unassigned */
|
||||
SD_DHCP6_OPTION_GEOCONF_CIVIC = 36, /* RFC 4776 */
|
||||
SD_DHCP6_OPTION_REMOTE_ID = 37, /* RFC 4649 */
|
||||
SD_DHCP6_OPTION_SUBSCRIBER_ID = 38, /* RFC 4580 */
|
||||
SD_DHCP6_OPTION_CLIENT_FQDN = 39, /* RFC 4704 */
|
||||
SD_DHCP6_OPTION_PANA_AGENT = 40, /* RFC 5192 */
|
||||
SD_DHCP6_OPTION_POSIX_TIMEZONE = 41, /* RFC 4833 */
|
||||
SD_DHCP6_OPTION_TZDB_TIMEZONE = 42, /* RFC 4833 */
|
||||
SD_DHCP6_OPTION_ERO = 43, /* RFC 4994 */
|
||||
SD_DHCP6_OPTION_LQ_QUERY = 44, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_CLIENT_DATA = 45, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_CLT_TIME = 46, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_LQ_RELAY_DATA = 47, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_LQ_CLIENT_LINK = 48, /* RFC 5007 */
|
||||
SD_DHCP6_OPTION_MIP6_HNIDF = 49, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_VDINF = 50, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_V6_LOST = 51, /* RFC 5223 */
|
||||
SD_DHCP6_OPTION_CAPWAP_AC_V6 = 52, /* RFC 5417 */
|
||||
SD_DHCP6_OPTION_RELAY_ID = 53, /* RFC 5460 */
|
||||
SD_DHCP6_OPTION_IPV6_ADDRESS_MOS = 54, /* RFC 5678 */
|
||||
SD_DHCP6_OPTION_IPV6_FQDN_MOS = 55, /* RFC 5678 */
|
||||
SD_DHCP6_OPTION_NTP_SERVER = 56, /* RFC 5908 */
|
||||
SD_DHCP6_OPTION_V6_ACCESS_DOMAIN = 57, /* RFC 5986 */
|
||||
SD_DHCP6_OPTION_SIP_UA_CS_LIST = 58, /* RFC 6011 */
|
||||
SD_DHCP6_OPTION_BOOTFILE_URL = 59, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_BOOTFILE_PARAM = 60, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_CLIENT_ARCH_TYPE = 61, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_NII = 62, /* RFC 5970 */
|
||||
SD_DHCP6_OPTION_GEOLOCATION = 63, /* RFC 6225 */
|
||||
SD_DHCP6_OPTION_AFTR_NAME = 64, /* RFC 6334 */
|
||||
SD_DHCP6_OPTION_ERP_LOCAL_DOMAIN_NAME = 65, /* RFC 6440 */
|
||||
SD_DHCP6_OPTION_RSOO = 66, /* RFC 6422 */
|
||||
SD_DHCP6_OPTION_PD_EXCLUDE = 67, /* RFC 6603 */
|
||||
SD_DHCP6_OPTION_VSS = 68, /* RFC 6607 */
|
||||
SD_DHCP6_OPTION_MIP6_IDINF = 69, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_UDINF = 70, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_HNP = 71, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_HAA = 72, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_MIP6_HAF = 73, /* RFC 6610 */
|
||||
SD_DHCP6_OPTION_RDNSS_SELECTION = 74, /* RFC 6731 */
|
||||
SD_DHCP6_OPTION_KRB_PRINCIPAL_NAME = 75, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_KRB_REALM_NAME = 76, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_KRB_DEFAULT_REALM_NAME = 77, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_KRB_KDC = 78, /* RFC 6784 */
|
||||
SD_DHCP6_OPTION_CLIENT_LINKLAYER_ADDR = 79, /* RFC 6939 */
|
||||
SD_DHCP6_OPTION_LINK_ADDRESS = 80, /* RFC 6977 */
|
||||
SD_DHCP6_OPTION_RADIUS = 81, /* RFC 7037 */
|
||||
SD_DHCP6_OPTION_SOL_MAX_RT = 82, /* RFC 7083, RFC 8415 */
|
||||
SD_DHCP6_OPTION_INF_MAX_RT = 83, /* RFC 7083, RFC 8415 */
|
||||
SD_DHCP6_OPTION_ADDRSEL = 84, /* RFC 7078 */
|
||||
SD_DHCP6_OPTION_ADDRSEL_TABLE = 85, /* RFC 7078 */
|
||||
SD_DHCP6_OPTION_V6_PCP_SERVER = 86, /* RFC 7291 */
|
||||
SD_DHCP6_OPTION_DHCPV4_MSG = 87, /* RFC 7341 */
|
||||
SD_DHCP6_OPTION_DHCP4_O_DHCP6_SERVER = 88, /* RFC 7341 */
|
||||
SD_DHCP6_OPTION_S46_RULE = 89, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_BR = 90, /* RFC 7598, RFC 8539 */
|
||||
SD_DHCP6_OPTION_S46_DMR = 91, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_V4V6BIND = 92, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_PORTPARAMS = 93, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_CONT_MAPE = 94, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_CONT_MAPT = 95, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_S46_CONT_LW = 96, /* RFC 7598 */
|
||||
SD_DHCP6_OPTION_4RD = 97, /* RFC 7600 */
|
||||
SD_DHCP6_OPTION_4RD_MAP_RULE = 98, /* RFC 7600 */
|
||||
SD_DHCP6_OPTION_4RD_NON_MAP_RULE = 99, /* RFC 7600 */
|
||||
SD_DHCP6_OPTION_LQ_BASE_TIME = 100, /* RFC 7653 */
|
||||
SD_DHCP6_OPTION_LQ_START_TIME = 101, /* RFC 7653 */
|
||||
SD_DHCP6_OPTION_LQ_END_TIME = 102, /* RFC 7653 */
|
||||
SD_DHCP6_OPTION_CAPTIVE_PORTAL = 103, /* RFC 8910 */
|
||||
SD_DHCP6_OPTION_MPL_PARAMETERS = 104, /* RFC 7774 */
|
||||
SD_DHCP6_OPTION_ANI_ATT = 105, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_NETWORK_NAME = 106, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_AP_NAME = 107, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_AP_BSSID = 108, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_OPERATOR_ID = 109, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_ANI_OPERATOR_REALM = 110, /* RFC 7839 */
|
||||
SD_DHCP6_OPTION_S46_PRIORITY = 111, /* RFC 8026 */
|
||||
SD_DHCP6_OPTION_MUD_URL_V6 = 112, /* RFC 8520 */
|
||||
SD_DHCP6_OPTION_V6_PREFIX64 = 113, /* RFC 8115 */
|
||||
SD_DHCP6_OPTION_F_BINDING_STATUS = 114, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_CONNECT_FLAGS = 115, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_REMOVAL_INFO = 116, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_HOST_NAME = 117, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_ZONE_NAME = 118, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_DNS_FLAGS = 119, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_EXPIRATION_TIME = 120, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_MAX_UNACKED_BNDUPD = 121, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_MCLT = 122, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_LIFETIME = 123, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_LIFETIME_SENT = 124, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_DOWN_TIME = 125, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PARTNER_RAW_CLT_TIME = 126, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_PROTOCOL_VERSION = 127, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_KEEPALIVE_TIME = 128, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_RECONFIGURE_DATA = 129, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_RELATIONSHIP_NAME = 130, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_SERVER_FLAGS = 131, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_SERVER_STATE = 132, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_START_TIME_OF_STATE = 133, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_F_STATE_EXPIRATION_TIME = 134, /* RFC 8156 */
|
||||
SD_DHCP6_OPTION_RELAY_PORT = 135, /* RFC 8357 */
|
||||
SD_DHCP6_OPTION_V6_SZTP_REDIRECT = 136, /* RFC 8572 */
|
||||
SD_DHCP6_OPTION_S46_BIND_IPV6_PREFIX = 137, /* RFC 8539 */
|
||||
SD_DHCP6_OPTION_IA_LL = 138, /* RFC 8947 */
|
||||
SD_DHCP6_OPTION_LLADDR = 139, /* RFC 8947 */
|
||||
SD_DHCP6_OPTION_SLAP_QUAD = 140, /* RFC 8948 */
|
||||
SD_DHCP6_OPTION_V6_DOTS_RI = 141, /* RFC 8973 */
|
||||
SD_DHCP6_OPTION_V6_DOTS_ADDRESS = 142, /* RFC 8973 */
|
||||
SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143 /* RFC 6153 */
|
||||
/* option codes 144-65535 are unassigned */
|
||||
};
|
||||
|
||||
_SD_END_DECLARATIONS;
|
||||
|
||||
#endif
|
||||
|
|
@ -50,6 +50,7 @@ int sd_id128_get_machine(sd_id128_t *ret);
|
|||
int sd_id128_get_boot(sd_id128_t *ret);
|
||||
int sd_id128_get_invocation(sd_id128_t *ret);
|
||||
|
||||
int sd_id128_get_app_specific(sd_id128_t base, sd_id128_t app_id, sd_id128_t *ret);
|
||||
int sd_id128_get_machine_app_specific(sd_id128_t app_id, sd_id128_t *ret);
|
||||
int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret);
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ enum {
|
|||
SD_NDISC_OPTION_RDNSS = 25,
|
||||
SD_NDISC_OPTION_FLAGS_EXTENSION = 26,
|
||||
SD_NDISC_OPTION_DNSSL = 31,
|
||||
SD_NDISC_OPTION_CAPTIVE_PORTAL = 37
|
||||
SD_NDISC_OPTION_CAPTIVE_PORTAL = 37,
|
||||
SD_NDISC_OPTION_PREF64 = 38
|
||||
};
|
||||
|
||||
/* Route preference, RFC 4191, Section 2.1 */
|
||||
|
|
@ -85,14 +86,17 @@ int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr);
|
|||
sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt);
|
||||
sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt);
|
||||
|
||||
int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr);
|
||||
int sd_ndisc_router_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
|
||||
int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size);
|
||||
int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
|
||||
|
||||
int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret);
|
||||
int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags);
|
||||
int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret);
|
||||
int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime);
|
||||
int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret);
|
||||
|
||||
/* Generic option access */
|
||||
|
|
@ -100,28 +104,42 @@ int sd_ndisc_router_option_rewind(sd_ndisc_router *rt);
|
|||
int sd_ndisc_router_option_next(sd_ndisc_router *rt);
|
||||
int sd_ndisc_router_option_get_type(sd_ndisc_router *rt, uint8_t *ret);
|
||||
int sd_ndisc_router_option_is_type(sd_ndisc_router *rt, uint8_t type);
|
||||
int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size);
|
||||
int sd_ndisc_router_option_get_raw(sd_ndisc_router *rt, const void **ret, size_t *ret_size);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_PREFIX_INFORMATION */
|
||||
int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint32_t *ret);
|
||||
int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint32_t *ret);
|
||||
int sd_ndisc_router_prefix_get_valid_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix_get_valid_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix_get_preferred_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix_get_preferred_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix_get_flags(sd_ndisc_router *rt, uint8_t *ret);
|
||||
int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr);
|
||||
int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen);
|
||||
int sd_ndisc_router_prefix_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
|
||||
int sd_ndisc_router_prefix_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_ROUTE_INFORMATION */
|
||||
int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint32_t *ret);
|
||||
int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret_addr);
|
||||
int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *prefixlen);
|
||||
int sd_ndisc_router_route_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_route_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
int sd_ndisc_router_route_get_address(sd_ndisc_router *rt, struct in6_addr *ret);
|
||||
int sd_ndisc_router_route_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
|
||||
int sd_ndisc_router_route_get_preference(sd_ndisc_router *rt, unsigned *ret);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_RDNSS */
|
||||
int sd_ndisc_router_rdnss_get_addresses(sd_ndisc_router *rt, const struct in6_addr **ret);
|
||||
int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint32_t *ret);
|
||||
int sd_ndisc_router_rdnss_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_rdnss_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_DNSSL */
|
||||
int sd_ndisc_router_dnssl_get_domains(sd_ndisc_router *rt, char ***ret);
|
||||
int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint32_t *ret);
|
||||
int sd_ndisc_router_dnssl_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_dnssl_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_CAPTIVE_PORTAL */
|
||||
int sd_ndisc_router_captive_portal_get_uri(sd_ndisc_router *rt, const char **ret, size_t *ret_size);
|
||||
|
||||
/* Specific option access: SD_NDISC_OPTION_PREF64 */
|
||||
int sd_ndisc_router_prefix64_get_prefix(sd_ndisc_router *rt, struct in6_addr *ret);
|
||||
int sd_ndisc_router_prefix64_get_prefixlen(sd_ndisc_router *rt, unsigned *ret);
|
||||
int sd_ndisc_router_prefix64_get_lifetime(sd_ndisc_router *rt, uint64_t *ret);
|
||||
int sd_ndisc_router_prefix64_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret);
|
||||
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc, sd_ndisc_unref);
|
||||
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ndisc_router, sd_ndisc_router_unref);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ libnm_systemd_shared = static_library(
|
|||
sources: files(
|
||||
'nm-sd-utils-shared.c',
|
||||
'src/basic/alloc-util.c',
|
||||
'src/basic/btrfs.c',
|
||||
'src/basic/env-file.c',
|
||||
'src/basic/env-util.c',
|
||||
'src/basic/escape.c',
|
||||
|
|
@ -58,6 +59,7 @@ libnm_systemd_shared = static_library(
|
|||
top_inc,
|
||||
src_inc,
|
||||
],
|
||||
c_args: libnm_systemd_common_cflags,
|
||||
dependencies: glib_dep,
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -105,6 +105,33 @@ void* greedy_realloc0(
|
|||
return q;
|
||||
}
|
||||
|
||||
void* greedy_realloc_append(
|
||||
void **p,
|
||||
size_t *n_p,
|
||||
const void *from,
|
||||
size_t n_from,
|
||||
size_t size) {
|
||||
|
||||
uint8_t *q;
|
||||
|
||||
assert(p);
|
||||
assert(n_p);
|
||||
assert(from || n_from == 0);
|
||||
|
||||
if (n_from > SIZE_MAX - *n_p)
|
||||
return NULL;
|
||||
|
||||
q = greedy_realloc(p, *n_p + n_from, size);
|
||||
if (!q)
|
||||
return NULL;
|
||||
|
||||
memcpy_safe(q + *n_p * size, from, n_from * size);
|
||||
|
||||
*n_p += n_from;
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
void *expand_to_usable(void *ptr, size_t newsize _unused_) {
|
||||
return ptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,13 +15,12 @@
|
|||
|
||||
typedef void (*free_func_t)(void *p);
|
||||
typedef void* (*mfree_func_t)(void *p);
|
||||
typedef void (*free_array_func_t)(void *p, size_t n);
|
||||
|
||||
/* If for some reason more than 4M are allocated on the stack, let's abort immediately. It's better than
|
||||
* proceeding and smashing the stack limits. Note that by default RLIMIT_STACK is 8M on Linux. */
|
||||
#define ALLOCA_MAX (4U*1024U*1024U)
|
||||
|
||||
#define new(t, n) ((t*) malloc_multiply(sizeof(t), (n)))
|
||||
#define new(t, n) ((t*) malloc_multiply(n, sizeof(t)))
|
||||
|
||||
#define new0(t, n) ((t*) calloc((n) ?: 1, sizeof(t)))
|
||||
|
||||
|
|
@ -46,9 +45,9 @@ typedef void (*free_array_func_t)(void *p, size_t n);
|
|||
(t*) alloca0((sizeof(t)*_n_)); \
|
||||
})
|
||||
|
||||
#define newdup(t, p, n) ((t*) memdup_multiply(p, sizeof(t), (n)))
|
||||
#define newdup(t, p, n) ((t*) memdup_multiply(p, n, sizeof(t)))
|
||||
|
||||
#define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, sizeof(t), (n)))
|
||||
#define newdup_suffix0(t, p, n) ((t*) memdup_suffix0_multiply(p, n, sizeof(t)))
|
||||
|
||||
#define malloc0(n) (calloc(1, (n) ?: 1))
|
||||
|
||||
|
|
@ -113,7 +112,7 @@ static inline bool size_multiply_overflow(size_t size, size_t need) {
|
|||
return _unlikely_(need != 0 && size > (SIZE_MAX / need));
|
||||
}
|
||||
|
||||
_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t size, size_t need) {
|
||||
_malloc_ _alloc_(1, 2) static inline void *malloc_multiply(size_t need, size_t size) {
|
||||
if (size_multiply_overflow(size, need))
|
||||
return NULL;
|
||||
|
||||
|
|
@ -129,7 +128,7 @@ _alloc_(2, 3) static inline void *reallocarray(void *p, size_t need, size_t size
|
|||
}
|
||||
#endif
|
||||
|
||||
_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, size_t need) {
|
||||
_alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t need, size_t size) {
|
||||
if (size_multiply_overflow(size, need))
|
||||
return NULL;
|
||||
|
||||
|
|
@ -138,7 +137,7 @@ _alloc_(2, 3) static inline void *memdup_multiply(const void *p, size_t size, si
|
|||
|
||||
/* Note that we can't decorate this function with _alloc_() since the returned memory area is one byte larger
|
||||
* than the product of its parameters. */
|
||||
static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t need) {
|
||||
static inline void *memdup_suffix0_multiply(const void *p, size_t need, size_t size) {
|
||||
if (size_multiply_overflow(size, need))
|
||||
return NULL;
|
||||
|
||||
|
|
@ -147,6 +146,7 @@ static inline void *memdup_suffix0_multiply(const void *p, size_t size, size_t n
|
|||
|
||||
void* greedy_realloc(void **p, size_t need, size_t size);
|
||||
void* greedy_realloc0(void **p, size_t need, size_t size);
|
||||
void* greedy_realloc_append(void **p, size_t *n_p, const void *from, size_t n_from, size_t size);
|
||||
|
||||
#define GREEDY_REALLOC(array, need) \
|
||||
greedy_realloc((void**) &(array), (need), sizeof((array)[0]))
|
||||
|
|
@ -154,6 +154,9 @@ void* greedy_realloc0(void **p, size_t need, size_t size);
|
|||
#define GREEDY_REALLOC0(array, need) \
|
||||
greedy_realloc0((void**) &(array), (need), sizeof((array)[0]))
|
||||
|
||||
#define GREEDY_REALLOC_APPEND(array, n_array, from, n_from) \
|
||||
greedy_realloc_append((void**) &(array), (size_t*) &(n_array), (from), (n_from), sizeof((array)[0]))
|
||||
|
||||
#define alloca0(n) \
|
||||
({ \
|
||||
char *_new_; \
|
||||
|
|
@ -224,7 +227,6 @@ static inline size_t malloc_sizeof_safe(void **xp) {
|
|||
MALLOC_SIZEOF_SAFE(x)/sizeof((x)[0]), \
|
||||
VOID_0))
|
||||
|
||||
|
||||
/* These are like strdupa()/strndupa(), but honour ALLOCA_MAX */
|
||||
#define strdupa_safe(s) \
|
||||
({ \
|
||||
|
|
@ -235,7 +237,40 @@ static inline size_t malloc_sizeof_safe(void **xp) {
|
|||
#define strndupa_safe(s, n) \
|
||||
({ \
|
||||
const char *_t = (s); \
|
||||
(char*) memdupa_suffix0(_t, strnlen(_t, (n))); \
|
||||
(char*) memdupa_suffix0(_t, strnlen(_t, n)); \
|
||||
})
|
||||
|
||||
/* Free every element of the array. */
|
||||
static inline void free_many(void **p, size_t n) {
|
||||
assert(p || n == 0);
|
||||
|
||||
FOREACH_ARRAY(i, p, n)
|
||||
*i = mfree(*i);
|
||||
}
|
||||
|
||||
/* Typesafe wrapper for char** rather than void**. Unfortunately C won't implicitly cast this. */
|
||||
static inline void free_many_charp(char **c, size_t n) {
|
||||
free_many((void**) c, n);
|
||||
}
|
||||
|
||||
_alloc_(2) static inline void *realloc0(void *p, size_t new_size) {
|
||||
size_t old_size;
|
||||
void *q;
|
||||
|
||||
/* Like realloc(), but initializes anything appended to zero */
|
||||
|
||||
old_size = MALLOC_SIZEOF_SAFE(p);
|
||||
|
||||
q = realloc(p, new_size);
|
||||
if (!q)
|
||||
return NULL;
|
||||
|
||||
new_size = MALLOC_SIZEOF_SAFE(q); /* Update with actually allocated space */
|
||||
|
||||
if (new_size > old_size)
|
||||
memset((uint8_t*) q + old_size, 0, new_size - old_size);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
#include "memory-util.h"
|
||||
|
|
|
|||
10
src/libnm-systemd-shared/src/basic/arphrd-util.h
Normal file
10
src/libnm-systemd-shared/src/basic/arphrd-util.h
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
|
||||
const char *arphrd_to_name(int id);
|
||||
int arphrd_from_name(const char *name);
|
||||
|
||||
size_t arphrd_to_hw_addr_len(uint16_t arphrd);
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "macro.h"
|
||||
|
||||
int asynchronous_job(void* (*func)(void *p), void *arg);
|
||||
|
||||
int asynchronous_sync(pid_t *ret_pid);
|
||||
int asynchronous_close(int fd);
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC(int, asynchronous_close);
|
||||
100
src/libnm-systemd-shared/src/basic/btrfs.c
Normal file
100
src/libnm-systemd-shared/src/basic/btrfs.c
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include "nm-sd-adapt-shared.h"
|
||||
|
||||
#include <linux/btrfs.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "btrfs.h"
|
||||
#include "fd-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "path-util.h"
|
||||
|
||||
int btrfs_validate_subvolume_name(const char *name) {
|
||||
|
||||
if (!filename_is_valid(name))
|
||||
return -EINVAL;
|
||||
|
||||
if (strlen(name) > BTRFS_SUBVOL_NAME_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int extract_subvolume_name(const char *path, char **ret) {
|
||||
_cleanup_free_ char *fn = NULL;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
assert(ret);
|
||||
|
||||
r = path_extract_filename(path, &fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = btrfs_validate_subvolume_name(fn);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*ret = TAKE_PTR(fn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int btrfs_subvol_make(int dir_fd, const char *path) {
|
||||
struct btrfs_ioctl_vol_args args = {};
|
||||
_cleanup_free_ char *subvolume = NULL, *parent = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(!isempty(path));
|
||||
|
||||
r = extract_subvolume_name(path, &subvolume);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = path_extract_directory(path, &parent);
|
||||
if (r < 0) {
|
||||
if (r != -EDESTADDRREQ) /* Propagate error, unless only a filename was specified, which is OK */
|
||||
return r;
|
||||
|
||||
dir_fd = fd_reopen_condition(dir_fd, O_CLOEXEC, O_PATH, &fd); /* drop O_PATH if it is set */
|
||||
if (dir_fd < 0)
|
||||
return dir_fd;
|
||||
} else {
|
||||
fd = openat(dir_fd, parent, O_DIRECTORY|O_RDONLY|O_CLOEXEC, 0);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
|
||||
dir_fd = fd;
|
||||
}
|
||||
|
||||
strncpy(args.name, subvolume, sizeof(args.name)-1);
|
||||
|
||||
return RET_NERRNO(ioctl(dir_fd, BTRFS_IOC_SUBVOL_CREATE, &args));
|
||||
}
|
||||
|
||||
int btrfs_subvol_make_fallback(int dir_fd, const char *path, mode_t mode) {
|
||||
mode_t old, combined;
|
||||
int r;
|
||||
|
||||
assert(path);
|
||||
|
||||
/* Let's work like mkdir(), i.e. take the specified mode, and mask it with the current umask. */
|
||||
old = umask(~mode);
|
||||
combined = old | ~mode;
|
||||
if (combined != ~mode)
|
||||
umask(combined);
|
||||
r = btrfs_subvol_make(dir_fd, path);
|
||||
umask(old);
|
||||
|
||||
if (r >= 0)
|
||||
return 1; /* subvol worked */
|
||||
if (!ERRNO_IS_NOT_SUPPORTED(r))
|
||||
return r;
|
||||
|
||||
if (mkdirat(dir_fd, path, mode) < 0)
|
||||
return -errno;
|
||||
|
||||
return 0; /* plain directory */
|
||||
}
|
||||
9
src/libnm-systemd-shared/src/basic/btrfs.h
Normal file
9
src/libnm-systemd-shared/src/basic/btrfs.h
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <fcntl.h>
|
||||
|
||||
int btrfs_validate_subvolume_name(const char *name);
|
||||
|
||||
int btrfs_subvol_make(int dir_fd, const char *path);
|
||||
|
||||
int btrfs_subvol_make_fallback(int dir_fd, const char *path, mode_t mode);
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
#include <sys/types.h>
|
||||
|
||||
#include "constants.h"
|
||||
#include "pidref.h"
|
||||
#include "set.h"
|
||||
|
||||
#define SYSTEMD_CGROUP_CONTROLLER_LEGACY "name=systemd"
|
||||
|
|
@ -35,7 +36,7 @@ typedef enum CGroupController {
|
|||
CGROUP_CONTROLLER_BPF_SOCKET_BIND,
|
||||
CGROUP_CONTROLLER_BPF_RESTRICT_NETWORK_INTERFACES,
|
||||
/* The BPF hook implementing RestrictFileSystems= is not defined here.
|
||||
* It's applied as late as possible in exec_child() so we don't block
|
||||
* It's applied as late as possible in exec_invoke() so we don't block
|
||||
* our own unit setup code. */
|
||||
|
||||
_CGROUP_CONTROLLER_MAX,
|
||||
|
|
@ -66,10 +67,13 @@ typedef enum CGroupMask {
|
|||
/* All real cgroup v2 controllers */
|
||||
CGROUP_MASK_V2 = CGROUP_MASK_CPU|CGROUP_MASK_CPUSET|CGROUP_MASK_IO|CGROUP_MASK_MEMORY|CGROUP_MASK_PIDS,
|
||||
|
||||
/* All controllers we want to delegate in case of Delegate=yes. Which are pretty much the v2 controllers only, as delegation on v1 is not safe, and bpf stuff isn't a real controller */
|
||||
CGROUP_MASK_DELEGATE = CGROUP_MASK_V2,
|
||||
|
||||
/* All cgroup v2 BPF pseudo-controllers */
|
||||
CGROUP_MASK_BPF = CGROUP_MASK_BPF_FIREWALL|CGROUP_MASK_BPF_DEVICES|CGROUP_MASK_BPF_FOREIGN|CGROUP_MASK_BPF_SOCKET_BIND|CGROUP_MASK_BPF_RESTRICT_NETWORK_INTERFACES,
|
||||
|
||||
_CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1
|
||||
_CGROUP_MASK_ALL = CGROUP_CONTROLLER_TO_MASK(_CGROUP_CONTROLLER_MAX) - 1,
|
||||
} CGroupMask;
|
||||
|
||||
static inline CGroupMask CGROUP_MASK_EXTEND_JOINED(CGroupMask mask) {
|
||||
|
|
@ -176,13 +180,13 @@ typedef enum CGroupUnified {
|
|||
* generate paths with multiple adjacent / removed.
|
||||
*/
|
||||
|
||||
int cg_enumerate_processes(const char *controller, const char *path, FILE **_f);
|
||||
int cg_read_pid(FILE *f, pid_t *_pid);
|
||||
int cg_read_event(const char *controller, const char *path, const char *event,
|
||||
char **val);
|
||||
int cg_enumerate_processes(const char *controller, const char *path, FILE **ret);
|
||||
int cg_read_pid(FILE *f, pid_t *ret);
|
||||
int cg_read_pidref(FILE *f, PidRef *ret);
|
||||
int cg_read_event(const char *controller, const char *path, const char *event, char **ret);
|
||||
|
||||
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **_d);
|
||||
int cg_read_subgroup(DIR *d, char **fn);
|
||||
int cg_enumerate_subgroups(const char *controller, const char *path, DIR **ret);
|
||||
int cg_read_subgroup(DIR *d, char **ret);
|
||||
|
||||
typedef enum CGroupFlags {
|
||||
CGROUP_SIGCONT = 1 << 0,
|
||||
|
|
@ -190,25 +194,31 @@ typedef enum CGroupFlags {
|
|||
CGROUP_REMOVE = 1 << 2,
|
||||
} CGroupFlags;
|
||||
|
||||
typedef int (*cg_kill_log_func_t)(pid_t pid, int sig, void *userdata);
|
||||
typedef int (*cg_kill_log_func_t)(const PidRef *pid, int sig, void *userdata);
|
||||
|
||||
int cg_kill(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
|
||||
int cg_kill_kernel_sigkill(const char *controller, const char *path);
|
||||
int cg_kill_recursive(const char *controller, const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
|
||||
int cg_kill(const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
|
||||
int cg_kill_kernel_sigkill(const char *path);
|
||||
int cg_kill_recursive(const char *path, int sig, CGroupFlags flags, Set *s, cg_kill_log_func_t kill_log, void *userdata);
|
||||
|
||||
int cg_split_spec(const char *spec, char **ret_controller, char **ret_path);
|
||||
int cg_mangle_path(const char *path, char **result);
|
||||
int cg_mangle_path(const char *path, char **ret);
|
||||
|
||||
int cg_get_path(const char *controller, const char *path, const char *suffix, char **fs);
|
||||
int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **fs);
|
||||
int cg_get_path(const char *controller, const char *path, const char *suffix, char **ret);
|
||||
int cg_get_path_and_check(const char *controller, const char *path, const char *suffix, char **ret);
|
||||
|
||||
int cg_pid_get_path(const char *controller, pid_t pid, char **path);
|
||||
int cg_pid_get_path(const char *controller, pid_t pid, char **ret);
|
||||
int cg_pidref_get_path(const char *controller, const PidRef *pidref, char **ret);
|
||||
|
||||
int cg_rmdir(const char *controller, const char *path);
|
||||
|
||||
int cg_is_threaded(const char *controller, const char *path);
|
||||
int cg_is_threaded(const char *path);
|
||||
|
||||
typedef enum {
|
||||
int cg_is_delegated(const char *path);
|
||||
int cg_is_delegated_fd(int fd);
|
||||
|
||||
int cg_has_coredump_receive(const char *path);
|
||||
|
||||
typedef enum {
|
||||
CG_KEY_MODE_GRACEFUL = 1 << 0,
|
||||
} CGroupKeyMode;
|
||||
|
||||
|
|
@ -239,14 +249,14 @@ int cg_get_attribute_as_uint64(const char *controller, const char *path, const c
|
|||
/* Does a parse_boolean() on the attribute contents and sets ret accordingly */
|
||||
int cg_get_attribute_as_bool(const char *controller, const char *path, const char *attribute, bool *ret);
|
||||
|
||||
int cg_get_owner(const char *controller, const char *path, uid_t *ret_uid);
|
||||
int cg_get_owner(const char *path, uid_t *ret_uid);
|
||||
|
||||
int cg_set_xattr(const char *controller, const char *path, const char *name, const void *value, size_t size, int flags);
|
||||
int cg_get_xattr(const char *controller, const char *path, const char *name, void *value, size_t size);
|
||||
int cg_get_xattr_malloc(const char *controller, const char *path, const char *name, char **ret);
|
||||
int cg_set_xattr(const char *path, const char *name, const void *value, size_t size, int flags);
|
||||
int cg_get_xattr(const char *path, const char *name, void *value, size_t size);
|
||||
int cg_get_xattr_malloc(const char *path, const char *name, char **ret);
|
||||
/* Returns negative on error, and 0 or 1 on success for the bool value */
|
||||
int cg_get_xattr_bool(const char *controller, const char *path, const char *name);
|
||||
int cg_remove_xattr(const char *controller, const char *path, const char *name);
|
||||
int cg_get_xattr_bool(const char *path, const char *name);
|
||||
int cg_remove_xattr(const char *path, const char *name);
|
||||
|
||||
int cg_install_release_agent(const char *controller, const char *agent);
|
||||
int cg_uninstall_release_agent(const char *controller);
|
||||
|
|
@ -257,27 +267,28 @@ int cg_is_empty_recursive(const char *controller, const char *path);
|
|||
int cg_get_root_path(char **path);
|
||||
|
||||
int cg_path_get_cgroupid(const char *path, uint64_t *ret);
|
||||
int cg_path_get_session(const char *path, char **session);
|
||||
int cg_path_get_owner_uid(const char *path, uid_t *uid);
|
||||
int cg_path_get_unit(const char *path, char **unit);
|
||||
int cg_path_get_unit_path(const char *path, char **unit);
|
||||
int cg_path_get_user_unit(const char *path, char **unit);
|
||||
int cg_path_get_machine_name(const char *path, char **machine);
|
||||
int cg_path_get_slice(const char *path, char **slice);
|
||||
int cg_path_get_user_slice(const char *path, char **slice);
|
||||
int cg_path_get_session(const char *path, char **ret_session);
|
||||
int cg_path_get_owner_uid(const char *path, uid_t *ret_uid);
|
||||
int cg_path_get_unit(const char *path, char **ret_unit);
|
||||
int cg_path_get_unit_path(const char *path, char **ret_unit);
|
||||
int cg_path_get_user_unit(const char *path, char **ret_unit);
|
||||
int cg_path_get_machine_name(const char *path, char **ret_machine);
|
||||
int cg_path_get_slice(const char *path, char **ret_slice);
|
||||
int cg_path_get_user_slice(const char *path, char **ret_slice);
|
||||
|
||||
int cg_shift_path(const char *cgroup, const char *cached_root, const char **shifted);
|
||||
int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **cgroup);
|
||||
int cg_shift_path(const char *cgroup, const char *cached_root, const char **ret_shifted);
|
||||
int cg_pid_get_path_shifted(pid_t pid, const char *cached_root, char **ret_cgroup);
|
||||
|
||||
int cg_pid_get_session(pid_t pid, char **session);
|
||||
int cg_pid_get_owner_uid(pid_t pid, uid_t *uid);
|
||||
int cg_pid_get_unit(pid_t pid, char **unit);
|
||||
int cg_pid_get_user_unit(pid_t pid, char **unit);
|
||||
int cg_pid_get_machine_name(pid_t pid, char **machine);
|
||||
int cg_pid_get_slice(pid_t pid, char **slice);
|
||||
int cg_pid_get_user_slice(pid_t pid, char **slice);
|
||||
int cg_pid_get_session(pid_t pid, char **ret_session);
|
||||
int cg_pid_get_owner_uid(pid_t pid, uid_t *ret_uid);
|
||||
int cg_pid_get_unit(pid_t pid, char **ret_unit);
|
||||
int cg_pidref_get_unit(const PidRef *pidref, char **ret);
|
||||
int cg_pid_get_user_unit(pid_t pid, char **ret_unit);
|
||||
int cg_pid_get_machine_name(pid_t pid, char **ret_machine);
|
||||
int cg_pid_get_slice(pid_t pid, char **ret_slice);
|
||||
int cg_pid_get_user_slice(pid_t pid, char **ret_slice);
|
||||
|
||||
int cg_path_decode_unit(const char *cgroup, char **unit);
|
||||
int cg_path_decode_unit(const char *cgroup, char **ret_unit);
|
||||
|
||||
bool cg_needs_escape(const char *p);
|
||||
int cg_escape(const char *p, char **ret);
|
||||
|
|
|
|||
|
|
@ -59,22 +59,13 @@
|
|||
#define NOTIFY_FD_MAX 768
|
||||
#define NOTIFY_BUFFER_MAX PIPE_BUF
|
||||
|
||||
#if HAVE_SPLIT_USR
|
||||
# define _CONF_PATHS_SPLIT_USR_NULSTR(n) "/lib/" n "\0"
|
||||
# define _CONF_PATHS_SPLIT_USR(n) , "/lib/" n
|
||||
#else
|
||||
# define _CONF_PATHS_SPLIT_USR_NULSTR(n)
|
||||
# define _CONF_PATHS_SPLIT_USR(n)
|
||||
#endif
|
||||
|
||||
/* Return a nulstr for a standard cascade of configuration paths, suitable to pass to
|
||||
* conf_files_list_nulstr() to implement drop-in directories for extending configuration files. */
|
||||
#define CONF_PATHS_NULSTR(n) \
|
||||
"/etc/" n "\0" \
|
||||
"/run/" n "\0" \
|
||||
"/usr/local/lib/" n "\0" \
|
||||
"/usr/lib/" n "\0" \
|
||||
_CONF_PATHS_SPLIT_USR_NULSTR(n)
|
||||
"/usr/lib/" n "\0"
|
||||
|
||||
#define CONF_PATHS_USR(n) \
|
||||
"/etc/" n, \
|
||||
|
|
@ -83,8 +74,7 @@
|
|||
"/usr/lib/" n
|
||||
|
||||
#define CONF_PATHS(n) \
|
||||
CONF_PATHS_USR(n) \
|
||||
_CONF_PATHS_SPLIT_USR(n)
|
||||
CONF_PATHS_USR(n)
|
||||
|
||||
#define CONF_PATHS_USR_STRV(n) \
|
||||
STRV_MAKE(CONF_PATHS_USR(n))
|
||||
|
|
@ -99,14 +89,9 @@
|
|||
* in containers so that our children inherit that. */
|
||||
#define DEFAULT_RLIMIT_MEMLOCK (1024ULL*1024ULL*8ULL)
|
||||
|
||||
#define PLYMOUTH_SOCKET { \
|
||||
.un.sun_family = AF_UNIX, \
|
||||
.un.sun_path = "\0/org/freedesktop/plymouthd", \
|
||||
}
|
||||
|
||||
/* Path where PID1 listens for varlink subscriptions from systemd-oomd to notify of changes in ManagedOOM settings. */
|
||||
#define VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM "/run/systemd/io.system.ManagedOOM"
|
||||
#define VARLINK_ADDR_PATH_MANAGED_OOM_SYSTEM "/run/systemd/io.systemd.ManagedOOM"
|
||||
/* Path where systemd-oomd listens for varlink connections from user managers to report changes in ManagedOOM settings. */
|
||||
#define VARLINK_ADDR_PATH_MANAGED_OOM_USER "/run/systemd/oom/io.system.ManagedOOM"
|
||||
#define VARLINK_ADDR_PATH_MANAGED_OOM_USER "/run/systemd/oom/io.systemd.ManagedOOM"
|
||||
|
||||
#define KERNEL_BASELINE_VERSION "4.15"
|
||||
|
|
|
|||
|
|
@ -127,7 +127,7 @@ static int parse_env_file_internal(
|
|||
state = VALUE;
|
||||
|
||||
if (!GREEDY_REALLOC(value, n_value+2))
|
||||
return -ENOMEM;
|
||||
return -ENOMEM;
|
||||
|
||||
value[n_value++] = c;
|
||||
}
|
||||
|
|
@ -245,7 +245,13 @@ static int parse_env_file_internal(
|
|||
break;
|
||||
|
||||
case COMMENT_ESCAPE:
|
||||
state = COMMENT;
|
||||
log_debug("The line which doesn't begin with \";\" or \"#\", but follows a comment" \
|
||||
" line trailing with escape is now treated as a non comment line since v254.");
|
||||
if (strchr(NEWLINE, c)) {
|
||||
state = PRE_KEY;
|
||||
line++;
|
||||
} else
|
||||
state = COMMENT;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -522,6 +528,7 @@ static int merge_env_file_push(
|
|||
|
||||
char ***env = ASSERT_PTR(userdata);
|
||||
char *expanded_value;
|
||||
int r;
|
||||
|
||||
assert(key);
|
||||
|
||||
|
|
@ -536,12 +543,12 @@ static int merge_env_file_push(
|
|||
return 0;
|
||||
}
|
||||
|
||||
expanded_value = replace_env(value, *env,
|
||||
REPLACE_ENV_USE_ENVIRONMENT|
|
||||
REPLACE_ENV_ALLOW_BRACELESS|
|
||||
REPLACE_ENV_ALLOW_EXTENDED);
|
||||
if (!expanded_value)
|
||||
return -ENOMEM;
|
||||
r = replace_env(value,
|
||||
*env,
|
||||
REPLACE_ENV_USE_ENVIRONMENT|REPLACE_ENV_ALLOW_BRACELESS|REPLACE_ENV_ALLOW_EXTENDED,
|
||||
&expanded_value);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "%s:%u: Failed to expand variable '%s': %m", strna(filename), line, value);
|
||||
|
||||
free_and_replace(value, expanded_value);
|
||||
|
||||
|
|
@ -599,7 +606,7 @@ static void write_env_var(FILE *f, const char *v) {
|
|||
fputc_unlocked('\n', f);
|
||||
}
|
||||
|
||||
int write_env_file_at(int dir_fd, const char *fname, char **l) {
|
||||
int write_env_file(int dir_fd, const char *fname, char **headers, char **l) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
int r;
|
||||
|
|
@ -613,6 +620,12 @@ int write_env_file_at(int dir_fd, const char *fname, char **l) {
|
|||
|
||||
(void) fchmod_umask(fileno(f), 0644);
|
||||
|
||||
STRV_FOREACH(i, headers) {
|
||||
assert(isempty(*i) || startswith(*i, "#"));
|
||||
fputs_unlocked(*i, f);
|
||||
fputc_unlocked('\n', f);
|
||||
}
|
||||
|
||||
STRV_FOREACH(i, l)
|
||||
write_env_var(f, *i);
|
||||
|
||||
|
|
@ -627,4 +640,12 @@ int write_env_file_at(int dir_fd, const char *fname, char **l) {
|
|||
(void) unlinkat(dir_fd, p, 0);
|
||||
return r;
|
||||
}
|
||||
|
||||
int write_vconsole_conf(int dir_fd, const char *fname, char **l) {
|
||||
char **headers = STRV_MAKE(
|
||||
"# Written by systemd-localed(8) or systemd-firstboot(1), read by systemd-localed",
|
||||
"# and systemd-vconsole-setup(8). Use localectl(1) to update this file.");
|
||||
|
||||
return write_env_file(dir_fd, fname, headers, l);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ int load_env_file_pairs_fd(int fd, const char *fname, char ***ret);
|
|||
|
||||
int merge_env_file(char ***env, FILE *f, const char *fname);
|
||||
|
||||
int write_env_file_at(int dir_fd, const char *fname, char **l);
|
||||
static inline int write_env_file(const char *fname, char **l) {
|
||||
return write_env_file_at(AT_FDCWD, fname, l);
|
||||
}
|
||||
int write_env_file(int dir_fd, const char *fname, char **headers, char **l);
|
||||
|
||||
int write_vconsole_conf(int dir_fd, const char *fname, char **l);
|
||||
|
|
|
|||
|
|
@ -29,20 +29,21 @@
|
|||
"_"
|
||||
|
||||
static bool env_name_is_valid_n(const char *e, size_t n) {
|
||||
if (!e)
|
||||
return false;
|
||||
|
||||
if (n == SIZE_MAX)
|
||||
n = strlen_ptr(e);
|
||||
|
||||
if (n <= 0)
|
||||
return false;
|
||||
|
||||
assert(e);
|
||||
|
||||
if (ascii_isdigit(e[0]))
|
||||
return false;
|
||||
|
||||
/* POSIX says the overall size of the environment block cannot
|
||||
* be > ARG_MAX, an individual assignment hence cannot be
|
||||
* either. Discounting the equal sign and trailing NUL this
|
||||
* hence leaves ARG_MAX-2 as longest possible variable
|
||||
* name. */
|
||||
/* POSIX says the overall size of the environment block cannot be > ARG_MAX, an individual assignment
|
||||
* hence cannot be either. Discounting the equal sign and trailing NUL this hence leaves ARG_MAX-2 as
|
||||
* longest possible variable name. */
|
||||
if (n > (size_t) sysconf(_SC_ARG_MAX) - 2)
|
||||
return false;
|
||||
|
||||
|
|
@ -246,9 +247,9 @@ static bool env_match(const char *t, const char *pattern) {
|
|||
return true;
|
||||
|
||||
if (!strchr(pattern, '=')) {
|
||||
size_t l = strlen(pattern);
|
||||
t = startswith(t, pattern);
|
||||
|
||||
return strneq(t, pattern, l) && t[l] == '=';
|
||||
return t && *t == '=';
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
@ -460,6 +461,35 @@ int strv_env_assign(char ***l, const char *key, const char *value) {
|
|||
return strv_env_replace_consume(l, p);
|
||||
}
|
||||
|
||||
int strv_env_assignf(char ***l, const char *key, const char *valuef, ...) {
|
||||
int r;
|
||||
|
||||
assert(l);
|
||||
assert(key);
|
||||
|
||||
if (!env_name_is_valid(key))
|
||||
return -EINVAL;
|
||||
|
||||
if (!valuef) {
|
||||
strv_env_unset(*l, key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
_cleanup_free_ char *value = NULL;
|
||||
va_list ap;
|
||||
va_start(ap, valuef);
|
||||
r = vasprintf(&value, valuef, ap);
|
||||
va_end(ap);
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
char *p = strjoin(key, "=", value);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
return strv_env_replace_consume(l, p);
|
||||
}
|
||||
|
||||
int _strv_env_assign_many(char ***l, ...) {
|
||||
va_list ap;
|
||||
int r;
|
||||
|
|
@ -502,32 +532,31 @@ int _strv_env_assign_many(char ***l, ...) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) {
|
||||
char* strv_env_get_n(char * const *l, const char *name, size_t k, ReplaceEnvFlags flags) {
|
||||
assert(name);
|
||||
|
||||
if (k == SIZE_MAX)
|
||||
k = strlen(name);
|
||||
if (k <= 0)
|
||||
return NULL;
|
||||
|
||||
STRV_FOREACH_BACKWARDS(i, l)
|
||||
if (strneq(*i, name, k) &&
|
||||
(*i)[k] == '=')
|
||||
return *i + k + 1;
|
||||
if (strneq(*i, name, k) && (*i)[k] == '=')
|
||||
return (char*) *i + k + 1;
|
||||
|
||||
if (flags & REPLACE_ENV_USE_ENVIRONMENT) {
|
||||
const char *t;
|
||||
|
||||
/* Safety check that the name is not overly long, before we do a stack allocation */
|
||||
if (k > (size_t) sysconf(_SC_ARG_MAX) - 2)
|
||||
return NULL;
|
||||
|
||||
t = strndupa_safe(name, k);
|
||||
return getenv(t);
|
||||
};
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strv_env_get(char **l, const char *name) {
|
||||
assert(name);
|
||||
|
||||
return strv_env_get_n(l, name, strlen(name), 0);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
char *strv_env_pairs_get(char **l, const char *name) {
|
||||
|
|
@ -578,7 +607,61 @@ char **strv_env_clean_with_callback(char **e, void (*invalid_callback)(const cha
|
|||
return e;
|
||||
}
|
||||
|
||||
char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
|
||||
static int strv_extend_with_length(char ***l, const char *s, size_t n) {
|
||||
char *c;
|
||||
|
||||
c = strndup(s, n);
|
||||
if (!c)
|
||||
return -ENOMEM;
|
||||
|
||||
return strv_consume(l, c);
|
||||
}
|
||||
|
||||
static int strv_env_get_n_validated(
|
||||
char **env,
|
||||
const char *name,
|
||||
size_t l,
|
||||
ReplaceEnvFlags flags,
|
||||
char **ret, /* points into the env block! do not free! */
|
||||
char ***unset_variables, /* updated in place */
|
||||
char ***bad_variables) { /* ditto */
|
||||
|
||||
char *e;
|
||||
int r;
|
||||
|
||||
assert(l == 0 || name);
|
||||
assert(ret);
|
||||
|
||||
if (env_name_is_valid_n(name, l)) {
|
||||
e = strv_env_get_n(env, name, l, flags);
|
||||
if (!e && unset_variables) {
|
||||
r = strv_extend_with_length(unset_variables, name, l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
} else {
|
||||
e = NULL; /* Resolve invalid variable names the same way as unset ones */
|
||||
|
||||
if (bad_variables) {
|
||||
r = strv_extend_with_length(bad_variables, name, l);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
*ret = e;
|
||||
return !!e;
|
||||
}
|
||||
|
||||
int replace_env_full(
|
||||
const char *format,
|
||||
size_t n,
|
||||
char **env,
|
||||
ReplaceEnvFlags flags,
|
||||
char **ret,
|
||||
char ***ret_unset_variables,
|
||||
char ***ret_bad_variables) {
|
||||
|
||||
enum {
|
||||
WORD,
|
||||
CURLY,
|
||||
|
|
@ -589,15 +672,22 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
|
|||
ALTERNATE_VALUE,
|
||||
} state = WORD;
|
||||
|
||||
_cleanup_strv_free_ char **unset_variables = NULL, **bad_variables = NULL;
|
||||
const char *e, *word = format, *test_value = NULL; /* test_value is initialized to appease gcc */
|
||||
char *k;
|
||||
_cleanup_free_ char *s = NULL;
|
||||
char ***pu, ***pb, *k;
|
||||
size_t i, len = 0; /* len is initialized to appease gcc */
|
||||
int nest = 0;
|
||||
int nest = 0, r;
|
||||
|
||||
assert(format);
|
||||
|
||||
for (e = format, i = 0; *e && i < n; e ++, i ++)
|
||||
if (n == SIZE_MAX)
|
||||
n = strlen(format);
|
||||
|
||||
pu = ret_unset_variables ? &unset_variables : NULL;
|
||||
pb = ret_bad_variables ? &bad_variables : NULL;
|
||||
|
||||
for (e = format, i = 0; *e && i < n; e++, i++)
|
||||
switch (state) {
|
||||
|
||||
case WORD:
|
||||
|
|
@ -609,27 +699,28 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
|
|||
if (*e == '{') {
|
||||
k = strnappend(s, word, e-word-1);
|
||||
if (!k)
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
free_and_replace(s, k);
|
||||
|
||||
word = e-1;
|
||||
state = VARIABLE;
|
||||
nest++;
|
||||
|
||||
} else if (*e == '$') {
|
||||
k = strnappend(s, word, e-word);
|
||||
if (!k)
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
free_and_replace(s, k);
|
||||
|
||||
word = e+1;
|
||||
state = WORD;
|
||||
|
||||
} else if (flags & REPLACE_ENV_ALLOW_BRACELESS && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
|
||||
} else if (FLAGS_SET(flags, REPLACE_ENV_ALLOW_BRACELESS) && strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
|
||||
k = strnappend(s, word, e-word-1);
|
||||
if (!k)
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
free_and_replace(s, k);
|
||||
|
||||
|
|
@ -642,12 +733,14 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
|
|||
|
||||
case VARIABLE:
|
||||
if (*e == '}') {
|
||||
const char *t;
|
||||
char *t;
|
||||
|
||||
t = strv_env_get_n(env, word+2, e-word-2, flags);
|
||||
r = strv_env_get_n_validated(env, word+2, e-word-2, flags, &t, pu, pb);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!strextend(&s, t))
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
word = e+1;
|
||||
state = WORD;
|
||||
|
|
@ -689,18 +782,37 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
|
|||
|
||||
nest--;
|
||||
if (nest == 0) {
|
||||
const char *t;
|
||||
_cleanup_strv_free_ char **u = NULL, **b = NULL;
|
||||
_cleanup_free_ char *v = NULL;
|
||||
char *t = NULL;
|
||||
|
||||
t = strv_env_get_n(env, word+2, len, flags);
|
||||
r = strv_env_get_n_validated(env, word+2, len, flags, &t, pu, pb);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (t && state == ALTERNATE_VALUE)
|
||||
t = v = replace_env_n(test_value, e-test_value, env, flags);
|
||||
else if (!t && state == DEFAULT_VALUE)
|
||||
t = v = replace_env_n(test_value, e-test_value, env, flags);
|
||||
if (t && state == ALTERNATE_VALUE) {
|
||||
r = replace_env_full(test_value, e-test_value, env, flags, &v, pu ? &u : NULL, pb ? &b : NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t = v;
|
||||
} else if (!t && state == DEFAULT_VALUE) {
|
||||
r = replace_env_full(test_value, e-test_value, env, flags, &v, pu ? &u : NULL, pb ? &b : NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
t = v;
|
||||
}
|
||||
|
||||
r = strv_extend_strv(&unset_variables, u, /* filter_duplicates= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
r = strv_extend_strv(&bad_variables, b, /* filter_duplicates= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!strextend(&s, t))
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
word = e+1;
|
||||
state = WORD;
|
||||
|
|
@ -711,12 +823,14 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
|
|||
assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
|
||||
|
||||
if (!strchr(VALID_BASH_ENV_NAME_CHARS, *e)) {
|
||||
const char *t;
|
||||
char *t = NULL;
|
||||
|
||||
t = strv_env_get_n(env, word+1, e-word-1, flags);
|
||||
r = strv_env_get_n_validated(env, word+1, e-word-1, flags, &t, &unset_variables, &bad_variables);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!strextend(&s, t))
|
||||
return NULL;
|
||||
return -ENOMEM;
|
||||
|
||||
word = e--;
|
||||
i--;
|
||||
|
|
@ -726,58 +840,83 @@ char *replace_env_n(const char *format, size_t n, char **env, unsigned flags) {
|
|||
}
|
||||
|
||||
if (state == VARIABLE_RAW) {
|
||||
const char *t;
|
||||
char *t;
|
||||
|
||||
assert(flags & REPLACE_ENV_ALLOW_BRACELESS);
|
||||
|
||||
t = strv_env_get_n(env, word+1, e-word-1, flags);
|
||||
return strjoin(s, t);
|
||||
} else
|
||||
return strnappend(s, word, e-word);
|
||||
r = strv_env_get_n_validated(env, word+1, e-word-1, flags, &t, &unset_variables, &bad_variables);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (!strextend(&s, t))
|
||||
return -ENOMEM;
|
||||
|
||||
} else if (!strextendn(&s, word, e-word))
|
||||
return -ENOMEM;
|
||||
|
||||
if (ret_unset_variables)
|
||||
*ret_unset_variables = TAKE_PTR(unset_variables);
|
||||
if (ret_bad_variables)
|
||||
*ret_bad_variables = TAKE_PTR(bad_variables);
|
||||
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char **replace_env_argv(char **argv, char **env) {
|
||||
_cleanup_strv_free_ char **ret = NULL;
|
||||
int replace_env_argv(
|
||||
char **argv,
|
||||
char **env,
|
||||
char ***ret,
|
||||
char ***ret_unset_variables,
|
||||
char ***ret_bad_variables) {
|
||||
|
||||
_cleanup_strv_free_ char **n = NULL, **unset_variables = NULL, **bad_variables = NULL;
|
||||
size_t k = 0, l = 0;
|
||||
int r;
|
||||
|
||||
l = strv_length(argv);
|
||||
|
||||
ret = new(char*, l+1);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
n = new(char*, l+1);
|
||||
if (!n)
|
||||
return -ENOMEM;
|
||||
|
||||
STRV_FOREACH(i, argv) {
|
||||
const char *word = *i;
|
||||
|
||||
/* If $FOO appears as single word, replace it by the split up variable */
|
||||
if ((*i)[0] == '$' && !IN_SET((*i)[1], '{', '$')) {
|
||||
char *e;
|
||||
char **w;
|
||||
if (word[0] == '$' && !IN_SET(word[1], '{', '$')) {
|
||||
_cleanup_strv_free_ char **m = NULL;
|
||||
const char *name = word + 1;
|
||||
char *e, **w;
|
||||
size_t q;
|
||||
|
||||
e = strv_env_get(env, *i+1);
|
||||
if (e) {
|
||||
int r;
|
||||
|
||||
r = strv_split_full(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE);
|
||||
if (r < 0) {
|
||||
ret[k] = NULL;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
if (env_name_is_valid(name)) {
|
||||
e = strv_env_get(env, name);
|
||||
if (e)
|
||||
r = strv_split_full(&m, e, WHITESPACE, EXTRACT_RELAX|EXTRACT_UNQUOTE);
|
||||
else if (ret_unset_variables)
|
||||
r = strv_extend(&unset_variables, name);
|
||||
else
|
||||
r = 0;
|
||||
} else if (ret_bad_variables)
|
||||
r = strv_extend(&bad_variables, name);
|
||||
else
|
||||
r = 0;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
q = strv_length(m);
|
||||
l = l + q - 1;
|
||||
|
||||
w = reallocarray(ret, l + 1, sizeof(char *));
|
||||
if (!w) {
|
||||
ret[k] = NULL;
|
||||
return NULL;
|
||||
}
|
||||
w = reallocarray(n, l + 1, sizeof(char*));
|
||||
if (!w)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = w;
|
||||
n = w;
|
||||
if (m) {
|
||||
memcpy(ret + k, m, q * sizeof(char*));
|
||||
memcpy(n + k, m, (q + 1) * sizeof(char*));
|
||||
m = mfree(m);
|
||||
}
|
||||
|
||||
|
|
@ -785,15 +924,41 @@ char **replace_env_argv(char **argv, char **env) {
|
|||
continue;
|
||||
}
|
||||
|
||||
_cleanup_strv_free_ char **u = NULL, **b = NULL;
|
||||
|
||||
/* If ${FOO} appears as part of a word, replace it by the variable as-is */
|
||||
ret[k] = replace_env(*i, env, 0);
|
||||
if (!ret[k])
|
||||
return NULL;
|
||||
k++;
|
||||
r = replace_env_full(
|
||||
word,
|
||||
/* length= */ SIZE_MAX,
|
||||
env,
|
||||
/* flags= */ 0,
|
||||
n + k,
|
||||
ret_unset_variables ? &u : NULL,
|
||||
ret_bad_variables ? &b : NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
n[++k] = NULL;
|
||||
|
||||
r = strv_extend_strv(&unset_variables, u, /* filter_duplicates= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = strv_extend_strv(&bad_variables, b, /*filter_duplicates= */ true);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
ret[k] = NULL;
|
||||
return TAKE_PTR(ret);
|
||||
if (ret_unset_variables) {
|
||||
strv_uniq(strv_sort(unset_variables));
|
||||
*ret_unset_variables = TAKE_PTR(unset_variables);
|
||||
}
|
||||
if (ret_bad_variables) {
|
||||
strv_uniq(strv_sort(bad_variables));
|
||||
*ret_bad_variables = TAKE_PTR(bad_variables);
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(n);
|
||||
return 0;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
|
|
@ -853,8 +1018,8 @@ int putenv_dup(const char *assignment, bool override) {
|
|||
}
|
||||
|
||||
int setenv_systemd_exec_pid(bool update_only) {
|
||||
char str[DECIMAL_STR_MAX(pid_t)];
|
||||
const char *e;
|
||||
int r;
|
||||
|
||||
/* Update $SYSTEMD_EXEC_PID=pid except when '*' is set for the variable. */
|
||||
|
||||
|
|
@ -865,10 +1030,9 @@ int setenv_systemd_exec_pid(bool update_only) {
|
|||
if (streq_ptr(e, "*"))
|
||||
return 0;
|
||||
|
||||
xsprintf(str, PID_FMT, getpid_cached());
|
||||
|
||||
if (setenv("SYSTEMD_EXEC_PID", str, 1) < 0)
|
||||
return -errno;
|
||||
r = setenvf("SYSTEMD_EXEC_PID", /* overwrite= */ 1, PID_FMT, getpid_cached());
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -944,4 +1108,45 @@ int getenv_steal_erase(const char *name, char **ret) {
|
|||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int set_full_environment(char **env) {
|
||||
int r;
|
||||
|
||||
clearenv();
|
||||
|
||||
STRV_FOREACH(e, env) {
|
||||
_cleanup_free_ char *k = NULL, *v = NULL;
|
||||
|
||||
r = split_pair(*e, "=", &k, &v);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (setenv(k, v, /* overwrite= */ true) < 0)
|
||||
return -errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int setenvf(const char *name, bool overwrite, const char *valuef, ...) {
|
||||
_cleanup_free_ char *value = NULL;
|
||||
va_list ap;
|
||||
int r;
|
||||
|
||||
assert(name);
|
||||
|
||||
if (!valuef)
|
||||
return RET_NERRNO(unsetenv(name));
|
||||
|
||||
va_start(ap, valuef);
|
||||
DISABLE_WARNING_FORMAT_NONLITERAL;
|
||||
r = vasprintf(&value, valuef, ap);
|
||||
REENABLE_WARNING;
|
||||
va_end(ap);
|
||||
|
||||
if (r < 0)
|
||||
return -ENOMEM;
|
||||
|
||||
return RET_NERRNO(setenv(name, value, overwrite));
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -19,19 +19,19 @@ bool env_name_is_valid(const char *e);
|
|||
bool env_value_is_valid(const char *e);
|
||||
bool env_assignment_is_valid(const char *e);
|
||||
|
||||
enum {
|
||||
typedef enum ReplaceEnvFlags {
|
||||
REPLACE_ENV_USE_ENVIRONMENT = 1 << 0,
|
||||
REPLACE_ENV_ALLOW_BRACELESS = 1 << 1,
|
||||
REPLACE_ENV_ALLOW_EXTENDED = 1 << 2,
|
||||
};
|
||||
} ReplaceEnvFlags;
|
||||
|
||||
char *replace_env_n(const char *format, size_t n, char **env, unsigned flags);
|
||||
char **replace_env_argv(char **argv, char **env);
|
||||
|
||||
static inline char *replace_env(const char *format, char **env, unsigned flags) {
|
||||
return replace_env_n(format, strlen(format), env, flags);
|
||||
int replace_env_full(const char *format, size_t n, char **env, ReplaceEnvFlags flags, char **ret, char ***ret_unset_variables, char ***ret_bad_variables);
|
||||
static inline int replace_env(const char *format, char **env, ReplaceEnvFlags flags, char **ret) {
|
||||
return replace_env_full(format, SIZE_MAX, env, flags, ret, NULL, NULL);
|
||||
}
|
||||
|
||||
int replace_env_argv(char **argv, char **env, char ***ret, char ***ret_unset_variables, char ***ret_bad_variables);
|
||||
|
||||
bool strv_env_is_valid(char **e);
|
||||
#define strv_env_clean(l) strv_env_clean_with_callback(l, NULL, NULL)
|
||||
char **strv_env_clean_with_callback(char **l, void (*invalid_callback)(const char *p, void *userdata), void *userdata);
|
||||
|
|
@ -49,11 +49,15 @@ int strv_env_replace_consume(char ***l, char *p); /* In place ... */
|
|||
int strv_env_replace_strdup(char ***l, const char *assignment);
|
||||
int strv_env_replace_strdup_passthrough(char ***l, const char *assignment);
|
||||
int strv_env_assign(char ***l, const char *key, const char *value);
|
||||
int strv_env_assignf(char ***l, const char *key, const char *valuef, ...) _printf_(3, 4);
|
||||
int _strv_env_assign_many(char ***l, ...) _sentinel_;
|
||||
#define strv_env_assign_many(l, ...) _strv_env_assign_many(l, __VA_ARGS__, NULL)
|
||||
|
||||
char *strv_env_get_n(char **l, const char *name, size_t k, unsigned flags) _pure_;
|
||||
char *strv_env_get(char **x, const char *n) _pure_;
|
||||
char* strv_env_get_n(char * const *l, const char *name, size_t k, ReplaceEnvFlags flags);
|
||||
static inline char* strv_env_get(char * const *x, const char *n) {
|
||||
return strv_env_get_n(x, n, SIZE_MAX, 0);
|
||||
}
|
||||
|
||||
char *strv_env_pairs_get(char **l, const char *name) _pure_;
|
||||
|
||||
int getenv_bool(const char *p);
|
||||
|
|
@ -74,3 +78,7 @@ int setenv_systemd_exec_pid(bool update_only);
|
|||
int getenv_path_list(const char *name, char ***ret_paths);
|
||||
|
||||
int getenv_steal_erase(const char *name, char **ret);
|
||||
|
||||
int set_full_environment(char **env);
|
||||
|
||||
int setenvf(const char *name, bool overwrite, const char *valuef, ...) _printf_(3,4);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
|
@ -73,6 +74,16 @@ static inline int RET_NERRNO(int ret) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* Collect possible errors in <acc>, so that the first error can be returned.
|
||||
* Returns (possibly updated) <acc>. */
|
||||
#define RET_GATHER(acc, err) \
|
||||
({ \
|
||||
int *__a = &(acc), __e = (err); \
|
||||
if (*__a >= 0 && __e < 0) \
|
||||
*__a = __e; \
|
||||
*__a; \
|
||||
})
|
||||
|
||||
static inline int errno_or_else(int fallback) {
|
||||
/* To be used when invoking library calls where errno handling is not defined clearly: we return
|
||||
* errno if it is set, and the specified error otherwise. The idea is that the caller initializes
|
||||
|
|
@ -84,12 +95,23 @@ static inline int errno_or_else(int fallback) {
|
|||
return -abs(fallback);
|
||||
}
|
||||
|
||||
/* abs(3) says: Trying to take the absolute value of the most negative integer is not defined. */
|
||||
#define _DEFINE_ABS_WRAPPER(name) \
|
||||
static inline bool ERRNO_IS_##name(intmax_t r) { \
|
||||
if (r == INTMAX_MIN) \
|
||||
return false; \
|
||||
return ERRNO_IS_NEG_##name(-imaxabs(r)); \
|
||||
}
|
||||
|
||||
assert_cc(INT_MAX <= INTMAX_MAX);
|
||||
|
||||
/* For send()/recv() or read()/write(). */
|
||||
static inline bool ERRNO_IS_TRANSIENT(int r) {
|
||||
return IN_SET(abs(r),
|
||||
EAGAIN,
|
||||
EINTR);
|
||||
static inline bool ERRNO_IS_NEG_TRANSIENT(intmax_t r) {
|
||||
return IN_SET(r,
|
||||
-EAGAIN,
|
||||
-EINTR);
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(TRANSIENT);
|
||||
|
||||
/* Hint #1: ENETUNREACH happens if we try to connect to "non-existing" special IP addresses, such as ::5.
|
||||
*
|
||||
|
|
@ -98,79 +120,87 @@ static inline bool ERRNO_IS_TRANSIENT(int r) {
|
|||
*
|
||||
* Hint #3: When asynchronous connect() on TCP fails because the host never acknowledges a single packet,
|
||||
* kernel tells us that with ETIMEDOUT, see tcp(7). */
|
||||
static inline bool ERRNO_IS_DISCONNECT(int r) {
|
||||
return IN_SET(abs(r),
|
||||
ECONNABORTED,
|
||||
ECONNREFUSED,
|
||||
ECONNRESET,
|
||||
EHOSTDOWN,
|
||||
EHOSTUNREACH,
|
||||
ENETDOWN,
|
||||
ENETRESET,
|
||||
ENETUNREACH,
|
||||
ENONET,
|
||||
ENOPROTOOPT,
|
||||
ENOTCONN,
|
||||
EPIPE,
|
||||
EPROTO,
|
||||
ESHUTDOWN,
|
||||
ETIMEDOUT);
|
||||
static inline bool ERRNO_IS_NEG_DISCONNECT(intmax_t r) {
|
||||
return IN_SET(r,
|
||||
-ECONNABORTED,
|
||||
-ECONNREFUSED,
|
||||
-ECONNRESET,
|
||||
-EHOSTDOWN,
|
||||
-EHOSTUNREACH,
|
||||
-ENETDOWN,
|
||||
-ENETRESET,
|
||||
-ENETUNREACH,
|
||||
-ENONET,
|
||||
-ENOPROTOOPT,
|
||||
-ENOTCONN,
|
||||
-EPIPE,
|
||||
-EPROTO,
|
||||
-ESHUTDOWN,
|
||||
-ETIMEDOUT);
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(DISCONNECT);
|
||||
|
||||
/* Transient errors we might get on accept() that we should ignore. As per error handling comment in
|
||||
* the accept(2) man page. */
|
||||
static inline bool ERRNO_IS_ACCEPT_AGAIN(int r) {
|
||||
return ERRNO_IS_DISCONNECT(r) ||
|
||||
ERRNO_IS_TRANSIENT(r) ||
|
||||
abs(r) == EOPNOTSUPP;
|
||||
static inline bool ERRNO_IS_NEG_ACCEPT_AGAIN(intmax_t r) {
|
||||
return ERRNO_IS_NEG_DISCONNECT(r) ||
|
||||
ERRNO_IS_NEG_TRANSIENT(r) ||
|
||||
r == -EOPNOTSUPP;
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(ACCEPT_AGAIN);
|
||||
|
||||
/* Resource exhaustion, could be our fault or general system trouble */
|
||||
static inline bool ERRNO_IS_RESOURCE(int r) {
|
||||
return IN_SET(abs(r),
|
||||
EMFILE,
|
||||
ENFILE,
|
||||
ENOMEM);
|
||||
static inline bool ERRNO_IS_NEG_RESOURCE(intmax_t r) {
|
||||
return IN_SET(r,
|
||||
-EMFILE,
|
||||
-ENFILE,
|
||||
-ENOMEM);
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(RESOURCE);
|
||||
|
||||
/* Seven different errors for "operation/system call/ioctl/socket feature not supported" */
|
||||
static inline bool ERRNO_IS_NOT_SUPPORTED(int r) {
|
||||
return IN_SET(abs(r),
|
||||
EOPNOTSUPP,
|
||||
ENOTTY,
|
||||
ENOSYS,
|
||||
EAFNOSUPPORT,
|
||||
EPFNOSUPPORT,
|
||||
EPROTONOSUPPORT,
|
||||
ESOCKTNOSUPPORT);
|
||||
static inline bool ERRNO_IS_NEG_NOT_SUPPORTED(intmax_t r) {
|
||||
return IN_SET(r,
|
||||
-EOPNOTSUPP,
|
||||
-ENOTTY,
|
||||
-ENOSYS,
|
||||
-EAFNOSUPPORT,
|
||||
-EPFNOSUPPORT,
|
||||
-EPROTONOSUPPORT,
|
||||
-ESOCKTNOSUPPORT);
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(NOT_SUPPORTED);
|
||||
|
||||
/* Two different errors for access problems */
|
||||
static inline bool ERRNO_IS_PRIVILEGE(int r) {
|
||||
return IN_SET(abs(r),
|
||||
EACCES,
|
||||
EPERM);
|
||||
static inline bool ERRNO_IS_NEG_PRIVILEGE(intmax_t r) {
|
||||
return IN_SET(r,
|
||||
-EACCES,
|
||||
-EPERM);
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(PRIVILEGE);
|
||||
|
||||
/* Three different errors for "not enough disk space" */
|
||||
static inline bool ERRNO_IS_DISK_SPACE(int r) {
|
||||
return IN_SET(abs(r),
|
||||
ENOSPC,
|
||||
EDQUOT,
|
||||
EFBIG);
|
||||
static inline bool ERRNO_IS_NEG_DISK_SPACE(intmax_t r) {
|
||||
return IN_SET(r,
|
||||
-ENOSPC,
|
||||
-EDQUOT,
|
||||
-EFBIG);
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(DISK_SPACE);
|
||||
|
||||
/* Three different errors for "this device does not quite exist" */
|
||||
static inline bool ERRNO_IS_DEVICE_ABSENT(int r) {
|
||||
return IN_SET(abs(r),
|
||||
ENODEV,
|
||||
ENXIO,
|
||||
ENOENT);
|
||||
static inline bool ERRNO_IS_NEG_DEVICE_ABSENT(intmax_t r) {
|
||||
return IN_SET(r,
|
||||
-ENODEV,
|
||||
-ENXIO,
|
||||
-ENOENT);
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(DEVICE_ABSENT);
|
||||
|
||||
/* Quite often we want to handle cases where the backing FS doesn't support extended attributes at all and
|
||||
* where it simply doesn't have the requested xattr the same way */
|
||||
static inline bool ERRNO_IS_XATTR_ABSENT(int r) {
|
||||
return abs(r) == ENODATA ||
|
||||
ERRNO_IS_NOT_SUPPORTED(r);
|
||||
static inline bool ERRNO_IS_NEG_XATTR_ABSENT(intmax_t r) {
|
||||
return r == -ENODATA ||
|
||||
ERRNO_IS_NEG_NOT_SUPPORTED(r);
|
||||
}
|
||||
_DEFINE_ABS_WRAPPER(XATTR_ABSENT);
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit,
|
|||
}
|
||||
|
||||
case 'u': {
|
||||
/* C++11 style 16bit unicode */
|
||||
/* C++11 style 16-bit unicode */
|
||||
|
||||
int a[4];
|
||||
size_t i;
|
||||
|
|
@ -211,7 +211,7 @@ int cunescape_one(const char *p, size_t length, char32_t *ret, bool *eight_bit,
|
|||
}
|
||||
|
||||
case 'U': {
|
||||
/* C++11 style 32bit unicode */
|
||||
/* C++11 style 32-bit unicode */
|
||||
|
||||
int a[8];
|
||||
size_t i;
|
||||
|
|
@ -474,6 +474,33 @@ char* octescape(const char *s, size_t len) {
|
|||
return buf;
|
||||
}
|
||||
|
||||
char* decescape(const char *s, const char *bad, size_t len) {
|
||||
char *buf, *t;
|
||||
|
||||
/* Escapes all chars in bad, in addition to \ and " chars, in \nnn decimal style escaping. */
|
||||
|
||||
assert(s || len == 0);
|
||||
|
||||
t = buf = new(char, len * 4 + 1);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t u = (uint8_t) s[i];
|
||||
|
||||
if (u < ' ' || u >= 127 || IN_SET(u, '\\', '"') || strchr(bad, u)) {
|
||||
*(t++) = '\\';
|
||||
*(t++) = '0' + (u / 100);
|
||||
*(t++) = '0' + ((u / 10) % 10);
|
||||
*(t++) = '0' + (u % 10);
|
||||
} else
|
||||
*(t++) = u;
|
||||
}
|
||||
|
||||
*t = 0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char* strcpy_backslash_escaped(char *t, const char *s, const char *bad) {
|
||||
assert(bad);
|
||||
assert(t);
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ static inline char* xescape(const char *s, const char *bad) {
|
|||
return xescape_full(s, bad, SIZE_MAX, 0);
|
||||
}
|
||||
char* octescape(const char *s, size_t len);
|
||||
char* decescape(const char *s, const char *bad, size_t len);
|
||||
char* escape_non_printable_full(const char *str, size_t console_width, XEscapeFlags flags);
|
||||
|
||||
char* shell_escape(const char *s, const char *bad);
|
||||
|
|
|
|||
|
|
@ -61,8 +61,8 @@ void hw_addr_hash_func(const struct hw_addr_data *p, struct siphash *state) {
|
|||
assert(p);
|
||||
assert(state);
|
||||
|
||||
siphash24_compress(&p->length, sizeof(p->length), state);
|
||||
siphash24_compress(p->bytes, p->length, state);
|
||||
siphash24_compress_typesafe(p->length, state);
|
||||
siphash24_compress_safe(p->bytes, p->length, state);
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(hw_addr_hash_ops, struct hw_addr_data, hw_addr_hash_func, hw_addr_compare);
|
||||
|
|
@ -108,7 +108,7 @@ int ether_addr_compare(const struct ether_addr *a, const struct ether_addr *b) {
|
|||
}
|
||||
|
||||
static void ether_addr_hash_func(const struct ether_addr *p, struct siphash *state) {
|
||||
siphash24_compress(p, sizeof(struct ether_addr), state);
|
||||
siphash24_compress_typesafe(*p, state);
|
||||
}
|
||||
|
||||
DEFINE_HASH_OPS(ether_addr_hash_ops, struct ether_addr, ether_addr_hash_func, ether_addr_compare);
|
||||
|
|
@ -272,3 +272,11 @@ int parse_ether_addr(const char *s, struct ether_addr *ret) {
|
|||
*ret = a.ether;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ether_addr_mark_random(struct ether_addr *addr) {
|
||||
assert(addr);
|
||||
|
||||
/* see eth_random_addr in the kernel */
|
||||
addr->ether_addr_octet[0] &= 0xfe; /* clear multicast bit */
|
||||
addr->ether_addr_octet[0] |= 0x02; /* set local assignment bit (IEEE802) */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,3 +113,5 @@ static inline bool ether_addr_is_global(const struct ether_addr *addr) {
|
|||
|
||||
extern const struct hash_ops ether_addr_hash_ops;
|
||||
extern const struct hash_ops ether_addr_hash_ops_free;
|
||||
|
||||
void ether_addr_mark_random(struct ether_addr *addr);
|
||||
|
|
|
|||
|
|
@ -275,11 +275,7 @@ int extract_many_words(const char **p, const char *separators, unsigned flags, .
|
|||
|
||||
r = extract_first_word(p, &l[c], separators, flags);
|
||||
if (r < 0) {
|
||||
int j;
|
||||
|
||||
for (j = 0; j < c; j++)
|
||||
free(l[j]);
|
||||
|
||||
free_many_charp(l, c);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,11 +94,25 @@ void safe_close_pair(int p[static 2]) {
|
|||
p[1] = safe_close(p[1]);
|
||||
}
|
||||
|
||||
void close_many(const int fds[], size_t n_fd) {
|
||||
assert(fds || n_fd <= 0);
|
||||
void close_many(const int fds[], size_t n_fds) {
|
||||
assert(fds || n_fds == 0);
|
||||
|
||||
for (size_t i = 0; i < n_fd; i++)
|
||||
safe_close(fds[i]);
|
||||
FOREACH_ARRAY(fd, fds, n_fds)
|
||||
safe_close(*fd);
|
||||
}
|
||||
|
||||
void close_many_unset(int fds[], size_t n_fds) {
|
||||
assert(fds || n_fds == 0);
|
||||
|
||||
FOREACH_ARRAY(fd, fds, n_fds)
|
||||
*fd = safe_close(*fd);
|
||||
}
|
||||
|
||||
void close_many_and_free(int *fds, size_t n_fds) {
|
||||
assert(fds || n_fds == 0);
|
||||
|
||||
close_many(fds, n_fds);
|
||||
free(fds);
|
||||
}
|
||||
|
||||
int fclose_nointr(FILE *f) {
|
||||
|
|
@ -158,6 +172,19 @@ int fd_nonblock(int fd, bool nonblock) {
|
|||
return RET_NERRNO(fcntl(fd, F_SETFL, nflags));
|
||||
}
|
||||
|
||||
int stdio_disable_nonblock(void) {
|
||||
int ret = 0;
|
||||
|
||||
/* stdin/stdout/stderr really should have O_NONBLOCK, which would confuse apps if left on, as
|
||||
* write()s might unexpectedly fail with EAGAIN. */
|
||||
|
||||
RET_GATHER(ret, fd_nonblock(STDIN_FILENO, false));
|
||||
RET_GATHER(ret, fd_nonblock(STDOUT_FILENO, false));
|
||||
RET_GATHER(ret, fd_nonblock(STDERR_FILENO, false));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fd_cloexec(int fd, bool cloexec) {
|
||||
int flags, nflags;
|
||||
|
||||
|
|
@ -176,32 +203,32 @@ int fd_cloexec(int fd, bool cloexec) {
|
|||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec) {
|
||||
int ret = 0, r;
|
||||
int r = 0;
|
||||
|
||||
assert(n_fds == 0 || fds);
|
||||
assert(fds || n_fds == 0);
|
||||
|
||||
for (size_t i = 0; i < n_fds; i++) {
|
||||
if (fds[i] < 0) /* Skip gracefully over already invalidated fds */
|
||||
FOREACH_ARRAY(fd, fds, n_fds) {
|
||||
if (*fd < 0) /* Skip gracefully over already invalidated fds */
|
||||
continue;
|
||||
|
||||
r = fd_cloexec(fds[i], cloexec);
|
||||
if (r < 0 && ret >= 0) /* Continue going, but return first error */
|
||||
ret = r;
|
||||
else
|
||||
ret = 1; /* report if we did anything */
|
||||
RET_GATHER(r, fd_cloexec(*fd, cloexec));
|
||||
|
||||
if (r >= 0)
|
||||
r = 1; /* report if we did anything */
|
||||
}
|
||||
|
||||
return ret;
|
||||
return r;
|
||||
}
|
||||
|
||||
_pure_ static bool fd_in_set(int fd, const int fdset[], size_t n_fdset) {
|
||||
assert(n_fdset == 0 || fdset);
|
||||
static bool fd_in_set(int fd, const int fds[], size_t n_fds) {
|
||||
assert(fd >= 0);
|
||||
assert(fds || n_fds == 0);
|
||||
|
||||
for (size_t i = 0; i < n_fdset; i++) {
|
||||
if (fdset[i] < 0)
|
||||
FOREACH_ARRAY(i, fds, n_fds) {
|
||||
if (*i < 0)
|
||||
continue;
|
||||
|
||||
if (fdset[i] == fd)
|
||||
if (*i == fd)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -232,7 +259,7 @@ int get_max_fd(void) {
|
|||
static int close_all_fds_frugal(const int except[], size_t n_except) {
|
||||
int max_fd, r = 0;
|
||||
|
||||
assert(n_except == 0 || except);
|
||||
assert(except || n_except == 0);
|
||||
|
||||
/* This is the inner fallback core of close_all_fds(). This never calls malloc() or opendir() or so
|
||||
* and hence is safe to be called in signal handler context. Most users should call close_all_fds(),
|
||||
|
|
@ -247,8 +274,7 @@ static int close_all_fds_frugal(const int except[], size_t n_except) {
|
|||
* spin the CPU for a long time. */
|
||||
if (max_fd > MAX_FD_LOOP_LIMIT)
|
||||
return log_debug_errno(SYNTHETIC_ERRNO(EPERM),
|
||||
"Refusing to loop over %d potential fds.",
|
||||
max_fd);
|
||||
"Refusing to loop over %d potential fds.", max_fd);
|
||||
|
||||
for (int fd = 3; fd >= 0; fd = fd < max_fd ? fd + 1 : -EBADF) {
|
||||
int q;
|
||||
|
|
@ -257,8 +283,8 @@ static int close_all_fds_frugal(const int except[], size_t n_except) {
|
|||
continue;
|
||||
|
||||
q = close_nointr(fd);
|
||||
if (q < 0 && q != -EBADF && r >= 0)
|
||||
r = q;
|
||||
if (q != -EBADF)
|
||||
RET_GATHER(r, q);
|
||||
}
|
||||
|
||||
return r;
|
||||
|
|
@ -589,7 +615,7 @@ int move_fd(int from, int to, int cloexec) {
|
|||
if (fl < 0)
|
||||
return -errno;
|
||||
|
||||
cloexec = !!(fl & FD_CLOEXEC);
|
||||
cloexec = FLAGS_SET(fl, FD_CLOEXEC);
|
||||
}
|
||||
|
||||
r = dup3(from, to, cloexec ? O_CLOEXEC : 0);
|
||||
|
|
@ -647,7 +673,7 @@ int rearrange_stdio(int original_input_fd, int original_output_fd, int original_
|
|||
original_output_fd,
|
||||
original_error_fd },
|
||||
null_fd = -EBADF, /* If we open /dev/null, we store the fd to it here */
|
||||
copy_fd[3] = { -EBADF, -EBADF, -EBADF }, /* This contains all fds we duplicate here
|
||||
copy_fd[3] = EBADF_TRIPLET, /* This contains all fds we duplicate here
|
||||
* temporarily, and hence need to close at the end. */
|
||||
r;
|
||||
bool null_readable, null_writable;
|
||||
|
|
@ -745,8 +771,7 @@ finish:
|
|||
safe_close_above_stdio(original_error_fd);
|
||||
|
||||
/* Close the copies we moved > 2 */
|
||||
for (int i = 0; i < 3; i++)
|
||||
safe_close(copy_fd[i]);
|
||||
close_many(copy_fd, 3);
|
||||
|
||||
/* Close our null fd, if it's > 2 */
|
||||
safe_close_above_stdio(null_fd);
|
||||
|
|
@ -756,9 +781,10 @@ finish:
|
|||
#endif /* NM_IGNORED */
|
||||
|
||||
int fd_reopen(int fd, int flags) {
|
||||
int new_fd, r;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0 || fd == AT_FDCWD);
|
||||
assert(!FLAGS_SET(flags, O_CREAT));
|
||||
|
||||
/* Reopens the specified fd with new flags. This is useful for convert an O_PATH fd into a regular one, or to
|
||||
* turn O_RDWR fds into O_RDONLY fds.
|
||||
|
|
@ -782,19 +808,12 @@ int fd_reopen(int fd, int flags) {
|
|||
* the same way as the non-O_DIRECTORY case. */
|
||||
return -ELOOP;
|
||||
|
||||
if (FLAGS_SET(flags, O_DIRECTORY) || fd == AT_FDCWD) {
|
||||
if (FLAGS_SET(flags, O_DIRECTORY) || fd == AT_FDCWD)
|
||||
/* If we shall reopen the fd as directory we can just go via "." and thus bypass the whole
|
||||
* magic /proc/ directory, and make ourselves independent of that being mounted. */
|
||||
new_fd = openat(fd, ".", flags | O_DIRECTORY);
|
||||
if (new_fd < 0)
|
||||
return -errno;
|
||||
return RET_NERRNO(openat(fd, ".", flags | O_DIRECTORY));
|
||||
|
||||
return new_fd;
|
||||
}
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
new_fd = open(FORMAT_PROC_FD_PATH(fd), flags);
|
||||
int new_fd = open(FORMAT_PROC_FD_PATH(fd), flags);
|
||||
if (new_fd < 0) {
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
|
|
@ -811,7 +830,6 @@ int fd_reopen(int fd, int flags) {
|
|||
return new_fd;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int fd_reopen_condition(
|
||||
int fd,
|
||||
int flags,
|
||||
|
|
@ -821,6 +839,7 @@ int fd_reopen_condition(
|
|||
int r, new_fd;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(!FLAGS_SET(flags, O_CREAT));
|
||||
|
||||
/* Invokes fd_reopen(fd, flags), but only if the existing F_GETFL flags don't match the specified
|
||||
* flags (masked by the specified mask). This is useful for converting O_PATH fds into real fds if
|
||||
|
|
@ -843,6 +862,7 @@ int fd_reopen_condition(
|
|||
return new_fd;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int fd_is_opath(int fd) {
|
||||
int r;
|
||||
|
||||
|
|
@ -901,34 +921,21 @@ int fd_get_diskseq(int fd, uint64_t *ret) {
|
|||
}
|
||||
|
||||
int path_is_root_at(int dir_fd, const char *path) {
|
||||
STRUCT_NEW_STATX_DEFINE(st);
|
||||
STRUCT_NEW_STATX_DEFINE(pst);
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
_cleanup_close_ int fd = -EBADF, pfd = -EBADF;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
if (!isempty(path)) {
|
||||
fd = openat(dir_fd, path, O_PATH|O_CLOEXEC);
|
||||
fd = openat(dir_fd, path, O_PATH|O_DIRECTORY|O_CLOEXEC);
|
||||
if (fd < 0)
|
||||
return -errno;
|
||||
return errno == ENOTDIR ? false : -errno;
|
||||
|
||||
dir_fd = fd;
|
||||
}
|
||||
|
||||
r = statx_fallback(dir_fd, ".", 0, STATX_TYPE|STATX_INO|STATX_MNT_ID, &st.sx);
|
||||
if (r == -ENOTDIR)
|
||||
return false;
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = statx_fallback(dir_fd, "..", 0, STATX_TYPE|STATX_INO|STATX_MNT_ID, &pst.sx);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* First, compare inode. If these are different, the fd does not point to the root directory "/". */
|
||||
if (!statx_inode_same(&st.sx, &pst.sx))
|
||||
return false;
|
||||
pfd = openat(dir_fd, "..", O_PATH|O_DIRECTORY|O_CLOEXEC);
|
||||
if (pfd < 0)
|
||||
return errno == ENOTDIR ? false : -errno;
|
||||
|
||||
/* Even if the parent directory has the same inode, the fd may not point to the root directory "/",
|
||||
* and we also need to check that the mount ids are the same. Otherwise, a construct like the
|
||||
|
|
@ -936,40 +943,64 @@ int path_is_root_at(int dir_fd, const char *path) {
|
|||
*
|
||||
* $ mkdir /tmp/x /tmp/x/y
|
||||
* $ mount --bind /tmp/x /tmp/x/y
|
||||
*
|
||||
* Note, statx() does not provide the mount ID and path_get_mnt_id_at() does not work when an old
|
||||
* kernel is used without /proc mounted. In that case, let's assume that we do not have such spurious
|
||||
* mount points in an early boot stage, and silently skip the following check. */
|
||||
*/
|
||||
|
||||
if (!FLAGS_SET(st.nsx.stx_mask, STATX_MNT_ID)) {
|
||||
return fds_are_same_mount(dir_fd, pfd);
|
||||
}
|
||||
|
||||
int fds_are_same_mount(int fd1, int fd2) {
|
||||
STRUCT_NEW_STATX_DEFINE(st1);
|
||||
STRUCT_NEW_STATX_DEFINE(st2);
|
||||
int r;
|
||||
|
||||
assert(fd1 >= 0);
|
||||
assert(fd2 >= 0);
|
||||
|
||||
r = statx_fallback(fd1, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &st1.sx);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = statx_fallback(fd2, "", AT_EMPTY_PATH, STATX_TYPE|STATX_INO|STATX_MNT_ID, &st2.sx);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
/* First, compare inode. If these are different, the fd does not point to the root directory "/". */
|
||||
if (!statx_inode_same(&st1.sx, &st2.sx))
|
||||
return false;
|
||||
|
||||
/* Note, statx() does not provide the mount ID and path_get_mnt_id_at() does not work when an old
|
||||
* kernel is used. In that case, let's assume that we do not have such spurious mount points in an
|
||||
* early boot stage, and silently skip the following check. */
|
||||
|
||||
if (!FLAGS_SET(st1.nsx.stx_mask, STATX_MNT_ID)) {
|
||||
int mntid;
|
||||
|
||||
r = path_get_mnt_id_at(dir_fd, "", &mntid);
|
||||
if (r == -ENOSYS)
|
||||
r = path_get_mnt_id_at_fallback(fd1, "", &mntid);
|
||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
return true; /* skip the mount ID check */
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(mntid >= 0);
|
||||
|
||||
st.nsx.stx_mnt_id = mntid;
|
||||
st.nsx.stx_mask |= STATX_MNT_ID;
|
||||
st1.nsx.stx_mnt_id = mntid;
|
||||
st1.nsx.stx_mask |= STATX_MNT_ID;
|
||||
}
|
||||
|
||||
if (!FLAGS_SET(pst.nsx.stx_mask, STATX_MNT_ID)) {
|
||||
if (!FLAGS_SET(st2.nsx.stx_mask, STATX_MNT_ID)) {
|
||||
int mntid;
|
||||
|
||||
r = path_get_mnt_id_at(dir_fd, "..", &mntid);
|
||||
if (r == -ENOSYS)
|
||||
r = path_get_mnt_id_at_fallback(fd2, "", &mntid);
|
||||
if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
|
||||
return true; /* skip the mount ID check */
|
||||
if (r < 0)
|
||||
return r;
|
||||
assert(mntid >= 0);
|
||||
|
||||
pst.nsx.stx_mnt_id = mntid;
|
||||
pst.nsx.stx_mask |= STATX_MNT_ID;
|
||||
st2.nsx.stx_mnt_id = mntid;
|
||||
st2.nsx.stx_mask |= STATX_MNT_ID;
|
||||
}
|
||||
|
||||
return statx_mount_same(&st.nsx, &pst.nsx);
|
||||
return statx_mount_same(&st1.nsx, &st2.nsx);
|
||||
}
|
||||
|
||||
const char *accmode_to_string(int flags) {
|
||||
|
|
@ -984,4 +1015,12 @@ const char *accmode_to_string(int flags) {
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid, int fd) {
|
||||
assert(buf);
|
||||
assert(fd >= 0);
|
||||
assert(pid >= 0);
|
||||
assert_se(snprintf_ok(buf, PROC_PID_FD_PATH_MAX, "/proc/" PID_FMT "/fd/%i", pid == 0 ? getpid_cached() : pid, fd));
|
||||
return buf;
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -16,7 +16,10 @@
|
|||
/* Make sure we can distinguish fd 0 and NULL */
|
||||
#define FD_TO_PTR(fd) INT_TO_PTR((fd)+1)
|
||||
#define PTR_TO_FD(p) (PTR_TO_INT(p)-1)
|
||||
#define PIPE_EBADF { -EBADF, -EBADF }
|
||||
|
||||
/* Useful helpers for initializing pipe(), socketpair() or stdio fd arrays */
|
||||
#define EBADF_PAIR { -EBADF, -EBADF }
|
||||
#define EBADF_TRIPLET { -EBADF, -EBADF, -EBADF }
|
||||
|
||||
int close_nointr(int fd);
|
||||
int safe_close(int fd);
|
||||
|
|
@ -29,7 +32,9 @@ static inline int safe_close_above_stdio(int fd) {
|
|||
return safe_close(fd);
|
||||
}
|
||||
|
||||
void close_many(const int fds[], size_t n_fd);
|
||||
void close_many(const int fds[], size_t n_fds);
|
||||
void close_many_unset(int fds[], size_t n_fds);
|
||||
void close_many_and_free(int *fds, size_t n_fds);
|
||||
|
||||
int fclose_nointr(FILE *f);
|
||||
FILE* safe_fclose(FILE *f);
|
||||
|
|
@ -47,6 +52,11 @@ static inline void fclosep(FILE **f) {
|
|||
safe_fclose(*f);
|
||||
}
|
||||
|
||||
static inline void* close_fd_ptr(void *p) {
|
||||
safe_close(PTR_TO_FD(p));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(FILE*, pclose, NULL);
|
||||
DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL);
|
||||
|
||||
|
|
@ -57,6 +67,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC_FULL(DIR*, closedir, NULL);
|
|||
#define _cleanup_close_pair_ _cleanup_(close_pairp)
|
||||
|
||||
int fd_nonblock(int fd, bool nonblock);
|
||||
int stdio_disable_nonblock(void);
|
||||
|
||||
int fd_cloexec(int fd, bool cloexec);
|
||||
int fd_cloexec_many(const int fds[], size_t n_fds, bool cloexec);
|
||||
|
||||
|
|
@ -102,6 +114,9 @@ int read_nr_open(void);
|
|||
int fd_get_diskseq(int fd, uint64_t *ret);
|
||||
|
||||
int path_is_root_at(int dir_fd, const char *path);
|
||||
static inline int path_is_root(const char *path) {
|
||||
return path_is_root_at(AT_FDCWD, path);
|
||||
}
|
||||
static inline int dir_fd_is_root(int dir_fd) {
|
||||
return path_is_root_at(dir_fd, NULL);
|
||||
}
|
||||
|
|
@ -109,6 +124,8 @@ static inline int dir_fd_is_root_or_cwd(int dir_fd) {
|
|||
return dir_fd == AT_FDCWD ? true : path_is_root_at(dir_fd, NULL);
|
||||
}
|
||||
|
||||
int fds_are_same_mount(int fd1, int fd2);
|
||||
|
||||
/* The maximum length a buffer for a /proc/self/fd/<fd> path needs */
|
||||
#define PROC_FD_PATH_MAX \
|
||||
(STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int))
|
||||
|
|
@ -123,6 +140,16 @@ static inline char *format_proc_fd_path(char buf[static PROC_FD_PATH_MAX], int f
|
|||
#define FORMAT_PROC_FD_PATH(fd) \
|
||||
format_proc_fd_path((char[PROC_FD_PATH_MAX]) {}, (fd))
|
||||
|
||||
/* The maximum length a buffer for a /proc/<pid>/fd/<fd> path needs */
|
||||
#define PROC_PID_FD_PATH_MAX \
|
||||
(STRLEN("/proc//fd/") + DECIMAL_STR_MAX(pid_t) + DECIMAL_STR_MAX(int))
|
||||
|
||||
char *format_proc_pid_fd_path(char buf[static PROC_PID_FD_PATH_MAX], pid_t pid, int fd);
|
||||
|
||||
/* Kinda the same as FORMAT_PROC_FD_PATH(), but goes by PID rather than "self" symlink */
|
||||
#define FORMAT_PROC_PID_FD_PATH(pid, fd) \
|
||||
format_proc_pid_fd_path((char[PROC_PID_FD_PATH_MAX]) {}, (pid), (fd))
|
||||
|
||||
const char *accmode_to_string(int flags);
|
||||
|
||||
/* Like ASSERT_PTR, but for fds */
|
||||
|
|
|
|||
|
|
@ -30,10 +30,13 @@
|
|||
#include "stdio-util.h"
|
||||
#include "string-util.h"
|
||||
#include "sync-util.h"
|
||||
#include "terminal-util.h"
|
||||
#include "tmpfile-util.h"
|
||||
|
||||
/* The maximum size of the file we'll read in one go in read_full_file() (64M). */
|
||||
#define READ_FULL_BYTES_MAX (64U*1024U*1024U - 1U)
|
||||
/* Used when a size is specified for read_full_file() with READ_FULL_FILE_UNBASE64 or _UNHEX */
|
||||
#define READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY 3
|
||||
|
||||
/* The maximum size of virtual files (i.e. procfs, sysfs, and other virtual "API" files) we'll read in one go
|
||||
* in read_virtual_file(). Note that this limit is different (and much lower) than the READ_FULL_BYTES_MAX
|
||||
|
|
@ -200,6 +203,19 @@ int write_string_stream_ts(
|
|||
return 0;
|
||||
}
|
||||
|
||||
static mode_t write_string_file_flags_to_mode(WriteStringFileFlags flags) {
|
||||
|
||||
/* We support three different modes, that are the ones that really make sense for text files like this:
|
||||
*
|
||||
* → 0600 (i.e. root-only)
|
||||
* → 0444 (i.e. read-only)
|
||||
* → 0644 (i.e. writable for root, readable for everyone else)
|
||||
*/
|
||||
|
||||
return FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 :
|
||||
FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0444) ? 0444 : 0644;
|
||||
}
|
||||
|
||||
static int write_string_file_atomic_at(
|
||||
int dir_fd,
|
||||
const char *fn,
|
||||
|
|
@ -225,7 +241,7 @@ static int write_string_file_atomic_at(
|
|||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
r = fchmod_umask(fileno(f), FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0644);
|
||||
r = fchmod_umask(fileno(f), write_string_file_flags_to_mode(flags));
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
|
|
@ -288,7 +304,7 @@ int write_string_file_ts_at(
|
|||
(FLAGS_SET(flags, WRITE_STRING_FILE_CREATE) ? O_CREAT : 0) |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_TRUNCATE) ? O_TRUNC : 0) |
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL) ? O_RDWR : O_WRONLY),
|
||||
(FLAGS_SET(flags, WRITE_STRING_FILE_MODE_0600) ? 0600 : 0666));
|
||||
write_string_file_flags_to_mode(flags));
|
||||
if (fd < 0) {
|
||||
r = -errno;
|
||||
goto fail;
|
||||
|
|
@ -576,7 +592,7 @@ int read_full_stream_full(
|
|||
size_t *ret_size) {
|
||||
|
||||
_cleanup_free_ char *buf = NULL;
|
||||
size_t n, n_next = 0, l;
|
||||
size_t n, n_next = 0, l, expected_decoded_size = size;
|
||||
int fd, r;
|
||||
|
||||
assert(f);
|
||||
|
|
@ -587,6 +603,13 @@ int read_full_stream_full(
|
|||
if (offset != UINT64_MAX && offset > LONG_MAX) /* fseek() can only deal with "long" offsets */
|
||||
return -ERANGE;
|
||||
|
||||
if ((flags & (READ_FULL_FILE_UNBASE64 | READ_FULL_FILE_UNHEX)) != 0) {
|
||||
if (size <= SIZE_MAX / READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY)
|
||||
size *= READ_FULL_FILE_ENCODED_STRING_AMPLIFICATION_BOUNDARY;
|
||||
else
|
||||
size = SIZE_MAX;
|
||||
}
|
||||
|
||||
fd = fileno(f);
|
||||
if (fd >= 0) { /* If the FILE* object is backed by an fd (as opposed to memory or such, see
|
||||
* fmemopen()), let's optimize our buffering */
|
||||
|
|
@ -711,6 +734,11 @@ int read_full_stream_full(
|
|||
explicit_bzero_safe(buf, n);
|
||||
free_and_replace(buf, decoded);
|
||||
n = l = decoded_size;
|
||||
|
||||
if (FLAGS_SET(flags, READ_FULL_FILE_FAIL_WHEN_LARGER) && l > expected_decoded_size) {
|
||||
r = -E2BIG;
|
||||
goto finalize;
|
||||
}
|
||||
}
|
||||
|
||||
if (!ret_size) {
|
||||
|
|
@ -1057,7 +1085,9 @@ int fdopen_independent(int fd, const char *mode, FILE **ret) {
|
|||
if (mode_flags < 0)
|
||||
return mode_flags;
|
||||
|
||||
copy_fd = fd_reopen(fd, mode_flags);
|
||||
/* Flags returned by fopen_mode_to_flags might contain O_CREAT, but it doesn't make sense for fd_reopen
|
||||
* since we're working on an existing fd anyway. Let's drop it here to avoid triggering assertion. */
|
||||
copy_fd = fd_reopen(fd, mode_flags & ~O_CREAT);
|
||||
if (copy_fd < 0)
|
||||
return copy_fd;
|
||||
|
||||
|
|
@ -1069,123 +1099,171 @@ int fdopen_independent(int fd, const char *mode, FILE **ret) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int search_and_fopen_internal(
|
||||
static int search_and_open_internal(
|
||||
const char *path,
|
||||
const char *mode,
|
||||
int mode, /* if ret_fd is NULL this is an [FRWX]_OK mode for access(), otherwise an open mode for open() */
|
||||
const char *root,
|
||||
char **search,
|
||||
FILE **ret,
|
||||
int *ret_fd,
|
||||
char **ret_path) {
|
||||
|
||||
int r;
|
||||
|
||||
assert(!ret_fd || !FLAGS_SET(mode, O_CREAT)); /* We don't support O_CREAT for this */
|
||||
assert(path);
|
||||
assert(mode);
|
||||
assert(ret);
|
||||
|
||||
if (path_is_absolute(path)) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
|
||||
if (ret_fd)
|
||||
/* We only specify 0777 here to appease static analyzers, it's never used since we
|
||||
* don't support O_CREAT here */
|
||||
r = fd = RET_NERRNO(open(path, mode, 0777));
|
||||
else
|
||||
r = RET_NERRNO(access(path, mode));
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_path) {
|
||||
r = path_simplify_alloc(path, ret_path);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
|
||||
if (ret_fd)
|
||||
*ret_fd = TAKE_FD(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!path_strv_resolve_uniq(search, root))
|
||||
return -ENOMEM;
|
||||
|
||||
STRV_FOREACH(i, search) {
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
_cleanup_free_ char *p = NULL;
|
||||
FILE *f;
|
||||
|
||||
p = path_join(root, *i, path);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
f = fopen(p, mode);
|
||||
if (f) {
|
||||
if (ret_fd)
|
||||
/* as above, 0777 is static analyzer appeasement */
|
||||
r = fd = RET_NERRNO(open(p, mode, 0777));
|
||||
else
|
||||
r = RET_NERRNO(access(p, F_OK));
|
||||
if (r >= 0) {
|
||||
if (ret_path)
|
||||
*ret_path = path_simplify(TAKE_PTR(p));
|
||||
|
||||
*ret = f;
|
||||
if (ret_fd)
|
||||
*ret_fd = TAKE_FD(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (errno != ENOENT)
|
||||
return -errno;
|
||||
if (r != -ENOENT)
|
||||
return r;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
int search_and_fopen(
|
||||
const char *filename,
|
||||
const char *mode,
|
||||
int search_and_open(
|
||||
const char *path,
|
||||
int mode,
|
||||
const char *root,
|
||||
const char **search,
|
||||
FILE **ret,
|
||||
char **search,
|
||||
int *ret_fd,
|
||||
char **ret_path) {
|
||||
|
||||
_cleanup_strv_free_ char **copy = NULL;
|
||||
|
||||
assert(filename);
|
||||
assert(mode);
|
||||
assert(ret);
|
||||
|
||||
if (path_is_absolute(filename)) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
|
||||
f = fopen(filename, mode);
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
if (ret_path) {
|
||||
char *p;
|
||||
|
||||
p = strdup(filename);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_path = path_simplify(p);
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(f);
|
||||
return 0;
|
||||
}
|
||||
assert(path);
|
||||
|
||||
copy = strv_copy((char**) search);
|
||||
if (!copy)
|
||||
return -ENOMEM;
|
||||
|
||||
return search_and_fopen_internal(filename, mode, root, copy, ret, ret_path);
|
||||
return search_and_open_internal(path, mode, root, copy, ret_fd, ret_path);
|
||||
}
|
||||
|
||||
int search_and_fopen_nulstr(
|
||||
const char *filename,
|
||||
static int search_and_fopen_internal(
|
||||
const char *path,
|
||||
const char *mode,
|
||||
const char *root,
|
||||
const char *search,
|
||||
FILE **ret,
|
||||
char **search,
|
||||
FILE **ret_file,
|
||||
char **ret_path) {
|
||||
|
||||
_cleanup_strv_free_ char **s = NULL;
|
||||
_cleanup_free_ char *found_path = NULL;
|
||||
_cleanup_close_ int fd = -EBADF;
|
||||
int r;
|
||||
|
||||
if (path_is_absolute(filename)) {
|
||||
_cleanup_fclose_ FILE *f = NULL;
|
||||
assert(path);
|
||||
assert(mode || !ret_file);
|
||||
|
||||
f = fopen(filename, mode);
|
||||
r = search_and_open(
|
||||
path,
|
||||
mode ? fopen_mode_to_flags(mode) : 0,
|
||||
root,
|
||||
search,
|
||||
ret_file ? &fd : NULL,
|
||||
ret_path ? &found_path : NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret_file) {
|
||||
FILE *f = take_fdopen(&fd, mode);
|
||||
if (!f)
|
||||
return -errno;
|
||||
|
||||
if (ret_path) {
|
||||
char *p;
|
||||
|
||||
p = strdup(filename);
|
||||
if (!p)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret_path = path_simplify(p);
|
||||
}
|
||||
|
||||
*ret = TAKE_PTR(f);
|
||||
return 0;
|
||||
*ret_file = f;
|
||||
}
|
||||
|
||||
s = strv_split_nulstr(search);
|
||||
if (!s)
|
||||
if (ret_path)
|
||||
*ret_path = TAKE_PTR(found_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int search_and_fopen(
|
||||
const char *path,
|
||||
const char *mode,
|
||||
const char *root,
|
||||
const char **search,
|
||||
FILE **ret_file,
|
||||
char **ret_path) {
|
||||
|
||||
_cleanup_strv_free_ char **copy = NULL;
|
||||
|
||||
assert(path);
|
||||
assert(mode || !ret_file);
|
||||
|
||||
copy = strv_copy((char**) search);
|
||||
if (!copy)
|
||||
return -ENOMEM;
|
||||
|
||||
return search_and_fopen_internal(filename, mode, root, s, ret, ret_path);
|
||||
return search_and_fopen_internal(path, mode, root, copy, ret_file, ret_path);
|
||||
}
|
||||
|
||||
int search_and_fopen_nulstr(
|
||||
const char *path,
|
||||
const char *mode,
|
||||
const char *root,
|
||||
const char *search,
|
||||
FILE **ret_file,
|
||||
char **ret_path) {
|
||||
|
||||
_cleanup_strv_free_ char **l = NULL;
|
||||
|
||||
assert(path);
|
||||
assert(mode || !ret_file);
|
||||
|
||||
l = strv_split_nulstr(search);
|
||||
if (!l)
|
||||
return -ENOMEM;
|
||||
|
||||
return search_and_fopen_internal(path, mode, root, l, ret_file, ret_path);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
|
|
@ -1259,33 +1337,31 @@ int read_timestamp_file(const char *fn, usec_t *ret) {
|
|||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
||||
int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space) {
|
||||
int r;
|
||||
|
||||
int fputs_with_separator(FILE *f, const char *s, const char *separator, bool *space) {
|
||||
assert(s);
|
||||
assert(space);
|
||||
|
||||
/* Outputs the specified string with fputs(), but optionally prefixes it with a separator. The *space parameter
|
||||
* when specified shall initially point to a boolean variable initialized to false. It is set to true after the
|
||||
* first invocation. This call is supposed to be use in loops, where a separator shall be inserted between each
|
||||
* element, but not before the first one. */
|
||||
/* Outputs the specified string with fputs(), but optionally prefixes it with a separator.
|
||||
* The *space parameter when specified shall initially point to a boolean variable initialized
|
||||
* to false. It is set to true after the first invocation. This call is supposed to be use in loops,
|
||||
* where a separator shall be inserted between each element, but not before the first one. */
|
||||
|
||||
if (!f)
|
||||
f = stdout;
|
||||
|
||||
if (space) {
|
||||
if (!separator)
|
||||
separator = " ";
|
||||
if (!separator)
|
||||
separator = " ";
|
||||
|
||||
if (*space) {
|
||||
r = fputs(separator, f);
|
||||
if (r < 0)
|
||||
return r;
|
||||
}
|
||||
if (*space)
|
||||
if (fputs(separator, f) < 0)
|
||||
return -EIO;
|
||||
|
||||
*space = true;
|
||||
}
|
||||
*space = true;
|
||||
|
||||
return fputs(s, f);
|
||||
if (fputs(s, f) < 0)
|
||||
return -EIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
|
|
@ -1406,7 +1482,7 @@ int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
|
|||
* and don't call isatty() on an invalid fd */
|
||||
flags |= READ_LINE_NOT_A_TTY;
|
||||
else
|
||||
flags |= isatty(fd) ? READ_LINE_IS_A_TTY : READ_LINE_NOT_A_TTY;
|
||||
flags |= isatty_safe(fd) ? READ_LINE_IS_A_TTY : READ_LINE_NOT_A_TTY;
|
||||
}
|
||||
if (FLAGS_SET(flags, READ_LINE_IS_A_TTY))
|
||||
break;
|
||||
|
|
@ -1437,6 +1513,36 @@ int read_line_full(FILE *f, size_t limit, ReadLineFlags flags, char **ret) {
|
|||
return (int) count;
|
||||
}
|
||||
|
||||
int read_stripped_line(FILE *f, size_t limit, char **ret) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
int r;
|
||||
|
||||
assert(f);
|
||||
|
||||
r = read_line(f, limit, ret ? &s : NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (ret) {
|
||||
const char *p;
|
||||
|
||||
p = strstrip(s);
|
||||
if (p == s)
|
||||
*ret = TAKE_PTR(s);
|
||||
else {
|
||||
char *copy;
|
||||
|
||||
copy = strdup(p);
|
||||
if (!copy)
|
||||
return -ENOMEM;
|
||||
|
||||
*ret = copy;
|
||||
}
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int safe_fgetc(FILE *f, char *ret) {
|
||||
int k;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ typedef enum {
|
|||
WRITE_STRING_FILE_NOFOLLOW = 1 << 8,
|
||||
WRITE_STRING_FILE_MKDIR_0755 = 1 << 9,
|
||||
WRITE_STRING_FILE_MODE_0600 = 1 << 10,
|
||||
WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL = 1 << 11,
|
||||
WRITE_STRING_FILE_MODE_0444 = 1 << 11,
|
||||
WRITE_STRING_FILE_SUPPRESS_REDUNDANT_VIRTUAL = 1 << 12,
|
||||
|
||||
/* And before you wonder, why write_string_file_atomic_label_ts() is a separate function instead of just one
|
||||
more flag here: it's about linking: we don't want to pull -lselinux into all users of write_string_file()
|
||||
|
|
@ -129,8 +130,12 @@ static inline int fopen_unlocked(const char *path, const char *mode, FILE **ret)
|
|||
|
||||
int fdopen_independent(int fd, const char *mode, FILE **ret);
|
||||
|
||||
int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **ret, char **ret_path);
|
||||
int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **ret, char **ret_path);
|
||||
int search_and_open(const char *path, int mode, const char *root, char **search, int *ret_fd, char **ret_path);
|
||||
static inline int search_and_access(const char *path, int mode, const char *root, char**search, char **ret_path) {
|
||||
return search_and_open(path, mode, root, search, NULL, ret_path);
|
||||
}
|
||||
int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **ret_file, char **ret_path);
|
||||
int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **ret_file, char **ret_path);
|
||||
|
||||
int fflush_and_check(FILE *f);
|
||||
int fflush_sync_and_check(FILE *f);
|
||||
|
|
@ -138,7 +143,7 @@ int fflush_sync_and_check(FILE *f);
|
|||
int write_timestamp_file_atomic(const char *fn, usec_t n);
|
||||
int read_timestamp_file(const char *fn, usec_t *ret);
|
||||
|
||||
int fputs_with_space(FILE *f, const char *s, const char *separator, bool *space);
|
||||
int fputs_with_separator(FILE *f, const char *s, const char *separator, bool *space);
|
||||
|
||||
typedef enum ReadLineFlags {
|
||||
READ_LINE_ONLY_NUL = 1 << 0,
|
||||
|
|
@ -162,6 +167,8 @@ static inline int read_nul_string(FILE *f, size_t limit, char **ret) {
|
|||
return read_line_full(f, limit, READ_LINE_ONLY_NUL, ret);
|
||||
}
|
||||
|
||||
int read_stripped_line(FILE *f, size_t limit, char **ret);
|
||||
|
||||
int safe_fgetc(FILE *f, char *ret);
|
||||
|
||||
int warn_file_is_world_accessible(const char *filename, struct stat *st, const char *unit, unsigned line);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "btrfs.h"
|
||||
#include "dirent-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "fileio.h"
|
||||
|
|
@ -292,8 +293,22 @@ int fchmod_umask(int fd, mode_t m) {
|
|||
|
||||
int fchmod_opath(int fd, mode_t m) {
|
||||
/* This function operates also on fd that might have been opened with
|
||||
* O_PATH. Indeed fchmodat() doesn't have the AT_EMPTY_PATH flag like
|
||||
* fchownat() does. */
|
||||
* O_PATH. The tool set we have is non-intuitive:
|
||||
* - fchmod(2) only operates on open files (i. e., fds with an open file description);
|
||||
* - fchmodat(2) does not have a flag arg like fchownat(2) does, so no way to pass AT_EMPTY_PATH;
|
||||
* + it should not be confused with the libc fchmodat(3) interface, which adds 4th flag argument,
|
||||
* but does not support AT_EMPTY_PATH (only supports AT_SYMLINK_NOFOLLOW);
|
||||
* - fchmodat2(2) supports all the AT_* flags, but is still very recent.
|
||||
*
|
||||
* We try to use fchmodat2(), and, if it is not supported, resort
|
||||
* to the /proc/self/fd dance. */
|
||||
|
||||
assert(fd >= 0);
|
||||
|
||||
if (fchmodat2(fd, "", m, AT_EMPTY_PATH) >= 0)
|
||||
return 0;
|
||||
if (!IN_SET(errno, ENOSYS, EPERM)) /* Some container managers block unknown syscalls with EPERM */
|
||||
return -errno;
|
||||
|
||||
if (chmod(FORMAT_PROC_FD_PATH(fd), m) < 0) {
|
||||
if (errno != ENOENT)
|
||||
|
|
@ -1108,6 +1123,16 @@ int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags
|
|||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
|
||||
/* This is like openat(), but has a few tricks up its sleeves, extending behaviour:
|
||||
*
|
||||
* • O_DIRECTORY|O_CREAT is supported, which causes a directory to be created, and immediately
|
||||
* opened. When used with the XO_SUBVOLUME flag this will even create a btrfs subvolume.
|
||||
*
|
||||
* • If O_CREAT is used with XO_LABEL, any created file will be immediately relabelled.
|
||||
*
|
||||
* • If the path is specified NULL or empty, behaves like fd_reopen().
|
||||
*/
|
||||
|
||||
if (isempty(path)) {
|
||||
assert(!FLAGS_SET(open_flags, O_CREAT|O_EXCL));
|
||||
return fd_reopen(dir_fd, open_flags & ~O_NOFOLLOW);
|
||||
|
|
@ -1120,7 +1145,10 @@ int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags
|
|||
}
|
||||
|
||||
if (FLAGS_SET(open_flags, O_DIRECTORY|O_CREAT)) {
|
||||
r = RET_NERRNO(mkdirat(dir_fd, path, mode));
|
||||
if (FLAGS_SET(xopen_flags, XO_SUBVOLUME))
|
||||
r = btrfs_subvol_make_fallback(dir_fd, path, mode);
|
||||
else
|
||||
r = RET_NERRNO(mkdirat(dir_fd, path, mode));
|
||||
if (r == -EEXIST) {
|
||||
if (FLAGS_SET(open_flags, O_EXCL))
|
||||
return -EEXIST;
|
||||
|
|
@ -1183,12 +1211,11 @@ int xopenat_lock(
|
|||
int r;
|
||||
|
||||
assert(dir_fd >= 0 || dir_fd == AT_FDCWD);
|
||||
assert(path);
|
||||
assert(IN_SET(operation & ~LOCK_NB, LOCK_EX, LOCK_SH));
|
||||
|
||||
/* POSIX/UNPOSIX locks don't work on directories (errno is set to -EBADF so let's return early with
|
||||
* the same error here). */
|
||||
if (FLAGS_SET(open_flags, O_DIRECTORY) && locktype != LOCK_BSD)
|
||||
if (FLAGS_SET(open_flags, O_DIRECTORY) && !IN_SET(locktype, LOCK_BSD, LOCK_NONE))
|
||||
return -EBADF;
|
||||
|
||||
for (;;) {
|
||||
|
|
|
|||
|
|
@ -133,7 +133,8 @@ int open_mkdir_at(int dirfd, const char *path, int flags, mode_t mode);
|
|||
int openat_report_new(int dirfd, const char *pathname, int flags, mode_t mode, bool *ret_newly_created);
|
||||
|
||||
typedef enum XOpenFlags {
|
||||
XO_LABEL = 1 << 0,
|
||||
XO_LABEL = 1 << 0,
|
||||
XO_SUBVOLUME = 1 << 1,
|
||||
} XOpenFlags;
|
||||
|
||||
int xopenat(int dir_fd, const char *path, int open_flags, XOpenFlags xopen_flags, mode_t mode);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ bool emoji_enabled(void) {
|
|||
return cached_emoji_enabled;
|
||||
}
|
||||
|
||||
const char *special_glyph(SpecialGlyph code) {
|
||||
const char *special_glyph_full(SpecialGlyph code, bool force_utf) {
|
||||
|
||||
/* A list of a number of interesting unicode glyphs we can use to decorate our output. It's probably wise to be
|
||||
* conservative here, and primarily stick to the glyphs defined in the eurlatgr font, so that display still
|
||||
|
|
@ -54,11 +54,12 @@ const char *special_glyph(SpecialGlyph code) {
|
|||
[SPECIAL_GLYPH_CROSS_MARK] = "-",
|
||||
[SPECIAL_GLYPH_LIGHT_SHADE] = "-",
|
||||
[SPECIAL_GLYPH_DARK_SHADE] = "X",
|
||||
[SPECIAL_GLYPH_FULL_BLOCK] = "#",
|
||||
[SPECIAL_GLYPH_SIGMA] = "S",
|
||||
[SPECIAL_GLYPH_ARROW_LEFT] = "<-",
|
||||
[SPECIAL_GLYPH_ARROW_RIGHT] = "->",
|
||||
[SPECIAL_GLYPH_ARROW_UP] = "^",
|
||||
[SPECIAL_GLYPH_ARROW_DOWN] = "v",
|
||||
[SPECIAL_GLYPH_ARROW_LEFT] = "<-",
|
||||
[SPECIAL_GLYPH_ARROW_RIGHT] = "->",
|
||||
[SPECIAL_GLYPH_ELLIPSIS] = "...",
|
||||
[SPECIAL_GLYPH_EXTERNAL_LINK] = "[LNK]",
|
||||
[SPECIAL_GLYPH_ECSTATIC_SMILEY] = ":-]",
|
||||
|
|
@ -73,6 +74,7 @@ const char *special_glyph(SpecialGlyph code) {
|
|||
[SPECIAL_GLYPH_RECYCLING] = "~",
|
||||
[SPECIAL_GLYPH_DOWNLOAD] = "\\",
|
||||
[SPECIAL_GLYPH_SPARKLES] = "*",
|
||||
[SPECIAL_GLYPH_LOW_BATTERY] = "!",
|
||||
[SPECIAL_GLYPH_WARNING_SIGN] = "!",
|
||||
},
|
||||
|
||||
|
|
@ -98,6 +100,7 @@ const char *special_glyph(SpecialGlyph code) {
|
|||
[SPECIAL_GLYPH_CROSS_MARK] = u8"✗", /* actually called: BALLOT X */
|
||||
[SPECIAL_GLYPH_LIGHT_SHADE] = u8"░",
|
||||
[SPECIAL_GLYPH_DARK_SHADE] = u8"▒",
|
||||
[SPECIAL_GLYPH_FULL_BLOCK] = u8"█",
|
||||
[SPECIAL_GLYPH_SIGMA] = u8"Σ",
|
||||
[SPECIAL_GLYPH_ARROW_UP] = u8"↑", /* actually called: UPWARDS ARROW */
|
||||
[SPECIAL_GLYPH_ARROW_DOWN] = u8"↓", /* actually called: DOWNWARDS ARROW */
|
||||
|
|
@ -131,7 +134,10 @@ const char *special_glyph(SpecialGlyph code) {
|
|||
[SPECIAL_GLYPH_RECYCLING] = u8"♻️", /* actually called: UNIVERSAL RECYCLNG SYMBOL */
|
||||
[SPECIAL_GLYPH_DOWNLOAD] = u8"⤵️", /* actually called: RIGHT ARROW CURVING DOWN */
|
||||
[SPECIAL_GLYPH_SPARKLES] = u8"✨",
|
||||
[SPECIAL_GLYPH_LOW_BATTERY] = u8"🪫",
|
||||
[SPECIAL_GLYPH_WARNING_SIGN] = u8"⚠️",
|
||||
[SPECIAL_GLYPH_COMPUTER_DISK] = u8"💽",
|
||||
[SPECIAL_GLYPH_WORLD] = u8"🌍",
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -139,5 +145,5 @@ const char *special_glyph(SpecialGlyph code) {
|
|||
return NULL;
|
||||
|
||||
assert(code < _SPECIAL_GLYPH_MAX);
|
||||
return draw_table[code >= _SPECIAL_GLYPH_FIRST_EMOJI ? emoji_enabled() : is_locale_utf8()][code];
|
||||
return draw_table[force_utf || (code >= _SPECIAL_GLYPH_FIRST_EMOJI ? emoji_enabled() : is_locale_utf8())][code];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,14 +22,15 @@ typedef enum SpecialGlyph {
|
|||
SPECIAL_GLYPH_MU,
|
||||
SPECIAL_GLYPH_CHECK_MARK,
|
||||
SPECIAL_GLYPH_CROSS_MARK,
|
||||
SPECIAL_GLYPH_ARROW_LEFT,
|
||||
SPECIAL_GLYPH_ARROW_RIGHT,
|
||||
SPECIAL_GLYPH_ARROW_UP,
|
||||
SPECIAL_GLYPH_ARROW_DOWN,
|
||||
SPECIAL_GLYPH_ELLIPSIS,
|
||||
SPECIAL_GLYPH_LIGHT_SHADE,
|
||||
SPECIAL_GLYPH_DARK_SHADE,
|
||||
SPECIAL_GLYPH_FULL_BLOCK,
|
||||
SPECIAL_GLYPH_SIGMA,
|
||||
SPECIAL_GLYPH_ARROW_UP,
|
||||
SPECIAL_GLYPH_ARROW_DOWN,
|
||||
SPECIAL_GLYPH_ARROW_LEFT,
|
||||
SPECIAL_GLYPH_ARROW_RIGHT,
|
||||
SPECIAL_GLYPH_ELLIPSIS,
|
||||
SPECIAL_GLYPH_EXTERNAL_LINK,
|
||||
_SPECIAL_GLYPH_FIRST_EMOJI,
|
||||
SPECIAL_GLYPH_ECSTATIC_SMILEY = _SPECIAL_GLYPH_FIRST_EMOJI,
|
||||
|
|
@ -44,15 +45,22 @@ typedef enum SpecialGlyph {
|
|||
SPECIAL_GLYPH_RECYCLING,
|
||||
SPECIAL_GLYPH_DOWNLOAD,
|
||||
SPECIAL_GLYPH_SPARKLES,
|
||||
SPECIAL_GLYPH_LOW_BATTERY,
|
||||
SPECIAL_GLYPH_WARNING_SIGN,
|
||||
SPECIAL_GLYPH_COMPUTER_DISK,
|
||||
SPECIAL_GLYPH_WORLD,
|
||||
_SPECIAL_GLYPH_MAX,
|
||||
_SPECIAL_GLYPH_INVALID = -EINVAL,
|
||||
} SpecialGlyph;
|
||||
|
||||
const char *special_glyph(SpecialGlyph code) _const_;
|
||||
|
||||
bool emoji_enabled(void);
|
||||
|
||||
const char *special_glyph_full(SpecialGlyph code, bool force_utf) _const_;
|
||||
|
||||
static inline const char *special_glyph(SpecialGlyph code) {
|
||||
return special_glyph_full(code, false);
|
||||
}
|
||||
|
||||
static inline const char *special_glyph_check_mark(bool b) {
|
||||
return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ void path_hash_func(const char *q, struct siphash *state) {
|
|||
|
||||
/* if path is absolute, add one "/" to the hash. */
|
||||
if (path_is_absolute(q))
|
||||
siphash24_compress("/", 1, state);
|
||||
siphash24_compress_byte('/', state);
|
||||
|
||||
for (;;) {
|
||||
const char *e;
|
||||
|
|
@ -71,7 +71,7 @@ DEFINE_HASH_OPS_FULL(path_hash_ops_free_free,
|
|||
#endif /* NM_IGNORED */
|
||||
|
||||
void trivial_hash_func(const void *p, struct siphash *state) {
|
||||
siphash24_compress(&p, sizeof(p), state);
|
||||
siphash24_compress_typesafe(p, state);
|
||||
}
|
||||
|
||||
int trivial_compare_func(const void *a, const void *b) {
|
||||
|
|
@ -97,7 +97,7 @@ const struct hash_ops trivial_hash_ops_free_free = {
|
|||
};
|
||||
|
||||
void uint64_hash_func(const uint64_t *p, struct siphash *state) {
|
||||
siphash24_compress(p, sizeof(uint64_t), state);
|
||||
siphash24_compress_typesafe(*p, state);
|
||||
}
|
||||
|
||||
int uint64_compare_func(const uint64_t *a, const uint64_t *b) {
|
||||
|
|
@ -109,7 +109,7 @@ DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func
|
|||
#if 0 /* NM_IGNORED */
|
||||
#if SIZEOF_DEV_T != 8
|
||||
void devt_hash_func(const dev_t *p, struct siphash *state) {
|
||||
siphash24_compress(p, sizeof(dev_t), state);
|
||||
siphash24_compress_typesafe(*p, state);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -93,14 +93,14 @@ extern const struct hash_ops trivial_hash_ops;
|
|||
extern const struct hash_ops trivial_hash_ops_free;
|
||||
extern const struct hash_ops trivial_hash_ops_free_free;
|
||||
|
||||
/* 32bit values we can always just embed in the pointer itself, but in order to support 32bit archs we need store 64bit
|
||||
/* 32-bit values we can always just embed in the pointer itself, but in order to support 32-bit archs we need store 64-bit
|
||||
* values indirectly, since they don't fit in a pointer. */
|
||||
void uint64_hash_func(const uint64_t *p, struct siphash *state);
|
||||
int uint64_compare_func(const uint64_t *a, const uint64_t *b) _pure_;
|
||||
extern const struct hash_ops uint64_hash_ops;
|
||||
|
||||
/* On some archs dev_t is 32bit, and on others 64bit. And sometimes it's 64bit on 32bit archs, and sometimes 32bit on
|
||||
* 64bit archs. Yuck! */
|
||||
/* On some archs dev_t is 32-bit, and on others 64-bit. And sometimes it's 64-bit on 32-bit archs, and sometimes 32-bit on
|
||||
* 64-bit archs. Yuck! */
|
||||
#if SIZEOF_DEV_T != 8
|
||||
void devt_hash_func(const dev_t *p, struct siphash *state);
|
||||
#else
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "random-util.h"
|
||||
#include "set.h"
|
||||
#include "siphash24.h"
|
||||
#include "sort-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
|
||||
|
|
@ -176,9 +177,9 @@ struct _packed_ indirect_storage {
|
|||
};
|
||||
|
||||
struct direct_storage {
|
||||
/* This gives us 39 bytes on 64bit, or 35 bytes on 32bit.
|
||||
* That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64bit,
|
||||
* or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32bit. */
|
||||
/* This gives us 39 bytes on 64-bit, or 35 bytes on 32-bit.
|
||||
* That's room for 4 set_entries + 4 DIB bytes + 3 unused bytes on 64-bit,
|
||||
* or 7 set_entries + 7 DIB bytes + 0 unused bytes on 32-bit. */
|
||||
uint8_t storage[sizeof(struct indirect_storage)];
|
||||
};
|
||||
|
||||
|
|
@ -2112,3 +2113,54 @@ bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needl
|
|||
|
||||
return set_fnmatch_one(include_patterns, needle);
|
||||
}
|
||||
|
||||
static int hashmap_entry_compare(
|
||||
struct hashmap_base_entry * const *a,
|
||||
struct hashmap_base_entry * const *b,
|
||||
compare_func_t compare) {
|
||||
|
||||
assert(a && *a);
|
||||
assert(b && *b);
|
||||
assert(compare);
|
||||
|
||||
return compare((*a)->key, (*b)->key);
|
||||
}
|
||||
|
||||
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n) {
|
||||
_cleanup_free_ struct hashmap_base_entry **entries = NULL;
|
||||
Iterator iter;
|
||||
unsigned idx;
|
||||
size_t n = 0;
|
||||
|
||||
assert(ret);
|
||||
|
||||
if (_hashmap_size(h) == 0) {
|
||||
*ret = NULL;
|
||||
if (ret_n)
|
||||
*ret_n = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* We append one more element than needed so that the resulting array can be used as a strv. We
|
||||
* don't count this entry in the returned size. */
|
||||
entries = new(struct hashmap_base_entry*, _hashmap_size(h) + 1);
|
||||
if (!entries)
|
||||
return -ENOMEM;
|
||||
|
||||
HASHMAP_FOREACH_IDX(idx, h, iter)
|
||||
entries[n++] = bucket_at(h, idx);
|
||||
|
||||
assert(n == _hashmap_size(h));
|
||||
entries[n] = NULL;
|
||||
|
||||
typesafe_qsort_r(entries, n, hashmap_entry_compare, h->hash_ops->compare);
|
||||
|
||||
/* Reuse the array. */
|
||||
FOREACH_ARRAY(e, entries, n)
|
||||
*e = entry_value(h, *e);
|
||||
|
||||
*ret = (void**) TAKE_PTR(entries);
|
||||
if (ret_n)
|
||||
*ret_n = n;
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -398,12 +398,28 @@ static inline char** ordered_hashmap_get_strv(OrderedHashmap *h) {
|
|||
return _hashmap_get_strv(HASHMAP_BASE(h));
|
||||
}
|
||||
|
||||
int _hashmap_dump_sorted(HashmapBase *h, void ***ret, size_t *ret_n);
|
||||
static inline int hashmap_dump_sorted(Hashmap *h, void ***ret, size_t *ret_n) {
|
||||
return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
|
||||
}
|
||||
static inline int ordered_hashmap_dump_sorted(OrderedHashmap *h, void ***ret, size_t *ret_n) {
|
||||
return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
|
||||
}
|
||||
static inline int set_dump_sorted(Set *h, void ***ret, size_t *ret_n) {
|
||||
return _hashmap_dump_sorted(HASHMAP_BASE(h), ret, ret_n);
|
||||
}
|
||||
|
||||
/*
|
||||
* Hashmaps are iterated in unpredictable order.
|
||||
* OrderedHashmaps are an exception to this. They are iterated in the order
|
||||
* the entries were inserted.
|
||||
* It is safe to remove the current entry.
|
||||
*/
|
||||
#define _HASHMAP_BASE_FOREACH(e, h, i) \
|
||||
for (Iterator i = ITERATOR_FIRST; _hashmap_iterate((h), &i, (void**)&(e), NULL); )
|
||||
#define HASHMAP_BASE_FOREACH(e, h) \
|
||||
_HASHMAP_BASE_FOREACH(e, h, UNIQ_T(i, UNIQ))
|
||||
|
||||
#define _HASHMAP_FOREACH(e, h, i) \
|
||||
for (Iterator i = ITERATOR_FIRST; hashmap_iterate((h), &i, (void**)&(e), NULL); )
|
||||
#define HASHMAP_FOREACH(e, h) \
|
||||
|
|
@ -414,6 +430,11 @@ static inline char** ordered_hashmap_get_strv(OrderedHashmap *h) {
|
|||
#define ORDERED_HASHMAP_FOREACH(e, h) \
|
||||
_ORDERED_HASHMAP_FOREACH(e, h, UNIQ_T(i, UNIQ))
|
||||
|
||||
#define _HASHMAP_BASE_FOREACH_KEY(e, k, h, i) \
|
||||
for (Iterator i = ITERATOR_FIRST; _hashmap_iterate((h), &i, (void**)&(e), (const void**) &(k)); )
|
||||
#define HASHMAP_BASE_FOREACH_KEY(e, k, h) \
|
||||
_HASHMAP_BASE_FOREACH_KEY(e, k, h, UNIQ_T(i, UNIQ))
|
||||
|
||||
#define _HASHMAP_FOREACH_KEY(e, k, h, i) \
|
||||
for (Iterator i = ITERATOR_FIRST; hashmap_iterate((h), &i, (void**)&(e), (const void**) &(k)); )
|
||||
#define HASHMAP_FOREACH_KEY(e, k, h) \
|
||||
|
|
|
|||
|
|
@ -116,7 +116,7 @@ int unhexmem_full(
|
|||
const char *p,
|
||||
size_t l,
|
||||
bool secure,
|
||||
void **ret,
|
||||
void **ret_data,
|
||||
size_t *ret_len) {
|
||||
|
||||
_cleanup_free_ uint8_t *buf = NULL;
|
||||
|
|
@ -157,8 +157,8 @@ int unhexmem_full(
|
|||
|
||||
if (ret_len)
|
||||
*ret_len = (size_t) (z - buf);
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(buf);
|
||||
if (ret_data)
|
||||
*ret_data = TAKE_PTR(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -557,12 +557,12 @@ int unbase64char(char c) {
|
|||
|
||||
offset += '9' - '0' + 1;
|
||||
|
||||
if (c == '+')
|
||||
if (IN_SET(c, '+', '-')) /* Support both the regular and the URL safe character set (see above) */
|
||||
return offset;
|
||||
|
||||
offset++;
|
||||
|
||||
if (c == '/')
|
||||
if (IN_SET(c, '/', '_')) /* ditto */
|
||||
return offset;
|
||||
|
||||
return -EINVAL;
|
||||
|
|
@ -772,7 +772,7 @@ int unbase64mem_full(
|
|||
const char *p,
|
||||
size_t l,
|
||||
bool secure,
|
||||
void **ret,
|
||||
void **ret_data,
|
||||
size_t *ret_size) {
|
||||
|
||||
_cleanup_free_ uint8_t *buf = NULL;
|
||||
|
|
@ -860,8 +860,8 @@ int unbase64mem_full(
|
|||
|
||||
if (ret_size)
|
||||
*ret_size = (size_t) (z - buf);
|
||||
if (ret)
|
||||
*ret = TAKE_PTR(buf);
|
||||
if (ret_data)
|
||||
*ret_data = TAKE_PTR(buf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ char hexchar(int x) _const_;
|
|||
int unhexchar(char c) _const_;
|
||||
|
||||
char *hexmem(const void *p, size_t l);
|
||||
int unhexmem_full(const char *p, size_t l, bool secure, void **mem, size_t *len);
|
||||
static inline int unhexmem(const char *p, size_t l, void **mem, size_t *len) {
|
||||
return unhexmem_full(p, l, false, mem, len);
|
||||
int unhexmem_full(const char *p, size_t l, bool secure, void **ret_data, size_t *ret_size);
|
||||
static inline int unhexmem(const char *p, void **ret_data, size_t *ret_size) {
|
||||
return unhexmem_full(p, SIZE_MAX, false, ret_data, ret_size);
|
||||
}
|
||||
|
||||
char base32hexchar(int x) _const_;
|
||||
|
|
@ -45,9 +45,9 @@ ssize_t base64_append(
|
|||
size_t l,
|
||||
size_t margin,
|
||||
size_t width);
|
||||
int unbase64mem_full(const char *p, size_t l, bool secure, void **mem, size_t *len);
|
||||
static inline int unbase64mem(const char *p, size_t l, void **mem, size_t *len) {
|
||||
return unbase64mem_full(p, l, false, mem, len);
|
||||
int unbase64mem_full(const char *p, size_t l, bool secure, void **ret_data, size_t *ret_size);
|
||||
static inline int unbase64mem(const char *p, void **ret_data, size_t *ret_size) {
|
||||
return unbase64mem_full(p, SIZE_MAX, false, ret_data, ret_size);
|
||||
}
|
||||
|
||||
void hexdump(FILE *f, const void *p, size_t s);
|
||||
|
|
|
|||
|
|
@ -736,10 +736,11 @@ int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen)
|
|||
}
|
||||
}
|
||||
|
||||
int in4_addr_prefix_covers(
|
||||
int in4_addr_prefix_covers_full(
|
||||
const struct in_addr *prefix,
|
||||
unsigned char prefixlen,
|
||||
const struct in_addr *address) {
|
||||
const struct in_addr *address,
|
||||
unsigned char address_prefixlen) {
|
||||
|
||||
struct in_addr masked_prefix, masked_address;
|
||||
int r;
|
||||
|
|
@ -747,6 +748,9 @@ int in4_addr_prefix_covers(
|
|||
assert(prefix);
|
||||
assert(address);
|
||||
|
||||
if (prefixlen > address_prefixlen)
|
||||
return false;
|
||||
|
||||
masked_prefix = *prefix;
|
||||
r = in4_addr_mask(&masked_prefix, prefixlen);
|
||||
if (r < 0)
|
||||
|
|
@ -760,10 +764,11 @@ int in4_addr_prefix_covers(
|
|||
return in4_addr_equal(&masked_prefix, &masked_address);
|
||||
}
|
||||
|
||||
int in6_addr_prefix_covers(
|
||||
int in6_addr_prefix_covers_full(
|
||||
const struct in6_addr *prefix,
|
||||
unsigned char prefixlen,
|
||||
const struct in6_addr *address) {
|
||||
const struct in6_addr *address,
|
||||
unsigned char address_prefixlen) {
|
||||
|
||||
struct in6_addr masked_prefix, masked_address;
|
||||
int r;
|
||||
|
|
@ -771,6 +776,9 @@ int in6_addr_prefix_covers(
|
|||
assert(prefix);
|
||||
assert(address);
|
||||
|
||||
if (prefixlen > address_prefixlen)
|
||||
return false;
|
||||
|
||||
masked_prefix = *prefix;
|
||||
r = in6_addr_mask(&masked_prefix, prefixlen);
|
||||
if (r < 0)
|
||||
|
|
@ -784,20 +792,21 @@ int in6_addr_prefix_covers(
|
|||
return in6_addr_equal(&masked_prefix, &masked_address);
|
||||
}
|
||||
|
||||
int in_addr_prefix_covers(
|
||||
int in_addr_prefix_covers_full(
|
||||
int family,
|
||||
const union in_addr_union *prefix,
|
||||
unsigned char prefixlen,
|
||||
const union in_addr_union *address) {
|
||||
const union in_addr_union *address,
|
||||
unsigned char address_prefixlen) {
|
||||
|
||||
assert(prefix);
|
||||
assert(address);
|
||||
|
||||
switch (family) {
|
||||
case AF_INET:
|
||||
return in4_addr_prefix_covers(&prefix->in, prefixlen, &address->in);
|
||||
return in4_addr_prefix_covers_full(&prefix->in, prefixlen, &address->in, address_prefixlen);
|
||||
case AF_INET6:
|
||||
return in6_addr_prefix_covers(&prefix->in6, prefixlen, &address->in6);
|
||||
return in6_addr_prefix_covers_full(&prefix->in6, prefixlen, &address->in6, address_prefixlen);
|
||||
default:
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
|
@ -922,12 +931,19 @@ int in_addr_prefix_from_string_auto_internal(
|
|||
|
||||
}
|
||||
|
||||
void in_addr_hash_func(const union in_addr_union *u, int family, struct siphash *state) {
|
||||
assert(u);
|
||||
assert(state);
|
||||
|
||||
siphash24_compress(u->bytes, FAMILY_ADDRESS_SIZE(family), state);
|
||||
}
|
||||
|
||||
void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state) {
|
||||
assert(a);
|
||||
assert(state);
|
||||
|
||||
siphash24_compress(&a->family, sizeof(a->family), state);
|
||||
siphash24_compress(&a->address, FAMILY_ADDRESS_SIZE(a->family), state);
|
||||
siphash24_compress_typesafe(a->family, state);
|
||||
in_addr_hash_func(&a->address, a->family, state);
|
||||
}
|
||||
|
||||
int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y) {
|
||||
|
|
@ -960,7 +976,7 @@ void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
|
|||
assert(addr);
|
||||
assert(state);
|
||||
|
||||
siphash24_compress(addr, sizeof(*addr), state);
|
||||
siphash24_compress_typesafe(*addr, state);
|
||||
}
|
||||
|
||||
int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
|
||||
|
|
|
|||
|
|
@ -144,9 +144,18 @@ int in4_addr_default_subnet_mask(const struct in_addr *addr, struct in_addr *mas
|
|||
int in4_addr_mask(struct in_addr *addr, unsigned char prefixlen);
|
||||
int in6_addr_mask(struct in6_addr *addr, unsigned char prefixlen);
|
||||
int in_addr_mask(int family, union in_addr_union *addr, unsigned char prefixlen);
|
||||
int in4_addr_prefix_covers(const struct in_addr *prefix, unsigned char prefixlen, const struct in_addr *address);
|
||||
int in6_addr_prefix_covers(const struct in6_addr *prefix, unsigned char prefixlen, const struct in6_addr *address);
|
||||
int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address);
|
||||
int in4_addr_prefix_covers_full(const struct in_addr *prefix, unsigned char prefixlen, const struct in_addr *address, unsigned char address_prefixlen);
|
||||
int in6_addr_prefix_covers_full(const struct in6_addr *prefix, unsigned char prefixlen, const struct in6_addr *address, unsigned char address_prefixlen);
|
||||
int in_addr_prefix_covers_full(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address, unsigned char address_prefixlen);
|
||||
static inline int in4_addr_prefix_covers(const struct in_addr *prefix, unsigned char prefixlen, const struct in_addr *address) {
|
||||
return in4_addr_prefix_covers_full(prefix, prefixlen, address, 32);
|
||||
}
|
||||
static inline int in6_addr_prefix_covers(const struct in6_addr *prefix, unsigned char prefixlen, const struct in6_addr *address) {
|
||||
return in6_addr_prefix_covers_full(prefix, prefixlen, address, 128);
|
||||
}
|
||||
static inline int in_addr_prefix_covers(int family, const union in_addr_union *prefix, unsigned char prefixlen, const union in_addr_union *address) {
|
||||
return in_addr_prefix_covers_full(family, prefix, prefixlen, address, family == AF_INET ? 32 : family == AF_INET6 ? 128 : 0);
|
||||
}
|
||||
int in_addr_parse_prefixlen(int family, const char *p, unsigned char *ret);
|
||||
int in_addr_prefix_from_string(const char *p, int family, union in_addr_union *ret_prefix, unsigned char *ret_prefixlen);
|
||||
|
||||
|
|
@ -176,6 +185,7 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
|
|||
* See also oss-fuzz#11344. */
|
||||
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
|
||||
|
||||
void in_addr_hash_func(const union in_addr_union *u, int family, struct siphash *state);
|
||||
void in_addr_data_hash_func(const struct in_addr_data *a, struct siphash *state);
|
||||
int in_addr_data_compare_func(const struct in_addr_data *x, const struct in_addr_data *y);
|
||||
void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state);
|
||||
|
|
@ -186,6 +196,16 @@ extern const struct hash_ops in_addr_data_hash_ops_free;
|
|||
extern const struct hash_ops in6_addr_hash_ops;
|
||||
extern const struct hash_ops in6_addr_hash_ops_free;
|
||||
|
||||
static inline void PTR_TO_IN4_ADDR(const void *p, struct in_addr *ret) {
|
||||
assert(ret);
|
||||
ret->s_addr = (uint32_t) ((uintptr_t) p);
|
||||
}
|
||||
|
||||
static inline void* IN4_ADDR_TO_PTR(const struct in_addr *a) {
|
||||
assert(a);
|
||||
return (void*) ((uintptr_t) a->s_addr);
|
||||
}
|
||||
|
||||
#define IPV4_ADDRESS_FMT_STR "%u.%u.%u.%u"
|
||||
#define IPV4_ADDRESS_FMT_VAL(address) \
|
||||
be32toh((address).s_addr) >> 24, \
|
||||
|
|
|
|||
|
|
@ -6,6 +6,43 @@
|
|||
#include "inotify-util.h"
|
||||
#include "stat-util.h"
|
||||
|
||||
bool inotify_event_next(
|
||||
union inotify_event_buffer *buffer,
|
||||
size_t size,
|
||||
struct inotify_event **iterator,
|
||||
int log_level) {
|
||||
|
||||
struct inotify_event *e;
|
||||
size_t offset = 0;
|
||||
|
||||
assert(buffer);
|
||||
assert(iterator);
|
||||
|
||||
if (*iterator) {
|
||||
assert((uint8_t*) *iterator >= buffer->raw);
|
||||
offset = (uint8_t*) *iterator - buffer->raw;
|
||||
offset += offsetof(struct inotify_event, name) + (*iterator)->len;
|
||||
}
|
||||
|
||||
if (size == offset)
|
||||
return false; /* reached end of list */
|
||||
|
||||
if (size < offset ||
|
||||
size - offset < offsetof(struct inotify_event, name)) {
|
||||
log_full(log_level, "Received invalid inotify event, ignoring.");
|
||||
return false;
|
||||
}
|
||||
|
||||
e = CAST_ALIGN_PTR(struct inotify_event, buffer->raw + offset);
|
||||
if (size - offset - offsetof(struct inotify_event, name) < e->len) {
|
||||
log_full(log_level, "Received invalid inotify event, ignoring.");
|
||||
return false;
|
||||
}
|
||||
|
||||
*iterator = e;
|
||||
return true;
|
||||
}
|
||||
|
||||
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
|
||||
int wd, r;
|
||||
|
||||
|
|
|
|||
|
|
@ -10,29 +10,27 @@
|
|||
|
||||
#define INOTIFY_EVENT_MAX (offsetof(struct inotify_event, name) + NAME_MAX + 1)
|
||||
|
||||
#define _FOREACH_INOTIFY_EVENT(e, buffer, sz, log_level, start, end) \
|
||||
for (struct inotify_event \
|
||||
*start = &((buffer).ev), \
|
||||
*end = (struct inotify_event*) ((uint8_t*) start + (sz)), \
|
||||
*e = start; \
|
||||
(size_t) ((uint8_t*) end - (uint8_t*) e) >= sizeof(struct inotify_event) && \
|
||||
((size_t) ((uint8_t*) end - (uint8_t*) e) >= sizeof(struct inotify_event) + e->len || \
|
||||
(log_full(log_level, "Received invalid inotify event, ignoring."), false)); \
|
||||
e = (struct inotify_event*) ((uint8_t*) e + sizeof(struct inotify_event) + e->len))
|
||||
|
||||
#define _FOREACH_INOTIFY_EVENT_FULL(e, buffer, sz, log_level) \
|
||||
_FOREACH_INOTIFY_EVENT(e, buffer, sz, log_level, UNIQ_T(start, UNIQ), UNIQ_T(end, UNIQ))
|
||||
/* This evaluates arguments multiple times */
|
||||
#define FOREACH_INOTIFY_EVENT_FULL(e, buffer, sz, log_level) \
|
||||
for (struct inotify_event *e = NULL; \
|
||||
inotify_event_next(&buffer, sz, &e, log_level); )
|
||||
|
||||
#define FOREACH_INOTIFY_EVENT(e, buffer, sz) \
|
||||
_FOREACH_INOTIFY_EVENT_FULL(e, buffer, sz, LOG_DEBUG)
|
||||
FOREACH_INOTIFY_EVENT_FULL(e, buffer, sz, LOG_DEBUG)
|
||||
|
||||
#define FOREACH_INOTIFY_EVENT_WARN(e, buffer, sz) \
|
||||
_FOREACH_INOTIFY_EVENT_FULL(e, buffer, sz, LOG_WARNING)
|
||||
FOREACH_INOTIFY_EVENT_FULL(e, buffer, sz, LOG_WARNING)
|
||||
|
||||
union inotify_event_buffer {
|
||||
struct inotify_event ev;
|
||||
uint8_t raw[INOTIFY_EVENT_MAX];
|
||||
};
|
||||
|
||||
bool inotify_event_next(
|
||||
union inotify_event_buffer *buffer,
|
||||
size_t size,
|
||||
struct inotify_event **iterator,
|
||||
int log_level);
|
||||
|
||||
int inotify_add_watch_fd(int fd, int what, uint32_t mask);
|
||||
int inotify_add_watch_and_warn(int fd, const char *pathname, uint32_t mask);
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "errno-util.h"
|
||||
#include "io-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "string-util.h"
|
||||
#include "time-util.h"
|
||||
|
||||
|
|
@ -58,8 +60,7 @@ ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll) {
|
|||
|
||||
assert(fd >= 0);
|
||||
|
||||
/* If called with nbytes == 0, let's call read() at least
|
||||
* once, to validate the operation */
|
||||
/* If called with nbytes == 0, let's call read() at least once, to validate the operation */
|
||||
|
||||
if (nbytes > (size_t) SSIZE_MAX)
|
||||
return -EINVAL;
|
||||
|
|
@ -111,13 +112,29 @@ int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll) {
|
|||
}
|
||||
|
||||
#if 0 /* NM_IGNORED */
|
||||
int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
|
||||
const uint8_t *p = ASSERT_PTR(buf);
|
||||
int loop_write_full(int fd, const void *buf, size_t nbytes, usec_t timeout) {
|
||||
const uint8_t *p;
|
||||
usec_t end;
|
||||
int r;
|
||||
|
||||
assert(fd >= 0);
|
||||
assert(buf || nbytes == 0);
|
||||
|
||||
if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
|
||||
return -EINVAL;
|
||||
if (nbytes == 0) {
|
||||
static const dummy_t dummy[0];
|
||||
assert_cc(sizeof(dummy) == 0);
|
||||
p = (const void*) dummy; /* Some valid pointer, in case NULL was specified */
|
||||
} else {
|
||||
if (nbytes == SIZE_MAX)
|
||||
nbytes = strlen(buf);
|
||||
else if (_unlikely_(nbytes > (size_t) SSIZE_MAX))
|
||||
return -EINVAL;
|
||||
|
||||
p = buf;
|
||||
}
|
||||
|
||||
/* When timeout is 0 or USEC_INFINITY this is not used. But we initialize it to a sensible value. */
|
||||
end = timestamp_is_set(timeout) ? usec_add(now(CLOCK_MONOTONIC), timeout) : USEC_INFINITY;
|
||||
|
||||
do {
|
||||
ssize_t k;
|
||||
|
|
@ -127,16 +144,31 @@ int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll) {
|
|||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN && do_poll) {
|
||||
/* We knowingly ignore any return value here,
|
||||
* and expect that any error/EOF is reported
|
||||
* via write() */
|
||||
if (errno != EAGAIN || timeout == 0)
|
||||
return -errno;
|
||||
|
||||
(void) fd_wait_for_event(fd, POLLOUT, USEC_INFINITY);
|
||||
continue;
|
||||
usec_t wait_for;
|
||||
|
||||
if (timeout == USEC_INFINITY)
|
||||
wait_for = USEC_INFINITY;
|
||||
else {
|
||||
usec_t t = now(CLOCK_MONOTONIC);
|
||||
if (t >= end)
|
||||
return -ETIME;
|
||||
|
||||
wait_for = usec_sub_unsigned(end, t);
|
||||
}
|
||||
|
||||
return -errno;
|
||||
r = fd_wait_for_event(fd, POLLOUT, wait_for);
|
||||
if (timeout == USEC_INFINITY || ERRNO_IS_NEG_TRANSIENT(r))
|
||||
/* If timeout == USEC_INFINITY we knowingly ignore any return value
|
||||
* here, and expect that any error/EOF is reported via write() */
|
||||
continue;
|
||||
if (r < 0)
|
||||
return r;
|
||||
if (r == 0)
|
||||
return -ETIME;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_unlikely_(nbytes > 0 && k == 0)) /* Can't really happen */
|
||||
|
|
@ -260,7 +292,7 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (lseek(fd, n, SEEK_CUR) == (off_t) -1)
|
||||
if (lseek(fd, n, SEEK_CUR) < 0)
|
||||
return -errno;
|
||||
|
||||
q += n;
|
||||
|
|
@ -281,102 +313,4 @@ ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length) {
|
|||
|
||||
return q - (const uint8_t*) p;
|
||||
}
|
||||
|
||||
char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value) {
|
||||
char *x;
|
||||
|
||||
x = strjoin(field, value);
|
||||
if (x)
|
||||
iovec[(*n_iovec)++] = IOVEC_MAKE_STRING(x);
|
||||
return x;
|
||||
}
|
||||
|
||||
char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value) {
|
||||
char *x;
|
||||
|
||||
x = set_iovec_string_field(iovec, n_iovec, field, value);
|
||||
free(value);
|
||||
return x;
|
||||
}
|
||||
|
||||
struct iovec_wrapper *iovw_new(void) {
|
||||
return malloc0(sizeof(struct iovec_wrapper));
|
||||
}
|
||||
|
||||
void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors) {
|
||||
if (free_vectors)
|
||||
for (size_t i = 0; i < iovw->count; i++)
|
||||
free(iovw->iovec[i].iov_base);
|
||||
|
||||
iovw->iovec = mfree(iovw->iovec);
|
||||
iovw->count = 0;
|
||||
}
|
||||
|
||||
struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw) {
|
||||
iovw_free_contents(iovw, true);
|
||||
|
||||
return mfree(iovw);
|
||||
}
|
||||
|
||||
struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw) {
|
||||
iovw_free_contents(iovw, false);
|
||||
|
||||
return mfree(iovw);
|
||||
}
|
||||
|
||||
int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len) {
|
||||
if (iovw->count >= IOV_MAX)
|
||||
return -E2BIG;
|
||||
|
||||
if (!GREEDY_REALLOC(iovw->iovec, iovw->count + 1))
|
||||
return -ENOMEM;
|
||||
|
||||
iovw->iovec[iovw->count++] = IOVEC_MAKE(data, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value) {
|
||||
_cleanup_free_ char *x = NULL;
|
||||
int r;
|
||||
|
||||
x = strjoin(field, value);
|
||||
if (!x)
|
||||
return -ENOMEM;
|
||||
|
||||
r = iovw_put(iovw, x, strlen(x));
|
||||
if (r >= 0)
|
||||
TAKE_PTR(x);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value) {
|
||||
_cleanup_free_ _unused_ char *free_ptr = value;
|
||||
|
||||
return iovw_put_string_field(iovw, field, value);
|
||||
}
|
||||
|
||||
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new) {
|
||||
for (size_t i = 0; i < iovw->count; i++)
|
||||
iovw->iovec[i].iov_base = (char *)iovw->iovec[i].iov_base - old + new;
|
||||
}
|
||||
|
||||
size_t iovw_size(struct iovec_wrapper *iovw) {
|
||||
size_t n = 0;
|
||||
|
||||
for (size_t i = 0; i < iovw->count; i++)
|
||||
n += iovw->iovec[i].iov_len;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
void iovec_array_free(struct iovec *iov, size_t n) {
|
||||
if (!iov)
|
||||
return;
|
||||
|
||||
for (size_t i = 0; i < n; i++)
|
||||
free(iov[i].iov_base);
|
||||
|
||||
free(iov);
|
||||
}
|
||||
#endif /* NM_IGNORED */
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "macro.h"
|
||||
#include "time-util.h"
|
||||
|
|
@ -15,7 +14,11 @@ int flush_fd(int fd);
|
|||
|
||||
ssize_t loop_read(int fd, void *buf, size_t nbytes, bool do_poll);
|
||||
int loop_read_exact(int fd, void *buf, size_t nbytes, bool do_poll);
|
||||
int loop_write(int fd, const void *buf, size_t nbytes, bool do_poll);
|
||||
|
||||
int loop_write_full(int fd, const void *buf, size_t nbytes, usec_t timeout);
|
||||
static inline int loop_write(int fd, const void *buf, size_t nbytes) {
|
||||
return loop_write_full(fd, buf, nbytes, 0);
|
||||
}
|
||||
|
||||
int pipe_eof(int fd);
|
||||
|
||||
|
|
@ -24,38 +27,6 @@ int fd_wait_for_event(int fd, int event, usec_t timeout);
|
|||
|
||||
ssize_t sparse_write(int fd, const void *p, size_t sz, size_t run_length);
|
||||
|
||||
static inline size_t IOVEC_TOTAL_SIZE(const struct iovec *i, size_t n) {
|
||||
size_t r = 0;
|
||||
|
||||
for (size_t j = 0; j < n; j++)
|
||||
r += i[j].iov_len;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline bool IOVEC_INCREMENT(struct iovec *i, size_t n, size_t k) {
|
||||
/* Returns true if there is nothing else to send (bytes written cover all of the iovec),
|
||||
* false if there's still work to do. */
|
||||
|
||||
for (size_t j = 0; j < n; j++) {
|
||||
size_t sub;
|
||||
|
||||
if (i[j].iov_len == 0)
|
||||
continue;
|
||||
if (k == 0)
|
||||
return false;
|
||||
|
||||
sub = MIN(i[j].iov_len, k);
|
||||
i[j].iov_len -= sub;
|
||||
i[j].iov_base = (uint8_t*) i[j].iov_base + sub;
|
||||
k -= sub;
|
||||
}
|
||||
|
||||
assert(k == 0); /* Anything else would mean that we wrote more bytes than available,
|
||||
* or the kernel reported writing more bytes than sent. */
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline bool FILE_SIZE_VALID(uint64_t l) {
|
||||
/* ftruncate() and friends take an unsigned file size, but actually cannot deal with file sizes larger than
|
||||
* 2^63 since the kernel internally handles it as signed value. This call allows checking for this early. */
|
||||
|
|
@ -73,40 +44,3 @@ static inline bool FILE_SIZE_VALID_OR_INFINITY(uint64_t l) {
|
|||
return FILE_SIZE_VALID(l);
|
||||
|
||||
}
|
||||
|
||||
#define IOVEC_NULL (struct iovec) {}
|
||||
#define IOVEC_MAKE(base, len) (struct iovec) { .iov_base = (base), .iov_len = (len) }
|
||||
#define IOVEC_MAKE_STRING(string) \
|
||||
({ \
|
||||
char *_s = (char*) (string); \
|
||||
IOVEC_MAKE(_s, strlen(_s)); \
|
||||
})
|
||||
|
||||
char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
|
||||
char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value);
|
||||
|
||||
struct iovec_wrapper {
|
||||
struct iovec *iovec;
|
||||
size_t count;
|
||||
};
|
||||
|
||||
struct iovec_wrapper *iovw_new(void);
|
||||
struct iovec_wrapper *iovw_free(struct iovec_wrapper *iovw);
|
||||
struct iovec_wrapper *iovw_free_free(struct iovec_wrapper *iovw);
|
||||
void iovw_free_contents(struct iovec_wrapper *iovw, bool free_vectors);
|
||||
|
||||
int iovw_put(struct iovec_wrapper *iovw, void *data, size_t len);
|
||||
static inline int iovw_consume(struct iovec_wrapper *iovw, void *data, size_t len) {
|
||||
/* Move data into iovw or free on error */
|
||||
int r = iovw_put(iovw, data, len);
|
||||
if (r < 0)
|
||||
free(data);
|
||||
return r;
|
||||
}
|
||||
|
||||
int iovw_put_string_field(struct iovec_wrapper *iovw, const char *field, const char *value);
|
||||
int iovw_put_string_field_free(struct iovec_wrapper *iovw, const char *field, char *value);
|
||||
void iovw_rebase(struct iovec_wrapper *iovw, char *old, char *new);
|
||||
size_t iovw_size(struct iovec_wrapper *iovw);
|
||||
|
||||
void iovec_array_free(struct iovec *iov, size_t n);
|
||||
|
|
|
|||
99
src/libnm-systemd-shared/src/basic/iovec-util.h
Normal file
99
src/libnm-systemd-shared/src/basic/iovec-util.h
Normal file
|
|
@ -0,0 +1,99 @@
|
|||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "macro.h"
|
||||
|
||||
/* An iovec pointing to a single NUL byte */
|
||||
#define IOVEC_NUL_BYTE (const struct iovec) { \
|
||||
.iov_base = (void*) (const uint8_t[1]) { 0 }, \
|
||||
.iov_len = 1, \
|
||||
}
|
||||
|
||||
size_t iovec_total_size(const struct iovec *iovec, size_t n);
|
||||
|
||||
bool iovec_increment(struct iovec *iovec, size_t n, size_t k);
|
||||
|
||||
/* This accepts both const and non-const pointers */
|
||||
#define IOVEC_MAKE(base, len) \
|
||||
(struct iovec) { \
|
||||
.iov_base = (void*) (base), \
|
||||
.iov_len = (len), \
|
||||
}
|
||||
|
||||
static inline struct iovec* iovec_make_string(struct iovec *iovec, const char *s) {
|
||||
assert(iovec);
|
||||
/* We don't use strlen_ptr() here, because we don't want to include string-util.h for now */
|
||||
*iovec = IOVEC_MAKE(s, s ? strlen(s) : 0);
|
||||
return iovec;
|
||||
}
|
||||
|
||||
#define IOVEC_MAKE_STRING(s) \
|
||||
*iovec_make_string(&(struct iovec) {}, s)
|
||||
|
||||
#define CONST_IOVEC_MAKE_STRING(s) \
|
||||
(const struct iovec) { \
|
||||
.iov_base = (char*) s, \
|
||||
.iov_len = STRLEN(s), \
|
||||
}
|
||||
|
||||
static inline void iovec_done(struct iovec *iovec) {
|
||||
/* A _cleanup_() helper that frees the iov_base in the iovec */
|
||||
assert(iovec);
|
||||
|
||||
iovec->iov_base = mfree(iovec->iov_base);
|
||||
iovec->iov_len = 0;
|
||||
}
|
||||
|
||||
static inline void iovec_done_erase(struct iovec *iovec) {
|
||||
assert(iovec);
|
||||
|
||||
iovec->iov_base = erase_and_free(iovec->iov_base);
|
||||
iovec->iov_len = 0;
|
||||
}
|
||||
|
||||
static inline bool iovec_is_set(const struct iovec *iovec) {
|
||||
/* Checks if the iovec points to a non-empty chunk of memory */
|
||||
return iovec && iovec->iov_len > 0 && iovec->iov_base;
|
||||
}
|
||||
|
||||
static inline bool iovec_is_valid(const struct iovec *iovec) {
|
||||
/* Checks if the iovec is either NULL, empty or points to a valid bit of memory */
|
||||
return !iovec || (iovec->iov_base || iovec->iov_len == 0);
|
||||
}
|
||||
|
||||
char* set_iovec_string_field(struct iovec *iovec, size_t *n_iovec, const char *field, const char *value);
|
||||
char* set_iovec_string_field_free(struct iovec *iovec, size_t *n_iovec, const char *field, char *value);
|
||||
|
||||
void iovec_array_free(struct iovec *iovec, size_t n_iovec);
|
||||
|
||||
static inline int iovec_memcmp(const struct iovec *a, const struct iovec *b) {
|
||||
|
||||
if (a == b)
|
||||
return 0;
|
||||
|
||||
return memcmp_nn(a ? a->iov_base : NULL,
|
||||
a ? a->iov_len : 0,
|
||||
b ? b->iov_base : NULL,
|
||||
b ? b->iov_len : 0);
|
||||
}
|
||||
|
||||
static inline struct iovec *iovec_memdup(const struct iovec *source, struct iovec *ret) {
|
||||
assert(ret);
|
||||
|
||||
if (!iovec_is_set(source))
|
||||
*ret = (struct iovec) {};
|
||||
else {
|
||||
void *p = memdup(source->iov_base, source->iov_len);
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
*ret = IOVEC_MAKE(p, source->iov_len);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -192,6 +192,18 @@
|
|||
_p; \
|
||||
})
|
||||
|
||||
#define LIST_CLEAR(name, head, free_func) \
|
||||
_LIST_CLEAR(name, head, free_func, UNIQ_T(elem, UNIQ))
|
||||
|
||||
/* Clear the list, destroying each element with free_func */
|
||||
#define _LIST_CLEAR(name, head, free_func, elem) \
|
||||
({ \
|
||||
typeof(head) elem; \
|
||||
while ((elem = LIST_POP(name, head))) \
|
||||
free_func(elem); \
|
||||
head; \
|
||||
})
|
||||
|
||||
/* Now include "macro.h", because we want our definition of assert() which the macros above use. We include
|
||||
* it down here instead of up top, since macro.h pulls in log.h which in turn needs our own definitions. */
|
||||
#include "macro.h"
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue