diff options
author | Thomas Haller <thaller@redhat.com> | 2022-05-16 09:44:49 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-05-16 09:44:50 +0200 |
commit | e2476b10634a8c6670bd2fbba5598e80f16c6285 (patch) | |
tree | b516dff71734ded78cf5cc8f119431ed7de12e6a | |
parent | 5704730a6c4e6851d4ba5471ea439502f7b72949 (diff) | |
parent | d9d72c6ea1525524a8e68da83f82055e6484960a (diff) |
release: bump version to 1.39.4 (development)1.39.4-dev
213 files changed, 5501 insertions, 9042 deletions
diff --git a/.gitlab-ci/run-test.sh b/.gitlab-ci/run-test.sh index 18038304f8..c8c26f0815 100755 --- a/.gitlab-ci/run-test.sh +++ b/.gitlab-ci/run-test.sh @@ -2,6 +2,8 @@ set -ex +export PAGER=cat + IS_FEDORA=0 IS_CENTOS=0 IS_ALPINE=0 diff --git a/Makefile.am b/Makefile.am index 60a171f528..a9f028dcf9 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1691,7 +1691,6 @@ libnm_lib_h_pub_real = \ src/libnm-client-public/nm-object.h \ src/libnm-client-public/nm-remote-connection.h \ src/libnm-client-public/nm-secret-agent-old.h \ - src/libnm-client-public/nm-types.h \ src/libnm-client-public/nm-vpn-connection.h \ src/libnm-client-public/nm-vpn-editor.h \ src/libnm-client-public/nm-vpn-plugin-old.h \ @@ -2329,12 +2328,8 @@ src_libnm_systemd_core_libnm_systemd_core_la_libadd = \ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \ src/libnm-systemd-core/nm-default-systemd-core.h \ - src/libnm-systemd-core/nm-sd-utils-core.c \ - src/libnm-systemd-core/nm-sd-utils-core.h \ src/libnm-systemd-core/nm-sd.c \ src/libnm-systemd-core/nm-sd.h \ - src/libnm-systemd-core/nm-sd-utils-dhcp.h \ - src/libnm-systemd-core/nm-sd-utils-dhcp.c \ 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/device-util.h \ @@ -2345,16 +2340,8 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \ src/libnm-systemd-core/sd-adapt-core/sd-daemon.h \ src/libnm-systemd-core/sd-adapt-core/sd-device.h \ src/libnm-systemd-core/sd-adapt-core/udev-util.h \ - src/libnm-systemd-core/src/libsystemd-network/arp-util.c \ - src/libnm-systemd-core/src/libsystemd-network/arp-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/dhcp-internal.h \ - src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h \ - src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c \ - src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c \ - src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c \ - src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.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 \ @@ -2369,10 +2356,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \ src/libnm-systemd-core/src/libsystemd-network/lldp-rx-internal.h \ src/libnm-systemd-core/src/libsystemd-network/network-common.c \ src/libnm-systemd-core/src/libsystemd-network/network-common.h \ - src/libnm-systemd-core/src/libsystemd-network/network-internal.c \ - src/libnm-systemd-core/src/libsystemd-network/network-internal.h \ - src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c \ - src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c \ src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c \ src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c \ src/libnm-systemd-core/src/libsystemd-network/sd-lldp-rx.c \ @@ -2384,9 +2367,6 @@ src_libnm_systemd_core_libnm_systemd_core_la_SOURCES = \ src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h \ 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-dhcp-client.h \ - src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h \ - src/libnm-systemd-core/src/systemd/sd-dhcp-option.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 \ @@ -2547,8 +2527,6 @@ src_core_libNetworkManager_la_SOURCES = \ src/core/dns/nm-dns-dnsmasq.h \ src/core/dns/nm-dns-systemd-resolved.c \ src/core/dns/nm-dns-systemd-resolved.h \ - src/core/dns/nm-dns-unbound.c \ - src/core/dns/nm-dns-unbound.h \ \ src/core/dnsmasq/nm-dnsmasq-manager.c \ src/core/dnsmasq/nm-dnsmasq-manager.h \ @@ -5337,6 +5315,7 @@ EXTRA_DIST += \ src/tests/client/test-client.check-on-disk/test_002.expected \ src/tests/client/test-client.check-on-disk/test_003.expected \ src/tests/client/test-client.check-on-disk/test_004.expected \ + src/tests/client/test-client.check-on-disk/test_offline.expected \ \ src/tests/client/meson.build \ $(NULL) @@ -1,4 +1,23 @@ ============================================= +NetworkManager-1.40 +Overview of changes since NetworkManager-1.38 +============================================= + +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! + +* Drop unused, internal systemd DHCPv4 client. This is long + replaced by nettools' n-dhcp4 implementation. +* The nmcli command now supports --offline argument with "add" and + "modify" commands, allowing operation on keyfile-formatted connection + profiles without the service running (e.g. during system provisioning). +* The device state file /run/NetworkManager/devices/$ifindex now has + new sections [dhcp4] and [dhcp6] containing the DHCP options for the + current lease. + +============================================= NetworkManager-1.38 Overview of changes since NetworkManager-1.36 ============================================= diff --git a/config.h.meson b/config.h.meson index 7d1feb53ad..7337165082 100644 --- a/config.h.meson +++ b/config.h.meson @@ -13,9 +13,6 @@ /* Define to path of dnsmasq binary */ #mesondefine DNSMASQ_PATH -/* Define to path of unbound dnssec-trigger-script */ -#mesondefine DNSSEC_TRIGGER_PATH - /* Gettext package */ #mesondefine GETTEXT_PACKAGE diff --git a/configure.ac b/configure.ac index 09c69720c3..8e00da68b0 100644 --- a/configure.ac +++ b/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], [38]) -m4_define([nm_micro_version], [0]) +m4_define([nm_minor_version], [39]) +m4_define([nm_micro_version], [4]) m4_define([nm_version], [nm_major_version.nm_minor_version.nm_micro_version]) @@ -306,11 +306,12 @@ AC_ARG_WITH(udev-dir, [Absolute path of the udev base directory. Set to 'no' not to install the udev rules]), [], [with_udev_dir="yes"]) if test "$with_udev_dir" != 'no'; then - if test "$with_udev_dir" != 'yes' && printf '%s' "$with_udev_dir" | grep -v -q '^/'; then - AC_MSG_ERROR([--with-udev-dir must be an absolute path or 'yes' or 'no'. Instead it is '$with_udev_dir']) - fi - if test "$with_udev_dir" = 'yes'; then - with_udev_dir="\$(prefix)/lib/udev" + if test "$with_udev_dir" = 'yes' -o "$with_udev_dir" = "" ; then + with_udev_dir="\${prefix}/lib/udev" + else + if printf '%s' "$with_udev_dir" | grep -v -q '^/'; then + AC_MSG_ERROR([--with-udev-dir must be an absolute path or 'yes' or 'no'. Instead it is '$with_udev_dir']) + fi fi UDEV_DIR="$with_udev_dir" AC_SUBST(UDEV_DIR) @@ -745,7 +746,6 @@ AC_SUBST(GLIB_MKENUMS) AC_ARG_WITH(dbus-sys-dir, AS_HELP_STRING([--with-dbus-sys-dir=DIR], [where D-BUS system.d directory is])) - if test -n "$with_dbus_sys_dir" ; then DBUS_SYS_DIR="$with_dbus_sys_dir" else @@ -1006,18 +1006,6 @@ fi AC_DEFINE_UNQUOTED(DNSMASQ_PATH, "$DNSMASQ_PATH", [Define to path of dnsmasq binary]) AC_SUBST(DNSMASQ_PATH) -# dnssec-trigger-script path -AC_ARG_WITH(dnssec_trigger, - AS_HELP_STRING([--with-dnssec-trigger=/path/to/dnssec-trigger-script], [path to unbound dnssec-trigger-script])) -if test "x${with_dnssec_trigger}" = x; then - AC_PATH_PROG(DNSSEC_TRIGGER_PATH, dnssec-trigger-script, /usr/libexec/dnssec-trigger-script, - /usr/local/libexec:/usr/local/lib:/usr/local/lib/dnssec-trigger:/usr/libexec:/usr/lib:/usr/lib/dnssec-trigger) -else - DNSSEC_TRIGGER_PATH="$with_dnssec_trigger" -fi -AC_DEFINE_UNQUOTED(DNSSEC_TRIGGER_PATH, "$DNSSEC_TRIGGER_PATH", [Define to path of unbound dnssec-trigger-script]) -AC_SUBST(DNSSEC_TRIGGER_PATH) - # system CA certificates path AC_ARG_WITH(system-ca-path, AS_HELP_STRING([--with-system-ca-path=/path/to/ssl/certs], [path to system CA certificates])) @@ -1374,8 +1362,10 @@ echo " exec_prefix: $exec_prefix" echo " sysconfdir: $sysconfdir" echo " localstatedir: $localstatedir" echo " runstatedir: $runstatedir" +echo " datarootdir: $datarootdir" echo " datadir: $datadir" echo " systemdunitdir: $with_systemdsystemunitdir" +echo " udev-dir: $with_udev_dir" echo " nmbinary: $nmbinary" echo " nmconfdir: $nmconfdir" echo " nmlibdir: $nmlibdir" @@ -1383,6 +1373,7 @@ echo " nmdatadir: $nmdatadir" echo " nmstatedir: $nmstatedir" echo " nmrundir: $nmrundir" echo " system-ca-path: $with_system_ca_path" +echo " dbus-sys-dir: $DBUS_SYS_DIR" echo echo "Platform:" diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec index 50d5d31ae8..779b71ba2a 100644 --- a/contrib/fedora/rpm/NetworkManager.spec +++ b/contrib/fedora/rpm/NetworkManager.spec @@ -13,8 +13,8 @@ %global glib2_version %(pkg-config --modversion glib-2.0 2>/dev/null || echo bad) %global epoch_version 1 -%global rpm_version __VERSION__ %global real_version __VERSION__ +%global rpm_version %{real_version} %global release_version __RELEASE_VERSION__ %global snapshot __SNAPSHOT__ %global git_sha __COMMIT__ diff --git a/contrib/fedora/rpm/release.sh b/contrib/fedora/rpm/release.sh index 9b2ba5ea8c..e653509869 100755 --- a/contrib/fedora/rpm/release.sh +++ b/contrib/fedora/rpm/release.sh @@ -548,9 +548,13 @@ done do_command git push "$ORIGIN" "${BRANCHES[@]}" || die "failed to to push branches ${BRANCHES[@]} to $ORIGIN" +FAIL=0 for r in "${RELEASE_FILES[@]}"; do - do_command ssh master.gnome.org ftpadmin install --unattended "$r" || die "ftpadmin install failed" + do_command ssh master.gnome.org ftpadmin install --unattended "$r" || FAIL=1 done +if [ "$FAIL" = 1 ]; then + die "ftpadmin install failed. This was the last step. Invoke the command manually" +fi CLEANUP_CHECKOUT_BRANCH= if [ "$DRY_RUN" = 0 ]; then diff --git a/contrib/fedora/utils/makerepo.sh b/contrib/fedora/utils/makerepo.sh index 7f471f75c6..47778b405b 100755 --- a/contrib/fedora/utils/makerepo.sh +++ b/contrib/fedora/utils/makerepo.sh @@ -70,7 +70,7 @@ git_remote_add_gnome() { } git_remote_add_github() { - git remote add "${2-origin}" "git://github.com/$1.git" + git remote add "${2-origin}" "https://github.com/$1.git" git remote 'set-url' --push "${2-origin}" "git@github.com:$1.git" } @@ -319,16 +319,25 @@ MAKEREPO_GIT_IGNORE_LAST="makerepo.gitignore.last-$CURRENT_BRANCH" get_local_mirror() { local URL="$1" + local DIRNAME + local FULLNAME if [[ -z "$URL" ]]; then return fi - local DIRNAME="$(echo $URL.git | sed -e 's#^.*/\([^/]\+\)$#\1#' -e 's/\(.*\)\.git$/\1/')" - local FULLNAME="$srcdir/.git/.makerepo-${DIRNAME}.git" - [[ -n "$NO_REMOTE" ]] && return + DIRNAME="${URL##*/}" + DIRNAME="${DIRNAME%.git}" + FULLNAME="$srcdir/.git/.makerepo-${DIRNAME}.git" + + if [ ! -d "$FULLNAME" ] && [ -d "$FULLNAME.git" ]; then + # due to a bug, old versions of the script might have created "*.git.git/" directories. + # rename. + mv "$FULLNAME.git" "$FULLNAME" + fi + if [[ ! -d "$FULLNAME" ]]; then if [[ -f "$FULLNAME" ]]; then # create a file with name $FULLNAME, to suppress local mirroring diff --git a/contrib/scripts/nm-in-container.d/data-nm-env-prepare.sh b/contrib/scripts/nm-in-container.d/data-nm-env-prepare.sh index 61cee0371c..49c91d3ff8 100755 --- a/contrib/scripts/nm-in-container.d/data-nm-env-prepare.sh +++ b/contrib/scripts/nm-in-container.d/data-nm-env-prepare.sh @@ -11,6 +11,9 @@ do_cleanup() { local IDX="$1" local NAME_PREFIX="${2:-net}" local PEER_PREFIX="${3:-d_}" + local NETNS_PREFIX="${4:-tt}" + + logger --id "nm-env-prepare-$IDX" "cleanup start # $@" pkill -F "/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid" dnsmasq &>/dev/null || : rm -rf "/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid" @@ -24,40 +27,60 @@ do_cleanup() { rm -rf "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf" - ip link del "$PEER_PREFIX$IDX" &>/dev/null || : + ip -netns "$NETNS_PREFIX$IDX" link del "$PEER_PREFIX$IDX" &>/dev/null || : + + ip netns del "$NETNS_PREFIX$IDX" &>/dev/null || : + + logger --id "nm-env-prepare-$IDX" "cleanup complete # $@" } do_setup() { local IDX="$1" local NAME_PREFIX="${2:-net}" local PEER_PREFIX="${3:-d_}" + local NETNS_PREFIX="${4:-tt}" - do_cleanup "$IDX" + logger --id "nm-env-prepare-$IDX" "setup start # $@" - ip link add "$NAME_PREFIX$IDX" type veth peer "$PEER_PREFIX$IDX" - ip link set "$PEER_PREFIX$IDX" up + ip netns add "$NETNS_PREFIX$IDX" + ip -netns "$NETNS_PREFIX$IDX" link set lo up - ip addr add "192.168.$((120 + IDX)).1/23" dev "$PEER_PREFIX$IDX" - ip addr add "192:168:$((120 + IDX))::1/64" dev "$PEER_PREFIX$IDX" + ip -netns "$NETNS_PREFIX$IDX" link add "$NAME_PREFIX$IDX" type veth peer "$PEER_PREFIX$IDX" + ip -netns "$NETNS_PREFIX$IDX" link set "$PEER_PREFIX$IDX" up + + ip -netns "$NETNS_PREFIX$IDX" addr add "192.168.$((120 + IDX)).1/23" dev "$PEER_PREFIX$IDX" + ip -netns "$NETNS_PREFIX$IDX" addr add "192:168:$((120 + IDX))::1/64" dev "$PEER_PREFIX$IDX" # PPPoE inside the rootless container is not actually working, because # /dev/ppp is not accessible. Still start it, so that we at least can # test how far it goes... echo "192.168.$((120 + $IDX)).180-200" > "/tmp/nm-pppoe-allip-$PEER_PREFIX$IDX" - pppoe-server -X "/tmp/nm-pppoe-$PEER_PREFIX$IDX.pid" -S isp -C isp -L "192.168.$((120 + IDX)).1" -p "/tmp/nm-pppoe-allip-$PEER_PREFIX$IDX" -I "$PEER_PREFIX$IDX" & - - dnsmasq \ - --conf-file=/dev/null \ - --pid-file="/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid" \ - --no-hosts \ - --keep-in-foreground \ - --bind-interfaces \ - --except-interface=lo \ - --clear-on-reload \ - --listen-address="192.168.$((120 + $IDX)).1" \ - --dhcp-range="192.168.$((120 + $IDX)).100,192.168.$((120 + $IDX)).150" \ - --no-ping \ - & + ip netns exec "$NETNS_PREFIX$IDX" \ + pppoe-server \ + -X "/tmp/nm-pppoe-$PEER_PREFIX$IDX.pid" \ + -S isp \ + -C isp \ + -L "192.168.$((120 + IDX)).1" \ + -p "/tmp/nm-pppoe-allip-$PEER_PREFIX$IDX" \ + -I "$PEER_PREFIX$IDX" \ + & + + ip netns exec "$NETNS_PREFIX$IDX" \ + dnsmasq \ + --conf-file=/dev/null \ + --pid-file="/tmp/nm-dnsmasq-$PEER_PREFIX$IDX.pid" \ + --no-hosts \ + --keep-in-foreground \ + --bind-interfaces \ + --log-debug \ + --log-queries \ + --log-dhcp \ + --except-interface=lo \ + --clear-on-reload \ + --listen-address="192.168.$((120 + $IDX)).1" \ + --dhcp-range="192.168.$((120 + $IDX)).100,192.168.$((120 + $IDX)).150" \ + --no-ping \ + & cat <<EOF > "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf" interface $PEER_PREFIX$IDX @@ -70,10 +93,17 @@ interface $PEER_PREFIX$IDX }; EOF - radvd \ - --config "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf" \ - --pidfile "/tmp/nm-radvd-$PEER_PREFIX$IDX.pid" \ - & + ip netns exec "$NETNS_PREFIX$IDX" \ + radvd \ + --config "/tmp/nm-radvd-$PEER_PREFIX$IDX.conf" \ + --pidfile "/tmp/nm-radvd-$PEER_PREFIX$IDX.pid" \ + --logmethod syslog \ + -d 5 \ + & + + ip -netns ""$NETNS_PREFIX$IDX"" link set "$NAME_PREFIX$IDX" netns $$ + + logger --id "nm-env-prepare-$IDX" "setup complete: netns=$NETNS_PREFIX$IDX, iface=$NAME_PREFIX$IDX, peer=$PEER_PREFIX$IDX # $@" } do_redo() { @@ -81,8 +111,27 @@ do_redo() { do_setup "$@" } +do_one_time_setup() { + if [ ! -d /tmp/sys2 ]; then + # `ip -netns t exec ...` will try to mount sysfs. But kernel rejects that in + # the container, unless a writable sysfs is already mounted. Due to --priviledged, + # we have /sys mounted rw, however, ip will first unmount /sys before trying to + # remount it. We thus need it mounted as rw one additional time. + # + # Let's do this setup step once, and never clean it up. + # https://github.com/containers/podman/issues/11887#issuecomment-938706628 + mkdir /tmp/sys2 + mount -t sysfs --make-private /tmp/sys2 + fi +} + ############################################################################### +# We do this one-time-setup always when the script runs, and never clean it +# up. +do_one_time_setup + + IDX=1 NAME_PREFIX=net PEER_PREFIX= diff --git a/contrib/scripts/nm-in-container.sh b/contrib/scripts/nm-in-container.sh index e4dda6d384..02a16e9da3 100755 --- a/contrib/scripts/nm-in-container.sh +++ b/contrib/scripts/nm-in-container.sh @@ -109,7 +109,54 @@ find NetworkManager bind mounted at $BASEDIR_NM run \`nm-env-prepare.sh setup --idx 1\` to setup test interfaces Configure NetworkManager with - \$ ./configure --enable-maintainer-mode --enable-more-warnings=error --with-more-asserts="\${NM_BUILD_MORE_ASSERTS:-1000}" --with-nm-cloud-setup=yes --prefix=/opt/test --localstatedir=/var --sysconfdir=/etc --enable-gtk-doc --enable-introspection --with-ofono=yes --with-dhclient=yes --with-dhcpcanon=yes --with-dhcpcd=yes --enable-more-logging --enable-compile-warnings=yes --enable-address-sanitizer=no --enable-undefined-sanitizer=no --with-valgrind=yes --enable-concheck --enable-wimax --enable-ifcfg-rh=yes --enable-config-plugin-ibft=yes --enable-ifcfg-suse --enable-ifupdown=yes --enable-ifnet --enable-vala=yes --enable-polkit=yes --with-libnm-glib=yes --with-nmcli=yes --with-nmtui=yes --with-modem-manager-1 --with-suspend-resume=systemd --enable-teamdctl=yes --enable-ovs=yes --enable-tests="\${NM_BUILD_TESTS:-yes}" --with-netconfig=/bin/nowhere/netconfig --with-resolvconf=/bin/nowhere/resolvconf --with-crypto=nss --with-session-tracking=systemd --with-consolekit=yes --with-systemd-logind=yes --with-iwd=yes --enable-json-validation=yes --with-consolekit=yes --with-config-dns-rc-manager-default=auto --with-config-dhcp-default=internal "\${NM_CONFIGURE_OTPS[@]}" + \$ ./configure \ + --enable-address-sanitizer=no \ + --enable-compile-warnings=yes \ + --enable-concheck \ + --enable-config-plugin-ibft=yes \ + --enable-gtk-doc \ + --enable-ifcfg-rh=yes \ + --enable-ifcfg-suse \ + --enable-ifnet \ + --enable-ifupdown=yes \ + --enable-introspection \ + --enable-json-validation=yes \ + --enable-maintainer-mode \ + --enable-more-logging \ + --enable-more-warnings=error \ + --enable-ovs=yes \ + --enable-polkit=yes \ + --enable-teamdctl=yes \ + --enable-undefined-sanitizer=no \ + --enable-vala=yes \ + --enable-wimax \ + --localstatedir=/var \ + --prefix=/opt/test \ + --sysconfdir=/etc \ + --with-config-dhcp-default=internal \ + --with-config-dns-rc-manager-default=auto \ + --with-consolekit=yes \ + --with-consolekit=yes \ + --with-crypto=nss \ + --with-dhclient=yes \ + --with-dhcpcanon=yes \ + --with-dhcpcd=yes \ + --with-iwd=yes \ + --with-libnm-glib=yes \ + --with-modem-manager-1 \ + --with-netconfig=/bin/nowhere/netconfig \ + --with-nm-cloud-setup=yes \ + --with-nmcli=yes \ + --with-nmtui=yes \ + --with-ofono=yes \ + --with-resolvconf=/bin/nowhere/resolvconf \ + --with-session-tracking=systemd \ + --with-suspend-resume=systemd \ + --with-systemd-logind=yes \ + --with-valgrind=yes \ + --enable-tests="\${NM_BUILD_TESTS:-yes}" \ + --with-more-asserts="\${NM_BUILD_MORE_ASSERTS:-1000}" \ + "\${NM_CONFIGURE_OTPS[@]}" Test with: \$ systemctl stop NetworkManager; /opt/test/sbin/NetworkManager --debug 2>&1 | tee -a /tmp/nm-log.txt EOF @@ -249,6 +296,8 @@ RUN dnf install -y \\ mlocate \\ mobile-broadband-provider-info-devel \\ newt-devel \\ + nispor \\ + nmstate \\ nss-devel \\ polkit-devel \\ ppp \\ diff --git a/examples/python/gi/checkpoint.py b/examples/python/gi/checkpoint.py index b63b1c37a4..6f3194cdb1 100755 --- a/examples/python/gi/checkpoint.py +++ b/examples/python/gi/checkpoint.py @@ -71,11 +71,11 @@ def find_checkpoint(nmc, path): def find_checkpoint_last(nmc): - l = [c.get_path() for c in nmc.get_checkpoints()] - if not l: - return None - l.sort(key=checkpoint_path_to_num) - return l[-1] + return max( + nmc.get_checkpoints(), + key=lambda c: checkpoint_path_to_num(c.get_path()), + default=None, + ) def validate_path(path, nmc): diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml index cb6b40afa0..18b25d9370 100644 --- a/man/NetworkManager.conf.xml +++ b/man/NetworkManager.conf.xml @@ -345,19 +345,12 @@ no-auto-default=* <para><literal>systemd-resolved</literal>: NetworkManager will push the DNS configuration to systemd-resolved</para> - <para><literal>unbound</literal>: NetworkManager will talk - to unbound and dnssec-triggerd, using "Conditional Forwarding" - with DNSSEC support. <filename>/etc/resolv.conf</filename> - will be managed by dnssec-trigger daemon. This option is - deprecated. Note that dnssec-trigger ships a NetworkManager dispatcher - script so this DNS plugin is not necessary.</para> - <para><literal>none</literal>: NetworkManager will not modify resolv.conf. This implies <literal>rc-manager</literal> <literal>unmanaged</literal></para> - <para>Note that the plugins <literal>dnsmasq</literal>, <literal>systemd-resolved</literal> - and <literal>unbound</literal> are caching local nameservers. + <para>Note that the plugins <literal>dnsmasq</literal> and <literal>systemd-resolved</literal> + are caching local nameservers. Hence, when NetworkManager writes <filename>&nmrundir;/resolv.conf</filename> and <filename>/etc/resolv.conf</filename> (according to <literal>rc-manager</literal> setting below), the name server there will be localhost only. diff --git a/man/nmcli-examples.xml b/man/nmcli-examples.xml index 5744ad12bb..0afa9797a3 100644 --- a/man/nmcli-examples.xml +++ b/man/nmcli-examples.xml @@ -614,6 +614,32 @@ Connection 'ethernet-4' (de89cdeb-a3e1-4d53-8fa0-c22546c775f4) successfully <screen><prompt>$ </prompt><userinput>nmcli connection add type bluetooth con-name "My Bluetooth Hotspot" autoconnect no ifname btnap0 bluetooth.type nap ipv4.method shared ipv6.method shared</userinput></screen> </example> + <example><title>Offline use</title> +<screen><prompt>$ </prompt><userinput>nmcli --offline con add type ethernet ' + conn.id eth0 \ + conn.interface-name eth0 \ + >/sysroot/etc/NetworkManager/system-connections/eth0.nmconnection</userinput></screen> + <para> + Creates a connection file in keyfile format without using the NetworkManager service. + This allows for use of familiar <command>nmcli</command> syntax in situations + where the service is not running, such as during system installation of image + provisioning and ensures the resulting file is correctly formatted. + </para> +<screen><prompt>$ </prompt><userinput>nmcli --offline con modify type ethernet ' + conn.id eth0-ipv6 \ + ipv4.method disabled \ + </sysroot/etc/NetworkManager/system-connections/eth0.nmconnection \ + >/sysroot/etc/NetworkManager/system-connections/eth0-ipv6.nmconnection</userinput></screen> + <para> + Read and write a connection file without using the NetworkManager service, modifying + some properties along the way. + </para> + <para> + This allows templating of the connection profiles using familiar + <command>nmcli</command> syntax in situations where the service is not running. + </para> + </example> + </refsect1> <refsect1> diff --git a/man/nmcli.xml b/man/nmcli.xml index d4f27b0b37..ba89b29112 100644 --- a/man/nmcli.xml +++ b/man/nmcli.xml @@ -316,6 +316,23 @@ <varlistentry> <term><group choice='plain'> + <arg choice='plain'><option>--offline</option></arg> + </group></term> + + <listitem> + <para>Work without a daemon. Makes <command>connection add</command> and + <command>connection modify</command> commands accept and produce connection + data via standard input/output. Ordinarily, nmcli would communicate with + the NetworkManager service.</para> + + <para>The connection data format (keyfile) is described in + <citerefentry><refentrytitle>nm-settings-keyfile</refentrytitle><manvolnum>5</manvolnum></citerefentry> + manual.</para> + </listitem> + </varlistentry> + + <varlistentry> + <term><group choice='plain'> <arg choice='plain'><option>-v</option></arg> <arg choice='plain'><option>--version</option></arg> </group></term> @@ -928,7 +945,7 @@ <arg choice='plain'><option>uuid</option></arg> <arg choice='plain'><option>path</option></arg> </group> - <arg choice='plain'><replaceable>ID</replaceable></arg> + <arg><replaceable>ID</replaceable></arg> <arg rep='repeat' choice='plain'> <group choice='req'> <arg choice='plain'><replaceable>option</replaceable> <replaceable>value</replaceable></arg> @@ -962,7 +979,14 @@ <para>The connection is identified by its name, UUID or D-Bus path. If <replaceable>ID</replaceable> is ambiguous, a keyword <option>id</option>, - <option>uuid</option> or <option>path</option> can be used.</para> + <option>uuid</option> or <option>path</option> can be used. + The <replaceable>ID</replaceable> is not used with the global + <option>--offline</option> option.</para> + + <para>When the global <option>--offline</option> is used, the + command reads the connection from the standard input and prints the + modified connection to standard output instead of making the + the NetworkManager daemon act upon specified connection.</para> </listitem> </varlistentry> @@ -1096,6 +1120,10 @@ </listitem> </varlistentry> </variablelist> + + <para>When the global <option>--offline</option> is used, the + command prints the resulting connection to standard output instead of + actually adding the connection via the NetworkManager daemon.</para> </listitem> </varlistentry> diff --git a/meson.build b/meson.build index 7a7eb176ae..4058e05f88 100644 --- a/meson.build +++ b/meson.build @@ -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.38.0', + version: '1.39.4', license: 'GPL2+', default_options: [ 'buildtype=debugoptimized', @@ -353,10 +353,14 @@ if enable_introspection endif udev_udevdir = get_option('udev_dir') -install_udevdir = (udev_udevdir != 'no') - -if install_udevdir and udev_udevdir == '' - udev_udevdir = dependency('udev').get_pkgconfig_variable('udevdir') +if udev_udevdir == 'no' + install_udevdir = false +else + install_udevdir = true + if (udev_udevdir == '' or udev_udevdir == 'yes') + udev_udevdir = join_paths(nm_prefix, 'lib/udev') + endif + assert(udev_udevdir.startswith('/'), 'udev_dir must be an absolute path, but is ' + udev_udevdir) endif systemd_systemdsystemunitdir = get_option('systemdsystemunitdir') @@ -364,7 +368,7 @@ install_systemdunitdir = (systemd_systemdsystemunitdir != 'no') if install_systemdunitdir and systemd_systemdsystemunitdir == '' assert(systemd_dep.found(), 'systemd required but not found, please provide a valid systemd user unit dir or disable it') - systemd_systemdsystemunitdir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir') + systemd_systemdsystemunitdir = systemd_dep.get_pkgconfig_variable('systemdsystemunitdir', define_variable: ['rootprefix', nm_prefix]) endif enable_systemd_journal = get_option('systemd_journal') @@ -551,7 +555,7 @@ endif dbus_conf_dir = get_option('dbus_conf_dir') if dbus_conf_dir == '' assert(dbus_dep.found(), 'D-Bus required but not found, please provide a valid system bus config dir') - dbus_conf_dir = join_paths(dbus_dep.get_pkgconfig_variable('datadir'), 'dbus-1', 'system.d') + dbus_conf_dir = join_paths(dbus_dep.get_pkgconfig_variable('datarootdir', define_variable: ['prefix', nm_prefix]), 'dbus-1', 'system.d') endif dbus_interfaces_dir = dbus_dep.get_pkgconfig_variable('interfaces_dir', define_variable: ['datadir', nm_datadir]) @@ -683,18 +687,11 @@ endforeach # external misc tools paths default_paths = ['/sbin', '/usr/sbin'] -dnssec_ts_paths = ['/usr/local/libexec', - '/usr/local/lib', - '/usr/local/lib/dnssec-trigger', - '/usr/libexec', - '/usr/lib', - '/usr/lib/dnssec-trigger'] # 0: cmdline option, 1: paths, 2: fallback -progs = [['iptables', default_paths, '/usr/sbin/iptables'], - ['nft', default_paths, '/usr/sbin/nft'], - ['dnsmasq', default_paths, ''], - ['dnssec_trigger', dnssec_ts_paths, join_paths(nm_libexecdir, 'dnssec-trigger-script') ], +progs = [['iptables', default_paths, '/usr/sbin/iptables'], + ['nft', default_paths, '/usr/sbin/nft'], + ['dnsmasq', default_paths, ''], ] foreach prog : progs @@ -1020,6 +1017,7 @@ output = '\nSystem paths:\n' output += ' prefix: ' + nm_prefix + '\n' output += ' exec_prefix: ' + nm_prefix + '\n' output += ' systemdunitdir: ' + systemd_systemdsystemunitdir + '\n' +output += ' udev_dir: ' + udev_udevdir + '\n' output += ' nmbinary: ' + nm_pkgsbindir + '\n' output += ' nmconfdir: ' + nm_pkgconfdir + '\n' output += ' nmlibdir: ' + nm_pkglibdir + '\n' @@ -1028,7 +1026,8 @@ output += ' nmstatedir: ' + nm_pkgstatedir + '\n' output += ' nmrundir: ' + nm_pkgrundir + '\n' output += ' nmvpndir: ' + nm_vpndir + '\n' output += ' nmplugindir: ' + nm_plugindir + '\n' -output += ' system-ca-path: ' + system_ca_path + '\n' +output += ' system_ca_path: ' + system_ca_path + '\n' +output += ' dbus_conf_dir: ' + dbus_conf_dir + '\n' output += '\nPlatform:\n' output += ' session tracking: ' + ','.join(session_trackers) + '\n' output += ' suspend/resume: ' + suspend_resume + '\n' diff --git a/meson_options.txt b/meson_options.txt index 42f84711d0..cec0664186 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -7,7 +7,6 @@ option('kernel_firmware_dir', type: 'string', value: '/lib/firmware', descriptio option('iptables', type: 'string', value: '', description: 'path to iptables') option('nft', type: 'string', value: '', description: 'path to nft') option('dnsmasq', type: 'string', value: '', description: 'path to dnsmasq') -option('dnssec_trigger', type: 'string', value: '', description: 'path to unbound dnssec-trigger-script') # platform option('dist_version', type: 'string', value: '', description: 'Define the NM\'s distribution version string') @@ -10,8 +10,8 @@ msgstr "" "Project-Id-Version: NetworkManager\n" "Report-Msgid-Bugs-To: https://gitlab.freedesktop.org/NetworkManager/NetworkMan" "ager/issues\n" -"POT-Creation-Date: 2022-03-31 15:26+0000\n" -"PO-Revision-Date: 2022-04-04 11:36+0300\n" +"POT-Creation-Date: 2022-05-12 15:26+0000\n" +"PO-Revision-Date: 2022-05-16 08:58+0300\n" "Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n" "Language-Team: Ukrainian <kde-i18n-uk@kde.org>\n" "Language: uk\n" @@ -193,7 +193,7 @@ msgstr "" #. * as "Wired Connection" or "VPN Connection". The %d is a number #. * that is combined with the first argument to create a unique #. * connection id. -#: ../src/core/NetworkManagerUtils.c:120 +#: ../src/core/NetworkManagerUtils.c:119 #, c-format msgctxt "connection id fallback" msgid "%s %u" @@ -261,7 +261,7 @@ msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń 6LOWPAN" msgid "Bond connection" msgstr "ŠŃŠøŠ²'ŃŠ·Š°Š½Šµ Š·'ŃŠ“Š½Š°Š½Š½Ń" -#: ../src/core/devices/nm-device-bridge.c:154 +#: ../src/core/devices/nm-device-bridge.c:161 msgid "Bridge connection" msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń Š¼ŃŃŃŠŗŠ°" @@ -596,7 +596,7 @@ msgstr "" msgid "Could not daemonize: %s [error %u]\n" msgstr "ŠŠµ Š²Š“Š°Š»Š¾ŃŃ ŃŃŠ²Š¾ŃŠøŃŠø ŃŠ¾Š½Š¾Š²Ń ŃŠ»ŃŠ¶Š±Ń: %s [ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° %u]\n" -#: ../src/core/nm-config.c:542 +#: ../src/core/nm-config.c:544 #: ../src/libnm-core-impl/nm-setting-ovs-bridge.c:187 #: ../src/libnmc-setting/nm-meta-setting-desc.c:2181 #: ../src/libnmc-setting/nm-meta-setting-desc.c:4242 @@ -604,93 +604,93 @@ msgstr "ŠŠµ Š²Š“Š°Š»Š¾ŃŃ ŃŃŠ²Š¾ŃŠøŃŠø ŃŠ¾Š½Š¾Š²Ń ŃŠ»ŃŠ¶Š±Ń: %s [ŠæŠ¾ msgid "'%s' is not valid" msgstr "Ā«%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼" -#: ../src/core/nm-config.c:564 +#: ../src/core/nm-config.c:566 #, c-format msgid "Bad '%s' option: " msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ¾Š²ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ»: " -#: ../src/core/nm-config.c:581 +#: ../src/core/nm-config.c:583 msgid "Config file location" msgstr "Š Š¾Š·ŃŠ°ŃŃŠ²Š°Š½Š½Ń ŃŠ°Š¹Š»Š° Š½Š°Š»Š°ŃŃŃŠ²Š°Š½Ń" -#: ../src/core/nm-config.c:588 +#: ../src/core/nm-config.c:590 msgid "Config directory location" msgstr "Š Š¾Š·ŃŠ°ŃŃŠ²Š°Š½Š½Ń ŠŗŠ°ŃŠ°Š»Š¾Š³Ń Š½Š°Š»Š°ŃŃŃŠ²Š°Š½Ń" -#: ../src/core/nm-config.c:595 +#: ../src/core/nm-config.c:597 msgid "System config directory location" msgstr "Š Š¾Š·ŃŠ°ŃŃŠ²Š°Š½Š½Ń Š·Š°Š³Š°Š»ŃŠ½Š¾ŃŠøŃŃŠµŠ¼Š½Š¾Š³Š¾ ŠŗŠ°ŃŠ°Š»Š¾Š³Ń Š½Š°Š»Š°ŃŃŃŠ²Š°Š½Ń" -#: ../src/core/nm-config.c:602 +#: ../src/core/nm-config.c:604 msgid "Internal config file location" msgstr "Š Š¾Š·ŃŠ°ŃŃŠ²Š°Š½Š½Ń Š²Š½ŃŃŃŃŃŠ½ŃŠ¾Š³Š¾ ŃŠ°Š¹Š»Š° Š½Š°Š»Š°ŃŃŃŠ²Š°Š½Ń" -#: ../src/core/nm-config.c:609 +#: ../src/core/nm-config.c:611 msgid "State file location" msgstr "Š Š¾Š·ŃŠ°ŃŃŠ²Š°Š½Š½Ń ŃŠ°Š¹Š»Š° ŃŃŠ°Š½Ń" -#: ../src/core/nm-config.c:616 +#: ../src/core/nm-config.c:618 msgid "State file for no-auto-default devices" msgstr "" "Š¤Š°Š¹Š» ŃŃŠ°Š½ŃŠ² Š“Š»Ń ŠæŃŠøŃŃŃŠ¾ŃŠ² Š±ŠµŠ· Š°Š²ŃŠ¾Š¼Š°ŃŠøŃŠ½ŠøŃ
ŃŠøŠæŠ¾Š²ŠøŃ
ŠæŠ°ŃŠ°Š¼ŠµŃŃŃŠ² (no-auto-" "default)" -#: ../src/core/nm-config.c:623 +#: ../src/core/nm-config.c:625 msgid "List of plugins separated by ','" msgstr "Š”ŠæŠøŃŠ¾Šŗ Š“Š¾Š“Š°ŃŠŗŃŠ², Š²ŃŠ“Š¾ŠŗŃŠµŠ¼Š»ŠµŠ½ŠøŃ
ŠŗŠ¾Š¼Š°Š¼Šø (Ā«,Ā»)" -#: ../src/core/nm-config.c:630 +#: ../src/core/nm-config.c:632 msgid "Quit after initial configuration" msgstr "ŠŠøŠ¹ŃŠø ŠæŃŃŠ»Ń ŠæŠ¾ŃŠ°ŃŠŗŠ¾Š²Š¾Š³Š¾ Š½Š°Š»Š°ŃŃŠ¾Š²ŃŠ²Š°Š½Š½Ń" -#: ../src/core/nm-config.c:637 +#: ../src/core/nm-config.c:639 msgid "Don't become a daemon, and log to stderr" msgstr "" "ŠŠµ ŠæŠµŃŠµŃ
Š¾Š“ŠøŃŠø Ń ŃŃŠ°Š½ ŃŠ¾Š½Š¾Š²Š¾Ń ŃŠ»ŃŠ¶Š±Šø Ń Š·Š°ŠæŠøŃŃŠ²Š°ŃŠø ŠæŠ¾Š²ŃŠ“Š¾Š¼Š»ŠµŠ½Š½Ń Š¶ŃŃŠ½Š°Š»Ń Š“Š¾ " "stderr" -#: ../src/core/nm-config.c:646 +#: ../src/core/nm-config.c:648 msgid "An http(s) address for checking internet connectivity" msgstr "ŠŠ“ŃŠµŃŠ° http(s) Š“Š»Ń ŃŠæŃŠ¾Š± ŠæŠµŃŠµŠ²ŃŃŠŗŠø Š¼Š¾Š¶Š»ŠøŠ²Š¾ŃŃŃ Š²ŃŃŠ°Š½Š¾Š²Š»ŠµŠ½Š½Ń Š·'ŃŠ“Š½Š°Š½Š½Ń" -#: ../src/core/nm-config.c:653 +#: ../src/core/nm-config.c:655 msgid "The interval between connectivity checks (in seconds)" msgstr "ŠŠ½ŃŠµŃŠ²Š°Š» Š¼ŃŠ¶ ŠæŠµŃŠµŠ²ŃŃŠŗŠ°Š¼Šø Š¼Š¾Š¶Š»ŠøŠ²Š¾ŃŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń (Ń ŃŠµŠŗŃŠ½Š“Š°Ń
)" -#: ../src/core/nm-config.c:660 +#: ../src/core/nm-config.c:662 msgid "The expected start of the response" msgstr "ŠŃŃŠŗŃŠ²Š°Š½ŠøŠ¹ ŠæŠ¾ŃŠ°ŃŠ¾Šŗ Š²ŃŠ“ŠæŠ¾Š²ŃŠ“Ń" -#: ../src/core/nm-config.c:669 +#: ../src/core/nm-config.c:671 msgid "NetworkManager options" msgstr "ŠŠ°ŃŠ°Š¼ŠµŃŃŠø NetworkManager" -#: ../src/core/nm-config.c:670 +#: ../src/core/nm-config.c:672 msgid "Show NetworkManager options" msgstr "ŠŠ¾ŠŗŠ°Š·Š°ŃŠø ŠæŠ°ŃŠ°Š¼ŠµŃŃŠø NetworkManager" -#: ../src/core/nm-manager.c:6121 +#: ../src/core/nm-manager.c:6146 #: ../src/libnmc-setting/nm-meta-setting-desc.c:8243 msgid "VPN connection" msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń VPN" #: ../src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5545 #: ../src/libnm-client-impl/nm-device.c:1779 -#: ../src/libnm-core-impl/nm-connection.c:3111 +#: ../src/libnm-core-impl/nm-connection.c:3172 #: ../src/nmtui/nm-editor-utils.c:196 msgid "Bond" msgstr "ŠŃŠøŠ²'ŃŠ·ŠŗŠ°" #: ../src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5616 #: ../src/libnm-client-impl/nm-device.c:1781 -#: ../src/libnm-core-impl/nm-connection.c:3113 +#: ../src/libnm-core-impl/nm-connection.c:3174 #: ../src/nmtui/nm-editor-utils.c:214 msgid "Team" msgstr "ŠŠ¾Š¼Š°Š½Š“Š°" #: ../src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c:5953 #: ../src/libnm-client-impl/nm-device.c:1783 -#: ../src/libnm-core-impl/nm-connection.c:3115 +#: ../src/libnm-core-impl/nm-connection.c:3176 #: ../src/nmtui/nm-editor-utils.c:205 msgid "Bridge" msgstr "ŠŃŃŃŠ¾Šŗ" @@ -823,7 +823,7 @@ msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š¼Š¾Š“ŠµŠ¼Š½ŠøŠ¼ Š·'ŃŠ“Š½Š msgid "The device is lacking capabilities required by the connection." msgstr "Š£ ŠæŃŠøŃŃŃŠ¾Ń Š½ŠµŠ¼Š°Ń Š¼Š¾Š¶Š»ŠøŠ²Š¾ŃŃŠµŠ¹, ŠæŠ¾ŃŃŃŠ±Š½ŠøŃ
Š·'ŃŠ“Š½Š°Š½Š½Ń." -#: ../src/libnm-client-impl/nm-device-olpc-mesh.c:102 +#: ../src/libnm-client-impl/nm-device-olpc-mesh.c:103 msgid "The connection was not an OLPC Mesh connection." msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń Š½Šµ Ń Š·'ŃŠ“Š½Š°Š½Š½ŃŠ¼ OLPC Mesh." @@ -936,13 +936,13 @@ msgid "Mobile Broadband" msgstr "ŠŠ¾Š±ŃŠ»ŃŠ½Š° ŃŠ°Š“ŃŠ¾Š¼ŠµŃŠµŠ¶Š°" #: ../src/libnm-client-impl/nm-device.c:1777 -#: ../src/libnm-core-impl/nm-connection.c:3119 +#: ../src/libnm-core-impl/nm-connection.c:3180 #: ../src/nmtui/nm-editor-utils.c:169 msgid "InfiniBand" msgstr "InfiniBand" #: ../src/libnm-client-impl/nm-device.c:1785 -#: ../src/libnm-core-impl/nm-connection.c:3117 +#: ../src/libnm-core-impl/nm-connection.c:3178 #: ../src/nmtui/nm-editor-utils.c:223 ../src/nmtui/nmt-page-vlan.c:57 msgid "VLAN" msgstr "VLAN" @@ -992,7 +992,7 @@ msgid "6LoWPAN" msgstr "6LoWPAN" #: ../src/libnm-client-impl/nm-device.c:1809 -#: ../src/libnm-core-impl/nm-connection.c:3125 +#: ../src/libnm-core-impl/nm-connection.c:3186 #: ../src/nmtui/nm-editor-utils.c:263 ../src/nmtui/nmt-page-wireguard.c:57 msgid "WireGuard" msgstr "WireGuard" @@ -1138,36 +1138,36 @@ msgstr "Š¼ŃŃŃŠøŃŃ UUID, ŃŠŗŠøŠ¹ ŠæŠ¾ŃŃŠµŠ±ŃŃ Š½Š¾ŃŠ¼Š°Š»ŃŠ·Š°ŃŃŃ" msgid "has duplicate UUIDs" msgstr "Š¼ŃŃŃŠøŃŃ Š“ŃŠ±Š»ŃŠŗŠ°ŃŠø UUID" -#: ../src/libnm-core-impl/nm-connection.c:1745 +#: ../src/libnm-core-impl/nm-connection.c:1805 msgid "setting not found" msgstr "ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾" -#: ../src/libnm-core-impl/nm-connection.c:1799 -#: ../src/libnm-core-impl/nm-connection.c:1824 -#: ../src/libnm-core-impl/nm-connection.c:1849 +#: ../src/libnm-core-impl/nm-connection.c:1859 +#: ../src/libnm-core-impl/nm-connection.c:1884 +#: ../src/libnm-core-impl/nm-connection.c:1909 msgid "setting is required for non-slave connections" msgstr "Š“Š»Ń Š½ŠµŠæŃŠ“Š»ŠµŠ³Š»ŠøŃ
Š·'ŃŠ“Š½Š°Š½Ń ŠæŠ¾ŃŃŃŠ±ŠµŠ½ ŠæŠ°ŃŠ°Š¼ŠµŃŃ" -#: ../src/libnm-core-impl/nm-connection.c:1812 -#: ../src/libnm-core-impl/nm-connection.c:1837 -#: ../src/libnm-core-impl/nm-connection.c:1862 +#: ../src/libnm-core-impl/nm-connection.c:1872 +#: ../src/libnm-core-impl/nm-connection.c:1897 +#: ../src/libnm-core-impl/nm-connection.c:1922 msgid "setting not allowed in slave connection" msgstr "ŠæŠ°ŃŠ°Š¼ŠµŃŃ Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŠ²Š°ŃŠø Ń ŠæŃŠ“Š»ŠµŠ³Š»Š¾Š¼Ń Š·'ŃŠ“Š½Š°Š½Š½Ń" -#: ../src/libnm-core-impl/nm-connection.c:1971 +#: ../src/libnm-core-impl/nm-connection.c:2032 msgid "Unexpected failure to normalize the connection" msgstr "ŠŠµŠ¾ŃŃŠŗŃŠ²Š°Š½Š° ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæŃŠ“ ŃŠ°Ń ŃŠæŃŠ¾Š±Šø Š½Š¾ŃŠ¼Š°Š»ŃŠ·ŃŠ²Š°ŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń" -#: ../src/libnm-core-impl/nm-connection.c:2032 +#: ../src/libnm-core-impl/nm-connection.c:2093 msgid "Unexpected failure to verify the connection" msgstr "ŠŠµŠ¾ŃŃŠŗŃŠ²Š°Š½Š° ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæŃŠ“ ŃŠ°Ń ŃŠæŃŠ¾Š±Šø ŠæŠµŃŠµŠ²ŃŃŠøŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń" -#: ../src/libnm-core-impl/nm-connection.c:2069 +#: ../src/libnm-core-impl/nm-connection.c:2130 #, c-format msgid "unexpected uuid %s instead of %s" msgstr "Š½ŠµŠ¾ŃŃŠŗŃŠ²Š°Š½ŠøŠ¹ UUID %s Š·Š°Š¼ŃŃŃŃ %s" -#: ../src/libnm-core-impl/nm-connection.c:2970 +#: ../src/libnm-core-impl/nm-connection.c:3031 #: ../src/libnm-core-impl/nm-setting-8021x.c:2607 #: ../src/libnm-core-impl/nm-setting-8021x.c:2644 #: ../src/libnm-core-impl/nm-setting-8021x.c:2662 @@ -1193,10 +1193,14 @@ msgstr "Š½ŠµŠ¾ŃŃŠŗŃŠ²Š°Š½ŠøŠ¹ UUID %s Š·Š°Š¼ŃŃŃŃ %s" msgid "property is missing" msgstr "Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ" -#: ../src/libnm-core-impl/nm-connection.c:3123 +#: ../src/libnm-core-impl/nm-connection.c:3184 msgid "IP Tunnel" msgstr "IP-ŃŃŠ½ŠµŠ»Ń" +#: ../src/libnm-core-impl/nm-connection.c:3188 +msgid "TUN/TAP" +msgstr "TUN/TAP" + #: ../src/libnm-core-impl/nm-dbus-utils.c:181 #, c-format msgid "Method returned type '%s', but expected '%s'" @@ -1212,239 +1216,239 @@ msgstr "ŠŠ½Š°ŃŠµŠ½Š½Ń Š½Šµ Š¼Š¾Š¶Šµ Š±ŃŃŠø Š¾Š±ŃŠ¾Š±Š»ŠµŠ½Š¾ ŃŠŗ ŃŠæŠøŃ msgid "value is not an integer in range [%lld, %lld]" msgstr "Š·Š½Š°ŃŠµŠ½Š½Ń Š½Šµ Ń ŃŃŠ»ŠøŠ¼ ŃŠøŃŠ»Š¾Š¼ Ń Š“ŃŠ°ŠæŠ°Š·Š¾Š½Ń [%lld, %lld]" -#: ../src/libnm-core-impl/nm-keyfile.c:332 +#: ../src/libnm-core-impl/nm-keyfile.c:331 msgid "ignoring missing number" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ ŠæŃŠ¾ŠæŃŃŠµŠ½Šµ ŃŠøŃŠ»Š¾" -#: ../src/libnm-core-impl/nm-keyfile.c:344 +#: ../src/libnm-core-impl/nm-keyfile.c:343 #, c-format msgid "ignoring invalid number '%s'" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ ŃŠøŃŠ»Š¾ Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-keyfile.c:373 +#: ../src/libnm-core-impl/nm-keyfile.c:372 #, c-format msgid "ignoring invalid %s address: %s" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Ń Š°Š“ŃŠµŃŃ %s: %s" -#: ../src/libnm-core-impl/nm-keyfile.c:419 +#: ../src/libnm-core-impl/nm-keyfile.c:418 #, c-format msgid "ignoring invalid gateway '%s' for %s route" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŃŠ»ŃŠ· Ā«%sĀ» Š“Š»Ń Š¼Š°ŃŃŃŃŃŃ %s" -#: ../src/libnm-core-impl/nm-keyfile.c:441 +#: ../src/libnm-core-impl/nm-keyfile.c:440 #, c-format msgid "ignoring invalid %s route: %s" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š¼Š°ŃŃŃŃŃ %s: %s" -#: ../src/libnm-core-impl/nm-keyfile.c:619 +#: ../src/libnm-core-impl/nm-keyfile.c:618 #, c-format msgid "unexpected character '%c' for address %s: '%s' (position %td)" msgstr "Š½ŠµŠ¾ŃŃŠŗŃŠ²Š°Š½ŠøŠ¹ ŃŠøŠ¼Š²Š¾Š» Ā«%cĀ» Š“Š»Ń Š°Š“ŃŠµŃŠø %s: Ā«%sĀ» (ŠæŠ¾Š·ŠøŃŃŃ %td)" -#: ../src/libnm-core-impl/nm-keyfile.c:635 +#: ../src/libnm-core-impl/nm-keyfile.c:634 #, c-format msgid "unexpected character '%c' for %s: '%s' (position %td)" msgstr "Š½ŠµŠ¾ŃŃŠŗŃŠ²Š°Š½ŠøŠ¹ ŃŠøŠ¼Š²Š¾Š» Ā«%cĀ» Š“Š»Ń %s: Ā«%sĀ» (ŠæŠ¾Š·ŠøŃŃŃ %td)" -#: ../src/libnm-core-impl/nm-keyfile.c:651 +#: ../src/libnm-core-impl/nm-keyfile.c:650 #, c-format msgid "unexpected character '%c' in prefix length for %s: '%s' (position %td)" msgstr "Š½ŠµŠ¾ŃŃŠŗŃŠ²Š°Š½ŠøŠ¹ ŃŠøŠ¼Š²Š¾Š» Ā«%cĀ» Ń ŠæŃŠµŃŃŠŗŃŃ Š“Š¾Š²Š¶ŠøŠ½Šø Š“Š»Ń %s: Ā«%sĀ» (ŠæŠ¾Š·ŠøŃŃŃ %td)" -#: ../src/libnm-core-impl/nm-keyfile.c:668 +#: ../src/libnm-core-impl/nm-keyfile.c:667 #, c-format msgid "garbage at the end of value %s: '%s'" msgstr "Š·Š°Š¹Š²Ń Š“Š°Š½Ń Š½Š°ŠæŃŠøŠŗŃŠ½ŃŃ Š·Š½Š°ŃŠµŠ½Š½Ń %s: Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-keyfile.c:678 +#: ../src/libnm-core-impl/nm-keyfile.c:677 #, c-format msgid "deprecated semicolon at the end of value %s: '%s'" msgstr "Š·Š°ŃŃŠ°ŃŃŠ»Š° ŠŗŃŠ°ŠæŠŗŠ° Š· ŠŗŠ¾Š¼Š¾Ń Š½Š°ŠæŃŠøŠŗŃŠ½ŃŃ Š·Š½Š°ŃŠµŠ½Š½Ń %s: Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-keyfile.c:697 +#: ../src/libnm-core-impl/nm-keyfile.c:696 #, c-format msgid "invalid prefix length for %s '%s', defaulting to %d" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŠæŃŠµŃŃŠŗŃ Š“Š¾Š²Š¶ŠøŠ½Šø Š“Š»Ń %s Ā«%sĀ», ŠæŠ¾Š²ŠµŃŃŠ°ŃŠ¼Š¾ŃŃ Š“Š¾ ŃŠøŠæŠ¾Š²Š¾Š³Š¾, %d" -#: ../src/libnm-core-impl/nm-keyfile.c:709 +#: ../src/libnm-core-impl/nm-keyfile.c:708 #, c-format msgid "missing prefix length for %s '%s', defaulting to %d" msgstr "ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ ŠæŃŠµŃŃŠŗŃ Š“Š¾Š²Š¶ŠøŠ½Šø Š“Š»Ń %s Ā«%sĀ», ŠæŠ¾Š²ŠµŃŃŠ°ŃŠ¼Š¾ŃŃ Š“Š¾ ŃŠøŠæŠ¾Š²Š¾Š³Š¾, %d" -#: ../src/libnm-core-impl/nm-keyfile.c:1052 +#: ../src/libnm-core-impl/nm-keyfile.c:1051 #: ../src/libnm-core-impl/nm-setting-ovs-external-ids.c:320 #: ../src/libnm-core-impl/nm-setting-user.c:364 #, c-format msgid "invalid value for \"%s\": %s" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń Š“Š»Ń Ā«%sĀ»: %s" -#: ../src/libnm-core-impl/nm-keyfile.c:1130 +#: ../src/libnm-core-impl/nm-keyfile.c:1129 #, c-format msgid "ignoring invalid DNS server IPv%c address '%s'" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Ń Š°Š“ŃŠµŃŃ IPv%c ŃŠµŃŠ²ŠµŃŠ° DNS Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-keyfile.c:1167 +#: ../src/libnm-core-impl/nm-keyfile.c:1166 #: ../src/libnmc-setting/nm-meta-setting-desc.c:1666 #, c-format msgid "invalid option '%s', use one of [%s]" msgstr "" "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ», ŃŠŗŠ¾ŃŠøŃŃŠ°Š¹ŃŠµŃŃ Š¾Š“Š½ŠøŠ¼ ŃŠ· ŃŠ°ŠŗŠøŃ
ŠæŠ°ŃŠ°Š¼ŠµŃŃŃŠ² [%s]" -#: ../src/libnm-core-impl/nm-keyfile.c:1229 +#: ../src/libnm-core-impl/nm-keyfile.c:1228 msgid "ignoring invalid MAC address" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Ń MAC-Š°Š“ŃŠµŃŃ" -#: ../src/libnm-core-impl/nm-keyfile.c:1305 +#: ../src/libnm-core-impl/nm-keyfile.c:1304 #, c-format msgid "ignoring invalid bond option %s%s%s = %s%s%s: %s" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ bond %s%s%s = %s%s%s: %s" -#: ../src/libnm-core-impl/nm-keyfile.c:1495 +#: ../src/libnm-core-impl/nm-keyfile.c:1494 msgid "ignoring invalid SSID" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ SSID" -#: ../src/libnm-core-impl/nm-keyfile.c:1513 +#: ../src/libnm-core-impl/nm-keyfile.c:1512 msgid "ignoring invalid raw password" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š½ŠµŠ¾Š±ŃŠ¾Š±Š»ŠµŠ½ŠøŠ¹ ŠæŠ°ŃŠ¾Š»Ń" -#: ../src/libnm-core-impl/nm-keyfile.c:1658 +#: ../src/libnm-core-impl/nm-keyfile.c:1657 msgid "invalid key/cert value" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń ŠŗŠ»ŃŃŠ°/ŃŠµŃŃŠøŃŃŠŗŠ°ŃŠ°" -#: ../src/libnm-core-impl/nm-keyfile.c:1673 +#: ../src/libnm-core-impl/nm-keyfile.c:1672 #, c-format msgid "invalid key/cert value path \"%s\"" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŃŠ»ŃŃ
Š“Š¾ ŠŗŠ»ŃŃŠ°/ŃŠµŃŃŠøŃŃŠŗŠ°ŃŠ°, Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-keyfile.c:1698 -#: ../src/libnm-core-impl/nm-keyfile.c:1795 +#: ../src/libnm-core-impl/nm-keyfile.c:1697 +#: ../src/libnm-core-impl/nm-keyfile.c:1794 #, c-format msgid "certificate or key file '%s' does not exist" msgstr "ŃŠ°Š¹Š»Š° ŃŠµŃŃŠøŃŃŠŗŠ°ŃŠ° Š°Š±Š¾ ŠŗŠ»ŃŃŠ° Ā«%sĀ» Š½Šµ ŃŃŠ½ŃŃ" -#: ../src/libnm-core-impl/nm-keyfile.c:1711 +#: ../src/libnm-core-impl/nm-keyfile.c:1710 #, c-format msgid "invalid PKCS#11 URI \"%s\"" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š° Š°Š“ŃŠµŃŠ° PKCS#11 Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-keyfile.c:1757 +#: ../src/libnm-core-impl/nm-keyfile.c:1756 msgid "invalid key/cert value data:;base64, is not base64" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Ń Š“Š°Š½Ń Š·Š½Š°ŃŠµŠ½Š½Ń ŠŗŠ»ŃŃŠ°/ŃŠµŃŃŠøŃŃŠŗŠ°ŃŠ° data:;base64, Š½Šµ Ń base64" -#: ../src/libnm-core-impl/nm-keyfile.c:1770 +#: ../src/libnm-core-impl/nm-keyfile.c:1769 msgid "invalid key/cert value data:;base64,file://" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń ŠŗŠ»ŃŃŠ°/ŃŠµŃŃŠøŃŃŠŗŠ°ŃŠ° data:;base64,file://" -#: ../src/libnm-core-impl/nm-keyfile.c:1811 +#: ../src/libnm-core-impl/nm-keyfile.c:1810 msgid "invalid key/cert value is not a valid blob" msgstr "" "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń ŠŗŠ»ŃŃŠ°/ŃŠµŃŃŠøŃŃŠŗŠ°ŃŠ°, Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ» Š½Šµ Ń " "ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š²ŠµŠ»ŠøŠŗŠøŠ¼ Š±ŃŠ½Š°ŃŠ½ŠøŠ¼ Š¾Š±'ŃŠŗŃŠ¾Š¼" -#: ../src/libnm-core-impl/nm-keyfile.c:1913 +#: ../src/libnm-core-impl/nm-keyfile.c:1912 #, c-format msgid "invalid parity value '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŠ°ŃŠ½Š¾ŃŃŃ, Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-keyfile.c:1935 -#: ../src/libnm-core-impl/nm-keyfile.c:3427 +#: ../src/libnm-core-impl/nm-keyfile.c:1934 +#: ../src/libnm-core-impl/nm-keyfile.c:3426 #, c-format msgid "invalid setting: %s" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ: %s" -#: ../src/libnm-core-impl/nm-keyfile.c:1955 +#: ../src/libnm-core-impl/nm-keyfile.c:1954 #, c-format msgid "ignoring invalid team configuration: %s" msgstr "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š½Š°Š»Š°ŃŃŃŠ²Š°Š½Š½Ń ŠŗŠ¾Š¼Š°Š½Š“Šø: %s" -#: ../src/libnm-core-impl/nm-keyfile.c:2038 +#: ../src/libnm-core-impl/nm-keyfile.c:2037 #, c-format msgid "invalid qdisc: %s" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ qdisc: %s" -#: ../src/libnm-core-impl/nm-keyfile.c:2088 +#: ../src/libnm-core-impl/nm-keyfile.c:2087 #, c-format msgid "invalid tfilter: %s" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ tfilter: %s" -#: ../src/libnm-core-impl/nm-keyfile.c:3252 +#: ../src/libnm-core-impl/nm-keyfile.c:3251 #, c-format msgid "error loading setting value: %s" msgstr "ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæŃŠ“ ŃŠ°Ń Š·Š°Š²Š°Š½ŃŠ°Š¶ŠµŠ½Š½Ń Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°: %s" -#: ../src/libnm-core-impl/nm-keyfile.c:3283 -#: ../src/libnm-core-impl/nm-keyfile.c:3295 -#: ../src/libnm-core-impl/nm-keyfile.c:3314 -#: ../src/libnm-core-impl/nm-keyfile.c:3326 -#: ../src/libnm-core-impl/nm-keyfile.c:3338 -#: ../src/libnm-core-impl/nm-keyfile.c:3400 -#: ../src/libnm-core-impl/nm-keyfile.c:3412 +#: ../src/libnm-core-impl/nm-keyfile.c:3282 +#: ../src/libnm-core-impl/nm-keyfile.c:3294 +#: ../src/libnm-core-impl/nm-keyfile.c:3313 +#: ../src/libnm-core-impl/nm-keyfile.c:3325 +#: ../src/libnm-core-impl/nm-keyfile.c:3337 +#: ../src/libnm-core-impl/nm-keyfile.c:3399 +#: ../src/libnm-core-impl/nm-keyfile.c:3411 msgid "value cannot be interpreted as integer" msgstr "Š·Š½Š°ŃŠµŠ½Š½Ń Š½Šµ Š¼Š¾Š¶Šµ Š±ŃŃŠø Š¾Š±ŃŠ¾Š±Š»ŠµŠ½Š¾ ŃŠŗ ŃŃŠ»Šµ ŃŠøŃŠ»Š¾" -#: ../src/libnm-core-impl/nm-keyfile.c:3368 +#: ../src/libnm-core-impl/nm-keyfile.c:3367 #, c-format msgid "ignoring invalid byte element '%u' (not between 0 and 255 inclusive)" msgstr "" "ŃŠ³Š½Š¾ŃŃŃŠ¼Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š±Š°Š¹ŃŠ¾Š²ŠøŠ¹ ŠµŠ»ŠµŠ¼ŠµŠ½Ń Ā«%uĀ» (Š½Šµ Ń Š“ŃŠ°ŠæŠ°Š·Š¾Š½Ń Š²ŃŠ“ 0 Š“Š¾ 255, " "Š²ŠŗŠ»ŃŃŠ½Š¾)" -#: ../src/libnm-core-impl/nm-keyfile.c:3452 +#: ../src/libnm-core-impl/nm-keyfile.c:3451 #, c-format msgid "invalid setting name '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š° Š½Š°Š·Š²Š° ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°, Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-keyfile.c:3499 +#: ../src/libnm-core-impl/nm-keyfile.c:3498 #, c-format msgid "invalid key '%s.%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŠŗŠ»ŃŃ Ā«%s.%sĀ»" -#: ../src/libnm-core-impl/nm-keyfile.c:3515 +#: ../src/libnm-core-impl/nm-keyfile.c:3514 #, c-format msgid "key '%s.%s' is not boolean" msgstr "ŠŗŠ»ŃŃ Ā«%s.%sĀ» Š½Šµ Ń Š±ŃŠ»ŠµŠ²ŠøŠ¼ Š·Š½Š°ŃŠµŠ½Š½ŃŠ¼" -#: ../src/libnm-core-impl/nm-keyfile.c:3532 +#: ../src/libnm-core-impl/nm-keyfile.c:3531 #, c-format msgid "key '%s.%s' is not a uint32" msgstr "ŠŗŠ»ŃŃ Ā«%s.%sĀ» Š½Šµ Ń Š·Š½Š°ŃŠµŠ½Š½ŃŠ¼ uint32" -#: ../src/libnm-core-impl/nm-keyfile.c:3589 +#: ../src/libnm-core-impl/nm-keyfile.c:3588 #, c-format msgid "invalid peer public key in section '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š²ŃŠ“ŠŗŃŠøŃŠøŠ¹ ŠŗŠ»ŃŃ Š²ŃŠ·Š»Š° Ń ŃŠ¾Š·Š“ŃŠ»Ń Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-keyfile.c:3604 +#: ../src/libnm-core-impl/nm-keyfile.c:3603 #, c-format msgid "key '%s.%s' is not a valid 256 bit key in base64 encoding" msgstr "ŠŗŠ»ŃŃ Ā«%s.%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ 256-Š±ŃŃŠ¾Š²ŠøŠ¼ ŠŗŠ»ŃŃŠµŠ¼ Ń ŠŗŠ¾Š“ŃŠ²Š°Š½Š½Ń base64" -#: ../src/libnm-core-impl/nm-keyfile.c:3627 +#: ../src/libnm-core-impl/nm-keyfile.c:3626 #, c-format msgid "key '%s.%s' is not a valid secret flag" msgstr "ŠŗŠ»ŃŃ Ā«%s.%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ ŠæŃŠ°ŠæŠ¾ŃŃŠµŠ¼ ŃŠµŃŃŃŃŠ°ŃŃŠ¹Š½ŠøŃ
Š“Š°Š½ŠøŃ
" -#: ../src/libnm-core-impl/nm-keyfile.c:3650 +#: ../src/libnm-core-impl/nm-keyfile.c:3649 #, c-format msgid "key '%s.%s' is not a integer in range 0 to 2^32" msgstr "ŠŗŠ»ŃŃ Ā«%s.%sĀ» Š½Šµ Ń ŃŃŠ»ŠøŠ¼Šø ŃŠøŃŠ»Š¾Š¼ Ń Š“ŃŠ°ŠæŠ°Š·Š¾Š½Ń Š²ŃŠ“ 0 Š“Š¾ 2^32" -#: ../src/libnm-core-impl/nm-keyfile.c:3666 +#: ../src/libnm-core-impl/nm-keyfile.c:3665 #, c-format msgid "key '%s.%s' is not a valid endpoint" msgstr "ŠŗŠ»ŃŃ Ā«%s.%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½Š¾Ń ŠŗŃŠ½ŃŠµŠ²Š¾Ń ŃŠ¾ŃŠŗŠ¾Ń" -#: ../src/libnm-core-impl/nm-keyfile.c:3692 +#: ../src/libnm-core-impl/nm-keyfile.c:3691 #, c-format msgid "key '%s.%s' has invalid allowed-ips" msgstr "Š“Š»Ń ŠŗŠ»ŃŃŠ° Ā«%s.%sĀ» Š²ŠŗŠ°Š·Š°Š½Š¾ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń allowed-ips" -#: ../src/libnm-core-impl/nm-keyfile.c:3707 +#: ../src/libnm-core-impl/nm-keyfile.c:3706 #, c-format msgid "peer '%s' is invalid: %s" msgstr "Š²ŃŠ·Š¾Š» Ā«%sĀ» Ń Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼: %s" -#: ../src/libnm-core-impl/nm-keyfile.c:4235 +#: ../src/libnm-core-impl/nm-keyfile.c:4234 #, c-format msgid "unsupported option \"%s.%s\" of variant type %s" msgstr "Š½ŠµŠæŃŠ“ŃŃŠøŠ¼ŃŠ²Š°Š½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%s.%sĀ» ŃŠøŠæŃ Š²Š°ŃŃŠ°Š½ŃŠ° %s" @@ -1518,9 +1522,16 @@ msgstr "" "ŠæŃŠ“ŃŃŠøŠ¼ŠŗŠø ŠæŠ°ŃŠ¾Š»ŃŠ² Š½Šµ ŠæŠµŃŠµŠ“Š±Š°ŃŠµŠ½Š¾, ŃŠŗŃŠ¾ ŃŠµŃŃŠøŃŃŠŗŠ°Ń Š½Šµ Š¼ŃŃŃŠøŃŃŃŃ Ń ŠŗŠ»ŃŃŃ " "PKCS#11" +#. normalizable warnings from here on. #: ../src/libnm-core-impl/nm-setting-8021x.c:2612 #: ../src/libnm-core-impl/nm-setting-8021x.c:2652 #: ../src/libnm-core-impl/nm-setting-8021x.c:2671 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2838 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2858 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2878 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2919 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2939 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2995 #: ../src/libnm-core-impl/nm-setting-adsl.c:181 #: ../src/libnm-core-impl/nm-setting-cdma.c:149 #: ../src/libnm-core-impl/nm-setting-cdma.c:159 @@ -1542,6 +1553,7 @@ msgstr "" #: ../src/libnm-core-impl/nm-setting-wireless-security.c:972 #: ../src/libnm-core-impl/nm-setting-wireless-security.c:1000 #: ../src/libnm-core-impl/nm-setting.c:2396 +#, c-format msgid "property is empty" msgstr "Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ Ń ŠæŠ¾ŃŠ¾Š¶Š½ŃŠ¾Ń" @@ -1582,15 +1594,15 @@ msgstr "Š¼Š¾Š¶Š½Š° Š²Š¼ŠøŠŗŠ°ŃŠø Š»ŠøŃŠµ Š“Š»Ń Š·'ŃŠ“Š½Š°Š½Ń Ethernet" #: ../src/libnm-core-impl/nm-setting-wireless.c:945 #: ../src/libnm-core-impl/nm-setting-wireless.c:958 #: ../src/libnm-core-impl/nm-setting-wpan.c:161 -#: ../src/libnm-core-impl/nm-utils.c:4152 +#: ../src/libnm-core-impl/nm-utils.c:4151 msgid "property is invalid" msgstr "Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ Ń Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š¾Ń" -#: ../src/libnm-core-impl/nm-setting-8021x.c:2831 -#: ../src/libnm-core-impl/nm-setting-8021x.c:2844 -#: ../src/libnm-core-impl/nm-setting-8021x.c:2857 -#: ../src/libnm-core-impl/nm-setting-8021x.c:2891 -#: ../src/libnm-core-impl/nm-setting-8021x.c:2904 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2832 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2852 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2872 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2913 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2933 #: ../src/libnm-core-impl/nm-setting-adsl.c:193 #: ../src/libnm-core-impl/nm-setting-adsl.c:206 #: ../src/libnm-core-impl/nm-setting-bluetooth.c:145 @@ -1599,7 +1611,7 @@ msgstr "Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ Ń Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š¾Ń" msgid "'%s' is not a valid value for the property" msgstr "Ā«%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š·Š½Š°ŃŠµŠ½Š½ŃŠ¼ Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ" -#: ../src/libnm-core-impl/nm-setting-8021x.c:2870 +#: ../src/libnm-core-impl/nm-setting-8021x.c:2891 msgid "invalid auth flags" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Ń ŠæŃŠ°ŠæŠ¾ŃŃŃ ŃŠ¾Š·ŠæŃŠ·Š½Š°Š²Š°Š½Š½Ń" @@ -1629,95 +1641,95 @@ msgid "A connection with a '%s' setting must have the slave-type set to '%s'" msgstr "" "ŠŠ»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń Š· ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ¾Š¼ Ā«%sĀ» Š¼Š°Ń Š±ŃŃŠø Š²ŃŃŠ°Š½Š¾Š²Š»ŠµŠ½Š¾ ŃŠøŠæ ŠæŃŠ“Š»ŠµŠ³Š»Š¾ŃŃŃ Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:513 +#: ../src/libnm-core-impl/nm-setting-bond.c:504 #, c-format msgid "'%s' option is empty" msgstr "ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ» Ń ŠæŠ¾ŃŠ¾Š¶Š½ŃŠ¼" -#: ../src/libnm-core-impl/nm-setting-bond.c:522 +#: ../src/libnm-core-impl/nm-setting-bond.c:513 #, c-format msgid "'%s' is not a valid IPv4 address for '%s' option" msgstr "Ā«%sĀ» Š½Šµ Ń ŠæŃŠøŠæŃŃŃŠøŠ¼Š¾Ń Š°Š“ŃŠµŃŠ¾Ń IPv4 Š“Š»Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:549 +#: ../src/libnm-core-impl/nm-setting-bond.c:540 #, c-format msgid "missing option name" msgstr "Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š½Š°Š·Š²Šø ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°" -#: ../src/libnm-core-impl/nm-setting-bond.c:554 +#: ../src/libnm-core-impl/nm-setting-bond.c:545 #, c-format msgid "invalid option '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:590 +#: ../src/libnm-core-impl/nm-setting-bond.c:581 #, c-format msgid "invalid value '%s' for option '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ» Š“Š»Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:837 +#: ../src/libnm-core-impl/nm-setting-bond.c:828 #, c-format msgid "mandatory option '%s' is missing" msgstr "ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ Š¾Š±Š¾Š²'ŃŠ·ŠŗŠ¾Š²ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:847 +#: ../src/libnm-core-impl/nm-setting-bond.c:838 #, c-format msgid "'%s' is not a valid value for '%s'" msgstr "Ā«%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š·Š½Š°ŃŠµŠ½Š½ŃŠ¼ Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:860 +#: ../src/libnm-core-impl/nm-setting-bond.c:851 #, c-format msgid "'%s=%s' is incompatible with '%s > 0'" msgstr "Ā«%s=%sĀ» Ń Š½ŠµŃŃŠ¼ŃŃŠ½ŠøŠ¼ Š· Ā«%s > 0Ā»" -#: ../src/libnm-core-impl/nm-setting-bond.c:877 +#: ../src/libnm-core-impl/nm-setting-bond.c:868 #, c-format msgid "'%s' is not valid for the '%s' option: %s" msgstr "Ā«%sĀ» Ń Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š“Š»Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ»: %s" -#: ../src/libnm-core-impl/nm-setting-bond.c:889 +#: ../src/libnm-core-impl/nm-setting-bond.c:880 #, c-format msgid "'%s' option is only valid for '%s=%s'" msgstr "ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ» Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŠ²Š°ŃŠø, Š»ŠøŃŠµ ŃŠŗŃŠ¾ Ā«%s=%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:902 +#: ../src/libnm-core-impl/nm-setting-bond.c:893 #, c-format msgid "'%s=%s' is not a valid configuration for '%s'" msgstr "Ā«%s=%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š½Š°Š»Š°ŃŃŃŠ²Š°Š½Š½ŃŠ¼ Š“Š»Ń Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:917 -#: ../src/libnm-core-impl/nm-setting-bond.c:928 -#: ../src/libnm-core-impl/nm-setting-bond.c:941 +#: ../src/libnm-core-impl/nm-setting-bond.c:908 +#: ../src/libnm-core-impl/nm-setting-bond.c:919 +#: ../src/libnm-core-impl/nm-setting-bond.c:932 #, c-format msgid "'%s' option requires '%s' option to be enabled" msgstr "Š²ŠøŠŗŠ¾ŃŠøŃŃŠ°Š½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ» Š²ŠøŠ¼Š°Š³Š°Ń Š²Š¼ŠøŠŗŠ°Š½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:958 +#: ../src/libnm-core-impl/nm-setting-bond.c:949 #, c-format msgid "'%s' option needs to be a value multiple of '%s' value" msgstr "Š·Š½Š°ŃŠµŠ½Š½ŃŠ¼ ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ» Š¼Š°Ń Š±ŃŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń, ŠŗŃŠ°ŃŠ½Šµ Š“Š¾ Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:975 -#: ../src/libnm-core-impl/nm-setting-bond.c:986 +#: ../src/libnm-core-impl/nm-setting-bond.c:966 +#: ../src/libnm-core-impl/nm-setting-bond.c:977 #, c-format msgid "'%s' option requires '%s' option to be set" msgstr "Š²ŠøŠŗŠ¾ŃŠøŃŃŠ°Š½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ» Š²ŠøŠ¼Š°Š³Š°Ń Š²ŃŃŠ°Š½Š¾Š²Š»ŠµŠ½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:999 +#: ../src/libnm-core-impl/nm-setting-bond.c:990 #, c-format msgid "'%s' option is only valid with mode '%s'" msgstr "ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ» Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š»ŠøŃŠµ Ń ŃŠµŠ¶ŠøŠ¼Ń Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-setting-bond.c:1012 +#: ../src/libnm-core-impl/nm-setting-bond.c:1003 #, c-format msgid "'%s' and '%s' cannot have different values" msgstr "ŠŠ½Š°ŃŠµŠ½Š½Ń Ā«%sĀ» Ń Ā«%sĀ» Š½Šµ Š¼Š¾Š¶ŃŃŃ Š±ŃŃŠø ŃŃŠ·Š½ŠøŠ¼Šø" -#: ../src/libnm-core-impl/nm-setting-bond.c:1035 +#: ../src/libnm-core-impl/nm-setting-bond.c:1026 #, c-format msgid "'%s' option should be string" msgstr "ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ» Š¼Š°Ń Š±ŃŃŠø ŃŃŠ“ŠŗŠ¾Š¼" -#: ../src/libnm-core-impl/nm-setting-bond.c:1048 +#: ../src/libnm-core-impl/nm-setting-bond.c:1039 #, c-format msgid "'%s' option is not valid with mode '%s'" msgstr "ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ» Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š· ŃŠµŠ¶ŠøŠ¼Š¾Š¼ Ā«%sĀ»" @@ -1764,6 +1776,11 @@ msgstr "Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ¾Š¼" msgid "'%s' option must be a power of 2" msgstr "ŠŠ½Š°ŃŠµŠ½Š½ŃŠ¼ ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ» Š¼Š°Ń Š±ŃŃŠø ŃŃŠµŠæŃŠ½Ń 2" +#: ../src/libnm-core-impl/nm-setting-bridge.c:1318 +#| msgid "vlan setting should have a ethernet setting as well" +msgid "bridge connection should have a ethernet setting as well" +msgstr "Š·'ŃŠ“Š½Š°Š½Š½Ń Š¼ŃŃŃŠŗŠ° Š¼Š°Ń ŃŃŠæŃŠ¾Š²Š¾Š“Š¶ŃŠ²Š°ŃŠøŃŃ ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ¾Š¼ ethernet" + #: ../src/libnm-core-impl/nm-setting-connection.c:1005 #, c-format msgid "setting required for connection of type '%s'" @@ -1945,7 +1962,11 @@ msgstr "" "Š£ Š·Š°ŠæŠøŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Š·Š°ŠŗŃŠøŃŠ¾Š³Š¾ ŠŗŠ»ŃŃŠ° InfiniBand Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š½Š°Š·Š²Šø Š±Š°ŃŃŠŗŃŠ²ŃŃŠŗŠ¾Š³Š¾ " "ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ" -#: ../src/libnm-core-impl/nm-setting-infiniband.c:264 +#: ../src/libnm-core-impl/nm-setting-infiniband.c:248 +msgid "the values 0 and 0x8000 are not allowed" +msgstr "Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŠ²Š°ŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń 0 Ń 0x8000" + +#: ../src/libnm-core-impl/nm-setting-infiniband.c:274 #, c-format msgid "" "interface name of software infiniband device must be '%s' or unset (instead " @@ -1954,7 +1975,19 @@ msgstr "" "Š½Š°Š·Š²Š¾Ń ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ ŠæŃŠ¾Š³ŃŠ°Š¼Š½Š¾Š³Š¾ ŠæŃŠøŃŃŃŠ¾Ń infiniband Š¼Š°Ń Š±ŃŃŠø Ā«%sĀ» Š°Š±Š¾ Š½Š°Š·Š²Ń " "Š¼Š°Ń Š±ŃŃŠø Š½Šµ Š²ŃŃŠ°Š½Š¾Š²Š»ŠµŠ½Š¾ (Š·Š°Š¼ŃŃŃŃ Š½ŠµŃ Š¼Š°Ń Š±ŃŃŠø Ā«%sĀ»)" -#: ../src/libnm-core-impl/nm-setting-infiniband.c:292 +#: ../src/libnm-core-impl/nm-setting-infiniband.c:282 +#, c-format +#| msgid "" +#| "interface name of software infiniband device must be '%s' or unset " +#| "(instead it is '%s')" +msgid "" +"interface name of software infiniband device with MAC address must be unset " +"(instead it is '%s')" +msgstr "" +"Š½Š°Š·Š²Ń ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ ŠæŃŠ¾Š³ŃŠ°Š¼Š½Š¾Š³Š¾ ŠæŃŠøŃŃŃŠ¾Ń infiniband Š· MAC-Š°Š“ŃŠµŃŠ¾Ń Š¼Š°Ń Š±ŃŃŠø Š½Šµ" +" Š²ŃŃŠ°Š½Š¾Š²Š»ŠµŠ½Š¾ (Š·Š°Š¼ŃŃŃŃ Š½ŠµŃ Š¼Š°Ń Š±ŃŃŠø Ā«%sĀ»)" + +#: ../src/libnm-core-impl/nm-setting-infiniband.c:310 #, c-format msgid "mtu can be at most %u but it is %u" msgstr "mtu Š½Šµ Š¼Š¾Š¶Šµ ŠæŠµŃŠµŠ²ŠøŃŃŠ²Š°ŃŠø %u, Š°Š»Šµ Š¼Š°ŃŠ¼Š¾ %u" @@ -3132,230 +3165,230 @@ msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŃŠøŠæ D-Bus Ā«%sĀ»" msgid "invalid link-watchers: %s" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń link-watchers: %s" -#: ../src/libnm-core-impl/nm-utils.c:2256 +#: ../src/libnm-core-impl/nm-utils.c:2255 #, c-format msgid "'%s' is not a valid handle." msgstr "Ā«%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š“ŠµŃŠŗŃŠøŠæŃŠ¾ŃŠ¾Š¼." -#: ../src/libnm-core-impl/nm-utils.c:2404 +#: ../src/libnm-core-impl/nm-utils.c:2403 #, c-format msgid "'%s' unexpected: parent already specified." msgstr "ŠŠµŠ¾ŃŃŠŗŃŠ²Š°Š½Šµ Ā«%sĀ»: Š±Š°ŃŃŠŗŃŠ²ŃŃŠŗŠøŠ¹ Š·Š°ŠæŠøŃ Š²Š¶Šµ Š²ŠŗŠ°Š·Š°Š½Š¾." -#: ../src/libnm-core-impl/nm-utils.c:2422 +#: ../src/libnm-core-impl/nm-utils.c:2421 #, c-format msgid "invalid handle: '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š“ŠµŃŠŗŃŠøŠæŃŠ¾Ń: Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-utils.c:2444 +#: ../src/libnm-core-impl/nm-utils.c:2443 msgid "parent not specified." msgstr "Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š±Š°ŃŃŠŗŃŠ²ŃŃŠŗŠøŠ¹ Š·Š°ŠæŠøŃ." -#: ../src/libnm-core-impl/nm-utils.c:2508 +#: ../src/libnm-core-impl/nm-utils.c:2507 #, c-format msgid "unsupported qdisc option: '%s'." msgstr "Š½ŠµŠæŃŠ“ŃŃŠøŠ¼ŃŠ²Š°Š½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ qdisc: Ā«%sĀ»." -#: ../src/libnm-core-impl/nm-utils.c:2638 +#: ../src/libnm-core-impl/nm-utils.c:2637 msgid "action name missing." msgstr "Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š½Š°Š·Š²Šø Š“ŃŃ." -#: ../src/libnm-core-impl/nm-utils.c:2663 +#: ../src/libnm-core-impl/nm-utils.c:2662 #, c-format msgid "unsupported action option: '%s'." msgstr "Š½ŠµŠæŃŠ“ŃŃŠøŠ¼ŃŠ²Š°Š½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ Š“ŃŃ: Ā«%sĀ»." -#: ../src/libnm-core-impl/nm-utils.c:2800 +#: ../src/libnm-core-impl/nm-utils.c:2799 msgid "invalid action: " msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š° Š“ŃŃ: " -#: ../src/libnm-core-impl/nm-utils.c:2804 +#: ../src/libnm-core-impl/nm-utils.c:2803 #, c-format msgid "unsupported tfilter option: '%s'." msgstr "Š½ŠµŠæŃŠ“ŃŃŠøŠ¼ŃŠ²Š°Š½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ tfilter: Ā«%sĀ»." -#: ../src/libnm-core-impl/nm-utils.c:3104 +#: ../src/libnm-core-impl/nm-utils.c:3103 #, c-format msgid "failed stat file %s: %s" msgstr "Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š¾ŃŃŠøŠ¼Š°ŃŠø ŃŃŠ°ŃŠøŃŃŠøŃŠ½Ń Š“Š°Š½Ń ŃŠ¾Š“Š¾ ŃŠ°Š¹Š»Š° %s: %s" -#: ../src/libnm-core-impl/nm-utils.c:3115 +#: ../src/libnm-core-impl/nm-utils.c:3114 #, c-format msgid "not a file (%s)" msgstr "Š½Šµ Ń ŃŠ°Š¹Š»Š¾Š¼ (%s)" -#: ../src/libnm-core-impl/nm-utils.c:3126 +#: ../src/libnm-core-impl/nm-utils.c:3125 #, c-format msgid "invalid file owner %d for %s" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š²Š»Š°ŃŠ½ŠøŠŗ ŃŠ°Š¹Š»Š°, %d, %s" -#: ../src/libnm-core-impl/nm-utils.c:3138 +#: ../src/libnm-core-impl/nm-utils.c:3137 #, c-format msgid "file permissions for %s" msgstr "ŃŠ°Š¹Š»Š¾Š²Ń ŠæŃŠ°Š²Š° Š“Š¾ŃŃŃŠæŃ Š“Š¾ %s" -#: ../src/libnm-core-impl/nm-utils.c:3148 +#: ../src/libnm-core-impl/nm-utils.c:3147 #, c-format msgid "reject %s" msgstr "Š²ŃŠ“Š¼Š¾Š²ŠøŃŠø %s" -#: ../src/libnm-core-impl/nm-utils.c:3168 +#: ../src/libnm-core-impl/nm-utils.c:3167 #, c-format msgid "path is not absolute (%s)" msgstr "ŃŠ»ŃŃ
Š½Šµ Ń Š°Š±ŃŠ¾Š»ŃŃŠ½ŠøŠ¼ (%s)" -#: ../src/libnm-core-impl/nm-utils.c:3183 +#: ../src/libnm-core-impl/nm-utils.c:3182 #, c-format msgid "Plugin file does not exist (%s)" msgstr "Š¤Š°Š¹Š»Š° Š“Š¾Š“Š°ŃŠŗŠ° Š½Šµ ŃŃŠ½ŃŃ (%s)" -#: ../src/libnm-core-impl/nm-utils.c:3192 +#: ../src/libnm-core-impl/nm-utils.c:3191 #, c-format msgid "Plugin is not a valid file (%s)" msgstr "ŠŠ¾Š“Š°ŃŠ¾Šŗ Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ ŃŠ°Š¹Š»Š¾Š¼ (%s)" -#: ../src/libnm-core-impl/nm-utils.c:3203 +#: ../src/libnm-core-impl/nm-utils.c:3202 #, c-format msgid "libtool archives are not supported (%s)" msgstr "ŠŃŠ“ŃŃŠøŠ¼ŠŗŠø Š°ŃŃ
ŃŠ²ŃŠ² libtool Š½Šµ ŠæŠµŃŠµŠ“Š±Š°ŃŠµŠ½Š¾ (%s)" -#: ../src/libnm-core-impl/nm-utils.c:3280 +#: ../src/libnm-core-impl/nm-utils.c:3279 #, c-format msgid "Could not find \"%s\" binary" msgstr "ŠŠµ Š²Š“Š°Š»Š¾ŃŃ Š·Š½Š°Š¹ŃŠø Š²ŠøŠŗŠ¾Š½ŃŠ²Š°Š½ŠøŠ¹ ŃŠ°Š¹Š» Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-utils.c:4103 +#: ../src/libnm-core-impl/nm-utils.c:4102 msgid "unknown secret flags" msgstr "Š½ŠµŠ²ŃŠ“Š¾Š¼Ń ŠæŃŠ°ŠæŠ¾ŃŃŃ ŃŠµŃŃŃŃŠ°ŃŃŠ¹Š½ŠøŃ
Š“Š°Š½ŠøŃ
" -#: ../src/libnm-core-impl/nm-utils.c:4113 +#: ../src/libnm-core-impl/nm-utils.c:4112 msgid "conflicting secret flags" msgstr "ŠŗŠ¾Š½ŃŠ»ŃŠŗŃ ŠæŃŠ°ŠæŠ¾ŃŃŃŠ² ŃŠµŃŃŃŃŠ°ŃŃŠ¹Š½ŠøŃ
Š“Š°Š½ŠøŃ
" -#: ../src/libnm-core-impl/nm-utils.c:4124 +#: ../src/libnm-core-impl/nm-utils.c:4123 msgid "secret flags must not be \"not-required\"" msgstr "ŠæŃŠ°ŠæŠ¾ŃŃŃ ŃŠµŃŃŃŃŠ°ŃŃŠ¹Š½ŠøŃ
Š“Š°Š½ŠøŃ
Š½Šµ Š¼Š¾Š¶ŃŃŃ Š±ŃŃŠø Ā«not-requiredĀ»" -#: ../src/libnm-core-impl/nm-utils.c:4132 +#: ../src/libnm-core-impl/nm-utils.c:4131 msgid "unsupported secret flags" msgstr "Š½ŠµŠæŃŠ“ŃŃŠøŠ¼ŃŠ²Š°Š½Ń ŠæŃŠ°ŠæŠ¾ŃŃŃ ŃŠµŃŃŃŃŠ°ŃŃŠ¹Š½ŠøŃ
Š“Š°Š½ŠøŃ
" -#: ../src/libnm-core-impl/nm-utils.c:4162 +#: ../src/libnm-core-impl/nm-utils.c:4161 msgid "can't be simultaneously disabled and enabled" msgstr "Š½Šµ Š¼Š¾Š¶Šµ Š±ŃŃŠø Š¾Š“Š½Š¾ŃŠ°ŃŠ½Š¾ Š²ŠøŠ¼ŠŗŠ½ŠµŠ½Š¾ Ń ŃŠ²ŃŠ¼ŠŗŠ½ŠµŠ½Š¾" -#: ../src/libnm-core-impl/nm-utils.c:4170 +#: ../src/libnm-core-impl/nm-utils.c:4169 msgid "WPS is required" msgstr "ŠŠ¾ŃŃŃŠ±Š½Š° WPS" -#: ../src/libnm-core-impl/nm-utils.c:4238 +#: ../src/libnm-core-impl/nm-utils.c:4237 #, c-format msgid "not a valid ethernet MAC address for mask at position %lld" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š° Š°Š“ŃŠµŃŠ° MAC ethernet Š“Š»Ń Š¼Š°ŃŠŗŠø Ń ŠæŠ¾Š·ŠøŃŃŃ %lld" -#: ../src/libnm-core-impl/nm-utils.c:4257 +#: ../src/libnm-core-impl/nm-utils.c:4256 #, c-format msgid "not a valid ethernet MAC address #%u at position %lld" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š° Š°Š“ŃŠµŃŠ° MAC ethernet #%u Ń ŠæŠ¾Š·ŠøŃŃŃ %lld" -#: ../src/libnm-core-impl/nm-utils.c:4889 +#: ../src/libnm-core-impl/nm-utils.c:4888 msgid "not valid utf-8" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Ń Š“Š°Š½Ń UTF-8" -#: ../src/libnm-core-impl/nm-utils.c:4910 -#: ../src/libnm-core-impl/nm-utils.c:4963 +#: ../src/libnm-core-impl/nm-utils.c:4909 +#: ../src/libnm-core-impl/nm-utils.c:4962 msgid "is not a JSON object" msgstr "Š½Šµ Ń Š¾Š±'ŃŠŗŃŠ¾Š¼ JSON" -#: ../src/libnm-core-impl/nm-utils.c:4939 +#: ../src/libnm-core-impl/nm-utils.c:4938 msgid "value is NULL" msgstr "Š·Š½Š°ŃŠµŠ½Š½ŃŠ¼ Ń NULL" -#: ../src/libnm-core-impl/nm-utils.c:4939 +#: ../src/libnm-core-impl/nm-utils.c:4938 msgid "value is empty" msgstr "ŠæŠ¾ŃŠ¾Š¶Š½Ń Š·Š½Š°ŃŠµŠ½Š½Ń" -#: ../src/libnm-core-impl/nm-utils.c:4951 +#: ../src/libnm-core-impl/nm-utils.c:4950 #, c-format msgid "invalid JSON at position %d (%s)" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŠŗŠ¾Š“ JSON Š½Š° ŠæŠ¾Š·ŠøŃŃŃ %d (%s)" -#: ../src/libnm-core-impl/nm-utils.c:5079 -#: ../src/libnm-core-impl/nm-utils.c:5099 +#: ../src/libnm-core-impl/nm-utils.c:5078 +#: ../src/libnm-core-impl/nm-utils.c:5098 msgid "unterminated escape sequence" msgstr "Š½ŠµŠ·Š°Š²ŠµŃŃŠµŠ½Š° ŠµŠŗŃŠ°Š½Š¾Š²Š°Š½Š° ŠæŠ¾ŃŠ»ŃŠ“Š¾Š²Š½ŃŃŃŃ" -#: ../src/libnm-core-impl/nm-utils.c:5125 +#: ../src/libnm-core-impl/nm-utils.c:5124 #, c-format msgid "unknown attribute '%s'" msgstr "Š½ŠµŠ²ŃŠ“Š¾Š¼ŠøŠ¹ Š°ŃŃŠøŠ±ŃŃ Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-utils.c:5143 +#: ../src/libnm-core-impl/nm-utils.c:5142 #, c-format msgid "missing key-value separator '%c' after '%s'" msgstr "ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ ŃŠ¾Š·Š“ŃŠ»ŃŠ½ŠøŠŗ ŠæŠ°Ń ŠŗŠ»ŃŃ-Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%cĀ» ŠæŃŃŠ»Ń Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-utils.c:5163 +#: ../src/libnm-core-impl/nm-utils.c:5162 #, c-format msgid "invalid uint32 value '%s' for attribute '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń uint32 Ā«%sĀ» Š°ŃŃŠøŠ±ŃŃŠ° Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-utils.c:5177 +#: ../src/libnm-core-impl/nm-utils.c:5176 #, c-format msgid "invalid int32 value '%s' for attribute '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń int32 Ā«%sĀ» Š°ŃŃŠøŠ±ŃŃŠ° Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-utils.c:5190 +#: ../src/libnm-core-impl/nm-utils.c:5189 #, c-format msgid "invalid uint64 value '%s' for attribute '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń uint64 Ā«%sĀ» Š°ŃŃŠøŠ±ŃŃŠ° Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-utils.c:5203 +#: ../src/libnm-core-impl/nm-utils.c:5202 #, c-format msgid "invalid uint8 value '%s' for attribute '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń uint8 Ā«%sĀ» Š°ŃŃŠøŠ±ŃŃŠ° Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-utils.c:5217 +#: ../src/libnm-core-impl/nm-utils.c:5216 #, c-format msgid "invalid boolean value '%s' for attribute '%s'" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š±ŃŠ»ŠµŠ²Šµ Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ» Š°ŃŃŠøŠ±ŃŃŠ° Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-utils.c:5231 +#: ../src/libnm-core-impl/nm-utils.c:5230 #, c-format msgid "unsupported attribute '%s' of type '%s'" msgstr "Š½ŠµŠæŃŠ“ŃŃŠøŠ¼ŃŠ²Š°Š½ŠøŠ¹ Š°ŃŃŠøŠ±ŃŃ Ā«%sĀ» ŃŠøŠæŃ Ā«%sĀ»" -#: ../src/libnm-core-impl/nm-utils.c:5532 +#: ../src/libnm-core-impl/nm-utils.c:5531 #, c-format msgid "Bridge VLANs %d and %d are not sorted by ascending vid" msgstr "VLAN Š¼ŃŃŃŠŗŠ° %d Ń %d Š½Šµ ŃŠæŠ¾ŃŃŠ“ŠŗŠ¾Š²Š°Š½Š¾ Š·Š° Š·ŃŠ¾ŃŃŠ°Š½Š½ŃŠ¼ vid" -#: ../src/libnm-core-impl/nm-utils.c:5556 +#: ../src/libnm-core-impl/nm-utils.c:5555 #, c-format msgid "duplicate bridge VLAN vid %u" msgstr "Š“ŃŠ±Š»ŃŠŗŠ°Ń Š¼ŃŃŃŠŗŠ° vid VLAN %u" -#: ../src/libnm-core-impl/nm-utils.c:5568 +#: ../src/libnm-core-impl/nm-utils.c:5567 msgid "only one VLAN can be the PVID" msgstr "Š»ŠøŃŠµ Š¾Š“Š½Š° Š· VLAN Š¼Š¾Š¶Šµ Š±ŃŃŠø PVID" -#: ../src/libnm-core-impl/nm-utils.c:5613 +#: ../src/libnm-core-impl/nm-utils.c:5612 #, c-format msgid "unknown flags 0x%x" msgstr "Š½ŠµŠ²ŃŠ“Š¾Š¼Ń ŠæŃŠ°ŠæŠ¾ŃŃŃ 0x%x" -#: ../src/libnm-core-impl/nm-utils.c:5625 +#: ../src/libnm-core-impl/nm-utils.c:5624 msgid "" "'fqdn-no-update' and 'fqdn-serv-update' flags cannot be set at the same time" msgstr "" "Š½Šµ Š¼Š¾Š¶Š½Š° Š¾Š“Š½Š¾ŃŠ°ŃŠ½Š¾ Š²ŃŃŠ°Š½Š¾Š²Š»ŃŠ²Š°ŃŠø ŠæŃŠ°ŠæŠ¾ŃŃŃ Ā«fqdn-no-updateĀ» Ń Ā«fqdn-serv-" "updateĀ»" -#: ../src/libnm-core-impl/nm-utils.c:5636 +#: ../src/libnm-core-impl/nm-utils.c:5635 msgid "'fqdn-clear-flags' flag is incompatible with other FQDN flags" msgstr "ŠæŃŠ°ŠæŠ¾ŃŠµŃŃ Ā«fqdn-clear-flagsĀ» Ń Š½ŠµŃŃŠ¼ŃŃŠ½ŠøŠ¼ ŃŠ· ŃŠ½ŃŠøŠ¼Šø ŠæŃŠ°ŠæŠ¾ŃŃŃŠ¼Šø FQDN" -#: ../src/libnm-core-impl/nm-utils.c:5644 +#: ../src/libnm-core-impl/nm-utils.c:5643 msgid "DHCPv6 does not support the E (encoded) FQDN flag" msgstr "Ń DHCPv6 Š½Šµ ŠæŠµŃŠµŠ“Š±Š°ŃŠµŠ½Š¾ ŠæŃŠ“ŃŃŠøŠ¼ŠŗŠø ŠæŃŠ°ŠæŠ¾ŃŃŃ E (Š·Š°ŠŗŠ¾Š“Š¾Š²Š°Š½Š¾) FQDN" @@ -3772,36 +3805,36 @@ msgstr "ŠŠµ Š²Š“Š°Š»Š¾ŃŃ ŃŠ¾Š·ŠæŃŠ·Š½Š°ŃŠø ŃŠµŃŃŠøŃŃŠŗŠ°Ń" msgid "not a valid private key" msgstr "Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š·Š°ŠŗŃŠøŃŠøŠ¼ ŠŗŠ»ŃŃŠµŠ¼" -#: ../src/libnm-glib-aux/nm-shared-utils.c:2669 +#: ../src/libnm-glib-aux/nm-shared-utils.c:2667 #, c-format msgid "object class '%s' has no property named '%s'" msgstr "Ń ŠŗŠ»Š°ŃŃ Š¾Š±'ŃŠŗŃŃŠ² Ā«%sĀ» Š½ŠµŠ¼Š°Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ ŃŠ· Š½Š°Š·Š²Š¾Ń Ā«%sĀ»" -#: ../src/libnm-glib-aux/nm-shared-utils.c:2678 +#: ../src/libnm-glib-aux/nm-shared-utils.c:2676 #, c-format msgid "property '%s' of object class '%s' is not writable" msgstr "Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ Ā«%sĀ» ŠŗŠ»Š°ŃŃ Š¾Š±'ŃŠŗŃŃŠ² Ā«%sĀ» Ń Š½ŠµŠæŃŠøŠ“Š°ŃŠ½Š¾Ń Š“Š¾ Š·Š°ŠæŠøŃŃ" -#: ../src/libnm-glib-aux/nm-shared-utils.c:2687 +#: ../src/libnm-glib-aux/nm-shared-utils.c:2685 #, c-format msgid "" "construct property \"%s\" for object '%s' can't be set after construction" msgstr "" "Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ construct Ā«%sĀ» Š¾Š±'ŃŠŗŃŠ° Ā«%sĀ» Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŃŃŠ°Š½Š¾Š²Š»ŃŠ²Š°ŃŠø ŠæŃŃŠ»Ń ŠæŠ¾Š±ŃŠ“Š¾Š²Šø" -#: ../src/libnm-glib-aux/nm-shared-utils.c:2698 +#: ../src/libnm-glib-aux/nm-shared-utils.c:2696 #, c-format msgid "'%s::%s' is not a valid property name; '%s' is not a GObject subtype" msgstr "Ā«%s::%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½Š¾Ń Š½Š°Š·Š²Š¾Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ; Ā«%sĀ» Š½Šµ Ń ŠæŃŠ“ŃŠøŠæŠ¾Š¼ GObject" -#: ../src/libnm-glib-aux/nm-shared-utils.c:2711 +#: ../src/libnm-glib-aux/nm-shared-utils.c:2709 #, c-format msgid "unable to set property '%s' of type '%s' from value of type '%s'" msgstr "" "Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²ŃŃŠ°Š½Š¾Š²ŠøŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ Ā«%sĀ» ŃŠøŠæŃ Ā«%sĀ» Š½Š° Š¾ŃŠ½Š¾Š²Ń Š·Š½Š°ŃŠµŠ½Š½Ń " "ŃŠøŠæŃ Ā«%sĀ»" -#: ../src/libnm-glib-aux/nm-shared-utils.c:2723 +#: ../src/libnm-glib-aux/nm-shared-utils.c:2721 #, c-format msgid "" "value \"%s\" of type '%s' is invalid or out of range for property '%s' of " @@ -3810,48 +3843,48 @@ msgstr "" "Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ» ŃŠøŠæŃ Ā«%sĀ» Ń Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š“Š»Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ Ā«%sĀ» ŃŠøŠæŃ Ā«%sĀ» Š°Š±Š¾ Š½Šµ " "Š½Š°Š»ŠµŠ¶ŠøŃŃ Š“Š¾ ŠæŃŠøŠæŃŃŃŠøŠ¼Š¾Š³Š¾ Š“ŃŠ°ŠæŠ°Š·Š¾Š½Ń Š·Š½Š°ŃŠµŠ½Ń" -#: ../src/libnm-glib-aux/nm-shared-utils.c:5688 +#: ../src/libnm-glib-aux/nm-shared-utils.c:5687 msgid "interface name is missing" msgstr "ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ Š½Š°Š·Š²Ń ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ" -#: ../src/libnm-glib-aux/nm-shared-utils.c:5696 +#: ../src/libnm-glib-aux/nm-shared-utils.c:5695 msgid "interface name is too short" msgstr "Š½Š°Š·Š²Š° ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ Ń Š½Š°Š“ŃŠ¾ ŠŗŠ¾ŃŠ¾ŃŠŗŠ¾Ń" -#: ../src/libnm-glib-aux/nm-shared-utils.c:5704 +#: ../src/libnm-glib-aux/nm-shared-utils.c:5703 msgid "interface name is reserved" msgstr "ŃŠ°ŠŗŃ Š½Š°Š·Š²Ń ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ Š·Š°ŃŠµŠ·ŠµŃŠ²Š¾Š²Š°Š½Š¾" -#: ../src/libnm-glib-aux/nm-shared-utils.c:5717 +#: ../src/libnm-glib-aux/nm-shared-utils.c:5716 msgid "interface name contains an invalid character" msgstr "Š½Š°Š·Š²Š° ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ Š¼ŃŃŃŠøŃŃ Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŃŠøŠ¼Š²Š¾Š»" -#: ../src/libnm-glib-aux/nm-shared-utils.c:5725 +#: ../src/libnm-glib-aux/nm-shared-utils.c:5724 msgid "interface name is longer than 15 characters" msgstr "Š½Š°Š·Š²Š° ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ Ń Š“Š¾Š²ŃŠ¾Ń Š·Š° 15 ŃŠøŠ¼Š²Š¾Š»ŃŠ²" -#: ../src/libnm-glib-aux/nm-shared-utils.c:5750 +#: ../src/libnm-glib-aux/nm-shared-utils.c:5749 #, c-format msgid "'%%' is not allowed in interface names" msgstr "Ā«%%Ā» Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŠ²Š°ŃŠø Ń Š½Š°Š·Š²Š°Ń
ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃŠ²" -#: ../src/libnm-glib-aux/nm-shared-utils.c:5762 +#: ../src/libnm-glib-aux/nm-shared-utils.c:5761 #, c-format msgid "'%s' is not allowed as interface name" msgstr "Ā«%sĀ» Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŠ²Š°ŃŠø ŃŠŗ Š½Š°Š·Š²Ń ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ" -#: ../src/libnm-glib-aux/nm-shared-utils.c:5784 +#: ../src/libnm-glib-aux/nm-shared-utils.c:5783 msgid "" "interface name must be alphanumerical with no forward or backward slashes" msgstr "" "Š½Š°Š·Š²Š° ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ Š¼Š°Ń ŃŠŗŠ»Š°Š“Š°ŃŠøŃŃ Š· Š»ŃŃŠµŃ Ń ŃŠøŃŃ Š±ŠµŠ· ŠæŠ¾ŃŠ°ŃŠŗŠ¾Š²Š¾Š³Š¾ Ń " "Š·Š°Š²ŠµŃŃŠ°Š»ŃŠ½Š¾Š³Š¾ ŃŠøŠ¼Š²Š¾Š»ŃŠ² ŠæŠ¾Ń
ŠøŠ»Š¾Ń ŃŠøŃŠŗŠø" -#: ../src/libnm-glib-aux/nm-shared-utils.c:5801 +#: ../src/libnm-glib-aux/nm-shared-utils.c:5800 msgid "interface name must not be empty" msgstr "Š½Š°Š·Š²Š° ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ Š½Šµ Š¼Š¾Š¶Šµ Š±ŃŃŠø ŠæŠ¾ŃŠ¾Š¶Š½ŃŠ¾Ń" -#: ../src/libnm-glib-aux/nm-shared-utils.c:5809 +#: ../src/libnm-glib-aux/nm-shared-utils.c:5808 msgid "interface name must be UTF-8 encoded" msgstr "Š½Š°Š·Š²Š° ŃŠ½ŃŠµŃŃŠµŠ¹ŃŃ Š¼Š°Ń Š±ŃŃŠø Š½Š°Š±Š¾ŃŠ¾Š¼ ŃŠøŠ¼Š²Š¾Š»ŃŠ² Ń ŠŗŠ¾Š“ŃŠ²Š°Š½Š½Ń UTF-8" @@ -3894,8 +3927,8 @@ msgstr "Ā«%sĀ» Ń Š½ŠµŠ¾Š“Š½Š¾Š·Š½Š°ŃŠ½ŠøŠ¼: %s" msgid "missing name, try one of [%s]" msgstr "ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ Š½Š°Š·Š²Ń, ŃŠæŃŠ¾Š±ŃŠ¹ŃŠµ Š¾Š“Š½Ń Š· ŃŠ°ŠŗŠøŃ
Š½Š°Š·Š²: [%s]" -#: ../src/libnmc-base/nm-client-utils.c:248 ../src/nmcli/connections.c:3612 -#: ../src/nmcli/connections.c:3670 +#: ../src/libnmc-base/nm-client-utils.c:248 ../src/nmcli/connections.c:3734 +#: ../src/nmcli/connections.c:3792 #, c-format msgid "'%s' not among [%s]" msgstr "Ā«%sĀ» Š½ŠµŠ¼Š°Ń ŃŠµŃŠµŠ“ [%s]" @@ -3907,8 +3940,8 @@ msgstr "Ā«%sĀ» Š½ŠµŠ¼Š°Ń ŃŠµŃŠµŠ“ [%s]" #: ../src/libnmc-setting/nm-meta-setting-desc.c:1837 #: ../src/libnmc-setting/nm-meta-setting-desc.c:1868 #: ../src/libnmc-setting/nm-meta-setting-desc.c:2832 -#: ../src/libnmc-setting/nm-meta-setting-desc.c:2890 ../src/nmcli/common.c:1477 -#: ../src/nmcli/connections.c:77 ../src/nmcli/connections.c:87 +#: ../src/libnmc-setting/nm-meta-setting-desc.c:2890 ../src/nmcli/common.c:1625 +#: ../src/nmcli/connections.c:78 ../src/nmcli/connections.c:88 #: ../src/nmcli/devices.c:484 ../src/nmcli/devices.c:591 #: ../src/nmcli/devices.c:597 ../src/nmcli/general.c:30 #: ../src/nmcli/general.c:85 ../src/nmcli/general.c:91 @@ -3955,7 +3988,7 @@ msgstr "Š·'ŃŠ“Š½Š°Š½Š½Ń (Š²ŃŃŠ°Š½Š¾Š²Š»ŠµŠ½Š½Ń Š“ŃŃŠ³Š¾ŃŃŠ“Š½ŠøŃ
Š·'Ń msgid "connected" msgstr "Š·'ŃŠ“Š½Š°Š½Š¾" -#: ../src/libnmc-base/nm-client-utils.c:303 ../src/nmcli/connections.c:80 +#: ../src/libnmc-base/nm-client-utils.c:303 ../src/nmcli/connections.c:81 msgid "deactivating" msgstr "Š“ŠµŠ°ŠŗŃŠøŠ²Š°ŃŃŃ" @@ -3984,8 +4017,8 @@ msgstr "Š“ŠµŠ°ŠŗŃŠøŠ²Š°ŃŃŃ (Š·Š·Š¾Š²Š½Ń)" #: ../src/libnmc-base/nm-client-utils.c:342 #: ../src/libnmc-setting/nm-meta-setting-desc.c:883 #: ../src/libnmc-setting/nm-meta-setting-desc.c:2824 -#: ../src/nmcli/connections.c:5381 ../src/nmcli/connections.c:7326 -#: ../src/nmcli/connections.c:7327 ../src/nmcli/devices.c:590 +#: ../src/nmcli/connections.c:5491 ../src/nmcli/connections.c:7446 +#: ../src/nmcli/connections.c:7447 ../src/nmcli/devices.c:590 #: ../src/nmcli/devices.c:596 ../src/nmcli/devices.c:1382 #: ../src/nmcli/general.c:92 ../src/nmcli/utils.h:313 msgid "yes" @@ -3994,8 +4027,8 @@ msgstr "ŃŠ°Šŗ" #: ../src/libnmc-base/nm-client-utils.c:343 #: ../src/libnmc-setting/nm-meta-setting-desc.c:883 #: ../src/libnmc-setting/nm-meta-setting-desc.c:2827 -#: ../src/nmcli/connections.c:5380 ../src/nmcli/connections.c:7326 -#: ../src/nmcli/connections.c:7327 ../src/nmcli/devices.c:590 +#: ../src/nmcli/connections.c:5490 ../src/nmcli/connections.c:7446 +#: ../src/nmcli/connections.c:7447 ../src/nmcli/devices.c:590 #: ../src/nmcli/devices.c:596 ../src/nmcli/devices.c:1382 #: ../src/nmcli/general.c:93 ../src/nmcli/utils.h:313 msgid "no" @@ -4014,8 +4047,8 @@ msgid "No reason given" msgstr "ŠŃŠøŃŠøŠ½Ń Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾" #. We should not really come here -#: ../src/libnmc-base/nm-client-utils.c:354 ../src/nmcli/connections.c:3632 -#: ../src/nmcli/connections.c:3691 +#: ../src/libnmc-base/nm-client-utils.c:354 ../src/nmcli/connections.c:3754 +#: ../src/nmcli/connections.c:3813 #, c-format msgid "Unknown error" msgstr "ŠŠµŠ²ŃŠ“Š¾Š¼Š° ŠæŠ¾Š¼ŠøŠ»ŠŗŠ°" @@ -4412,7 +4445,7 @@ msgstr "ŠŠ¾ŃŠøŃŃŃŠ²Š°Ń" #: ../src/libnmc-base/nm-vpn-helpers.c:143 #: ../src/libnmc-base/nm-vpn-helpers.c:147 #: ../src/libnmc-base/nm-vpn-helpers.c:153 -#: ../src/libnmc-base/nm-vpn-helpers.c:158 ../src/nmcli/devices.c:4662 +#: ../src/libnmc-base/nm-vpn-helpers.c:158 ../src/nmcli/devices.c:4668 #: ../src/nmtui/nmt-page-dsl.c:64 ../src/nmtui/nmt-page-wifi.c:271 #: ../src/nmtui/nmt-page-wifi.c:305 ../src/nmtui/nmt-page-wifi.c:344 msgid "Password" @@ -9313,16 +9346,23 @@ msgstr "" "Š½Š° ŃŠøŠ¼ŃŠ°ŃŠ¾Š²Ń Š°Š“ŃŠµŃŠø, ŃŠŗŃ Š½Š°Š»Š°ŃŃŠ¾Š²Š°Š½Š¾ Š·Š° Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾Ń Š²ŃŠ“ŠæŠ¾Š²ŃŠ“Š½Š¾Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ." #: ../src/libnmc-setting/settings-docs.h.in:258 +#| msgid "" +#| "A list of IPv6 addresses and their prefix length. Multiple addresses can " +#| "be separated by comma. For example \"2001:db8:85a3::8a2e:370:7334/64, " +#| "2001:db8:85a3::5/64\". The addresses are listed in increasing priority, " +#| "meaning the last address will be the primary address." msgid "" "A list of IPv6 addresses and their prefix length. Multiple addresses can be " "separated by comma. For example \"2001:db8:85a3::8a2e:370:7334/64, 2001:" -"db8:85a3::5/64\". The addresses are listed in increasing priority, meaning " -"the last address will be the primary address." +"db8:85a3::5/64\". The addresses are listed in decreasing priority, meaning " +"the first address will be the primary address. This can make a difference " +"with IPv6 source address selection (RFC 6724, section 5)." msgstr "" -"Š”ŠæŠøŃŠ¾Šŗ Š°Š“ŃŠµŃ IPv46ŃŠ° ŃŃ
Š½ŃŃ
Š“Š¾Š²Š¶ŠøŠ½ ŠæŃŠµŃŃŠŗŃŠ°. ŠŠµŠŗŃŠ»ŃŠŗŠ° Š°Š“ŃŠµŃ Š¼Š¾Š¶Š½Š° " +"Š”ŠæŠøŃŠ¾Šŗ Š°Š“ŃŠµŃ IPv6 ŃŠ° ŃŃ
Š½ŃŃ
Š“Š¾Š²Š¶ŠøŠ½ ŠæŃŠµŃŃŠŗŃŠ°. ŠŠµŠŗŃŠ»ŃŠŗŠ° Š°Š“ŃŠµŃ Š¼Š¾Š¶Š½Š° " "Š²ŃŠ“Š¾ŠŗŃŠµŠ¼Š»ŃŠ²Š°ŃŠø ŠŗŠ¾Š¼Š°Š¼Šø. ŠŃŠøŠŗŠ»Š°Š“: \"2001:db8:85a3::8a2e:370:7334/64, 2001:" -"db8:85a3::5/64\". Š”ŠæŠøŃŠ¾Šŗ Š°Š“ŃŠµŃ ŃŠŗŠ»Š°Š“Š°ŃŃŃŃŃ Š·Š° Š·Š±ŃŠ»ŃŃŠµŠ½Š½ŃŠ¼ ŠæŃŃŠ¾ŃŠøŃŠµŃŠ½Š¾ŃŃŃ, " -"ŃŠ¾Š±ŃŠ¾ Š¾ŃŃŠ°Š½Š½Ń Š°Š“ŃŠµŃŠ° Š±ŃŠ“Šµ Š¾ŃŠ½Š¾Š²Š½Š¾Ń." +"db8:85a3::5/64\". Š”ŠæŠøŃŠ¾Šŗ Š°Š“ŃŠµŃ ŃŠŗŠ»Š°Š“Š°ŃŃŃŃŃ Š·Š° Š·Š¼ŠµŠ½ŃŠµŠ½Š½ŃŠ¼ ŠæŃŃŠ¾ŃŠøŃŠµŃŠ½Š¾ŃŃŃ, " +"ŃŠ¾Š±ŃŠ¾ ŠæŠµŃŃŠ° Š°Š“ŃŠµŃŠ° Š±ŃŠ“Šµ Š¾ŃŠ½Š¾Š²Š½Š¾Ń. Š¦Šµ Š¼Š¾Š¶Šµ Š²ŠæŠ»ŠøŠ½ŃŃŠø Š½Š° Š²ŠøŠ±ŃŃ ŠæŠ¾ŃŠ°ŃŠŗŠ¾Š²Š¾Ń Š°Š“ŃŠµŃŠø" +" ŠæŃŠø Š²ŠøŠŗŠ¾ŃŠøŃŃŠ°Š½Š½Ń IPv6 (RFC 6724, ŃŠ¾Š·Š“ŃŠ» 5)." #: ../src/libnmc-setting/settings-docs.h.in:260 msgid "" @@ -10810,28 +10850,28 @@ msgstr "nmcli ŃŃŠæŃŃŠ½Š¾ Š·Š°ŃŠµŃŃŃŃŠ¾Š²Š°Š½Š¾ ŃŠŗ Š°Š³ŠµŠ½Ń polkit.\ msgid "Error: polkit agent initialization failed: %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŃŠ½ŃŃŃŠ°Š»ŃŠ·ŃŠ²Š°ŃŠø Š°Š³ŠµŠ½Ń polkit: %s" -#: ../src/nmcli/common.c:360 ../src/nmcli/common.c:361 -#: ../src/nmcli/common.c:391 ../src/nmcli/common.c:392 -#: ../src/nmcli/connections.c:1621 +#: ../src/nmcli/common.c:362 ../src/nmcli/common.c:363 +#: ../src/nmcli/common.c:393 ../src/nmcli/common.c:394 +#: ../src/nmcli/connections.c:1737 msgid "GROUP" msgstr "ŠŠ Š£ŠŠ" -#: ../src/nmcli/common.c:639 +#: ../src/nmcli/common.c:642 #, c-format msgid "Error: openconnect failed: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²ŠøŠŗŠ¾Š½Š°ŃŠø openconnect: %s\n" -#: ../src/nmcli/common.c:646 +#: ../src/nmcli/common.c:649 #, c-format msgid "Error: openconnect failed with status %d\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²ŠøŠŗŠ¾Š½Š°Š½Š½Ń openconnect Š·Š°Š²ŠµŃŃŠøŠ»Š¾ŃŃ Š½ŠµŠ²Š“Š°Š»Š¾ Š·Ń ŃŃŠ°Š½Š¾Š¼ %d\n" -#: ../src/nmcli/common.c:648 +#: ../src/nmcli/common.c:651 #, c-format msgid "Error: openconnect failed with signal %d\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²ŠøŠŗŠ¾Š½Š°Š½Š½Ń openconnect Š·Š°Š²ŠµŃŃŠøŠ»Š¾ŃŃ Š½ŠµŠ²Š“Š°Š»Š¾ ŃŠ· ŃŠøŠ³Š½Š°Š»Š¾Š¼ %d\n" -#: ../src/nmcli/common.c:740 +#: ../src/nmcli/common.c:743 #, c-format msgid "" "Warning: password for '%s' not given in 'passwd-file' and nmcli cannot ask " @@ -10840,132 +10880,141 @@ msgstr "" "ŠŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń: Ń Ā«passwd-fileĀ» Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ ŠæŠ°ŃŠ¾Š»Ń Š“Š¾ Ā«%sĀ», Š° nmcli Š½Šµ Š¼Š¾Š¶Šµ " "Š·Š°ŠæŠøŃŠ°ŃŠø ŠæŃŠ¾ ŠæŠ°ŃŠ¾Š»Ń Š±ŠµŠ· ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«--askĀ».\n" -#: ../src/nmcli/common.c:1261 +#: ../src/nmcli/common.c:1264 #, c-format msgid "Error: Could not create NMClient object: %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŃŃŠ²Š¾ŃŠøŃŠø Š¾Š±'ŃŠŗŃ NMClient: %s." -#: ../src/nmcli/common.c:1287 +#: ../src/nmcli/common.c:1395 +msgid "Error: command doesn't support --offline mode." +msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ń ŠŗŠ¾Š¼Š°Š½Š“Ń Š½Šµ ŠæŠµŃŠµŠ“Š±Š°ŃŠµŠ½Š¾ ŠæŃŠ“ŃŃŠøŠ¼ŠŗŠø ŃŠµŠ¶ŠøŠ¼Ń --offline." + +#: ../src/nmcli/common.c:1435 msgid "Error: NetworkManager is not running." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: NetworkManager Š½Šµ ŠæŃŠ°ŃŃŃ." -#: ../src/nmcli/common.c:1390 +#: ../src/nmcli/common.c:1538 #, c-format msgid "Error: argument '%s' not understood. Try passing --help instead." msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ» Ń Š½ŠµŠ²ŃŠ“Š¾Š¼ŠøŠ¼. Š”ŠæŃŠ¾Š±ŃŠ¹ŃŠµ ŃŠŗŠ¾ŃŠøŃŃŠ°ŃŠøŃŃ ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ¾Š¼ --help." -#: ../src/nmcli/common.c:1401 +#: ../src/nmcli/common.c:1549 msgid "Error: missing argument. Try passing --help." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ ŠæŠ°ŃŠ°Š¼ŠµŃŃ. Š”ŠæŃŠ¾Š±ŃŠ¹ŃŠµ ŃŠŗŠ¾ŃŠøŃŃŠ°ŃŠøŃŃ ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ¾Š¼ --help." -#: ../src/nmcli/common.c:1466 +#: ../src/nmcli/common.c:1614 msgid "access denied" msgstr "Š“Š¾ŃŃŃŠæ Š·Š°Š±Š¾ŃŠ¾Š½ŠµŠ½Š¾" -#: ../src/nmcli/common.c:1468 +#: ../src/nmcli/common.c:1616 msgid "NetworkManager is not running" msgstr "NetworkManager Š½Šµ Š·Š°ŠæŃŃŠµŠ½Š¾" -#: ../src/nmcli/common.c:1478 +#: ../src/nmcli/common.c:1626 msgid "none" msgstr "Š½ŠµŠ¼Š°Ń" -#: ../src/nmcli/common.c:1479 +#: ../src/nmcli/common.c:1627 msgid "portal" msgstr "ŠæŠ¾ŃŃŠ°Š»" -#: ../src/nmcli/common.c:1480 +#: ../src/nmcli/common.c:1628 msgid "limited" msgstr "Š¾Š±Š¼ŠµŠ¶ŠµŠ½Š°" -#: ../src/nmcli/common.c:1481 +#: ../src/nmcli/common.c:1629 msgid "full" msgstr "ŠæŠ¾Š²Š½Š°" #. define some prompts for connection editor -#: ../src/nmcli/connections.c:59 +#: ../src/nmcli/connections.c:60 msgid "Setting name? " msgstr "ŠŠ°Š·Š²Š° ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°? " -#: ../src/nmcli/connections.c:60 +#: ../src/nmcli/connections.c:61 msgid "Property name? " msgstr "ŠŠ°Š·Š²Š° Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ? " -#: ../src/nmcli/connections.c:61 +#: ../src/nmcli/connections.c:62 msgid "Enter connection type: " msgstr "ŠŠŗŠ°Š¶ŃŃŃ ŃŠøŠæ Š·'ŃŠ“Š½Š°Š½Š½Ń: " #. define some other prompts -#: ../src/nmcli/connections.c:65 +#: ../src/nmcli/connections.c:66 msgid "Connection (name, UUID, or path): " msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń (Š½Š°Š·Š²Š°, UUID Š°Š±Š¾ ŃŠ»ŃŃ
):" -#: ../src/nmcli/connections.c:66 +#: ../src/nmcli/connections.c:67 msgid "VPN connection (name, UUID, or path): " msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń VPN (Š½Š°Š·Š²Š°, UUID Š°Š±Š¾ ŃŠ»ŃŃ
):" -#: ../src/nmcli/connections.c:67 +#: ../src/nmcli/connections.c:68 msgid "Connection(s) (name, UUID, or path): " msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń (Š½Š°Š·Š²Š°, UUID Š°Š±Š¾ ŃŠ»ŃŃ
):" -#: ../src/nmcli/connections.c:68 +#: ../src/nmcli/connections.c:69 msgid "Connection(s) (name, UUID, path or apath): " msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń (Š½Š°Š·Š²Š°, UUID, ŃŠ»ŃŃ
Š°Š±Š¾ apath):" -#: ../src/nmcli/connections.c:78 +#: ../src/nmcli/connections.c:79 msgid "activating" msgstr "Š°ŠŗŃŠøŠ²Š°ŃŃŃ" -#: ../src/nmcli/connections.c:79 +#: ../src/nmcli/connections.c:80 msgid "activated" msgstr "Š°ŠŗŃŠøŠ²Š¾Š²Š°Š½Š¾" -#: ../src/nmcli/connections.c:81 +#: ../src/nmcli/connections.c:82 msgid "deactivated" msgstr "Š²ŠøŠ¼ŠŗŠ½ŠµŠ½Š¾" -#: ../src/nmcli/connections.c:88 +#: ../src/nmcli/connections.c:89 msgid "VPN connecting (prepare)" msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń VPN (ŠæŃŠøŠ³Š¾ŃŃŠ²Š°Š½Š½Ń)" -#: ../src/nmcli/connections.c:90 +#: ../src/nmcli/connections.c:91 msgid "VPN connecting (need authentication)" msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń VPN (ŠæŠ¾ŃŃŃŠ±Š½Šµ ŃŠ¾Š·ŠæŃŠ·Š½Š°Š²Š°Š½Š½Ń)" -#: ../src/nmcli/connections.c:91 +#: ../src/nmcli/connections.c:92 msgid "VPN connecting" msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń VPN" -#: ../src/nmcli/connections.c:93 +#: ../src/nmcli/connections.c:94 msgid "VPN connecting (getting IP configuration)" msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń VPN (Š¾ŃŃŠøŠ¼Š°Š½Š½Ń Š½Š°Š»Š°ŃŃŃŠ²Š°Š½Ń IP)" -#: ../src/nmcli/connections.c:94 +#: ../src/nmcli/connections.c:95 msgid "VPN connected" msgstr "VPN Š·'ŃŠ“Š½Š°Š½Š¾" -#: ../src/nmcli/connections.c:95 +#: ../src/nmcli/connections.c:96 msgid "VPN connection failed" msgstr "ŠŠµŠ²Š“Š°Š»Š° ŃŠæŃŠ¾Š±Š° Š·'ŃŠ“Š½Š°Š½Š½Ń VPN" -#: ../src/nmcli/connections.c:96 +#: ../src/nmcli/connections.c:97 msgid "VPN disconnected" msgstr "VPN ŃŠ¾Š·'ŃŠ“Š½Š°Š½Š¾" -#: ../src/nmcli/connections.c:526 +#: ../src/nmcli/connections.c:172 ../src/nmcli/connections.c:232 +#, c-format +msgid "Error: Error writting connection: %s" +msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæŃŠ“ ŃŠ°Ń Š·Š°ŠæŠøŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń: %s" + +#: ../src/nmcli/connections.c:652 msgid "WiMax is no longer supported" msgstr "ŠŃŠ“ŃŃŠøŠ¼ŠŗŃ WiMax ŠæŃŠøŠæŠøŠ½ŠµŠ½Š¾" -#: ../src/nmcli/connections.c:532 +#: ../src/nmcli/connections.c:658 msgid "WEP encryption is known to be insecure" msgstr "ŠŃŠ“Š¾Š¼Š¾, ŃŠ¾ ŃŠøŃŃŃŠ²Š°Š½Š½Ń WEP Š½Šµ Ń Š±ŠµŠ·ŠæŠµŃŠ½ŠøŠ¼" -#: ../src/nmcli/connections.c:614 +#: ../src/nmcli/connections.c:740 msgid "never" msgstr "Š½ŃŠŗŠ¾Š»Šø" -#: ../src/nmcli/connections.c:965 +#: ../src/nmcli/connections.c:1089 #, c-format msgid "" "Usage: nmcli connection { COMMAND | help }\n" @@ -11043,7 +11092,7 @@ msgstr "" " export [id | uuid | path] <ŃŠ“ŠµŠ½ŃŠøŃŃŠŗŠ°ŃŠ¾Ń> [<ŃŠ°Š¹Š» ŃŠµŠ·ŃŠ»ŃŃŠ°ŃŃŠ²>]\n" "\n" -#: ../src/nmcli/connections.c:991 +#: ../src/nmcli/connections.c:1115 #, c-format msgid "" "Usage: nmcli connection show { ARGUMENTS | help }\n" @@ -11091,7 +11140,7 @@ msgstr "" "ŠÆŠŗŃŠ¾ Š²ŠŗŠ°Š·Š°Š½Š¾ ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«--activeĀ», Š±ŃŠ°ŃŠøŠ¼ŃŃŃŃŃ Š“Š¾ ŃŠ²Š°Š³Šø Š»ŠøŃŠµ Š°ŠŗŃŠøŠ²Š½Ń ŠæŃŠ¾ŃŃŠ»Ń. " "ŠŠ°Š³Š°Š»ŃŠ½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ --show-secrets ŠæŠ¾ŠŗŠ°Š¶Šµ ŃŠ°ŠŗŠ¾Š¶ ŠæŠ¾Š²'ŃŠ·Š°Š½Ń ŠæŠ°ŃŠ¾Š»Ń.\n" -#: ../src/nmcli/connections.c:1012 +#: ../src/nmcli/connections.c:1136 #, c-format msgid "" "Usage: nmcli connection up { ARGUMENTS | help }\n" @@ -11137,7 +11186,7 @@ msgstr "" "passwd-file - ŃŠ°Š¹Š» Š· ŠæŠ°ŃŠ¾Š»ŃŠ¼Šø, ŠæŠ¾ŃŃŃŠ±Š½ŠøŠ¼Šø Š“Š»Ń Š°ŠŗŃŠøŠ²Š°ŃŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń\n" "\n" -#: ../src/nmcli/connections.c:1035 +#: ../src/nmcli/connections.c:1159 #, c-format msgid "" "Usage: nmcli connection down { ARGUMENTS | help }\n" @@ -11159,7 +11208,7 @@ msgstr "" "Š½Š°Š·Š²Š¾Ń, UUID Š°Š±Š¾ ŃŠ»ŃŃ
Š¾Š¼ D-Bus.\n" "\n" -#: ../src/nmcli/connections.c:1047 +#: ../src/nmcli/connections.c:1171 #, c-format msgid "" "Usage: nmcli connection add { ARGUMENTS | help }\n" @@ -11487,7 +11536,7 @@ msgstr "" " [ip6 <Š°Š“ŃŠµŃŠ° IPv6>] [gw6 <ŃŠ»ŃŠ· IPv6>]\n" "\n" -#: ../src/nmcli/connections.c:1177 +#: ../src/nmcli/connections.c:1301 #, c-format msgid "" "Usage: nmcli connection modify { ARGUMENTS | help }\n" @@ -11544,7 +11593,7 @@ msgstr "" "nmcli con mod em1-1 remove sriov\n" "\n" -#: ../src/nmcli/connections.c:1205 +#: ../src/nmcli/connections.c:1329 #, c-format msgid "" "Usage: nmcli connection clone { ARGUMENTS | help }\n" @@ -11567,7 +11616,7 @@ msgstr "" "ŃŠ“ŠµŠ½ŃŠøŃŃŠŗŠ°ŃŠ¾ŃŠ° (Š·Š°Š“Š°ŃŃŃŃŃ ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ¾Š¼ <Š½Š¾Š²Š° Š½Š°Š·Š²Š°>).\n" "\n" -#: ../src/nmcli/connections.c:1217 +#: ../src/nmcli/connections.c:1341 #, c-format msgid "" "Usage: nmcli connection edit { ARGUMENTS | help }\n" @@ -11595,7 +11644,7 @@ msgstr "" "ŠŠ¾Š“Š°ŃŠø Š½Š¾Š²ŠøŠ¹ ŠæŃŠ¾ŃŃŠ»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń Š·Š° Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾Ń ŃŠ½ŃŠµŃŠ°ŠŗŃŠøŠ²Š½Š¾Š³Š¾ ŃŠµŠ“Š°ŠŗŃŠ¾ŃŠ°.\n" "\n" -#: ../src/nmcli/connections.c:1232 +#: ../src/nmcli/connections.c:1356 #, c-format msgid "" "Usage: nmcli connection delete { ARGUMENTS | help }\n" @@ -11614,7 +11663,7 @@ msgstr "" "ŠŃŠ¾ŃŃŠ»Ń Š¼Š¾Š¶Š½Š° Š²ŠŗŠ°Š·Š°ŃŠø Š·Š° Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾Ń Š½Š°Š·Š², UUID Š°Š±Š¾ ŃŠ»ŃŃ
Ń D-Bus.\n" "\n" -#: ../src/nmcli/connections.c:1243 +#: ../src/nmcli/connections.c:1367 #, c-format msgid "" "Usage: nmcli connection monitor { ARGUMENTS | help }\n" @@ -11636,7 +11685,7 @@ msgstr "" "Š”ŃŠµŠ¶ŠøŃŃ Š·Š° ŃŃŃŠ¼Š° ŠæŃŠ¾ŃŃŠ»ŃŠ¼Šø Š·'ŃŠ“Š½Š°Š½Ń, ŃŠŗŃŠ¾ ŠŗŠ¾Š½ŠŗŃŠµŃŠ½ŠøŠ¹ ŠæŃŠ¾ŃŃŠ»Ń Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾.\n" "\n" -#: ../src/nmcli/connections.c:1255 +#: ../src/nmcli/connections.c:1379 #, c-format msgid "" "Usage: nmcli connection reload { help }\n" @@ -11649,7 +11698,7 @@ msgstr "" "ŠŠµŃŠµŠ·Š°Š²Š°Š½ŃŠ°Š¶ŠøŃŠø ŃŃŃŃ
ŃŠ°Š¹Š»Šø Š·'ŃŠ“Š½Š°Š½Ń Š· Š“ŠøŃŠŗŠ°.\n" "\n" -#: ../src/nmcli/connections.c:1263 +#: ../src/nmcli/connections.c:1387 #, c-format msgid "" "Usage: nmcli connection load { ARGUMENTS | help }\n" @@ -11672,7 +11721,7 @@ msgstr "" "ŃŠ¾Š³Š¾, ŃŠ¾Š± Š·Š°Š²Š°Š½ŃŠ°Š¶ŠøŃŠø Š“Š¾ NetworkManager Š½Š°Š¹ŃŠ²ŃŠ¶ŃŃŃ Š½Š°Š»Š°ŃŃŃŠ²Š°Š½Š½Ń.\n" "\n" -#: ../src/nmcli/connections.c:1276 +#: ../src/nmcli/connections.c:1400 #, c-format msgid "" "Usage: nmcli connection import { ARGUMENTS | help }\n" @@ -11697,7 +11746,7 @@ msgstr "" "ŃŠ¼ŠæŠ¾ŃŃŃŃŃŃŃŃ Š“Š¾Š“Š°ŃŠŗŠ°Š¼Šø VPN NetworkManager.\n" "\n" -#: ../src/nmcli/connections.c:1289 +#: ../src/nmcli/connections.c:1413 #, c-format msgid "" "Usage: nmcli connection export { ARGUMENTS | help }\n" @@ -11717,7 +11766,7 @@ msgstr "" "ŠŠ°Š½Ń ŃŠæŃŃŠ¼Š¾Š²ŃŠ²Š°ŃŠøŠ¼ŃŃŃŃŃ Š“Š¾ ŃŃŠ°Š½Š“Š°ŃŃŠ½Š¾Š³Š¾ Š²ŠøŠ²ŠµŠ“ŠµŠ½Š½Ń Š°Š±Š¾ Š“Š¾ Š²ŠŗŠ°Š·Š°Š½Š¾Š³Š¾ ŃŠ°Š¹Š»Š°.\n" "\n" -#: ../src/nmcli/connections.c:1300 +#: ../src/nmcli/connections.c:1424 #, c-format msgid "" "Usage: nmcli connection migrate { ARGUMENTS | help }\n" @@ -11736,329 +11785,329 @@ msgstr "" "Š·Š¾ŠŗŃŠµŠ¼Š° Ā«keyfileĀ» (ŃŠøŠæŠ¾Š²ŠøŠ¹) Š°Š±Š¾ Ā«ifcfg-rhĀ».\n" "\n" -#: ../src/nmcli/connections.c:1391 +#: ../src/nmcli/connections.c:1507 #, c-format msgid "Error updating secrets for %s: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæŃŠ“ ŃŠ°Ń ŠæŃŠ¾Š±Šø Š¾Š½Š¾Š²Š»ŠµŠ½Š½Ń ŠæŠ°ŃŠ¾Š»ŃŠ² Š“Š»Ń %s: %s\n" -#: ../src/nmcli/connections.c:1442 +#: ../src/nmcli/connections.c:1558 msgid "Connection profile details" msgstr "ŠŠ°ŃŠ°Š¼ŠµŃŃŠø ŠæŃŠ¾ŃŃŠ»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń" -#: ../src/nmcli/connections.c:1460 ../src/nmcli/connections.c:1567 +#: ../src/nmcli/connections.c:1576 ../src/nmcli/connections.c:1683 #, c-format msgid "Error: 'connection show': %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«connection showĀ»: %s" -#: ../src/nmcli/connections.c:1549 +#: ../src/nmcli/connections.c:1665 msgid "Active connection details" msgstr "ŠŠŗŃŠøŠ²ŃŠ²Š°ŃŠø ŠæŠ°ŃŠ°Š¼ŠµŃŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń" -#: ../src/nmcli/connections.c:1678 ../src/nmcli/devices.c:1637 +#: ../src/nmcli/connections.c:1794 ../src/nmcli/devices.c:1637 #: ../src/nmcli/devices.c:1654 ../src/nmcli/devices.c:1672 #: ../src/nmcli/devices.c:1691 ../src/nmcli/devices.c:1755 #: ../src/nmcli/devices.c:1884 msgid "NAME" msgstr "ŠŠŠŠŠ" -#: ../src/nmcli/connections.c:1778 +#: ../src/nmcli/connections.c:1894 #, c-format msgid "invalid field '%s'; allowed fields: %s and %s, or %s,%s" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ ŠæŠ¾Š»Šµ Ā«%sĀ»; Š“Š¾Š·Š²Š¾Š»ŠµŠ½Ń ŠæŠ¾Š»Ń: %s Ń %s Š°Š±Š¾ %s,%s" -#: ../src/nmcli/connections.c:1795 ../src/nmcli/connections.c:1806 +#: ../src/nmcli/connections.c:1911 ../src/nmcli/connections.c:1922 #, c-format msgid "'%s' has to be alone" msgstr "Ā«%sĀ» Š¼Š°Ń Š±ŃŃŠø ŃŠ“ŠøŠ½ŠøŠ¼" -#: ../src/nmcli/connections.c:2061 +#: ../src/nmcli/connections.c:2178 #, c-format msgid "incorrect string '%s' of '--order' option" msgstr "ŠæŠ¾Š¼ŠøŠ»ŠŗŠ¾Š²ŠøŠ¹ ŃŃŠ“Š¾Šŗ Ā«%sĀ» Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŃ Ā«--orderĀ»" -#: ../src/nmcli/connections.c:2085 +#: ../src/nmcli/connections.c:2202 #, c-format msgid "incorrect item '%s' in '--order' option" msgstr "ŠæŠ¾Š¼ŠøŠ»ŠŗŠ¾Š²ŠøŠ¹ ŠæŃŠ½ŠŗŃ Ā«%sĀ» Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŃ Ā«--orderĀ»" -#: ../src/nmcli/connections.c:2125 +#: ../src/nmcli/connections.c:2247 msgid "No connection specified" msgstr "ŠŠµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š·'ŃŠ“Š½Š°Š½Š½Ń" -#: ../src/nmcli/connections.c:2138 +#: ../src/nmcli/connections.c:2260 #, c-format msgid "%s argument is missing" msgstr "ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń %s" -#: ../src/nmcli/connections.c:2159 +#: ../src/nmcli/connections.c:2281 #, c-format msgid "unknown connection '%s'" msgstr "Š½ŠµŠ²ŃŠ“Š¾Š¼Šµ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»" -#: ../src/nmcli/connections.c:2188 +#: ../src/nmcli/connections.c:2310 msgid "'--order' argument is missing" msgstr "ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń Ā«--orderĀ»" -#: ../src/nmcli/connections.c:2252 +#: ../src/nmcli/connections.c:2374 msgid "NetworkManager active profiles" msgstr "ŠŠŗŃŠøŠ²Š½Ń ŠæŃŠ¾ŃŃŠ»Ń NetworkManager" -#: ../src/nmcli/connections.c:2253 +#: ../src/nmcli/connections.c:2375 msgid "NetworkManager connection profiles" msgstr "ŠŃŠ¾ŃŃŠ»Ń Š·'ŃŠ“Š½Š°Š½Ń NetworkManager" -#: ../src/nmcli/connections.c:2309 ../src/nmcli/connections.c:3030 -#: ../src/nmcli/connections.c:3042 ../src/nmcli/connections.c:3054 -#: ../src/nmcli/connections.c:3290 ../src/nmcli/connections.c:9448 -#: ../src/nmcli/connections.c:9470 ../src/nmcli/devices.c:3317 -#: ../src/nmcli/devices.c:3330 ../src/nmcli/devices.c:3342 -#: ../src/nmcli/devices.c:3646 ../src/nmcli/devices.c:3657 -#: ../src/nmcli/devices.c:3676 ../src/nmcli/devices.c:3685 -#: ../src/nmcli/devices.c:3707 ../src/nmcli/devices.c:3718 -#: ../src/nmcli/devices.c:3739 ../src/nmcli/devices.c:4303 -#: ../src/nmcli/devices.c:4314 ../src/nmcli/devices.c:4323 -#: ../src/nmcli/devices.c:4337 ../src/nmcli/devices.c:4355 -#: ../src/nmcli/devices.c:4364 ../src/nmcli/devices.c:4520 -#: ../src/nmcli/devices.c:4531 ../src/nmcli/devices.c:4750 -#: ../src/nmcli/devices.c:4929 +#: ../src/nmcli/connections.c:2431 ../src/nmcli/connections.c:3152 +#: ../src/nmcli/connections.c:3164 ../src/nmcli/connections.c:3176 +#: ../src/nmcli/connections.c:3412 ../src/nmcli/connections.c:9579 +#: ../src/nmcli/connections.c:9601 ../src/nmcli/devices.c:3323 +#: ../src/nmcli/devices.c:3336 ../src/nmcli/devices.c:3348 +#: ../src/nmcli/devices.c:3652 ../src/nmcli/devices.c:3663 +#: ../src/nmcli/devices.c:3682 ../src/nmcli/devices.c:3691 +#: ../src/nmcli/devices.c:3713 ../src/nmcli/devices.c:3724 +#: ../src/nmcli/devices.c:3745 ../src/nmcli/devices.c:4309 +#: ../src/nmcli/devices.c:4320 ../src/nmcli/devices.c:4329 +#: ../src/nmcli/devices.c:4343 ../src/nmcli/devices.c:4361 +#: ../src/nmcli/devices.c:4370 ../src/nmcli/devices.c:4526 +#: ../src/nmcli/devices.c:4537 ../src/nmcli/devices.c:4756 +#: ../src/nmcli/devices.c:4935 #, c-format msgid "Error: %s argument is missing." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń %s." -#: ../src/nmcli/connections.c:2344 +#: ../src/nmcli/connections.c:2466 #, c-format msgid "Error: %s - no such connection profile." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŃŠ¾ŃŃŠ»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń %s Š½Šµ ŃŃŠ½ŃŃ." -#: ../src/nmcli/connections.c:2436 ../src/nmcli/connections.c:3016 -#: ../src/nmcli/connections.c:3090 ../src/nmcli/connections.c:8948 -#: ../src/nmcli/connections.c:9038 ../src/nmcli/connections.c:9577 -#: ../src/nmcli/devices.c:1984 ../src/nmcli/devices.c:2254 -#: ../src/nmcli/devices.c:2427 ../src/nmcli/devices.c:2551 -#: ../src/nmcli/devices.c:2738 ../src/nmcli/devices.c:3517 -#: ../src/nmcli/devices.c:4484 ../src/nmcli/devices.c:4936 +#: ../src/nmcli/connections.c:2558 ../src/nmcli/connections.c:3138 +#: ../src/nmcli/connections.c:3212 ../src/nmcli/connections.c:9085 +#: ../src/nmcli/connections.c:9169 ../src/nmcli/connections.c:9708 +#: ../src/nmcli/devices.c:1984 ../src/nmcli/devices.c:2260 +#: ../src/nmcli/devices.c:2433 ../src/nmcli/devices.c:2557 +#: ../src/nmcli/devices.c:2744 ../src/nmcli/devices.c:3523 +#: ../src/nmcli/devices.c:4490 ../src/nmcli/devices.c:4942 #: ../src/nmcli/general.c:1067 #, c-format msgid "Error: %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: %s." -#: ../src/nmcli/connections.c:2528 ../src/nmcli/devices.c:4703 +#: ../src/nmcli/connections.c:2650 ../src/nmcli/devices.c:4709 #, c-format msgid "no active connection on device '%s'" msgstr "Š½Š° ŠæŃŠøŃŃŃŠ¾Ń Ā«%sĀ» Š½ŠµŠ¼Š°Ń Š°ŠŗŃŠøŠ²Š½ŠøŃ
Š·'ŃŠ“Š½Š°Š½Ń" -#: ../src/nmcli/connections.c:2536 +#: ../src/nmcli/connections.c:2658 msgid "no active connection or device" msgstr "Š½ŠµŠ¼Š°Ń Š°ŠŗŃŠøŠ²Š½ŠøŃ
Š·'ŃŠ“Š½Š°Š½Ń Š°Š±Š¾ ŠæŃŠøŃŃŃŠ¾ŃŠ²" -#: ../src/nmcli/connections.c:2559 +#: ../src/nmcli/connections.c:2681 #, c-format msgid "device '%s' not compatible with connection '%s': " msgstr "ŠæŃŠøŃŃŃŃŠ¹ Ā«%sĀ» Š½ŠµŃŃŠ¼ŃŃŠ½ŠøŠ¹ Š·Ń Š·'ŃŠ“Š½Š°Š½Š½ŃŠ¼ Ā«%sĀ»: " -#: ../src/nmcli/connections.c:2597 +#: ../src/nmcli/connections.c:2719 #, c-format msgid "device '%s' not compatible with connection '%s'" msgstr "ŠæŃŠøŃŃŃŃŠ¹ Ā«%sĀ» Š½ŠµŃŃŠ¼ŃŃŠ½ŠøŠ¹ Š·Ń Š·'ŃŠ“Š½Š°Š½Š½ŃŠ¼ Ā«%sĀ»" -#: ../src/nmcli/connections.c:2604 +#: ../src/nmcli/connections.c:2726 #, c-format msgid "device '%s' not found for connection '%s'" msgstr "Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ ŠæŃŠøŃŃŃŠ¾Ń Ā«%sĀ» Š“Š»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»" -#: ../src/nmcli/connections.c:2612 +#: ../src/nmcli/connections.c:2734 #, c-format msgid "no device found for connection '%s'" msgstr "Š½Šµ Š²ŠøŃŠ²Š»ŠµŠ½Š¾ ŠæŃŠøŃŃŃŠ¾Ń Š“Š»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»" -#: ../src/nmcli/connections.c:2663 +#: ../src/nmcli/connections.c:2785 #, c-format msgid "Hint: use '%s' to get more details." msgstr "ŠŃŠ“ŠŗŠ°Š·ŠŗŠ°: ŃŠŗŠ¾ŃŠøŃŃŠ°Š¹ŃŠµŃŃ Ā«%sĀ», ŃŠ¾Š± Š¾Š·Š½Š°Š¹Š¾Š¼ŠøŃŠøŃŃ ŃŠ· ŠæŠ¾Š“ŃŠ¾Š±ŠøŃŃŠ¼Šø." -#: ../src/nmcli/connections.c:2681 +#: ../src/nmcli/connections.c:2803 #, c-format msgid "Connection successfully activated (%s) (D-Bus active path: %s)\n" msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń ŃŃŠæŃŃŠ½Š¾ Š·Š°Š“ŃŃŠ½Š¾ (%s) (Š°ŠŗŃŠøŠ²Š½ŠøŠ¹ ŃŠ»ŃŃ
D-Bus: %s)\n" -#: ../src/nmcli/connections.c:2685 ../src/nmcli/connections.c:2836 -#: ../src/nmcli/connections.c:7218 +#: ../src/nmcli/connections.c:2807 ../src/nmcli/connections.c:2958 +#: ../src/nmcli/connections.c:7338 #, c-format msgid "Connection successfully activated (D-Bus active path: %s)\n" msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń ŃŃŠæŃŃŠ½Š¾ Š·Š°Š“ŃŃŠ½Š¾ (Š°ŠŗŃŠøŠ²Š½ŠøŠ¹ ŃŠ»ŃŃ
D-Bus: %s)\n" -#: ../src/nmcli/connections.c:2692 ../src/nmcli/connections.c:2815 +#: ../src/nmcli/connections.c:2814 ../src/nmcli/connections.c:2937 #, c-format msgid "Error: Connection activation failed: %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š°ŠŗŃŠøŠ²ŃŠ²Š°ŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń: %s" -#: ../src/nmcli/connections.c:2728 +#: ../src/nmcli/connections.c:2850 #, c-format msgid "Error: Timeout expired (%d seconds)" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠµŃŠµŠ²ŠøŃŠµŠ½Š¾ ŃŠ°Ń Š¾ŃŃŠŗŃŠ²Š°Š½Š½Ń (%d ŃŠµŠŗŃŠ½Š“)." -#: ../src/nmcli/connections.c:2910 +#: ../src/nmcli/connections.c:3032 #, c-format msgid "unknown device '%s'." msgstr "Š½ŠµŠ²ŃŠ“Š¾Š¼ŠøŠ¹ ŠæŃŠøŃŃŃŃŠ¹, Ā«%sĀ»." -#: ../src/nmcli/connections.c:2918 +#: ../src/nmcli/connections.c:3040 msgid "neither a valid connection nor device given" msgstr "Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š½Ń ŠŗŠ¾ŃŠµŠŗŃŠ½Š¾Š³Š¾ Š·'ŃŠ“Š½Š°Š½Š½Ń, Š½Ń ŠæŃŠøŃŃŃŠ¾Ń" -#: ../src/nmcli/connections.c:2933 +#: ../src/nmcli/connections.c:3055 #, c-format msgid "invalid passwd-file '%s' at line %zd: %s" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŃŠ°Š¹Š» passwd Ā«%sĀ» Ń ŃŃŠ“ŠŗŃ %zd: %s" -#: ../src/nmcli/connections.c:2941 +#: ../src/nmcli/connections.c:3063 #, c-format msgid "invalid passwd-file '%s': %s" msgstr "Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŃŠ°Š¹Š» passwd Ā«%sĀ»: %s" -#: ../src/nmcli/connections.c:3064 ../src/nmcli/connections.c:9481 +#: ../src/nmcli/connections.c:3186 ../src/nmcli/connections.c:9612 #: ../src/nmcli/devices.c:1941 ../src/nmcli/devices.c:1990 -#: ../src/nmcli/devices.c:2433 ../src/nmcli/devices.c:3377 -#: ../src/nmcli/devices.c:3755 ../src/nmcli/devices.c:4374 -#: ../src/nmcli/devices.c:4537 ../src/nmcli/devices.c:4758 -#: ../src/nmcli/devices.c:4941 +#: ../src/nmcli/devices.c:2439 ../src/nmcli/devices.c:3383 +#: ../src/nmcli/devices.c:3761 ../src/nmcli/devices.c:4380 +#: ../src/nmcli/devices.c:4543 ../src/nmcli/devices.c:4764 +#: ../src/nmcli/devices.c:4947 #, c-format msgid "Error: invalid extra argument '%s'." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š“Š¾Š“Š°ŃŠŗŠ¾Š²ŠøŠ¹ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń, Ā«%sĀ»." -#: ../src/nmcli/connections.c:3098 +#: ../src/nmcli/connections.c:3220 msgid "preparing" msgstr "ŠæŃŠøŠ³Š¾ŃŃŠ²Š°Š½Š½Ń" -#: ../src/nmcli/connections.c:3206 +#: ../src/nmcli/connections.c:3328 #, c-format msgid "Connection '%s' (%s) successfully deleted.\n" msgstr "ŠŠ°ŠæŠøŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) ŃŃŠæŃŃŠ½Š¾ Š²ŠøŠ»ŃŃŠµŠ½Š¾.\n" -#: ../src/nmcli/connections.c:3222 +#: ../src/nmcli/connections.c:3344 #, c-format msgid "Connection '%s' successfully deactivated (D-Bus active path: %s)\n" msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» ŃŃŠæŃŃŠ½Š¾ Š²ŠøŠ¼ŠŗŠ½ŠµŠ½Š¾ (Š°ŠŗŃŠøŠ²Š½ŠøŠ¹ ŃŠ»ŃŃ
D-Bus: %s)\n" -#: ../src/nmcli/connections.c:3271 ../src/nmcli/connections.c:9134 -#: ../src/nmcli/connections.c:9169 ../src/nmcli/connections.c:9358 +#: ../src/nmcli/connections.c:3393 ../src/nmcli/connections.c:9265 +#: ../src/nmcli/connections.c:9300 ../src/nmcli/connections.c:9489 #, c-format msgid "Error: No connection specified." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š·'ŃŠ“Š½Š°Š½Š½Ń." -#: ../src/nmcli/connections.c:3303 +#: ../src/nmcli/connections.c:3425 #, c-format msgid "Error: '%s' is not an active connection.\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Š½Šµ Ń Š°ŠŗŃŠøŠ²Š½ŠøŠ¼ Š·'ŃŠ“Š½Š°Š½Š½ŃŠ¼.\n" -#: ../src/nmcli/connections.c:3304 +#: ../src/nmcli/connections.c:3426 #, c-format msgid "Error: not all active connections found." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ ŃŃŃ Š°ŠŗŃŠøŠ²Š½Ń Š·'ŃŠ“Š½Š°Š½Š½Ń Š·Š½Š°Š¹Š“ŠµŠ½Š¾." -#: ../src/nmcli/connections.c:3312 +#: ../src/nmcli/connections.c:3434 #, c-format msgid "Error: no active connection provided." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š½Š°Š“Š°Š½Š¾ Š°ŠŗŃŠøŠ²Š½Š¾Š³Š¾ Š·'ŃŠ“Š½Š°Š½Š½Ń." -#: ../src/nmcli/connections.c:3344 +#: ../src/nmcli/connections.c:3466 #, c-format msgid "Connection '%s' deactivation failed: %s\n" msgstr "ŠŠµŠ²Š“Š°Š»Š° ŃŠæŃŠ¾Š±Š° Š²ŠøŠ¼ŠŗŠ½ŃŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»: %s\n" -#: ../src/nmcli/connections.c:3825 +#: ../src/nmcli/connections.c:3947 #, c-format msgid "Warning: master='%s' doesn't refer to any existing profile.\n" msgstr "" "ŠŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń: master='%s' Š½Šµ ŠæŠ¾ŃŠøŠ»Š°ŃŃŃŃŃ Š½Ń Š½Š° Š¾Š“ŠøŠ½ Š· Š½Š°ŃŠ²Š½ŠøŃ
ŠæŃŠ¾ŃŃŠ»ŃŠ².\n" -#: ../src/nmcli/connections.c:4200 +#: ../src/nmcli/connections.c:4322 #, c-format msgid "Error: invalid property '%s': %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š° Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ, Ā«%sĀ»: %s." -#: ../src/nmcli/connections.c:4217 +#: ../src/nmcli/connections.c:4339 #, c-format msgid "Error: failed to %s %s.%s: %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ %s %s.%s: %s." -#: ../src/nmcli/connections.c:4298 +#: ../src/nmcli/connections.c:4420 #, c-format msgid "Error: invalid slave type; %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŃŠøŠæ ŠæŃŠ“Š»ŠµŠ³Š»Š¾Š³Š¾; %s." -#: ../src/nmcli/connections.c:4309 +#: ../src/nmcli/connections.c:4431 #, c-format msgid "Error: invalid connection type; %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŃŠøŠæ Š·'ŃŠ“Š½Š°Š½Š½Ń; %s." -#: ../src/nmcli/connections.c:4400 +#: ../src/nmcli/connections.c:4522 #, c-format msgid "Error: bad connection type: %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ¾Š¼ŠøŠ»ŠŗŠ¾Š²ŠøŠ¹ ŃŠøŠæ Š·'ŃŠ“Š½Š°Š½Š½Ń: %s" -#: ../src/nmcli/connections.c:4486 +#: ../src/nmcli/connections.c:4608 msgid "Error: master is required" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŃŠ»ŃŠ“ Š²ŠŗŠ°Š·Š°ŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«masterĀ»" -#: ../src/nmcli/connections.c:4587 +#: ../src/nmcli/connections.c:4709 #, c-format msgid "Error: '%s' is not a valid monitoring mode; use '%s' or '%s'.\n" msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ ŃŠµŠ¶ŠøŠ¼Š¾Š¼ ŃŠæŠ¾ŃŃŠµŃŠµŠ¶ŠµŠ½Š½Ń; ŃŠŗŠ¾ŃŠøŃŃŠ°Š¹ŃŠµŃŃ Ā«%sĀ» Š°Š±Š¾ " "Ā«%sĀ».\n" -#: ../src/nmcli/connections.c:4626 +#: ../src/nmcli/connections.c:4748 #, c-format msgid "Error: 'bt-type': '%s' not valid; use [%s, %s, %s (%s), %s]." msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«bt-typeĀ»: Ā«%sĀ» Ń Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼; ŃŠŗŠ¾ŃŠøŃŃŠ°Š¹ŃŠµŃŃ Š·Š½Š°ŃŠµŠ½Š½ŃŠ¼ Š· ŠæŠµŃŠµŠ»ŃŠŗŃ " "[%s, %s, %s (%s), %s]." -#: ../src/nmcli/connections.c:4973 +#: ../src/nmcli/connections.c:5095 #, c-format msgid "Error: setting '%s' is mandatory and cannot be removed." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ» Ń Š¾Š±Š¾Š²'ŃŠ·ŠŗŠ¾Š²ŠøŠ¼, Š¹Š¾Š³Š¾ Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠ»ŃŃŠ°ŃŠø." -#: ../src/nmcli/connections.c:4989 +#: ../src/nmcli/connections.c:5111 #, c-format msgid "Error: value for '%s' is missing." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ»." -#: ../src/nmcli/connections.c:5040 +#: ../src/nmcli/connections.c:5162 msgid "Error: <setting>.<property> argument is missing." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń <ŠæŠ°ŃŠ°Š¼ŠµŃŃ>.<Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ>." -#: ../src/nmcli/connections.c:5082 +#: ../src/nmcli/connections.c:5204 msgid "Error: missing setting." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ ŠæŠ°ŃŠ°Š¼ŠµŃŃ." -#: ../src/nmcli/connections.c:5096 +#: ../src/nmcli/connections.c:5218 #, c-format msgid "Error: invalid setting argument '%s'." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°, Ā«%sĀ»." -#: ../src/nmcli/connections.c:5127 +#: ../src/nmcli/connections.c:5249 #, c-format msgid "Error: invalid or not allowed setting '%s': %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š°Š±Š¾ Š·Š°Š±Š¾ŃŠ¾Š½ŠµŠ½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ, Ā«%sĀ»: %s." -#: ../src/nmcli/connections.c:5186 ../src/nmcli/connections.c:5207 +#: ../src/nmcli/connections.c:5308 ../src/nmcli/connections.c:5329 #, c-format msgid "Error: '%s' is ambiguous (%s.%s or %s.%s)." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Ń Š½ŠµŠ¾Š“Š½Š¾Š·Š½Š°ŃŠ½ŠøŠ¼ (%s.%s Š°Š±Š¾ %s.%s)." -#: ../src/nmcli/connections.c:5231 +#: ../src/nmcli/connections.c:5353 #, c-format msgid "Error: invalid <setting>.<property> '%s'." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń <ŠæŠ°ŃŠ°Š¼ŠµŃŃ>.<Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ>, Ā«%sĀ»." -#: ../src/nmcli/connections.c:5265 +#: ../src/nmcli/connections.c:5387 ../src/nmcli/devices.c:2159 #, c-format msgid "Warning: %s.\n" msgstr "ŠŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń: %s.\n" -#: ../src/nmcli/connections.c:5284 +#: ../src/nmcli/connections.c:5403 #, c-format msgid "" "Warning: There is another connection with the name '%1$s'. Reference the " @@ -12079,7 +12128,7 @@ msgstr[3] "" "ŠŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń: ŃŃŠ½ŃŃ ŃŠ½ŃŠµ Š·'ŃŠ“Š½Š°Š½Š½Ń Š· Š½Š°Š·Š²Š¾Ń Ā«%1$sĀ». ŠŠ¾ŃŠøŠ»Š°Š¹ŃŠµŃŃ Š½Š° Š·'ŃŠ“Š½Š°Š½Š½Ń " "Š·Š° Š¹Š¾Š³Š¾ UUID, Ā«%2$sĀ»\n" -#: ../src/nmcli/connections.c:5306 ../src/nmcli/connections.c:8986 +#: ../src/nmcli/connections.c:5425 ../src/nmcli/connections.c:9117 #, c-format msgid "Error: Failed to add '%s' connection: %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š“Š¾Š“Š°ŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»: %s" @@ -12093,12 +12142,12 @@ msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š“Š¾Š“Š°ŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ #. * #. * This is true for many messages that the user might parse. But this one #. * seems in particular interesting for a user to parse. -#: ../src/nmcli/connections.c:5323 +#: ../src/nmcli/connections.c:5442 #, c-format msgid "Connection '%s' (%s) successfully added.\n" msgstr "ŠŠ°ŠæŠøŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) ŃŃŠæŃŃŠ½Š¾ Š“Š¾Š“Š°Š½Š¾.\n" -#: ../src/nmcli/connections.c:5467 +#: ../src/nmcli/connections.c:5577 #, c-format msgid "" "You can specify this option more than once. Press <Enter> when you're done.\n" @@ -12107,7 +12156,7 @@ msgstr "" "Š·Š°Š²ŠµŃŃŠøŃŠµ.\n" #. Ask for optional arguments. -#: ../src/nmcli/connections.c:5567 +#: ../src/nmcli/connections.c:5677 #, c-format msgid "There is %d optional setting for %s.\n" msgid_plural "There are %d optional settings for %s.\n" @@ -12116,7 +12165,7 @@ msgstr[1] "ŠŠ»Ń Ā«%2$sĀ» ŠæŠµŃŠµŠ“Š±Š°ŃŠµŠ½Š¾ %1$d Š“Š¾Š“Š°ŃŠŗŠ¾Š²ŠøŠ¹ ŠæŠ° msgstr[2] "ŠŠ»Ń Š·'ŃŠ“Š½Š°Š½Ń ŃŠøŠæŃ Ā«%2$sĀ» ŠæŠµŃŠµŠ“Š±Š°ŃŠµŠ½Š¾ %1$d Š“Š¾Š“Š°ŃŠŗŠ¾Š²ŠøŃ
Š°ŃŠ³ŃŠ¼ŠµŠ½ŃŃŠ².\n" msgstr[3] "ŠŠ»Ń Š·'ŃŠ“Š½Š°Š½Ń ŃŠøŠæŃ Ā«%2$sĀ» ŠæŠµŃŠµŠ“Š±Š°ŃŠµŠ½Š¾ %1$d Š“Š¾Š“Š°ŃŠŗŠ¾Š²ŠøŠ¹ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń.\n" -#: ../src/nmcli/connections.c:5574 +#: ../src/nmcli/connections.c:5684 #, c-format msgid "Do you want to provide it? %s" msgid_plural "Do you want to provide them? %s" @@ -12125,22 +12174,22 @@ msgstr[1] "Š„Š¾ŃŠµŃŠµ Š²ŠŗŠ°Š·Š°ŃŠø ŃŃ
? %s" msgstr[2] "Š„Š¾ŃŠµŃŠµ Š²ŠŗŠ°Š·Š°ŃŠø ŃŃ
? %s" msgstr[3] "Š„Š¾ŃŠµŃŠµ Š²ŠŗŠ°Š·Š°ŃŠø Š¹Š¾Š³Š¾? %s" -#: ../src/nmcli/connections.c:5701 ../src/nmcli/utils.c:280 +#: ../src/nmcli/connections.c:5825 ../src/nmcli/utils.c:280 #, c-format msgid "Error: value for '%s' argument is required." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŃŠ»ŃŠ“ Š²ŠŗŠ°Š·Š°ŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ» Š°ŃŠ³ŃŠ¼ŠµŠ½ŃŃ." -#: ../src/nmcli/connections.c:5708 +#: ../src/nmcli/connections.c:5832 #, c-format msgid "Error: 'save': %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«saveĀ»: %s." -#: ../src/nmcli/connections.c:5793 ../src/nmcli/connections.c:5806 +#: ../src/nmcli/connections.c:5917 ../src/nmcli/connections.c:5930 #, c-format msgid "Error: '%s' argument is required." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŃŠ»ŃŠ“ Š²ŠŗŠ°Š·Š°ŃŠø ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ»." -#: ../src/nmcli/connections.c:6767 +#: ../src/nmcli/connections.c:6887 #, c-format msgid "['%s' setting values]\n" msgstr "['%s' Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°]\n" @@ -12148,7 +12197,7 @@ msgstr "['%s' Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°]\n" #. TRANSLATORS: do not translate command names and keywords before :: #. * However, you should translate terms enclosed in <>. #. -#: ../src/nmcli/connections.c:6878 +#: ../src/nmcli/connections.c:6998 #, c-format msgid "" "---[ Main menu ]---\n" @@ -12182,7 +12231,7 @@ msgstr "" "nmcli <ŠæŠ°ŃŠ°Š¼ŠµŃŃ-Š½Š°Š»Š°ŃŃ.> <Š·Š½Š°Ń.> :: Š½Š°Š»Š°ŃŃŠ¾Š²ŃŠ²Š°Š½Š½Ń nmcli\n" "quit :: Š·Š°Š²ŠµŃŃŠøŃŠø ŃŠ¾Š±Š¾ŃŃ nmcli\n" -#: ../src/nmcli/connections.c:6905 +#: ../src/nmcli/connections.c:7025 #, c-format msgid "" "goto <setting>[.<prop>] | <prop> :: enter setting/property for editing\n" @@ -12203,7 +12252,7 @@ msgstr "" " nmcli connection> goto secondaries\n" " nmcli> goto ipv4.addresses\n" -#: ../src/nmcli/connections.c:6913 +#: ../src/nmcli/connections.c:7033 #, c-format msgid "" "remove <setting>[.<prop>] :: remove setting or reset property value\n" @@ -12225,7 +12274,7 @@ msgstr "" "ŠŃŠøŠŗŠ»Š°Š“Šø: nmcli> remove wifi-sec\n" " nmcli> remove eth.mtu\n" -#: ../src/nmcli/connections.c:6920 +#: ../src/nmcli/connections.c:7040 #, c-format msgid "" "set [<setting>.<prop> <value>] :: set property value\n" @@ -12241,7 +12290,7 @@ msgstr "" "\n" "ŠŃŠøŠŗŠ»Š°Š“: nmcli> s con.id My connection\n" -#: ../src/nmcli/connections.c:6925 +#: ../src/nmcli/connections.c:7045 #, c-format msgid "" "add [<setting>.<prop> <value>] :: add property value\n" @@ -12256,7 +12305,7 @@ msgstr "" "\n" "ŠŃŠøŠŗŠ»Š°Š“: nmcli> add ipv4.addresses 192.168.1.1/24\n" -#: ../src/nmcli/connections.c:6930 +#: ../src/nmcli/connections.c:7050 #, c-format msgid "" "describe [<setting>.<prop>] :: describe property\n" @@ -12269,7 +12318,7 @@ msgstr "" "ŠŠ¾ŠŗŠ°Š·ŃŃ Š¾ŠæŠøŃ Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ. Š”ŠæŠøŃŠ¾Šŗ ŃŃŃŃ
ŠæŠ°ŃŠ°Š¼ŠµŃŃŃŠ² Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŠµŠ¹ NM Š¼Š¾Š¶Š½Š° " "Š·Š½Š°Š¹ŃŠø Š½Š° ŃŃŠ¾ŃŃŠ½ŃŃ Š“Š¾Š²ŃŠ“Š½ŠøŠŗŠ° (man) nm-settings(5).\n" -#: ../src/nmcli/connections.c:6935 +#: ../src/nmcli/connections.c:7055 #, c-format msgid "" "print [all] :: print setting or connection values\n" @@ -12284,7 +12333,7 @@ msgstr "" "\n" "ŠŃŠøŠŗŠ»Š°Š“: nmcli ipv4> print all\n" -#: ../src/nmcli/connections.c:6941 +#: ../src/nmcli/connections.c:7061 #, c-format msgid "" "verify [all | fix] :: verify setting or connection validity\n" @@ -12309,7 +12358,7 @@ msgstr "" " nmcli> verify fix\n" " nmcli bond> verify\n" -#: ../src/nmcli/connections.c:6951 +#: ../src/nmcli/connections.c:7071 #, c-format msgid "" "save [persistent|temporary] :: save the connection\n" @@ -12336,7 +12385,7 @@ msgstr "" "ŠæŠ¾ŃŃŃŠ±Š½Š¾\n" "ŠæŠ¾Š²Š½ŃŃŃŃ Š²ŠøŠ»ŃŃŠøŃŠø ŠæŠ¾ŃŃŃŠ¹Š½Šµ Š·'ŃŠ“Š½Š°Š½Š½Ń, Š²Š°Š¼ Š“Š¾Š²ŠµŠ“ŠµŃŃŃŃ Š²ŠøŠ»ŃŃŠøŃŠø Š¹Š¾Š³Š¾ ŠæŃŠ¾ŃŃŠ»Ń.\n" -#: ../src/nmcli/connections.c:6962 +#: ../src/nmcli/connections.c:7082 #, c-format msgid "" "activate [<ifname>] [/<ap>|<nsp>] :: activate the connection\n" @@ -12357,7 +12406,7 @@ msgstr "" "/<ap>|<nsp> - AP (Wi-Fi) Š°Š±Š¾ NSP (WiMAX) (Š“Š¾Š“Š°Š¹ŃŠµ Š½Š° ŠæŠ¾ŃŠ°ŃŠŗŃ Ā«/Ā», ŃŠŗŃŠ¾ Š½Šµ " "Š²ŠŗŠ°Š·Š°Š½Š¾ <ŃŠ½ŃŠµŃŃŠµŠ¹Ń>)\n" -#: ../src/nmcli/connections.c:6970 ../src/nmcli/connections.c:7129 +#: ../src/nmcli/connections.c:7090 ../src/nmcli/connections.c:7249 #, c-format msgid "" "back :: go to upper menu level\n" @@ -12366,7 +12415,7 @@ msgstr "" "back :: ŠæŃŠ“Š½ŃŃŠøŃŃ Ń Š¼ŠµŠ½Ń Š½Š° Š¾Š“ŠøŠ½ ŃŃŠ²ŠµŠ½Ń\n" "\n" -#: ../src/nmcli/connections.c:6973 +#: ../src/nmcli/connections.c:7093 #, c-format msgid "" "help/? [<command>] :: help for the nmcli commands\n" @@ -12375,7 +12424,7 @@ msgstr "" "help/? [<ŠŗŠ¾Š¼Š°Š½Š“Š°>] :: Š“Š¾Š²ŃŠ“ŠŗŠ° Š· ŠŗŠ¾Š¼Š°Š½Š“Šø nmcli\n" "\n" -#: ../src/nmcli/connections.c:6976 +#: ../src/nmcli/connections.c:7096 #, c-format msgid "" "nmcli [<conf-option> <value>] :: nmcli configuration\n" @@ -12402,7 +12451,7 @@ msgstr "" " nmcli> nmcli save-confirmation no\n" " nmcli> nmcli prompt-color 3\n" -#: ../src/nmcli/connections.c:6998 ../src/nmcli/connections.c:7135 +#: ../src/nmcli/connections.c:7118 ../src/nmcli/connections.c:7255 #, c-format msgid "" "quit :: exit nmcli\n" @@ -12416,8 +12465,8 @@ msgstr "" "Š·Š°ŠæŠøŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Š½Šµ Š±ŃŠ»Š¾ Š·Š±ŠµŃŠµŠ¶ŠµŠ½Š¾, ŠŗŠ¾ŃŠøŃŃŃŠ²Š°ŃŠµŠ²Ń Š±ŃŠ“Šµ Š·Š°ŠæŃŠ¾ŠæŠ¾Š½Š¾Š²Š°Š½Š¾ " "ŠæŃŠ“ŃŠ²ŠµŃŠ“ŠøŃŠø Š“ŃŃ Š· Š²ŠøŃ
Š¾Š“Ń Š· ŠæŃŠ¾Š³ŃŠ°Š¼Šø.\n" -#: ../src/nmcli/connections.c:7003 ../src/nmcli/connections.c:7140 -#: ../src/nmcli/connections.c:7528 ../src/nmcli/connections.c:8556 +#: ../src/nmcli/connections.c:7123 ../src/nmcli/connections.c:7260 +#: ../src/nmcli/connections.c:7648 ../src/nmcli/connections.c:8680 #, c-format msgid "Unknown command: '%s'\n" msgstr "ŠŠµŠ²ŃŠ“Š¾Š¼Š° ŠŗŠ¾Š¼Š°Š½Š“Š° Ā«%sĀ».\n" @@ -12425,7 +12474,7 @@ msgstr "ŠŠµŠ²ŃŠ“Š¾Š¼Š° ŠŗŠ¾Š¼Š°Š½Š“Š° Ā«%sĀ».\n" #. TRANSLATORS: do not translate command names and keywords before :: #. * However, you should translate terms enclosed in <>. #. -#: ../src/nmcli/connections.c:7068 +#: ../src/nmcli/connections.c:7188 #, c-format msgid "" "---[ Property menu ]---\n" @@ -12452,7 +12501,7 @@ msgstr "" "help/? [<ŠŗŠ¾Š¼Š°Š½Š“Š°>] :: Š²ŠøŠ²ŠµŃŃŠø ŃŃ Š“Š¾Š²ŃŠ“ŠŗŃ Š°Š±Š¾ Š¾ŠæŠøŃ ŠŗŠ¾Š¼Š°Š½Š“Šø\n" "quit :: Š²ŠøŠ¹ŃŠø Š· nmcli\n" -#: ../src/nmcli/connections.c:7092 +#: ../src/nmcli/connections.c:7212 #, c-format msgid "" "set [<value>] :: set new value\n" @@ -12464,7 +12513,7 @@ msgstr "" "ŠŠ° Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾Ń ŃŃŃŃ ŠŗŠ¾Š¼Š°Š½Š“Šø Š¼Š¾Š¶Š½Š° Š·Š¼ŃŠ½ŠøŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ Š½Š° Š²ŠŗŠ°Š·Š°Š½Šµ " "<Š·Š½Š°ŃŠµŠ½Š½Ń>\n" -#: ../src/nmcli/connections.c:7096 +#: ../src/nmcli/connections.c:7216 #, c-format msgid "" "add [<value>] :: append new value to the property\n" @@ -12479,7 +12528,7 @@ msgstr "" "ŃŠŗŃŠ¾ Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ Š½Š°Š»ŠµŠ¶ŠøŃŃ Š“Š¾ ŃŠøŠæŃ ŠŗŠ¾Š½ŃŠµŠ¹Š½ŠµŃŃŠ². ŠÆŠŗŃŠ¾ Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ ŃŠŗŠ»Š°Š“Š°ŃŃŃŃŃ " "Š»ŠøŃŠµ Š· Š¾Š“Š½Š¾Š³Š¾ Š·Š½Š°ŃŠµŠ½Š½Ń, ŃŠµ Š·Š½Š°ŃŠµŠ½Š½Ń Š±ŃŠ“Šµ Š·Š°Š¼ŃŠ½ŠµŠ½Š¾ (ŃŠµ ŃŠ°Š¼Šµ, ŃŠ¾ Ń Ā«setĀ»).\n" -#: ../src/nmcli/connections.c:7102 +#: ../src/nmcli/connections.c:7222 #, c-format msgid "" "change :: change current value\n" @@ -12490,7 +12539,7 @@ msgstr "" "\n" "ŠŠ¾ŠŗŠ°Š·ŃŃ ŠæŠ¾ŃŠ¾ŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń Ń Š½Š°Š“Š°Ń Š·Š¼Š¾Š³Ń Š¹Š¾Š³Š¾ ŃŠµŠ“Š°Š³ŃŠ²Š°ŃŠø.\n" -#: ../src/nmcli/connections.c:7107 +#: ../src/nmcli/connections.c:7227 #, c-format msgid "" "remove [<value>|<index>|<option name>] :: delete the value\n" @@ -12523,7 +12572,7 @@ msgstr "" " nmcli bond.options> remove downdelay\n" "\n" -#: ../src/nmcli/connections.c:7118 +#: ../src/nmcli/connections.c:7238 #, c-format msgid "" "describe :: describe property\n" @@ -12536,7 +12585,7 @@ msgstr "" "ŠŠ¾ŠŗŠ°Š·ŃŃ Š¾ŠæŠøŃ Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ. Š”ŠæŠøŃŠ¾Šŗ ŃŃŃŃ
ŠæŠ°ŃŠ°Š¼ŠµŃŃŃŠ² Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŠµŠ¹ NM Š¼Š¾Š¶Š½Š° " "Š·Š½Š°Š¹ŃŠø Š½Š° ŃŃŠ¾ŃŃŠ½ŃŃ Š“Š¾Š²ŃŠ“Š½ŠøŠŗŠ° (man) nm-settings(5).\n" -#: ../src/nmcli/connections.c:7123 +#: ../src/nmcli/connections.c:7243 #, c-format msgid "" "print [property|setting|connection] :: print property (setting, connection) " @@ -12551,7 +12600,7 @@ msgstr "" "ŠŠøŠ²Š¾Š“ŠøŃŃ Š·Š½Š°ŃŠµŠ½Š½Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ. ŠŠ° Š“Š¾ŠæŠ¾Š¼Š¾Š³Š¾Ń Š°ŃŠ³ŃŠ¼ŠµŠ½ŃŃ ŠŗŠ¾Š¼Š°Š½Š“Šø Š²Šø Š¼Š¾Š¶ŠµŃŠµ " "Š²ŠøŠ²Š¾Š“ŠøŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń ŃŃŃŠ¾Š³Š¾ ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Š°Š±Š¾ ŃŃŃŠ¾Š³Š¾ Š·Š°ŠæŠøŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń.\n" -#: ../src/nmcli/connections.c:7132 +#: ../src/nmcli/connections.c:7252 #, c-format msgid "" "help/? [<command>] :: help for nmcli commands\n" @@ -12560,24 +12609,24 @@ msgstr "" "help/? [<ŠŗŠ¾Š¼Š°Š½Š“Š°>] :: Š“Š¾Š²ŃŠ“ŠŗŠ° Š· ŠŗŠ¾Š¼Š°Š½Š“Šø nmcli\n" "\n" -#: ../src/nmcli/connections.c:7224 +#: ../src/nmcli/connections.c:7344 #, c-format msgid "Error: Connection activation failed.\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²Š“Š°Š»Š° ŃŠæŃŠ¾Š±Š° Š°ŠŗŃŠøŠ²Š°ŃŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń.\n" #. TRANSLATORS: status line in nmcli connection editor -#: ../src/nmcli/connections.c:7322 +#: ../src/nmcli/connections.c:7442 #, c-format msgid "[ Type: %s | Name: %s | UUID: %s | Dirty: %s | Temp: %s ]\n" msgstr "[ Š¢ŠøŠæ: %s | ŠŠ°Š·Š²Š°: %s | UUID: %s | ŠŠµ Š·Š±ŠµŃŠµŠ¶ŠµŠ½Š¾: %s | Š¢ŠøŠ¼Ń.: %s ]\n" -#: ../src/nmcli/connections.c:7360 +#: ../src/nmcli/connections.c:7480 #, c-format msgid "The connection is not saved. Do you really want to quit? %s" msgstr "" "Š'ŃŠ“Š½Š°Š½Š½Ń Š½Šµ Š·Š±ŠµŃŠµŠ¶ŠµŠ½Š¾. ŠŠø ŃŠæŃŠ°Š²Š“Ń Ń
Š¾ŃŠµŃŠµ Š·Š°Š²ŠµŃŃŠøŃŠø ŃŠ¾Š±Š¾ŃŃ ŠæŃŠ¾Š³ŃŠ°Š¼Šø? %s" -#: ../src/nmcli/connections.c:7404 +#: ../src/nmcli/connections.c:7524 #, c-format msgid "" "The connection profile has been removed from another client. You may type " @@ -12586,60 +12635,60 @@ msgstr "" "ŠŃŠ¾ŃŃŠ»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń Š±ŃŠ»Š¾ Š²ŠøŠ»ŃŃŠµŠ½Š¾ Š· ŃŠ½ŃŠ¾Š³Š¾ ŠŗŠ»ŃŃŠ½ŃŠ°. ŠŠø Š¼Š¾Š¶ŠµŃŠµ Š²Š²ŠµŃŃŠø Ā«saveĀ» Ń " "Š³Š¾Š»Š¾Š²Š½Š¾Š¼Ń Š¼ŠµŠ½Ń, ŃŠ¾Š± Š²ŃŠ“Š½Š¾Š²ŠøŃŠø Š¹Š¾Š³Š¾.\n" -#: ../src/nmcli/connections.c:7436 ../src/nmcli/connections.c:7828 -#: ../src/nmcli/connections.c:7898 +#: ../src/nmcli/connections.c:7556 ../src/nmcli/connections.c:7948 +#: ../src/nmcli/connections.c:8018 #, c-format msgid "Allowed values for '%s' property: %s\n" msgstr "ŠŠ¾Š¶Š»ŠøŠ²Ń Š·Š½Š°ŃŠµŠ½Š½Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ Ā«%sĀ»: %s\n" -#: ../src/nmcli/connections.c:7438 ../src/nmcli/connections.c:7831 -#: ../src/nmcli/connections.c:7900 +#: ../src/nmcli/connections.c:7558 ../src/nmcli/connections.c:7951 +#: ../src/nmcli/connections.c:8020 #, c-format msgid "Enter '%s' value: " msgstr "ŠŠ²ŠµŠ“ŃŃŃ Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ»: " -#: ../src/nmcli/connections.c:7451 ../src/nmcli/connections.c:7468 -#: ../src/nmcli/connections.c:7839 ../src/nmcli/connections.c:7911 +#: ../src/nmcli/connections.c:7571 ../src/nmcli/connections.c:7588 +#: ../src/nmcli/connections.c:7959 ../src/nmcli/connections.c:8031 #, c-format msgid "Error: failed to set '%s' property: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²ŃŃŠ°Š½Š¾Š²ŠøŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ Ā«%sĀ»: %s\n" -#: ../src/nmcli/connections.c:7460 +#: ../src/nmcli/connections.c:7580 #, c-format msgid "Edit '%s' value: " msgstr "Š ŠµŠ“Š°Š³ŃŠ²Š°Š½Š½Ń Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ»: " -#: ../src/nmcli/connections.c:7481 ../src/nmcli/settings.c:440 +#: ../src/nmcli/connections.c:7601 ../src/nmcli/settings.c:440 #, c-format msgid "Error: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: %s\n" -#: ../src/nmcli/connections.c:7500 +#: ../src/nmcli/connections.c:7620 #, c-format msgid "Unknown command argument: '%s'\n" msgstr "ŠŠµŠ²ŃŠ“Š¾Š¼ŠøŠ¹ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń ŠŗŠ¾Š¼Š°Š½Š“Šø: Ā«%sĀ»\n" -#: ../src/nmcli/connections.c:7595 +#: ../src/nmcli/connections.c:7715 #, c-format msgid "Available settings: %s\n" msgstr "ŠŠ¾ŃŃŃŠæŠ½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠø: %s\n" -#: ../src/nmcli/connections.c:7606 +#: ../src/nmcli/connections.c:7726 #, c-format msgid "Error: invalid setting name; %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š° Š½Š°Š·Š²Š° ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°; %s\n" -#: ../src/nmcli/connections.c:7623 +#: ../src/nmcli/connections.c:7743 #, c-format msgid "Available properties: %s\n" msgstr "ŠŠ¾ŃŃŃŠæŠ½Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ: %s\n" -#: ../src/nmcli/connections.c:7631 +#: ../src/nmcli/connections.c:7751 #, c-format msgid "Error: property %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ %s\n" -#: ../src/nmcli/connections.c:7676 +#: ../src/nmcli/connections.c:7796 #, c-format msgid "" "Saving the connection with 'autoconnect=yes'. That might result in an " @@ -12650,12 +12699,12 @@ msgstr "" "Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Š¼Š¾Š¶Šµ ŠæŃŠøŠ·Š²ŠµŃŃŠø Š“Š¾ Š½ŠµŠ³Š°Š¹Š½Š¾Š³Š¾ Š·Š°Š“ŃŃŠ½Š½Ń Š·'ŃŠ“Š½Š°Š½Š½Ń.\n" "Š„Š¾ŃŠµŃŠµ Š·Š±ŠµŃŠµŠ³ŃŠø Š·Š°ŠæŠøŃ? %s" -#: ../src/nmcli/connections.c:7762 +#: ../src/nmcli/connections.c:7882 #, c-format msgid "You may edit the following settings: %s\n" msgstr "ŠŠ¾Š¶Š½Š° ŃŠµŠ“Š°Š³ŃŠ²Š°ŃŠø ŃŠ°ŠŗŃ ŠæŠ°ŃŠ°Š¼ŠµŃŃŠø: %s\n" -#: ../src/nmcli/connections.c:7790 +#: ../src/nmcli/connections.c:7910 #, c-format msgid "" "The connection profile has been removed from another client. You may type " @@ -12664,234 +12713,234 @@ msgstr "" "ŠŃŠ¾ŃŃŠ»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń Š±ŃŠ»Š¾ Š²ŠøŠ»ŃŃŠµŠ½Š¾ Š· ŃŠ½ŃŠ¾Š³Š¾ ŠŗŠ»ŃŃŠ½ŃŠ°. ŠŠø Š¼Š¾Š¶ŠµŃŠµ Š²Š²ŠµŃŃŠø Ā«saveĀ», " "ŃŠ¾Š± Š²ŃŠ“Š½Š¾Š²ŠøŃŠø Š¹Š¾Š³Š¾.\n" -#: ../src/nmcli/connections.c:7845 ../src/nmcli/connections.c:8127 -#: ../src/nmcli/connections.c:8160 +#: ../src/nmcli/connections.c:7965 ../src/nmcli/connections.c:8247 +#: ../src/nmcli/connections.c:8280 #, c-format msgid "Error: no setting selected; valid are [%s]\n" msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠøŠ±ŃŠ°Š½Š¾ Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°; ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼Šø Š·Š½Š°ŃŠµŠ½Š½ŃŠ¼Šø Ń ŃŠ°ŠŗŃ: [%s]\n" -#: ../src/nmcli/connections.c:7846 +#: ../src/nmcli/connections.c:7966 #, c-format msgid "use 'goto <setting>' first, or 'set <setting>.<property>'\n" msgstr "" "ŃŠæŠ¾ŃŠ°ŃŠŗŃ ŃŠŗŠ¾ŃŠøŃŃŠ°Š¹ŃŠµŃŃ ŠŗŠ¾Š¼Š°Š½Š“Š¾Ń Ā«goto <ŠæŠ°ŃŠ°Š¼ŠµŃŃ>Ā» Š°Š±Š¾ ŠŗŠ¾Š¼Š°Š½Š“Š¾Ń Ā«set " "<ŠæŠ°ŃŠ°Š¼ŠµŃŃ>.<Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ>Ā»\n" -#: ../src/nmcli/connections.c:7866 ../src/nmcli/connections.c:8043 -#: ../src/nmcli/connections.c:8149 +#: ../src/nmcli/connections.c:7986 ../src/nmcli/connections.c:8163 +#: ../src/nmcli/connections.c:8269 #, c-format msgid "Error: invalid setting argument '%s'; valid are [%s]\n" msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°, Ā«%sĀ»; ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼Šø Ń ŃŠ°ŠŗŃ ŠŠŠ ŠŠŠŠ¢Š Š: " "[%s]\n" -#: ../src/nmcli/connections.c:7876 +#: ../src/nmcli/connections.c:7996 #, c-format msgid "Error: missing setting for '%s' property\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Š“Š»Ń Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ Ā«%sĀ»\n" -#: ../src/nmcli/connections.c:7883 +#: ../src/nmcli/connections.c:8003 #, c-format msgid "Error: invalid property: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š° Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ: %s\n" -#: ../src/nmcli/connections.c:7944 +#: ../src/nmcli/connections.c:8064 #, c-format msgid "Error: unknown setting '%s'\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²ŃŠ“Š¾Š¼Šµ Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ»\n" -#: ../src/nmcli/connections.c:7970 +#: ../src/nmcli/connections.c:8090 #, c-format msgid "You may edit the following properties: %s\n" msgstr "ŠŠ¾Š¶Š½Š° ŃŠµŠ“Š°Š³ŃŠ²Š°ŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń ŃŠ°ŠŗŠøŃ
Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŠµŠ¹: %s\n" -#: ../src/nmcli/connections.c:8016 ../src/nmcli/connections.c:8077 +#: ../src/nmcli/connections.c:8136 ../src/nmcli/connections.c:8197 #, c-format msgid "Error: failed to remove value of '%s': %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²ŠøŠ»ŃŃŠøŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń Ā«%sĀ»: %s\n" -#: ../src/nmcli/connections.c:8022 +#: ../src/nmcli/connections.c:8142 #, c-format msgid "Error: no argument given; valid are [%s]\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š°ŃŠ³ŃŠ¼ŠµŠ½ŃŃ; ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼Šø Š°ŃŠ³ŃŠ¼ŠµŠ½ŃŠ°Š¼Šø Ń ŃŠ°ŠŗŃ: [%s]\n" -#: ../src/nmcli/connections.c:8041 +#: ../src/nmcli/connections.c:8161 #, c-format msgid "Setting '%s' is not present in the connection.\n" msgstr "Š£ Š·'ŃŠ“Š½Š°Š½Š½Ń Š½ŠµŠ¼Š°Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ».\n" -#: ../src/nmcli/connections.c:8103 +#: ../src/nmcli/connections.c:8223 #, c-format msgid "Error: %s properties, nor it is a setting name.\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ %s Ń Š½Šµ Ń Š½Š°Š·Š²Š¾Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°.\n" -#: ../src/nmcli/connections.c:8128 ../src/nmcli/connections.c:8161 +#: ../src/nmcli/connections.c:8248 ../src/nmcli/connections.c:8281 #, c-format msgid "use 'goto <setting>' first, or 'describe <setting>.<property>'\n" msgstr "" "ŃŠŗŠ¾ŃŠøŃŃŠ°Š¹ŃŠµŃŃ ŃŠæŠ¾ŃŠ°ŃŠŗŃ ŠŗŠ¾Š¼Š°Š½Š“Š¾Ń Ā«goto <ŠæŠ°ŃŠ°Š¼ŠµŃŃ> Š°Š±Š¾ ŠŗŠ¾Š¼Š°Š½Š“Š¾Ń Ā«describe " "<ŠæŠ°ŃŠ°Š¼ŠµŃŃ>.<Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ>Ā»\n" -#: ../src/nmcli/connections.c:8184 +#: ../src/nmcli/connections.c:8304 #, c-format msgid "Error: invalid property: %s, neither a valid setting name.\n" msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š° Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ: %s Ń Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½Š¾Ń Š½Š°Š·Š²Š¾Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°.\n" -#: ../src/nmcli/connections.c:8214 +#: ../src/nmcli/connections.c:8334 #, c-format msgid "Error: unknown setting: '%s'\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²ŃŠ“Š¾Š¼ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ: Ā«%sĀ»\n" -#: ../src/nmcli/connections.c:8219 +#: ../src/nmcli/connections.c:8339 #, c-format msgid "Error: '%s' setting not present in the connection\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ń Š·'ŃŠ“Š½Š°Š½Š½Ń Š½ŠµŠ¼Š°Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ».\n" -#: ../src/nmcli/connections.c:8251 +#: ../src/nmcli/connections.c:8371 #, c-format msgid "Error: invalid property: %s%s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Š° Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ: %s%s\n" -#: ../src/nmcli/connections.c:8253 +#: ../src/nmcli/connections.c:8373 msgid ", neither a valid setting name" msgstr ", Ń Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½Š¾Ń Š½Š°Š·Š²Š¾Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ°" -#: ../src/nmcli/connections.c:8269 +#: ../src/nmcli/connections.c:8389 #, c-format msgid "Invalid verify option: %s\n" msgstr "ŠŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ verify: %s\n" -#: ../src/nmcli/connections.c:8277 +#: ../src/nmcli/connections.c:8397 #, c-format msgid "Verify setting '%s': %s\n" msgstr "ŠŠµŃŠµŠ²ŃŃŠŗŠ° ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° Ā«%sĀ»: %s\n" -#: ../src/nmcli/connections.c:8292 +#: ../src/nmcli/connections.c:8412 #, c-format msgid "Verify connection: %s\n" msgstr "ŠŠµŃŠµŠ²ŃŃŠŗŠ° Š·'ŃŠ“Š½Š°Š½Š½Ń: %s\n" -#: ../src/nmcli/connections.c:8294 +#: ../src/nmcli/connections.c:8414 #, c-format msgid "The error cannot be fixed automatically.\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŃ Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠæŃŠ°Š²ŠøŃŠø Ń Š°Š²ŃŠ¾Š¼Š°ŃŠøŃŠ½Š¾Š¼Ń ŃŠµŠ¶ŠøŠ¼Ń.\n" -#: ../src/nmcli/connections.c:8314 +#: ../src/nmcli/connections.c:8434 #, c-format msgid "Error: invalid argument '%s'\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń Ā«%sĀ»\n" -#: ../src/nmcli/connections.c:8367 +#: ../src/nmcli/connections.c:8491 #, c-format msgid "Error: Failed to save '%s' (%s) connection: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š“Š¾Š“Š°ŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s): %s\n" -#: ../src/nmcli/connections.c:8373 +#: ../src/nmcli/connections.c:8497 #, c-format msgid "Error: Timeout saving '%s' (%s) connection\n" msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠµŃŠµŠ²ŠøŃŠµŠ½Š½Ń ŃŠ°ŃŃ Š¾ŃŃŠŗŃŠ²Š°Š½Š½Ń Š½Š° Š·Š±ŠµŃŠµŠ¶ŠµŠ½Š½Ń Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s)\n" -#: ../src/nmcli/connections.c:8377 +#: ../src/nmcli/connections.c:8501 #, c-format msgid "Connection '%s' (%s) successfully saved.\n" msgstr "ŠŠ°ŠæŠøŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) ŃŃŠæŃŃŠ½Š¾ Š·Š±ŠµŃŠµŠ¶ŠµŠ½Š¾.\n" -#: ../src/nmcli/connections.c:8378 +#: ../src/nmcli/connections.c:8502 #, c-format msgid "Connection '%s' (%s) successfully updated.\n" msgstr "ŠŠ°ŠæŠøŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) ŃŃŠæŃŃŠ½Š¾ Š¾Š½Š¾Š²Š»ŠµŠ½Š¾.\n" -#: ../src/nmcli/connections.c:8412 +#: ../src/nmcli/connections.c:8536 #, c-format msgid "Error: connection verification failed: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·'ŃŠ“Š½Š°Š½Š½Ń Š½Šµ ŠæŃŠ¾Š¹ŃŠ»Š¾ ŠæŠµŃŠµŠ²ŃŃŠŗŠø: %s\n" -#: ../src/nmcli/connections.c:8413 +#: ../src/nmcli/connections.c:8537 msgid "(unknown error)" msgstr "(Š½ŠµŠ²ŃŠ“Š¾Š¼Š° ŠæŠ¾Š¼ŠøŠ»ŠŗŠ°)" -#: ../src/nmcli/connections.c:8414 +#: ../src/nmcli/connections.c:8538 #, c-format msgid "You may try running 'verify fix' to fix errors.\n" msgstr "ŠŠø Š¼Š¾Š¶ŠµŃŠµ ŃŠæŃŠ¾Š±ŃŠ²Š°ŃŠø Š·Š°ŠæŃŃŃŠøŃŠø Ā«verify fixĀ» Š“Š»Ń Š²ŠøŠæŃŠ°Š²Š»ŠµŠ½Š½Ń ŠæŠ¾Š¼ŠøŠ»Š¾Šŗ.\n" #. TRANSLATORS: do not translate 'save', leave it as it is -#: ../src/nmcli/connections.c:8437 +#: ../src/nmcli/connections.c:8561 #, c-format msgid "Error: connection is not saved. Type 'save' first.\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·'ŃŠ“Š½Š°Š½Š½Ń Š½Šµ Š·Š±ŠµŃŠµŠ¶ŠµŠ½Š¾. Š”ŠæŠ¾ŃŠ°ŃŠŗŃ Š²Š²ŠµŠ“ŃŃŃ Ā«saveĀ».\n" -#: ../src/nmcli/connections.c:8441 +#: ../src/nmcli/connections.c:8565 #, c-format msgid "Error: connection is not valid: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·'ŃŠ“Š½Š°Š½Š½Ń: %s\n" -#: ../src/nmcli/connections.c:8457 +#: ../src/nmcli/connections.c:8581 #, c-format msgid "Error: Cannot activate connection: %s.\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š“ŃŃŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń: %s.\n" -#: ../src/nmcli/connections.c:8466 +#: ../src/nmcli/connections.c:8590 #, c-format msgid "Error: Failed to activate '%s' (%s) connection: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š“ŃŃŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s): %s\n" -#: ../src/nmcli/connections.c:8473 +#: ../src/nmcli/connections.c:8597 msgid "Monitoring connection activation (press any key to continue)\n" msgstr "" "Š”ŠæŠ¾ŃŃŠµŃŃŠ³Š°ŃŠ¼Š¾ Š·Š° Š°ŠŗŃŠøŠ²Š°ŃŃŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń (Š½Š°ŃŠøŃŠ½ŃŃŃ Š±ŃŠ“Ń-ŃŠŗŃ ŠŗŠ»Š°Š²ŃŃŃ, ŃŠ¾Š± " "ŠæŃŠ¾Š“Š¾Š²Š¶ŠøŃŠø)\n" -#: ../src/nmcli/connections.c:8508 +#: ../src/nmcli/connections.c:8632 #, c-format msgid "Error: status-line: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŃŃŠ“Š¾Šŗ ŃŃŠ°Š½Ń: %s\n" -#: ../src/nmcli/connections.c:8516 +#: ../src/nmcli/connections.c:8640 #, c-format msgid "Error: save-confirmation: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: save-confirmation: %s\n" -#: ../src/nmcli/connections.c:8524 +#: ../src/nmcli/connections.c:8648 #, c-format msgid "Error: show-secrets: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: show-secrets: %s\n" -#: ../src/nmcli/connections.c:8532 +#: ../src/nmcli/connections.c:8656 #, c-format msgid "Current nmcli configuration:\n" msgstr "ŠŠ¾ŃŠ¾ŃŠ½Šµ Š½Š°Š»Š°ŃŃŃŠ²Š°Š½Š½Ń nmcli:\n" -#: ../src/nmcli/connections.c:8540 +#: ../src/nmcli/connections.c:8664 #, c-format msgid "Invalid configuration option '%s'; allowed [%s]\n" msgstr "" "ŠŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ Š½Š°Š»Š°ŃŃŃŠ²Š°Š½Š½Ń, Ā«%sĀ»; Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŠ²Š°ŃŠø Š»ŠøŃŠµ ŃŠ°ŠŗŃ: " "[%s]\n" -#: ../src/nmcli/connections.c:8772 +#: ../src/nmcli/connections.c:8896 #, c-format msgid "Error: only one of 'id', 'filename', uuid, or 'path' can be provided." msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š¼Š¾Š¶Š½Š° Š²ŠŗŠ°Š·ŃŠ²Š°ŃŠø Š»ŠøŃŠµ Š¾Š“ŠøŠ½ Š· ŠæŠ°ŃŠ°Š¼ŠµŃŃŃŠ² Ā«idĀ», Ā«filenameĀ», uuid Š°Š±Š¾ " "Ā«pathĀ»." -#: ../src/nmcli/connections.c:8787 ../src/nmcli/connections.c:8956 +#: ../src/nmcli/connections.c:8911 #, c-format msgid "Error: Unknown connection '%s'." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²ŃŠ“Š¾Š¼Šµ Š·'ŃŠ“Š½Š°Š½Š½Ń, Ā«%sĀ»." -#: ../src/nmcli/connections.c:8804 +#: ../src/nmcli/connections.c:8928 #, c-format msgid "Warning: editing existing connection '%s'; 'type' argument is ignored\n" msgstr "" "ŠŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń: ŃŠµŠ“Š°Š³ŃŠ²Š°Š½Š½Ń Š²Š¶Šµ ŃŃŠ²Š¾ŃŠµŠ½Š¾Š³Š¾ Š·Š°ŠæŠøŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»; Š°ŃŠ³ŃŠ¼ŠµŠ½Ń " "Ā«typeĀ» ŠæŃŠ¾ŃŠ³Š½Š¾ŃŠ¾Š²Š°Š½Š¾\n" -#: ../src/nmcli/connections.c:8808 +#: ../src/nmcli/connections.c:8932 #, c-format msgid "" "Warning: editing existing connection '%s'; 'con-name' argument is ignored\n" @@ -12899,227 +12948,227 @@ msgstr "" "ŠŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń: ŃŠµŠ“Š°Š³ŃŠ²Š°Š½Š½Ń Š²Š¶Šµ ŃŃŠ²Š¾ŃŠµŠ½Š¾Š³Š¾ Š·Š°ŠæŠøŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»; Š°ŃŠ³ŃŠ¼ŠµŠ½Ń " "Ā«con-nameĀ» ŠæŃŠ¾ŃŠ³Š½Š¾ŃŠ¾Š²Š°Š½Š¾\n" -#: ../src/nmcli/connections.c:8835 +#: ../src/nmcli/connections.c:8959 #, c-format msgid "Valid connection types: %s\n" msgstr "ŠŠ¾ŃŠµŠŗŃŠ½Ń ŃŠøŠæŠø Š·'ŃŠ“Š½Š°Š½Ń: %s\n" -#: ../src/nmcli/connections.c:8837 +#: ../src/nmcli/connections.c:8961 #, c-format msgid "Error: invalid connection type; %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŃŠøŠæ Š·'ŃŠ“Š½Š°Š½Š½Ń; %s\n" -#: ../src/nmcli/connections.c:8876 +#: ../src/nmcli/connections.c:9000 #, c-format msgid "===| nmcli interactive connection editor |===" msgstr "===| ŠŠ½ŃŠµŃŠ°ŠŗŃŠøŠ²Š½ŠøŠ¹ ŃŠµŠ“Š°ŠŗŃŠ¾Ń Š·'ŃŠ“Š½Š°Š½Ń nmcli |===" -#: ../src/nmcli/connections.c:8879 +#: ../src/nmcli/connections.c:9003 #, c-format msgid "Editing existing '%s' connection: '%s'" msgstr "Š ŠµŠ“Š°Š³ŃŠ²Š°Š½Š½Ń Š½Š°ŃŠ²Š½Š¾Š³Š¾ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»: Ā«%sĀ»" -#: ../src/nmcli/connections.c:8881 +#: ../src/nmcli/connections.c:9005 #, c-format msgid "Adding a new '%s' connection" msgstr "ŠŠ¾Š“Š°Š²Š°Š½Š½Ń Š½Š¾Š²Š¾Š³Š¾ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»" #. TRANSLATORS: do not translate 'help', leave it as it is -#: ../src/nmcli/connections.c:8884 +#: ../src/nmcli/connections.c:9008 #, c-format msgid "Type 'help' or '?' for available commands." msgstr "ŠŠ²ŠµŠ“ŃŃŃ Ā«helpĀ» Š°Š±Š¾ Ā«?Ā», ŃŠ¾Š± Š¾Š·Š½Š°Š¹Š¾Š¼ŠøŃŠøŃŃ Š·Ń ŃŠæŠøŃŠŗŠ¾Š¼ Š“Š¾ŃŃŃŠæŠ½ŠøŃ
ŠŗŠ¾Š¼Š°Š½Š“." #. TRANSLATORS: do not translate 'print', leave it as it is -#: ../src/nmcli/connections.c:8887 +#: ../src/nmcli/connections.c:9011 #, c-format msgid "Type 'print' to show all the connection properties." msgstr "ŠŠ²ŠµŠ“ŃŃŃ Ā«printĀ», ŃŠ¾Š± ŠæŠ¾Š±Š°ŃŠøŃŠø ŃŃŃ Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń." #. TRANSLATORS: do not translate 'describe', leave it as it is -#: ../src/nmcli/connections.c:8890 +#: ../src/nmcli/connections.c:9014 #, c-format msgid "Type 'describe [<setting>.<prop>]' for detailed property description." msgstr "" "Š©Š¾Š± Š¾Š·Š½Š°Š¹Š¾Š¼ŠøŃŠøŃŃ Š· Š“Š¾ŠŗŠ»Š°Š“Š½ŠøŠ¼ Š¾ŠæŠøŃŠ¾Š¼ Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ, ŃŠŗŠ¾ŃŠøŃŃŠ°Š¹ŃŠµŃŃ ŠŗŠ¾Š¼Š°Š½Š“Š¾Ń " "Ā«describe [<ŠæŠ°ŃŠ°Š¼ŠµŃŃ>.<Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ>]." -#: ../src/nmcli/connections.c:8917 +#: ../src/nmcli/connections.c:9041 #, c-format msgid "Error: Failed to modify connection '%s': %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²Š½ŠµŃŃŠø Š·Š¼ŃŠ½Šø Š“Š¾ Š·Š°ŠæŠøŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»: %s" -#: ../src/nmcli/connections.c:8925 +#: ../src/nmcli/connections.c:9049 #, c-format msgid "Connection '%s' (%s) successfully modified.\n" msgstr "ŠŠ¼ŃŠ½Šø Š“Š¾ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) ŃŃŠæŃŃŠ½Š¾ Š²Š½ŠµŃŠµŠ½Š¾.\n" -#: ../src/nmcli/connections.c:8991 +#: ../src/nmcli/connections.c:9122 #, c-format msgid "%s (%s) cloned as %s (%s).\n" msgstr "%s (%s) ŠŗŠ»Š¾Š½Š¾Š²Š°Š½Š¾ ŃŠŗ %s (%s).\n" -#: ../src/nmcli/connections.c:9049 +#: ../src/nmcli/connections.c:9180 msgid "New connection name: " msgstr "ŠŠ¾Š²Š° Š½Š°Š·Š²Š° Š·'ŃŠ“Š½Š°Š½Š½Ń: " -#: ../src/nmcli/connections.c:9051 +#: ../src/nmcli/connections.c:9182 #, c-format msgid "Error: <new name> argument is missing." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ ŠæŠ°ŃŠ°Š¼ŠµŃŃ <Š½Š¾Š²Š° Š½Š°Š·Š²Š°>." -#: ../src/nmcli/connections.c:9057 ../src/nmcli/connections.c:9588 +#: ../src/nmcli/connections.c:9188 ../src/nmcli/connections.c:9719 #, c-format msgid "Error: unknown extra argument: '%s'." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²ŃŠ“Š¾Š¼ŠøŠ¹ Š·Š°Š¹Š²ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ: Ā«%sĀ»." -#: ../src/nmcli/connections.c:9091 +#: ../src/nmcli/connections.c:9222 #, c-format msgid "Error: not all connections deleted." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²ŠøŠ»ŃŃŠµŠ½Š¾ Š½Šµ ŃŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń." -#: ../src/nmcli/connections.c:9092 +#: ../src/nmcli/connections.c:9223 #, c-format msgid "Error: Connection deletion failed: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š²ŠøŠ»ŃŃŠøŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń: %s\n" -#: ../src/nmcli/connections.c:9147 ../src/nmcli/connections.c:9274 -#: ../src/nmcli/connections.c:9741 +#: ../src/nmcli/connections.c:9278 ../src/nmcli/connections.c:9405 +#: ../src/nmcli/connections.c:9872 #, c-format msgid "Error: %s.\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: %s.\n" -#: ../src/nmcli/connections.c:9148 ../src/nmcli/connections.c:9275 -#: ../src/nmcli/connections.c:9742 +#: ../src/nmcli/connections.c:9279 ../src/nmcli/connections.c:9406 +#: ../src/nmcli/connections.c:9873 #, c-format msgid "Error: not all connections found." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·Š½Š°Š¹Š“ŠµŠ½Š¾ Š½Šµ ŃŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń." -#: ../src/nmcli/connections.c:9207 +#: ../src/nmcli/connections.c:9338 #, c-format msgid "Error: cannot delete unknown connection(s): %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠ»ŃŃŠ°ŃŠø Š½ŠµŠ²ŃŠ“Š¾Š¼Ń Š·'ŃŠ“Š½Š°Š½Š½Ń: %s." -#: ../src/nmcli/connections.c:9215 +#: ../src/nmcli/connections.c:9346 #, c-format msgid "%s: connection profile changed\n" msgstr "%s: Š·Š¼ŃŠ½ŠµŠ½Š¾ ŠæŃŠ¾ŃŃŠ»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń\n" -#: ../src/nmcli/connections.c:9241 +#: ../src/nmcli/connections.c:9372 #, c-format msgid "%s: connection profile created\n" msgstr "%s: ŃŃŠ²Š¾ŃŠµŠ½Š¾ ŠæŃŠ¾ŃŃŠ»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń\n" -#: ../src/nmcli/connections.c:9250 +#: ../src/nmcli/connections.c:9381 #, c-format msgid "%s: connection profile removed\n" msgstr "%s: Š²ŠøŠ»ŃŃŠµŠ½Š¾ ŠæŃŠ¾ŃŃŠ»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń\n" -#: ../src/nmcli/connections.c:9318 +#: ../src/nmcli/connections.c:9449 #, c-format msgid "Error: failed to reload connections: %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠæŠµŃŠµŠ·Š°Š²Š°Š½ŃŠ°Š¶ŠøŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń: %s." -#: ../src/nmcli/connections.c:9390 +#: ../src/nmcli/connections.c:9521 #, c-format msgid "Error: failed to load connection: %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š²Š°Š½ŃŠ°Š¶ŠøŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń: %s." -#: ../src/nmcli/connections.c:9398 +#: ../src/nmcli/connections.c:9529 #, c-format msgid "Could not load file '%s'\n" msgstr "ŠŠµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š²Š°Š½ŃŠ°Š¶ŠøŃŠø ŃŠ°Š¹Š» Ā«%sĀ»\n" -#: ../src/nmcli/connections.c:9402 +#: ../src/nmcli/connections.c:9533 msgid "File to import: " msgstr "Š¤Š°Š¹Š» Š“Š»Ń ŃŠ¼ŠæŠ¾ŃŃŃŠ²Š°Š½Š½Ń: " -#: ../src/nmcli/connections.c:9433 +#: ../src/nmcli/connections.c:9564 #, c-format msgid "Error: No arguments provided." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š½Š°Š“Š°Š½Š¾ Š°ŃŠ³ŃŠ¼ŠµŠ½ŃŃŠ²." -#: ../src/nmcli/connections.c:9464 +#: ../src/nmcli/connections.c:9595 #, c-format msgid "Warning: 'type' already specified, ignoring extra one.\n" msgstr "" "ŠŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń: Š·Š½Š°ŃŠµŠ½Š½Ń Ā«typeĀ» Š²Š¶Šµ Š·Š°Š“Š°Š½Š¾, Š·Š°Š¹Š²Šµ Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŃŠ¾ŃŠ³Š½Š¾ŃŠ¾Š²Š°Š½Š¾.\n" -#: ../src/nmcli/connections.c:9479 +#: ../src/nmcli/connections.c:9610 #, c-format msgid "Warning: 'file' already specified, ignoring extra one.\n" msgstr "" "ŠŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń: Š·Š½Š°ŃŠµŠ½Š½Ń Ā«fileĀ» Š²Š¶Šµ Š·Š°Š“Š°Š½Š¾, Š·Š°Š¹Š²Šµ Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŃŠ¾ŃŠ³Š½Š¾ŃŠ¾Š²Š°Š½Š¾.\n" -#: ../src/nmcli/connections.c:9493 +#: ../src/nmcli/connections.c:9624 #, c-format msgid "Error: 'type' argument is required." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŃŠ»ŃŠ“ Š²ŠŗŠ°Š·Š°ŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń Ā«typeĀ»." -#: ../src/nmcli/connections.c:9498 +#: ../src/nmcli/connections.c:9629 #, c-format msgid "Error: 'file' argument is required." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŃŠ»ŃŠ“ Š²ŠŗŠ°Š·Š°ŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń Ā«fileĀ»." -#: ../src/nmcli/connections.c:9508 +#: ../src/nmcli/connections.c:9639 #, c-format msgid "Error: failed to find VPN plugin for %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š½Š°Š¹ŃŠø Š“Š¾Š“Š°ŃŠ¾Šŗ VPN Š“Š»Ń %s." -#: ../src/nmcli/connections.c:9517 ../src/nmcli/connections.c:9609 +#: ../src/nmcli/connections.c:9648 ../src/nmcli/connections.c:9740 #, c-format msgid "Error: failed to load VPN plugin: %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š²Š°Š½ŃŠ°Š¶ŠøŃŠø Š“Š¾Š“Š°ŃŠ¾Šŗ VPN: %s." -#: ../src/nmcli/connections.c:9528 +#: ../src/nmcli/connections.c:9659 #, c-format msgid "Error: failed to import '%s': %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŃŠ¼ŠæŠ¾ŃŃŃŠ²Š°ŃŠø Ā«%sĀ»: %s." -#: ../src/nmcli/connections.c:9594 +#: ../src/nmcli/connections.c:9725 msgid "Output file name: " msgstr "ŠŠ°Š·Š²Š° ŃŠ°Š¹Š»Š° ŃŠµŠ·ŃŠ»ŃŃŠ°ŃŃŠ²: " -#: ../src/nmcli/connections.c:9599 +#: ../src/nmcli/connections.c:9730 #, c-format msgid "Error: the connection is not VPN." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·'ŃŠ“Š½Š°Š½Š½Ń Š½Šµ Š½Š°Š»ŠµŠ¶ŠøŃŃ Š“Š¾ ŃŠøŠæŃ VPN." -#: ../src/nmcli/connections.c:9623 +#: ../src/nmcli/connections.c:9754 #, c-format msgid "Error: failed to create temporary file %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŃŃŠ²Š¾ŃŠøŃŠø ŃŠøŠ¼ŃŠ°ŃŠ¾Š²ŠøŠ¹ ŃŠ°Š¹Š» %s." -#: ../src/nmcli/connections.c:9633 +#: ../src/nmcli/connections.c:9764 #, c-format msgid "Error: failed to export '%s': %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠµŠŗŃŠæŠ¾ŃŃŃŠ²Š°ŃŠø Ā«%sĀ»: %s." -#: ../src/nmcli/connections.c:9647 +#: ../src/nmcli/connections.c:9778 #, c-format msgid "Error: failed to read temporary file '%s': %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠæŃŠ¾ŃŠøŃŠ°ŃŠø ŃŠøŠ¼ŃŠ°ŃŠ¾Š²ŠøŠ¹ ŃŠ°Š¹Š» Ā«%sĀ»: %s." -#: ../src/nmcli/connections.c:9671 +#: ../src/nmcli/connections.c:9802 #, c-format msgid "Error: not all connections migrated." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠµŃŠµŠ½ŠµŃŠµŠ½Š¾ Š½Šµ ŃŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń." -#: ../src/nmcli/connections.c:9672 +#: ../src/nmcli/connections.c:9803 #, c-format msgid "Error: Connection migration failed: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠæŠµŃŠµŠ½ŠµŃŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń: %s\n" -#: ../src/nmcli/connections.c:9676 +#: ../src/nmcli/connections.c:9807 #, c-format msgid "Connection '%s' (%s) successfully migrated.\n" msgstr "ŠŠ°ŠæŠøŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s) ŃŃŠæŃŃŠ½Š¾ ŠæŠµŃŠµŠ½ŠµŃŠµŠ½Š¾.\n" -#: ../src/nmcli/connections.c:9708 +#: ../src/nmcli/connections.c:9839 msgid "'--plugin' argument is missing" msgstr "ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń Š“Š¾ --plugin" -#: ../src/nmcli/connections.c:9804 +#: ../src/nmcli/connections.c:9935 #, c-format msgid "Error: cannot migrate unknown connection(s): %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠæŠµŃŠµŠ½ŠµŃŃŠø Š½ŠµŠ²ŃŠ“Š¾Š¼Ń Š·'ŃŠ“Š½Š°Š½Š½Ń: %s." @@ -13673,148 +13722,148 @@ msgstr "" msgid "Error: Connection activation failed: (%d) %s.\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š°ŠŗŃŠøŠ²ŃŠ²Š°ŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń: (%d) %s.\n" -#: ../src/nmcli/devices.c:2139 +#: ../src/nmcli/devices.c:2140 #, c-format msgid "Error: Failed to setup a Wi-Fi hotspot: %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š½Š°Š»Š°ŃŃŃŠ²Š°ŃŠø ŃŠ¾ŃŠŗŃ Š“Š¾ŃŃŃŠæŃ Wi-Fi: %s" -#: ../src/nmcli/devices.c:2143 +#: ../src/nmcli/devices.c:2144 #, c-format msgid "Error: Failed to add/activate new connection: %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š“Š¾Š“Š°ŃŠø Š°Š±Š¾ Š·Š°Š“ŃŃŃŠø Š½Š¾Š²Šµ Š·'ŃŠ“Š½Š°Š½Š½Ń: %s" -#: ../src/nmcli/devices.c:2147 +#: ../src/nmcli/devices.c:2148 #, c-format msgid "Error: Failed to activate connection: %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š·Š°Š“ŃŃŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń: %s" -#: ../src/nmcli/devices.c:2210 +#: ../src/nmcli/devices.c:2216 #, c-format msgid "Error: Device activation failed: %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ Š°ŠŗŃŠøŠ²ŃŠ²Š°ŃŠø ŠæŃŠøŃŃŃŃŠ¹: %s" -#: ../src/nmcli/devices.c:2260 +#: ../src/nmcli/devices.c:2266 #, c-format msgid "Error: extra argument not allowed: '%s'." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š“Š¾Š“Š°ŃŠŗŠ¾Š²ŠøŠ¹ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń, Ā«%sĀ»." -#: ../src/nmcli/devices.c:2329 ../src/nmcli/devices.c:2342 -#: ../src/nmcli/devices.c:2601 +#: ../src/nmcli/devices.c:2335 ../src/nmcli/devices.c:2348 +#: ../src/nmcli/devices.c:2607 #, c-format msgid "Device '%s' successfully disconnected.\n" msgstr "ŠŃŠøŃŃŃŃŠ¹ Ā«%sĀ» ŃŃŠæŃŃŠ½Š¾ Š²ŃŠ“'ŃŠ“Š½Š°Š½Š¾.\n" -#: ../src/nmcli/devices.c:2331 ../src/nmcli/devices.c:2671 +#: ../src/nmcli/devices.c:2337 ../src/nmcli/devices.c:2677 #, c-format msgid "Device '%s' successfully removed.\n" msgstr "ŠŃŠøŃŃŃŃŠ¹ Ā«%sĀ» ŃŃŠæŃŃŠ½Š¾ Š²ŠøŠ»ŃŃŠµŠ½Š¾.\n" -#: ../src/nmcli/devices.c:2397 ../src/nmcli/devices.c:2477 +#: ../src/nmcli/devices.c:2403 ../src/nmcli/devices.c:2483 #, c-format msgid "Error: Reapplying connection to device '%s' (%s) failed: %s" msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²Š“Š°Š»Š¾ŃŃ ŠæŠ¾Š²ŃŠ¾ŃŠ½Š¾ Š·Š°ŃŃŠ¾ŃŃŠ²Š°ŃŠø Š·'ŃŠ“Š½Š°Š½Š½Ń ŃŠ· ŠæŃŠøŃŃŃŠ¾ŃŠ¼ Ā«%sĀ» (%s): %s" -#: ../src/nmcli/devices.c:2407 ../src/nmcli/devices.c:2486 +#: ../src/nmcli/devices.c:2413 ../src/nmcli/devices.c:2492 #, c-format msgid "Connection successfully reapplied to device '%s'.\n" msgstr "Š'ŃŠ“Š½Š°Š½Š½Ń ŃŃŠæŃŃŠ½Š¾ ŠæŠ¾Š²ŃŠ¾ŃŠ½Š¾ Š·Š°ŃŃŠ¾ŃŠ¾Š²Š°Š½Š¾ Š“Š¾ ŠæŃŠøŃŃŃŠ¾Ń Ā«%sĀ».\n" -#: ../src/nmcli/devices.c:2508 +#: ../src/nmcli/devices.c:2514 #, c-format msgid "Error: Reading applied connection from device '%s' (%s) failed: %s" msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŃŠæŃŠ¾Š±Š° ŃŠøŃŠ°Š½Š½Ń Š·Š°ŃŃŠ¾ŃŠ¾Š²Š°Š½Š¾Š³Š¾ Š·'ŃŠ“Š½Š°Š½Š½Ń Š· ŠæŃŠøŃŃŃŠ¾Ń Ā«%sĀ» (%s) Š·Š°Š·Š½Š°Š»Š° " "Š½ŠµŠ²Š“Š°ŃŃ: %s" -#: ../src/nmcli/devices.c:2585 +#: ../src/nmcli/devices.c:2591 #, c-format msgid "Error: not all devices disconnected." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ ŃŃŃ ŠæŃŠøŃŃŃŠ¾Ń Š²ŃŠ“'ŃŠ“Š½Š°Š½Š¾." -#: ../src/nmcli/devices.c:2586 +#: ../src/nmcli/devices.c:2592 #, c-format msgid "Error: Device '%s' (%s) disconnecting failed: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²Š“Š°Š»Š° ŃŠæŃŠ¾Š±Š° Š²ŃŠ“'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ» (%s): %s\n" -#: ../src/nmcli/devices.c:2662 +#: ../src/nmcli/devices.c:2668 #, c-format msgid "Error: not all devices deleted." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²ŠøŠ»ŃŃŠµŠ½Š¾ Š½Šµ ŃŃŃ ŠæŃŠøŃŃŃŠ¾Ń." -#: ../src/nmcli/devices.c:2663 +#: ../src/nmcli/devices.c:2669 #, c-format msgid "Error: Device '%s' (%s) deletion failed: %s\n" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ¾Š¼ŠøŠ»ŠŗŠ° ŠæŃŠ“ ŃŠ°Ń ŃŠæŃŠ¾Š±Šø Š²ŠøŠ»ŃŃŠµŠ½Š½Ń ŠæŃŠøŃŃŃŠ¾Ń Ā«%sĀ» (%s): %s\n" -#: ../src/nmcli/devices.c:2744 +#: ../src/nmcli/devices.c:2750 #, c-format msgid "Error: No property specified." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠŗŠ°Š·Š°Š½Š¾ Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ." -#: ../src/nmcli/devices.c:2761 ../src/nmcli/devices.c:2780 +#: ../src/nmcli/devices.c:2767 ../src/nmcli/devices.c:2786 #: ../src/nmcli/general.c:796 ../src/nmcli/general.c:818 #, c-format msgid "Error: '%s' argument is missing." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŃŠ¾ŠæŃŃŠµŠ½Š¾ ŠæŠ°ŃŠ°Š¼ŠµŃŃ %s." -#: ../src/nmcli/devices.c:2769 +#: ../src/nmcli/devices.c:2775 #, c-format msgid "Error: 'managed': %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«managedĀ»: %s." -#: ../src/nmcli/devices.c:2788 +#: ../src/nmcli/devices.c:2794 #, c-format msgid "Error: 'autoconnect': %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«autoconnectĀ»: %s." -#: ../src/nmcli/devices.c:2795 ../src/nmcli/general.c:868 +#: ../src/nmcli/devices.c:2801 ../src/nmcli/general.c:868 #, c-format msgid "Error: property '%s' is not known." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š²Š»Š°ŃŃŠøŠ²ŃŃŃŃ Ā«%sĀ» Ń Š½ŠµŠ²ŃŠ“Š¾Š¼Š¾Ń." -#: ../src/nmcli/devices.c:2842 +#: ../src/nmcli/devices.c:2848 #, c-format msgid "%s: using connection '%s'\n" msgstr "%s: Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŃŠ¼Š¾ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ»\n" -#: ../src/nmcli/devices.c:2868 +#: ../src/nmcli/devices.c:2874 #, c-format msgid "%s: device created\n" msgstr "%s: ŃŃŠ²Š¾ŃŠµŠ½Š¾ Š·Š°ŠæŠøŃ ŠæŃŠøŃŃŃŠ¾Ń\n" -#: ../src/nmcli/devices.c:2875 +#: ../src/nmcli/devices.c:2881 #, c-format msgid "%s: device removed\n" msgstr "%s: ŠæŃŠøŃŃŃŃŠ¹ Š²ŠøŠ»ŃŃŠµŠ½Š¾\n" -#: ../src/nmcli/devices.c:3051 +#: ../src/nmcli/devices.c:3057 msgid "Wi-Fi scan list" msgstr "Š”ŠæŠøŃŠ¾Šŗ ŃŠŗŠ°Š½ŃŠ²Š°Š½Š½Ń Wi-Fi" -#: ../src/nmcli/devices.c:3168 ../src/nmcli/devices.c:3449 +#: ../src/nmcli/devices.c:3174 ../src/nmcli/devices.c:3455 #, c-format msgid "Error: Access point with bssid '%s' not found." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ ŃŠ¾ŃŠŗŠø Š“Š¾ŃŃŃŠæŃ Š· bssid Ā«%sĀ»." -#: ../src/nmcli/devices.c:3370 +#: ../src/nmcli/devices.c:3376 #, c-format msgid "Error: 'device wifi': %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«device wifiĀ»: %s" -#: ../src/nmcli/devices.c:3390 +#: ../src/nmcli/devices.c:3396 #, c-format msgid "Error: invalid rescan argument: '%s' not among [auto, no, yes]" msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ Š°ŃŠ³ŃŠ¼ŠµŠ½Ń rescan: Ā«%sĀ» Š½Šµ Š½Š°Š»ŠµŠ¶ŠøŃŃ Š“Š¾ Š½Š°Š±Š¾ŃŃ [auto, no, " "yes]" -#: ../src/nmcli/devices.c:3429 +#: ../src/nmcli/devices.c:3435 #, c-format msgid "Error: Device '%s' not found." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ ŠæŃŠøŃŃŃŃŠ¹ Ā«%sĀ»." -#: ../src/nmcli/devices.c:3433 +#: ../src/nmcli/devices.c:3439 #, c-format msgid "" "Error: Device '%s' was not recognized as a Wi-Fi device, check " @@ -13823,28 +13872,28 @@ msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŃŠøŃŃŃŃŠ¹ Ā«%sĀ» Š½Šµ ŃŠ¾Š·ŠæŃŠ·Š½Š°Š½Š¾ ŃŠŗ ŠæŃŠøŃŃŃŃŠ¹ Wi-Fi, ŠæŠµŃŠµŠ²ŃŃŃŠµ, ŃŠø ŠæŃŠ°ŃŃŃ " "Š“Š¾Š“Š°ŃŠ¾Šŗ Wi-Fi NetworkManager." -#: ../src/nmcli/devices.c:3438 ../src/nmcli/devices.c:3790 -#: ../src/nmcli/devices.c:4419 ../src/nmcli/devices.c:4554 -#: ../src/nmcli/devices.c:4689 +#: ../src/nmcli/devices.c:3444 ../src/nmcli/devices.c:3796 +#: ../src/nmcli/devices.c:4425 ../src/nmcli/devices.c:4560 +#: ../src/nmcli/devices.c:4695 #, c-format msgid "Error: Device '%s' is not a Wi-Fi device." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŃŠøŃŃŃŃŠ¹ Ā«%sĀ» Š½Šµ Ń ŠæŃŠøŃŃŃŠ¾ŃŠ¼ Wi-Fi." -#: ../src/nmcli/devices.c:3618 +#: ../src/nmcli/devices.c:3624 msgid "SSID or BSSID: " msgstr "SSID Š°Š±Š¾ BSSID: " -#: ../src/nmcli/devices.c:3623 +#: ../src/nmcli/devices.c:3629 #, c-format msgid "Error: SSID or BSSID are missing." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š²ŠøŃŃŠ°ŃŠ°Ń SSID Š°Š±Š¾ BSSID." -#: ../src/nmcli/devices.c:3667 +#: ../src/nmcli/devices.c:3673 #, c-format msgid "Error: bssid argument value '%s' is not a valid BSSID." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° bssid, Ā«%sĀ», Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ BSSID." -#: ../src/nmcli/devices.c:3698 +#: ../src/nmcli/devices.c:3704 #, c-format msgid "" "Error: wep-key-type argument value '%s' is invalid, use 'key' or 'phrase'." @@ -13852,49 +13901,49 @@ msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·Š½Š°ŃŠµŠ½Š½Ń ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° wep-key-type, Ā«%sĀ», Ń Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼, ŃŠ»ŃŠ“ " "Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŠ²Š°ŃŠø Ā«keyĀ» Š°Š±Š¾ Ā«phraseĀ»." -#: ../src/nmcli/devices.c:3726 ../src/nmcli/devices.c:3747 +#: ../src/nmcli/devices.c:3732 ../src/nmcli/devices.c:3753 #, c-format msgid "Error: %s: %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: %s: %s." -#: ../src/nmcli/devices.c:3769 +#: ../src/nmcli/devices.c:3775 #, c-format msgid "Error: BSSID to connect to (%s) differs from bssid argument (%s)." msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: BSSID Š“Š»Ń Š·'ŃŠ“Š½Š°Š½Š½Ń Š· (%s) Š²ŃŠ“ŃŃŠ·Š½ŃŃŃŃŃŃ Š²ŃŠ“ ŠæŠ°ŃŠ°Š¼ŠµŃŃŠ° bssid (%s)." -#: ../src/nmcli/devices.c:3777 +#: ../src/nmcli/devices.c:3783 #, c-format msgid "Error: Parameter '%s' is neither SSID nor BSSID." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ» Š½Šµ Š“Š¾ŃŃŠ²Š½ŃŃ Š½Ń SSID, Š½Ń BSSID." -#: ../src/nmcli/devices.c:3793 ../src/nmcli/devices.c:4422 -#: ../src/nmcli/devices.c:4557 ../src/nmcli/devices.c:4789 +#: ../src/nmcli/devices.c:3799 ../src/nmcli/devices.c:4428 +#: ../src/nmcli/devices.c:4563 ../src/nmcli/devices.c:4795 #, c-format msgid "Error: No Wi-Fi device found." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ Š¶Š¾Š“Š½Š¾Š³Š¾ ŠæŃŠøŃŃŃŠ¾Ń Wi-Fi." -#: ../src/nmcli/devices.c:3815 +#: ../src/nmcli/devices.c:3821 #, c-format msgid "Error: Failed to scan hidden SSID: %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ¼Š¾Š¶Š»ŠøŠ²Š¾ Š²ŠøŠŗŠ¾Š½Š°ŃŠø ŃŠŗŠ°Š½ŃŠ²Š°Š½Š½Ń ŠæŃŠøŃ
Š¾Š²Š°Š½Š¾Š³Š¾ SSID: %s." -#: ../src/nmcli/devices.c:3847 +#: ../src/nmcli/devices.c:3853 #, c-format msgid "Error: No network with SSID '%s' found." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ Š¼ŠµŃŠµŠ¶Ń Š· SSID Ā«%sĀ»." -#: ../src/nmcli/devices.c:3851 +#: ../src/nmcli/devices.c:3857 #, c-format msgid "Error: No access point with BSSID '%s' found." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š·Š½Š°Š¹Š“ŠµŠ½Š¾ ŃŠ¾ŃŠŗŠø Š“Š¾ŃŃŃŠæŃ Š· BSSID Ā«%sĀ»." -#: ../src/nmcli/devices.c:3880 +#: ../src/nmcli/devices.c:3886 #, c-format msgid "Error: Connection '%s' exists but properties don't match." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŃŃŠ½ŃŃ Š·'ŃŠ“Š½Š°Š½Š½Ń Ā«%sĀ», Š°Š»Šµ Š¹Š¾Š³Š¾ Š²Š»Š°ŃŃŠøŠ²Š¾ŃŃŃ Ń Š½ŠµŠ²ŃŠ“ŠæŠ¾Š²ŃŠ“Š½ŠøŠ¼Šø." -#: ../src/nmcli/devices.c:3929 +#: ../src/nmcli/devices.c:3935 #, c-format msgid "" "Warning: '%s' should be SSID for hidden APs; but it looks like a BSSID.\n" @@ -13902,86 +13951,86 @@ msgstr "" "ŠŠ¾ŠæŠµŃŠµŠ“Š¶ŠµŠ½Š½Ń: Ā«%sĀ» Š¼Š°Ń Š±ŃŃŠø SSID Š“Š»Ń ŠæŃŠøŃ
Š¾Š²Š°Š½ŠøŃ
ŃŠ¾ŃŠ¾Šŗ Š“Š¾ŃŃŃŠæŃ; Š²ŃŃŠ¼, " "Š·Š“Š°ŃŃŃŃŃ, Š¼Š°ŃŠ¼Š¾ BSSID.\n" -#: ../src/nmcli/devices.c:3971 +#: ../src/nmcli/devices.c:3977 msgid "Password: " msgstr "ŠŠ°ŃŠ¾Š»Ń: " -#: ../src/nmcli/devices.c:4109 +#: ../src/nmcli/devices.c:4115 #, c-format msgid "'%s' is not valid WPA PSK" msgstr "Ā«%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ PSK WPA" -#: ../src/nmcli/devices.c:4130 +#: ../src/nmcli/devices.c:4136 #, c-format msgid "'%s' is not valid WEP key (it should be 5 or 13 ASCII chars)" msgstr "" "Ā«%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ ŠŗŠ»ŃŃŠµŠ¼ WEP (ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¹ ŠŗŠ»ŃŃ Š¼Š°Ń ŃŠŗŠ»Š°Š“Š°ŃŠøŃŃ Š· 5 Š°Š±Š¾ 13 " "ŃŠøŠ¼Š²Š¾Š»ŃŠ² ASCII)" -#: ../src/nmcli/devices.c:4149 +#: ../src/nmcli/devices.c:4155 #, c-format msgid "Hotspot password: %s\n" msgstr "ŠŠ°ŃŠ¾Š»Ń Š“Š¾ ŃŠ¾ŃŠŗŠø Š“Š¾ŃŃŃŠæŃ: %s\n" -#: ../src/nmcli/devices.c:4328 +#: ../src/nmcli/devices.c:4334 #, c-format msgid "Error: ssid is too long." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: SSID Ń Š½Š°Š“ŃŠ¾ Š“Š¾Š²Š³ŠøŠ¼." -#: ../src/nmcli/devices.c:4346 +#: ../src/nmcli/devices.c:4352 #, c-format msgid "Error: band argument value '%s' is invalid; use 'a' or 'bg'." msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š·Š½Š°ŃŠµŠ½Š½Ń Š°ŃŠ³ŃŠ¼ŠµŠ½ŃŃ Ā«bandĀ» Ā«%sĀ» Ń Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼; Š¼Š°Ń Š±ŃŃŠø Ā«aĀ» Š°Š±Š¾ Ā«bgĀ»." -#: ../src/nmcli/devices.c:4397 +#: ../src/nmcli/devices.c:4403 #, c-format msgid "Error: channel requires band too." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŃŠ°Š·Š¾Š¼ ŃŠ· ŠŗŠ°Š½Š°Š»Š¾Š¼ ŃŠ»ŃŠ“ Š²ŠŗŠ°Š·Š°ŃŠø ŃŠ¼ŃŠ³Ń." -#: ../src/nmcli/devices.c:4404 +#: ../src/nmcli/devices.c:4410 #, c-format msgid "Error: channel '%s' not valid for band '%s'." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŠ²Š°ŃŠø ŠŗŠ°Š½Š°Š» Ā«%sĀ» Š“Š»Ń ŃŠ¼ŃŠ³Šø Ā«%sĀ»." -#: ../src/nmcli/devices.c:4435 +#: ../src/nmcli/devices.c:4441 #, c-format msgid "Error: Device '%s' supports neither AP nor Ad-Hoc mode." msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š“Š»Ń ŠæŃŠøŃŃŃŠ¾Ń Ā«%sĀ» Š½Šµ ŠæŠµŃŠµŠ“Š±Š°ŃŠµŠ½Š¾ Š½Ń ŃŠµŠ¶ŠøŠ¼Ń ŃŠ¾ŃŠŗŠø Š“Š¾ŃŃŃŠæŃ, Š½Ń ŃŠµŠ¶ŠøŠ¼Ń " "Ad-Hoc." -#: ../src/nmcli/devices.c:4462 +#: ../src/nmcli/devices.c:4468 #, c-format msgid "Error: Invalid 'password': %s." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠŗŠ¾ŃŠµŠŗŃŠ½Šµ Š·Š½Š°ŃŠµŠ½Š½Ń Ā«passwordĀ»: %s." -#: ../src/nmcli/devices.c:4513 ../src/nmcli/devices.c:4743 +#: ../src/nmcli/devices.c:4519 ../src/nmcli/devices.c:4749 #, c-format msgid "Error: '%s' cannot repeat." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½Šµ Š¼Š¾Š¶Š½Š° ŠæŠ¾Š²ŃŠ¾ŃŃŠ²Š°ŃŠø Ā«%sĀ»." -#: ../src/nmcli/devices.c:4648 ../src/nmcli/devices.c:4651 -#: ../src/nmcli/devices.c:4655 ../src/nmcli/devices.c:4658 +#: ../src/nmcli/devices.c:4654 ../src/nmcli/devices.c:4657 +#: ../src/nmcli/devices.c:4661 ../src/nmcli/devices.c:4664 #: ../src/nmtui/nmt-page-wifi.c:253 msgid "Security" msgstr "ŠŠ°Ń
ŠøŃŃ" -#: ../src/nmcli/devices.c:4648 +#: ../src/nmcli/devices.c:4654 msgid "None" msgstr "ŠŠµŠ¼Š°Ń" -#: ../src/nmcli/devices.c:4777 +#: ../src/nmcli/devices.c:4783 #, c-format msgid "%s" msgstr "%s" #. Main header name -#: ../src/nmcli/devices.c:4830 +#: ../src/nmcli/devices.c:4836 msgid "Device LLDP neighbors" msgstr "LLDP-ŃŃŃŃŠ“Šø ŠæŃŠøŃŃŃŠ¾Ń" -#: ../src/nmcli/devices.c:4963 +#: ../src/nmcli/devices.c:4969 #, c-format msgid "Error: 'device lldp list': %s" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«device lldp listĀ»: %s" @@ -14564,7 +14613,7 @@ msgid "master" msgstr "Š¾ŃŠ½Š¾Š²Š½ŠøŠ¹" #: ../src/nmcli/general.c:1419 ../src/nmtui/nm-editor-utils.c:247 -#: ../src/nmtui/nmt-connect-connection-list.c:390 +#: ../src/nmtui/nmt-connect-connection-list.c:391 msgid "VPN" msgstr "VPN" @@ -14707,59 +14756,59 @@ msgstr "ŠŠ°Š»Š¾ Š±ŃŃŠø Š·Š½Š°ŃŠµŠ½Š½Ń Š“Š»Ń Ā«%sĀ»\n" msgid "Expected a line break following '%s'\n" msgstr "ŠŠ°Š² Š±ŃŃŠø ŃŠøŠ¼Š²Š¾Š» ŃŠ¾Š·ŃŠøŠ²Ń ŃŃŠ“ŠŗŠ° ŃŠ· Š½Š°ŃŃŃŠæŠ½ŠøŠ¼ Ā«%sĀ»\n" -#: ../src/nmcli/nmcli.c:789 +#: ../src/nmcli/nmcli.c:792 #, c-format msgid "Error: Option '--terse' is specified the second time." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«--terseĀ» Š²ŠŗŠ°Š·Š°Š½Š¾ Š“Š²ŃŃŃ." -#: ../src/nmcli/nmcli.c:795 +#: ../src/nmcli/nmcli.c:798 #, c-format msgid "Error: Option '--terse' is mutually exclusive with '--pretty'." msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«--terseĀ» Ń Ā«--prettyĀ» Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŠ²Š°ŃŠø Š¾Š“Š½Š¾ŃŠ°ŃŠ½Š¾." -#: ../src/nmcli/nmcli.c:803 +#: ../src/nmcli/nmcli.c:806 #, c-format msgid "Error: Option '--pretty' is specified the second time." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«--prettyĀ» Š²ŠŗŠ°Š·Š°Š½Š¾ Š“Š²ŃŃŃ." -#: ../src/nmcli/nmcli.c:809 +#: ../src/nmcli/nmcli.c:812 #, c-format msgid "Error: Option '--pretty' is mutually exclusive with '--terse'." msgstr "" "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«--prettyĀ» Ń Ā«--terseĀ» Š½Šµ Š¼Š¾Š¶Š½Š° Š²ŠøŠŗŠ¾ŃŠøŃŃŠ¾Š²ŃŠ²Š°ŃŠø Š¾Š“Š½Š¾ŃŠ°ŃŠ½Š¾" -#: ../src/nmcli/nmcli.c:824 +#: ../src/nmcli/nmcli.c:827 #, c-format msgid "Error: '%s' is not a valid argument for '%s' option." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š°ŃŠ³ŃŠ¼ŠµŠ½ŃŠ¾Š¼ Ā«%sĀ»." -#: ../src/nmcli/nmcli.c:841 ../src/nmcli/nmcli.c:856 +#: ../src/nmcli/nmcli.c:844 ../src/nmcli/nmcli.c:859 #, c-format msgid "Error: '%s' is not valid argument for '%s' option." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ Š°ŃŠ³ŃŠ¼ŠµŠ½ŃŠ¾Š¼ Ā«%sĀ»." -#: ../src/nmcli/nmcli.c:882 +#: ../src/nmcli/nmcli.c:885 #, c-format msgid "Error: '%s' is not a valid timeout." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Ā«%sĀ» Š½Šµ Ń ŠŗŠ¾ŃŠµŠŗŃŠ½ŠøŠ¼ ŃŠ°ŃŠ¾Š¼ Š¾ŃŃŠŗŃŠ²Š°Š½Š½Ń." -#: ../src/nmcli/nmcli.c:889 +#: ../src/nmcli/nmcli.c:892 #, c-format msgid "nmcli tool, version %s\n" msgstr "ŃŠ½ŃŃŃŃŠ¼ŠµŠ½Ń nmcli, Š²ŠµŃŃŃŃ %s\n" -#: ../src/nmcli/nmcli.c:898 +#: ../src/nmcli/nmcli.c:901 #, c-format msgid "Error: Option '%s' is unknown, try 'nmcli -help'." msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: Š½ŠµŠ²ŃŠ“Š¾Š¼ŠøŠ¹ ŠæŠ°ŃŠ°Š¼ŠµŃŃ Ā«%sĀ», ŃŠæŃŠ¾Š±ŃŠ¹ŃŠµ Ā«nmcli -helpĀ»." -#: ../src/nmcli/nmcli.c:956 ../src/nmcli/nmcli.c:965 +#: ../src/nmcli/nmcli.c:959 ../src/nmcli/nmcli.c:968 #, c-format msgid "Error: nmcli terminated by signal %s (%d)" msgstr "ŠŠ¾Š¼ŠøŠ»ŠŗŠ°: ŃŠ¾Š±Š¾ŃŃ nmcli ŠæŠµŃŠµŃŠ²Š°Š½Š¾ ŃŠøŠ³Š½Š°Š»Š¾Š¼ %s (%d)" -#: ../src/nmcli/nmcli.c:1030 +#: ../src/nmcli/nmcli.c:1035 msgid "Success" msgstr "ŠŠøŠŗŠ¾Š½Š°Š½Š¾" diff --git a/src/c-list/.github/workflows/ci.yml b/src/c-list/.github/workflows/ci.yml index 76a41592d0..e07f3118d7 100644 --- a/src/c-list/.github/workflows/ci.yml +++ b/src/c-list/.github/workflows/ci.yml @@ -9,23 +9,19 @@ on: jobs: ci: name: CI with Default Configuration - runs-on: ubuntu-latest - - steps: - - name: Fetch Sources - uses: actions/checkout@v2 - - name: Run through C-Util CI - uses: c-util/automation/src/ci-c-util@v1 - with: - m32: 1 - valgrind: 1 + uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1 + with: + cabuild_ref: "v1" + m32: true + matrixmode: true + valgrind: true ci-msvc: name: CI with MSVC runs-on: ${{ matrix.os }} strategy: matrix: - os: [windows-2016, windows-latest] + os: [windows-2019, windows-latest] steps: - name: Fetch Sources diff --git a/src/c-list/AUTHORS b/src/c-list/AUTHORS index 439473ced6..76dea8729d 100644 --- a/src/c-list/AUTHORS +++ b/src/c-list/AUTHORS @@ -30,11 +30,12 @@ AUTHORS-LGPL: along with this program; If not, see <http://www.gnu.org/licenses/>. COPYRIGHT: (ordered alphabetically) - Copyright (C) 2015-2019 Red Hat, Inc. + Copyright (C) 2015-2022 Red Hat, Inc. AUTHORS: (ordered alphabetically) Danilo Horta <danilo.horta@pm.me> David Rheinsberg <david.rheinsberg@gmail.com> Lucas De Marchi <lucas.de.marchi@gmail.com> + Michele Dionisio Thomas Haller <thaller@redhat.com> Tom Gundersen <teg@jklm.no> diff --git a/src/c-list/NEWS.md b/src/c-list/NEWS.md index 0404389597..02d2c9a5ca 100644 --- a/src/c-list/NEWS.md +++ b/src/c-list/NEWS.md @@ -1,5 +1,18 @@ # c-list - Circular Intrusive Double Linked List Collection +## CHANGES WITH 4: + + * The minimum required meson version is now 0.60.0. + + * New function c_list_split() is added. It reverses c_list_splice() + and thus allows to split a list in half. + + * TBD + + Contributions from: David Rheinsberg + + - TBD, YYYY-MM-DD + ## CHANGES WITH 3: * API break: The c_list_loop_*() symbols were removed, since we saw diff --git a/src/c-list/README.md b/src/c-list/README.md index d14198999f..a2e47528ed 100644 --- a/src/c-list/README.md +++ b/src/c-list/README.md @@ -20,7 +20,7 @@ The requirements for this project are: At build-time, the following software is required: - * `meson >= 0.41` + * `meson >= 0.60` * `pkg-config >= 0.29` ### Build diff --git a/src/c-list/meson.build b/src/c-list/meson.build index 21bb784f1c..1776b105f2 100644 --- a/src/c-list/meson.build +++ b/src/c-list/meson.build @@ -1,15 +1,46 @@ project( 'c-list', 'c', - version: '3', - license: 'Apache', default_options: [ 'c_std=c99', ], + license: 'Apache', + meson_version: '>=0.60.0', + version: '3.0.0', ) +major = meson.project_version().split('.')[0] project_description = 'Circular Intrusive Double Linked List Collection' -add_project_arguments('-D_GNU_SOURCE', language: 'c') mod_pkgconfig = import('pkgconfig') +# See c-stdaux for details on these. We do not have c-stdaux as dependency, so +# we keep a duplicated set here, reduced to the minimum. +cflags = meson.get_compiler('c').get_supported_arguments( + '-D_GNU_SOURCE', + + '-Wno-gnu-alignof-expression', + '-Wno-maybe-uninitialized', + '-Wno-unknown-warning-option', + '-Wno-unused-parameter', + + '-Wno-error=type-limits', + '-Wno-error=missing-field-initializers', + + '-Wdate-time', + '-Wdeclaration-after-statement', + '-Wlogical-op', + '-Wmissing-include-dirs', + '-Wmissing-noreturn', + '-Wnested-externs', + '-Wredundant-decls', + '-Wshadow', + '-Wstrict-aliasing=3', + '-Wsuggest-attribute=noreturn', + '-Wundef', + '-Wwrite-strings', +) +add_project_arguments(cflags, language: 'c') + subdir('src') + +meson.override_dependency('libclist-'+major, libclist_dep, static: true) diff --git a/src/c-list/src/c-list.h b/src/c-list/src/c-list.h index 69de0b31eb..711b54d630 100644 --- a/src/c-list/src/c-list.h +++ b/src/c-list/src/c-list.h @@ -260,6 +260,31 @@ static inline void c_list_splice(CList *target, CList *source) { } /** + * c_list_split() - split one list in two + * @source: the list to split + * @where: new starting element of newlist + * @target: new list + * + * This splits @source in two. All elements following @where (including @where) + * are moved to @target, replacing any old list. If @where points to @source + * (i.e., the end of the list), @target will be empty. + */ +static inline void c_list_split(CList *source, CList *where, CList *target) { + if (where == source) { + *target = (CList)C_LIST_INIT(*target); + } else { + target->next = where; + target->prev = source->prev; + + where->prev->next = source; + source->prev = where->prev; + + where->prev = target; + target->prev->next = target; + } +} + +/** * c_list_first() - return pointer to first element, or NULL if empty * @list: list to operate on, or NULL * diff --git a/src/c-list/src/meson.build b/src/c-list/src/meson.build index 0261ae0c2f..ec7f29d5f5 100644 --- a/src/c-list/src/meson.build +++ b/src/c-list/src/meson.build @@ -13,10 +13,10 @@ if not meson.is_subproject() install_headers('c-list.h') mod_pkgconfig.generate( - version: meson.project_version(), - name: 'libclist', - filebase: 'libclist', description: project_description, + filebase: 'libclist-'+major, + name: 'libclist', + version: meson.project_version(), ) endif diff --git a/src/c-list/src/test-api.c b/src/c-list/src/test-api.c index bf760cf92f..864d198a65 100644 --- a/src/c-list/src/test-api.c +++ b/src/c-list/src/test-api.c @@ -17,7 +17,8 @@ typedef struct { } Node; static void test_api(void) { - CList *list_iter, *list_safe, list = C_LIST_INIT(list); + CList *list_iter, *list_safe; + CList list = C_LIST_INIT(list), list2 = C_LIST_INIT(list2); Node node = { .id = 0, .link = C_LIST_INIT(node.link) }; assert(c_list_init(&list) == &list); @@ -68,7 +69,7 @@ static void test_api(void) { c_list_unlink(&node.link); assert(!c_list_is_linked(&node.link)); - /* swap / splice list operators */ + /* swap / splice / split list operators */ c_list_swap(&list, &list); assert(c_list_is_empty(&list)); @@ -76,6 +77,10 @@ static void test_api(void) { c_list_splice(&list, &list); assert(c_list_is_empty(&list)); + c_list_split(&list, &list, &list2); + assert(c_list_is_empty(&list)); + assert(c_list_is_empty(&list2)); + /* direct/raw iterators */ c_list_for_each(list_iter, &list) diff --git a/src/c-list/src/test-basic.c b/src/c-list/src/test-basic.c index 06cccd852b..58ed863684 100644 --- a/src/c-list/src/test-basic.c +++ b/src/c-list/src/test-basic.c @@ -11,6 +11,18 @@ #include <string.h> #include "c-list.h" +static void assert_list_integrity(CList *list) { + CList *iter; + + iter = list; + do { + assert(iter->next->prev == iter); + assert(iter->prev->next == iter); + + iter = iter->next; + } while (iter != list); +} + static void test_iterators(void) { CList *iter, *safe, a, b, list = C_LIST_INIT(list); unsigned int i; @@ -158,6 +170,85 @@ static void test_splice(void) { assert(c_list_last(&target) == &e2); } +static void test_split(void) { + CList e1, e2; + + /* split empty list */ + { + CList source = C_LIST_INIT(source), target; + + c_list_split(&source, &source, &target); + assert(c_list_is_empty(&source)); + assert(c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } + + /* split 1-element list excluding the element */ + { + CList source = C_LIST_INIT(source), target; + + c_list_link_tail(&source, &e1); + c_list_split(&source, &source, &target); + assert(!c_list_is_empty(&source)); + assert(c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } + + /* split 1-element list including the element */ + { + CList source = C_LIST_INIT(source), target; + + c_list_link_tail(&source, &e1); + c_list_split(&source, &e1, &target); + assert(c_list_is_empty(&source)); + assert(!c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } + + /* split 2-element list excluding the elements */ + { + CList source = C_LIST_INIT(source), target; + + c_list_link_tail(&source, &e1); + c_list_link_tail(&source, &e2); + c_list_split(&source, &source, &target); + assert(!c_list_is_empty(&source)); + assert(c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } + + /* split 2-element list including one element */ + { + CList source = C_LIST_INIT(source), target; + + c_list_link_tail(&source, &e1); + c_list_link_tail(&source, &e2); + c_list_split(&source, &e2, &target); + assert(!c_list_is_empty(&source)); + assert(!c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } + + /* split 2-element list including both elements */ + { + CList source = C_LIST_INIT(source), target; + + c_list_link_tail(&source, &e1); + c_list_link_tail(&source, &e2); + c_list_split(&source, &e1, &target); + assert(c_list_is_empty(&source)); + assert(!c_list_is_empty(&target)); + assert_list_integrity(&source); + assert_list_integrity(&target); + } +} + + static void test_flush(void) { CList e1 = C_LIST_INIT(e1), e2 = C_LIST_INIT(e2); CList list1 = C_LIST_INIT(list1), list2 = C_LIST_INIT(list2); @@ -220,6 +311,7 @@ int main(void) { test_iterators(); test_swap(); test_splice(); + test_split(); test_flush(); test_macros(); test_gnu(); diff --git a/src/c-rbtree/.github/workflows/ci.yml b/src/c-rbtree/.github/workflows/ci.yml index c270c52ca7..6350d3c746 100644 --- a/src/c-rbtree/.github/workflows/ci.yml +++ b/src/c-rbtree/.github/workflows/ci.yml @@ -9,25 +9,15 @@ on: jobs: ci: name: CI with Default Configuration - runs-on: ubuntu-latest - - steps: - - name: Fetch Sources - uses: actions/checkout@v2 - - name: Run through C-Util CI - uses: c-util/automation/src/ci-c-util@v1 - with: - m32: 1 - valgrind: 1 - + uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1 + with: + cabuild_ref: "v1" + m32: true + matrixmode: true + valgrind: true ci-ptrace: name: Reduced CI with PTrace - runs-on: ubuntu-latest - env: - CRBTREE_TEST_PTRACE: '1' - - steps: - - name: Fetch Sources - uses: actions/checkout@v2 - - name: Run through C-Util CI - uses: c-util/automation/src/ci-c-util@v1 + uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1 + with: + cabuild_ref: "v1" + mesonargs: '-Dptrace=true' diff --git a/src/c-rbtree/.gitmodules b/src/c-rbtree/.gitmodules index a86b29fd1c..e69de29bb2 100644 --- a/src/c-rbtree/.gitmodules +++ b/src/c-rbtree/.gitmodules @@ -1,3 +0,0 @@ -[submodule "subprojects/c-stdaux"] - path = subprojects/c-stdaux - url = https://github.com/c-util/c-stdaux.git diff --git a/src/c-rbtree/AUTHORS b/src/c-rbtree/AUTHORS index ed4e72e915..cd557de26c 100644 --- a/src/c-rbtree/AUTHORS +++ b/src/c-rbtree/AUTHORS @@ -30,7 +30,7 @@ AUTHORS-LGPL: along with this program; If not, see <http://www.gnu.org/licenses/>. COPYRIGHT: (ordered alphabetically) - Copyright (C) 2015-2019 Red Hat, Inc. + Copyright (C) 2015-2022 Red Hat, Inc. AUTHORS: (ordered alphabetically) David Rheinsberg <david.rheinsberg@gmail.com> diff --git a/src/c-rbtree/NEWS.md b/src/c-rbtree/NEWS.md index d76a412908..3fe061d977 100644 --- a/src/c-rbtree/NEWS.md +++ b/src/c-rbtree/NEWS.md @@ -1,5 +1,20 @@ # c-rbtree - Intrusive Red-Black Tree Collection +## CHANGES WITH 4: + + * Add 'ptrace' build option to enable running tests using 'ptrace' + to verify extended execution properties. This option should not + be used in setups where 'ptrace' cannot be employed (like running + under gdb or valgrind). This option only affects the test-suite. + + * meson-0.60.0 is now the minimum required meson version. + + * TBD + + Contributions from: David Rheinsberg + + - TBD, YYYY-MM-DD + ## CHANGES WITH 3: * Add more helpers. Add both a collection of iteratiors and helpers diff --git a/src/c-rbtree/README.md b/src/c-rbtree/README.md index c725bbb8f4..e3183ac8aa 100644 --- a/src/c-rbtree/README.md +++ b/src/c-rbtree/README.md @@ -22,7 +22,7 @@ The requirements for this project are: At build-time, the following software is required: - * `meson >= 0.41` + * `meson >= 0.60` * `pkg-config >= 0.29` ### Build diff --git a/src/c-rbtree/meson.build b/src/c-rbtree/meson.build index c131946762..f3ae209dbb 100644 --- a/src/c-rbtree/meson.build +++ b/src/c-rbtree/meson.build @@ -1,19 +1,22 @@ project( 'c-rbtree', 'c', - version: '3', - license: 'Apache', default_options: [ 'c_std=c11' ], + license: 'Apache', + meson_version: '>=0.60.0', + version: '3.0.0', ) +major = meson.project_version().split('.')[0] project_description = 'Intrusive Red-Black Tree Collection' -add_project_arguments('-D_GNU_SOURCE', language: 'c') mod_pkgconfig = import('pkgconfig') +use_ptrace = get_option('ptrace') -sub_cstdaux = subproject('c-stdaux') - -dep_cstdaux = sub_cstdaux.get_variable('libcstdaux_dep') +dep_cstdaux = dependency('libcstdaux-1') +add_project_arguments(dep_cstdaux.get_variable('cflags').split(' '), language: 'c') subdir('src') + +meson.override_dependency('libcrbtree-'+major, libcrbtree_dep, static: true) diff --git a/src/c-rbtree/meson_options.txt b/src/c-rbtree/meson_options.txt new file mode 100644 index 0000000000..ec35818053 --- /dev/null +++ b/src/c-rbtree/meson_options.txt @@ -0,0 +1 @@ +option('ptrace', type: 'boolean', value: false, description: 'Allow ptrace in test suite') diff --git a/src/c-rbtree/src/c-rbtree.h b/src/c-rbtree/src/c-rbtree.h index d4d0fe45c0..5c6fd0a559 100644 --- a/src/c-rbtree/src/c-rbtree.h +++ b/src/c-rbtree/src/c-rbtree.h @@ -144,6 +144,11 @@ static inline void c_rbnode_init(CRBNode *n) { * * Return: Pointer to parent container, or NULL. */ +/* + * Note: This was carefully designed to avoid multiple evaluation of `_what`, + * but avoid context-expression-extensions. That is why it uses the + * possibly odd style of `(x ?: offsetof(...)) - offsetof(...))`. + */ #define c_rbnode_entry(_what, _t, _m) \ ((_t *)(void *)(((unsigned long)(void *)(_what) ?: \ offsetof(_t, _m)) - offsetof(_t, _m))) diff --git a/src/c-rbtree/src/meson.build b/src/c-rbtree/src/meson.build index d0b4d63ce9..c5cce8102c 100644 --- a/src/c-rbtree/src/meson.build +++ b/src/c-rbtree/src/meson.build @@ -8,8 +8,8 @@ libcrbtree_deps = [ dep_cstdaux, ] -libcrbtree_private = static_library( - 'crbtree-private', +libcrbtree_both = both_libraries( + 'crbtree-'+major, [ 'c-rbtree.c', ], @@ -18,26 +18,19 @@ libcrbtree_private = static_library( '-fno-common', ], dependencies: libcrbtree_deps, - pic: true, -) - -libcrbtree_shared = shared_library( - 'crbtree', - objects: libcrbtree_private.extract_all_objects(), - dependencies: libcrbtree_deps, install: not meson.is_subproject(), - soversion: 0, - link_depends: libcrbtree_symfile, link_args: [ '-Wl,--no-undefined', '-Wl,--version-script=@0@'.format(libcrbtree_symfile), ], + link_depends: libcrbtree_symfile, + soversion: 0, ) libcrbtree_dep = declare_dependency( - include_directories: include_directories('.'), - link_with: libcrbtree_private, dependencies: libcrbtree_deps, + include_directories: include_directories('.'), + link_with: libcrbtree_both.get_static_lib(), version: meson.project_version(), ) @@ -45,11 +38,11 @@ if not meson.is_subproject() install_headers('c-rbtree.h') mod_pkgconfig.generate( - libraries: libcrbtree_shared, - version: meson.project_version(), - name: 'libcrbtree', - filebase: 'libcrbtree', description: project_description, + filebase: 'libcrbtree-'+major, + libraries: libcrbtree_both.get_shared_lib(), + name: 'libcrbtree', + version: meson.project_version(), ) endif @@ -57,7 +50,7 @@ endif # target: test-* # -test_api = executable('test-api', ['test-api.c'], link_with: libcrbtree_shared) +test_api = executable('test-api', ['test-api.c'], link_with: libcrbtree_both.get_shared_lib()) test('API Symbol Visibility', test_api) test_basic = executable('test-basic', ['test-basic.c'], dependencies: libcrbtree_dep) @@ -70,7 +63,9 @@ test_misc = executable('test-misc', ['test-misc.c'], dependencies: libcrbtree_de test('Miscellaneous', test_misc) test_parallel = executable('test-parallel', ['test-parallel.c'], dependencies: libcrbtree_dep) -test('Lockless Parallel Readers', test_parallel) +if use_ptrace + test('Lockless Parallel Readers', test_parallel) +endif test_posix = executable('test-posix', ['test-posix.c'], dependencies: libcrbtree_dep) test('Posix tsearch(3p) Comparison', test_posix) diff --git a/src/c-rbtree/src/test-parallel.c b/src/c-rbtree/src/test-parallel.c index 1388722bf3..4baf8e702d 100644 --- a/src/c-rbtree/src/test-parallel.c +++ b/src/c-rbtree/src/test-parallel.c @@ -364,9 +364,6 @@ int main(int argc, char **argv) { unsigned int i; int r; - if (!getenv("CRBTREE_TEST_PTRACE")) - return 77; - /* we want stable tests, so use fixed seed */ srand(0xdeadbeef); diff --git a/src/c-rbtree/subprojects/c-stdaux b/src/c-rbtree/subprojects/c-stdaux deleted file mode 160000 -Subproject c5f166d02ff68af5cdcbad1bdcea2cb134e34ce diff --git a/src/c-rbtree/subprojects/libcstdaux-1.wrap b/src/c-rbtree/subprojects/libcstdaux-1.wrap new file mode 100644 index 0000000000..036020aafe --- /dev/null +++ b/src/c-rbtree/subprojects/libcstdaux-1.wrap @@ -0,0 +1,3 @@ +[wrap-git] +url = https://github.com/c-util/c-stdaux.git +revision = v1 diff --git a/src/c-siphash/.github/workflows/ci.yml b/src/c-siphash/.github/workflows/ci.yml index b40abf690f..d54b120011 100644 --- a/src/c-siphash/.github/workflows/ci.yml +++ b/src/c-siphash/.github/workflows/ci.yml @@ -9,13 +9,9 @@ on: jobs: ci: name: CI with Default Configuration - runs-on: ubuntu-latest - - steps: - - name: Fetch Sources - uses: actions/checkout@v2 - - name: Run through C-Util CI - uses: c-util/automation/src/ci-c-util@v1 - with: - m32: 1 - valgrind: 1 + uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1 + with: + cabuild_ref: "v1" + m32: true + matrixmode: true + valgrind: true diff --git a/src/c-siphash/.gitmodules b/src/c-siphash/.gitmodules index a86b29fd1c..e69de29bb2 100644 --- a/src/c-siphash/.gitmodules +++ b/src/c-siphash/.gitmodules @@ -1,3 +0,0 @@ -[submodule "subprojects/c-stdaux"] - path = subprojects/c-stdaux - url = https://github.com/c-util/c-stdaux.git diff --git a/src/c-siphash/AUTHORS b/src/c-siphash/AUTHORS index b59660c5ee..3c6436a932 100644 --- a/src/c-siphash/AUTHORS +++ b/src/c-siphash/AUTHORS @@ -30,7 +30,7 @@ AUTHORS-LGPL: along with this program; If not, see <http://www.gnu.org/licenses/>. COPYRIGHT: (ordered alphabetically) - Copyright (C) 2015-2019 Red Hat, Inc. + Copyright (C) 2015-2022 Red Hat, Inc. AUTHORS: (ordered alphabetically) David Rheinsberg <david.rheinsberg@gmail.com> diff --git a/src/c-siphash/README.md b/src/c-siphash/README.md index ba09041be4..bd97d06b61 100644 --- a/src/c-siphash/README.md +++ b/src/c-siphash/README.md @@ -21,7 +21,7 @@ The requirements for this project are: At build-time, the following software is required: - * `meson >= 0.41` + * `meson >= 0.60` * `pkg-config >= 0.29` ### Build diff --git a/src/c-siphash/meson.build b/src/c-siphash/meson.build index 2b07b019b3..ffcb6a76ae 100644 --- a/src/c-siphash/meson.build +++ b/src/c-siphash/meson.build @@ -1,19 +1,21 @@ project( 'c-siphash', 'c', - version: '1', - license: 'Apache', default_options: [ 'c_std=c11' ], + license: 'Apache', + meson_version: '>=0.60.0', + version: '1.0.0', ) +major = meson.project_version().split('.')[0] project_description = 'Streaming-capable SipHash Implementation' -add_project_arguments('-D_GNU_SOURCE', language: 'c') mod_pkgconfig = import('pkgconfig') -sub_cstdaux = subproject('c-stdaux') - -dep_cstdaux = sub_cstdaux.get_variable('libcstdaux_dep') +dep_cstdaux = dependency('libcstdaux-1') +add_project_arguments(dep_cstdaux.get_variable('cflags').split(' '), language: 'c') subdir('src') + +meson.override_dependency('libcsiphash-'+major, libcsiphash_dep, static: true) diff --git a/src/c-siphash/src/meson.build b/src/c-siphash/src/meson.build index 7ee9c601e7..55c2e4f150 100644 --- a/src/c-siphash/src/meson.build +++ b/src/c-siphash/src/meson.build @@ -8,8 +8,8 @@ libcsiphash_deps = [ dep_cstdaux, ] -libcsiphash_private = static_library( - 'csiphash-private', +libcsiphash_both = both_libraries( + 'csiphash-'+major, [ 'c-siphash.c', ], @@ -18,26 +18,19 @@ libcsiphash_private = static_library( '-fno-common', ], dependencies: libcsiphash_deps, - pic: true, -) - -libcsiphash_shared = shared_library( - 'csiphash', - objects: libcsiphash_private.extract_all_objects(), - dependencies: libcsiphash_deps, install: not meson.is_subproject(), - soversion: 0, - link_depends: libcsiphash_symfile, link_args: [ '-Wl,--no-undefined', '-Wl,--version-script=@0@'.format(libcsiphash_symfile), ], + link_depends: libcsiphash_symfile, + soversion: 0, ) libcsiphash_dep = declare_dependency( - include_directories: include_directories('.'), - link_with: libcsiphash_private, dependencies: libcsiphash_deps, + include_directories: include_directories('.'), + link_with: libcsiphash_both.get_static_lib(), version: meson.project_version(), ) @@ -45,11 +38,11 @@ if not meson.is_subproject() install_headers('c-siphash.h') mod_pkgconfig.generate( - libraries: libcsiphash_shared, - version: meson.project_version(), - name: 'libcsiphash', - filebase: 'libcsiphash', description: project_description, + filebase: 'libcsiphash-'+major, + libraries: libcsiphash_both.get_shared_lib(), + name: 'libcsiphash', + version: meson.project_version(), ) endif @@ -57,7 +50,7 @@ endif # target: test-* # -test_api = executable('test-api', ['test-api.c'], link_with: libcsiphash_shared) +test_api = executable('test-api', ['test-api.c'], link_with: libcsiphash_both.get_shared_lib()) test('API Symbol Visibility', test_api) test_basic = executable('test-basic', ['test-basic.c'], dependencies: libcsiphash_dep) diff --git a/src/c-siphash/subprojects/c-stdaux b/src/c-siphash/subprojects/c-stdaux deleted file mode 160000 -Subproject c5f166d02ff68af5cdcbad1bdcea2cb134e34ce diff --git a/src/c-siphash/subprojects/libcstdaux-1.wrap b/src/c-siphash/subprojects/libcstdaux-1.wrap new file mode 100644 index 0000000000..036020aafe --- /dev/null +++ b/src/c-siphash/subprojects/libcstdaux-1.wrap @@ -0,0 +1,3 @@ +[wrap-git] +url = https://github.com/c-util/c-stdaux.git +revision = v1 diff --git a/src/c-stdaux/.github/workflows/ci.yml b/src/c-stdaux/.github/workflows/ci.yml index b40abf690f..d54b120011 100644 --- a/src/c-stdaux/.github/workflows/ci.yml +++ b/src/c-stdaux/.github/workflows/ci.yml @@ -9,13 +9,9 @@ on: jobs: ci: name: CI with Default Configuration - runs-on: ubuntu-latest - - steps: - - name: Fetch Sources - uses: actions/checkout@v2 - - name: Run through C-Util CI - uses: c-util/automation/src/ci-c-util@v1 - with: - m32: 1 - valgrind: 1 + uses: bus1/cabuild/.github/workflows/ci-c-util.yml@v1 + with: + cabuild_ref: "v1" + m32: true + matrixmode: true + valgrind: true diff --git a/src/c-stdaux/AUTHORS b/src/c-stdaux/AUTHORS index 6015c4f31c..555ecb5581 100644 --- a/src/c-stdaux/AUTHORS +++ b/src/c-stdaux/AUTHORS @@ -30,7 +30,7 @@ AUTHORS-LGPL: along with this program; If not, see <http://www.gnu.org/licenses/>. COPYRIGHT: (ordered alphabetically) - Copyright (C) 2018-2019 Red Hat, Inc. + Copyright (C) 2018-2022 Red Hat, Inc. AUTHORS: (ordered alphabetically) David Rheinsberg <david.rheinsberg@gmail.com> diff --git a/src/c-stdaux/README.md b/src/c-stdaux/README.md index 51bff9778f..124c692e12 100644 --- a/src/c-stdaux/README.md +++ b/src/c-stdaux/README.md @@ -21,7 +21,7 @@ The requirements for this project are: At build-time, the following software is required: - * `meson >= 0.41` + * `meson >= 0.60` * `pkg-config >= 0.29` ### Build diff --git a/src/c-stdaux/meson.build b/src/c-stdaux/meson.build index c8c5da536f..3054e25073 100644 --- a/src/c-stdaux/meson.build +++ b/src/c-stdaux/meson.build @@ -1,15 +1,86 @@ project( 'c-stdaux', 'c', - version: '1', - license: 'Apache', default_options: [ 'c_std=c11' ], + license: 'Apache', + meson_version: '>=0.60.0', + version: '1.0.0', ) +major = meson.project_version().split('.')[0] project_description = 'Auxiliary macros and functions for the C standard library' -add_project_arguments('-D_GNU_SOURCE', language: 'c') mod_pkgconfig = import('pkgconfig') +# +# CFLAGS +# +# We have a set of compiler flags for GCC and CLANG which adjust their warnings +# and behavior to our coding-style. +# +# This variable is exported to dependent projects via meson for them to use as +# well. Since these exports are limited to strings, we need to be careful that +# the individual entries do not contain spaces (see the assertion below). +# +cflags = meson.get_compiler('c').get_supported_arguments( + # Enable GNU features of our dependencies. See feature_test_macros(7). + '-D_GNU_SOURCE', + + # Prevent CLANG from complaining that alignof-expressions are GNU-only. + '-Wno-gnu-alignof-expression', + # Never complain about *MAYBE* uninit variables. This is very flaky and + # produces bogus results with LTO. + '-Wno-maybe-uninitialized', + # Do not complain about unknown GCC/CLANG warnings. + '-Wno-unknown-warning-option', + # There is no standardized way to mark unused arguments, so never + # complain about them. + '-Wno-unused-parameter', + + # Preprocessor evaluations often lead to warnings about comparisons + # that are always true/false. Make sure they do not break a build but + # keep them on for diagnostics. + '-Wno-error=type-limits', + # As we use designated field-initializers, this warning should never + # trigger, but still does on GCC in combination with some other + # preprocessor checks. Lets just make sure it does not break builds. + '-Wno-error=missing-field-initializers', + + # Warn if we ever use `__DATE__` and similar in our build. We want + # reproducible builds. + '-Wdate-time', + # We strictly follow decl-before-statements, so check it. + '-Wdeclaration-after-statement', + # More strict logical-op sanity checks. + '-Wlogical-op', + # Loudly complain about missing include-directories. + '-Wmissing-include-dirs', + # We want hints about noreturn functions, so warn about them. + '-Wmissing-noreturn', + # Warn if an extern-decl is inside a function. We want imports as + # global attributes, never as local ones. + '-Wnested-externs', + # Warn about redundant declarations. We want declarations in headers + # and want them to be unique. + '-Wredundant-decls', + # Warn about shadowed variables so we do not accidentally override + # variables of parent scopes and thus confuse macros. + '-Wshadow', + # Warn about aliasing violations. Level-3 produces the least false + # positives, but is the slowest. Force it to avoid breaking -Werror + # builds. + '-Wstrict-aliasing=3', + # Suggest 'noreturn' attributes. They are useful, we want them! + '-Wsuggest-attribute=noreturn', + # Warn about undefined identifiers in preprocessor conditionals. + '-Wundef', + # Make sure literal strings are considered 'const'. + '-Wwrite-strings', +) +assert(not ''.join(cflags).contains(' '), 'Malformed compiler flags.') +add_project_arguments(cflags, language: 'c') + subdir('src') + +meson.override_dependency('libcstdaux-'+major, libcstdaux_dep, static: true) diff --git a/src/c-stdaux/src/meson.build b/src/c-stdaux/src/meson.build index f6db824d24..a9322d4daa 100644 --- a/src/c-stdaux/src/meson.build +++ b/src/c-stdaux/src/meson.build @@ -6,6 +6,7 @@ libcstdaux_dep = declare_dependency( include_directories: include_directories('.'), + variables: { 'cflags': ' '.join(cflags) }, version: meson.project_version(), ) @@ -13,10 +14,10 @@ if not meson.is_subproject() install_headers('c-stdaux.h') mod_pkgconfig.generate( - version: meson.project_version(), - name: 'libcstdaux', - filebase: 'libcstdaux', description: project_description, + filebase: 'libcstdaux-'+major, + name: 'libcstdaux', + version: meson.project_version(), ) endif diff --git a/src/c-stdaux/src/test-basic.c b/src/c-stdaux/src/test-basic.c index d58d561d23..15499353cb 100644 --- a/src/c-stdaux/src/test-basic.c +++ b/src/c-stdaux/src/test-basic.c @@ -359,7 +359,7 @@ static void test_destructors(void) { /* make sure c_closep() deals fine with negative FDs */ { - _c_cleanup_(c_closep) int t = 0; + _c_cleanup_(c_closep) _c_unused_ int t = 0; t = -1; } @@ -370,7 +370,7 @@ static void test_destructors(void) { * path works as well. */ for (i = 0; i < 2; ++i) { - _c_cleanup_(c_closep) int t = -1; + _c_cleanup_(c_closep) _c_unused_ int t = -1; t = eventfd(0, EFD_CLOEXEC); c_assert(t >= 0); @@ -401,7 +401,7 @@ static void test_destructors(void) { /* make sure c_flosep() deals fine with NULL */ { - _c_cleanup_(c_fclosep) FILE *t = (void *)0xdeadbeef; + _c_cleanup_(c_fclosep) _c_unused_ FILE *t = (void *)0xdeadbeef; t = NULL; } @@ -412,7 +412,7 @@ static void test_destructors(void) { * path works as well. */ for (i = 0; i < 2; ++i) { - _c_cleanup_(c_fclosep) FILE *t = NULL; + _c_cleanup_(c_fclosep) _c_unused_ FILE *t = NULL; int tfd; tfd = eventfd(0, EFD_CLOEXEC); diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c index 5727aac814..56f551060c 100644 --- a/src/core/NetworkManagerUtils.c +++ b/src/core/NetworkManagerUtils.c @@ -30,7 +30,6 @@ #include "libnm-platform/nm-linux-platform.h" #include "libnm-platform/nm-platform-utils.h" #include "nm-auth-utils.h" -#include "libnm-systemd-shared/nm-sd-utils-shared.h" /*****************************************************************************/ @@ -1155,7 +1154,7 @@ nm_utils_file_is_in_path(const char *abs_filename, const char *abs_path) g_return_val_if_fail(abs_filename && abs_filename[0] == '/', NULL); g_return_val_if_fail(abs_path && abs_path[0] == '/', NULL); - path = nm_sd_utils_path_startswith(abs_filename, abs_path); + path = nm_path_startswith(abs_filename, abs_path); if (!path) return NULL; diff --git a/src/core/devices/nm-device-bond.c b/src/core/devices/nm-device-bond.c index 16896d5753..21fe9b07eb 100644 --- a/src/core/devices/nm-device-bond.c +++ b/src/core/devices/nm-device-bond.c @@ -312,7 +312,7 @@ set_bond_attr_or_default(NMDevice *device, NMSettingBond *s_bond, const char *op NMDeviceBond *self = NM_DEVICE_BOND(device); const char *value; - value = nm_setting_bond_get_option_or_default(s_bond, opt); + value = nm_setting_bond_get_option_normalized(s_bond, opt); if (!value) { if (_LOGT_ENABLED(LOGD_BOND) && nm_setting_bond_get_option_by_name(s_bond, opt)) _LOGT(LOGD_BOND, "bond option '%s' not set as it conflicts with other options", opt); @@ -346,7 +346,7 @@ set_bond_arp_ip_targets(NMDevice *device, NMSettingBond *s_bond) set_arp_targets( device, cur_arp_ip_target, - nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)); + nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET)); } static gboolean @@ -361,7 +361,7 @@ apply_bonding_config(NMDeviceBond *self) s_bond = nm_device_get_applied_setting(device, NM_TYPE_SETTING_BOND); g_return_val_if_fail(s_bond, FALSE); - mode_str = nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_MODE); + mode_str = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE); mode = _nm_setting_bond_mode_from_string(mode_str); g_return_val_if_fail(mode != NM_BOND_MODE_UNKNOWN, FALSE); @@ -424,8 +424,14 @@ commit_port_options(NMDevice *bond_device, NMDevice *port, NMSettingBondPort *s_ queue_id_str); } -static gboolean -enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboolean configure) +static NMTernary +attach_port(NMDevice *device, + NMDevice *port, + NMConnection *connection, + gboolean configure, + GCancellable *cancellable, + NMDeviceAttachPortCallback callback, + gpointer user_data) { NMDeviceBond *self = NM_DEVICE_BOND(device); NMSettingBondPort *s_port; @@ -442,7 +448,7 @@ enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboole nm_device_bring_up(port, TRUE, NULL); if (!success) { - _LOGI(LOGD_BOND, "assigning bond port %s: failed", nm_device_get_ip_iface(port)); + _LOGI(LOGD_BOND, "attaching bond port %s: failed", nm_device_get_ip_iface(port)); return FALSE; } @@ -450,15 +456,15 @@ enslave_slave(NMDevice *device, NMDevice *port, NMConnection *connection, gboole commit_port_options(device, port, s_port); - _LOGI(LOGD_BOND, "assigned bond port %s", nm_device_get_ip_iface(port)); + _LOGI(LOGD_BOND, "attached bond port %s", nm_device_get_ip_iface(port)); } else - _LOGI(LOGD_BOND, "bond port %s was assigned", nm_device_get_ip_iface(port)); + _LOGI(LOGD_BOND, "bond port %s was attached", nm_device_get_ip_iface(port)); return TRUE; } static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) +detach_port(NMDevice *device, NMDevice *port, gboolean configure) { NMDeviceBond *self = NM_DEVICE_BOND(device); gboolean success; @@ -472,10 +478,10 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) configure = FALSE; } - ifindex_slave = nm_device_get_ip_ifindex(slave); + ifindex_slave = nm_device_get_ip_ifindex(port); if (ifindex_slave <= 0) - _LOGD(LOGD_BOND, "bond slave %s is already released", nm_device_get_ip_iface(slave)); + _LOGD(LOGD_BOND, "bond port %s is already detached", nm_device_get_ip_iface(port)); if (configure) { NMConnection *applied; @@ -490,9 +496,9 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) ifindex_slave); if (success) { - _LOGI(LOGD_BOND, "released bond slave %s", nm_device_get_ip_iface(slave)); + _LOGI(LOGD_BOND, "detached bond port %s", nm_device_get_ip_iface(port)); } else { - _LOGW(LOGD_BOND, "failed to release bond slave %s", nm_device_get_ip_iface(slave)); + _LOGW(LOGD_BOND, "failed to detach bond port %s", nm_device_get_ip_iface(port)); } } @@ -512,12 +518,12 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) * other state is noticed by the now-released slave. */ if (ifindex_slave > 0) { - if (!nm_device_bring_up(slave, TRUE, NULL)) - _LOGW(LOGD_BOND, "released bond slave could not be brought up."); + if (!nm_device_bring_up(port, TRUE, NULL)) + _LOGW(LOGD_BOND, "detached bond port could not be brought up."); } } else { if (ifindex_slave > 0) { - _LOGI(LOGD_BOND, "bond slave %s was released", nm_device_get_ip_iface(slave)); + _LOGI(LOGD_BOND, "bond port %s was detached", nm_device_get_ip_iface(port)); } } } @@ -612,7 +618,7 @@ reapply_connection(NMDevice *device, NMConnection *con_old, NMConnection *con_ne s_bond = nm_connection_get_setting_bond(con_new); g_return_if_fail(s_bond); - value = nm_setting_bond_get_option_or_default(s_bond, NM_SETTING_BOND_OPTION_MODE); + value = nm_setting_bond_get_option_normalized(s_bond, NM_SETTING_BOND_OPTION_MODE); mode = _nm_setting_bond_mode_from_string(value); g_return_if_fail(mode != NM_BOND_MODE_UNKNOWN); @@ -663,8 +669,8 @@ nm_device_bond_class_init(NMDeviceBondClass *klass) device_class->create_and_realize = create_and_realize; device_class->act_stage1_prepare = act_stage1_prepare; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; + device_class->attach_port = attach_port; + device_class->detach_port = detach_port; device_class->can_reapply_change = can_reapply_change; device_class->reapply_connection = reapply_connection; } diff --git a/src/core/devices/nm-device-bridge.c b/src/core/devices/nm-device-bridge.c index f11c172abb..dcdd160195 100644 --- a/src/core/devices/nm-device-bridge.c +++ b/src/core/devices/nm-device-bridge.c @@ -974,8 +974,14 @@ deactivate(NMDevice *device) } } -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) +static NMTernary +attach_port(NMDevice *device, + NMDevice *port, + NMConnection *connection, + gboolean configure, + GCancellable *cancellable, + NMDeviceAttachPortCallback callback, + gpointer user_data) { NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); NMConnection *master_connection; @@ -985,7 +991,7 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool if (configure) { if (!nm_platform_link_enslave(nm_device_get_platform(device), nm_device_get_ip_ifindex(device), - nm_device_get_ip_ifindex(slave))) + nm_device_get_ip_ifindex(port))) return FALSE; master_connection = nm_device_get_applied_connection(device); @@ -1009,25 +1015,25 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool * (except for the default one) and so there's no need to flush. */ if (plat_vlans - && !nm_platform_link_set_bridge_vlans(nm_device_get_platform(slave), - nm_device_get_ifindex(slave), + && !nm_platform_link_set_bridge_vlans(nm_device_get_platform(port), + nm_device_get_ifindex(port), TRUE, plat_vlans)) return FALSE; } - commit_slave_options(slave, s_port); + commit_slave_options(port, s_port); - _LOGI(LOGD_BRIDGE, "attached bridge port %s", nm_device_get_ip_iface(slave)); + _LOGI(LOGD_BRIDGE, "attached bridge port %s", nm_device_get_ip_iface(port)); } else { - _LOGI(LOGD_BRIDGE, "bridge port %s was attached", nm_device_get_ip_iface(slave)); + _LOGI(LOGD_BRIDGE, "bridge port %s was attached", nm_device_get_ip_iface(port)); } return TRUE; } static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) +detach_port(NMDevice *device, NMDevice *port, gboolean configure) { NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); gboolean success; @@ -1040,10 +1046,10 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) configure = FALSE; } - ifindex_slave = nm_device_get_ip_ifindex(slave); + ifindex_slave = nm_device_get_ip_ifindex(port); if (ifindex_slave <= 0) { - _LOGD(LOGD_TEAM, "bond slave %s is already released", nm_device_get_ip_iface(slave)); + _LOGD(LOGD_TEAM, "bridge port %s is already detached", nm_device_get_ip_iface(port)); return; } @@ -1053,12 +1059,12 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) ifindex_slave); if (success) { - _LOGI(LOGD_BRIDGE, "detached bridge port %s", nm_device_get_ip_iface(slave)); + _LOGI(LOGD_BRIDGE, "detached bridge port %s", nm_device_get_ip_iface(port)); } else { - _LOGW(LOGD_BRIDGE, "failed to detach bridge port %s", nm_device_get_ip_iface(slave)); + _LOGW(LOGD_BRIDGE, "failed to detach bridge port %s", nm_device_get_ip_iface(port)); } } else { - _LOGI(LOGD_BRIDGE, "bridge port %s was detached", nm_device_get_ip_iface(slave)); + _LOGI(LOGD_BRIDGE, "bridge port %s was detached", nm_device_get_ip_iface(port)); } } @@ -1084,10 +1090,6 @@ create_and_realize(NMDevice *device, s_bridge = nm_connection_get_setting_bridge(connection); nm_assert(s_bridge); - s_wired = nm_connection_get_setting_wired(connection); - if (s_wired) - mtu = nm_setting_wired_get_mtu(s_wired); - hwaddr = nm_setting_bridge_get_mac_address(s_bridge); if (!hwaddr && nm_device_hw_addr_get_cloned(device, connection, FALSE, &hwaddr_cloned, NULL, NULL)) { @@ -1112,6 +1114,11 @@ create_and_realize(NMDevice *device, _platform_lnk_bridge_init_from_setting(s_bridge, &props); + s_wired = nm_connection_get_setting_wired(connection); + nm_assert(s_wired); + + mtu = nm_setting_wired_get_mtu(s_wired); + /* If mtu != 0, we set the MTU of the new bridge at creation time. However, kernel will still * automatically adjust the MTU of the bridge based on the minimum of the slave's MTU. * We don't want this automatism as the user asked for a fixed MTU. @@ -1182,8 +1189,8 @@ nm_device_bridge_class_init(NMDeviceBridgeClass *klass) device_class->act_stage1_prepare = act_stage1_prepare; device_class->act_stage2_config = act_stage2_config; device_class->deactivate = deactivate; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; + device_class->attach_port = attach_port; + device_class->detach_port = detach_port; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; } diff --git a/src/core/devices/nm-device-vrf.c b/src/core/devices/nm-device-vrf.c index ae80e1d462..2aef0e3d1e 100644 --- a/src/core/devices/nm-device-vrf.c +++ b/src/core/devices/nm-device-vrf.c @@ -206,38 +206,44 @@ update_connection(NMDevice *device, NMConnection *connection) g_object_set(G_OBJECT(s_vrf), NM_SETTING_VRF_TABLE, priv->props.table, NULL); } -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) +static NMTernary +attach_port(NMDevice *device, + NMDevice *port, + NMConnection *connection, + gboolean configure, + GCancellable *cancellable, + NMDeviceAttachPortCallback callback, + gpointer user_data) { - NMDeviceVrf *self = NM_DEVICE_VRF(device); - gboolean success = TRUE; - const char *slave_iface = nm_device_get_ip_iface(slave); + NMDeviceVrf *self = NM_DEVICE_VRF(device); + gboolean success = TRUE; + const char *port_iface = nm_device_get_ip_iface(port); - nm_device_master_check_slave_physical_port(device, slave, LOGD_DEVICE); + nm_device_master_check_slave_physical_port(device, port, LOGD_DEVICE); if (configure) { - nm_device_take_down(slave, TRUE); + nm_device_take_down(port, TRUE); success = nm_platform_link_enslave(nm_device_get_platform(device), nm_device_get_ip_ifindex(device), - nm_device_get_ip_ifindex(slave)); - nm_device_bring_up(slave, TRUE, NULL); + nm_device_get_ip_ifindex(port)); + nm_device_bring_up(port, TRUE, NULL); if (!success) return FALSE; - _LOGI(LOGD_DEVICE, "enslaved VRF slave %s", slave_iface); + _LOGI(LOGD_DEVICE, "attached VRF port %s", port_iface); } else - _LOGI(LOGD_BOND, "VRF slave %s was enslaved", slave_iface); + _LOGI(LOGD_BOND, "VRF port %s was attached", port_iface); return TRUE; } static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) +detach_port(NMDevice *device, NMDevice *port, gboolean configure) { NMDeviceVrf *self = NM_DEVICE_VRF(device); gboolean success; - int ifindex_slave; + int ifindex_port; int ifindex; if (configure) { @@ -246,26 +252,26 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) configure = FALSE; } - ifindex_slave = nm_device_get_ip_ifindex(slave); + ifindex_port = nm_device_get_ip_ifindex(port); - if (ifindex_slave <= 0) - _LOGD(LOGD_DEVICE, "VRF slave %s is already released", nm_device_get_ip_iface(slave)); + if (ifindex_port <= 0) + _LOGD(LOGD_DEVICE, "VRF port %s is already detached", nm_device_get_ip_iface(port)); if (configure) { - if (ifindex_slave > 0) { + if (ifindex_port > 0) { success = nm_platform_link_release(nm_device_get_platform(device), nm_device_get_ip_ifindex(device), - ifindex_slave); + ifindex_port); if (success) { - _LOGI(LOGD_DEVICE, "released VRF slave %s", nm_device_get_ip_iface(slave)); + _LOGI(LOGD_DEVICE, "detached VRF port %s", nm_device_get_ip_iface(port)); } else { - _LOGW(LOGD_DEVICE, "failed to release VRF slave %s", nm_device_get_ip_iface(slave)); + _LOGW(LOGD_DEVICE, "failed to detach VRF port %s", nm_device_get_ip_iface(port)); } } } else { - if (ifindex_slave > 0) { - _LOGI(LOGD_DEVICE, "VRF slave %s was released", nm_device_get_ip_iface(slave)); + if (ifindex_port > 0) { + _LOGI(LOGD_DEVICE, "VRF port %s was detached", nm_device_get_ip_iface(port)); } } } @@ -316,8 +322,8 @@ nm_device_vrf_class_init(NMDeviceVrfClass *klass) device_class->is_master = TRUE; device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_VRF); - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; + device_class->attach_port = attach_port; + device_class->detach_port = detach_port; device_class->link_changed = link_changed; device_class->unrealize_notify = unrealize_notify; device_class->create_and_realize = create_and_realize; diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 70b52b1ac1..f4171630a2 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -120,11 +120,12 @@ typedef enum _nm_packed { } AddrMethodState; typedef struct { - CList lst_slave; - NMDevice *slave; - gulong watch_id; - bool slave_is_enslaved; - bool configure; + CList lst_slave; + NMDevice *slave; + GCancellable *cancellable; + gulong watch_id; + bool slave_is_enslaved; + bool configure; } SlaveInfo; typedef struct { @@ -604,6 +605,7 @@ typedef struct _NMDevicePrivate { const NMDeviceIPState state; NMDeviceIPState state_; }; + gulong dnsmgr_update_pending_signal_id; } ip_data; union { @@ -2930,6 +2932,13 @@ _add_capabilities(NMDevice *self, NMDeviceCapabilities capabilities) /*****************************************************************************/ static void +_dev_ip_state_dnsmgr_update_pending_changed(NMDnsManager *dnsmgr, GParamSpec *pspec, NMDevice *self) +{ + _dev_ip_state_check(self, AF_INET); + _dev_ip_state_check(self, AF_INET6); +} + +static void _dev_ip_state_req_timeout_cancel(NMDevice *self, int addr_family) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); @@ -3321,6 +3330,27 @@ got_ip_state: combinedip_state = priv->ip_data.state; } + if (combinedip_state == NM_DEVICE_IP_STATE_READY + && priv->ip_data.state <= NM_DEVICE_IP_STATE_PENDING + && nm_dns_manager_get_update_pending(nm_manager_get_dns_manager(priv->manager))) { + /* We would be ready, but a DNS update is pending. That prevents us from getting fully ready. */ + if (priv->ip_data.dnsmgr_update_pending_signal_id == 0) { + priv->ip_data.dnsmgr_update_pending_signal_id = + g_signal_connect(nm_manager_get_dns_manager(priv->manager), + "notify::" NM_DNS_MANAGER_UPDATE_PENDING, + G_CALLBACK(_dev_ip_state_dnsmgr_update_pending_changed), + self); + _LOGT_ip(AF_UNSPEC, + "check-state: (combined) state: wait for DNS before becoming ready"); + } + combinedip_state = NM_DEVICE_IP_STATE_PENDING; + } + if (combinedip_state != NM_DEVICE_IP_STATE_PENDING + && priv->ip_data.dnsmgr_update_pending_signal_id != 0) { + nm_clear_g_signal_handler(nm_manager_get_dns_manager(priv->manager), + &priv->ip_data.dnsmgr_update_pending_signal_id); + } + _LOGT_ip(AF_UNSPEC, "check-state: (combined) state %s => %s", nm_device_ip_state_to_string(priv->ip_data.state), @@ -5898,43 +5928,16 @@ find_slave_info(NMDevice *self, NMDevice *slave) return NULL; } -/** - * nm_device_master_enslave_slave: - * @self: the master device - * @slave: the slave device to enslave - * @connection: (allow-none): the slave device's connection - * - * If @self is capable of enslaving other devices (ie it's a bridge, bond, team, - * etc) then this function enslaves @slave. - * - * Returns: %TRUE on success, %FALSE on failure or if this device cannot enslave - * other devices. - */ -static gboolean -nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection) +static void +attach_port_done(NMDevice *self, NMDevice *slave, gboolean success) { SlaveInfo *info; - gboolean success = FALSE; - gboolean configure; - - g_return_val_if_fail(self != NULL, FALSE); - g_return_val_if_fail(slave != NULL, FALSE); - g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->enslave_slave != NULL, FALSE); info = find_slave_info(self, slave); if (!info) - return FALSE; - - if (info->slave_is_enslaved) - success = TRUE; - else { - configure = (info->configure && connection != NULL); - if (configure) - g_return_val_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED, FALSE); + return; - success = NM_DEVICE_GET_CLASS(self)->enslave_slave(self, slave, connection, configure); - info->slave_is_enslaved = success; - } + info->slave_is_enslaved = success; nm_device_slave_notify_enslave(info->slave, success); @@ -5954,8 +5957,71 @@ nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *co */ if (success) nm_device_activate_schedule_stage3_ip_config(self, FALSE); +} - return success; +static void +attach_port_cb(NMDevice *self, GError *error, gpointer user_data) +{ + NMDevice *slave = user_data; + SlaveInfo *info; + + if (nm_utils_error_is_cancelled(error)) + return; + + info = find_slave_info(self, slave); + if (!info) + return; + + nm_clear_g_cancellable(&info->cancellable); + attach_port_done(self, slave, !error); +} + +/** + * nm_device_master_enslave_slave: + * @self: the master device + * @slave: the slave device to enslave + * @connection: (allow-none): the slave device's connection + * + * If @self is capable of enslaving other devices (ie it's a bridge, bond, team, + * etc) then this function enslaves @slave. + */ +static void +nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *connection) +{ + SlaveInfo *info; + NMTernary success; + gboolean configure; + + g_return_if_fail(self); + g_return_if_fail(slave); + g_return_if_fail(NM_DEVICE_GET_CLASS(self)->attach_port); + + info = find_slave_info(self, slave); + if (!info) + return; + + if (info->slave_is_enslaved) + success = TRUE; + else { + configure = (info->configure && connection != NULL); + if (configure) + g_return_if_fail(nm_device_get_state(slave) >= NM_DEVICE_STATE_DISCONNECTED); + + nm_clear_g_cancellable(&info->cancellable); + info->cancellable = g_cancellable_new(); + success = NM_DEVICE_GET_CLASS(self)->attach_port(self, + slave, + connection, + configure, + info->cancellable, + attach_port_cb, + slave); + + if (success == NM_TERNARY_DEFAULT) + return; + } + + attach_port_done(self, slave, success); } /** @@ -5988,7 +6054,7 @@ nm_device_master_release_slave(NMDevice *self, RELEASE_SLAVE_TYPE_NO_CONFIG, RELEASE_SLAVE_TYPE_CONFIG, RELEASE_SLAVE_TYPE_CONFIG_FORCE)); - g_return_if_fail(NM_DEVICE_GET_CLASS(self)->release_slave != NULL); + g_return_if_fail(NM_DEVICE_GET_CLASS(self)->detach_port != NULL); info = find_slave_info(self, slave); @@ -6009,13 +6075,14 @@ nm_device_master_release_slave(NMDevice *self, g_return_if_fail(self == slave_priv->master); nm_assert(slave == info->slave); + nm_clear_g_cancellable(&info->cancellable); /* first, let subclasses handle the release ... */ if (info->slave_is_enslaved || nm_device_sys_iface_state_is_external(slave) || release_type >= RELEASE_SLAVE_TYPE_CONFIG_FORCE) - NM_DEVICE_GET_CLASS(self)->release_slave(self, - slave, - release_type >= RELEASE_SLAVE_TYPE_CONFIG); + NM_DEVICE_GET_CLASS(self)->detach_port(self, + slave, + release_type >= RELEASE_SLAVE_TYPE_CONFIG); /* raise notifications about the release, including clearing is_enslaved. */ nm_device_slave_notify_release(slave, reason); @@ -6356,7 +6423,7 @@ device_recheck_slave_status(NMDevice *self, const NMPlatformLink *plink) NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED); } - if (master && NM_DEVICE_GET_CLASS(master)->enslave_slave) { + if (master && NM_DEVICE_GET_CLASS(master)->attach_port) { nm_device_master_add_slave(master, self, FALSE); goto out; } @@ -7581,7 +7648,7 @@ nm_device_master_add_slave(NMDevice *self, NMDevice *slave, gboolean configure) g_return_val_if_fail(NM_IS_DEVICE(self), FALSE); g_return_val_if_fail(NM_IS_DEVICE(slave), FALSE); - g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->enslave_slave != NULL, FALSE); + g_return_val_if_fail(NM_DEVICE_GET_CLASS(self)->attach_port, FALSE); priv = NM_DEVICE_GET_PRIVATE(self); slave_priv = NM_DEVICE_GET_PRIVATE(slave); @@ -10036,6 +10103,7 @@ _dev_ipdhcpx_notify(NMDhcpClient *client, const NMDhcpClientNotifyData *notify_d FALSE); if (notify_data->lease_update.accepted) { + nm_manager_write_device_state(priv->manager, self, NULL); if (priv->ipdhcp_data_x[IS_IPv4].state != NM_DEVICE_IP_STATE_READY) { _dev_ipdhcpx_set_state(self, addr_family, NM_DEVICE_IP_STATE_READY); nm_dispatcher_call_device(NM_DISPATCHER_ACTION_DHCP_CHANGE_X(IS_IPv4), @@ -12342,7 +12410,8 @@ delete_on_deactivate_check_and_schedule(NMDevice *self) static void _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gboolean from_reapply) { - const int IS_IPv4 = NM_IS_IPv4(addr_family); + const int IS_IPv4 = NM_IS_IPv4(addr_family); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE(self); _dev_ipsharedx_cleanup(self, addr_family); @@ -12358,6 +12427,9 @@ _cleanup_ip_pre(NMDevice *self, int addr_family, CleanupType cleanup_type, gbool _dev_ipmanual_cleanup(self); + nm_clear_g_signal_handler(nm_manager_get_dns_manager(priv->manager), + &priv->ip_data.dnsmgr_update_pending_signal_id); + _dev_ip_state_cleanup(self, AF_UNSPEC, from_reapply); _dev_ip_state_cleanup(self, addr_family, from_reapply); } diff --git a/src/core/devices/nm-device.h b/src/core/devices/nm-device.h index 80def12511..377c2fb6b8 100644 --- a/src/core/devices/nm-device.h +++ b/src/core/devices/nm-device.h @@ -163,6 +163,7 @@ typedef enum { } NMDeviceCheckDevAvailableFlags; typedef void (*NMDeviceDeactivateCallback)(NMDevice *self, GError *error, gpointer user_data); +typedef void (*NMDeviceAttachPortCallback)(NMDevice *self, GError *error, gpointer user_data); typedef struct _NMDeviceClass { NMDBusObjectClass parent; @@ -373,12 +374,18 @@ typedef struct _NMDeviceClass { NMConnection *connection, GError **error); - gboolean (*enslave_slave)(NMDevice *self, - NMDevice *slave, - NMConnection *connection, - gboolean configure); - - void (*release_slave)(NMDevice *self, NMDevice *slave, gboolean configure); + /* Attachs a port asynchronously. Returns TRUE/FALSE on immediate + * success/error; in such cases, the callback is not invoked. If the + * action couldn't be completed immediately, DEFAULT is returned and + * the callback will always be invoked asynchronously. */ + NMTernary (*attach_port)(NMDevice *self, + NMDevice *port, + NMConnection *connection, + gboolean configure, + GCancellable *cancellable, + NMDeviceAttachPortCallback callback, + gpointer user_data); + void (*detach_port)(NMDevice *self, NMDevice *port, gboolean configure); void (*parent_changed_notify)(NMDevice *self, int old_ifindex, diff --git a/src/core/devices/ovs/nm-device-ovs-bridge.c b/src/core/devices/ovs/nm-device-ovs-bridge.c index 683ada1339..bea6e77bc8 100644 --- a/src/core/devices/ovs/nm-device-ovs-bridge.c +++ b/src/core/devices/ovs/nm-device-ovs-bridge.c @@ -78,20 +78,26 @@ act_stage3_ip_config(NMDevice *device, int addr_family) nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL); } -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) +static NMTernary +attach_port(NMDevice *device, + NMDevice *port, + NMConnection *connection, + gboolean configure, + GCancellable *cancellable, + NMDeviceAttachPortCallback callback, + gpointer user_data) { if (!configure) return TRUE; - if (!NM_IS_DEVICE_OVS_PORT(slave)) + if (!NM_IS_DEVICE_OVS_PORT(port)) return FALSE; return TRUE; } static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) +detach_port(NMDevice *device, NMDevice *port, gboolean configure) {} void @@ -159,8 +165,8 @@ nm_device_ovs_bridge_class_init(NMDeviceOvsBridgeClass *klass) device_class->get_generic_capabilities = get_generic_capabilities; device_class->act_stage3_ip_config = act_stage3_ip_config; device_class->ready_for_ip_config = ready_for_ip_config; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; + device_class->attach_port = attach_port; + device_class->detach_port = detach_port; device_class->can_reapply_change_ovs_external_ids = TRUE; device_class->reapply_connection = nm_device_ovs_reapply_connection; } diff --git a/src/core/devices/ovs/nm-device-ovs-port.c b/src/core/devices/ovs/nm-device-ovs-port.c index 116f58c43a..a64314dd0c 100644 --- a/src/core/devices/ovs/nm-device-ovs-port.c +++ b/src/core/devices/ovs/nm-device-ovs-port.c @@ -72,20 +72,42 @@ act_stage3_ip_config(NMDevice *device, int addr_family) nm_device_devip_set_state(device, addr_family, NM_DEVICE_IP_STATE_READY, NULL); } +typedef struct { + NMDevice *device; + NMDevice *port; + GCancellable *cancellable; + NMDeviceAttachPortCallback callback; + gpointer callback_user_data; +} AttachPortData; + static void add_iface_cb(GError *error, gpointer user_data) { - NMDevice *slave = user_data; - - if (error && !g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING)) { - nm_log_warn(LOGD_DEVICE, - "device %s could not be added to a ovs port: %s", - nm_device_get_iface(slave), - error->message); - nm_device_state_changed(slave, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_OVSDB_FAILED); + AttachPortData *data = user_data; + NMDeviceOvsPort *self; + gs_free_error GError *local = NULL; + + if (g_cancellable_is_cancelled(data->cancellable)) { + local = nm_utils_error_new_cancelled(FALSE, NULL); + error = local; + } else if (error && !nm_utils_error_is_cancelled_or_disposing(error)) { + self = NM_DEVICE_OVS_PORT(data->device); + _LOGW(LOGD_DEVICE, + "device %s could not be added to a ovs port: %s", + nm_device_get_iface(data->port), + error->message); + nm_device_state_changed(data->port, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_OVSDB_FAILED); } - g_object_unref(slave); + data->callback(data->device, error, data->callback_user_data); + + g_object_unref(data->device); + g_object_unref(data->port); + nm_clear_g_cancellable(&data->cancellable); + + nm_g_slice_free(data); } static gboolean @@ -115,14 +137,21 @@ set_mtu_cb(GError *error, gpointer user_data) g_object_unref(self); } -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) +static NMTernary +attach_port(NMDevice *device, + NMDevice *port, + NMConnection *connection, + gboolean configure, + GCancellable *cancellable, + NMDeviceAttachPortCallback callback, + gpointer user_data) { NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device); NMActiveConnection *ac_port = NULL; NMActiveConnection *ac_bridge = NULL; NMDevice *bridge_device; NMSettingWired *s_wired; + AttachPortData *data; if (!configure) return TRUE; @@ -131,42 +160,49 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool ac_bridge = nm_active_connection_get_master(ac_port); if (!ac_bridge) { _LOGW(LOGD_DEVICE, - "can't enslave %s: bridge active-connection not found", - nm_device_get_iface(slave)); + "can't attach %s: bridge active-connection not found", + nm_device_get_iface(port)); return FALSE; } bridge_device = nm_active_connection_get_device(ac_bridge); if (!bridge_device) { - _LOGW(LOGD_DEVICE, "can't enslave %s: bridge device not found", nm_device_get_iface(slave)); + _LOGW(LOGD_DEVICE, "can't attach %s: bridge device not found", nm_device_get_iface(port)); return FALSE; } + data = g_slice_new(AttachPortData); + *data = (AttachPortData){ + .device = g_object_ref(device), + .port = g_object_ref(port), + .cancellable = g_object_ref(cancellable), + .callback = callback, + .callback_user_data = user_data, + }; + nm_ovsdb_add_interface(nm_ovsdb_get(), nm_active_connection_get_applied_connection(ac_bridge), nm_device_get_applied_connection(device), - nm_device_get_applied_connection(slave), + nm_device_get_applied_connection(port), bridge_device, - slave, + port, add_iface_cb, - g_object_ref(slave)); + data); /* DPDK ports does not have a link after the devbind, so the MTU must be * set on ovsdb after adding the interface. */ - if (NM_IS_DEVICE_OVS_INTERFACE(slave) && _ovs_interface_is_dpdk(slave)) { - s_wired = nm_device_get_applied_setting(slave, NM_TYPE_SETTING_WIRED); - - if (!s_wired || !nm_setting_wired_get_mtu(s_wired)) - return TRUE; - - nm_ovsdb_set_interface_mtu(nm_ovsdb_get(), - nm_device_get_ip_iface(slave), - nm_setting_wired_get_mtu(s_wired), - set_mtu_cb, - g_object_ref(slave)); + if (NM_IS_DEVICE_OVS_INTERFACE(port) && _ovs_interface_is_dpdk(port)) { + s_wired = nm_device_get_applied_setting(port, NM_TYPE_SETTING_WIRED); + if (s_wired && nm_setting_wired_get_mtu(s_wired)) { + nm_ovsdb_set_interface_mtu(nm_ovsdb_get(), + nm_device_get_ip_iface(port), + nm_setting_wired_get_mtu(s_wired), + set_mtu_cb, + g_object_ref(port)); + } } - return TRUE; + return NM_TERNARY_DEFAULT; } static void @@ -186,31 +222,31 @@ del_iface_cb(GError *error, gpointer user_data) } static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) +detach_port(NMDevice *device, NMDevice *port, gboolean configure) { - NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device); - bool slave_not_managed = !NM_IN_SET(nm_device_sys_iface_state_get(slave), - NM_DEVICE_SYS_IFACE_STATE_MANAGED, - NM_DEVICE_SYS_IFACE_STATE_ASSUME); + NMDeviceOvsPort *self = NM_DEVICE_OVS_PORT(device); + bool port_not_managed = !NM_IN_SET(nm_device_sys_iface_state_get(port), + NM_DEVICE_SYS_IFACE_STATE_MANAGED, + NM_DEVICE_SYS_IFACE_STATE_ASSUME); - _LOGI(LOGD_DEVICE, "releasing ovs interface %s", nm_device_get_ip_iface(slave)); + _LOGI(LOGD_DEVICE, "detaching ovs interface %s", nm_device_get_ip_iface(port)); /* Even if the an interface's device has gone away (e.g. externally * removed and thus we're called with configure=FALSE), we still need * to make sure its OVSDB entry is gone. */ - if (configure || slave_not_managed) { + if (configure || port_not_managed) { nm_ovsdb_del_interface(nm_ovsdb_get(), - nm_device_get_iface(slave), + nm_device_get_iface(port), del_iface_cb, - g_object_ref(slave)); + g_object_ref(port)); } if (configure) { /* Open VSwitch is going to delete this one. We must ignore what happens * next with the interface. */ - if (NM_IS_DEVICE_OVS_INTERFACE(slave)) - nm_device_update_from_platform_link(slave, NULL); + if (NM_IS_DEVICE_OVS_INTERFACE(port)) + nm_device_update_from_platform_link(port, NULL); } } @@ -245,8 +281,8 @@ nm_device_ovs_port_class_init(NMDeviceOvsPortClass *klass) device_class->get_generic_capabilities = get_generic_capabilities; device_class->act_stage3_ip_config = act_stage3_ip_config; device_class->ready_for_ip_config = ready_for_ip_config; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; + device_class->attach_port = attach_port; + device_class->detach_port = detach_port; device_class->can_reapply_change_ovs_external_ids = TRUE; device_class->reapply_connection = nm_device_ovs_reapply_connection; } diff --git a/src/core/devices/ovs/nm-ovsdb.c b/src/core/devices/ovs/nm-ovsdb.c index 44e16cb78f..eb8efe4bf8 100644 --- a/src/core/devices/ovs/nm-ovsdb.c +++ b/src/core/devices/ovs/nm-ovsdb.c @@ -376,6 +376,9 @@ ovsdb_call_method(NMOvsdb *self, NMOvsdbPrivate *priv = NM_OVSDB_GET_PRIVATE(self); OvsdbMethodCall *call; + /* FIXME(shutdown): this function should accept a cancellable to + * interrupt the operation. */ + /* Ensure we're not unsynchronized before we queue the method call. */ ovsdb_try_connect(self); @@ -1550,7 +1553,7 @@ _external_ids_to_string(const GArray *arr) if (!arr) return g_strdup("empty"); - nm_str_buf_init(&strbuf, NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE); + strbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_104, FALSE); nm_str_buf_append(&strbuf, "["); for (i = 0; i < arr->len; i++) { const NMUtilsNamedValue *n = &g_array_index(arr, NMUtilsNamedValue, i); diff --git a/src/core/devices/team/nm-device-team.c b/src/core/devices/team/nm-device-team.c index b67c710020..1f098806d3 100644 --- a/src/core/devices/team/nm-device-team.c +++ b/src/core/devices/team/nm-device-team.c @@ -790,19 +790,25 @@ deactivate(NMDevice *device) teamd_cleanup(self, TRUE); } -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) +static NMTernary +attach_port(NMDevice *device, + NMDevice *port, + NMConnection *connection, + gboolean configure, + GCancellable *cancellable, + NMDeviceAttachPortCallback callback, + gpointer user_data) { - NMDeviceTeam *self = NM_DEVICE_TEAM(device); - NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); - gboolean success = TRUE; - const char *slave_iface = nm_device_get_ip_iface(slave); + NMDeviceTeam *self = NM_DEVICE_TEAM(device); + NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); + gboolean success = TRUE; + const char *port_iface = nm_device_get_ip_iface(port); NMSettingTeamPort *s_team_port; - nm_device_master_check_slave_physical_port(device, slave, LOGD_TEAM); + nm_device_master_check_slave_physical_port(device, port, LOGD_TEAM); if (configure) { - nm_device_take_down(slave, TRUE); + nm_device_take_down(port, TRUE); s_team_port = nm_connection_get_setting_team_port(connection); if (s_team_port) { @@ -811,19 +817,19 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool if (config) { if (!priv->tdc) { _LOGW(LOGD_TEAM, - "enslaved team port %s config not changed, not connected to teamd", - slave_iface); + "attached team port %s config not changed, not connected to teamd", + port_iface); } else { gs_free char *sanitized_config = NULL; int err; sanitized_config = g_strdup(config); g_strdelimit(sanitized_config, "\r\n", ' '); - err = teamdctl_port_config_update_raw(priv->tdc, slave_iface, sanitized_config); + err = teamdctl_port_config_update_raw(priv->tdc, port_iface, sanitized_config); if (err != 0) { _LOGE(LOGD_TEAM, "failed to update config for port %s (err=%d)", - slave_iface, + port_iface, err); return FALSE; } @@ -832,8 +838,8 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool } success = nm_platform_link_enslave(nm_device_get_platform(device), nm_device_get_ip_ifindex(device), - nm_device_get_ip_ifindex(slave)); - nm_device_bring_up(slave, TRUE, NULL); + nm_device_get_ip_ifindex(port)); + nm_device_bring_up(port, TRUE, NULL); if (!success) return FALSE; @@ -841,21 +847,21 @@ enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gbool nm_clear_g_source(&priv->teamd_read_timeout); priv->teamd_read_timeout = g_timeout_add_seconds(5, teamd_read_timeout_cb, self); - _LOGI(LOGD_TEAM, "enslaved team port %s", slave_iface); + _LOGI(LOGD_TEAM, "attached team port %s", port_iface); } else - _LOGI(LOGD_TEAM, "team port %s was enslaved", slave_iface); + _LOGI(LOGD_TEAM, "team port %s was attached", port_iface); return TRUE; } static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) +detach_port(NMDevice *device, NMDevice *port, gboolean configure) { NMDeviceTeam *self = NM_DEVICE_TEAM(device); NMDeviceTeamPrivate *priv = NM_DEVICE_TEAM_GET_PRIVATE(self); gboolean do_release, success; NMSettingTeamPort *s_port; - int ifindex_slave; + int ifindex_port; int ifindex; do_release = configure; @@ -865,39 +871,39 @@ release_slave(NMDevice *device, NMDevice *slave, gboolean configure) do_release = FALSE; } - ifindex_slave = nm_device_get_ip_ifindex(slave); + ifindex_port = nm_device_get_ip_ifindex(port); - if (ifindex_slave <= 0) { - _LOGD(LOGD_TEAM, "team port %s is already released", nm_device_get_ip_iface(slave)); + if (ifindex_port <= 0) { + _LOGD(LOGD_TEAM, "team port %s is already detached", nm_device_get_ip_iface(port)); } else if (do_release) { success = nm_platform_link_release(nm_device_get_platform(device), nm_device_get_ip_ifindex(device), - ifindex_slave); + ifindex_port); if (success) - _LOGI(LOGD_TEAM, "released team port %s", nm_device_get_ip_iface(slave)); + _LOGI(LOGD_TEAM, "detached team port %s", nm_device_get_ip_iface(port)); else - _LOGW(LOGD_TEAM, "failed to release team port %s", nm_device_get_ip_iface(slave)); + _LOGW(LOGD_TEAM, "failed to detach team port %s", nm_device_get_ip_iface(port)); /* Kernel team code "closes" the port when releasing it, (which clears * IFF_UP), so we must bring it back up here to ensure carrier changes and * other state is noticed by the now-released port. */ - if (!nm_device_bring_up(slave, TRUE, NULL)) { + if (!nm_device_bring_up(port, TRUE, NULL)) { _LOGW(LOGD_TEAM, - "released team port %s could not be brought up", - nm_device_get_ip_iface(slave)); + "detached team port %s could not be brought up", + nm_device_get_ip_iface(port)); } nm_clear_g_source(&priv->teamd_read_timeout); priv->teamd_read_timeout = g_timeout_add_seconds(5, teamd_read_timeout_cb, self); } else - _LOGI(LOGD_TEAM, "team port %s was released", nm_device_get_ip_iface(slave)); + _LOGI(LOGD_TEAM, "team port %s was detached", nm_device_get_ip_iface(port)); /* Delete any port configuration we previously set */ if (configure && priv->tdc - && (s_port = nm_device_get_applied_setting(slave, NM_TYPE_SETTING_TEAM_PORT)) + && (s_port = nm_device_get_applied_setting(port, NM_TYPE_SETTING_TEAM_PORT)) && (nm_setting_team_port_get_config(s_port))) - teamdctl_port_config_update_raw(priv->tdc, nm_device_get_ip_iface(slave), "{}"); + teamdctl_port_config_update_raw(priv->tdc, nm_device_get_ip_iface(port), "{}"); } static gboolean @@ -1064,8 +1070,8 @@ nm_device_team_class_init(NMDeviceTeamClass *klass) device_class->act_stage1_prepare = act_stage1_prepare; device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; device_class->deactivate = deactivate; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; + device_class->attach_port = attach_port; + device_class->detach_port = detach_port; obj_properties[PROP_CONFIG] = g_param_spec_string(NM_DEVICE_TEAM_CONFIG, "", diff --git a/src/core/dhcp/nm-dhcp-client.c b/src/core/dhcp/nm-dhcp-client.c index 2bfd7e01eb..e71590858a 100644 --- a/src/core/dhcp/nm-dhcp-client.c +++ b/src/core/dhcp/nm-dhcp-client.c @@ -291,6 +291,7 @@ nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3Co if (!IS_IPv4 && l3cd) { if (nm_dhcp_utils_merge_new_dhcp6_lease(priv->l3cd, l3cd, &l3cd_merged)) { + _LOGD("lease merged with existing one"); l3cd = nm_l3_config_data_seal(l3cd_merged); } } @@ -327,14 +328,6 @@ nm_dhcp_client_set_state(NMDhcpClient *self, NMDhcpState new_state, const NML3Co keys[i], (char *) g_hash_table_lookup(options, keys[i])); } - - if (priv->config.addr_family == AF_INET6) { - gs_free char *event_id = NULL; - - event_id = nm_dhcp_utils_get_dhcp6_event_id(options); - if (event_id) - _LOGT("event-id: \"%s\"", event_id); - } } } @@ -1080,7 +1073,7 @@ config_init(NMDhcpClientConfig *config, const NMDhcpClientConfig *src) if (!config->send_hostname) { nm_clear_g_free((gpointer *) &config->hostname); } else if ((config->use_fqdn && !nm_sd_dns_name_is_valid(config->hostname)) - || (!config->use_fqdn && !nm_sd_hostname_is_valid(config->hostname, FALSE))) { + || (!config->use_fqdn && !nm_hostname_is_valid(config->hostname, FALSE))) { nm_log_warn(LOGD_DHCP, "dhcp%c: %s '%s' is invalid, will be ignored", nm_utils_addr_family_to_char(config->addr_family), diff --git a/src/core/dhcp/nm-dhcp-nettools.c b/src/core/dhcp/nm-dhcp-nettools.c index aac189676d..7068a6e924 100644 --- a/src/core/dhcp/nm-dhcp-nettools.c +++ b/src/core/dhcp/nm-dhcp-nettools.c @@ -13,22 +13,24 @@ #include <ctype.h> #include <net/if_arp.h> +#include "n-dhcp4/src/n-dhcp4.h" + #include "libnm-glib-aux/nm-dedup-multi.h" -#include "libnm-std-aux/unaligned.h" +#include "libnm-glib-aux/nm-io-utils.h" #include "libnm-glib-aux/nm-str-buf.h" +#include "libnm-std-aux/unaligned.h" -#include "nm-l3-config-data.h" -#include "nm-utils.h" -#include "nm-config.h" -#include "nm-dhcp-utils.h" -#include "nm-dhcp-options.h" -#include "nm-core-utils.h" #include "NetworkManagerUtils.h" #include "libnm-platform/nm-platform.h" +#include "nm-config.h" +#include "nm-core-utils.h" #include "nm-dhcp-client-logging.h" -#include "n-dhcp4/src/n-dhcp4.h" +#include "nm-dhcp-options.h" +#include "nm-dhcp-utils.h" +#include "nm-l3-config-data.h" +#include "nm-utils.h" + #include "libnm-systemd-shared/nm-sd-utils-shared.h" -#include "libnm-systemd-core/nm-sd-utils-dhcp.h" /*****************************************************************************/ @@ -887,12 +889,15 @@ dhcp4_event_cb(int fd, GIOCondition condition, gpointer user_data) r = n_dhcp4_client_dispatch(priv->client); if (r < 0) { - /* FIXME: if any operation (e.g. send()) fails during the + /* If any operation (e.g. send()) fails during the * dispatch, n-dhcp4 returns an error without arming timers * or progressing state, so the only reasonable thing to do * is to move to failed state so that the client will be - * restarted. Ideally n-dhcp4 should retry failed operations - * a predefined number of times (possibly infinite). + * restarted. + * + * That means, n_dhcp4_client_dispatch() must not fail if it can + * somehow workaround the problem. A failure is really fatal + * and the client needs to be restarted. */ _LOGE("error %d dispatching events", r); nm_clear_g_source_inst(&priv->event_source); @@ -1107,18 +1112,20 @@ ip4_start(NMDhcpClient *client, GError **error) if (client_config->v4.last_address) inet_pton(AF_INET, client_config->v4.last_address, &last_addr); else { - /* - * TODO: we stick to the systemd-networkd lease file format. Quite easy for now to - * just use the functions in systemd code. Anyway, as in the end we just use the - * ip address from all the options found in the lease, write a function that parses - * the lease file just for the assigned address and returns it in &last_address. - * Then drop reference to systemd-networkd structures and functions. - */ - nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; - - dhcp_lease_load(&lease, lease_file); - if (lease) - sd_dhcp_lease_get_address(lease, &last_addr); + gs_free char *contents = NULL; + gs_free char *s_addr = NULL; + + nm_utils_file_get_contents(-1, + lease_file, + 64 * 1024, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, + &contents, + NULL, + NULL, + NULL); + nm_parse_env_file(contents, "ADDRESS", &s_addr); + if (s_addr) + nm_utils_parse_inaddr_bin(AF_INET, s_addr, NULL, &last_addr); } if (last_addr.s_addr) { diff --git a/src/core/dhcp/nm-dhcp-systemd.c b/src/core/dhcp/nm-dhcp-systemd.c index 4a718de9ec..045d528791 100644 --- a/src/core/dhcp/nm-dhcp-systemd.c +++ b/src/core/dhcp/nm-dhcp-systemd.c @@ -25,7 +25,6 @@ #include "libnm-platform/nm-platform.h" #include "nm-dhcp-client-logging.h" #include "libnm-systemd-core/nm-sd.h" -#include "libnm-systemd-core/nm-sd-utils-dhcp.h" /*****************************************************************************/ @@ -47,7 +46,6 @@ static GType nm_dhcp_systemd_get_type(void); /*****************************************************************************/ typedef struct { - sd_dhcp_client *client4; sd_dhcp6_client *client6; char *lease_file; @@ -70,675 +68,6 @@ G_DEFINE_TYPE(NMDhcpSystemd, nm_dhcp_systemd, NM_TYPE_DHCP_CLIENT) /*****************************************************************************/ static NML3ConfigData * -lease_to_ip4_config(NMDedupMultiIndex *multi_idx, - const char *iface, - int ifindex, - sd_dhcp_lease *lease, - GError **error) -{ - nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; - gs_unref_hashtable GHashTable *options = NULL; - const struct in_addr *addr_list; - char addr_str[NM_UTILS_INET_ADDRSTRLEN]; - const char *s; - nm_auto_free_gstring GString *str = NULL; - nm_auto_free sd_dhcp_route **routes_static = NULL; - nm_auto_free sd_dhcp_route **routes_classless = NULL; - const char *const *search_domains = NULL; - guint32 default_route_metric_offset; - guint16 mtu; - int i; - int num; - int is_classless; - int n_routes_static; - int n_routes_classless; - const void *data; - gsize data_len; - gboolean has_router_from_classless = FALSE; - const gint32 ts = nm_utils_get_monotonic_timestamp_sec(); - gint64 ts_time = time(NULL); - struct in_addr a_address; - struct in_addr a_netmask; - struct in_addr a_next_server; - struct in_addr server_id; - struct in_addr broadcast; - const struct in_addr *a_router; - guint32 a_plen; - guint32 a_lifetime; - guint32 renewal; - guint32 rebinding; - gs_free nm_sd_dhcp_option *private_options = NULL; - - nm_assert(lease != NULL); - - if (sd_dhcp_lease_get_address(lease, &a_address) < 0) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "could not get address from lease"); - return NULL; - } - - if (sd_dhcp_lease_get_netmask(lease, &a_netmask) < 0) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "could not get netmask from lease"); - return NULL; - } - - if (sd_dhcp_lease_get_lifetime(lease, &a_lifetime) < 0) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_UNKNOWN, - "could not get lifetime from lease"); - return NULL; - } - - l3cd = nm_l3_config_data_new(multi_idx, ifindex, NM_IP_CONFIG_SOURCE_DHCP); - - options = nm_dhcp_option_create_options_dict(); - - _nm_utils_inet4_ntop(a_address.s_addr, addr_str); - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_IP_ADDRESS, addr_str); - - a_plen = nm_utils_ip4_netmask_to_prefix(a_netmask.s_addr); - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_SUBNET_MASK, - _nm_utils_inet4_ntop(a_netmask.s_addr, addr_str)); - - nm_dhcp_option_add_option_u64(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_IP_ADDRESS_LEASE_TIME, - a_lifetime); - nm_dhcp_option_add_option_u64(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_NM_EXPIRY, - (guint64) (ts_time + a_lifetime)); - - if (sd_dhcp_lease_get_next_server(lease, &a_next_server) == 0) { - _nm_utils_inet4_ntop(a_next_server.s_addr, addr_str); - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NM_NEXT_SERVER, addr_str); - } - - nm_l3_config_data_add_address_4(l3cd, - &((const NMPlatformIP4Address){ - .address = a_address.s_addr, - .peer_address = a_address.s_addr, - .plen = a_plen, - .addr_source = NM_IP_CONFIG_SOURCE_DHCP, - .timestamp = ts, - .lifetime = a_lifetime, - .preferred = a_lifetime, - })); - - if (sd_dhcp_lease_get_server_identifier(lease, &server_id) >= 0) { - _nm_utils_inet4_ntop(server_id.s_addr, addr_str); - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_SERVER_ID, addr_str); - } - - if (sd_dhcp_lease_get_broadcast(lease, &broadcast) >= 0) { - _nm_utils_inet4_ntop(broadcast.s_addr, addr_str); - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_BROADCAST, addr_str); - } - - num = sd_dhcp_lease_get_dns(lease, &addr_list); - if (num > 0) { - nm_gstring_prepare(&str); - for (i = 0; i < num; i++) { - _nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str); - g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - - if (addr_list[i].s_addr == 0 || nm_ip4_addr_is_localhost(addr_list[i].s_addr)) { - /* Skip localhost addresses, like also networkd does. - * See https://github.com/systemd/systemd/issues/4524. */ - continue; - } - nm_l3_config_data_add_nameserver(l3cd, AF_INET, &addr_list[i].s_addr); - } - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_DOMAIN_NAME_SERVER, - str->str); - } - - num = sd_dhcp_lease_get_search_domains(lease, (char ***) &search_domains); - if (num > 0) { - nm_gstring_prepare(&str); - for (i = 0; i < num; i++) { - g_string_append(nm_gstring_add_space_delimiter(str), search_domains[i]); - nm_l3_config_data_add_search(l3cd, AF_INET, search_domains[i]); - } - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_DOMAIN_SEARCH_LIST, - str->str); - } - - if (sd_dhcp_lease_get_domainname(lease, &s) >= 0) { - gs_strfreev char **domains = NULL; - char **d; - - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_DOMAIN_NAME, s); - - /* Multiple domains sometimes stuffed into option 15 "Domain Name". - * As systemd escapes such characters, split them at \\032. */ - domains = g_strsplit(s, "\\032", 0); - for (d = domains; *d; d++) - nm_l3_config_data_add_domain(l3cd, AF_INET, *d); - } - - if (sd_dhcp_lease_get_hostname(lease, &s) >= 0) { - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_HOST_NAME, s); - } - - default_route_metric_offset = 0; - n_routes_static = sd_dhcp_lease_get_static_routes(lease, &routes_static); - n_routes_classless = sd_dhcp_lease_get_classless_routes(lease, &routes_classless); - for (is_classless = 1; is_classless >= 0; is_classless--) { - int n_routes = (is_classless ? n_routes_classless : n_routes_static); - sd_dhcp_route *const *routes = (is_classless ? routes_classless : routes_static); - - if (n_routes <= 0) - continue; - - nm_gstring_prepare(&str); - - for (i = 0; i < n_routes; i++) { - char network_net_str[NM_UTILS_INET_ADDRSTRLEN]; - char gateway_str[NM_UTILS_INET_ADDRSTRLEN]; - guint8 r_plen; - struct in_addr r_network; - struct in_addr r_gateway; - in_addr_t network_net; - guint32 m; - - if (sd_dhcp_route_get_destination(routes[i], &r_network) < 0) - continue; - if (sd_dhcp_route_get_destination_prefix_length(routes[i], &r_plen) < 0 || r_plen > 32) - continue; - if (sd_dhcp_route_get_gateway(routes[i], &r_gateway) < 0) - continue; - - network_net = nm_utils_ip4_address_clear_host_address(r_network.s_addr, r_plen); - _nm_utils_inet4_ntop(network_net, network_net_str); - _nm_utils_inet4_ntop(r_gateway.s_addr, gateway_str); - - g_string_append_printf(nm_gstring_add_space_delimiter(str), - "%s/%d %s", - network_net_str, - (int) r_plen, - gateway_str); - - if (!is_classless && n_routes_classless > 0) { - /* RFC 3443: if the DHCP server returns both a Classless Static Routes - * option and a Static Routes option, the DHCP client MUST ignore the - * Static Routes option. */ - continue; - } - - if (r_plen == 0) { - if (!is_classless) { - /* for option 33 (static route), RFC 2132 says: - * - * The default route (0.0.0.0) is an illegal destination for a static - * route. */ - continue; - } - - /* if there are multiple default routes, we add them with differing - * metrics. */ - m = default_route_metric_offset++; - has_router_from_classless = TRUE; - } else - m = 0; - - nm_l3_config_data_add_route_4(l3cd, - &((const NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .network = network_net, - .plen = r_plen, - .gateway = r_gateway.s_addr, - .pref_src = a_address.s_addr, - .metric_any = TRUE, - .metric = m, - .table_any = TRUE, - .table_coerced = 0, - })); - } - - if (str->len > 0) { - nm_dhcp_option_add_option(options, - AF_INET, - is_classless ? NM_DHCP_OPTION_DHCP4_CLASSLESS_STATIC_ROUTE - : NM_DHCP_OPTION_DHCP4_STATIC_ROUTE, - str->str); - } - } - - num = sd_dhcp_lease_get_router(lease, &a_router); - if (num > 0) { - default_route_metric_offset = 0; - - nm_gstring_prepare(&str); - for (i = 0; i < num; i++) { - guint32 m; - - s = _nm_utils_inet4_ntop(a_router[i].s_addr, addr_str); - g_string_append(nm_gstring_add_space_delimiter(str), s); - - if (a_router[i].s_addr == 0) { - /* silently skip 0.0.0.0 */ - continue; - } - - if (has_router_from_classless) { - /* If the DHCP server returns both a Classless Static Routes option and a - * Router option, the DHCP client MUST ignore the Router option [RFC 3442]. - * - * Be more lenient and ignore the Router option only if Classless Static - * Routes contain a default gateway (as other DHCP backends do). - */ - continue; - } - - /* if there are multiple default routes, we add them with differing - * metrics. */ - m = default_route_metric_offset++; - - nm_l3_config_data_add_route_4(l3cd, - &((const NMPlatformIP4Route){ - .rt_source = NM_IP_CONFIG_SOURCE_DHCP, - .gateway = a_router[i].s_addr, - .pref_src = a_address.s_addr, - .table_any = TRUE, - .table_coerced = 0, - .metric_any = TRUE, - .metric = m, - })); - } - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROUTER, str->str); - } - - if (sd_dhcp_lease_get_mtu(lease, &mtu) >= 0 && mtu) { - nm_dhcp_option_add_option_u64(options, AF_INET, NM_DHCP_OPTION_DHCP4_INTERFACE_MTU, mtu); - nm_l3_config_data_set_mtu(l3cd, mtu); - } - - num = sd_dhcp_lease_get_ntp(lease, &addr_list); - if (num > 0) { - nm_gstring_prepare(&str); - for (i = 0; i < num; i++) { - _nm_utils_inet4_ntop(addr_list[i].s_addr, addr_str); - g_string_append(nm_gstring_add_space_delimiter(str), addr_str); - } - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NTP_SERVER, str->str); - } - - if (sd_dhcp_lease_get_root_path(lease, &s) >= 0) { - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_ROOT_PATH, s); - } - - if (sd_dhcp_lease_get_t1(lease, &renewal) >= 0) { - nm_dhcp_option_add_option_u64(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_RENEWAL_T1_TIME, - renewal); - } - - if (sd_dhcp_lease_get_t2(lease, &rebinding) >= 0) { - nm_dhcp_option_add_option_u64(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_REBINDING_T2_TIME, - rebinding); - } - - if (sd_dhcp_lease_get_timezone(lease, &s) >= 0) { - nm_dhcp_option_add_option(options, AF_INET, NM_DHCP_OPTION_DHCP4_NEW_TZDB_TIMEZONE, s); - } - - if (sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len) >= 0) { - if (!!memmem(data, data_len, "ANDROID_METERED", NM_STRLEN("ANDROID_METERED"))) - nm_l3_config_data_set_metered(l3cd, TRUE); - } - - num = nm_sd_dhcp_lease_get_private_options(lease, &private_options); - if (num > 0) { - for (i = 0; i < num; i++) { - guint8 code = private_options[i].code; - const guint8 *l_data = private_options[i].data; - gsize l_data_len = private_options[i].data_len; - char *option_string; - - if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY) { - if (nm_dhcp_lease_data_parse_cstr(l_data, l_data_len, &l_data_len)) { - gs_free char *to_free = NULL; - const char *escaped; - - escaped = - nm_utils_buf_utf8safe_escape((char *) l_data, l_data_len, 0, &to_free); - nm_dhcp_option_add_option(options, - AF_INET, - NM_DHCP_OPTION_DHCP4_PRIVATE_PROXY_AUTODISCOVERY, - escaped ?: ""); - - nm_l3_config_data_set_proxy_method(l3cd, NM_PROXY_CONFIG_METHOD_AUTO); - nm_l3_config_data_set_proxy_pac_url(l3cd, escaped ?: ""); - } - continue; - } - if (code == NM_DHCP_OPTION_DHCP4_PRIVATE_CLASSLESS_STATIC_ROUTE) { - /* nettools and dhclient parse option 249 (Microsoft Classless Static Route) - * as fallback for routes and ignores them from private options. - * - * The systemd plugin does not, and for consistency with nettools we - * also don't expose it as private option either. */ - continue; - } - - option_string = nm_utils_bin2hexstr_full(l_data, l_data_len, ':', FALSE, NULL); - nm_dhcp_option_take_option(options, AF_INET, code, option_string); - } - } - - nm_dhcp_option_add_requests_to_options(options, AF_INET); - - nm_l3_config_data_set_dhcp_lease_from_options(l3cd, AF_INET, g_steal_pointer(&options)); - - return g_steal_pointer(&l3cd); -} - -/*****************************************************************************/ - -static void -bound4_handle(NMDhcpSystemd *self, gboolean extended) -{ - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - const char *iface = nm_dhcp_client_get_iface(NM_DHCP_CLIENT(self)); - nm_auto_unref_l3cd_init NML3ConfigData *l3cd = NULL; - sd_dhcp_lease *lease = NULL; - GError *error = NULL; - - if (sd_dhcp_client_get_lease(priv->client4, &lease) < 0 || !lease) { - _LOGW("no lease!"); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); - return; - } - - _LOGD("lease available"); - - l3cd = lease_to_ip4_config(nm_dhcp_client_get_multi_idx(NM_DHCP_CLIENT(self)), - iface, - nm_dhcp_client_get_ifindex(NM_DHCP_CLIENT(self)), - lease, - &error); - if (!l3cd) { - _LOGW("%s", error->message); - g_clear_error(&error); - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), NM_DHCP_STATE_FAIL, NULL); - return; - } - - dhcp_lease_save(lease, priv->lease_file); - - nm_dhcp_client_set_state(NM_DHCP_CLIENT(self), - extended ? NM_DHCP_STATE_EXTENDED : NM_DHCP_STATE_BOUND, - l3cd); -} - -static int -dhcp_event_cb(sd_dhcp_client *client, int event, gpointer user_data) -{ - NMDhcpSystemd *self = NM_DHCP_SYSTEMD(user_data); - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - char addr_str[INET_ADDRSTRLEN]; - sd_dhcp_lease *lease = NULL; - struct in_addr addr; - int r; - - nm_assert(priv->client4 == client); - - _LOGD("client event %d", event); - - switch (event) { - case SD_DHCP_CLIENT_EVENT_EXPIRED: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_EXPIRE, NULL); - break; - case SD_DHCP_CLIENT_EVENT_STOP: - nm_dhcp_client_set_state(NM_DHCP_CLIENT(user_data), NM_DHCP_STATE_FAIL, NULL); - break; - case SD_DHCP_CLIENT_EVENT_RENEW: - case SD_DHCP_CLIENT_EVENT_IP_CHANGE: - bound4_handle(self, TRUE); - break; - case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE: - bound4_handle(self, FALSE); - break; - case SD_DHCP_CLIENT_EVENT_SELECTING: - r = sd_dhcp_client_get_lease(priv->client4, &lease); - if (r < 0) - return r; - r = sd_dhcp_lease_get_server_identifier(lease, &addr); - if (r < 0) - return r; - if (nm_dhcp_client_server_id_is_rejected(NM_DHCP_CLIENT(user_data), &addr)) { - _LOGD("server-id %s is in the reject-list, ignoring", - nm_utils_inet_ntop(AF_INET, &addr, addr_str)); - return -ENOMSG; - } - break; - case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE: - break; - default: - _LOGW("unhandled DHCP event %d", event); - break; - } - - return 0; -} - -static gboolean -ip4_start(NMDhcpClient *client, GError **error) -{ - nm_auto(sd_dhcp_client_unrefp) sd_dhcp_client *sd_client = NULL; - NMDhcpSystemd *self = NM_DHCP_SYSTEMD(client); - NMDhcpSystemdPrivate *priv = NM_DHCP_SYSTEMD_GET_PRIVATE(self); - const NMDhcpClientConfig *client_config; - gs_free char *lease_file = NULL; - GBytes *hwaddr; - const uint8_t *hwaddr_arr; - gsize hwaddr_len; - int arp_type; - GBytes *client_id; - gs_unref_bytes GBytes *client_id_new = NULL; - GBytes *vendor_class_identifier; - const uint8_t *client_id_arr; - size_t client_id_len; - struct in_addr last_addr = {0}; - const char *hostname; - const char *mud_url; - int r, i; - GBytes *bcast_hwaddr; - const uint8_t *bcast_hwaddr_arr; - gsize bcast_hwaddr_len; - - g_return_val_if_fail(!priv->client4, FALSE); - g_return_val_if_fail(!priv->client6, FALSE); - - client_config = nm_dhcp_client_get_config(client); - - /* TODO: honor nm_dhcp_client_get_anycast_address() */ - - r = sd_dhcp_client_new(&sd_client, FALSE); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to create dhcp-client: %s"); - return FALSE; - } - - _LOGT("dhcp-client4: set " NM_HASH_OBFUSCATE_PTR_FMT, NM_HASH_OBFUSCATE_PTR(sd_client)); - - r = sd_dhcp_client_attach_event(sd_client, NULL, 0); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to attach event: %s"); - return FALSE; - } - - hwaddr = client_config->hwaddr; - if (!hwaddr || !(hwaddr_arr = g_bytes_get_data(hwaddr, &hwaddr_len)) - || (arp_type = nm_utils_arp_type_detect_from_hwaddrlen(hwaddr_len)) < 0) { - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "invalid MAC address"); - return FALSE; - } - - bcast_hwaddr_arr = NULL; - bcast_hwaddr = client_config->bcast_hwaddr; - if (bcast_hwaddr) { - bcast_hwaddr_arr = g_bytes_get_data(bcast_hwaddr, &bcast_hwaddr_len); - if (bcast_hwaddr_len != hwaddr_len) - bcast_hwaddr_arr = NULL; - } - - r = sd_dhcp_client_set_mac(sd_client, - hwaddr_arr, - bcast_hwaddr_arr, - hwaddr_len, - (guint16) arp_type); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set MAC address: %s"); - return FALSE; - } - - r = sd_dhcp_client_set_ifindex(sd_client, nm_dhcp_client_get_ifindex(client)); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set ifindex: %s"); - return FALSE; - } - - nm_dhcp_utils_get_leasefile_path(AF_INET, - "internal", - client_config->iface, - client_config->uuid, - &lease_file); - - if (client_config->v4.last_address) - inet_pton(AF_INET, client_config->v4.last_address, &last_addr); - else { - nm_auto(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; - - dhcp_lease_load(&lease, lease_file); - if (lease) - sd_dhcp_lease_get_address(lease, &last_addr); - } - - r = sd_dhcp_client_set_request_broadcast(sd_client, client_config->v4.request_broadcast); - nm_assert(r >= 0); - - if (last_addr.s_addr) { - r = sd_dhcp_client_set_request_address(sd_client, &last_addr); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set last IPv4 address: %s"); - return FALSE; - } - } - - client_id = client_config->client_id; - if (!client_id) { - client_id_new = nm_utils_dhcp_client_id_mac(arp_type, hwaddr_arr, hwaddr_len); - client_id = client_id_new; - } - - if (!(client_id_arr = g_bytes_get_data(client_id, &client_id_len)) || client_id_len < 2) { - /* invalid client-ids are not expected. */ - nm_assert_not_reached(); - - nm_utils_error_set_literal(error, NM_UTILS_ERROR_UNKNOWN, "no valid IPv4 client-id"); - return FALSE; - } - - /* Note that we always set a client-id. In particular for infiniband that is necessary, - * see https://tools.ietf.org/html/rfc4390#section-2.1 . */ - r = sd_dhcp_client_set_client_id(sd_client, - client_id_arr[0], - client_id_arr + 1, - NM_MIN(client_id_len - 1, _NM_MAX_CLIENT_ID_LEN)); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set IPv4 client-id: %s"); - return FALSE; - } - - /* Add requested options */ - for (i = 0; i < (int) G_N_ELEMENTS(_nm_dhcp_option_dhcp4_options); i++) { - if (_nm_dhcp_option_dhcp4_options[i].include) { - nm_assert(_nm_dhcp_option_dhcp4_options[i].option_num <= 255); - r = sd_dhcp_client_set_request_option(sd_client, - _nm_dhcp_option_dhcp4_options[i].option_num); - nm_assert(r >= 0 || r == -EEXIST); - } - } - - hostname = client_config->hostname; - if (hostname) { - /* FIXME: sd-dhcp decides which hostname/FQDN option to send (12 or 81) - * only based on whether the hostname has a domain part or not. At the - * moment there is no way to force one or another. - */ - r = sd_dhcp_client_set_hostname(sd_client, hostname); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set DHCP hostname: %s"); - return FALSE; - } - } - - mud_url = client_config->mud_url; - if (mud_url) { - r = sd_dhcp_client_set_mud_url(sd_client, mud_url); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set DHCP MUDURL: %s"); - return FALSE; - } - } - - vendor_class_identifier = client_config->vendor_class_identifier; - if (vendor_class_identifier) { - const char *option_data; - gsize len; - - option_data = g_bytes_get_data(vendor_class_identifier, &len); - nm_assert(option_data); - nm_assert(len <= 255); - - option_data = nm_strndup_a(300, option_data, len, NULL); - - r = sd_dhcp_client_set_vendor_class_identifier(sd_client, option_data); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set DHCP vendor class identifier: %s"); - return FALSE; - } - } - - r = sd_dhcp_client_set_callback(sd_client, dhcp_event_cb, client); - if (r < 0) { - nm_utils_error_set_errno(error, r, "failed to set callback: %s"); - return FALSE; - } - - priv->client4 = g_steal_pointer(&sd_client); - - g_free(priv->lease_file); - priv->lease_file = g_steal_pointer(&lease_file); - - nm_dhcp_client_set_effective_client_id(client, client_id); - - r = sd_dhcp_client_start(priv->client4); - if (r < 0) { - sd_dhcp_client_set_callback(priv->client4, NULL, NULL); - nm_clear_pointer(&priv->client4, sd_dhcp_client_unref); - nm_utils_error_set_errno(error, r, "failed to start DHCP client: %s"); - return FALSE; - } - - return TRUE; -} - -static NML3ConfigData * lease_to_ip6_config(NMDedupMultiIndex *multi_idx, const char *iface, int ifindex, @@ -952,7 +281,6 @@ ip6_start(NMDhcpClient *client, const struct in6_addr *ll_addr, GError **error) GBytes *duid; gboolean prefix_delegation; - g_return_val_if_fail(!priv->client4, FALSE); g_return_val_if_fail(!priv->client6, FALSE); client_config = nm_dhcp_client_get_config(client); @@ -1079,18 +407,13 @@ stop(NMDhcpClient *client, gboolean release) NM_DHCP_CLIENT_CLASS(nm_dhcp_systemd_parent_class)->stop(client, release); - _LOGT("dhcp-client%d: stop %p", - priv->client4 ? '4' : '6', - priv->client4 ? (gpointer) priv->client4 : (gpointer) priv->client6); + _LOGT("dhcp-client6: stop"); - if (priv->client4) { - sd_dhcp_client_set_callback(priv->client4, NULL, NULL); - r = sd_dhcp_client_stop(priv->client4); - } else if (priv->client6) { - sd_dhcp6_client_set_callback(priv->client6, NULL, NULL); - r = sd_dhcp6_client_stop(priv->client6); - } + if (!priv->client6) + return; + sd_dhcp6_client_set_callback(priv->client6, NULL, NULL); + r = sd_dhcp6_client_stop(priv->client6); if (r) _LOGW("failed to stop client (%d)", r); } @@ -1108,12 +431,6 @@ dispose(GObject *object) nm_clear_g_free(&priv->lease_file); - if (priv->client4) { - sd_dhcp_client_stop(priv->client4); - sd_dhcp_client_unref(priv->client4); - priv->client4 = NULL; - } - if (priv->client6) { sd_dhcp6_client_stop(priv->client6); sd_dhcp6_client_unref(priv->client6); @@ -1131,14 +448,13 @@ nm_dhcp_systemd_class_init(NMDhcpSystemdClass *sdhcp_class) object_class->dispose = dispose; - client_class->ip4_start = ip4_start; client_class->ip6_start = ip6_start; client_class->stop = stop; } const NMDhcpClientFactory _nm_dhcp_client_factory_systemd = { .name = "systemd", - .get_type_4 = nm_dhcp_systemd_get_type, + .get_type_4 = nm_dhcp_nettools_get_type, .get_type_6 = nm_dhcp_systemd_get_type, .undocumented = TRUE, }; diff --git a/src/core/dhcp/nm-dhcp-utils.c b/src/core/dhcp/nm-dhcp-utils.c index 081e284196..3ae7e6b71c 100644 --- a/src/core/dhcp/nm-dhcp-utils.c +++ b/src/core/dhcp/nm-dhcp-utils.c @@ -295,7 +295,7 @@ process_classful_routes(const char *iface, return; if ((NM_PTRARRAY_LEN(searches) % 2) != 0) { - _LOG2I(LOGD_DHCP, iface, " static routes provided, but invalid"); + _LOG2I(LOGD_DHCP4, iface, " static routes provided, but invalid"); return; } @@ -305,11 +305,11 @@ process_classful_routes(const char *iface, guint32 rt_addr, rt_route; if (inet_pton(AF_INET, *s, &rt_addr) <= 0) { - _LOG2W(LOGD_DHCP, iface, "DHCP provided invalid static route address: '%s'", *s); + _LOG2W(LOGD_DHCP4, iface, "DHCP provided invalid static route address: '%s'", *s); continue; } if (inet_pton(AF_INET, *(s + 1), &rt_route) <= 0) { - _LOG2W(LOGD_DHCP, iface, "DHCP provided invalid static route gateway: '%s'", *(s + 1)); + _LOG2W(LOGD_DHCP4, iface, "DHCP provided invalid static route gateway: '%s'", *(s + 1)); continue; } @@ -340,7 +340,7 @@ process_classful_routes(const char *iface, nm_l3_config_data_add_route_4(l3cd, &route); - _LOG2I(LOGD_DHCP, + _LOG2I(LOGD_DHCP4, iface, " static route %s", nm_platform_ip4_route_to_string(&route, sbuf, sizeof(sbuf))); @@ -352,6 +352,7 @@ process_domain_search(int addr_family, const char *iface, const char *str, NML3C { gs_free const char **searches = NULL; gs_free char *unescaped = NULL; + NMLogDomain logd = NM_IS_IPv4(addr_family) ? LOGD_DHCP4 : LOGD_DHCP6; const char **s; char *p; int i; @@ -373,13 +374,13 @@ process_domain_search(int addr_family, const char *iface, const char *str, NML3C } while (*p++); if (strchr(unescaped, '\\')) { - _LOG2W(LOGD_DHCP, iface, " invalid domain search: '%s'", unescaped); + _LOG2W(logd, iface, " invalid domain search: '%s'", unescaped); return; } searches = nm_strsplit_set(unescaped, " "); for (s = searches; searches && *s; s++) { - _LOG2I(LOGD_DHCP, iface, " domain search '%s'", *s); + _LOG2I(logd, iface, " domain search '%s'", *s); nm_l3_config_data_add_search(l3cd, addr_family, *s); } } @@ -822,26 +823,6 @@ nm_dhcp_utils_get_leasefile_path(int addr_family, return FALSE; } -char * -nm_dhcp_utils_get_dhcp6_event_id(GHashTable *lease) -{ - const char *start; - const char *iaid; - - if (!lease) - return NULL; - - iaid = g_hash_table_lookup(lease, "iaid"); - if (!iaid) - return NULL; - - start = g_hash_table_lookup(lease, "life_starts"); - if (!start) - return NULL; - - return g_strdup_printf("%s|%s", iaid, start); -} - gboolean nm_dhcp_utils_merge_new_dhcp6_lease(const NML3ConfigData *l3cd_old, const NML3ConfigData *l3cd_new, diff --git a/src/core/dns/nm-dns-dnsmasq.c b/src/core/dns/nm-dns-dnsmasq.c index 43426882ed..7d0f0490e0 100644 --- a/src/core/dns/nm-dns-dnsmasq.c +++ b/src/core/dns/nm-dns-dnsmasq.c @@ -678,19 +678,23 @@ typedef struct { char *name_owner; + GSource *main_timeout_source; + GSource *burst_retry_timeout_source; + gint64 burst_start_at; GPid process_pid; guint name_owner_changed_id; - guint main_timeout_id; - - guint burst_retry_timeout_id; guint8 burst_count; bool is_stopped : 1; + bool set_server_ex_args_dirty : 1; + + bool update_pending : 1; + } NMDnsDnsmasqPrivate; struct _NMDnsDnsmasq { @@ -704,7 +708,8 @@ struct _NMDnsDnsmasqClass { G_DEFINE_TYPE(NMDnsDnsmasq, nm_dns_dnsmasq, NM_TYPE_DNS_PLUGIN) -#define NM_DNS_DNSMASQ_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDnsDnsmasq, NM_IS_DNS_DNSMASQ) +#define NM_DNS_DNSMASQ_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMDnsDnsmasq, NM_IS_DNS_DNSMASQ, NMDnsPlugin) /*****************************************************************************/ @@ -717,6 +722,55 @@ static gboolean start_dnsmasq(NMDnsDnsmasq *self, gboolean force_start, GError * /*****************************************************************************/ +static gboolean +_update_pending_detect(NMDnsDnsmasq *self) +{ + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self); + + if (priv->is_stopped) + return FALSE; + if (priv->main_timeout_source) { + /* we are waiting for dnsmasq to start. */ + return TRUE; + } + if (priv->update_cancellable) { + /* An update is in progress. Busy. */ + return TRUE; + } + if (priv->set_server_ex_args_dirty) { + /* the args just changed and were not yet sent. Busy. */ + return TRUE; + } + + return FALSE; +} + +static void +_update_pending_maybe_changed(NMDnsDnsmasq *self) +{ + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self); + gboolean update_pending; + + update_pending = _update_pending_detect(self); + if (priv->update_pending == update_pending) + return; + + priv->update_pending = update_pending; + _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self)); +} + +static gboolean +get_update_pending(NMDnsPlugin *plugin) +{ + NMDnsDnsmasq *self = NM_DNS_DNSMASQ(plugin); + NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self); + + nm_assert(priv->update_pending == _update_pending_detect(self)); + return priv->update_pending; +} + +/*****************************************************************************/ + static void add_dnsmasq_nameserver(NMDnsDnsmasq *self, GVariantBuilder *servers, @@ -871,6 +925,7 @@ static void dnsmasq_update_done(GObject *source_object, GAsyncResult *res, gpointer user_data) { NMDnsDnsmasq *self; + NMDnsDnsmasqPrivate *priv; gs_free_error GError *error = NULL; gs_unref_variant GVariant *response = NULL; @@ -880,10 +935,16 @@ dnsmasq_update_done(GObject *source_object, GAsyncResult *res, gpointer user_dat return; self = user_data; + priv = NM_DNS_DNSMASQ_GET_PRIVATE(self); + + nm_clear_g_cancellable(&priv->update_cancellable); + if (!response) _LOGW("dnsmasq update failed: %s", error->message); else _LOGD("dnsmasq update successful"); + + _update_pending_maybe_changed(self); } static void @@ -899,6 +960,8 @@ send_dnsmasq_update(NMDnsDnsmasq *self) nm_clear_g_cancellable(&priv->update_cancellable); priv->update_cancellable = g_cancellable_new(); + priv->set_server_ex_args_dirty = FALSE; + g_dbus_connection_call(priv->dbus_connection, priv->name_owner, DNSMASQ_DBUS_PATH, @@ -911,6 +974,8 @@ send_dnsmasq_update(NMDnsDnsmasq *self) priv->update_cancellable, dnsmasq_update_done, self); + + _update_pending_maybe_changed(self); } /*****************************************************************************/ @@ -928,17 +993,19 @@ _main_cleanup(NMDnsDnsmasq *self, gboolean emit_failed) nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id); - nm_clear_g_source(&priv->main_timeout_id); + nm_clear_g_source_inst(&priv->main_timeout_source); nm_clear_g_cancellable(&priv->update_cancellable); /* cancelling the main_cancellable will also cause _gl_pid_spawn*() to terminate the * process in the background. */ nm_clear_g_cancellable(&priv->main_cancellable); - if (!priv->is_stopped && priv->burst_retry_timeout_id == 0) { + if (!priv->is_stopped && !priv->burst_retry_timeout_source) { start_dnsmasq(self, FALSE, NULL); send_dnsmasq_update(self); } + + _update_pending_maybe_changed(self); } static void @@ -961,8 +1028,10 @@ name_owner_changed(NMDnsDnsmasq *self, const char *name_owner) } _LOGT("D-Bus name for dnsmasq got owner %s", name_owner); - nm_clear_g_source(&priv->main_timeout_id); + nm_clear_g_source_inst(&priv->main_timeout_source); send_dnsmasq_update(self); + + _update_pending_maybe_changed(self); } static void @@ -1047,11 +1116,11 @@ _burst_retry_timeout_cb(gpointer user_data) NMDnsDnsmasq *self = user_data; NMDnsDnsmasqPrivate *priv = NM_DNS_DNSMASQ_GET_PRIVATE(self); - priv->burst_retry_timeout_id = 0; + nm_clear_g_source_inst(&priv->burst_retry_timeout_source); start_dnsmasq(self, TRUE, NULL); send_dnsmasq_update(self); - return G_SOURCE_REMOVE; + return G_SOURCE_CONTINUE; } static gboolean @@ -1090,33 +1159,35 @@ start_dnsmasq(NMDnsDnsmasq *self, gboolean force_start, GError **error) || priv->burst_start_at + RATELIMIT_INTERVAL_MSEC <= now) { priv->burst_start_at = now; priv->burst_count = 1; - nm_clear_g_source(&priv->burst_retry_timeout_id); + nm_clear_g_source_inst(&priv->burst_retry_timeout_source); _LOGT("rate-limit: start burst interval of %d seconds %s", RATELIMIT_INTERVAL_MSEC / 1000, force_start ? " (force)" : ""); } else if (priv->burst_count < RATELIMIT_BURST) { - nm_assert(priv->burst_retry_timeout_id == 0); + nm_assert(!priv->burst_retry_timeout_source); priv->burst_count++; _LOGT("rate-limit: %u try within burst interval of %d seconds", (guint) priv->burst_count, RATELIMIT_INTERVAL_MSEC / 1000); } else { - if (priv->burst_retry_timeout_id == 0) { + if (!priv->burst_retry_timeout_source) { _LOGW("dnsmasq dies and gets respawned too quickly. Back off. Something is very wrong"); - priv->burst_retry_timeout_id = - g_timeout_add_seconds((2 * RATELIMIT_INTERVAL_MSEC) / 1000, - _burst_retry_timeout_cb, - self); + priv->burst_retry_timeout_source = + nm_g_timeout_add_seconds_source((2 * RATELIMIT_INTERVAL_MSEC) / 1000, + _burst_retry_timeout_cb, + self); } else _LOGT("rate-limit: currently rate-limited from restart"); return TRUE; } - priv->main_timeout_id = g_timeout_add(10000, spawn_timeout_cb, self); + priv->main_timeout_source = nm_g_timeout_add_source(10000, spawn_timeout_cb, self); priv->main_cancellable = g_cancellable_new(); _gl_pid_spawn(dm_binary, priv->main_cancellable, spawn_notify, self); + + _update_pending_maybe_changed(self); return TRUE; } @@ -1136,8 +1207,11 @@ update(NMDnsPlugin *plugin, nm_clear_pointer(&priv->set_server_ex_args, g_variant_unref); priv->set_server_ex_args = g_variant_ref_sink(create_update_args(self, global_config, ip_data_lst_head, hostdomain)); + priv->set_server_ex_args_dirty = TRUE; send_dnsmasq_update(self); + + _update_pending_maybe_changed(self); return TRUE; } @@ -1151,11 +1225,13 @@ stop(NMDnsPlugin *plugin) priv->is_stopped = TRUE; priv->burst_start_at = 0; - nm_clear_g_source(&priv->burst_retry_timeout_id); + nm_clear_g_source_inst(&priv->burst_retry_timeout_source); /* Cancelling the cancellable will also terminate the * process (in the background). */ _main_cleanup(self, FALSE); + + _update_pending_maybe_changed(self); } /*****************************************************************************/ @@ -1178,7 +1254,7 @@ dispose(GObject *object) priv->is_stopped = TRUE; - nm_clear_g_source(&priv->burst_retry_timeout_id); + nm_clear_g_source_inst(&priv->burst_retry_timeout_source); _main_cleanup(self, FALSE); @@ -1197,8 +1273,9 @@ nm_dns_dnsmasq_class_init(NMDnsDnsmasqClass *dns_class) object_class->dispose = dispose; - plugin_class->plugin_name = "dnsmasq"; - plugin_class->is_caching = TRUE; - plugin_class->stop = stop; - plugin_class->update = update; + plugin_class->plugin_name = "dnsmasq"; + plugin_class->is_caching = TRUE; + plugin_class->stop = stop; + plugin_class->update = update; + plugin_class->get_update_pending = get_update_pending; } diff --git a/src/core/dns/nm-dns-manager.c b/src/core/dns/nm-dns-manager.c index 566f3d6626..1e54452aa4 100644 --- a/src/core/dns/nm-dns-manager.c +++ b/src/core/dns/nm-dns-manager.c @@ -26,7 +26,6 @@ #include "libnm-core-intern/nm-core-internal.h" #include "libnm-glib-aux/nm-str-buf.h" -#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "NetworkManagerUtils.h" #include "devices/nm-device.h" @@ -35,7 +34,6 @@ #include "nm-dns-dnsmasq.h" #include "nm-dns-plugin.h" #include "nm-dns-systemd-resolved.h" -#include "nm-dns-unbound.h" #include "nm-ip-config.h" #include "nm-l3-config-data.h" #include "nm-manager.h" @@ -57,6 +55,8 @@ #define HAS_NETCONFIG 1 #endif +#define UPDATE_PENDING_UNBLOCK_TIMEOUT_MSEC 5000 + /*****************************************************************************/ typedef enum { SR_SUCCESS, SR_NOTFOUND, SR_ERROR } SpawnResult; @@ -78,7 +78,11 @@ enum { LAST_SIGNAL }; -NM_GOBJECT_PROPERTIES_DEFINE(NMDnsManager, PROP_MODE, PROP_RC_MANAGER, PROP_CONFIGURATION, ); +NM_GOBJECT_PROPERTIES_DEFINE(NMDnsManager, + PROP_MODE, + PROP_RC_MANAGER, + PROP_CONFIGURATION, + PROP_UPDATE_PENDING, ); static guint signals[LAST_SIGNAL] = {0}; @@ -89,6 +93,11 @@ typedef struct { CList ip_data_lst_head; GVariant *config_variant; + /* A DNS plugin should not be marked as pending indefinitely. + * We are only blocked if "update_pending" is TRUE and we have + * "update_pending_unblock" timer ticking. */ + GSource *update_pending_unblock; + bool ip_data_lst_need_sort : 1; bool configs_lst_need_sort : 1; @@ -98,6 +107,8 @@ typedef struct { bool config_changed : 1; + bool update_pending : 1; + char *hostdomain; guint updates_queue; @@ -109,6 +120,9 @@ typedef struct { NMDnsPlugin *sd_resolve_plugin; NMDnsPlugin *plugin; + gulong update_changed_signal_id_sd; + gulong update_changed_signal_id; + NMConfig *config; struct { @@ -137,28 +151,23 @@ NM_DEFINE_SINGLETON_GETTER(NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER #define _NMLOG_PREFIX_NAME "dns-mgr" #define _NMLOG_DOMAIN LOGD_DNS -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ - char __prefix[20]; \ - const NMDnsManager *const __self = (self); \ - \ - _nm_log(__level, \ - _NMLOG_DOMAIN, \ - 0, \ - NULL, \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - ((!__self || __self == singleton_instance) \ - ? "" \ - : nm_sprintf_buf(__prefix, "[%p]", __self)) \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ +#define _NMLOG(level, ...) \ + G_STMT_START \ + { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ + _nm_unused const NMDnsManager *const __self = (self); \ + \ + _nm_log(__level, \ + _NMLOG_DOMAIN, \ + 0, \ + NULL, \ + NULL, \ + "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ G_STMT_END /*****************************************************************************/ @@ -207,6 +216,85 @@ static NM_UTILS_LOOKUP_STR_DEFINE( /*****************************************************************************/ +static gboolean +_update_pending_detect(NMDnsManager *self) +{ + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self); + + if (priv->plugin && nm_dns_plugin_get_update_pending(priv->plugin)) + return TRUE; + if (priv->sd_resolve_plugin && nm_dns_plugin_get_update_pending(priv->sd_resolve_plugin)) + return TRUE; + return FALSE; +} + +static gboolean +_update_pending_unblock_cb(gpointer user_data) +{ + NMDnsManager *self = user_data; + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self); + + nm_assert(priv->update_pending); + nm_assert(priv->update_pending_unblock); + nm_assert(_update_pending_detect(self)); + + nm_clear_g_source_inst(&priv->update_pending_unblock); + + _LOGW( + "update-pending changed: DNS plugin did not become ready again. Assume something is wrong"); + + _notify(self, PROP_UPDATE_PENDING); + return G_SOURCE_CONTINUE; +} + +static void +_update_pending_maybe_changed(NMDnsManager *self) +{ + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self); + gboolean update_pending; + + update_pending = _update_pending_detect(self); + if (priv->update_pending == update_pending) + return; + + if (update_pending) { + nm_assert(!priv->update_pending_unblock); + priv->update_pending_unblock = nm_g_timeout_add_source(UPDATE_PENDING_UNBLOCK_TIMEOUT_MSEC, + _update_pending_unblock_cb, + self); + } else + nm_clear_g_source_inst(&priv->update_pending_unblock); + + priv->update_pending = update_pending; + _LOGD("update-pending changed: %spending", update_pending ? "" : "not "); + _notify(self, PROP_UPDATE_PENDING); +} + +static void +_update_pending_changed_cb(NMDnsPlugin *plugin, gboolean update_pending, NMDnsManager *self) +{ + _update_pending_maybe_changed(self); +} + +gboolean +nm_dns_manager_get_update_pending(NMDnsManager *self) +{ + NMDnsManagerPrivate *priv; + + g_return_val_if_fail(NM_IS_DNS_MANAGER(self), FALSE); + + priv = NM_DNS_MANAGER_GET_PRIVATE(self); + nm_assert(priv->update_pending == _update_pending_detect(self)); + nm_assert(priv->update_pending || !priv->update_pending_unblock); + + /* update-pending can only be TRUE for a certain time (before we assume + * something is really wrong with the plugin). That is, as long as + * update_pending_unblock is ticking. */ + return !!priv->update_pending_unblock; +} + +/*****************************************************************************/ + static int _dns_config_ip_data_get_dns_priority1(const NML3ConfigData *l3cd, int addr_family) { @@ -2015,7 +2103,7 @@ nm_dns_manager_set_hostname(NMDnsManager *self, const char *hostname, gboolean s domain = hostname; } - if (!nm_sd_hostname_is_valid(domain, FALSE)) + if (!nm_hostname_is_valid(domain, FALSE)) domain = NULL; } } @@ -2120,6 +2208,7 @@ _clear_plugin(NMDnsManager *self) nm_clear_g_source(&priv->plugin_ratelimit.timer); if (priv->plugin) { + nm_clear_g_signal_handler(priv->plugin, &priv->update_changed_signal_id); nm_dns_plugin_stop(priv->plugin); g_clear_object(&priv->plugin); return TRUE; @@ -2127,6 +2216,20 @@ _clear_plugin(NMDnsManager *self) return FALSE; } +static gboolean +_clear_sd_resolved_plugin(NMDnsManager *self) +{ + NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE(self); + + if (priv->sd_resolve_plugin) { + nm_clear_g_signal_handler(priv->sd_resolve_plugin, &priv->update_changed_signal_id_sd); + nm_dns_plugin_stop(priv->sd_resolve_plugin); + g_clear_object(&priv->sd_resolve_plugin); + return TRUE; + } + return FALSE; +} + static NMDnsManagerResolvConfManager _check_resconf_immutable(NMDnsManagerResolvConfManager rc_manager) { @@ -2313,16 +2416,14 @@ again: priv->plugin = nm_dns_dnsmasq_new(); plugin_changed = TRUE; } - } else if (nm_streq0(mode, "unbound")) { - if (force_reload_plugin || !NM_IS_DNS_UNBOUND(priv->plugin)) { - _clear_plugin(self); - priv->plugin = nm_dns_unbound_new(); - plugin_changed = TRUE; - } } else { if (!NM_IN_STRSET(mode, "none", "default")) { - if (mode) - _LOGW("init: unknown dns mode '%s'", mode); + if (mode) { + if (nm_streq(mode, "unbound")) + _LOGW("init: ns mode 'unbound' was removed. Update your configuration"); + else + _LOGW("init: unknown dns mode '%s'", mode); + } mode = "default"; } if (_clear_plugin(self)) @@ -2359,7 +2460,7 @@ again: priv->sd_resolve_plugin = nm_dns_systemd_resolved_new(); systemd_resolved_changed = TRUE; } - } else if (nm_clear_g_object(&priv->sd_resolve_plugin)) + } else if (_clear_sd_resolved_plugin(self)) systemd_resolved_changed = TRUE; g_object_freeze_notify(G_OBJECT(self)); @@ -2390,6 +2491,23 @@ again: "")); } + if (plugin_changed && priv->plugin && priv->update_changed_signal_id == 0) { + priv->update_changed_signal_id = g_signal_connect(priv->plugin, + NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED, + G_CALLBACK(_update_pending_changed_cb), + self); + } + + if (systemd_resolved_changed && priv->sd_resolve_plugin + && priv->update_changed_signal_id_sd == 0) { + priv->update_changed_signal_id_sd = g_signal_connect(priv->sd_resolve_plugin, + NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED, + G_CALLBACK(_update_pending_changed_cb), + self); + } + + _update_pending_maybe_changed(self); + g_object_thaw_notify(G_OBJECT(self)); } @@ -2594,6 +2712,9 @@ get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) case PROP_CONFIGURATION: g_value_set_variant(value, _get_config_variant(self)); break; + case PROP_UPDATE_PENDING: + g_value_set_boolean(value, nm_dns_manager_get_update_pending(self)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); break; @@ -2641,9 +2762,11 @@ dispose(GObject *object) if (priv->config) g_signal_handlers_disconnect_by_func(priv->config, config_changed_cb, self); - g_clear_object(&priv->sd_resolve_plugin); + _clear_sd_resolved_plugin(self); _clear_plugin(self); + nm_clear_g_source_inst(&priv->update_pending_unblock); + c_list_for_each_entry_safe (ip_data, ip_data_safe, &priv->ip_data_lst_head, ip_data_lst) _dns_config_ip_data_free(ip_data); @@ -2719,6 +2842,13 @@ nm_dns_manager_class_init(NMDnsManagerClass *klass) NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_UPDATE_PENDING] = + g_param_spec_boolean(NM_DNS_MANAGER_UPDATE_PENDING, + "", + "", + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); signals[CONFIG_CHANGED] = g_signal_new(NM_DNS_MANAGER_CONFIG_CHANGED, diff --git a/src/core/dns/nm-dns-manager.h b/src/core/dns/nm-dns-manager.h index c30d4b3ac6..210f9f6cb3 100644 --- a/src/core/dns/nm-dns-manager.h +++ b/src/core/dns/nm-dns-manager.h @@ -80,9 +80,10 @@ typedef struct _NMDnsConfigData { (G_TYPE_INSTANCE_GET_CLASS((o), NM_TYPE_DNS_MANAGER, NMDnsManagerClass)) /* properties */ -#define NM_DNS_MANAGER_MODE "mode" -#define NM_DNS_MANAGER_RC_MANAGER "rc-manager" -#define NM_DNS_MANAGER_CONFIGURATION "configuration" +#define NM_DNS_MANAGER_MODE "mode" +#define NM_DNS_MANAGER_RC_MANAGER "rc-manager" +#define NM_DNS_MANAGER_CONFIGURATION "configuration" +#define NM_DNS_MANAGER_UPDATE_PENDING "update-pending" /* internal signals */ #define NM_DNS_MANAGER_CONFIG_CHANGED "config-changed" @@ -149,6 +150,8 @@ void nm_dns_manager_stop(NMDnsManager *self); NMDnsPlugin *nm_dns_manager_get_systemd_resolved(NMDnsManager *self); +gboolean nm_dns_manager_get_update_pending(NMDnsManager *self); + /*****************************************************************************/ char *nmtst_dns_create_resolv_conf(const char *const *searches, diff --git a/src/core/dns/nm-dns-plugin.c b/src/core/dns/nm-dns-plugin.c index 847d783996..41a0dbc138 100644 --- a/src/core/dns/nm-dns-plugin.c +++ b/src/core/dns/nm-dns-plugin.c @@ -17,11 +17,16 @@ /*****************************************************************************/ +enum { + UPDATE_PENDING_CHANGED, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = {0}; + typedef struct _NMDnsPluginPrivate { - GPid pid; - guint watch_id; - char *progname; - char *pidfile; + bool update_pending_inited : 1; + bool update_pending : 1; } NMDnsPluginPrivate; G_DEFINE_ABSTRACT_TYPE(NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT) @@ -32,26 +37,29 @@ G_DEFINE_ABSTRACT_TYPE(NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT) #define _NMLOG_PREFIX_NAME "dns-plugin" #define _NMLOG_DOMAIN LOGD_DNS -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - const NMLogLevel __level = (level); \ - \ - if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ - char __prefix[20]; \ - const NMDnsPlugin *const __self = (self); \ - \ - _nm_log(__level, \ - _NMLOG_DOMAIN, \ - 0, \ - NULL, \ - NULL, \ - "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - _NMLOG_PREFIX_NAME, \ - (!__self ? "" : nm_sprintf_buf(__prefix, "[%p]", __self)) \ - _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ +#define _NMLOG(level, ...) \ + G_STMT_START \ + { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) { \ + char __prefix[20]; \ + const NMDnsPlugin *const __self = (self); \ + \ + _nm_log(__level, \ + _NMLOG_DOMAIN, \ + 0, \ + NULL, \ + NULL, \ + "%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + (!__self ? "" \ + : nm_sprintf_buf(__prefix, \ + "[" NM_HASH_OBFUSCATE_PTR_FMT "]", \ + NM_HASH_OBFUSCATE_PTR( \ + __self))) _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } \ + } \ G_STMT_END /*****************************************************************************/ @@ -104,10 +112,109 @@ nm_dns_plugin_stop(NMDnsPlugin *self) /*****************************************************************************/ +static gboolean +_get_update_pending(NMDnsPlugin *self) +{ + NMDnsPluginClass *klass; + + nm_assert(NM_IS_DNS_PLUGIN(self)); + + klass = NM_DNS_PLUGIN_GET_CLASS(self); + if (klass->get_update_pending) { + if (klass->get_update_pending(self)) + return TRUE; + } + return FALSE; +} + +gboolean +nm_dns_plugin_get_update_pending(NMDnsPlugin *self) +{ + NMDnsPluginPrivate *priv; + + g_return_val_if_fail(NM_IS_DNS_PLUGIN(self), FALSE); + + priv = NM_DNS_PLUGIN_GET_PRIVATE(self); + + /* We cache the boolean and rely on the subclass to call + * _nm_dns_plugin_update_pending_maybe_changed(). The subclass + * anyway must get it right to notify us when the value (maybe) + * changes. By caching the value, the subclass is free to notify + * even if the value did not actually change. + * + * Also, this allows the base implementation to combine multiple + * sources/reasons (if we need that in the future). */ + + if (!priv->update_pending_inited) { + priv->update_pending_inited = TRUE; + priv->update_pending = _get_update_pending(self); + _LOGD("[%s] update-pending changed (%spending)", + nm_dns_plugin_get_name(self), + priv->update_pending ? "" : "not "); + } else + nm_assert(priv->update_pending == _get_update_pending(self)); + + return priv->update_pending; +} + +void +_nm_dns_plugin_update_pending_maybe_changed(NMDnsPlugin *self) +{ + NMDnsPluginPrivate *priv; + gboolean v; + + g_return_if_fail(NM_IS_DNS_PLUGIN(self)); + + priv = NM_DNS_PLUGIN_GET_PRIVATE(self); + + v = _get_update_pending(self); + + if (!priv->update_pending_inited) + priv->update_pending_inited = TRUE; + else if (priv->update_pending == v) + return; + + priv->update_pending = v; + + _LOGD("[%s] update-pending changed (%spending)", + nm_dns_plugin_get_name(self), + priv->update_pending ? "" : "not "); + + g_signal_emit(self, signals[UPDATE_PENDING_CHANGED], 0, (gboolean) priv->update_pending); +} + +/*****************************************************************************/ + static void nm_dns_plugin_init(NMDnsPlugin *self) -{} +{ + NMDnsPluginPrivate *priv; + + priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_DNS_PLUGIN, NMDnsPluginPrivate); + + self->_priv = priv; + + nm_assert(priv->update_pending_inited == FALSE); + nm_assert(priv->update_pending == FALSE); + + nm_shutdown_wait_obj_register_object(self, "dns-plugin"); +} static void -nm_dns_plugin_class_init(NMDnsPluginClass *plugin_class) -{} +nm_dns_plugin_class_init(NMDnsPluginClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + g_type_class_add_private(object_class, sizeof(NMDnsPluginPrivate)); + + signals[UPDATE_PENDING_CHANGED] = g_signal_new(NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED, + G_OBJECT_CLASS_TYPE(klass), + G_SIGNAL_RUN_FIRST, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN); +} diff --git a/src/core/dns/nm-dns-plugin.h b/src/core/dns/nm-dns-plugin.h index f9c424abfa..24d6083be1 100644 --- a/src/core/dns/nm-dns-plugin.h +++ b/src/core/dns/nm-dns-plugin.h @@ -19,8 +19,13 @@ #define NM_DNS_PLUGIN_GET_CLASS(obj) \ (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DNS_PLUGIN, NMDnsPluginClass)) +#define NM_DNS_PLUGIN_UPDATE_PENDING_CHANGED "update-pending-changed" + +struct _NMDnsPluginPrivate; + typedef struct { - GObject parent; + GObject parent; + struct _NMDnsPluginPrivate *_priv; } NMDnsPlugin; typedef struct { @@ -39,6 +44,8 @@ typedef struct { void (*stop)(NMDnsPlugin *self); + gboolean (*get_update_pending)(NMDnsPlugin *self); + const char *plugin_name; /* Types should set to TRUE if they start a local caching nameserver @@ -63,4 +70,8 @@ gboolean nm_dns_plugin_update(NMDnsPlugin *self, void nm_dns_plugin_stop(NMDnsPlugin *self); +gboolean nm_dns_plugin_get_update_pending(NMDnsPlugin *self); + +void _nm_dns_plugin_update_pending_maybe_changed(NMDnsPlugin *self); + #endif /* __NM_DNS_PLUGIN_H__ */ diff --git a/src/core/dns/nm-dns-systemd-resolved.c b/src/core/dns/nm-dns-systemd-resolved.c index c4993884d2..ac6fe5dedb 100644 --- a/src/core/dns/nm-dns-systemd-resolved.c +++ b/src/core/dns/nm-dns-systemd-resolved.c @@ -40,8 +40,8 @@ static const char *const DBUS_OP_SET_LINK_DNS_OVER_TLS = "SetLinkDNSOverTLS"; /*****************************************************************************/ typedef struct { - int ifindex; - CList configs_lst_head; + int ifindex; + GPtrArray *ip_data_list; } InterfaceConfig; typedef struct { @@ -50,6 +50,7 @@ typedef struct { GVariant *argument; NMDnsSystemdResolved *self; int ifindex; + int ref_count; } RequestItem; struct _NMDnsSystemdResolvedResolveHandle { @@ -82,10 +83,13 @@ typedef struct { char *dbus_owner; CList handle_lst_head; guint name_owner_changed_id; + guint n_pending; bool send_updates_warn_ratelimited : 1; bool try_start_blocked : 1; + bool stopped : 1; bool dbus_initied : 1; bool send_updates_waiting : 1; + bool update_pending : 1; /* These two variables ensure that the log is not spammed with * API (not) supported messages. * They can be removed when no distro uses systemd-resolved < v240 anymore @@ -106,7 +110,7 @@ struct _NMDnsSystemdResolvedClass { G_DEFINE_TYPE(NMDnsSystemdResolved, nm_dns_systemd_resolved, NM_TYPE_DNS_PLUGIN) #define NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMDnsSystemdResolved, NM_IS_DNS_SYSTEMD_RESOLVED) + _NM_GET_PRIVATE(self, NMDnsSystemdResolved, NM_IS_DNS_SYSTEMD_RESOLVED, NMDnsPlugin) /*****************************************************************************/ @@ -146,10 +150,88 @@ static void _resolve_start(NMDnsSystemdResolved *self, NMDnsSystemdResolvedResol /*****************************************************************************/ +static gboolean +_update_pending_detect(NMDnsSystemdResolved *self) +{ + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + + if (priv->n_pending > 0) { + /* we have pending calls. We definitely want to wait for them to complete. */ + return TRUE; + } + if (!priv->dbus_initied) { + if (!priv->dbus_connection) + return FALSE; + /* D-Bus not yet initialized (and we don't know the name owner yet). Pending. */ + return TRUE; + } + if (priv->try_start_timeout_source) { + /* We are waiting to D-Bus activate resolved. Pending. */ + return TRUE; + } + if (priv->try_start_blocked) { + /* We earlier tried to start resolved, but are rate limited. We are not pending an update + * (that we expect to complete any time soon). */ + return FALSE; + } + if (priv->send_updates_waiting) { + /* we wait to send updates. We are pending. */ + return TRUE; + } + return FALSE; +} + static void -_request_item_free(RequestItem *request_item) +_update_pending_maybe_changed(NMDnsSystemdResolved *self) { - c_list_unlink_stale(&request_item->request_queue_lst); + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + gboolean update_pending; + + /* Important: we need to make sure that we call _update_pending_maybe_changed(), when + * the state changes. */ + + update_pending = _update_pending_detect(self); + if (priv->update_pending != update_pending) { + priv->update_pending = update_pending; + _nm_dns_plugin_update_pending_maybe_changed(NM_DNS_PLUGIN(self)); + } +} + +static gboolean +get_update_pending(NMDnsPlugin *plugin) +{ + NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin); + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + + nm_assert(priv->update_pending == _update_pending_detect(self)); + return priv->update_pending; +} + +/*****************************************************************************/ + +static RequestItem * +_request_item_ref(RequestItem *request_item) +{ + nm_assert(request_item); + nm_assert(request_item->ref_count > 0); + nm_assert(request_item->ref_count < G_MAXINT); + nm_assert(!c_list_is_empty(&request_item->request_queue_lst)); + + request_item->ref_count++; + return request_item; +} + +static void +_request_item_unref(RequestItem *request_item) +{ + nm_assert(request_item); + nm_assert(request_item->ref_count > 0); + + if (--request_item->ref_count > 0) + return; + + nm_assert(c_list_is_empty(&request_item->request_queue_lst)); + g_variant_unref(request_item->argument); nm_g_slice_free(request_item); } @@ -165,6 +247,7 @@ _request_item_append(NMDnsSystemdResolved *self, request_item = g_slice_new(RequestItem); *request_item = (RequestItem){ + .ref_count = 1, .operation = operation, .argument = g_variant_ref_sink(argument), .self = self, @@ -178,8 +261,8 @@ _request_item_append(NMDnsSystemdResolved *self, static void _interface_config_free(InterfaceConfig *config) { - nm_c_list_elem_free_all(&config->configs_lst_head, NULL); - g_slice_free(InterfaceConfig, config); + nm_g_ptr_array_unref(config->ip_data_list); + nm_g_slice_free(config); } static void @@ -191,42 +274,48 @@ call_done(GObject *source, GAsyncResult *r, gpointer user_data) NMDnsSystemdResolvedPrivate *priv; RequestItem *request_item; NMLogLevel log_level; - - v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), r, &error); - if (nm_utils_error_is_cancelled(error)) - return; + const char *operation; + int ifindex; request_item = user_data; self = request_item->self; - priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + operation = request_item->operation; + ifindex = request_item->ifindex; + _request_item_unref(request_item); + + priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + + v = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), r, &error); + if (nm_utils_error_is_cancelled(error)) + goto out_dec_pending; if (v) { - if (request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE + if (operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE && priv->has_link_default_route == NM_TERNARY_DEFAULT) { priv->has_link_default_route = NM_TERNARY_TRUE; _LOGD("systemd-resolved support for SetLinkDefaultRoute(): API supported"); } - if (request_item->operation == DBUS_OP_SET_LINK_DNS_OVER_TLS + if (operation == DBUS_OP_SET_LINK_DNS_OVER_TLS && priv->has_link_dns_over_tls == NM_TERNARY_DEFAULT) { priv->has_link_dns_over_tls = NM_TERNARY_TRUE; _LOGD("systemd-resolved support for SetLinkDNSOverTLS(): API supported"); } priv->send_updates_warn_ratelimited = FALSE; - return; + goto out_dec_pending; } if (nm_g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) { if (priv->has_link_default_route == NM_TERNARY_DEFAULT - && request_item->operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE) { + && operation == DBUS_OP_SET_LINK_DEFAULT_ROUTE) { priv->has_link_default_route = NM_TERNARY_FALSE; _LOGD("systemd-resolved support for SetLinkDefaultRoute(): API not supported"); } if (priv->has_link_dns_over_tls == NM_TERNARY_DEFAULT - && request_item->operation == DBUS_OP_SET_LINK_DNS_OVER_TLS) { + && operation == DBUS_OP_SET_LINK_DNS_OVER_TLS) { priv->has_link_dns_over_tls = NM_TERNARY_FALSE; _LOGD("systemd-resolved support for SetLinkDNSOverTLS(): API not supported"); } - return; + goto out_dec_pending; } log_level = LOGL_DEBUG; @@ -234,18 +323,25 @@ call_done(GObject *source, GAsyncResult *r, gpointer user_data) priv->send_updates_warn_ratelimited = TRUE; log_level = LOGL_WARN; } - _NMLOG(log_level, - "send-updates %s@%d failed: %s", - request_item->operation, - request_item->ifindex, - error->message); + _NMLOG(log_level, "send-updates %s@%d failed: %s", operation, ifindex, error->message); + +out_dec_pending: + nm_assert(priv->n_pending > 0); + if (--priv->n_pending <= 0) { + _update_pending_maybe_changed(self); + /* We keep @self alive while pending operations are in progress. It's simpler + * to implement. But this requires that we implement "stop()" signal to cancel + * all pending requests. Cancelling is necessary, because during shutdown, + * we must wrap up fast, and not hang an undefined amount time. */ + g_object_unref(self); + } } static gboolean -update_add_ip_config(NMDnsSystemdResolved *self, - GVariantBuilder *dns, - GVariantBuilder *domains, - NMDnsConfigIPData *ip_data) +update_add_ip_config(NMDnsSystemdResolved *self, + GVariantBuilder *dns, + GVariantBuilder *domains, + const NMDnsConfigIPData *ip_data) { gsize addr_size; guint n; @@ -258,8 +354,12 @@ update_add_ip_config(NMDnsSystemdResolved *self, addr_size = nm_utils_addr_family_to_size(ip_data->addr_family); if ((!ip_data->domains.search || !ip_data->domains.search[0]) - && !ip_data->domains.has_default_route_exclusive && !ip_data->domains.has_default_route) + && !ip_data->domains.has_default_route_exclusive && !ip_data->domains.has_default_route) { + /* we have no search domain (which systemd-resolved uses to routing the request), but + * also the "DefaultRoute" is not set on the interface. This setting has no effect and + * gets ignored. */ return FALSE; + } nameservers = nm_l3_config_data_get_nameservers(ip_data->l3cd, ip_data->addr_family, &n); for (i = 0; i < n; i++) { @@ -295,23 +395,28 @@ free_pending_updates(NMDnsSystemdResolved *self) NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); RequestItem *request_item; - while ((request_item = - c_list_first_entry(&priv->request_queue_lst_head, RequestItem, request_queue_lst))) - _request_item_free(request_item); + while ( + (request_item = + c_list_first_entry(&priv->request_queue_lst_head, RequestItem, request_queue_lst))) { + c_list_unlink(&request_item->request_queue_lst); + _request_item_unref(request_item); + } } static gboolean -prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic) +prepare_one_interface(NMDnsSystemdResolved *self, const InterfaceConfig *ic) { GVariantBuilder dns; GVariantBuilder domains; - NMCListElem *elem; - NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; - NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; - NMSettingConnectionDnsOverTls dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT; - const char *mdns_arg = NULL, *llmnr_arg = NULL, *dns_over_tls_arg = NULL; + NMSettingConnectionMdns mdns = NM_SETTING_CONNECTION_MDNS_DEFAULT; + NMSettingConnectionLlmnr llmnr = NM_SETTING_CONNECTION_LLMNR_DEFAULT; + NMSettingConnectionDnsOverTls dns_over_tls = NM_SETTING_CONNECTION_DNS_OVER_TLS_DEFAULT; + const char *mdns_arg = NULL; + const char *llmnr_arg = NULL; + const char *dns_over_tls_arg = NULL; gboolean has_config = FALSE; gboolean has_default_route = FALSE; + guint i; g_variant_builder_init(&dns, G_VARIANT_TYPE("(ia(iay))")); g_variant_builder_add(&dns, "i", ic->ifindex); @@ -321,18 +426,22 @@ prepare_one_interface(NMDnsSystemdResolved *self, InterfaceConfig *ic) g_variant_builder_add(&domains, "i", ic->ifindex); g_variant_builder_open(&domains, G_VARIANT_TYPE("a(sb)")); - c_list_for_each_entry (elem, &ic->configs_lst_head, lst) { - NMDnsConfigIPData *ip_data = elem->data; + if (ic->ip_data_list) { + for (i = 0; i < ic->ip_data_list->len; i++) { + const NMDnsConfigIPData *ip_data = ic->ip_data_list->pdata[i]; - has_config |= update_add_ip_config(self, &dns, &domains, ip_data); + if (update_add_ip_config(self, &dns, &domains, ip_data)) + has_config = TRUE; - if (ip_data->domains.has_default_route) - has_default_route = TRUE; + if (ip_data->domains.has_default_route) + has_default_route = TRUE; - if (NM_IS_IPv4(ip_data->addr_family)) { - mdns = NM_MAX(mdns, nm_l3_config_data_get_mdns(ip_data->l3cd)); - llmnr = NM_MAX(llmnr, nm_l3_config_data_get_llmnr(ip_data->l3cd)); - dns_over_tls = NM_MAX(dns_over_tls, nm_l3_config_data_get_dns_over_tls(ip_data->l3cd)); + if (NM_IS_IPv4(ip_data->addr_family)) { + mdns = NM_MAX(mdns, nm_l3_config_data_get_mdns(ip_data->l3cd)); + llmnr = NM_MAX(llmnr, nm_l3_config_data_get_llmnr(ip_data->l3cd)); + dns_over_tls = + NM_MAX(dns_over_tls, nm_l3_config_data_get_dns_over_tls(ip_data->l3cd)); + } } } @@ -439,6 +548,7 @@ again: goto again; } + _update_pending_maybe_changed(self); return G_SOURCE_CONTINUE; } @@ -447,6 +557,9 @@ ensure_resolved_running(NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + if (priv->stopped) + return NM_TERNARY_FALSE; + if (!priv->dbus_initied) return NM_TERNARY_DEFAULT; @@ -469,6 +582,7 @@ ensure_resolved_running(NMDnsSystemdResolved *self) NULL, NULL, NULL); + _update_pending_maybe_changed(self); return NM_TERNARY_DEFAULT; } @@ -523,6 +637,12 @@ send_updates(NMDnsSystemdResolved *self) request_item->operation, (ss = g_variant_print(request_item->argument, FALSE))); + if (priv->n_pending++ == 0) { + /* We are inside send_updates(). All callers are already calling + * _update_pending_maybe_changed() afterwards. */ + g_object_ref(self); + } + g_dbus_connection_call(priv->dbus_connection, priv->dbus_owner, SYSTEMD_RESOLVED_DBUS_PATH, @@ -534,7 +654,7 @@ send_updates(NMDnsSystemdResolved *self) -1, priv->cancellable, call_done, - request_item); + _request_item_ref(request_item)); } start_resolve: @@ -554,43 +674,54 @@ update(NMDnsPlugin *plugin, const char *hostdomain, GError **error) { - NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin); - NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); - gs_unref_hashtable GHashTable *interfaces = NULL; - gs_free gpointer *interfaces_keys = NULL; + NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin); + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + gs_unref_hashtable GHashTable *interfaces = NULL; + const NMUtilsNamedValue *interfaces_arr; + NMUtilsNamedValue interfaces_arr_stack[50]; + gs_free NMUtilsNamedValue *interfaces_arr_heap = NULL; guint interfaces_len; - int ifindex; gpointer pointer; NMDnsConfigIPData *ip_data; GHashTableIter iter; + gs_unref_array GArray *dirty_array = NULL; guint i; + nm_assert(!priv->stopped); + + /* Group configs by ifindex/interfaces. */ interfaces = g_hash_table_new_full(nm_direct_hash, NULL, NULL, (GDestroyNotify) _interface_config_free); c_list_for_each_entry (ip_data, ip_data_lst_head, ip_data_lst) { - InterfaceConfig *ic = NULL; + InterfaceConfig *ic = NULL; + int ifindex = ip_data->data->ifindex; - ifindex = ip_data->data->ifindex; nm_assert(ifindex == nm_l3_config_data_get_ifindex(ip_data->l3cd)); ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(ifindex)); if (!ic) { - ic = g_slice_new(InterfaceConfig); - ic->ifindex = ifindex; - c_list_init(&ic->configs_lst_head); + ic = g_slice_new(InterfaceConfig); + *ic = (InterfaceConfig){ + .ifindex = ifindex, + .ip_data_list = g_ptr_array_sized_new(4), + }; g_hash_table_insert(interfaces, GINT_TO_POINTER(ifindex), ic); } - c_list_link_tail(&ic->configs_lst_head, &nm_c_list_elem_new_stale(ip_data)->lst); + g_ptr_array_add(ic->ip_data_list, ip_data); } free_pending_updates(self); - interfaces_keys = - nm_utils_hash_keys_to_array(interfaces, nm_cmp_int2ptr_p_with_data, NULL, &interfaces_len); + interfaces_arr = nm_utils_hash_to_array_with_buffer(interfaces, + &interfaces_len, + nm_cmp_int2ptr_p_with_data, + NULL, + interfaces_arr_stack, + &interfaces_arr_heap); for (i = 0; i < interfaces_len; i++) { - InterfaceConfig *ic = g_hash_table_lookup(interfaces, GINT_TO_POINTER(interfaces_keys[i])); + const InterfaceConfig *ic = interfaces_arr[i].value_ptr; if (prepare_one_interface(self, ic)) g_hash_table_add(priv->dirty_interfaces, GINT_TO_POINTER(ic->ifindex)); @@ -602,23 +733,38 @@ update(NMDnsPlugin *plugin, * resolved, and the current update doesn't contain that interface, * reset the resolved configuration for that ifindex. */ g_hash_table_iter_init(&iter, priv->dirty_interfaces); - while (g_hash_table_iter_next(&iter, (gpointer *) &pointer, NULL)) { - ifindex = GPOINTER_TO_INT(pointer); - if (!g_hash_table_contains(interfaces, GINT_TO_POINTER(ifindex))) { + while (g_hash_table_iter_next(&iter, &pointer, NULL)) { + int ifindex = GPOINTER_TO_INT(pointer); + + if (g_hash_table_contains(interfaces, GINT_TO_POINTER(ifindex))) { + /* the interface is still tracked and still dirty. Keep. */ + continue; + } + + if (!dirty_array) + dirty_array = g_array_new(FALSE, FALSE, sizeof(int)); + g_array_append_val(dirty_array, ifindex); + + g_hash_table_iter_remove(&iter); + } + if (dirty_array) { + g_array_sort_with_data(dirty_array, nm_cmp_int2ptr_p_with_data, NULL); + for (i = 0; i < dirty_array->len; i++) { + int ifindex = g_array_index(dirty_array, int, i); InterfaceConfig ic; _LOGT("clear previously configured ifindex %d", ifindex); ic = (InterfaceConfig){ - .ifindex = ifindex, - .configs_lst_head = C_LIST_INIT(ic.configs_lst_head), + .ifindex = ifindex, + .ip_data_list = NULL, }; prepare_one_interface(self, &ic); - g_hash_table_iter_remove(&iter); } } priv->send_updates_waiting = TRUE; send_updates(self); + _update_pending_maybe_changed(self); return TRUE; } @@ -649,6 +795,7 @@ name_owner_changed(NMDnsSystemdResolved *self, const char *owner) } send_updates(self); + _update_pending_maybe_changed(self); } static void @@ -957,6 +1104,48 @@ nm_dns_systemd_resolved_resolve_cancel(NMDnsSystemdResolvedResolveHandle *handle /*****************************************************************************/ static void +stop(NMDnsPlugin *plugin) +{ + NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(plugin); + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); + NMDnsSystemdResolvedResolveHandle *handle; + + /* This function must be re-entrant!! + * + * Currently there is no concept of unregistering/shutting down. It's not + * clear whether we should de-configure anything in systemd-resolved, we + * don't. + * + * Implementing stop() is important because pending operations take a + * reference on @self. We can only cancel (fast shutdown) the instance + * by cancelling those requests. */ + + priv->stopped = TRUE; + priv->try_start_blocked = TRUE; + + nm_clear_g_cancellable(&priv->cancellable); + + nm_clear_g_free(&priv->dbus_owner); + + while ((handle = c_list_first_entry(&priv->handle_lst_head, + NMDnsSystemdResolvedResolveHandle, + handle_lst))) { + gs_free_error GError *error = NULL; + + nm_utils_error_set_cancelled(&error, TRUE, "NMDnsSystemdResolved"); + _resolve_complete_error(handle, error); + } + + free_pending_updates(self); + + nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id); + + nm_clear_g_source_inst(&priv->try_start_timeout_source); +} + +/*****************************************************************************/ + +static void nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); @@ -974,6 +1163,8 @@ nm_dns_systemd_resolved_init(NMDnsSystemdResolved *self) return; } + priv->update_pending = TRUE; + priv->name_owner_changed_id = nm_dbus_connection_signal_subscribe_name_owner_changed(priv->dbus_connection, SYSTEMD_RESOLVED_DBUS_SERVICE, @@ -998,33 +1189,15 @@ nm_dns_systemd_resolved_new(void) static void dispose(GObject *object) { - NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(object); - NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); - NMDnsSystemdResolvedResolveHandle *handle; - - while ((handle = c_list_first_entry(&priv->handle_lst_head, - NMDnsSystemdResolvedResolveHandle, - handle_lst))) { - gs_free_error GError *error = NULL; - - nm_utils_error_set_cancelled(&error, TRUE, "NMDnsSystemdResolved"); - _resolve_complete_error(handle, error); - } - - free_pending_updates(self); - - nm_clear_g_dbus_connection_signal(priv->dbus_connection, &priv->name_owner_changed_id); + NMDnsSystemdResolved *self = NM_DNS_SYSTEMD_RESOLVED(object); + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE(self); - nm_clear_g_cancellable(&priv->cancellable); - - nm_clear_g_source_inst(&priv->try_start_timeout_source); + stop(NM_DNS_PLUGIN(self)); g_clear_object(&priv->dbus_connection); - nm_clear_pointer(&priv->dirty_interfaces, g_hash_table_unref); + nm_clear_pointer(&priv->dirty_interfaces, g_hash_table_destroy); G_OBJECT_CLASS(nm_dns_systemd_resolved_parent_class)->dispose(object); - - nm_clear_g_free(&priv->dbus_owner); } static void @@ -1035,7 +1208,9 @@ nm_dns_systemd_resolved_class_init(NMDnsSystemdResolvedClass *dns_class) object_class->dispose = dispose; - plugin_class->plugin_name = "systemd-resolved"; - plugin_class->is_caching = TRUE; - plugin_class->update = update; + plugin_class->plugin_name = "systemd-resolved"; + plugin_class->is_caching = TRUE; + plugin_class->stop = stop; + plugin_class->update = update; + plugin_class->get_update_pending = get_update_pending; } diff --git a/src/core/dns/nm-dns-unbound.c b/src/core/dns/nm-dns-unbound.c deleted file mode 100644 index 8a75cf08f0..0000000000 --- a/src/core/dns/nm-dns-unbound.c +++ /dev/null @@ -1,84 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2014 Red Hat, Inc. - * Author: Pavel Å imerda <psimerda@redhat.com> - */ - -#include "src/core/nm-default-daemon.h" - -#include "nm-dns-unbound.h" - -#include "NetworkManagerUtils.h" - -/*****************************************************************************/ - -struct _NMDnsUnbound { - NMDnsPlugin parent; -}; - -struct _NMDnsUnboundClass { - NMDnsPluginClass parent; -}; - -G_DEFINE_TYPE(NMDnsUnbound, nm_dns_unbound, NM_TYPE_DNS_PLUGIN) - -/*****************************************************************************/ - -static gboolean -update(NMDnsPlugin *plugin, - const NMGlobalDnsConfig *global_config, - const CList *ip_config_lst_head, - const char *hostdomain, - GError **error) -{ - char *argv[] = {DNSSEC_TRIGGER_PATH, "--async", "--update", NULL}; - gs_free_error GError *local = NULL; - int status; - - /* TODO: We currently call a script installed with the dnssec-trigger - * package that queries all information itself. Later, the dependency - * on that package will be optional and the only hard dependency will - * be unbound. - * - * Unbound configuration should be later handled by this plugin directly, - * without calling custom scripts. The dnssec-trigger functionality - * may be eventually merged into NetworkManager. - */ - if (!g_spawn_sync("/", argv, NULL, 0, NULL, NULL, NULL, NULL, &status, &local)) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "error spawning dns-trigger: %s", - local->message); - return FALSE; - } - if (status != 0) { - nm_utils_error_set(error, - NM_UTILS_ERROR_UNKNOWN, - "dns-trigger exited with error code %d", - status); - return FALSE; - } - return TRUE; -} - -/*****************************************************************************/ - -static void -nm_dns_unbound_init(NMDnsUnbound *unbound) -{} - -NMDnsPlugin * -nm_dns_unbound_new(void) -{ - return g_object_new(NM_TYPE_DNS_UNBOUND, NULL); -} - -static void -nm_dns_unbound_class_init(NMDnsUnboundClass *klass) -{ - NMDnsPluginClass *plugin_class = NM_DNS_PLUGIN_CLASS(klass); - - plugin_class->plugin_name = "unbound"; - plugin_class->is_caching = TRUE; - plugin_class->update = update; -} diff --git a/src/core/dns/nm-dns-unbound.h b/src/core/dns/nm-dns-unbound.h deleted file mode 100644 index feb3309913..0000000000 --- a/src/core/dns/nm-dns-unbound.h +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ -/* - * Copyright (C) 2014 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DNS_UNBOUND_H__ -#define __NETWORKMANAGER_DNS_UNBOUND_H__ - -#include "nm-dns-plugin.h" - -#define NM_TYPE_DNS_UNBOUND (nm_dns_unbound_get_type()) -#define NM_DNS_UNBOUND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_DNS_UNBOUND, NMDnsUnbound)) -#define NM_DNS_UNBOUND_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_DNS_UNBOUND, NMDnsUnboundClass)) -#define NM_IS_DNS_UNBOUND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_DNS_UNBOUND)) -#define NM_IS_DNS_UNBOUND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_DNS_UNBOUND)) -#define NM_DNS_UNBOUND_GET_CLASS(obj) \ - (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_DNS_UNBOUND, NMDnsUnboundClass)) - -typedef struct _NMDnsUnbound NMDnsUnbound; -typedef struct _NMDnsUnboundClass NMDnsUnboundClass; - -GType nm_dns_unbound_get_type(void); - -NMDnsPlugin *nm_dns_unbound_new(void); - -#endif /* __NETWORKMANAGER_DNS_UNBOUND_H__ */ diff --git a/src/core/meson.build b/src/core/meson.build index 2148d23b76..f3359ad0f5 100644 --- a/src/core/meson.build +++ b/src/core/meson.build @@ -123,7 +123,6 @@ libNetworkManager = static_library( 'dns/nm-dns-manager.c', 'dns/nm-dns-plugin.c', 'dns/nm-dns-systemd-resolved.c', - 'dns/nm-dns-unbound.c', 'dnsmasq/nm-dnsmasq-manager.c', 'dnsmasq/nm-dnsmasq-utils.c', 'ppp/nm-ppp-manager-call.c', diff --git a/src/core/nm-config.c b/src/core/nm-config.c index ea1c2ab300..cdc070900f 100644 --- a/src/core/nm-config.c +++ b/src/core/nm-config.c @@ -11,7 +11,9 @@ #include <stdio.h> #include "nm-utils.h" +#include "nm-dhcp-config.h" #include "devices/nm-device.h" +#include "dhcp/nm-dhcp-options.h" #include "NetworkManagerUtils.h" #include "libnm-core-intern/nm-core-internal.h" #include "libnm-core-intern/nm-keyfile-internal.h" @@ -2573,13 +2575,16 @@ nm_config_device_state_write(int ifindex, NMTernary nm_owned, guint32 route_metric_default_aspired, guint32 route_metric_default_effective, - const char *next_server, - const char *root_path, - const char *dhcp_bootfile) + NMDhcpConfig *dhcp4_config, + NMDhcpConfig *dhcp6_config) { char path[NM_STRLEN(NM_CONFIG_DEVICE_STATE_DIR "/") + DEVICE_STATE_FILENAME_LEN_MAX + 1]; - GError *local = NULL; - nm_auto_unref_keyfile GKeyFile *kf = NULL; + GError *local = NULL; + nm_auto_unref_keyfile GKeyFile *kf = NULL; + const char *root_path = NULL; + const char *next_server = NULL; + const char *dhcp_bootfile = NULL; + int IS_IPv4; g_return_val_if_fail(ifindex > 0, FALSE); g_return_val_if_fail(!connection_uuid || *connection_uuid, FALSE); @@ -2630,6 +2635,15 @@ nm_config_device_state_write(int ifindex, route_metric_default_aspired); } } + + if (dhcp4_config) { + next_server = nm_dhcp_config_get_option(dhcp4_config, "next_server"); + root_path = nm_dhcp_config_get_option(dhcp4_config, "root_path"); + dhcp_bootfile = nm_dhcp_config_get_option(dhcp4_config, "filename"); + if (!dhcp_bootfile) + dhcp_bootfile = nm_dhcp_config_get_option(dhcp4_config, "bootfile_name"); + } + if (next_server) { g_key_file_set_string(kf, DEVICE_RUN_STATE_KEYFILE_GROUP_DEVICE, @@ -2649,6 +2663,28 @@ nm_config_device_state_write(int ifindex, dhcp_bootfile); } + for (IS_IPv4 = 1; IS_IPv4 >= 0; IS_IPv4--) { + NMDhcpConfig *dhcp_config = IS_IPv4 ? dhcp4_config : dhcp6_config; + gs_free NMUtilsNamedValue *values = NULL; + guint i; + guint num; + + if (!dhcp_config) + continue; + + values = nm_dhcp_config_get_option_values(dhcp_config, &num); + for (i = 0; i < num; i++) { + gs_free char *name_full = NULL; + const char *prefix = IS_IPv4 ? "dhcp4" : "dhcp6"; + + if (NM_STR_HAS_PREFIX(values[i].name, NM_DHCP_OPTION_REQPREFIX)) + continue; + + name_full = g_strdup_printf("%s.%s", prefix, values[i].name); + g_key_file_set_string(kf, prefix, name_full, values[i].value_str); + } + } + if (!g_key_file_save_to_file(kf, path, &local)) { _LOGW("device-state: write #%d (%s) failed: %s", ifindex, path, local->message); g_error_free(local); diff --git a/src/core/nm-config.h b/src/core/nm-config.h index 2c23ff200e..d7498f92be 100644 --- a/src/core/nm-config.h +++ b/src/core/nm-config.h @@ -183,9 +183,8 @@ gboolean nm_config_device_state_write(int NMTernary nm_owned, guint32 route_metric_default_aspired, guint32 route_metric_default_effective, - const char *next_server, - const char *root_path, - const char *dhcp_bootfile); + NMDhcpConfig *dhcp4_config, + NMDhcpConfig *dhcp6_config); void nm_config_device_state_prune_stale(GHashTable *preserve_ifindexes, NMPlatform *preserve_in_platform); diff --git a/src/core/nm-core-utils.c b/src/core/nm-core-utils.c index c8b789b30a..b2ebe30c25 100644 --- a/src/core/nm-core-utils.c +++ b/src/core/nm-core-utils.c @@ -30,7 +30,6 @@ #include "libnm-glib-aux/nm-secret-utils.h" #include "libnm-glib-aux/nm-time-utils.h" #include "libnm-glib-aux/nm-str-buf.h" -#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "nm-utils.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-setting-connection.h" @@ -5114,7 +5113,7 @@ nm_utils_spawn_helper(const char *const *args, fcntl(info->child_stdout, F_SETFL, fd_flags | O_NONBLOCK); /* Watch process stdin */ - nm_str_buf_init(&info->out_buffer, 32, TRUE); + info->out_buffer = NM_STR_BUF_INIT(32, TRUE); for (arg = args; *arg; arg++) { nm_str_buf_append(&info->out_buffer, *arg); nm_str_buf_append_c(&info->out_buffer, '\0'); @@ -5128,7 +5127,7 @@ nm_utils_spawn_helper(const char *const *args, g_source_attach(info->output_source, g_main_context_get_thread_default()); /* Watch process stdout */ - nm_str_buf_init(&info->in_buffer, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); + info->in_buffer = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); info->input_source = nm_g_unix_fd_source_new(info->child_stdout, G_IO_IN | G_IO_ERR | G_IO_HUP, G_PRIORITY_DEFAULT, @@ -5223,7 +5222,7 @@ again: * @shortened: (out) (transfer full): on return, the shortened hostname * * Checks whether the input hostname is valid. If not, tries to shorten it - * to HOST_NAME_MAX or to the first dot, whatever comes earlier. + * to HOST_NAME_MAX (64) or to the first dot, whatever comes earlier. * The new hostname is returned in @shortened. * * Returns: %TRUE if the input hostname was already valid or if was shortened @@ -5239,7 +5238,7 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened) nm_assert(hostname); nm_assert(shortened); - if (nm_sd_hostname_is_valid(hostname, FALSE)) { + if (nm_hostname_is_valid(hostname, FALSE)) { *shortened = NULL; return TRUE; } @@ -5249,11 +5248,11 @@ nm_utils_shorten_hostname(const char *hostname, char **shortened) l = (dot - hostname); else l = strlen(hostname); - l = MIN(l, (gsize) HOST_NAME_MAX); + l = MIN(l, (gsize) NM_HOST_NAME_MAX); s = g_strndup(hostname, l); - if (!nm_sd_hostname_is_valid(s, FALSE)) { + if (!nm_hostname_is_valid(s, FALSE)) { *shortened = NULL; return FALSE; } diff --git a/src/core/nm-dhcp-config.c b/src/core/nm-dhcp-config.c index b32c9b7056..394a3a4924 100644 --- a/src/core/nm-dhcp-config.c +++ b/src/core/nm-dhcp-config.c @@ -125,6 +125,29 @@ nm_dhcp_config_set_lease(NMDhcpConfig *self, const NML3ConfigData *l3cd) _notify(self, PROP_OPTIONS); } +NMUtilsNamedValue * +nm_dhcp_config_get_option_values(NMDhcpConfig *self, guint *num) +{ + NMDhcpConfigPrivate *priv = NM_DHCP_CONFIG_GET_PRIVATE(self); + NMDhcpLease *lease; + NMUtilsNamedValue *buffer = NULL; + + if (!priv->l3cd) { + NM_SET_OUT(num, 0); + return NULL; + } + + lease = nm_l3_config_data_get_dhcp_lease(priv->l3cd, nm_dhcp_config_get_addr_family(self)); + nm_utils_named_values_from_strdict_full(nm_dhcp_lease_get_options(lease), + num, + nm_strcmp_p_with_data, + NULL, + NULL, + 0, + &buffer); + return buffer; +} + const char * nm_dhcp_config_get_option(NMDhcpConfig *self, const char *key) { diff --git a/src/core/nm-dhcp-config.h b/src/core/nm-dhcp-config.h index cae0e11aa2..cdca4ef1fb 100644 --- a/src/core/nm-dhcp-config.h +++ b/src/core/nm-dhcp-config.h @@ -30,7 +30,8 @@ int nm_dhcp_config_get_addr_family(NMDhcpConfig *self); void nm_dhcp_config_set_lease(NMDhcpConfig *self, const NML3ConfigData *l3cd); -const char *nm_dhcp_config_get_option(NMDhcpConfig *self, const char *option); +NMUtilsNamedValue *nm_dhcp_config_get_option_values(NMDhcpConfig *self, guint *num); +const char *nm_dhcp_config_get_option(NMDhcpConfig *self, const char *option); GVariant *nm_dhcp_config_get_options(NMDhcpConfig *self); diff --git a/src/core/nm-firewall-utils.c b/src/core/nm-firewall-utils.c index 8fa8059e00..1311f50399 100644 --- a/src/core/nm-firewall-utils.c +++ b/src/core/nm-firewall-utils.c @@ -679,8 +679,7 @@ _fw_nft_set(gboolean add, const char *ip_iface, in_addr_t addr, guint8 plen) NM_UTILS_STR_UTF8_SAFE_FLAG_ESCAPE_CTRL, &ss1)); - stdin_buf = g_bytes_new_static(nm_str_buf_get_str(&strbuf), strbuf.len); - + stdin_buf = nm_str_buf_finalize_to_gbytes(&strbuf); _fw_nft_call_sync(stdin_buf, NULL); } diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index 521536979f..ee661e499e 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -20,6 +20,7 @@ #include "devices/nm-device-factory.h" #include "devices/nm-device-generic.h" #include "devices/nm-device.h" +#include "dns/nm-dns-manager.h" #include "dhcp/nm-dhcp-manager.h" #include "libnm-core-aux-intern/nm-common-macros.h" #include "libnm-core-intern/nm-core-internal.h" @@ -144,6 +145,9 @@ NM_GOBJECT_PROPERTIES_DEFINE(NMManager, typedef struct { NMPlatform *platform; + NMDnsManager *dns_mgr; + gulong dns_mgr_update_pending_signal_id; + GArray *capabilities; CList active_connections_lst_head; /* Oldest ACs at the beginning */ @@ -346,6 +350,9 @@ static NMActiveConnection *_new_active_connection(NMManager *self, static void policy_activating_ac_changed(GObject *object, GParamSpec *pspec, gpointer user_data); +static void device_has_pending_action_changed(NMDevice *device, GParamSpec *pspec, NMManager *self); +static void check_if_startup_complete(NMManager *self); + static gboolean find_master(NMManager *self, NMConnection *connection, NMDevice *device, @@ -1601,7 +1608,11 @@ manager_device_state_changed(NMDevice *device, nm_settings_device_added(priv->settings, device); } -static void device_has_pending_action_changed(NMDevice *device, GParamSpec *pspec, NMManager *self); +static void +_dns_mgr_update_pending_cb(NMDevice *device, GParamSpec *pspec, NMManager *self) +{ + check_if_startup_complete(self); +} static void check_if_startup_complete(NMManager *self) @@ -1616,6 +1627,20 @@ check_if_startup_complete(NMManager *self) if (!priv->devices_inited) return; + if (nm_dns_manager_get_update_pending(nm_manager_get_dns_manager(self))) { + if (priv->dns_mgr_update_pending_signal_id == 0) { + priv->dns_mgr_update_pending_signal_id = + g_signal_connect(nm_manager_get_dns_manager(self), + "notify::" NM_DNS_MANAGER_UPDATE_PENDING, + G_CALLBACK(_dns_mgr_update_pending_cb), + self); + } + return; + } + + nm_clear_g_signal_handler(nm_manager_get_dns_manager(self), + &priv->dns_mgr_update_pending_signal_id); + c_list_for_each_entry (device, &priv->devices_lst_head, devices_lst) { reason = nm_device_has_pending_action_reason(device); if (reason) { @@ -7014,10 +7039,6 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde guint32 route_metric_default_aspired; guint32 route_metric_default_effective; NMTernary nm_owned; - NMDhcpConfig *dhcp_config; - const char *next_server = NULL; - const char *root_path = NULL; - const char *dhcp_bootfile = NULL; NM_SET_OUT(out_ifindex, 0); @@ -7059,15 +7080,6 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde TRUE, &route_metric_default_aspired); - dhcp_config = nm_device_get_dhcp_config(device, AF_INET); - if (dhcp_config) { - root_path = nm_dhcp_config_get_option(dhcp_config, "root_path"); - next_server = nm_dhcp_config_get_option(dhcp_config, "next_server"); - dhcp_bootfile = nm_dhcp_config_get_option(dhcp_config, "filename"); - if (!dhcp_bootfile) - dhcp_bootfile = nm_dhcp_config_get_option(dhcp_config, "bootfile_name"); - } - if (!nm_config_device_state_write(ifindex, managed_type, perm_hw_addr_fake, @@ -7075,9 +7087,8 @@ nm_manager_write_device_state(NMManager *self, NMDevice *device, int *out_ifinde nm_owned, route_metric_default_aspired, route_metric_default_effective, - next_server, - root_path, - dhcp_bootfile)) + nm_device_get_dhcp_config(device, AF_INET), + nm_device_get_dhcp_config(device, AF_INET6))) return FALSE; NM_SET_OUT(out_ifindex, ifindex); @@ -7790,6 +7801,28 @@ impl_manager_checkpoint_adjust_rollback_timeout(NMDBusObject /*****************************************************************************/ +NMDnsManager * +nm_manager_get_dns_manager(NMManager *self) +{ + NMManagerPrivate *priv; + + g_return_val_if_fail(NM_IS_MANAGER(self), NULL); + + priv = NM_MANAGER_GET_PRIVATE(self); + + if (G_UNLIKELY(!priv->dns_mgr)) { + /* Initialize lazily on first use. + * + * But keep a reference. This is to ensure proper lifetimes between + * singleton instances (i.e. nm_dns_manager_get() outlives NMManager). */ + priv->dns_mgr = g_object_ref(nm_dns_manager_get()); + } + + return priv->dns_mgr; +} + +/*****************************************************************************/ + static void auth_mgr_changed(NMAuthManager *auth_manager, gpointer user_data) { @@ -8250,6 +8283,9 @@ dispose(GObject *object) g_clear_object(&priv->concheck_mgr); } + nm_clear_g_signal_handler(priv->dns_mgr, &priv->dns_mgr_update_pending_signal_id); + g_clear_object(&priv->dns_mgr); + if (priv->auth_mgr) { g_signal_handlers_disconnect_by_func(priv->auth_mgr, G_CALLBACK(auth_mgr_changed), self); g_clear_object(&priv->auth_mgr); diff --git a/src/core/nm-manager.h b/src/core/nm-manager.h index f8563c3aa1..fcb0022720 100644 --- a/src/core/nm-manager.h +++ b/src/core/nm-manager.h @@ -200,6 +200,10 @@ NMMetered nm_manager_get_metered(NMManager *self); void nm_manager_notify_device_availability_maybe_changed(NMManager *self); +struct _NMDnsManager; + +struct _NMDnsManager *nm_manager_get_dns_manager(NMManager *self); + /*****************************************************************************/ void nm_manager_device_auth_request(NMManager *self, diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index 1ff66e25de..2b988527e9 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -389,15 +389,15 @@ typedef struct { gint64 startup_complete_start_timestamp_msec; GHashTable *startup_complete_idx; CList startup_complete_scd_lst_head; - guint startup_complete_timeout_id; + GSource *startup_complete_timeout_source; + + GSource *kf_db_flush_idle_source_timestamps; + GSource *kf_db_flush_idle_source_seen_bssids; guint connections_len; guint connections_generation; - guint kf_db_flush_idle_id_timestamps; - guint kf_db_flush_idle_id_seen_bssids; - bool kf_db_pruned_timestamps; bool kf_db_pruned_seen_bssid; @@ -541,9 +541,9 @@ _startup_complete_timeout_cb(gpointer user_data) NMSettings *self = user_data; NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self); - priv->startup_complete_timeout_id = 0; + nm_clear_g_source_inst(&priv->startup_complete_timeout_source); _startup_complete_check(self, 0); - return G_SOURCE_REMOVE; + return G_SOURCE_CONTINUE; } static void @@ -567,7 +567,7 @@ _startup_complete_check(NMSettings *self, gint64 now_msec) return; } - nm_clear_g_source(&priv->startup_complete_timeout_id); + nm_clear_g_source_inst(&priv->startup_complete_timeout_source); if (c_list_is_empty(&priv->startup_complete_scd_lst_head)) goto ready; @@ -609,8 +609,10 @@ next_with_ready: timeout_msec = priv->startup_complete_start_timestamp_msec + scd_not_ready->timeout_msec - nm_utils_get_monotonic_timestamp_msec(); - priv->startup_complete_timeout_id = - g_timeout_add(NM_CLAMP(0, timeout_msec, 60000), _startup_complete_timeout_cb, self); + priv->startup_complete_timeout_source = + nm_g_timeout_add_source(NM_CLAMP(0, timeout_msec, 60000), + _startup_complete_timeout_cb, + self); _LOGT("startup-complete: wait for suitable device for connection \"%s\" (%s) which has " "\"connection.wait-device-timeout\" set", nm_settings_connection_get_id(scd_not_ready->sett_conn), @@ -637,7 +639,7 @@ ready: _LOGT("startup-complete: ready, no more profiles to wait for"); priv->startup_complete_start_timestamp_msec = 0; nm_assert(!priv->startup_complete_idx); - nm_assert(priv->startup_complete_timeout_id == 0); + nm_assert(!priv->startup_complete_timeout_source); _notify(self, PROP_STARTUP_COMPLETE); } @@ -3842,13 +3844,13 @@ _kf_db_got_dirty_flush(NMSettings *self, gboolean is_timestamps) NMKeyFileDB *kf_db; if (is_timestamps) { - prefix = "timestamps"; - kf_db = priv->kf_db_timestamps; - priv->kf_db_flush_idle_id_timestamps = 0; + prefix = "timestamps"; + kf_db = priv->kf_db_timestamps; + nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_timestamps); } else { - prefix = "seen-bssids"; - kf_db = priv->kf_db_seen_bssids; - priv->kf_db_flush_idle_id_seen_bssids = 0; + prefix = "seen-bssids"; + kf_db = priv->kf_db_seen_bssids; + nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_seen_bssids); } if (nm_key_file_db_is_dirty(kf_db)) @@ -3859,7 +3861,7 @@ _kf_db_got_dirty_flush(NMSettings *self, gboolean is_timestamps) nm_key_file_db_get_filename(kf_db)); } - return G_SOURCE_REMOVE; + return G_SOURCE_CONTINUE; } static gboolean @@ -3880,26 +3882,27 @@ _kf_db_got_dirty_fcn(NMKeyFileDB *kf_db, gpointer user_data) NMSettings *self = user_data; NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self); GSourceFunc idle_func; - guint *p_id; + GSource **p_source; const char *prefix; if (priv->kf_db_timestamps == kf_db) { prefix = "timestamps"; - p_id = &priv->kf_db_flush_idle_id_timestamps; + p_source = &priv->kf_db_flush_idle_source_timestamps; idle_func = _kf_db_got_dirty_flush_timestamps_cb; } else if (priv->kf_db_seen_bssids == kf_db) { prefix = "seen-bssids"; - p_id = &priv->kf_db_flush_idle_id_seen_bssids; + p_source = &priv->kf_db_flush_idle_source_seen_bssids; idle_func = _kf_db_got_dirty_flush_seen_bssids_cb; } else { nm_assert_not_reached(); return; } - if (*p_id != 0) + if (*p_source) return; _LOGT("[%s-keyfile]: schedule flushing changes to disk", prefix); - *p_id = g_idle_add_full(G_PRIORITY_LOW, idle_func, self, NULL); + *p_source = + nm_g_source_attach(nm_g_idle_source_new(G_PRIORITY_LOW, idle_func, self, NULL), NULL); } void @@ -4100,7 +4103,7 @@ dispose(GObject *object) nm_assert(c_list_is_empty(&priv->sce_dirty_lst_head)); nm_assert(g_hash_table_size(priv->sce_idx) == 0); - nm_clear_g_source(&priv->startup_complete_timeout_id); + nm_clear_g_source_inst(&priv->startup_complete_timeout_source); nm_clear_pointer(&priv->startup_complete_idx, g_hash_table_destroy); nm_assert(c_list_is_empty(&priv->startup_complete_scd_lst_head)); @@ -4154,8 +4157,8 @@ finalize(GObject *object) g_clear_object(&priv->agent_mgr); - nm_clear_g_source(&priv->kf_db_flush_idle_id_timestamps); - nm_clear_g_source(&priv->kf_db_flush_idle_id_seen_bssids); + nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_timestamps); + nm_clear_g_source_inst(&priv->kf_db_flush_idle_source_seen_bssids); _kf_db_to_file(self, TRUE, FALSE); _kf_db_to_file(self, FALSE, FALSE); nm_key_file_db_destroy(priv->kf_db_timestamps); diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c index efb9bfce4f..1d7de8d24b 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -26,8 +26,6 @@ #include "libnm-core-intern/nm-core-internal.h" #include "libnm-core-intern/nm-keyfile-internal.h" -#include "libnm-systemd-shared/nm-sd-utils-shared.h" - #include "settings/nm-settings-plugin.h" #include "settings/nm-settings-storage.h" #include "settings/nm-settings-utils.h" @@ -1247,9 +1245,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin) /* dirname_libs are a set of read-only directories with lower priority than /etc or /run. * There is nothing complicated about having multiple of such directories, so dirname_libs * is a list (which currently only has at most one directory). */ - priv->dirname_libs[0] = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB)); + priv->dirname_libs[0] = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_LIB)); priv->dirname_libs[1] = NULL; - priv->dirname_run = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN)); + priv->dirname_run = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_RUN)); priv->dirname_etc = nm_config_data_get_value(NM_CONFIG_GET_DATA_ORIG, NM_CONFIG_KEYFILE_GROUP_KEYFILE, NM_CONFIG_KEYFILE_KEY_KEYFILE_PATH, @@ -1262,9 +1260,9 @@ nms_keyfile_plugin_init(NMSKeyfilePlugin *plugin) } else if (!priv->dirname_etc || priv->dirname_etc[0] != '/') { /* either invalid path or unspecified. Use the default. */ g_free(priv->dirname_etc); - priv->dirname_etc = nm_sd_utils_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT)); + priv->dirname_etc = nm_path_simplify(g_strdup(NM_KEYFILE_PATH_NAME_ETC_DEFAULT)); } else - nm_sd_utils_path_simplify(priv->dirname_etc); + nm_path_simplify(priv->dirname_etc); /* no duplicates */ if (NM_IN_STRSET(priv->dirname_libs[0], priv->dirname_etc, priv->dirname_run)) diff --git a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c index 11a8e4169c..b24acc45af 100644 --- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c +++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c @@ -1924,6 +1924,7 @@ test_write_bridge_main(void) gs_unref_object NMConnection *connection = NULL; NMSettingConnection *s_con; NMSettingBridge *s_bridge; + NMSettingWired *s_wired; NMSettingIPConfig *s_ip4; NMSettingIPConfig *s_ip6; @@ -1953,6 +1954,11 @@ test_write_bridge_main(void) g_assert(s_bridge); nm_connection_add_setting(connection, NM_SETTING(s_bridge)); + /* Ethernet setting */ + s_wired = (NMSettingWired *) nm_setting_wired_new(); + g_assert(s_wired); + nm_connection_add_setting(connection, NM_SETTING(s_wired)); + /* IP4 setting */ s_ip4 = (NMSettingIPConfig *) nm_setting_ip4_config_new(); g_assert(s_ip4); diff --git a/src/core/tests/test-core.c b/src/core/tests/test-core.c index b4e1c4d5f3..11a7f32349 100644 --- a/src/core/tests/test-core.c +++ b/src/core/tests/test-core.c @@ -15,7 +15,6 @@ #include "NetworkManagerUtils.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-core-utils.h" -#include "libnm-systemd-core/nm-sd-utils-core.h" #include "dns/nm-dns-manager.h" #include "nm-connectivity.h" @@ -2314,7 +2313,6 @@ test_dns_create_resolv_conf(void) static void test_machine_id_read(void) { - NMUuid machine_id_sd; const NMUuid *machine_id; char machine_id_str[33]; gpointer logstate; @@ -2346,27 +2344,6 @@ test_machine_id_read(void) == machine_id_str); g_assert(strlen(machine_id_str) == 32); g_assert_cmpstr(machine_id_str, ==, nm_utils_machine_id_str()); - - /* double check with systemd's implementation... */ - if (!nm_sd_utils_id128_get_machine(&machine_id_sd)) { - /* if systemd failed to read /etc/machine-id, the file likely - * is invalid. Our machine-id is fake, and we have nothing to - * compare against. */ - - if (g_file_test(LOCALSTATEDIR "/lib/dbus/machine-id", G_FILE_TEST_EXISTS)) { - /* Hm. So systemd failed to read /etc/machine-id, but we may have the one from D-Bus. - * With LOCALSTATEDIR"/lib/dbus/machine-id", we don't really know whether we - * parsed that file. Assume we don't know and skip the test on this system. */ - g_assert(!nm_utils_machine_id_is_fake()); - return; - } - - /* OK, in this case, our function should have generated a random machine ID. */ - g_assert(nm_utils_machine_id_is_fake()); - } else { - g_assert(!nm_utils_machine_id_is_fake()); - g_assert_cmpmem(&machine_id_sd, sizeof(NMUuid), machine_id, 16); - } } /*****************************************************************************/ diff --git a/src/core/tests/test-systemd.c b/src/core/tests/test-systemd.c index 71a6a60df1..cf31ec33cc 100644 --- a/src/core/tests/test-systemd.c +++ b/src/core/tests/test-systemd.c @@ -13,27 +13,6 @@ /*****************************************************************************/ static void -test_dhcp_create(void) -{ - sd_dhcp_client *client4 = NULL; - int r; - - r = sd_dhcp_client_new(&client4, FALSE); - g_assert(r == 0); - g_assert(client4); - - if (/* never true */ client4 == (gpointer) &r) { - /* we don't want to call this, but ensure that the linker - * includes all these symbols. */ - sd_dhcp_client_start(client4); - } - - sd_dhcp_client_unref(client4); -} - -/*****************************************************************************/ - -static void test_lldp_create(void) { sd_lldp_rx *lldp = NULL; @@ -119,141 +98,6 @@ test_sd_event(void) /*****************************************************************************/ -static void -test_path_equal(void) -{ -#define _path_equal_check(path, expected) \ - G_STMT_START \ - { \ - const char *_path0 = (path); \ - const char *_expected = (expected); \ - gs_free char *_path = g_strdup(_path0); \ - const char *_path_result; \ - \ - _path_result = nm_sd_utils_path_simplify(_path); \ - g_assert(_path_result == _path); \ - g_assert_cmpstr(_path, ==, _expected); \ - } \ - G_STMT_END - - _path_equal_check("", ""); - _path_equal_check(".", "."); - _path_equal_check("..", ".."); - _path_equal_check("/..", "/.."); - _path_equal_check("//..", "/.."); - _path_equal_check("/.", "/"); - _path_equal_check("./", "."); - _path_equal_check("./.", "."); - _path_equal_check(".///.", "."); - _path_equal_check(".///./", "."); - _path_equal_check(".////", "."); - _path_equal_check("//..//foo/", "/../foo"); - _path_equal_check("///foo//./bar/.", "/foo/bar"); - _path_equal_check(".//./foo//./bar/.", "foo/bar"); -} - -/*****************************************************************************/ - -static void -_test_unbase64char(char ch, gboolean maybe_invalid) -{ - int r; - - r = nm_sd_utils_unbase64char(ch, FALSE); - - if (ch == '=') { - g_assert(!maybe_invalid); - g_assert_cmpint(r, <, 0); - g_assert_cmpint(nm_sd_utils_unbase64char(ch, TRUE), ==, G_MAXINT); - } else { - g_assert_cmpint(r, ==, nm_sd_utils_unbase64char(ch, TRUE)); - if (r >= 0) - g_assert_cmpint(r, <=, 255); - if (!maybe_invalid) - g_assert_cmpint(r, >=, 0); - } -} - -static void -_test_unbase64mem_mem(const char *base64, const guint8 *expected_arr, gsize expected_len) -{ - gs_free char *expected_base64 = NULL; - int r; - nm_auto_free guint8 *exp2_arr = NULL; - nm_auto_free guint8 *exp3_arr = NULL; - gsize exp2_len; - gsize exp3_len; - gsize i; - - expected_base64 = g_base64_encode(expected_arr, expected_len); - - for (i = 0; expected_base64[i]; i++) - _test_unbase64char(expected_base64[i], FALSE); - - r = nm_sd_utils_unbase64mem(expected_base64, - strlen(expected_base64), - TRUE, - &exp2_arr, - &exp2_len); - g_assert_cmpint(r, ==, 0); - g_assert_cmpmem(expected_arr, expected_len, exp2_arr, exp2_len); - - if (!nm_streq(base64, expected_base64)) { - r = nm_sd_utils_unbase64mem(base64, strlen(base64), TRUE, &exp3_arr, &exp3_len); - g_assert_cmpint(r, ==, 0); - g_assert_cmpmem(expected_arr, expected_len, exp3_arr, exp3_len); - } -} - -#define _test_unbase64mem(base64, expected_str) \ - _test_unbase64mem_mem(base64, (const guint8 *) "" expected_str "", NM_STRLEN(expected_str)) - -static void -_test_unbase64mem_inval(const char *base64) -{ - gs_free guint8 *exp_arr = NULL; - gsize exp_len = 0; - int r; - - r = nm_sd_utils_unbase64mem(base64, strlen(base64), TRUE, &exp_arr, &exp_len); - g_assert_cmpint(r, <, 0); - g_assert(!exp_arr); - g_assert(exp_len == 0); -} - -static void -test_nm_sd_utils_unbase64mem(void) -{ - gs_free char *rnd_base64 = NULL; - guint8 rnd_buf[30]; - guint i, rnd_len; - - _test_unbase64mem("", ""); - _test_unbase64mem(" ", ""); - _test_unbase64mem(" Y Q == ", "a"); - _test_unbase64mem(" Y WJjZGV mZ 2g = ", "abcdefgh"); - _test_unbase64mem_inval(" Y %WJjZGV mZ 2g = "); - _test_unbase64mem_inval(" Y %WJjZGV mZ 2g = a"); - _test_unbase64mem("YQ==", "a"); - _test_unbase64mem_inval("YQ==a"); - - rnd_len = nmtst_get_rand_uint32() % sizeof(rnd_buf); - for (i = 0; i < rnd_len; i++) - rnd_buf[i] = nmtst_get_rand_uint32() % 256; - rnd_base64 = g_base64_encode(rnd_buf, rnd_len); - _test_unbase64mem_mem(rnd_base64, rnd_buf, rnd_len); - - _test_unbase64char('=', FALSE); - for (i = 0; i < 10; i++) { - char ch = nmtst_get_rand_uint32() % 256; - - if (ch != '=') - _test_unbase64char(ch, TRUE); - } -} - -/*****************************************************************************/ - NMTST_DEFINE(); int @@ -261,11 +105,8 @@ main(int argc, char **argv) { nmtst_init(&argc, &argv, TRUE); - g_test_add_func("/systemd/dhcp/create", test_dhcp_create); g_test_add_func("/systemd/lldp/create", test_lldp_create); g_test_add_func("/systemd/sd-event", test_sd_event); - g_test_add_func("/systemd/test_path_equal", test_path_equal); - g_test_add_func("/systemd/test_nm_sd_utils_unbase64mem", test_nm_sd_utils_unbase64mem); return g_test_run(); } diff --git a/src/core/tests/test-utils.c b/src/core/tests/test-utils.c index ad9950ddb4..2bcb6f6946 100644 --- a/src/core/tests/test-utils.c +++ b/src/core/tests/test-utils.c @@ -234,8 +234,10 @@ test_shorten_hostname(void) * system configuration (`getconf HOST_NAME_MAX`). On Linux * it's typically 64 characters, but POSIX allows up to * 255 characters. + * + * We use our own define NM_HOST_NAME_MAX, which is always 64. */ - maxhost = g_strnfill(HOST_NAME_MAX, 'a'); + maxhost = g_strnfill(NM_HOST_NAME_MAX, 'a'); do_test_shorten_hostname("name1", TRUE, NULL); diff --git a/src/libnm-client-impl/nm-client.c b/src/libnm-client-impl/nm-client.c index b18f47be32..f7bd2db545 100644 --- a/src/libnm-client-impl/nm-client.c +++ b/src/libnm-client-impl/nm-client.c @@ -20,6 +20,7 @@ #include "nm-checkpoint.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-helpers.h" +#include "nm-wifi-p2p-peer.h" #include "nm-device-6lowpan.h" #include "nm-device-adsl.h" #include "nm-device-bond.h" @@ -33,7 +34,6 @@ #include "nm-device-macsec.h" #include "nm-device-macvlan.h" #include "nm-device-modem.h" -#include "nm-device-olpc-mesh.h" #include "nm-device-ovs-bridge.h" #include "nm-device-ovs-interface.h" #include "nm-device-ovs-port.h" @@ -46,6 +46,7 @@ #include "nm-device-wifi.h" #include "nm-device-wireguard.h" #include "nm-device-wpan.h" +#include "nm-device-olpc-mesh.h" #include "nm-dhcp-config.h" #include "nm-dhcp4-config.h" #include "nm-dhcp6-config.h" @@ -56,7 +57,6 @@ #include "nm-remote-connection.h" #include "nm-utils.h" #include "nm-vpn-connection.h" -#include "nm-wifi-p2p-peer.h" /*****************************************************************************/ @@ -8399,9 +8399,9 @@ nm_client_class_init(NMClientClass *client_class) * * Whether a connectivity checking service has been enabled. * - * Since: 1.10 - * * The property setter is a synchronous D-Bus call. This is deprecated since 1.22. + * + * Since: 1.10 */ obj_properties[PROP_CONNECTIVITY_CHECK_ENABLED] = g_param_spec_boolean(NM_CLIENT_CONNECTIVITY_CHECK_ENABLED, @@ -8729,7 +8729,7 @@ nm_client_class_init(NMClientClass *client_class) G_TYPE_UINT); /** * NMClient::connection-added: - * @client: the settings object that received the signal + * @client: the client that received the signal * @connection: the new connection * * Notifies that a #NMConnection has been added. @@ -8747,7 +8747,7 @@ nm_client_class_init(NMClientClass *client_class) /** * NMClient::connection-removed: - * @client: the settings object that received the signal + * @client: the client that received the signal * @connection: the removed connection * * Notifies that a #NMConnection has been removed. @@ -8765,7 +8765,7 @@ nm_client_class_init(NMClientClass *client_class) /** * NMClient::active-connection-added: - * @client: the settings object that received the signal + * @client: the client that received the signal * @active_connection: the new active connection * * Notifies that a #NMActiveConnection has been added. @@ -8783,7 +8783,7 @@ nm_client_class_init(NMClientClass *client_class) /** * NMClient::active-connection-removed: - * @client: the settings object that received the signal + * @client: the client that received the signal * @active_connection: the removed active connection * * Notifies that a #NMActiveConnection has been removed. diff --git a/src/libnm-client-impl/nm-default-libnm.h b/src/libnm-client-impl/nm-default-libnm.h index 5b3a8e5179..859766a301 100644 --- a/src/libnm-client-impl/nm-default-libnm.h +++ b/src/libnm-client-impl/nm-default-libnm.h @@ -16,6 +16,16 @@ /*****************************************************************************/ #include "nm-version.h" +#include "nm-dbus-interface.h" +#include "nm-dhcp-config.h" +#include "nm-ip-config.h" +#include "nm-connection.h" +#include "nm-remote-connection.h" +#include "nm-active-connection.h" +#include "nm-device.h" +#include "nm-checkpoint.h" +#include "nm-client.h" +#include "nm-vpn-connection.h" #include "nm-libnm-utils.h" /*****************************************************************************/ diff --git a/src/libnm-client-impl/nm-device-macvlan.c b/src/libnm-client-impl/nm-device-macvlan.c index a8363c930c..be6d56e44c 100644 --- a/src/libnm-client-impl/nm-device-macvlan.c +++ b/src/libnm-client-impl/nm-device-macvlan.c @@ -120,11 +120,11 @@ nm_device_macvlan_get_tap(NMDeviceMacvlan *device) * Returns: the hardware address. This is the internal string used by the * device, and must not be modified. * - * Since: 1.2 - * * This property is not implemented yet, and the function always return NULL. * * Deprecated: 1.24: Use nm_device_get_hw_address() instead. + * + * Since: 1.2 **/ const char * nm_device_macvlan_get_hw_address(NMDeviceMacvlan *device) diff --git a/src/libnm-client-impl/nm-device-olpc-mesh.c b/src/libnm-client-impl/nm-device-olpc-mesh.c index 26fceb3bd5..38f9e472c8 100644 --- a/src/libnm-client-impl/nm-device-olpc-mesh.c +++ b/src/libnm-client-impl/nm-device-olpc-mesh.c @@ -5,12 +5,13 @@ #include "libnm-client-impl/nm-default-libnm.h" +#include "nm-access-point.h" +#include "nm-device-wifi.h" #include "nm-device-olpc-mesh.h" #include "nm-setting-connection.h" #include "nm-setting-olpc-mesh.h" #include "nm-object-private.h" -#include "nm-device-wifi.h" /*****************************************************************************/ diff --git a/src/libnm-client-impl/nm-device-vxlan.c b/src/libnm-client-impl/nm-device-vxlan.c index d7bd9cbe94..d81b551601 100644 --- a/src/libnm-client-impl/nm-device-vxlan.c +++ b/src/libnm-client-impl/nm-device-vxlan.c @@ -96,10 +96,10 @@ nm_device_vxlan_get_hw_address(NMDeviceVxlan *device) * * Returns: %TRUE if the device has carrier. * - * Since: 1.2 - * * This property is not implemented yet, and the function always returns * FALSE. + * + * Since: 1.2 **/ gboolean nm_device_vxlan_get_carrier(NMDeviceVxlan *device) @@ -541,9 +541,9 @@ nm_device_vxlan_class_init(NMDeviceVxlanClass *klass) * * Whether the device has carrier. * - * Since: 1.2 - * * This property is not implemented yet, and the property is always FALSE. + * + * Since: 1.2 **/ obj_properties[PROP_CARRIER] = g_param_spec_boolean(NM_DEVICE_VXLAN_CARRIER, "", diff --git a/src/libnm-client-impl/nm-device-wifi-p2p.c b/src/libnm-client-impl/nm-device-wifi-p2p.c index fb72f25052..6e667ac61a 100644 --- a/src/libnm-client-impl/nm-device-wifi-p2p.c +++ b/src/libnm-client-impl/nm-device-wifi-p2p.c @@ -5,13 +5,13 @@ #include "libnm-client-impl/nm-default-libnm.h" +#include "nm-wifi-p2p-peer.h" #include "nm-device-wifi-p2p.h" #include "libnm-glib-aux/nm-dbus-aux.h" #include "nm-setting-connection.h" #include "nm-setting-wifi-p2p.h" #include "nm-utils.h" -#include "nm-wifi-p2p-peer.h" #include "nm-object-private.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-helpers.h" diff --git a/src/libnm-client-impl/nm-device-wifi.c b/src/libnm-client-impl/nm-device-wifi.c index b062ea9e04..616aca5008 100644 --- a/src/libnm-client-impl/nm-device-wifi.c +++ b/src/libnm-client-impl/nm-device-wifi.c @@ -6,6 +6,7 @@ #include "libnm-client-impl/nm-default-libnm.h" +#include "nm-access-point.h" #include "nm-device-wifi.h" #include <linux/if_ether.h> @@ -15,7 +16,6 @@ #include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" #include "nm-utils.h" -#include "nm-access-point.h" #include "nm-object-private.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-dbus-helpers.h" diff --git a/src/libnm-client-impl/nm-device-wimax.c b/src/libnm-client-impl/nm-device-wimax.c index b9db20bb67..cdbe7fbc2f 100644 --- a/src/libnm-client-impl/nm-device-wimax.c +++ b/src/libnm-client-impl/nm-device-wimax.c @@ -6,9 +6,8 @@ #include "libnm-client-impl/nm-default-libnm.h" -#include "nm-device-wimax.h" - #include "nm-wimax-nsp.h" +#include "nm-device-wimax.h" /*****************************************************************************/ diff --git a/src/libnm-client-impl/nm-libnm-utils.h b/src/libnm-client-impl/nm-libnm-utils.h index db5f31ea5a..9d9cfa2530 100644 --- a/src/libnm-client-impl/nm-libnm-utils.h +++ b/src/libnm-client-impl/nm-libnm-utils.h @@ -7,12 +7,8 @@ #define __NM_LIBNM_UTILS_H__ #include "c-list/src/c-list.h" -#include "nm-device.h" #include "libnm-glib-aux/nm-ref-string.h" #include "libnm-glib-aux/nm-logging-fwd.h" -#include "nm-types.h" -#include "nm-object.h" -#include "nm-client.h" /*****************************************************************************/ diff --git a/src/libnm-client-public/NetworkManager.h b/src/libnm-client-public/NetworkManager.h index 66f676a111..de3c7821ff 100644 --- a/src/libnm-client-public/NetworkManager.h +++ b/src/libnm-client-public/NetworkManager.h @@ -8,48 +8,19 @@ #define __NETWORKMANAGER_H_INSIDE__ -#include "nm-access-point.h" -#include "nm-active-connection.h" -#include "nm-client.h" -#include "nm-connection.h" -#include "nm-core-enum-types.h" +#include <gio/gio.h> + +#include "nm-version.h" #include "nm-dbus-interface.h" -#include "nm-device-6lowpan.h" -#include "nm-device-adsl.h" -#include "nm-device-bond.h" -#include "nm-device-bridge.h" -#include "nm-device-bt.h" -#include "nm-device-dummy.h" -#include "nm-device-ethernet.h" -#include "nm-device-generic.h" -#include "nm-device-infiniband.h" -#include "nm-device-ip-tunnel.h" -#include "nm-device-macsec.h" -#include "nm-device-macvlan.h" -#include "nm-device-modem.h" -#include "nm-device-olpc-mesh.h" -#include "nm-device-ovs-bridge.h" -#include "nm-device-ovs-interface.h" -#include "nm-device-ovs-port.h" -#include "nm-device-ppp.h" -#include "nm-device-team.h" -#include "nm-device-tun.h" -#include "nm-device-veth.h" -#include "nm-device-vlan.h" -#include "nm-device-vxlan.h" -#include "nm-device-wifi-p2p.h" -#include "nm-device-wifi.h" -#include "nm-device-wimax.h" -#include "nm-device-wireguard.h" -#include "nm-device-wpan.h" -#include "nm-device.h" -#include "nm-dhcp-config.h" -#include "nm-enum-types.h" -#include "nm-ethtool-utils.h" -#include "nm-ip-config.h" + +#include "nm-core-enum-types.h" + +#include "nm-connection.h" +#include "nm-simple-connection.h" #include "nm-keyfile.h" -#include "nm-object.h" -#include "nm-remote-connection.h" +#include "nm-setting.h" +#include "nm-utils.h" + #include "nm-setting-6lowpan.h" #include "nm-setting-8021x.h" #include "nm-setting-adsl.h" @@ -102,18 +73,59 @@ #include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" #include "nm-setting-wpan.h" -#include "nm-setting.h" -#include "nm-simple-connection.h" -#include "nm-utils.h" -#include "nm-version.h" -#include "nm-vpn-connection.h" + #include "nm-vpn-dbus-interface.h" -#include "nm-vpn-editor.h" -#include "nm-vpn-editor-plugin.h" #include "nm-vpn-plugin-info.h" -#include "nm-vpn-service-plugin.h" +#include "nm-vpn-editor-plugin.h" + +#include "nm-enum-types.h" + +#include "nm-ethtool-utils.h" + +#include "nm-object.h" +#include "nm-dhcp-config.h" +#include "nm-ip-config.h" +#include "nm-remote-connection.h" +#include "nm-active-connection.h" +#include "nm-checkpoint.h" +#include "nm-access-point.h" #include "nm-wifi-p2p-peer.h" #include "nm-wimax-nsp.h" +#include "nm-device.h" +#include "nm-vpn-connection.h" +#include "nm-vpn-editor.h" +#include "nm-vpn-service-plugin.h" + +#include "nm-client.h" + +#include "nm-device-6lowpan.h" +#include "nm-device-adsl.h" +#include "nm-device-bond.h" +#include "nm-device-bridge.h" +#include "nm-device-bt.h" +#include "nm-device-dummy.h" +#include "nm-device-ethernet.h" +#include "nm-device-generic.h" +#include "nm-device-infiniband.h" +#include "nm-device-ip-tunnel.h" +#include "nm-device-macsec.h" +#include "nm-device-macvlan.h" +#include "nm-device-modem.h" +#include "nm-device-ovs-bridge.h" +#include "nm-device-ovs-interface.h" +#include "nm-device-ovs-port.h" +#include "nm-device-ppp.h" +#include "nm-device-team.h" +#include "nm-device-tun.h" +#include "nm-device-veth.h" +#include "nm-device-vlan.h" +#include "nm-device-vxlan.h" +#include "nm-device-wifi.h" +#include "nm-device-wifi-p2p.h" +#include "nm-device-olpc-mesh.h" +#include "nm-device-wimax.h" +#include "nm-device-wireguard.h" +#include "nm-device-wpan.h" #include "nm-autoptr.h" diff --git a/src/libnm-client-public/meson.build b/src/libnm-client-public/meson.build index 3ae4e8d83f..f76fd1868f 100644 --- a/src/libnm-client-public/meson.build +++ b/src/libnm-client-public/meson.build @@ -45,7 +45,6 @@ libnm_client_headers = files( 'nm-object.h', 'nm-remote-connection.h', 'nm-secret-agent-old.h', - 'nm-types.h', 'nm-vpn-connection.h', 'nm-vpn-editor.h', 'nm-vpn-plugin-old.h', diff --git a/src/libnm-client-public/nm-access-point.h b/src/libnm-client-public/nm-access-point.h index 9f9216bb59..5a78e34f73 100644 --- a/src/libnm-client-public/nm-access-point.h +++ b/src/libnm-client-public/nm-access-point.h @@ -42,6 +42,7 @@ G_BEGIN_DECLS /** * NMAccessPoint: */ +typedef struct _NMAccessPoint NMAccessPoint; typedef struct _NMAccessPointClass NMAccessPointClass; GType nm_access_point_get_type(void); diff --git a/src/libnm-client-public/nm-active-connection.h b/src/libnm-client-public/nm-active-connection.h index a65b4f20f7..5c3148269a 100644 --- a/src/libnm-client-public/nm-active-connection.h +++ b/src/libnm-client-public/nm-active-connection.h @@ -46,6 +46,7 @@ G_BEGIN_DECLS /** * NMActiveConnection: */ +typedef struct _NMActiveConnection NMActiveConnection; typedef struct _NMActiveConnectionClass NMActiveConnectionClass; GType nm_active_connection_get_type(void); @@ -61,14 +62,18 @@ NM_AVAILABLE_IN_1_10 NMActivationStateFlags nm_active_connection_get_state_flags(NMActiveConnection *connection); NM_AVAILABLE_IN_1_8 NMActiveConnectionStateReason nm_active_connection_get_state_reason(NMActiveConnection *connection); -NMDevice *nm_active_connection_get_master(NMActiveConnection *connection); -gboolean nm_active_connection_get_default(NMActiveConnection *connection); -NMIPConfig *nm_active_connection_get_ip4_config(NMActiveConnection *connection); -NMDhcpConfig *nm_active_connection_get_dhcp4_config(NMActiveConnection *connection); -gboolean nm_active_connection_get_default6(NMActiveConnection *connection); -NMIPConfig *nm_active_connection_get_ip6_config(NMActiveConnection *connection); -NMDhcpConfig *nm_active_connection_get_dhcp6_config(NMActiveConnection *connection); -gboolean nm_active_connection_get_vpn(NMActiveConnection *connection); + +struct _NMDevice; + +struct _NMDevice *nm_active_connection_get_master(NMActiveConnection *connection); + +gboolean nm_active_connection_get_default(NMActiveConnection *connection); +NMIPConfig *nm_active_connection_get_ip4_config(NMActiveConnection *connection); +NMDhcpConfig *nm_active_connection_get_dhcp4_config(NMActiveConnection *connection); +gboolean nm_active_connection_get_default6(NMActiveConnection *connection); +NMIPConfig *nm_active_connection_get_ip6_config(NMActiveConnection *connection); +NMDhcpConfig *nm_active_connection_get_dhcp6_config(NMActiveConnection *connection); +gboolean nm_active_connection_get_vpn(NMActiveConnection *connection); G_END_DECLS diff --git a/src/libnm-client-public/nm-checkpoint.h b/src/libnm-client-public/nm-checkpoint.h index def1f5544c..456d7f6bdc 100644 --- a/src/libnm-client-public/nm-checkpoint.h +++ b/src/libnm-client-public/nm-checkpoint.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS /** * NMCheckpoint: */ +typedef struct _NMCheckpoint NMCheckpoint; typedef struct _NMCheckpointClass NMCheckpointClass; GType nm_checkpoint_get_type(void); diff --git a/src/libnm-client-public/nm-client.h b/src/libnm-client-public/nm-client.h index 2e3e77c43c..6307f11217 100644 --- a/src/libnm-client-public/nm-client.h +++ b/src/libnm-client-public/nm-client.h @@ -11,8 +11,6 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include "nm-types.h" - G_BEGIN_DECLS /** @@ -148,6 +146,7 @@ gboolean nm_dns_entry_get_vpn(NMDnsEntry *entry); * D-Bus signals gets processed and the #NMClient instance updates and * emits #GObject signals. */ +typedef struct _NMClient NMClient; typedef struct _NMClientClass NMClientClass; GType nm_client_get_type(void); diff --git a/src/libnm-client-public/nm-device-6lowpan.h b/src/libnm-client-public/nm-device-6lowpan.h index 2388bf3816..d5f8a7a5c1 100644 --- a/src/libnm-client-public/nm-device-6lowpan.h +++ b/src/libnm-client-public/nm-device-6lowpan.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS /** * NMDevice6Lowpan: */ +typedef struct _NMDevice6Lowpan NMDevice6Lowpan; typedef struct _NMDevice6LowpanClass NMDevice6LowpanClass; NM_AVAILABLE_IN_1_14 diff --git a/src/libnm-client-public/nm-device-adsl.h b/src/libnm-client-public/nm-device-adsl.h index fa8a127899..a4fbec51db 100644 --- a/src/libnm-client-public/nm-device-adsl.h +++ b/src/libnm-client-public/nm-device-adsl.h @@ -28,6 +28,7 @@ G_BEGIN_DECLS /** * NMDeviceAdsl: */ +typedef struct _NMDeviceAdsl NMDeviceAdsl; typedef struct _NMDeviceAdslClass NMDeviceAdslClass; GType nm_device_adsl_get_type(void); diff --git a/src/libnm-client-public/nm-device-bond.h b/src/libnm-client-public/nm-device-bond.h index 19e0e04638..6edc6106f6 100644 --- a/src/libnm-client-public/nm-device-bond.h +++ b/src/libnm-client-public/nm-device-bond.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS /** * NMDeviceBond: */ +typedef struct _NMDeviceBond NMDeviceBond; typedef struct _NMDeviceBondClass NMDeviceBondClass; GType nm_device_bond_get_type(void); diff --git a/src/libnm-client-public/nm-device-bridge.h b/src/libnm-client-public/nm-device-bridge.h index 07905195b7..e37400221b 100644 --- a/src/libnm-client-public/nm-device-bridge.h +++ b/src/libnm-client-public/nm-device-bridge.h @@ -31,6 +31,7 @@ G_BEGIN_DECLS /** * NMDeviceBridge: */ +typedef struct _NMDeviceBridge NMDeviceBridge; typedef struct _NMDeviceBridgeClass NMDeviceBridgeClass; GType nm_device_bridge_get_type(void); diff --git a/src/libnm-client-public/nm-device-bt.h b/src/libnm-client-public/nm-device-bt.h index c277bae99b..fa8d730815 100644 --- a/src/libnm-client-public/nm-device-bt.h +++ b/src/libnm-client-public/nm-device-bt.h @@ -31,6 +31,7 @@ G_BEGIN_DECLS /** * NMDeviceBt: */ +typedef struct _NMDeviceBt NMDeviceBt; typedef struct _NMDeviceBtClass NMDeviceBtClass; GType nm_device_bt_get_type(void); diff --git a/src/libnm-client-public/nm-device-dummy.h b/src/libnm-client-public/nm-device-dummy.h index d5b8cb2428..8b2f748577 100644 --- a/src/libnm-client-public/nm-device-dummy.h +++ b/src/libnm-client-public/nm-device-dummy.h @@ -29,6 +29,7 @@ G_BEGIN_DECLS /** * NMDeviceDummy: */ +typedef struct _NMDeviceDummy NMDeviceDummy; typedef struct _NMDeviceDummyClass NMDeviceDummyClass; GType nm_device_dummy_get_type(void); diff --git a/src/libnm-client-public/nm-device-ethernet.h b/src/libnm-client-public/nm-device-ethernet.h index 636e5eb57a..828865c7f9 100644 --- a/src/libnm-client-public/nm-device-ethernet.h +++ b/src/libnm-client-public/nm-device-ethernet.h @@ -35,6 +35,7 @@ G_BEGIN_DECLS /** * NMDeviceEthernet: */ +typedef struct _NMDeviceEthernet NMDeviceEthernet; typedef struct _NMDeviceEthernetClass NMDeviceEthernetClass; GType nm_device_ethernet_get_type(void); diff --git a/src/libnm-client-public/nm-device-generic.h b/src/libnm-client-public/nm-device-generic.h index 7b543b2ff6..ff24c6f10c 100644 --- a/src/libnm-client-public/nm-device-generic.h +++ b/src/libnm-client-public/nm-device-generic.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS /** * NMDeviceGeneric: */ +typedef struct _NMDeviceGeneric NMDeviceGeneric; typedef struct _NMDeviceGenericClass NMDeviceGenericClass; GType nm_device_generic_get_type(void); diff --git a/src/libnm-client-public/nm-device-infiniband.h b/src/libnm-client-public/nm-device-infiniband.h index 3999b2d560..53b16176ec 100644 --- a/src/libnm-client-public/nm-device-infiniband.h +++ b/src/libnm-client-public/nm-device-infiniband.h @@ -31,6 +31,7 @@ G_BEGIN_DECLS /** * NMDeviceInfiniband: */ +typedef struct _NMDeviceInfiniband NMDeviceInfiniband; typedef struct _NMDeviceInfinibandClass NMDeviceInfinibandClass; GType nm_device_infiniband_get_type(void); diff --git a/src/libnm-client-public/nm-device-ip-tunnel.h b/src/libnm-client-public/nm-device-ip-tunnel.h index d79127298b..4f55dc0bd4 100644 --- a/src/libnm-client-public/nm-device-ip-tunnel.h +++ b/src/libnm-client-public/nm-device-ip-tunnel.h @@ -42,6 +42,7 @@ G_BEGIN_DECLS /** * NMDeviceIPTunnel: */ +typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel; typedef struct _NMDeviceIPTunnelClass NMDeviceIPTunnelClass; NM_AVAILABLE_IN_1_2 diff --git a/src/libnm-client-public/nm-device-macsec.h b/src/libnm-client-public/nm-device-macsec.h index e468344fbb..b1ec363713 100644 --- a/src/libnm-client-public/nm-device-macsec.h +++ b/src/libnm-client-public/nm-device-macsec.h @@ -42,6 +42,7 @@ G_BEGIN_DECLS /** * NMDeviceMacsec: */ +typedef struct _NMDeviceMacsec NMDeviceMacsec; typedef struct _NMDeviceMacsecClass NMDeviceMacsecClass; NM_AVAILABLE_IN_1_6 diff --git a/src/libnm-client-public/nm-device-macvlan.h b/src/libnm-client-public/nm-device-macvlan.h index ec7eb640a7..9569933418 100644 --- a/src/libnm-client-public/nm-device-macvlan.h +++ b/src/libnm-client-public/nm-device-macvlan.h @@ -33,6 +33,7 @@ G_BEGIN_DECLS /** * NMDeviceMacvlan: */ +typedef struct _NMDeviceMacvlan NMDeviceMacvlan; typedef struct _NMDeviceMacvlanClass NMDeviceMacvlanClass; NM_AVAILABLE_IN_1_2 diff --git a/src/libnm-client-public/nm-device-modem.h b/src/libnm-client-public/nm-device-modem.h index f9dfc34815..4ef175728a 100644 --- a/src/libnm-client-public/nm-device-modem.h +++ b/src/libnm-client-public/nm-device-modem.h @@ -34,6 +34,7 @@ G_BEGIN_DECLS /** * NMDeviceModem: */ +typedef struct _NMDeviceModem NMDeviceModem; typedef struct _NMDeviceModemClass NMDeviceModemClass; GType nm_device_modem_get_type(void); diff --git a/src/libnm-client-public/nm-device-olpc-mesh.h b/src/libnm-client-public/nm-device-olpc-mesh.h index 86ac2ce706..ea3a309619 100644 --- a/src/libnm-client-public/nm-device-olpc-mesh.h +++ b/src/libnm-client-public/nm-device-olpc-mesh.h @@ -32,6 +32,7 @@ G_BEGIN_DECLS /** * NMDeviceOlpcMesh: */ +typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh; typedef struct _NMDeviceOlpcMeshClass NMDeviceOlpcMeshClass; GType nm_device_olpc_mesh_get_type(void); diff --git a/src/libnm-client-public/nm-device-ovs-bridge.h b/src/libnm-client-public/nm-device-ovs-bridge.h index f0ef154728..8c45405776 100644 --- a/src/libnm-client-public/nm-device-ovs-bridge.h +++ b/src/libnm-client-public/nm-device-ovs-bridge.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS /** * NMDeviceOvsBridge: */ +typedef struct _NMDeviceOvsBridge NMDeviceOvsBridge; typedef struct _NMDeviceOvsBridgeClass NMDeviceOvsBridgeClass; NM_AVAILABLE_IN_1_10 diff --git a/src/libnm-client-public/nm-device-ovs-interface.h b/src/libnm-client-public/nm-device-ovs-interface.h index 12b30a75b5..1ba7ac3a4c 100644 --- a/src/libnm-client-public/nm-device-ovs-interface.h +++ b/src/libnm-client-public/nm-device-ovs-interface.h @@ -29,6 +29,7 @@ G_BEGIN_DECLS /** * NMDeviceOvsInterface: */ +typedef struct _NMDeviceOvsInterface NMDeviceOvsInterface; typedef struct _NMDeviceOvsInterfaceClass NMDeviceOvsInterfaceClass; NM_AVAILABLE_IN_1_10 diff --git a/src/libnm-client-public/nm-device-ovs-port.h b/src/libnm-client-public/nm-device-ovs-port.h index 170067f9cc..7524cacb55 100644 --- a/src/libnm-client-public/nm-device-ovs-port.h +++ b/src/libnm-client-public/nm-device-ovs-port.h @@ -30,6 +30,7 @@ G_BEGIN_DECLS /** * NMDeviceOvsPort: */ +typedef struct _NMDeviceOvsPort NMDeviceOvsPort; typedef struct _NMDeviceOvsPortClass NMDeviceOvsPortClass; NM_AVAILABLE_IN_1_10 diff --git a/src/libnm-client-public/nm-device-ppp.h b/src/libnm-client-public/nm-device-ppp.h index ff99d9f974..4003f901c8 100644 --- a/src/libnm-client-public/nm-device-ppp.h +++ b/src/libnm-client-public/nm-device-ppp.h @@ -24,6 +24,7 @@ G_BEGIN_DECLS /** * NMDevicePpp: */ +typedef struct _NMDevicePpp NMDevicePpp; typedef struct _NMDevicePppClass NMDevicePppClass; GType nm_device_ppp_get_type(void); diff --git a/src/libnm-client-public/nm-device-team.h b/src/libnm-client-public/nm-device-team.h index eab5e4e6b4..406949a109 100644 --- a/src/libnm-client-public/nm-device-team.h +++ b/src/libnm-client-public/nm-device-team.h @@ -31,6 +31,7 @@ G_BEGIN_DECLS /** * NMDeviceTeam: */ +typedef struct _NMDeviceTeam NMDeviceTeam; typedef struct _NMDeviceTeamClass NMDeviceTeamClass; GType nm_device_team_get_type(void); diff --git a/src/libnm-client-public/nm-device-tun.h b/src/libnm-client-public/nm-device-tun.h index cc05b0c16f..e1e7310d37 100644 --- a/src/libnm-client-public/nm-device-tun.h +++ b/src/libnm-client-public/nm-device-tun.h @@ -34,6 +34,7 @@ G_BEGIN_DECLS /** * NMDeviceTun: */ +typedef struct _NMDeviceTun NMDeviceTun; typedef struct _NMDeviceTunClass NMDeviceTunClass; NM_AVAILABLE_IN_1_2 diff --git a/src/libnm-client-public/nm-device-veth.h b/src/libnm-client-public/nm-device-veth.h index 41b419156e..8f61ae2052 100644 --- a/src/libnm-client-public/nm-device-veth.h +++ b/src/libnm-client-public/nm-device-veth.h @@ -28,6 +28,7 @@ G_BEGIN_DECLS /** * NMDeviceVeth: */ +typedef struct _NMDeviceVeth NMDeviceVeth; typedef struct _NMDeviceVethClass NMDeviceVethClass; NM_AVAILABLE_IN_1_30 diff --git a/src/libnm-client-public/nm-device-vlan.h b/src/libnm-client-public/nm-device-vlan.h index c392058695..c74453fdbd 100644 --- a/src/libnm-client-public/nm-device-vlan.h +++ b/src/libnm-client-public/nm-device-vlan.h @@ -31,6 +31,7 @@ G_BEGIN_DECLS /** * NMDeviceVlan: */ +typedef struct _NMDeviceVlan NMDeviceVlan; typedef struct _NMDeviceVlanClass NMDeviceVlanClass; GType nm_device_vlan_get_type(void); diff --git a/src/libnm-client-public/nm-device-vrf.h b/src/libnm-client-public/nm-device-vrf.h index 3b59023acc..fbc8b20224 100644 --- a/src/libnm-client-public/nm-device-vrf.h +++ b/src/libnm-client-public/nm-device-vrf.h @@ -25,6 +25,7 @@ G_BEGIN_DECLS /** * NMDeviceVrf: */ +typedef struct _NMDeviceVrf NMDeviceVrf; typedef struct _NMDeviceVrfClass NMDeviceVrfClass; NM_AVAILABLE_IN_1_24 diff --git a/src/libnm-client-public/nm-device-vxlan.h b/src/libnm-client-public/nm-device-vxlan.h index 5264e9caf5..7939539d61 100644 --- a/src/libnm-client-public/nm-device-vxlan.h +++ b/src/libnm-client-public/nm-device-vxlan.h @@ -46,6 +46,7 @@ G_BEGIN_DECLS /** * NMDeviceVxlan: */ +typedef struct _NMDeviceVxlan NMDeviceVxlan; typedef struct _NMDeviceVxlanClass NMDeviceVxlanClass; NM_AVAILABLE_IN_1_2 diff --git a/src/libnm-client-public/nm-device-wifi-p2p.h b/src/libnm-client-public/nm-device-wifi-p2p.h index cf68b496b9..ad0ca43664 100644 --- a/src/libnm-client-public/nm-device-wifi-p2p.h +++ b/src/libnm-client-public/nm-device-wifi-p2p.h @@ -34,6 +34,7 @@ G_BEGIN_DECLS * * Since: 1.16 */ +typedef struct _NMDeviceWifiP2P NMDeviceWifiP2P; typedef struct _NMDeviceWifiP2PClass NMDeviceWifiP2PClass; NM_AVAILABLE_IN_1_16 diff --git a/src/libnm-client-public/nm-device-wifi.h b/src/libnm-client-public/nm-device-wifi.h index 1c767316ae..287b792e80 100644 --- a/src/libnm-client-public/nm-device-wifi.h +++ b/src/libnm-client-public/nm-device-wifi.h @@ -36,6 +36,7 @@ G_BEGIN_DECLS /** * NMDeviceWifi: */ +typedef struct _NMDeviceWifi NMDeviceWifi; typedef struct _NMDeviceWifiClass NMDeviceWifiClass; GType nm_device_wifi_get_type(void); diff --git a/src/libnm-client-public/nm-device-wimax.h b/src/libnm-client-public/nm-device-wimax.h index 123b95b26c..e62288192c 100644 --- a/src/libnm-client-public/nm-device-wimax.h +++ b/src/libnm-client-public/nm-device-wimax.h @@ -39,6 +39,7 @@ G_BEGIN_DECLS * * Deprecated: 1.22: WiMAX is no longer supported by NetworkManager since 1.2.0. */ +typedef struct _NMDeviceWimax NMDeviceWimax; typedef struct _NMDeviceWimaxClass NMDeviceWimaxClass; NM_DEPRECATED_IN_1_2 diff --git a/src/libnm-client-public/nm-device-wireguard.h b/src/libnm-client-public/nm-device-wireguard.h index 4a18bd8117..756dfb4e46 100644 --- a/src/libnm-client-public/nm-device-wireguard.h +++ b/src/libnm-client-public/nm-device-wireguard.h @@ -28,6 +28,7 @@ G_BEGIN_DECLS /** * NMDeviceWireGuard: */ +typedef struct _NMDeviceWireGuard NMDeviceWireGuard; typedef struct _NMDeviceWireGuardClass NMDeviceWireGuardClass; #define NM_DEVICE_WIREGUARD_PUBLIC_KEY "public-key" diff --git a/src/libnm-client-public/nm-device-wpan.h b/src/libnm-client-public/nm-device-wpan.h index b8a7a3bf85..8b011851b1 100644 --- a/src/libnm-client-public/nm-device-wpan.h +++ b/src/libnm-client-public/nm-device-wpan.h @@ -28,6 +28,7 @@ G_BEGIN_DECLS /** * NMDeviceWpan: */ +typedef struct _NMDeviceWpan NMDeviceWpan; typedef struct _NMDeviceWpanClass NMDeviceWpanClass; NM_AVAILABLE_IN_1_14 diff --git a/src/libnm-client-public/nm-device.h b/src/libnm-client-public/nm-device.h index 9e9dbea64d..f58d3ddba8 100644 --- a/src/libnm-client-public/nm-device.h +++ b/src/libnm-client-public/nm-device.h @@ -62,6 +62,7 @@ _NM_DEPRECATED_SYNC_WRITABLE_PROPERTY /** * NMDevice: */ +typedef struct _NMDevice NMDevice; typedef struct _NMDeviceClass NMDeviceClass; /** diff --git a/src/libnm-client-public/nm-dhcp-config.h b/src/libnm-client-public/nm-dhcp-config.h index 0188f9c23e..625efb5844 100644 --- a/src/libnm-client-public/nm-dhcp-config.h +++ b/src/libnm-client-public/nm-dhcp-config.h @@ -25,6 +25,7 @@ G_BEGIN_DECLS /** * NMDhcpConfig: */ +typedef struct _NMDhcpConfig NMDhcpConfig; typedef struct _NMDhcpConfigClass NMDhcpConfigClass; #define NM_DHCP_CONFIG_FAMILY "family" diff --git a/src/libnm-client-public/nm-enum-types.c.template b/src/libnm-client-public/nm-enum-types.c.template index c2627f447d..5d693fe3e6 100644 --- a/src/libnm-client-public/nm-enum-types.c.template +++ b/src/libnm-client-public/nm-enum-types.c.template @@ -5,45 +5,9 @@ #include "nm-version-macros.h" #include "NetworkManager.h" -#include "nm-access-point.h" -#include "nm-active-connection.h" -#include "nm-checkpoint.h" -#include "nm-client.h" -#include "nm-device-adsl.h" -#include "nm-device-bond.h" -#include "nm-device-bridge.h" -#include "nm-device-bt.h" -#include "nm-device-dummy.h" -#include "nm-device-ethernet.h" -#include "nm-device-generic.h" -#include "nm-device-infiniband.h" -#include "nm-device-ip-tunnel.h" -#include "nm-device-macsec.h" -#include "nm-device-macvlan.h" -#include "nm-device-modem.h" -#include "nm-device-olpc-mesh.h" -#include "nm-device-ovs-interface.h" -#include "nm-device-ovs-port.h" -#include "nm-device-ovs-bridge.h" -#include "nm-device-ppp.h" -#include "nm-device-team.h" -#include "nm-device-tun.h" -#include "nm-device-vlan.h" -#include "nm-device-vxlan.h" -#include "nm-device-wifi.h" -#include "nm-device-wimax.h" -#include "nm-device.h" -#include "nm-dhcp-config.h" -#include "nm-ip-config.h" -#include "nm-object.h" -#include "nm-remote-connection.h" -#include "nm-types.h" -#include "nm-vpn-connection.h" -#include "nm-vpn-editor.h" -#include "nm-wimax-nsp.h" #include "nm-secret-agent-old.h" #include "nm-vpn-plugin-old.h" -#include "nm-vpn-service-plugin.h" + /*** END file-header ***/ /*** BEGIN value-header ***/ diff --git a/src/libnm-client-public/nm-ip-config.h b/src/libnm-client-public/nm-ip-config.h index 99b1948dbe..9ad15d30dc 100644 --- a/src/libnm-client-public/nm-ip-config.h +++ b/src/libnm-client-public/nm-ip-config.h @@ -27,6 +27,7 @@ G_BEGIN_DECLS /** * NMIPConfig: */ +typedef struct _NMIPConfig NMIPConfig; typedef struct _NMIPConfigClass NMIPConfigClass; #define NM_IP_CONFIG_FAMILY "family" diff --git a/src/libnm-client-public/nm-object.h b/src/libnm-client-public/nm-object.h index efa3aa536a..c6daf1e6ca 100644 --- a/src/libnm-client-public/nm-object.h +++ b/src/libnm-client-public/nm-object.h @@ -11,8 +11,6 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include "nm-types.h" - G_BEGIN_DECLS #define NM_TYPE_OBJECT (nm_object_get_type()) @@ -28,14 +26,17 @@ G_BEGIN_DECLS /** * NMObject: */ +typedef struct _NMObject NMObject; typedef struct _NMObjectClass NMObjectClass; GType nm_object_get_type(void); const char *nm_object_get_path(NMObject *object); +struct _NMClient; + NM_AVAILABLE_IN_1_24 -NMClient *nm_object_get_client(NMObject *object); +struct _NMClient *nm_object_get_client(NMObject *object); G_END_DECLS diff --git a/src/libnm-client-public/nm-remote-connection.h b/src/libnm-client-public/nm-remote-connection.h index 6104ecb817..f00b25d613 100644 --- a/src/libnm-client-public/nm-remote-connection.h +++ b/src/libnm-client-public/nm-remote-connection.h @@ -37,6 +37,7 @@ G_BEGIN_DECLS /** * NMRemoteConnection: */ +typedef struct _NMRemoteConnection NMRemoteConnection; typedef struct _NMRemoteConnectionClass NMRemoteConnectionClass; GType nm_remote_connection_get_type(void); diff --git a/src/libnm-client-public/nm-secret-agent-old.h b/src/libnm-client-public/nm-secret-agent-old.h index b45b12bb6a..ca7bfa4cc9 100644 --- a/src/libnm-client-public/nm-secret-agent-old.h +++ b/src/libnm-client-public/nm-secret-agent-old.h @@ -6,8 +6,6 @@ #ifndef __NM_SECRET_AGENT_OLD_H__ #define __NM_SECRET_AGENT_OLD_H__ -#include "nm-types.h" - G_BEGIN_DECLS #define NM_TYPE_SECRET_AGENT_OLD (nm_secret_agent_old_get_type()) diff --git a/src/libnm-client-public/nm-types.h b/src/libnm-client-public/nm-types.h deleted file mode 100644 index 81ffe790d5..0000000000 --- a/src/libnm-client-public/nm-types.h +++ /dev/null @@ -1,56 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2014 - 2018 Red Hat, Inc. - */ - -#ifndef __NM_TYPES_H__ -#define __NM_TYPES_H__ - -#include <gio/gio.h> - -#include "nm-dbus-interface.h" -#include "nm-connection.h" - -typedef struct _NMAccessPoint NMAccessPoint; -typedef struct _NMActiveConnection NMActiveConnection; -typedef struct _NMCheckpoint NMCheckpoint; -typedef struct _NMClient NMClient; -typedef struct _NMDevice NMDevice; -typedef struct _NMDevice6Lowpan NMDevice6Lowpan; -typedef struct _NMDeviceAdsl NMDeviceAdsl; -typedef struct _NMDeviceBond NMDeviceBond; -typedef struct _NMDeviceBridge NMDeviceBridge; -typedef struct _NMDeviceBt NMDeviceBt; -typedef struct _NMDeviceDummy NMDeviceDummy; -typedef struct _NMDeviceEthernet NMDeviceEthernet; -typedef struct _NMDeviceGeneric NMDeviceGeneric; -typedef struct _NMDeviceIPTunnel NMDeviceIPTunnel; -typedef struct _NMDeviceInfiniband NMDeviceInfiniband; -typedef struct _NMDeviceMacsec NMDeviceMacsec; -typedef struct _NMDeviceMacvlan NMDeviceMacvlan; -typedef struct _NMDeviceModem NMDeviceModem; -typedef struct _NMDeviceOlpcMesh NMDeviceOlpcMesh; -typedef struct _NMDeviceOvsBridge NMDeviceOvsBridge; -typedef struct _NMDeviceOvsInterface NMDeviceOvsInterface; -typedef struct _NMDeviceOvsPort NMDeviceOvsPort; -typedef struct _NMDevicePpp NMDevicePpp; -typedef struct _NMDeviceTeam NMDeviceTeam; -typedef struct _NMDeviceTun NMDeviceTun; -typedef struct _NMDeviceVeth NMDeviceVeth; -typedef struct _NMDeviceVlan NMDeviceVlan; -typedef struct _NMDeviceVrf NMDeviceVrf; -typedef struct _NMDeviceVxlan NMDeviceVxlan; -typedef struct _NMDeviceWifi NMDeviceWifi; -typedef struct _NMDeviceWifiP2P NMDeviceWifiP2P; -typedef struct _NMDeviceWimax NMDeviceWimax; -typedef struct _NMDeviceWireGuard NMDeviceWireGuard; -typedef struct _NMDeviceWpan NMDeviceWpan; -typedef struct _NMDhcpConfig NMDhcpConfig; -typedef struct _NMIPConfig NMIPConfig; -typedef struct _NMObject NMObject; -typedef struct _NMRemoteConnection NMRemoteConnection; -typedef struct _NMVpnConnection NMVpnConnection; -typedef struct _NMWifiP2PPeer NMWifiP2PPeer; -typedef struct _NMWimaxNsp NMWimaxNsp; - -#endif /* NM_TYPES_H */ diff --git a/src/libnm-client-public/nm-vpn-connection.h b/src/libnm-client-public/nm-vpn-connection.h index 33ca139d20..578c033349 100644 --- a/src/libnm-client-public/nm-vpn-connection.h +++ b/src/libnm-client-public/nm-vpn-connection.h @@ -32,6 +32,7 @@ G_BEGIN_DECLS /** * NMVpnConnection: */ +typedef struct _NMVpnConnection NMVpnConnection; typedef struct _NMVpnConnectionClass NMVpnConnectionClass; GType nm_vpn_connection_get_type(void); diff --git a/src/libnm-client-public/nm-vpn-editor.h b/src/libnm-client-public/nm-vpn-editor.h index f89617a897..9c4facb2b1 100644 --- a/src/libnm-client-public/nm-vpn-editor.h +++ b/src/libnm-client-public/nm-vpn-editor.h @@ -13,7 +13,6 @@ #include <glib.h> #include <glib-object.h> -#include "nm-types.h" #include "nm-vpn-editor-plugin.h" diff --git a/src/libnm-client-public/nm-vpn-plugin-old.h b/src/libnm-client-public/nm-vpn-plugin-old.h index 7704c1539e..fe0d4bc2cd 100644 --- a/src/libnm-client-public/nm-vpn-plugin-old.h +++ b/src/libnm-client-public/nm-vpn-plugin-old.h @@ -32,7 +32,7 @@ G_BEGIN_DECLS typedef struct { NM_DEPRECATED_IN_1_2 GObject parent; -} NMVpnPluginOld NM_DEPRECATED_IN_1_2; +} NMVpnPluginOld; typedef struct { NM_DEPRECATED_IN_1_2 @@ -85,7 +85,7 @@ typedef struct { /*< private >*/ NM_DEPRECATED_IN_1_2 gpointer padding[8]; -} NMVpnPluginOldClass NM_DEPRECATED_IN_1_2; +} NMVpnPluginOldClass; NM_DEPRECATED_IN_1_2 GType nm_vpn_plugin_old_get_type(void); diff --git a/src/libnm-client-public/nm-vpn-service-plugin.h b/src/libnm-client-public/nm-vpn-service-plugin.h index 81fb6730ae..5187d93d43 100644 --- a/src/libnm-client-public/nm-vpn-service-plugin.h +++ b/src/libnm-client-public/nm-vpn-service-plugin.h @@ -39,7 +39,7 @@ G_BEGIN_DECLS typedef struct { NM_AVAILABLE_IN_1_2 GObject parent; -} NMVpnServicePlugin NM_AVAILABLE_IN_1_2; +} NMVpnServicePlugin; typedef struct { NM_AVAILABLE_IN_1_2 @@ -92,7 +92,7 @@ typedef struct { /*< private >*/ NM_AVAILABLE_IN_1_2 gpointer padding[8]; -} NMVpnServicePluginClass NM_AVAILABLE_IN_1_2; +} NMVpnServicePluginClass; NM_AVAILABLE_IN_1_2 GType nm_vpn_service_plugin_get_type(void); diff --git a/src/libnm-client-public/nm-wifi-p2p-peer.h b/src/libnm-client-public/nm-wifi-p2p-peer.h index 73e6995cd2..eff27bcbb9 100644 --- a/src/libnm-client-public/nm-wifi-p2p-peer.h +++ b/src/libnm-client-public/nm-wifi-p2p-peer.h @@ -38,6 +38,7 @@ G_BEGIN_DECLS /** * NMWifiP2PPeer: */ +typedef struct _NMWifiP2PPeer NMWifiP2PPeer; typedef struct _NMWifiP2PPeerClass NMWifiP2PPeerClass; NM_AVAILABLE_IN_1_16 diff --git a/src/libnm-client-public/nm-wimax-nsp.h b/src/libnm-client-public/nm-wimax-nsp.h index f19272db5a..9cd4153ccb 100644 --- a/src/libnm-client-public/nm-wimax-nsp.h +++ b/src/libnm-client-public/nm-wimax-nsp.h @@ -33,6 +33,7 @@ G_BEGIN_DECLS * * Deprecated: 1.22: WiMAX is no longer supported by NetworkManager since 1.2.0. */ +typedef struct _NMWimaxNsp NMWimaxNsp; typedef struct _NMWimaxNspClass NMWimaxNspClass; GType nm_wimax_nsp_get_type(void); diff --git a/src/libnm-core-impl/nm-connection.c b/src/libnm-core-impl/nm-connection.c index 27cea2cb2b..aed4be2113 100644 --- a/src/libnm-core-impl/nm-connection.c +++ b/src/libnm-core-impl/nm-connection.c @@ -1708,7 +1708,7 @@ _normalize_required_settings(NMConnection *self) NMSetting *s_bridge; gboolean changed = FALSE; - if (nm_connection_get_setting_vlan(self)) { + if (nm_connection_get_setting_vlan(self) || nm_connection_get_setting_bridge(self)) { if (!nm_connection_get_setting_wired(self)) { nm_connection_add_setting(self, nm_setting_wired_new()); changed = TRUE; @@ -3168,22 +3168,24 @@ nm_connection_get_virtual_device_description(NMConnection *connection) iface = nm_connection_get_interface_name(connection); - if (!strcmp(type, NM_SETTING_BOND_SETTING_NAME)) + if (nm_streq(type, NM_SETTING_BOND_SETTING_NAME)) display_type = _("Bond"); - else if (!strcmp(type, NM_SETTING_TEAM_SETTING_NAME)) + else if (nm_streq(type, NM_SETTING_TEAM_SETTING_NAME)) display_type = _("Team"); - else if (!strcmp(type, NM_SETTING_BRIDGE_SETTING_NAME)) + else if (nm_streq(type, NM_SETTING_BRIDGE_SETTING_NAME)) display_type = _("Bridge"); - else if (!strcmp(type, NM_SETTING_VLAN_SETTING_NAME)) + else if (nm_streq(type, NM_SETTING_VLAN_SETTING_NAME)) display_type = _("VLAN"); - else if (!strcmp(type, NM_SETTING_INFINIBAND_SETTING_NAME)) { + else if (nm_streq(type, NM_SETTING_INFINIBAND_SETTING_NAME)) { display_type = _("InfiniBand"); iface = nm_setting_infiniband_get_virtual_interface_name( nm_connection_get_setting_infiniband(connection)); - } else if (!strcmp(type, NM_SETTING_IP_TUNNEL_SETTING_NAME)) + } else if (nm_streq(type, NM_SETTING_IP_TUNNEL_SETTING_NAME)) display_type = _("IP Tunnel"); - else if (!strcmp(type, NM_SETTING_WIREGUARD_SETTING_NAME)) + else if (nm_streq(type, NM_SETTING_WIREGUARD_SETTING_NAME)) display_type = _("WireGuard"); + else if (nm_streq(type, NM_SETTING_TUN_SETTING_NAME)) + display_type = _("TUN/TAP"); if (!iface || !display_type) return NULL; diff --git a/src/libnm-core-impl/nm-keyfile-utils.c b/src/libnm-core-impl/nm-keyfile-utils.c index c599aefa7b..95073bcc93 100644 --- a/src/libnm-core-impl/nm-keyfile-utils.c +++ b/src/libnm-core-impl/nm-keyfile-utils.c @@ -210,7 +210,7 @@ nm_keyfile_plugin_kf_set_integer_list_uint(GKeyFile *kf, g_return_if_fail(group && group[0]); g_return_if_fail(key && key[0]); - nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE); + strbuf = NM_STR_BUF_INIT(length * 4u + 2u, FALSE); for (i = 0; i < length; i++) nm_str_buf_append_printf(&strbuf, "%u;", data[i]); nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf)); @@ -231,7 +231,7 @@ nm_keyfile_plugin_kf_set_integer_list_uint8(GKeyFile *kf, g_return_if_fail(group && group[0]); g_return_if_fail(key && key[0]); - nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE); + strbuf = NM_STR_BUF_INIT(length * 4u + 2u, FALSE); for (i = 0; i < length; i++) nm_str_buf_append_printf(&strbuf, "%u;", (guint) data[i]); nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf)); @@ -542,7 +542,7 @@ _keyfile_key_encode(const char *name, char **out_to_free) len = i + strlen(&name[i]); nm_assert(len == strlen(name)); - nm_str_buf_init(&str, len + 15u, FALSE); + str = NM_STR_BUF_INIT(len + 15u, FALSE); if (name[0] == ' ') { nm_assert(i == 0); diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c index 00fb8a335d..76d15cb1a0 100644 --- a/src/libnm-core-impl/nm-keyfile.c +++ b/src/libnm-core-impl/nm-keyfile.c @@ -21,7 +21,6 @@ #include "libnm-glib-aux/nm-uuid.h" #include "libnm-glib-aux/nm-str-buf.h" #include "libnm-glib-aux/nm-secret-utils.h" -#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "libnm-core-aux-intern/nm-common-macros.h" #include "libnm-core-aux-intern/nm-libnm-core-utils.h" #include "libnm-core-intern/nm-core-internal.h" @@ -4062,7 +4061,7 @@ _write_setting_wireguard(NMSetting *setting, KeyfileWriterInfo *info) public_key = nm_wireguard_peer_get_public_key(peer); if (!public_key || !public_key[0] - || !NM_STRCHAR_ALL(public_key, ch, nm_sd_utils_unbase64char(ch, TRUE) >= 0)) { + || !NM_STRCHAR_ALL(public_key, ch, nm_unbase64char(ch) != -EINVAL)) { /* invalid peer. Skip it */ continue; } @@ -4375,7 +4374,7 @@ nm_keyfile_utils_create_filename(const char *name, gboolean with_extension) g_return_val_if_fail(name && name[0], NULL); - nm_str_buf_init(&str, 0, FALSE); + str = NM_STR_BUF_INIT(0, FALSE); len = strlen(name); diff --git a/src/libnm-core-impl/nm-setting-bond.c b/src/libnm-core-impl/nm-setting-bond.c index ae2fe051b2..2984e6fc22 100644 --- a/src/libnm-core-impl/nm-setting-bond.c +++ b/src/libnm-core-impl/nm-setting-bond.c @@ -362,15 +362,6 @@ _bond_get_option_normalized(NMSettingBond *self, const char *option, gboolean ge return _bond_get_option_or_default(self, option); } -const char * -nm_setting_bond_get_option_or_default(NMSettingBond *self, const char *option) -{ - g_return_val_if_fail(NM_IS_SETTING_BOND(self), NULL); - g_return_val_if_fail(option, NULL); - - return _bond_get_option_normalized(self, option, FALSE); -} - static int _atoi(const char *value) { diff --git a/src/libnm-core-impl/nm-setting-bridge.c b/src/libnm-core-impl/nm-setting-bridge.c index 41cd6632f2..39a3fb6017 100644 --- a/src/libnm-core-impl/nm-setting-bridge.c +++ b/src/libnm-core-impl/nm-setting-bridge.c @@ -435,7 +435,7 @@ nm_bridge_vlan_to_str(const NMBridgeVlan *vlan, GError **error) * future if more parameters are added to the object that could * make it invalid. */ - nm_str_buf_init(&string, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE); + string = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE); if (vlan->vid_start == vlan->vid_end) nm_str_buf_append_printf(&string, "%u", vlan->vid_start); @@ -1311,6 +1311,15 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) NM_SETTING_BRIDGE_VLANS)) return NM_SETTING_VERIFY_NORMALIZABLE; + if (connection && !nm_connection_get_setting_wired(connection)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_SETTING_NOT_FOUND, + _("bridge connection should have a ethernet setting as well")); + g_prefix_error(error, "%s: ", NM_SETTING_BRIDGE_SETTING_NAME); + return NM_SETTING_VERIFY_NORMALIZABLE; + } + return TRUE; } diff --git a/src/libnm-core-impl/nm-setting-ethtool.c b/src/libnm-core-impl/nm-setting-ethtool.c index 49c0d78097..71179efd39 100644 --- a/src/libnm-core-impl/nm-setting-ethtool.c +++ b/src/libnm-core-impl/nm-setting-ethtool.c @@ -45,11 +45,11 @@ get_variant_type_from_ethtool_id(NMEthtoolID ethtool_id) * * %Returns: %TRUE, if @optname is valid * - * Since: 1.20 - * * Note that nm_ethtool_optname_is_feature() was first added to the libnm header files * in 1.14.0 but forgot to actually add to the library. This happened belatedly in 1.20.0 and * the stable versions 1.18.2, 1.16.4 and 1.14.8 (with linker version "libnm_1_14_8"). + * + * Since: 1.20 */ gboolean nm_ethtool_optname_is_feature(const char *optname) diff --git a/src/libnm-core-impl/nm-setting-ip-config.c b/src/libnm-core-impl/nm-setting-ip-config.c index cffd5b19ff..1bad2e93b0 100644 --- a/src/libnm-core-impl/nm-setting-ip-config.c +++ b/src/libnm-core-impl/nm-setting-ip-config.c @@ -2481,10 +2481,10 @@ nm_ip_routing_rule_set_suppress_prefixlength(NMIPRoutingRule *self, gint32 suppr * * Returns: %TRUE if a uid range is set. * - * Since: 1.34 - * * This API was wrongly introduced in the header files for 1.32, but the * symbols were not exported. The API only works since 1.34 and newer. + * + * Since: 1.34 */ gboolean nm_ip_routing_rule_get_uid_range(const NMIPRoutingRule *self, @@ -2509,10 +2509,10 @@ nm_ip_routing_rule_get_uid_range(const NMIPRoutingRule *self, * For a valid range, start must be less or equal to end. * If set to an invalid range, the range gets unset. * - * Since: 1.34 - * * This API was wrongly introduced in the header files for 1.32, but the * symbols were not exported. The API only works since 1.34 and newer. + * + * Since: 1.34 */ void nm_ip_routing_rule_set_uid_range(NMIPRoutingRule *self, @@ -3814,7 +3814,7 @@ nm_ip_routing_rule_to_string(const NMIPRoutingRule *self, } } - nm_str_buf_init(&str, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE); + str = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE); if (self->priority_has) { nm_str_buf_append_printf(nm_str_buf_append_required_delimiter(&str, ' '), diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c index d5d884f2e4..0d3f6a6fda 100644 --- a/src/libnm-core-impl/nm-utils.c +++ b/src/libnm-core-impl/nm-utils.c @@ -23,7 +23,6 @@ #include "libnm-glib-aux/nm-enum-utils.h" #include "libnm-glib-aux/nm-time-utils.h" #include "libnm-glib-aux/nm-secret-utils.h" -#include "libnm-systemd-shared/nm-sd-utils-shared.h" #include "libnm-core-aux-intern/nm-common-macros.h" #include "nm-utils-private.h" #include "nm-setting-private.h" @@ -5356,7 +5355,7 @@ nm_utils_base64secret_decode(const char *base64_key, gsize required_key_len, gui base64_key_len = strlen(base64_key); - r = nm_sd_utils_unbase64mem(base64_key, base64_key_len, TRUE, &bin_arr, &bin_len); + r = nm_unbase64mem_full(base64_key, base64_key_len, TRUE, &bin_arr, &bin_len); if (r < 0) return FALSE; if (bin_len != required_key_len) { diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index 032f6a9a4c..f669bf8d80 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -491,8 +491,6 @@ typedef enum { NMBondOptionType _nm_setting_bond_get_option_type(NMSettingBond *setting, const char *name); -const char *nm_setting_bond_get_option_or_default(NMSettingBond *self, const char *option); - #define NM_BOND_AD_ACTOR_SYSTEM_DEFAULT "00:00:00:00:00:00" /*****************************************************************************/ diff --git a/src/libnm-core-intern/nm-keyfile-utils.h b/src/libnm-core-intern/nm-keyfile-utils.h index f79f020f67..08f169ac94 100644 --- a/src/libnm-core-intern/nm-keyfile-utils.h +++ b/src/libnm-core-intern/nm-keyfile-utils.h @@ -12,10 +12,6 @@ /*****************************************************************************/ -#include "libnm-glib-aux/nm-shared-utils.h" - -/*****************************************************************************/ - #define NM_KEYFILE_GROUP_VPN_SECRETS "vpn-secrets" #define NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER "wireguard-peer." diff --git a/src/libnm-core-public/nm-version-macros.h.in b/src/libnm-core-public/nm-version-macros.h.in index 516aded5e1..07e7989957 100644 --- a/src/libnm-core-public/nm-version-macros.h.in +++ b/src/libnm-core-public/nm-version-macros.h.in @@ -71,6 +71,7 @@ #define NM_VERSION_1_34 (NM_ENCODE_VERSION (1, 34, 0)) #define NM_VERSION_1_36 (NM_ENCODE_VERSION (1, 36, 0)) #define NM_VERSION_1_38 (NM_ENCODE_VERSION (1, 38, 0)) +#define NM_VERSION_1_40 (NM_ENCODE_VERSION (1, 40, 0)) /* For releases, NM_API_VERSION is equal to NM_VERSION. * diff --git a/src/libnm-core-public/nm-version.h b/src/libnm-core-public/nm-version.h index ac98f86819..22a79382e0 100644 --- a/src/libnm-core-public/nm-version.h +++ b/src/libnm-core-public/nm-version.h @@ -327,6 +327,20 @@ #define NM_AVAILABLE_IN_1_38 #endif +#if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_40 +#define NM_DEPRECATED_IN_1_40 G_DEPRECATED +#define NM_DEPRECATED_IN_1_40_FOR(f) G_DEPRECATED_FOR(f) +#else +#define NM_DEPRECATED_IN_1_40 +#define NM_DEPRECATED_IN_1_40_FOR(f) +#endif + +#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_40 +#define NM_AVAILABLE_IN_1_40 G_UNAVAILABLE(1, 40) +#else +#define NM_AVAILABLE_IN_1_40 +#endif + /* * Synchronous API for calling D-Bus in libnm is deprecated. See * https://developer.gnome.org/libnm/stable/usage.html#sync-api diff --git a/src/libnm-glib-aux/nm-default-glib.h b/src/libnm-glib-aux/nm-default-glib.h index 9d04ddc407..f39e16cc5b 100644 --- a/src/libnm-glib-aux/nm-default-glib.h +++ b/src/libnm-glib-aux/nm-default-glib.h @@ -33,27 +33,27 @@ #if NM_MORE_ASSERTS == 0 #ifndef G_DISABLE_CAST_CHECKS /* Unless compiling with G_DISABLE_CAST_CHECKS, glib performs type checking - * during G_VARIANT_TYPE() via g_variant_type_checked_(). This is not necessary - * because commonly this cast is needed during something like - * - * g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}")); - * - * Note that in if the variant type would be invalid, the check still - * wouldn't make the buggy code magically work. Instead of passing a - * bogus type string (bad), it would pass %NULL to g_variant_builder_init() - * (also bad). - * - * Also, a function like g_variant_builder_init() already validates - * the input type via something like - * - * g_return_if_fail (g_variant_type_is_container (type)); - * - * So, by having G_VARIANT_TYPE() also validate the type, we validate - * twice, whereas the first validation is rather pointless because it - * doesn't prevent the function to be called with invalid arguments. - * - * Just patch G_VARIANT_TYPE() to perform no check. - */ + * during G_VARIANT_TYPE() via g_variant_type_checked_(). This is not necessary + * because commonly this cast is needed during something like + * + * g_variant_builder_init (&props, G_VARIANT_TYPE ("a{sv}")); + * + * Note that in if the variant type would be invalid, the check still + * wouldn't make the buggy code magically work. Instead of passing a + * bogus type string (bad), it would pass %NULL to g_variant_builder_init() + * (also bad). + * + * Also, a function like g_variant_builder_init() already validates + * the input type via something like + * + * g_return_if_fail (g_variant_type_is_container (type)); + * + * So, by having G_VARIANT_TYPE() also validate the type, we validate + * twice, whereas the first validation is rather pointless because it + * doesn't prevent the function to be called with invalid arguments. + * + * Just patch G_VARIANT_TYPE() to perform no check. + */ #undef G_VARIANT_TYPE #define G_VARIANT_TYPE(type_string) ((const GVariantType *) (type_string)) #endif @@ -63,8 +63,6 @@ #include "nm-gassert-patch.h" -#include "libnm-std-aux/nm-std-aux.h" -#include "libnm-std-aux/nm-std-utils.h" #include "libnm-glib-aux/nm-macros-internal.h" #include "libnm-glib-aux/nm-shared-utils.h" #include "libnm-glib-aux/nm-errno.h" diff --git a/src/libnm-glib-aux/nm-enum-utils.c b/src/libnm-glib-aux/nm-enum-utils.c index 3b9b7e8d13..b7f7a3f6cc 100644 --- a/src/libnm-glib-aux/nm-enum-utils.c +++ b/src/libnm-glib-aux/nm-enum-utils.c @@ -142,7 +142,7 @@ _nm_utils_enum_to_str_full(GType type, flags_separator = flags_separator ?: " "; - nm_str_buf_init(&strbuf, 16, FALSE); + strbuf = NM_STR_BUF_INIT(16, FALSE); for (; value_infos && value_infos->nick; value_infos++) { nm_assert(_enum_is_valid_flags_nick(value_infos->nick)); diff --git a/src/libnm-glib-aux/nm-io-utils.c b/src/libnm-glib-aux/nm-io-utils.c index 503f044f30..0823a16c42 100644 --- a/src/libnm-glib-aux/nm-io-utils.c +++ b/src/libnm-glib-aux/nm-io-utils.c @@ -723,3 +723,288 @@ nm_sd_notify(const char *state) return 0; } + +/*****************************************************************************/ + +#define SHELL_NEED_ESCAPE "\"\\`$" + +int +nm_parse_env_file_full( + const char *contents, + int (*push)(unsigned line, const char *key, const char *value, void *userdata), + void *userdata) +{ + gsize last_value_whitespace = G_MAXSIZE; + gsize last_key_whitespace = G_MAXSIZE; + nm_auto_str_buf NMStrBuf key = NM_STR_BUF_INIT(0, FALSE); + nm_auto_str_buf NMStrBuf value = NM_STR_BUF_INIT(0, FALSE); + unsigned line = 1; + int r; + enum { + PRE_KEY, + KEY, + PRE_VALUE, + VALUE, + VALUE_ESCAPE, + SINGLE_QUOTE_VALUE, + DOUBLE_QUOTE_VALUE, + DOUBLE_QUOTE_VALUE_ESCAPE, + COMMENT, + COMMENT_ESCAPE + } state = PRE_KEY; + + /* Copied and adjusted from systemd's parse_env_file_internal(). + * https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L15 */ + + nm_assert(push); + + if (!contents) + return -ENOENT; + + for (const char *p = contents; *p; p++) { + char c = *p; + + switch (state) { + case PRE_KEY: + if (NM_IN_SET(c, '#', ';')) + state = COMMENT; + else if (!nm_ascii_is_whitespace(c)) { + state = KEY; + last_key_whitespace = G_MAXSIZE; + nm_str_buf_append_c(&key, c); + } + break; + + case KEY: + if (nm_ascii_is_newline(c)) { + state = PRE_KEY; + line++; + nm_str_buf_reset(&key); + } else if (c == '=') { + state = PRE_VALUE; + last_value_whitespace = G_MAXSIZE; + } else { + if (!nm_ascii_is_whitespace(c)) + last_key_whitespace = G_MAXSIZE; + else if (last_key_whitespace == G_MAXSIZE) + last_key_whitespace = key.len; + nm_str_buf_append_c(&key, c); + } + break; + + case PRE_VALUE: + if (nm_ascii_is_newline(c)) { + state = PRE_KEY; + line++; + + /* strip trailing whitespace from key */ + if (last_key_whitespace != G_MAXSIZE) + nm_str_buf_get_str_unsafe(&key)[last_key_whitespace] = 0; + + r = push(line, + nm_str_buf_get_str(&key), + nm_str_buf_get_str(&value) ?: "", + userdata); + if (r < 0) + return r; + + nm_str_buf_reset(&key); + nm_str_buf_reset(&value); + } else if (c == '\'') + state = SINGLE_QUOTE_VALUE; + else if (c == '"') + state = DOUBLE_QUOTE_VALUE; + else if (c == '\\') + state = VALUE_ESCAPE; + else if (!nm_ascii_is_whitespace(c)) { + state = VALUE; + nm_str_buf_append_c(&value, c); + } + + break; + + case VALUE: + if (nm_ascii_is_newline(c)) { + state = PRE_KEY; + line++; + + /* Chomp off trailing whitespace from value */ + if (last_value_whitespace != G_MAXSIZE) + nm_str_buf_get_str_unsafe(&value)[last_value_whitespace] = 0; + + /* strip trailing whitespace from key */ + if (last_key_whitespace != G_MAXSIZE) + nm_str_buf_get_str_unsafe(&key)[last_key_whitespace] = 0; + + r = push(line, + nm_str_buf_get_str(&key), + nm_str_buf_get_str(&value) ?: "", + userdata); + if (r < 0) + return r; + + nm_str_buf_reset(&key); + nm_str_buf_reset(&value); + } else if (c == '\\') { + state = VALUE_ESCAPE; + last_value_whitespace = G_MAXSIZE; + } else { + if (!nm_ascii_is_whitespace(c)) + last_value_whitespace = G_MAXSIZE; + else if (last_value_whitespace == G_MAXSIZE) + last_value_whitespace = value.len; + nm_str_buf_append_c(&value, c); + } + break; + + case VALUE_ESCAPE: + state = VALUE; + if (!nm_ascii_is_newline(c)) { + /* Escaped newlines we eat up entirely */ + nm_str_buf_append_c(&value, c); + } + break; + + case SINGLE_QUOTE_VALUE: + if (c == '\'') + state = PRE_VALUE; + else + nm_str_buf_append_c(&value, c); + break; + + case DOUBLE_QUOTE_VALUE: + if (c == '"') + state = PRE_VALUE; + else if (c == '\\') + state = DOUBLE_QUOTE_VALUE_ESCAPE; + else + nm_str_buf_append_c(&value, c); + break; + + case DOUBLE_QUOTE_VALUE_ESCAPE: + state = DOUBLE_QUOTE_VALUE; + if (strchr(SHELL_NEED_ESCAPE, c)) { + /* If this is a char that needs escaping, just unescape it. */ + nm_str_buf_append_c(&value, c); + } else if (c != '\n') { + /* If other char than what needs escaping, keep the "\" in place, like the + * real shell does. */ + nm_str_buf_append_c(&value, '\\', c); + } + /* Escaped newlines (aka "continuation lines") are eaten up entirely */ + break; + + case COMMENT: + if (c == '\\') + state = COMMENT_ESCAPE; + else if (nm_ascii_is_newline(c)) { + state = PRE_KEY; + line++; + } + break; + + case COMMENT_ESCAPE: + state = COMMENT; + break; + } + } + + if (NM_IN_SET(state, + PRE_VALUE, + VALUE, + VALUE_ESCAPE, + SINGLE_QUOTE_VALUE, + DOUBLE_QUOTE_VALUE, + DOUBLE_QUOTE_VALUE_ESCAPE)) { + if (state == VALUE) + if (last_value_whitespace != G_MAXSIZE) + nm_str_buf_get_str_unsafe(&value)[last_value_whitespace] = 0; + + /* strip trailing whitespace from key */ + if (last_key_whitespace != G_MAXSIZE) + nm_str_buf_get_str_unsafe(&key)[last_key_whitespace] = 0; + + r = push(line, nm_str_buf_get_str(&key), nm_str_buf_get_str(&value) ?: "", userdata); + if (r < 0) + return r; + } + + return 0; +} + +/*****************************************************************************/ + +static int +check_utf8ness_and_warn(const char *key, const char *value) +{ + /* Taken from systemd's check_utf8ness_and_warn() + * https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L273 */ + + if (!g_utf8_validate(key, -1, NULL)) + return -EINVAL; + + if (!g_utf8_validate(value, -1, NULL)) + return -EINVAL; + + return 0; +} + +static int +parse_env_file_push(unsigned line, const char *key, const char *value, void *userdata) +{ + const char *k; + va_list *ap = userdata; + va_list aq; + int r; + + r = check_utf8ness_and_warn(key, value); + if (r < 0) + return r; + + va_copy(aq, *ap); + + while ((k = va_arg(aq, const char *))) { + char **v; + + v = va_arg(aq, char **); + if (nm_streq(key, k)) { + va_end(aq); + g_free(*v); + *v = g_strdup(value); + return 1; + } + } + + va_end(aq); + return 0; +} + +int +nm_parse_env_filev(const char *contents, va_list ap) +{ + va_list aq; + int r; + + /* Copied from systemd's parse_env_filev(). + * https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L333 */ + + va_copy(aq, ap); + r = nm_parse_env_file_full(contents, parse_env_file_push, &aq); + va_end(aq); + return r; +} + +int +nm_parse_env_file_sentinel(const char *contents, ...) +{ + va_list ap; + int r; + + /* Copied from systemd's parse_env_file_sentinel(). + * https://github.com/systemd/systemd/blob/6247128902ca71ee2ad406cf69af04ea389d3d27/src/basic/env-file.c#L347 */ + + va_start(ap, contents); + r = nm_parse_env_filev(contents, ap); + va_end(ap); + return r; +} diff --git a/src/libnm-glib-aux/nm-io-utils.h b/src/libnm-glib-aux/nm-io-utils.h index a850398679..ef015153ca 100644 --- a/src/libnm-glib-aux/nm-io-utils.h +++ b/src/libnm-glib-aux/nm-io-utils.h @@ -77,4 +77,15 @@ int nm_io_sockaddr_un_set(struct sockaddr_un *ret, NMOptionBool is_abstract, con int nm_sd_notify(const char *state); +/*****************************************************************************/ + +int nm_parse_env_file_full( + const char *contents, + int (*push)(unsigned line, const char *key, const char *value, void *userdata), + void *userdata); + +int nm_parse_env_filev(const char *contents, va_list ap); +int nm_parse_env_file_sentinel(const char *contents, ...) G_GNUC_NULL_TERMINATED; +#define nm_parse_env_file(contents, ...) nm_parse_env_file_sentinel((contents), __VA_ARGS__, NULL) + #endif /* __NM_IO_UTILS_H__ */ diff --git a/src/libnm-glib-aux/nm-macros-internal.h b/src/libnm-glib-aux/nm-macros-internal.h index 7cc8ac9797..6f6aeff106 100644 --- a/src/libnm-glib-aux/nm-macros-internal.h +++ b/src/libnm-glib-aux/nm-macros-internal.h @@ -1053,6 +1053,24 @@ nm_g_variant_equal(GVariant *a, GVariant *b) * the kernel command line. */ #define NM_ASCII_WHITESPACES " \n\t\r" +static inline gboolean +nm_ascii_is_whitespace(char ch) +{ + /* Checks whether @ch is in NM_ASCII_WHITESPACES. + * Similar to g_ascii_isspace(), however this one does not accept '\f'. + * This is the same as systemd's strchr(WHITESPACE, ch). */ + return NM_IN_SET(ch, ' ', '\n', '\t', '\r'); +} + +#define NM_ASCII_NEWLINE "\n\r" + +static inline gboolean +nm_ascii_is_newline(char ch) +{ + /* This is the same as systemd's (!!strchr(NEWLINE, ch)). */ + return NM_IN_SET(ch, '\n', '\t'); +} + #define nm_str_skip_leading_spaces(str) \ ({ \ typeof(*(str)) *_str_sls = (str); \ diff --git a/src/libnm-glib-aux/nm-shared-utils.c b/src/libnm-glib-aux/nm-shared-utils.c index ad99a6b929..b8102cc8bc 100644 --- a/src/libnm-glib-aux/nm-shared-utils.c +++ b/src/libnm-glib-aux/nm-shared-utils.c @@ -37,6 +37,13 @@ const void *const _NM_PTRARRAY_EMPTY[1] = {NULL}; const NMIPAddr nm_ip_addr_zero = {}; +/* We use _nm_alignas(NMIPAddr). Ensure that this struct has the same + * alignment as in_addr_t and struct in6_addr. */ +G_STATIC_ASSERT(_nm_alignof(NMIPAddr) == 4); +G_STATIC_ASSERT(_nm_alignof(in_addr_t) == 4); +G_STATIC_ASSERT(_nm_alignof(struct in_addr) == 4); +G_STATIC_ASSERT(_nm_alignof(struct in6_addr) == 4); + /* this initializes a struct in_addr/in6_addr and allows for untrusted * arguments (like unsuitable @addr_family or @src_len). It's almost safe * in the sense that it verifies input arguments strictly. Also, it @@ -2998,7 +3005,7 @@ nm_utils_buf_utf8safe_unescape(const char *str, return str; } - nm_str_buf_init(&strbuf, len + 1u, FALSE); + strbuf = NM_STR_BUF_INIT(len + 1u, FALSE); nm_str_buf_append_len(&strbuf, str, s - str); str = s; @@ -3165,7 +3172,7 @@ nm_utils_buf_utf8safe_escape(gconstpointer buf, return str; } - nm_str_buf_init(&strbuf, buflen + 5, NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET)); + strbuf = NM_STR_BUF_INIT(buflen + 5, NM_FLAGS_HAS(flags, NM_UTILS_STR_UTF8_SAFE_FLAG_SECRET)); s = str; do { @@ -3432,51 +3439,6 @@ nm_utils_named_value_clear_with_g_free(NMUtilsNamedValue *val) G_STATIC_ASSERT(G_STRUCT_OFFSET(NMUtilsNamedValue, name) == 0); -NMUtilsNamedValue * -nm_utils_named_values_from_strdict_full(GHashTable *hash, - guint *out_len, - GCompareDataFunc compare_func, - gpointer user_data, - NMUtilsNamedValue *provided_buffer, - guint provided_buffer_len, - NMUtilsNamedValue **out_allocated_buffer) -{ - GHashTableIter iter; - NMUtilsNamedValue *values; - guint i, len; - - nm_assert(provided_buffer_len == 0 || provided_buffer); - nm_assert(!out_allocated_buffer || !*out_allocated_buffer); - - if (!hash || !(len = g_hash_table_size(hash))) { - NM_SET_OUT(out_len, 0); - return NULL; - } - - if (provided_buffer_len >= len + 1) { - /* the buffer provided by the caller is large enough. Use it. */ - values = provided_buffer; - } else { - /* allocate a new buffer. */ - values = g_new(NMUtilsNamedValue, len + 1); - NM_SET_OUT(out_allocated_buffer, values); - } - - i = 0; - g_hash_table_iter_init(&iter, hash); - while (g_hash_table_iter_next(&iter, (gpointer *) &values[i].name, &values[i].value_ptr)) - i++; - nm_assert(i == len); - values[i].name = NULL; - values[i].value_ptr = NULL; - - if (compare_func) - nm_utils_named_value_list_sort(values, len, compare_func, user_data); - - NM_SET_OUT(out_len, len); - return values; -} - gssize nm_utils_named_value_list_find(const NMUtilsNamedValue *arr, gsize len, @@ -3626,6 +3588,52 @@ nm_utils_hash_values_to_array(GHashTable *hash, return arr; } +NMUtilsNamedValue * +nm_utils_hash_to_array_full(GHashTable *hash, + guint *out_len, + GCompareDataFunc compare_func, + gpointer user_data, + NMUtilsNamedValue *provided_buffer, + guint provided_buffer_len, + NMUtilsNamedValue **out_allocated_buffer) +{ + GHashTableIter iter; + NMUtilsNamedValue *values; + guint len; + guint i; + + nm_assert(provided_buffer_len == 0 || provided_buffer); + nm_assert(!out_allocated_buffer || !*out_allocated_buffer); + + if (!hash || ((len = g_hash_table_size(hash)) == 0)) { + NM_SET_OUT(out_len, 0); + return NULL; + } + + if (provided_buffer_len >= len + 1) { + /* the buffer provided by the caller is large enough. Use it. */ + values = provided_buffer; + } else { + /* allocate a new buffer. */ + values = g_new(NMUtilsNamedValue, len + 1); + NM_SET_OUT(out_allocated_buffer, values); + } + + i = 0; + g_hash_table_iter_init(&iter, hash); + while (g_hash_table_iter_next(&iter, &values[i].name_ptr, &values[i].value_ptr)) + i++; + nm_assert(i == len); + values[i].name_ptr = NULL; + values[i].value_ptr = NULL; + + if (compare_func && len > 1) + g_qsort_with_data(values, len, sizeof(NMUtilsNamedValue), compare_func, user_data); + + NM_SET_OUT(out_len, len); + return values; +} + /*****************************************************************************/ /** @@ -5840,10 +5848,22 @@ _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact new_size = nm_utils_get_next_realloc_size(!strbuf->_priv_do_bzero_mem, new_size); } - strbuf->_priv_str = nm_secret_mem_realloc(strbuf->_priv_str, - strbuf->_priv_do_bzero_mem, - strbuf->_priv_allocated, - new_size); + if (strbuf->_priv_malloced) { + strbuf->_priv_str = nm_secret_mem_realloc(strbuf->_priv_str, + strbuf->_priv_do_bzero_mem, + strbuf->_priv_allocated, + new_size); + } else { + char *old = strbuf->_priv_str; + + strbuf->_priv_str = g_malloc(new_size); + if (strbuf->_priv_len > 0) { + memcpy(strbuf->_priv_str, old, strbuf->_priv_len); + if (strbuf->_priv_do_bzero_mem) + nm_explicit_bzero(old, strbuf->_priv_len); + } + strbuf->_priv_malloced = TRUE; + } strbuf->_priv_allocated = new_size; } @@ -6584,7 +6604,7 @@ nm_utils_validate_hostname(const char *hostname) if (dot) return FALSE; - return (p - hostname <= HOST_NAME_MAX); + return (p - hostname <= NM_HOST_NAME_MAX); } /*****************************************************************************/ @@ -6713,3 +6733,540 @@ nm_g_main_context_can_acquire(GMainContext *context) g_main_context_release(context); return TRUE; } + +/*****************************************************************************/ + +int +nm_unbase64char(char c) +{ + /* copied from systemd's unbase64char(): + * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/basic/hexdecoct.c#L539 */ + + switch (c) { + case 'A' ... 'Z': + return c - 'A'; + case 'a' ... 'z': + return (c - 'a') + ('Z' - 'A' + 1); + case '0' ... '9': + return (c - '0') + (('Z' - 'A' + 1) + ('z' - 'a' + 1)); + case '+': + return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1); + case '/': + return ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1) + 1; + case '=': + /* The padding is a different kind of base64 character. Return + * a special error code for it. */ + return -ERANGE; + default: + return -EINVAL; + } +} + +static int +unbase64_next(const char **p, size_t *l) +{ + int ret; + + nm_assert(p); + nm_assert(l); + + /* copied from systemd's unbase64_next(): + * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/basic/hexdecoct.c#L709 */ + + /* Find the next non-whitespace character, and decode it. If we find padding, we return it as INT_MAX. We + * greedily skip all preceding and all following whitespace. */ + + for (;;) { + if (*l == 0) + return -EPIPE; + + if (!nm_ascii_is_whitespace(**p)) + break; + + /* Skip leading whitespace */ + (*p)++; + (*l)--; + } + + ret = nm_unbase64char(**p); + if (ret < 0) { + nm_assert(NM_IN_SET(ret, -EINVAL, -ERANGE)); + if (ret != -ERANGE) + return ret; + } + + for (;;) { + (*p)++; + (*l)--; + + if (*l == 0) + break; + if (!nm_ascii_is_whitespace(**p)) + break; + + /* Skip following whitespace */ + } + + nm_assert(ret == -ERANGE || ret >= 0); + return ret; +} + +/** + * nm_unbase64mem_full: + * @p: a valid base64 string. Whitespace is ignored, but invalid encodings + * will cause the function to fail. + * @l: the length of @p. @p is not treated as NUL terminated string but + * merely as a buffer of ascii characters. + * @secure: whether the temporary memory will be cleared to avoid leaving + * secrets in memory (see also nm_explicit_bzero()). + * @mem: (transfer full): the decoded buffer on success. + * @len: the length of @mem on success. + * + * glib provides g_base64_decode(), but that does not report any errors + * from invalid encodings. Our own implementation (based on systemd code) + * rejects invalid inputs. + * + * Returns: a non-negative code on success. Invalid encoding let the + * function fail. + */ +int +nm_unbase64mem_full(const char *p, gsize l, gboolean secure, guint8 **ret, gsize *ret_size) +{ + gs_free uint8_t *buf = NULL; + const char *x; + guint8 *z; + gsize len; + int r; + + /* copied from systemd's unbase64mem_full(): + * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/basic/hexdecoct.c#L751 */ + + nm_assert(p || l == 0); + + if (l == G_MAXSIZE) + l = strlen(p); + + /* A group of four input bytes needs three output bytes, in case of padding we need to add two or three extra + * bytes. Note that this calculation is an upper boundary, as we ignore whitespace while decoding */ + len = (l / 4) * 3 + (l % 4 != 0 ? (l % 4) - 1 : 0); + + buf = g_malloc(len + 1); + + for (x = p, z = buf;;) { + int a; /* a == 00XXXXXX */ + int b; /* b == 00YYYYYY */ + int c; /* c == 00ZZZZZZ */ + int d; /* d == 00WWWWWW */ + + a = unbase64_next(&x, &l); + if (a < 0) { + if (a == -EPIPE) /* End of string */ + break; + if (a == -ERANGE) { /* Padding is not allowed at the beginning of a 4ch block */ + r = -EINVAL; + goto on_failure; + } + r = a; + goto on_failure; + } + + b = unbase64_next(&x, &l); + if (b < 0) { + if (b == -ERANGE) { + /* Padding is not allowed at the second character of a 4ch block either */ + r = -EINVAL; + goto on_failure; + } + r = b; + goto on_failure; + } + + c = unbase64_next(&x, &l); + if (c < 0) { + if (c != -ERANGE) { + r = c; + goto on_failure; + } + } + + d = unbase64_next(&x, &l); + if (d < 0) { + if (d != -ERANGE) { + r = d; + goto on_failure; + } + } + + if (c == -ERANGE) { /* Padding at the third character */ + + if (d != -ERANGE) { /* If the third character is padding, the fourth must be too */ + r = -EINVAL; + goto on_failure; + } + + /* b == 00YY0000 */ + if (b & 15) { + r = -EINVAL; + goto on_failure; + } + + if (l > 0) { /* Trailing rubbish? */ + r = -ENAMETOOLONG; + goto on_failure; + } + + *(z++) = (uint8_t) a << 2 | (uint8_t) (b >> 4); /* XXXXXXYY */ + break; + } + + if (d == -ERANGE) { + /* c == 00ZZZZ00 */ + if (c & 3) { + r = -EINVAL; + goto on_failure; + } + + if (l > 0) { /* Trailing rubbish? */ + r = -ENAMETOOLONG; + goto on_failure; + } + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + break; + } + + *(z++) = (uint8_t) a << 2 | (uint8_t) b >> 4; /* XXXXXXYY */ + *(z++) = (uint8_t) b << 4 | (uint8_t) c >> 2; /* YYYYZZZZ */ + *(z++) = (uint8_t) c << 6 | (uint8_t) d; /* ZZWWWWWW */ + } + + *z = '\0'; + + NM_SET_OUT(ret_size, (gsize) (z - buf)); + NM_SET_OUT(ret, g_steal_pointer(&buf)); + return 0; + +on_failure: + if (secure) + nm_explicit_bzero(buf, len); + return r; +} + +/*****************************************************************************/ + +static const char * +skip_slash_or_dot(const char *p) +{ + for (; !nm_str_is_empty(p);) { + if (p[0] == '/') { + p += 1; + continue; + } + if (p[0] == '.' && p[1] == '/') { + p += 2; + continue; + } + break; + } + return p; +} + +int +nm_path_find_first_component(const char **p, gboolean accept_dot_dot, const char **ret) +{ + const char *q, *first, *end_first, *next; + size_t len; + + /* Copied from systemd's path_compare() + * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L809 */ + + nm_assert(p); + + /* When a path is input, then returns the pointer to the first component and its length, and + * move the input pointer to the next component or nul. This skips both over any '/' + * immediately *before* and *after* the first component before returning. + * + * Examples + * Input: p: "//.//aaa///bbbbb/cc" + * Output: p: "bbbbb///cc" + * ret: "aaa///bbbbb/cc" + * return value: 3 (== strlen("aaa")) + * + * Input: p: "aaa//" + * Output: p: (pointer to NUL) + * ret: "aaa//" + * return value: 3 (== strlen("aaa")) + * + * Input: p: "/", ".", "" + * Output: p: (pointer to NUL) + * ret: NULL + * return value: 0 + * + * Input: p: NULL + * Output: p: NULL + * ret: NULL + * return value: 0 + * + * Input: p: "(too long component)" + * Output: return value: -EINVAL + * + * (when accept_dot_dot is false) + * Input: p: "//..//aaa///bbbbb/cc" + * Output: return value: -EINVAL + */ + + q = *p; + + first = skip_slash_or_dot(q); + if (nm_str_is_empty(first)) { + *p = first; + if (ret) + *ret = NULL; + return 0; + } + if (nm_streq(first, ".")) { + *p = first + 1; + if (ret) + *ret = NULL; + return 0; + } + + end_first = strchrnul(first, '/'); + len = end_first - first; + + if (len > NAME_MAX) + return -EINVAL; + if (!accept_dot_dot && len == 2 && first[0] == '.' && first[1] == '.') + return -EINVAL; + + next = skip_slash_or_dot(end_first); + + *p = next + (nm_streq(next, ".") ? 1 : 0); + if (ret) + *ret = first; + return len; +} + +int +nm_path_compare(const char *a, const char *b) +{ + /* Copied from systemd's path_compare() + * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L415 */ + + /* Order NULL before non-NULL */ + NM_CMP_SELF(a, b); + + /* A relative path and an absolute path must not compare as equal. + * Which one is sorted before the other does not really matter. + * Here a relative path is ordered before an absolute path. */ + NM_CMP_DIRECT(nm_path_is_absolute(a), nm_path_is_absolute(b)); + + for (;;) { + const char *aa, *bb; + int j, k; + + j = nm_path_find_first_component(&a, TRUE, &aa); + k = nm_path_find_first_component(&b, TRUE, &bb); + + if (j < 0 || k < 0) { + /* When one of paths is invalid, order invalid path after valid one. */ + NM_CMP_DIRECT(j < 0, k < 0); + + /* fallback to use strcmp() if both paths are invalid. */ + NM_CMP_DIRECT_STRCMP(a, b); + return 0; + } + + /* Order prefixes first: "/foo" before "/foo/bar" */ + if (j == 0) { + if (k == 0) + return 0; + return -1; + } + if (k == 0) + return 1; + + /* Alphabetical sort: "/foo/aaa" before "/foo/b" */ + NM_CMP_DIRECT_MEMCMP(aa, bb, NM_MIN(j, k)); + + /* Sort "/foo/a" before "/foo/aaa" */ + NM_CMP_DIRECT(j, k); + } +} + +char * +nm_path_startswith_full(const char *path, const char *prefix, gboolean accept_dot_dot) +{ + /* Copied from systemd's path_startswith_full() + * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L375 */ + + nm_assert(path); + nm_assert(prefix); + + /* Returns a pointer to the start of the first component after the parts matched by + * the prefix, iff + * - both paths are absolute or both paths are relative, + * and + * - each component in prefix in turn matches a component in path at the same position. + * An empty string will be returned when the prefix and path are equivalent. + * + * Returns NULL otherwise. + */ + + if ((path[0] == '/') != (prefix[0] == '/')) + return NULL; + + for (;;) { + const char *p, *q; + int r, k; + + r = nm_path_find_first_component(&path, accept_dot_dot, &p); + if (r < 0) + return NULL; + + k = nm_path_find_first_component(&prefix, accept_dot_dot, &q); + if (k < 0) + return NULL; + + if (k == 0) + return (char *) (p ?: path); + + if (r != k) + return NULL; + + if (strncmp(p, q, r) != 0) + return NULL; + } +} + +char * +nm_path_simplify(char *path) +{ + bool add_slash = false; + char *f = path; + int r; + + /* Copied from systemd's path_simplify() + * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.c#L325 */ + + nm_assert(path); + + /* Removes redundant inner and trailing slashes. Also removes unnecessary dots. + * Modifies the passed string in-place. + * + * ///foo//./bar/. becomes /foo/bar + * .//./foo//./bar/. becomes foo/bar + */ + + if (path[0] == '\0') + return path; + + if (nm_path_is_absolute(path)) + f++; + + for (const char *p = f;;) { + const char *e; + + r = nm_path_find_first_component(&p, TRUE, &e); + if (r == 0) + break; + + if (add_slash) + *f++ = '/'; + + if (r < 0) { + /* if path is invalid, then refuse to simplify remaining part. */ + memmove(f, p, strlen(p) + 1); + return path; + } + + memmove(f, e, r); + f += r; + + add_slash = TRUE; + } + + /* Special rule, if we stripped everything, we need a "." for the current directory. */ + if (f == path) + *f++ = '.'; + + *f = '\0'; + return path; +} + +/*****************************************************************************/ + +static gboolean +valid_ldh_char(char c) +{ + /* "LDH" ā "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */ + + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '-'; +} + +/** + * nm_hostname_is_valid: + * @s: the hostname to check. + * @trailing_dot: Accept trailing dot on multi-label names. + * + * Return: %TRUE if valid. + */ +gboolean +nm_hostname_is_valid(const char *s, gboolean trailing_dot) +{ + unsigned n_dots = 0; + const char *p; + gboolean dot; + gboolean hyphen; + + /* Copied from systemd's hostname_is_valid() + * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/hostname-util.c#L85 */ + + /* Check if s looks like a valid hostname or FQDN. This does not do full DNS validation, but only + * checks if the name is composed of allowed characters and the length is not above the maximum + * allowed by Linux (c.f. dns_name_is_valid()). A trailing dot is allowed if + * VALID_HOSTNAME_TRAILING_DOT flag is set and at least two components are present in the name. Note + * that due to the restricted charset and length this call is substantially more conservative than + * dns_name_is_valid(). Doesn't accept empty hostnames, hostnames with leading dots, and hostnames + * with multiple dots in a sequence. Doesn't allow hyphens at the beginning or end of label. */ + + if (nm_str_is_empty(s)) + return FALSE; + + for (p = s, dot = hyphen = TRUE; *p; p++) + if (*p == '.') { + if (dot || hyphen) + return FALSE; + + dot = TRUE; + hyphen = FALSE; + n_dots++; + + } else if (*p == '-') { + if (dot) + return FALSE; + + dot = FALSE; + hyphen = TRUE; + + } else { + if (!valid_ldh_char(*p)) + return FALSE; + + dot = FALSE; + hyphen = FALSE; + } + + if (dot && (n_dots < 2 || !trailing_dot)) + return FALSE; + if (hyphen) + return FALSE; + + /* Note that HOST_NAME_MAX is 64 on Linux, but DNS allows domain names up to + * 255 characters */ + if (p - s > NM_HOST_NAME_MAX) + return FALSE; + + return TRUE; +} diff --git a/src/libnm-glib-aux/nm-shared-utils.h b/src/libnm-glib-aux/nm-shared-utils.h index daefa068c9..0e123cf1c0 100644 --- a/src/libnm-glib-aux/nm-shared-utils.h +++ b/src/libnm-glib-aux/nm-shared-utils.h @@ -216,7 +216,7 @@ nm_ether_addr_equal(const NMEtherAddr *a, const NMEtherAddr *b) typedef struct { union { - guint8 addr_ptr[1]; + guint8 addr_ptr[sizeof(struct in6_addr)]; in_addr_t addr4; struct in_addr addr4_struct; struct in6_addr addr6; @@ -1977,6 +1977,7 @@ typedef struct { NMUtilsNamedEntry named_entry; const char *name; char *name_mutable; + gpointer name_ptr; }; union { const char *value_str; @@ -1990,14 +1991,28 @@ typedef struct { .name = (n), .value_ptr = (v) \ } -NMUtilsNamedValue * -nm_utils_named_values_from_strdict_full(GHashTable *hash, - guint *out_len, - GCompareDataFunc compare_func, - gpointer user_data, - NMUtilsNamedValue *provided_buffer, - guint provided_buffer_len, - NMUtilsNamedValue **out_allocated_buffer); +NMUtilsNamedValue *nm_utils_hash_to_array_full(GHashTable *hash, + guint *out_len, + GCompareDataFunc compare_func, + gpointer user_data, + NMUtilsNamedValue *provided_buffer, + guint provided_buffer_len, + NMUtilsNamedValue **out_allocated_buffer); + +#define nm_utils_named_values_from_strdict_full(hash, \ + out_len, \ + compare_func, \ + user_data, \ + provided_buffer, \ + provided_buffer_len, \ + out_allocated_buffer) \ + nm_utils_hash_to_array_full((hash), \ + (out_len), \ + (compare_func), \ + (user_data), \ + (provided_buffer), \ + (provided_buffer_len), \ + (out_allocated_buffer)) #define nm_utils_named_values_from_strdict(hash, out_len, array, out_allocated_buffer) \ nm_utils_named_values_from_strdict_full((hash), \ @@ -2038,6 +2053,29 @@ gpointer *nm_utils_hash_values_to_array(GHashTable *hash, gpointer user_data, guint *out_len); +static inline NMUtilsNamedValue * +nm_utils_hash_to_array(GHashTable *hash, + GCompareDataFunc compare_func, + gpointer user_data, + guint *out_len) +{ + return nm_utils_hash_to_array_full(hash, out_len, compare_func, user_data, NULL, 0, NULL); +} + +#define nm_utils_hash_to_array_with_buffer(hash, \ + out_len, \ + compare_func, \ + user_data, \ + array, \ + out_allocated_buffer) \ + nm_utils_hash_to_array_full((hash), \ + (out_len), \ + (compare_func), \ + (user_data), \ + (array), \ + G_N_ELEMENTS(array), \ + (out_allocated_buffer)) + static inline const char ** nm_strdict_get_keys(const GHashTable *hash, gboolean sorted, guint *out_length) { @@ -3224,6 +3262,12 @@ char *_nm_utils_format_variant_attributes(GHashTable *a /*****************************************************************************/ +/* glibc defines HOST_NAME_MAX as 64. Also Linux' sethostname() enforces + * that (__NEW_UTS_LEN). However, musl sets this to 255. + * + * At some places, we want to follow Linux. Hardcode our own define. */ +#define NM_HOST_NAME_MAX 64 + gboolean nm_utils_is_localhost(const char *name); gboolean nm_utils_is_specific_hostname(const char *name); @@ -3276,4 +3320,46 @@ gboolean nm_utils_validate_hostname(const char *hostname); void nm_utils_thread_local_register_destroy(gpointer tls_data, GDestroyNotify destroy_notify); +/*****************************************************************************/ + +int nm_unbase64char(char c); +int nm_unbase64mem_full(const char *p, gsize l, gboolean secure, guint8 **ret, gsize *ret_size); + +/*****************************************************************************/ + +static inline gboolean +nm_path_is_absolute(const char *p) +{ + /* Copied from systemd's path_is_absolute() + * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/basic/path-util.h#L50 */ + + nm_assert(p); + return p[0] == '/'; +} + +int nm_path_find_first_component(const char **p, gboolean accept_dot_dot, const char **ret); + +int nm_path_compare(const char *a, const char *b); + +static inline gboolean +nm_path_equal(const char *a, const char *b) +{ + return nm_path_compare(a, b) == 0; +} + +char *nm_path_simplify(char *path); + +char * +nm_path_startswith_full(const char *path, const char *prefix, gboolean accept_dot_dot) _nm_pure; + +static inline char * +nm_path_startswith(const char *path, const char *prefix) +{ + return nm_path_startswith_full(path, prefix, TRUE); +} + +/*****************************************************************************/ + +gboolean nm_hostname_is_valid(const char *s, gboolean trailing_dot); + #endif /* __NM_SHARED_UTILS_H__ */ diff --git a/src/libnm-glib-aux/nm-str-buf.h b/src/libnm-glib-aux/nm-str-buf.h index 47d1f055be..9a3c5baf42 100644 --- a/src/libnm-glib-aux/nm-str-buf.h +++ b/src/libnm-glib-aux/nm-str-buf.h @@ -26,6 +26,7 @@ typedef struct _NMStrBuf { }; bool _priv_do_bzero_mem; + bool _priv_malloced; } NMStrBuf; /*****************************************************************************/ @@ -36,29 +37,56 @@ _nm_str_buf_assert(const NMStrBuf *strbuf) nm_assert(strbuf); nm_assert((!!strbuf->_priv_str) == (strbuf->_priv_allocated > 0)); nm_assert(strbuf->_priv_len <= strbuf->_priv_allocated); + nm_assert(!strbuf->_priv_malloced || strbuf->_priv_str); } static inline NMStrBuf -NM_STR_BUF_INIT(gsize allocated, gboolean do_bzero_mem) +NM_STR_BUF_INIT_FULL(char *str, + gsize len, + gsize allocated, + gboolean malloced, + gboolean do_bzero_mem) { NMStrBuf strbuf = { - ._priv_str = allocated ? g_malloc(allocated) : NULL, + ._priv_str = allocated > 0 ? str : NULL, ._priv_allocated = allocated, - ._priv_len = 0, + ._priv_len = len, ._priv_do_bzero_mem = do_bzero_mem, + ._priv_malloced = allocated > 0 && malloced, }; + _nm_str_buf_assert(&strbuf); + return strbuf; } -static inline void -nm_str_buf_init(NMStrBuf *strbuf, gsize len, bool do_bzero_mem) +static inline NMStrBuf +NM_STR_BUF_INIT(gsize allocated, gboolean do_bzero_mem) { - nm_assert(strbuf); - *strbuf = NM_STR_BUF_INIT(len, do_bzero_mem); - _nm_str_buf_assert(strbuf); + return NM_STR_BUF_INIT_FULL(allocated > 0 ? g_malloc(allocated) : NULL, + 0, + allocated, + allocated > 0, + do_bzero_mem); } +#define NM_STR_BUF_INIT_A(size, do_bzero_mem) \ + NM_STR_BUF_INIT_FULL( \ + g_alloca(size), \ + 0, \ + NM_STATIC_ASSERT_EXPR_1((size) > 0 && (size) <= NM_UTILS_GET_NEXT_REALLOC_SIZE_488) \ + ? (size) \ + : 0, \ + FALSE, \ + (do_bzero_mem)); + +#define NM_STR_BUF_INIT_ARR(arr, do_bzero_mem) \ + NM_STR_BUF_INIT_FULL((arr), \ + 0, \ + NM_STATIC_ASSERT_EXPR_1(sizeof(arr) > sizeof(char *)) ? sizeof(arr) : 0, \ + FALSE, \ + (do_bzero_mem)); + void _nm_str_buf_ensure_size(NMStrBuf *strbuf, gsize new_size, gboolean reserve_exact); static inline void @@ -359,10 +387,10 @@ static inline gboolean nm_str_buf_is_initalized(NMStrBuf *strbuf) { nm_assert(strbuf); -#if NM_MORE_ASSERTS - if (strbuf->_priv_str) - _nm_str_buf_assert(strbuf); -#endif + if (NM_MORE_ASSERTS > 0) { + if (strbuf->_priv_str) + _nm_str_buf_assert(strbuf); + } return !!strbuf->_priv_str; } @@ -399,6 +427,29 @@ nm_str_buf_get_str(NMStrBuf *strbuf) return strbuf->_priv_str; } +/** + * nm_str_buf_get_str_unsafe: + * @strbuf: the buffer + * + * Usually, NMStrBuf is used to construct NUL terminated strings. But + * while constructing the buffer (nm_str_buf_append*()), it does + * not NUL terminate the buffer yet. Only nm_str_buf_get_str() + * and nm_str_buf_finalize() ensure that the returned string is + * actually NUL terminated. + * + * NMStrBuf can also be used for binary data, or you might not + * require the NUL termination. In that case, nm_str_buf_get_str_unsafe() + * will give you the pointer, but you must not rely on it being NUL + * terminated. This is the "unsafe" part of it. + * + * The returned string is of course initialized up to length "strbuf->len" + * and allocated with "strbuf->allocated" bytes. + * + * If currently no buffer is allocated, %NULL is returned. + * + * Returns: (transfer none): very similar to nm_str_buf_get_str(), + * except that the result is no guaranteed to be NUL terminated. + */ static inline char * nm_str_buf_get_str_unsafe(NMStrBuf *strbuf) { @@ -440,9 +491,11 @@ nm_str_buf_get_char(const NMStrBuf *strbuf, gsize index) * Returns: (transfer full): the string of the buffer * which must be freed by the caller. The @strbuf * is afterwards in undefined state, though it can be - * reused after nm_str_buf_init(). - * Note that if no string is allocated yet (after nm_str_buf_init() with - * length zero), this will return %NULL. */ + * reused after resetting with NM_STR_BUF_INIT(). + * Note that if no string is allocated yet (after NM_STR_BUF_INIT() with + * length zero), this will return %NULL. + * + * If the buffer was not malloced before, it will be malloced now. */ static inline char * nm_str_buf_finalize(NMStrBuf *strbuf, gsize *out_len) { @@ -453,6 +506,16 @@ nm_str_buf_finalize(NMStrBuf *strbuf, gsize *out_len) if (!strbuf->_priv_str) return NULL; + if (!strbuf->_priv_malloced) { + char *str = g_steal_pointer(&strbuf->_priv_str); + char *result; + + result = g_strndup(str, strbuf->_priv_len); + if (strbuf->_priv_do_bzero_mem) + nm_explicit_bzero(str, strbuf->_priv_len); + return result; + } + nm_str_buf_maybe_expand(strbuf, 1, TRUE); strbuf->_priv_str[strbuf->_priv_len] = '\0'; @@ -484,7 +547,7 @@ nm_str_buf_finalize_to_gbytes(NMStrBuf *strbuf) * * Frees the associated memory of @strbuf. The buffer * afterwards is in undefined state, but can be re-initialized - * with nm_str_buf_init(). + * with NM_STR_BUF_INIT(). */ static inline void nm_str_buf_destroy(NMStrBuf *strbuf) @@ -494,7 +557,8 @@ nm_str_buf_destroy(NMStrBuf *strbuf) _nm_str_buf_assert(strbuf); if (strbuf->_priv_do_bzero_mem) nm_explicit_bzero(strbuf->_priv_str, strbuf->_priv_len); - g_free(strbuf->_priv_str); + if (strbuf->_priv_malloced) + g_free(strbuf->_priv_str); /* the buffer is in invalid state afterwards, however, we clear it * so far, that nm_auto_str_buf is happy when calling diff --git a/src/libnm-glib-aux/nm-test-utils.h b/src/libnm-glib-aux/nm-test-utils.h index 2dfe9e323e..83702070b8 100644 --- a/src/libnm-glib-aux/nm-test-utils.h +++ b/src/libnm-glib-aux/nm-test-utils.h @@ -185,7 +185,7 @@ #define nmtst_assert_strv(strv, ...) \ G_STMT_START \ { \ - const char *const *const _strv = (strv); \ + const char *const *const _strv = NM_CAST_STRV_CC(strv); \ const char *const _exp[] = {__VA_ARGS__, NULL}; \ const gsize _n = G_N_ELEMENTS(_exp) - 1; \ gsize _i; \ @@ -196,6 +196,7 @@ g_assert(_exp[_i]); \ g_assert_cmpstr(_strv[_i], ==, _exp[_i]); \ } \ + g_assert(!_strv[_n]); \ } \ G_STMT_END diff --git a/src/libnm-glib-aux/tests/test-shared-general.c b/src/libnm-glib-aux/tests/test-shared-general.c index 46689947e1..5e9310f5ac 100644 --- a/src/libnm-glib-aux/tests/test-shared-general.c +++ b/src/libnm-glib-aux/tests/test-shared-general.c @@ -10,6 +10,7 @@ #include "libnm-glib-aux/nm-str-buf.h" #include "libnm-glib-aux/nm-time-utils.h" #include "libnm-glib-aux/nm-ref-string.h" +#include "libnm-glib-aux/nm-io-utils.h" #include "libnm-glib-aux/nm-test-utils.h" @@ -781,6 +782,9 @@ test_nm_utils_get_next_realloc_size(void) {NM_UTILS_GET_NEXT_REALLOC_SIZE_232, NM_UTILS_GET_NEXT_REALLOC_SIZE_232, NM_UTILS_GET_NEXT_REALLOC_SIZE_232}, + {NM_UTILS_GET_NEXT_REALLOC_SIZE_488, + NM_UTILS_GET_NEXT_REALLOC_SIZE_488, + NM_UTILS_GET_NEXT_REALLOC_SIZE_488}, {NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000}, @@ -913,27 +917,58 @@ test_nm_str_buf(void) { guint i_run; - for (i_run = 0; TRUE; i_run++) { - nm_auto_str_buf NMStrBuf strbuf = {}; - nm_auto_free_gstring GString *gstr = NULL; + for (i_run = 0; i_run < 1000; i_run++) { + char stack_buf[1024]; + nm_auto_str_buf NMStrBuf strbuf; + nm_auto_free_gstring GString *gstr = NULL; int i, j, k; int c; - nm_str_buf_init(&strbuf, nmtst_get_rand_uint32() % 200u + 1u, nmtst_get_rand_bool()); + switch (nmtst_get_rand_uint32() % 10) { + case 0: + memset(&strbuf, 0, sizeof(strbuf)); + break; + case 1 ... 4: + strbuf = NM_STR_BUF_INIT_FULL(stack_buf, + 0, + nmtst_get_rand_uint32() % sizeof(stack_buf), + FALSE, + nmtst_get_rand_bool()); + break; + default: + strbuf = NM_STR_BUF_INIT(nmtst_get_rand_uint32() % 200u + 1u, nmtst_get_rand_bool()); + break; + } - if (i_run < 1000) { - c = nmtst_get_rand_word_length(NULL); - for (i = 0; i < c; i++) - nm_str_buf_append_c(&strbuf, '0' + (i % 10)); - gstr = g_string_new(nm_str_buf_get_str(&strbuf)); - j = nmtst_get_rand_uint32() % (strbuf.len + 1); - k = nmtst_get_rand_uint32() % (strbuf.len - j + 2) - 1; + c = nmtst_get_rand_word_length(NULL); + for (i = 0; i < c; i++) + nm_str_buf_append_c(&strbuf, '0' + (i % 10)); + gstr = g_string_new(nm_str_buf_get_str(&strbuf)); + j = nmtst_get_rand_uint32() % (strbuf.len + 1); + k = nmtst_get_rand_uint32() % (strbuf.len - j + 2) - 1; - nm_str_buf_erase(&strbuf, j, k, nmtst_get_rand_bool()); - g_string_erase(gstr, j, k); + nm_str_buf_erase(&strbuf, j, k, nmtst_get_rand_bool()); + g_string_erase(gstr, j, k); + if (gstr->str[0]) g_assert_cmpstr(gstr->str, ==, nm_str_buf_get_str(&strbuf)); + else + g_assert(NM_IN_STRSET(nm_str_buf_get_str(&strbuf), NULL, "")); + } + + for (i_run = 0; i_run < 50; i_run++) { + char stack_buf[20]; + nm_auto_str_buf NMStrBuf strbuf = NM_STR_BUF_INIT_ARR(stack_buf, nmtst_get_rand_bool()); + + nm_str_buf_append_c_len(&strbuf, 'a', nmtst_get_rand_uint32() % (sizeof(stack_buf) * 2)); + if (strbuf.len <= sizeof(stack_buf)) { + g_assert(stack_buf == nm_str_buf_get_str_unsafe(&strbuf)); } else - return; + g_assert(stack_buf != nm_str_buf_get_str_unsafe(&strbuf)); + + if (strbuf.len < sizeof(stack_buf)) { + g_assert(stack_buf == nm_str_buf_get_str(&strbuf)); + } else + g_assert(stack_buf != nm_str_buf_get_str(&strbuf)); } } @@ -1417,6 +1452,755 @@ test_nm_ascii(void) /*****************************************************************************/ +static int +_env_file_push_cb(unsigned line, const char *key, const char *value, void *user_data) +{ + char ***strv = user_data; + char *s_line; + gsize key_l; + gsize strv_l; + gsize i; + + g_assert(strv); + g_assert(key); + g_assert(key[0]); + g_assert(!strchr(key, '=')); + g_assert(value); + + key_l = strlen(key); + + s_line = g_strconcat(key, "=", value, NULL); + + strv_l = 0; + if (*strv) { + const char *s; + + for (i = 0; (s = (*strv)[i]); i++) { + if (g_str_has_prefix(s, key) && s[key_l] == '=') { + g_free((*strv)[i]); + (*strv)[i] = s_line; + return 0; + } + } + strv_l = i; + } + + *strv = g_realloc(*strv, sizeof(char *) * (strv_l + 2)); + (*strv)[strv_l] = s_line; + (*strv)[strv_l + 1] = NULL; + + return 0; +} + +static void +test_parse_env_file(void) +{ + gs_strfreev char **data = NULL; + gs_free char *arg1 = NULL; + gs_free char *arg2 = NULL; + int r; + +#define env_file_1 \ + "a=a\n" \ + "a=b\n" \ + "a=b\n" \ + "a=a\n" \ + "b=b\\\n" \ + "c\n" \ + "d= d\\\n" \ + "e \\\n" \ + "f \n" \ + "g=g\\ \n" \ + "h= Ä
ÄĆ³Å\\ ÅÄÅÅŗżĀµ \n" \ + "i=i\\" + r = nm_parse_env_file_full(env_file_1, _env_file_push_cb, &data); + g_assert_cmpint(r, ==, 0); + nmtst_assert_strv(data, "a=a", "b=bc", "d=de f", "g=g ", "h=Ä
ÄĆ³Å ÅÄÅÅŗżĀµ", "i=i"); + nm_clear_pointer(&data, g_strfreev); + + r = nm_parse_env_file(env_file_1, "a", &arg1); + g_assert_cmpint(r, ==, 0); + g_assert_cmpstr(arg1, ==, "a"); + nm_clear_g_free(&arg1); + + r = nm_parse_env_file(env_file_1, "a", &arg1, "d", &arg2); + g_assert_cmpint(r, ==, 0); + g_assert_cmpstr(arg1, ==, "a"); + g_assert_cmpstr(arg2, ==, "de f"); + nm_clear_g_free(&arg1); + nm_clear_g_free(&arg2); + +#define env_file_2 "a=a\\\n" + r = nm_parse_env_file_full(env_file_2, _env_file_push_cb, &data); + g_assert_cmpint(r, ==, 0); + nmtst_assert_strv(data, "a=a"); + nm_clear_pointer(&data, g_strfreev); + +#define env_file_3 \ + "#SPAMD_ARGS=\"-d --socketpath=/var/lib/bulwark/spamd \\\n" \ + "#--nouser-config \\\n" \ + "normal=line \\\n" \ + ";normal=ignored \\\n" \ + "normal_ignored \\\n" \ + "normal ignored \\\n" + r = nm_parse_env_file_full(env_file_3, _env_file_push_cb, &data); + g_assert_cmpint(r, ==, 0); + g_assert(!data); + +#define env_file_4 \ + "# Generated\n" \ + "\n" \ + "HWMON_MODULES=\"coretemp f71882fg\"\n" \ + "\n" \ + "# For compatibility reasons\n" \ + "\n" \ + "MODULE_0=coretemp\n" \ + "MODULE_1=f71882fg" + r = nm_parse_env_file_full(env_file_4, _env_file_push_cb, &data); + g_assert_cmpint(r, ==, 0); + nmtst_assert_strv(data, + "HWMON_MODULES=coretemp f71882fg", + "MODULE_0=coretemp", + "MODULE_1=f71882fg"); + nm_clear_pointer(&data, g_strfreev); + +#define env_file_5 \ + "a=\n" \ + "b=" + r = nm_parse_env_file_full(env_file_5, _env_file_push_cb, &data); + g_assert_cmpint(r, ==, 0); + nmtst_assert_strv(data, "a=", "b="); + nm_clear_pointer(&data, g_strfreev); + +#define env_file_6 \ + "a=\\ \\n \\t \\x \\y \\' \n" \ + "b= \\$' \n" \ + "c= ' \\n\\t\\$\\`\\\\\n" \ + "' \n" \ + "d= \" \\n\\t\\$\\`\\\\\n" \ + "\" \n" + r = nm_parse_env_file_full(env_file_6, _env_file_push_cb, &data); + g_assert_cmpint(r, ==, 0); + nmtst_assert_strv(data, "a= n t x y '", "b=$'", "c= \\n\\t\\$\\`\\\\\n", "d= \\n\\t$`\\\n"); + nm_clear_pointer(&data, g_strfreev); +} + +/*****************************************************************************/ + +static void +test_unbase64char(void) +{ + static const int expected[128] = { + [0] = -1, [1] = -1, [2] = -1, [3] = -1, [4] = -1, [5] = -1, [6] = -1, + [7] = -1, [8] = -1, [9] = -1, [10] = -1, [11] = -1, [12] = -1, [13] = -1, + [14] = -1, [15] = -1, [16] = -1, [17] = -1, [18] = -1, [19] = -1, [20] = -1, + [21] = -1, [22] = -1, [23] = -1, [24] = -1, [25] = -1, [26] = -1, [27] = -1, + [28] = -1, [29] = -1, [30] = -1, [31] = -1, [32] = -1, [33] = -1, [34] = -1, + [35] = -1, [36] = -1, [37] = -1, [38] = -1, [39] = -1, [40] = -1, [41] = -1, + [42] = -1, ['+'] = 62, [44] = -1, [45] = -1, [46] = -1, ['/'] = 63, ['0'] = 52, + ['1'] = 53, ['2'] = 54, ['3'] = 55, ['4'] = 56, ['5'] = 57, ['6'] = 58, ['7'] = 59, + ['8'] = 60, ['9'] = 61, [58] = -1, [59] = -1, [60] = -1, [61] = -1, [62] = -1, + [63] = -1, [64] = -1, ['A'] = 0, ['B'] = 1, ['C'] = 2, ['D'] = 3, ['E'] = 4, + ['F'] = 5, ['G'] = 6, ['H'] = 7, ['I'] = 8, ['J'] = 9, ['K'] = 10, ['L'] = 11, + ['M'] = 12, ['N'] = 13, ['O'] = 14, ['P'] = 15, ['Q'] = 16, ['R'] = 17, ['S'] = 18, + ['T'] = 19, ['U'] = 20, ['V'] = 21, ['W'] = 22, ['X'] = 23, ['Y'] = 24, ['Z'] = 25, + [91] = -1, [92] = -1, [93] = -1, [94] = -1, [95] = -1, [96] = -1, ['a'] = 26, + ['b'] = 27, ['c'] = 28, ['d'] = 29, ['e'] = 30, ['f'] = 31, ['g'] = 32, ['h'] = 33, + ['i'] = 34, ['j'] = 35, ['k'] = 36, ['l'] = 37, ['m'] = 38, ['n'] = 39, ['o'] = 40, + ['p'] = 41, ['q'] = 42, ['r'] = 43, ['s'] = 44, ['t'] = 45, ['u'] = 46, ['v'] = 47, + ['w'] = 48, ['x'] = 49, ['y'] = 50, ['z'] = 51, [123] = -1, [124] = -1, [125] = -1, + [126] = -1, [127] = -1, + }; + int i; + + /* Copied from systemd's TEST(unbase64char) + * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L44 */ + + g_assert_cmpint(nm_unbase64char('A'), ==, 0); + g_assert_cmpint(nm_unbase64char('Z'), ==, 25); + g_assert_cmpint(nm_unbase64char('a'), ==, 26); + g_assert_cmpint(nm_unbase64char('z'), ==, 51); + g_assert_cmpint(nm_unbase64char('0'), ==, 52); + g_assert_cmpint(nm_unbase64char('9'), ==, 61); + g_assert_cmpint(nm_unbase64char('+'), ==, 62); + g_assert_cmpint(nm_unbase64char('/'), ==, 63); + g_assert_cmpint(nm_unbase64char('='), ==, -ERANGE); + g_assert_cmpint(nm_unbase64char('\0'), ==, -EINVAL); + g_assert_cmpint(nm_unbase64char('\1'), ==, -EINVAL); + g_assert_cmpint(nm_unbase64char('\x7F'), ==, -EINVAL); + g_assert_cmpint(nm_unbase64char('\x80'), ==, -EINVAL); + g_assert_cmpint(nm_unbase64char('\xFF'), ==, -EINVAL); + + for (i = 0; i < 256; i++) { + int base64; + + base64 = nm_unbase64char((char) i); + + if (base64 < 0) { + if (((char) i) == '=') + g_assert_cmpint(base64, ==, -ERANGE); + else + g_assert_cmpint(base64, ==, -EINVAL); + base64 = -1; + } + + if (i >= G_N_ELEMENTS(expected)) { + g_assert_cmpint(base64, ==, -1); + continue; + } + g_assert_cmpint(base64, ==, expected[i]); + } +} + +/*****************************************************************************/ + +static void +test_unbase64mem1(void) +{ + nm_auto_str_buf NMStrBuf encoded_wrapped = NM_STR_BUF_INIT(400, FALSE); + uint8_t data[4096]; + int i_run; + + /* Copied from systemd's TEST(base64mem_linebreak) + * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L280 */ + + for (i_run = 0; i_run < 20; i_run++) { + gs_free char *encoded = NULL; + gs_free guint8 *decoded = NULL; + gsize decoded_size; + guint64 n; + guint64 m; + guint64 i; + guint64 j; + gssize l; + int r; + + /* Try a bunch of differently sized blobs */ + n = nmtst_get_rand_uint64() % sizeof(data); + nmtst_rand_buf(NULL, data, n); + + /* Break at various different columns */ + m = 1 + (nmtst_get_rand_uint64() % (n + 5)); + + encoded = g_base64_encode(data, n); + g_assert(encoded); + l = strlen(encoded); + + nm_str_buf_reset(&encoded_wrapped); + for (i = 0, j = 0; i < l; i++, j++) { + if (j == m) { + nm_str_buf_append_c(&encoded_wrapped, '\n'); + j = 0; + } + nm_str_buf_append_c(&encoded_wrapped, encoded[i]); + } + + g_assert_cmpint(strlen(nm_str_buf_get_str(&encoded_wrapped)), ==, encoded_wrapped.len); + + r = nm_unbase64mem_full(nm_str_buf_get_str(&encoded_wrapped), + nmtst_get_rand_bool() ? SIZE_MAX : encoded_wrapped.len, + nmtst_get_rand_bool(), + &decoded, + &decoded_size); + g_assert_cmpint(r, >=, 0); + g_assert_cmpmem(data, n, decoded, decoded_size); + + for (j = 0; j < encoded_wrapped.len; j++) + g_assert((nm_str_buf_get_str(&encoded_wrapped)[j] == '\n') == (j % (m + 1) == m)); + } +} + +/*****************************************************************************/ + +static void +_assert_unbase64mem(const char *input, const char *output, int ret) +{ + gs_free guint8 *buffer = NULL; + gsize size = 0; + int r; + + r = nm_unbase64mem_full(input, SIZE_MAX, nmtst_get_rand_bool(), &buffer, &size); + g_assert_cmpint(r, ==, ret); + + if (ret >= 0) { + g_assert_cmpmem(buffer, size, output, strlen(output)); + g_assert_cmpint(((const char *) buffer)[size], ==, '\0'); + } else { + g_assert(!buffer); + g_assert_cmpint(size, ==, 0); + } +} + +static void +test_unbase64mem2(void) +{ + /* Copied from systemd's TEST(unbase64mem) + * https://github.com/systemd/systemd/blob/688efe7703328c5a0251fafac55757b8864a9f9a/src/test/test-hexdecoct.c#L324 */ + + _assert_unbase64mem("", "", 0); + _assert_unbase64mem("Zg==", "f", 0); + _assert_unbase64mem("Zm8=", "fo", 0); + _assert_unbase64mem("Zm9v", "foo", 0); + _assert_unbase64mem("Zm9vYg==", "foob", 0); + _assert_unbase64mem("Zm9vYmE=", "fooba", 0); + _assert_unbase64mem("Zm9vYmFy", "foobar", 0); + + _assert_unbase64mem(" ", "", 0); + _assert_unbase64mem(" \n\r ", "", 0); + _assert_unbase64mem(" Zg\n== ", "f", 0); + _assert_unbase64mem(" Zm 8=\r", "fo", 0); + _assert_unbase64mem(" Zm9\n\r\r\nv ", "foo", 0); + _assert_unbase64mem(" Z m9vYg==\n\r", "foob", 0); + _assert_unbase64mem(" Zm 9vYmE= ", "fooba", 0); + _assert_unbase64mem(" Z m9v YmFy ", "foobar", 0); + + _assert_unbase64mem("A", NULL, -EPIPE); + _assert_unbase64mem("A====", NULL, -EINVAL); + _assert_unbase64mem("AAB==", NULL, -EINVAL); + _assert_unbase64mem(" A A A B = ", NULL, -EINVAL); + _assert_unbase64mem(" Z m 8 = q u u x ", NULL, -ENAMETOOLONG); +} + +/*****************************************************************************/ + +static void +_test_unbase64mem_mem(const char *base64, const guint8 *expected_arr, gsize expected_len) +{ + gs_free char *expected_base64 = NULL; + int r; + nm_auto_free guint8 *exp2_arr = NULL; + nm_auto_free guint8 *exp3_arr = NULL; + gsize exp2_len; + gsize exp3_len; + + expected_base64 = g_base64_encode(expected_arr, expected_len); + + r = nm_unbase64mem_full(expected_base64, strlen(expected_base64), TRUE, &exp2_arr, &exp2_len); + g_assert_cmpint(r, ==, 0); + g_assert_cmpmem(expected_arr, expected_len, exp2_arr, exp2_len); + + if (!nm_streq(base64, expected_base64)) { + r = nm_unbase64mem_full(base64, strlen(base64), TRUE, &exp3_arr, &exp3_len); + g_assert_cmpint(r, ==, 0); + g_assert_cmpmem(expected_arr, expected_len, exp3_arr, exp3_len); + } +} + +#define _test_unbase64mem(base64, expected_str) \ + _test_unbase64mem_mem(base64, (const guint8 *) "" expected_str "", NM_STRLEN(expected_str)) + +static void +_test_unbase64mem_inval(const char *base64) +{ + gs_free guint8 *exp_arr = NULL; + gsize exp_len = 0; + int r; + + r = nm_unbase64mem_full(base64, strlen(base64), TRUE, &exp_arr, &exp_len); + g_assert_cmpint(r, <, 0); + g_assert(!exp_arr); + g_assert(exp_len == 0); +} + +static void +test_unbase64mem3(void) +{ + gs_free char *rnd_base64 = NULL; + guint8 rnd_buf[30]; + guint i, rnd_len; + + _test_unbase64mem("", ""); + _test_unbase64mem(" ", ""); + _test_unbase64mem(" Y Q == ", "a"); + _test_unbase64mem(" Y WJjZGV mZ 2g = ", "abcdefgh"); + _test_unbase64mem_inval(" Y %WJjZGV mZ 2g = "); + _test_unbase64mem_inval(" Y %WJjZGV mZ 2g = a"); + _test_unbase64mem("YQ==", "a"); + _test_unbase64mem_inval("YQ==a"); + + rnd_len = nmtst_get_rand_uint32() % sizeof(rnd_buf); + for (i = 0; i < rnd_len; i++) + rnd_buf[i] = nmtst_get_rand_uint32() % 256; + rnd_base64 = g_base64_encode(rnd_buf, rnd_len); + _test_unbase64mem_mem(rnd_base64, rnd_buf, rnd_len); +} + +/*****************************************************************************/ + +static void +assert_path_compare(const char *a, const char *b, int expected) +{ + int r; + + g_assert(NM_IN_SET(expected, -1, 0, 1)); + + g_assert_cmpint(nm_path_compare(a, a), ==, 0); + g_assert_cmpint(nm_path_compare(b, b), ==, 0); + + r = nm_path_compare(a, b); + g_assert_cmpint(r, ==, expected); + r = nm_path_compare(b, a); + g_assert_cmpint(r, ==, -expected); + + g_assert(nm_path_equal(a, a) == 1); + g_assert(nm_path_equal(b, b) == 1); + g_assert(nm_path_equal(a, b) == (expected == 0)); + g_assert(nm_path_equal(b, a) == (expected == 0)); +} + +static void +test_path_compare(void) +{ + /* Copied from systemd. + * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/test/test-path-util.c#L126 */ + + assert_path_compare("/goo", "/goo", 0); + assert_path_compare("/goo", "/goo", 0); + assert_path_compare("//goo", "/goo", 0); + assert_path_compare("//goo/////", "/goo", 0); + assert_path_compare("goo/////", "goo", 0); + assert_path_compare("/goo/boo", "/goo//boo", 0); + assert_path_compare("//goo/boo", "/goo/boo//", 0); + assert_path_compare("//goo/././//./boo//././//", "/goo/boo//.", 0); + assert_path_compare("/.", "//.///", 0); + assert_path_compare("/x", "x/", 1); + assert_path_compare("x/", "/", -1); + assert_path_compare("/x/./y", "x/y", 1); + assert_path_compare("/x/./y", "/x/y", 0); + assert_path_compare("/x/./././y", "/x/y/././.", 0); + assert_path_compare("./x/./././y", "./x/y/././.", 0); + assert_path_compare(".", "./.", 0); + assert_path_compare(".", "././.", 0); + assert_path_compare("./..", ".", 1); + assert_path_compare("x/.y", "x/y", -1); + assert_path_compare("foo", "/foo", -1); + assert_path_compare("/foo", "/foo/bar", -1); + assert_path_compare("/foo/aaa", "/foo/b", -1); + assert_path_compare("/foo/aaa", "/foo/b/a", -1); + assert_path_compare("/foo/a", "/foo/aaa", -1); + assert_path_compare("/foo/a/b", "/foo/aaa", -1); +} + +/*****************************************************************************/ + +static void +test_path_equal(void) +{ +#define _path_equal_check(path, expected) \ + G_STMT_START \ + { \ + const char *_path0 = (path); \ + const char *_expected = (expected); \ + gs_free char *_path = g_strdup(_path0); \ + const char *_path_result; \ + \ + _path_result = nm_path_simplify(_path); \ + g_assert(_path_result == _path); \ + g_assert_cmpstr(_path, ==, _expected); \ + } \ + G_STMT_END + + _path_equal_check("", ""); + _path_equal_check(".", "."); + _path_equal_check("..", ".."); + _path_equal_check("/..", "/.."); + _path_equal_check("//..", "/.."); + _path_equal_check("/.", "/"); + _path_equal_check("./", "."); + _path_equal_check("./.", "."); + _path_equal_check(".///.", "."); + _path_equal_check(".///./", "."); + _path_equal_check(".////", "."); + _path_equal_check("//..//foo/", "/../foo"); + _path_equal_check("///foo//./bar/.", "/foo/bar"); + _path_equal_check(".//./foo//./bar/.", "foo/bar"); +} + +/*****************************************************************************/ + +static void +assert_path_find_first_component(const char *path, + gboolean accept_dot_dot, + const char *const *expected, + int ret) +{ + const char *p; + + for (p = path;;) { + const char *e; + int r; + + r = nm_path_find_first_component(&p, accept_dot_dot, &e); + if (r <= 0) { + if (r == 0) { + if (path) + g_assert(p == path + strlen(path)); + else + g_assert(!p); + g_assert(!e); + } + g_assert(r == ret); + g_assert(!expected || !*expected); + return; + } + + g_assert(e); + g_assert(strcspn(e, "/") == (size_t) r); + g_assert(strlen(*expected) == (size_t) r); + g_assert(strncmp(e, *expected++, r) == 0); + } +} + +static void +test_path_find_first_component(void) +{ + gs_free char *hoge = NULL; + char foo[NAME_MAX * 2]; + + /* Copied from systemd. + * https://github.com/systemd/systemd/blob/bc85f8b51d962597360e982811e674c126850f56/src/test/test-path-util.c#L631 */ + + assert_path_find_first_component(NULL, false, NULL, 0); + assert_path_find_first_component("", false, NULL, 0); + assert_path_find_first_component("/", false, NULL, 0); + assert_path_find_first_component(".", false, NULL, 0); + assert_path_find_first_component("./", false, NULL, 0); + assert_path_find_first_component("./.", false, NULL, 0); + assert_path_find_first_component("..", false, NULL, -EINVAL); + assert_path_find_first_component("/..", false, NULL, -EINVAL); + assert_path_find_first_component("./..", false, NULL, -EINVAL); + assert_path_find_first_component("////./././//.", false, NULL, 0); + assert_path_find_first_component("a/b/c", false, NM_MAKE_STRV("a", "b", "c"), 0); + assert_path_find_first_component("././//.///aa/bbb//./ccc", + false, + NM_MAKE_STRV("aa", "bbb", "ccc"), + 0); + assert_path_find_first_component("././//.///aa/.../../bbb//./ccc/.", + false, + NM_MAKE_STRV("aa", "..."), + -EINVAL); + assert_path_find_first_component("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", + false, + NM_MAKE_STRV("aaa", ".bbb"), + -EINVAL); + assert_path_find_first_component("a/foo./b", false, NM_MAKE_STRV("a", "foo.", "b"), 0); + + assert_path_find_first_component(NULL, true, NULL, 0); + assert_path_find_first_component("", true, NULL, 0); + assert_path_find_first_component("/", true, NULL, 0); + assert_path_find_first_component(".", true, NULL, 0); + assert_path_find_first_component("./", true, NULL, 0); + assert_path_find_first_component("./.", true, NULL, 0); + assert_path_find_first_component("..", true, NM_MAKE_STRV(".."), 0); + assert_path_find_first_component("/..", true, NM_MAKE_STRV(".."), 0); + assert_path_find_first_component("./..", true, NM_MAKE_STRV(".."), 0); + assert_path_find_first_component("////./././//.", true, NULL, 0); + assert_path_find_first_component("a/b/c", true, NM_MAKE_STRV("a", "b", "c"), 0); + assert_path_find_first_component("././//.///aa/bbb//./ccc", + true, + NM_MAKE_STRV("aa", "bbb", "ccc"), + 0); + assert_path_find_first_component("././//.///aa/.../../bbb//./ccc/.", + true, + NM_MAKE_STRV("aa", "...", "..", "bbb", "ccc"), + 0); + assert_path_find_first_component("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", + true, + NM_MAKE_STRV("aaa", ".bbb", "..", "c.", "d.dd", "..eeee"), + 0); + assert_path_find_first_component("a/foo./b", true, NM_MAKE_STRV("a", "foo.", "b"), 0); + + memset(foo, 'a', sizeof(foo) - 1); + foo[sizeof(foo) - 1] = '\0'; + + assert_path_find_first_component(foo, false, NULL, -EINVAL); + assert_path_find_first_component(foo, true, NULL, -EINVAL); + + hoge = g_strjoin("", "a/b/c/", foo, "//d/e/.//f/", NULL); + g_assert(hoge); + + assert_path_find_first_component(hoge, false, NM_MAKE_STRV("a", "b", "c"), -EINVAL); + assert_path_find_first_component(hoge, true, NM_MAKE_STRV("a", "b", "c"), -EINVAL); +} + +/*****************************************************************************/ + +static void +assert_path_startswith(const char *path, + const char *prefix, + const char *skipped, + const char *expected) +{ + const char *p; + + p = nm_path_startswith(path, prefix); + g_assert_cmpstr(p, ==, expected); + if (p) { + gs_free char *q = NULL; + + g_assert(skipped); + q = g_strjoin("", skipped, p, NULL); + g_assert_cmpstr(q, ==, path); + g_assert(p == path + strlen(skipped)); + } else + g_assert(!skipped); +} + +static void +test_path_startswith(void) +{ + assert_path_startswith("/foo/bar/barfoo/", "/foo", "/foo/", "bar/barfoo/"); + assert_path_startswith("/foo/bar/barfoo/", "/foo/", "/foo/", "bar/barfoo/"); + assert_path_startswith("/foo/bar/barfoo/", "/", "/", "foo/bar/barfoo/"); + assert_path_startswith("/foo/bar/barfoo/", "////", "/", "foo/bar/barfoo/"); + assert_path_startswith("/foo/bar/barfoo/", "/foo//bar/////barfoo///", "/foo/bar/barfoo/", ""); + assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo////", "/foo/bar/barfoo/", ""); + assert_path_startswith("/foo/bar/barfoo/", "/foo/bar///barfoo/", "/foo/bar/barfoo/", ""); + assert_path_startswith("/foo/bar/barfoo/", "/foo////bar/barfoo/", "/foo/bar/barfoo/", ""); + assert_path_startswith("/foo/bar/barfoo/", "////foo/bar/barfoo/", "/foo/bar/barfoo/", ""); + assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfoo", "/foo/bar/barfoo/", ""); + + assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa/", NULL, NULL); + assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfooa", NULL, NULL); + assert_path_startswith("/foo/bar/barfoo/", "", NULL, NULL); + assert_path_startswith("/foo/bar/barfoo/", "/bar/foo", NULL, NULL); + assert_path_startswith("/foo/bar/barfoo/", "/f/b/b/", NULL, NULL); + assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/barfo", NULL, NULL); + assert_path_startswith("/foo/bar/barfoo/", "/foo/bar/bar", NULL, NULL); + assert_path_startswith("/foo/bar/barfoo/", "/fo", NULL, NULL); +} + +/*****************************************************************************/ + +static void +assert_path_simplify(const char *in, const char *out) +{ + gs_free char *p = NULL; + + g_assert(in); + p = g_strdup(in); + nm_path_simplify(p); + g_assert_cmpstr(p, ==, out); +} + +static void +test_path_simplify(void) +{ + gs_free char *hoge = NULL; + gs_free char *hoge_out = NULL; + char foo[NAME_MAX * 2]; + + assert_path_simplify("", ""); + assert_path_simplify("aaa/bbb////ccc", "aaa/bbb/ccc"); + assert_path_simplify("//aaa/.////ccc", "/aaa/ccc"); + assert_path_simplify("///", "/"); + assert_path_simplify("///.//", "/"); + assert_path_simplify("///.//.///", "/"); + assert_path_simplify("////.././///../.", "/../.."); + assert_path_simplify(".", "."); + assert_path_simplify("./", "."); + assert_path_simplify(".///.//./.", "."); + assert_path_simplify(".///.//././/", "."); + assert_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", + "/aaa/.bbb/../c./d.dd/..eeee"); + assert_path_simplify("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..", + "/aaa/.bbb/../c./d.dd/..eeee/.."); + assert_path_simplify(".//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..", + "aaa/.bbb/../c./d.dd/..eeee/.."); + assert_path_simplify("..//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..", + "../aaa/.bbb/../c./d.dd/..eeee/.."); + + memset(foo, 'a', sizeof(foo) - 1); + foo[sizeof(foo) - 1] = '\0'; + + assert_path_simplify(foo, foo); + + hoge = g_strjoin("", "/", foo, NULL); + g_assert(hoge); + assert_path_simplify(hoge, hoge); + nm_clear_g_free(&hoge); + + hoge = + g_strjoin("", "a////.//././//./b///././/./c/////././//./", foo, "//.//////d/e/.//f/", NULL); + g_assert(hoge); + + hoge_out = g_strjoin("", "a/b/c/", foo, "//.//////d/e/.//f/", NULL); + g_assert(hoge_out); + + assert_path_simplify(hoge, hoge_out); +} + +/*****************************************************************************/ + +static void +test_hostname_is_valid(void) +{ + g_assert(nm_hostname_is_valid("foobar", FALSE)); + g_assert(nm_hostname_is_valid("foobar.com", FALSE)); + g_assert(!nm_hostname_is_valid("foobar.com.", FALSE)); + g_assert(nm_hostname_is_valid("fooBAR", FALSE)); + g_assert(nm_hostname_is_valid("fooBAR.com", FALSE)); + g_assert(!nm_hostname_is_valid("fooBAR.", FALSE)); + g_assert(!nm_hostname_is_valid("fooBAR.com.", FALSE)); + g_assert(!nm_hostname_is_valid("fƶƶbar", FALSE)); + g_assert(!nm_hostname_is_valid("", FALSE)); + g_assert(!nm_hostname_is_valid(".", FALSE)); + g_assert(!nm_hostname_is_valid("..", FALSE)); + g_assert(!nm_hostname_is_valid("foobar.", FALSE)); + g_assert(!nm_hostname_is_valid(".foobar", FALSE)); + g_assert(!nm_hostname_is_valid("foo..bar", FALSE)); + g_assert(!nm_hostname_is_valid("foo.bar..", FALSE)); + + G_STATIC_ASSERT_EXPR(NM_HOST_NAME_MAX <= HOST_NAME_MAX); + +#define _assert_hostname_length(n, valid) \ + G_STMT_START \ + { \ + const gsize _n = (n); \ + gs_free char *_h = g_strnfill(_n, 'x'); \ + gboolean _valid; \ + \ + _valid = nm_hostname_is_valid(_h, FALSE); \ + g_assert_cmpint(_valid, ==, (valid)); \ + } \ + G_STMT_END + + _assert_hostname_length(NM_HOST_NAME_MAX - 10, TRUE); + _assert_hostname_length(NM_HOST_NAME_MAX - 1, TRUE); + _assert_hostname_length(NM_HOST_NAME_MAX, TRUE); + _assert_hostname_length(NM_HOST_NAME_MAX + 1, FALSE); + _assert_hostname_length(NM_HOST_NAME_MAX + 10, FALSE); + + g_assert(!nm_hostname_is_valid( + "au-xph5-rvgrdsb5hcxc-47et3a5vvkrc-server-wyoz4elpdpe3.openstack.local", + FALSE)); + + g_assert(nm_hostname_is_valid("foobar", TRUE)); + g_assert(nm_hostname_is_valid("foobar.com", TRUE)); + g_assert(nm_hostname_is_valid("foobar.com.", TRUE)); + g_assert(nm_hostname_is_valid("fooBAR", TRUE)); + g_assert(nm_hostname_is_valid("fooBAR.com", TRUE)); + g_assert(!nm_hostname_is_valid("fooBAR.", TRUE)); + g_assert(nm_hostname_is_valid("fooBAR.com.", TRUE)); + g_assert(!nm_hostname_is_valid("fƶƶbar", TRUE)); + g_assert(!nm_hostname_is_valid("", TRUE)); + g_assert(!nm_hostname_is_valid(".", TRUE)); + g_assert(!nm_hostname_is_valid("..", TRUE)); + g_assert(!nm_hostname_is_valid("foobar.", TRUE)); + g_assert(!nm_hostname_is_valid(".foobar", TRUE)); + g_assert(!nm_hostname_is_valid("foo..bar", TRUE)); + g_assert(!nm_hostname_is_valid("foo.bar..", TRUE)); + g_assert( + nm_hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + TRUE)); + g_assert( + !nm_hostname_is_valid("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" + "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", + TRUE)); +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -1450,6 +2234,17 @@ main(int argc, char **argv) g_test_add_func("/general/test_utils_hashtable_cmp", test_utils_hashtable_cmp); g_test_add_func("/general/test_nm_g_source_sentinel", test_nm_g_source_sentinel); g_test_add_func("/general/test_nm_ascii", test_nm_ascii); + g_test_add_func("/general/test_parse_env_file", test_parse_env_file); + g_test_add_func("/general/test_unbase64char", test_unbase64char); + g_test_add_func("/general/test_unbase64mem1", test_unbase64mem1); + g_test_add_func("/general/test_unbase64mem2", test_unbase64mem2); + g_test_add_func("/general/test_unbase64mem3", test_unbase64mem3); + g_test_add_func("/general/test_path_compare", test_path_compare); + g_test_add_func("/general/test_path_equal", test_path_equal); + g_test_add_func("/general/test_path_find_first_component", test_path_find_first_component); + g_test_add_func("/general/test_path_startswith", test_path_startswith); + g_test_add_func("/general/test_path_simplify", test_path_simplify); + g_test_add_func("/general/test_hostname_is_valid", test_hostname_is_valid); return g_test_run(); } diff --git a/src/libnm-log-core/nm-logging.c b/src/libnm-log-core/nm-logging.c index f464ef296d..5cce508daf 100644 --- a/src/libnm-log-core/nm-logging.c +++ b/src/libnm-log-core/nm-logging.c @@ -468,7 +468,7 @@ _domains_to_string(gboolean include_level_override, * nm_logging_setup(), because we want to expand "DEFAULT" and "ALL". */ - nm_str_buf_init(&sbuf, NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE); + sbuf = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_40, FALSE); for (diter = &domain_desc[0]; diter->name; diter++) { /* If it's set for any lower level, it will also be set for LOGL_ERR */ diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h index 5c72fade99..a4cba9ced8 100644 --- a/src/libnm-platform/nm-platform.h +++ b/src/libnm-platform/nm-platform.h @@ -333,6 +333,9 @@ typedef enum { * should be configured. */ \ bool a_force_commit : 1; \ \ + /* Don't have a bitfield as last field in __NMPlatformIPAddress_COMMON. It would then + * be unclear how the following fields get merged. We could also use a zero bitfield, + * but instead we just have there the uint8 field. */ \ guint8 plen; \ ; @@ -343,10 +346,7 @@ typedef enum { **/ typedef struct { __NMPlatformIPAddress_COMMON; - union { - guint8 address_ptr[1]; - guint32 __dummy_for_32bit_alignment; - }; + _nm_alignas(NMIPAddr) guint8 address_ptr[]; } NMPlatformIPAddress; /** @@ -358,11 +358,15 @@ struct _NMPlatformIP4Address { /* Whether the address is ready to be configured. By default, an address is, but this * flag may indicate that the address is just for tracking purpose only, but the ACD - * state is not yet ready for the address to be configured. */ + * state is not yet ready for the address to be configured. + * + * This bit fits actually in an alignment gap between __NMPlatformIPAddress_COMMON and + * "address" field. Usually "address" must be the first field after __NMPlatformIPAddress_COMMON, + * but there is a gap. We have a static assertion that checks this, so all is good. */ bool a_acd_not_ready : 1; /* The local address IFA_LOCAL. */ - in_addr_t address; + _nm_alignas(NMIPAddr) in_addr_t address; /* The IFA_ADDRESS PTP peer address. This field is rather important, because * it constitutes the identifier for the IPv4 address (e.g. you can add two @@ -390,7 +394,7 @@ struct _NMPlatformIP4Address { **/ struct _NMPlatformIP6Address { __NMPlatformIPAddress_COMMON; - struct in6_addr address; + _nm_alignas(NMIPAddr) struct in6_addr address; struct in6_addr peer_address; }; @@ -426,6 +430,47 @@ typedef union { #define __NMPlatformIPRoute_COMMON \ __NMPlatformObjWithIfindex_COMMON; \ \ + /* rtnh_flags + * + * Routes with rtm_flags RTM_F_CLONED are hidden by platform and + * do not exist from the point-of-view of platform users. + * Such a route is not alive, according to nmp_object_is_alive(). + * + * NOTE: currently we ignore all flags except RTM_F_CLONED + * and RTNH_F_ONLINK. + * We also may not properly consider the flags as part of the ID + * in route-cmp. */ \ + unsigned r_rtm_flags; \ + \ + /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \ + guint32 mss; \ + \ + /* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \ + guint32 window; \ + \ + /* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \ + guint32 cwnd; \ + \ + /* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \ + guint32 initcwnd; \ + \ + /* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \ + guint32 initrwnd; \ + \ + /* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \ + guint32 mtu; \ + \ + /* RTA_PRIORITY (iproute2: metric) + * If "metric_any" is %TRUE, then this is interpreted as an offset that will be + * added to a default base metric. In such cases, the offset is usually zero. */ \ + guint32 metric; \ + \ + /* rtm_table, RTA_TABLE. + * + * This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and + * zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main + * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \ + guint32 table_coerced; \ /* The NMIPConfigSource. For routes that we receive from cache this corresponds * to the rtm_protocol field (and is one of the NM_IP_CONFIG_SOURCE_RTPROT_* values). * When adding a route, the source will be coerced to the protocol using @@ -440,8 +485,6 @@ typedef union { * to zero, in which case the first matching route (with proto ignored) is deleted. */ \ NMIPConfigSource rt_source; \ \ - guint8 plen; \ - \ /* RTA_METRICS: * * For IPv4 routes, these properties are part of their @@ -480,62 +523,22 @@ typedef union { /* Whether the route should be committed even if it was removed externally. */ \ bool r_force_commit : 1; \ \ - /* rtnh_flags - * - * Routes with rtm_flags RTM_F_CLONED are hidden by platform and - * do not exist from the point-of-view of platform users. - * Such a route is not alive, according to nmp_object_is_alive(). - * - * NOTE: currently we ignore all flags except RTM_F_CLONED - * and RTNH_F_ONLINK. - * We also may not properly consider the flags as part of the ID - * in route-cmp. */ \ - unsigned r_rtm_flags; \ - \ - /* RTA_METRICS.RTAX_ADVMSS (iproute2: advmss) */ \ - guint32 mss; \ - \ - /* RTA_METRICS.RTAX_WINDOW (iproute2: window) */ \ - guint32 window; \ - \ - /* RTA_METRICS.RTAX_CWND (iproute2: cwnd) */ \ - guint32 cwnd; \ - \ - /* RTA_METRICS.RTAX_INITCWND (iproute2: initcwnd) */ \ - guint32 initcwnd; \ - \ - /* RTA_METRICS.RTAX_INITRWND (iproute2: initrwnd) */ \ - guint32 initrwnd; \ - \ - /* RTA_METRICS.RTAX_MTU (iproute2: mtu) */ \ - guint32 mtu; \ - \ - /* RTA_PRIORITY (iproute2: metric) - * If "metric_any" is %TRUE, then this is interpreted as an offset that will be - * added to a default base metric. In such cases, the offset is usually zero. */ \ - guint32 metric; \ - \ - /* rtm_table, RTA_TABLE. - * - * This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and - * zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main - * table. Use nm_platform_route_table_coerce()/nm_platform_route_table_uncoerce(). */ \ - guint32 table_coerced; \ - \ /* rtm_type. * * This is not the original type, if type_coerced is 0 then * it means RTN_UNSPEC otherwise the type value is preserved. - * */ \ + */ \ guint8 type_coerced; \ + \ + /* Don't have a bitfield as last field in __NMPlatformIPAddress_COMMON. It would then + * be unclear how the following fields get merged. We could also use a zero bitfield, + * but instead we just have there the uint8 field. */ \ + guint8 plen; \ ; typedef struct { __NMPlatformIPRoute_COMMON; - union { - guint8 network_ptr[1]; - guint32 __dummy_for_32bit_alignment; - }; + _nm_alignas(NMIPAddr) guint8 network_ptr[]; } NMPlatformIPRoute; #define NM_PLATFORM_IP_ROUTE_CAST(route) \ @@ -827,10 +830,10 @@ typedef struct { } NMPlatformVFVlan; typedef struct { + guint num_vlans; guint32 index; guint32 min_tx_rate; guint32 max_tx_rate; - guint num_vlans; NMPlatformVFVlan *vlans; struct { guint8 data[20]; /* _NM_UTILS_HWADDR_LEN_MAX */ @@ -848,41 +851,41 @@ typedef struct { } NMPlatformBridgeVlan; typedef struct { - NMEtherAddr group_addr; - bool mcast_querier : 1; - bool mcast_query_use_ifaddr : 1; - bool mcast_snooping : 1; - bool stp_state : 1; - bool vlan_stats_enabled : 1; - guint16 group_fwd_mask; - guint16 priority; - guint16 vlan_protocol; - guint32 ageing_time; - guint32 forward_delay; - guint32 hello_time; - guint32 max_age; - guint32 mcast_last_member_count; - guint32 mcast_startup_query_count; - guint32 mcast_hash_max; guint64 mcast_last_member_interval; guint64 mcast_membership_interval; guint64 mcast_querier_interval; guint64 mcast_query_interval; guint64 mcast_query_response_interval; guint64 mcast_startup_query_interval; + guint32 ageing_time; + guint32 forward_delay; + guint32 hello_time; + guint32 max_age; + guint32 mcast_hash_max; + guint32 mcast_last_member_count; + guint32 mcast_startup_query_count; + guint16 group_fwd_mask; + guint16 priority; + guint16 vlan_protocol; + NMEtherAddr group_addr; guint8 mcast_router; + bool mcast_querier : 1; + bool mcast_query_use_ifaddr : 1; + bool mcast_snooping : 1; + bool stp_state : 1; + bool vlan_stats_enabled : 1; } NMPlatformLnkBridge; extern const NMPlatformLnkBridge nm_platform_lnk_bridge_default; typedef struct { + int parent_ifindex; in_addr_t local; in_addr_t remote; - int parent_ifindex; - guint16 input_flags; - guint16 output_flags; guint32 input_key; guint32 output_key; + guint16 input_flags; + guint16 output_flags; guint8 ttl; guint8 tos; bool path_mtu_discovery : 1; @@ -898,12 +901,12 @@ typedef struct { struct in6_addr local; struct in6_addr remote; int parent_ifindex; + guint flow_label; + guint32 flags; guint8 ttl; guint8 tclass; guint8 encap_limit; guint8 proto; - guint flow_label; - guint32 flags; /* IP6GRE only */ guint32 input_key; @@ -915,9 +918,9 @@ typedef struct { } NMPlatformLnkIp6Tnl; typedef struct { + int parent_ifindex; in_addr_t local; in_addr_t remote; - int parent_ifindex; guint8 ttl; guint8 tos; bool path_mtu_discovery : 1; @@ -946,9 +949,9 @@ typedef struct { } NMPlatformLnkMacvlan; typedef struct { + int parent_ifindex; in_addr_t local; in_addr_t remote; - int parent_ifindex; guint16 flags; guint8 ttl; guint8 tos; @@ -984,9 +987,9 @@ typedef struct { typedef struct { struct in6_addr group6; struct in6_addr local6; + int parent_ifindex; in_addr_t group; in_addr_t local; - int parent_ifindex; guint32 id; guint32 ageing; guint32 limit; diff --git a/src/libnm-std-aux/nm-default-std.h b/src/libnm-std-aux/nm-default-std.h index 23f5fc604b..45c0d1538c 100644 --- a/src/libnm-std-aux/nm-default-std.h +++ b/src/libnm-std-aux/nm-default-std.h @@ -42,52 +42,52 @@ #if NM_MORE_ASSERTS == 0 /* The cast macros like NM_TYPE() are implemented via G_TYPE_CHECK_INSTANCE_CAST() - * and _G_TYPE_CIC(). The latter, by default performs runtime checks of the type - * by calling g_type_check_instance_cast(). - * This check has a certain overhead without being helpful. - * - * Example 1: - * static void foo (NMType *obj) - * { - * access_obj_without_check (obj); - * } - * foo ((NMType *) obj); - * // There is no runtime check and passing an invalid pointer - * // leads to a crash. - * - * Example 2: - * static void foo (NMType *obj) - * { - * access_obj_without_check (obj); - * } - * foo (NM_TYPE (obj)); - * // There is a runtime check which prints a g_warning(), but that doesn't - * // avoid the crash as NM_TYPE() cannot do anything then passing on the - * // invalid pointer. - * - * Example 3: - * static void foo (NMType *obj) - * { - * g_return_if_fail (NM_IS_TYPE (obj)); - * access_obj_without_check (obj); - * } - * foo ((NMType *) obj); - * // There is a runtime check which prints a g_critical() which also avoids - * // the crash. That is actually helpful to catch bugs and avoid crashes. - * - * Example 4: - * static void foo (NMType *obj) - * { - * g_return_if_fail (NM_IS_TYPE (obj)); - * access_obj_without_check (obj); - * } - * foo (NM_TYPE (obj)); - * // The runtime check is performed twice, with printing a g_warning() and - * // a g_critical() and avoiding the crash. - * - * Example 3 is how it should be done. Type checks in NM_TYPE() are pointless. - * Disable them for our production builds. - */ + * and _G_TYPE_CIC(). The latter, by default performs runtime checks of the type + * by calling g_type_check_instance_cast(). + * This check has a certain overhead without being helpful. + * + * Example 1: + * static void foo (NMType *obj) + * { + * access_obj_without_check (obj); + * } + * foo ((NMType *) obj); + * // There is no runtime check and passing an invalid pointer + * // leads to a crash. + * + * Example 2: + * static void foo (NMType *obj) + * { + * access_obj_without_check (obj); + * } + * foo (NM_TYPE (obj)); + * // There is a runtime check which prints a g_warning(), but that doesn't + * // avoid the crash as NM_TYPE() cannot do anything then passing on the + * // invalid pointer. + * + * Example 3: + * static void foo (NMType *obj) + * { + * g_return_if_fail (NM_IS_TYPE (obj)); + * access_obj_without_check (obj); + * } + * foo ((NMType *) obj); + * // There is a runtime check which prints a g_critical() which also avoids + * // the crash. That is actually helpful to catch bugs and avoid crashes. + * + * Example 4: + * static void foo (NMType *obj) + * { + * g_return_if_fail (NM_IS_TYPE (obj)); + * access_obj_without_check (obj); + * } + * foo (NM_TYPE (obj)); + * // The runtime check is performed twice, with printing a g_warning() and + * // a g_critical() and avoiding the crash. + * + * Example 3 is how it should be done. Type checks in NM_TYPE() are pointless. + * Disable them for our production builds. + */ #ifndef G_DISABLE_CAST_CHECKS #define G_DISABLE_CAST_CHECKS #endif @@ -99,4 +99,9 @@ /*****************************************************************************/ +#include "libnm-std-aux/nm-std-aux.h" +#include "libnm-std-aux/nm-std-utils.h" + +/*****************************************************************************/ + #endif /* __NM_DEFAULT_STD_H__ */ diff --git a/src/libnm-std-aux/nm-std-utils.h b/src/libnm-std-aux/nm-std-utils.h index 76d49d2f5f..6aa787eb6a 100644 --- a/src/libnm-std-aux/nm-std-utils.h +++ b/src/libnm-std-aux/nm-std-utils.h @@ -14,12 +14,12 @@ * certain buffer sizes. * * The use of these defines is to get favorable allocation sequences. - * For example, nm_str_buf_init() asks for an initial allocation size. Note that + * For example, NM_STR_BUF_INIT() asks for an initial allocation size. Note that * it reserves the exactly requested amount, under the assumption that the * user may know how many bytes will be required. However, often the caller * doesn't know in advance, and NMStrBuf grows exponentially by calling * nm_utils_get_next_realloc_size(). - * Imagine you call nm_str_buf_init() with an initial buffer size 100, and you + * Imagine you call NM_STR_BUF_INIT() with an initial buffer size 100, and you * add one character at a time. Then the first reallocation will increase the * buffer size only from 100 to 104. * If you however start with an initial buffer size of 104, then the next reallocation @@ -30,6 +30,7 @@ #define NM_UTILS_GET_NEXT_REALLOC_SIZE_40 ((size_t) 40) #define NM_UTILS_GET_NEXT_REALLOC_SIZE_104 ((size_t) 104) #define NM_UTILS_GET_NEXT_REALLOC_SIZE_232 ((size_t) 232) +#define NM_UTILS_GET_NEXT_REALLOC_SIZE_488 ((size_t) 488) #define NM_UTILS_GET_NEXT_REALLOC_SIZE_1000 ((size_t) 1000) size_t nm_utils_get_next_realloc_size(bool true_realloc, size_t requested); diff --git a/src/libnm-systemd-core/meson.build b/src/libnm-systemd-core/meson.build index 80b95c4224..70293a6154 100644 --- a/src/libnm-systemd-core/meson.build +++ b/src/libnm-systemd-core/meson.build @@ -3,20 +3,13 @@ libnm_systemd_core = static_library( 'nm-systemd-core', sources: files( - 'src/libsystemd-network/arp-util.c', 'src/libsystemd-network/dhcp-identifier.c', - 'src/libsystemd-network/dhcp-network.c', - 'src/libsystemd-network/dhcp-option.c', - 'src/libsystemd-network/dhcp-packet.c', 'src/libsystemd-network/dhcp6-network.c', 'src/libsystemd-network/dhcp6-option.c', 'src/libsystemd-network/dhcp6-protocol.c', 'src/libsystemd-network/lldp-neighbor.c', 'src/libsystemd-network/lldp-network.c', 'src/libsystemd-network/network-common.c', - 'src/libsystemd-network/network-internal.c', - 'src/libsystemd-network/sd-dhcp-client.c', - 'src/libsystemd-network/sd-dhcp-lease.c', 'src/libsystemd-network/sd-dhcp6-client.c', 'src/libsystemd-network/sd-dhcp6-lease.c', 'src/libsystemd-network/sd-lldp-rx.c', @@ -25,8 +18,6 @@ libnm_systemd_core = static_library( 'src/libsystemd/sd-id128/id128-util.c', 'src/libsystemd/sd-id128/sd-id128.c', 'nm-sd.c', - 'nm-sd-utils-core.c', - 'nm-sd-utils-dhcp.c', 'sd-adapt-core/nm-sd-adapt-core.c', ), include_directories: [ diff --git a/src/libnm-systemd-core/nm-sd-utils-core.c b/src/libnm-systemd-core/nm-sd-utils-core.c deleted file mode 100644 index 21e8a3044e..0000000000 --- a/src/libnm-systemd-core/nm-sd-utils-core.c +++ /dev/null @@ -1,27 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "libnm-systemd-core/nm-default-systemd-core.h" - -#include "nm-sd-utils-core.h" - -#include "libnm-glib-aux/nm-uuid.h" - -#include "nm-sd-adapt-core.h" - -#include "sd-id128.h" - -/*****************************************************************************/ - -NMUuid * -nm_sd_utils_id128_get_machine(NMUuid *out_uuid) -{ - g_assert(out_uuid); - - G_STATIC_ASSERT_EXPR(sizeof(*out_uuid) == sizeof(sd_id128_t)); - if (sd_id128_get_machine((sd_id128_t *) out_uuid) < 0) - return NULL; - return out_uuid; -} diff --git a/src/libnm-systemd-core/nm-sd-utils-core.h b/src/libnm-systemd-core/nm-sd-utils-core.h deleted file mode 100644 index ccad002989..0000000000 --- a/src/libnm-systemd-core/nm-sd-utils-core.h +++ /dev/null @@ -1,17 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __NM_SD_UTILS_CORE_H__ -#define __NM_SD_UTILS_CORE_H__ - -/*****************************************************************************/ - -struct _NMUuid; - -struct _NMUuid *nm_sd_utils_id128_get_machine(struct _NMUuid *out_uuid); - -/*****************************************************************************/ - -#endif /* __NM_SD_UTILS_CORE_H__ */ diff --git a/src/libnm-systemd-core/nm-sd-utils-dhcp.c b/src/libnm-systemd-core/nm-sd-utils-dhcp.c deleted file mode 100644 index 13c75055ec..0000000000 --- a/src/libnm-systemd-core/nm-sd-utils-dhcp.c +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2019 Red Hat, Inc. - */ - -#include "libnm-systemd-core/nm-default-systemd-core.h" - -#include "nm-sd-utils-dhcp.h" - -#include "sd-adapt-core/nm-sd-adapt-core.h" -#include "src/libsystemd-network/dhcp-lease-internal.h" - -int -nm_sd_dhcp_lease_get_private_options(sd_dhcp_lease *lease, nm_sd_dhcp_option **out_options) -{ - int cnt = 0; - - g_return_val_if_fail(lease, -EINVAL); - g_return_val_if_fail(out_options, -EINVAL); - g_return_val_if_fail(*out_options == NULL, -EINVAL); - - if (lease->private_options == NULL) - return -ENODATA; - - LIST_FOREACH(options, raw_option, lease->private_options) - cnt++; - - *out_options = g_new(nm_sd_dhcp_option, cnt); - cnt = 0; - - LIST_FOREACH(options, raw_option, lease->private_options) - { - (*out_options)[cnt].code = raw_option->tag; - (*out_options)[cnt].data = raw_option->data; - (*out_options)[cnt].data_len = raw_option->length; - cnt++; - } - - return cnt; -} diff --git a/src/libnm-systemd-core/nm-sd-utils-dhcp.h b/src/libnm-systemd-core/nm-sd-utils-dhcp.h deleted file mode 100644 index 6487a90dfe..0000000000 --- a/src/libnm-systemd-core/nm-sd-utils-dhcp.h +++ /dev/null @@ -1,19 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2019 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__ -#define __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__ - -#include "nm-sd.h" - -typedef struct { - uint8_t code; - uint8_t data_len; - void *data; -} nm_sd_dhcp_option; - -int nm_sd_dhcp_lease_get_private_options(sd_dhcp_lease *lease, nm_sd_dhcp_option **out_options); - -#endif /* __NETWORKMANAGER_DHCP_SYSTEMD_UTILS_H__ */ diff --git a/src/libnm-systemd-core/nm-sd.c b/src/libnm-systemd-core/nm-sd.c index 9978a159c4..b512e3fcba 100644 --- a/src/libnm-systemd-core/nm-sd.c +++ b/src/libnm-systemd-core/nm-sd.c @@ -108,6 +108,5 @@ nm_sd_event_attach_default(void) /* ensure that defines in nm-sd.h correspond to the internal defines. */ #include "nm-sd-adapt-core.h" -#include "dhcp-lease-internal.h" /*****************************************************************************/ diff --git a/src/libnm-systemd-core/nm-sd.h b/src/libnm-systemd-core/nm-sd.h index 421f53729b..79bc503106 100644 --- a/src/libnm-systemd-core/nm-sd.h +++ b/src/libnm-systemd-core/nm-sd.h @@ -6,7 +6,6 @@ #ifndef __NM_SD_H__ #define __NM_SD_H__ -#include "src/systemd/sd-dhcp-client.h" #include "src/systemd/sd-dhcp6-client.h" #include "src/systemd/sd-lldp-rx.h" @@ -14,15 +13,4 @@ guint nm_sd_event_attach_default(void); -/***************************************************************************** - * expose internal systemd API - * - * FIXME: don't use any internal systemd API. - *****************************************************************************/ - -struct sd_dhcp_lease; - -int dhcp_lease_save(struct sd_dhcp_lease *lease, const char *lease_file); -int dhcp_lease_load(struct sd_dhcp_lease **ret, const char *lease_file); - #endif /* __NM_SD_H__ */ diff --git a/src/libnm-systemd-core/src/libsystemd-network/arp-util.c b/src/libnm-systemd-core/src/libsystemd-network/arp-util.c deleted file mode 100644 index c8a73111b5..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/arp-util.c +++ /dev/null @@ -1,142 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright Ā© 2014 Axis Communications AB. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include <arpa/inet.h> -#include <linux/filter.h> -#include <netinet/if_ether.h> - -#include "arp-util.h" -#include "ether-addr-util.h" -#include "fd-util.h" -#include "in-addr-util.h" -#include "unaligned.h" -#include "util.h" - -int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac) { - struct sock_filter filter[] = { - BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ - BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(struct ether_arp), 1, 0), /* packet >= arp packet ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hrd)), /* A <- header */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPHRD_ETHER, 1, 0), /* header == ethernet ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pro)), /* A <- protocol */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 1, 0), /* protocol == IP ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_hln)), /* A <- hardware address length */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct ether_addr), 1, 0), /* length == sizeof(ether_addr)? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_pln)), /* A <- protocol address length */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, sizeof(struct in_addr), 1, 0), /* length == sizeof(in_addr) ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, ea_hdr.ar_op)), /* A <- operation */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REQUEST, 2, 0), /* protocol == request ? */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ARPOP_REPLY, 1, 0), /* protocol == reply ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - /* Sender Hardware Address must be different from our own */ - BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(&mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_sha)), /* A <- 4 bytes of SHA */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 4), /* A == X ? */ - BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(&mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(struct ether_arp, arp_sha) + 4), /* A <- remainder of SHA */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - /* Sender Protocol Address or Target Protocol Address must be equal to the one we care about */ - BPF_STMT(BPF_LDX + BPF_IMM, htobe32(a->s_addr)), /* X <- clients IP */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_spa)), /* A <- SPA */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == X ? */ - BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct ether_arp, arp_tpa)), /* A <- TPA */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 0, 1), /* A == 0 ? */ - BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - }; - struct sock_fprog fprog = { - .len = ELEMENTSOF(filter), - .filter = (struct sock_filter*) filter, - }; - - assert(fd >= 0); - - if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)) < 0) - return -errno; - - return 0; -} - -int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac) { - union sockaddr_union link = { - .ll.sll_family = AF_PACKET, - .ll.sll_protocol = htobe16(ETH_P_ARP), - .ll.sll_ifindex = ifindex, - .ll.sll_halen = ETH_ALEN, - .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, - }; - _cleanup_close_ int s = -1; - int r; - - assert(ifindex > 0); - assert(mac); - - s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); - if (s < 0) - return -errno; - - r = arp_update_filter(s, a, mac); - if (r < 0) - return r; - - if (bind(s, &link.sa, sizeof(link.ll)) < 0) - return -errno; - - return TAKE_FD(s); -} - -int arp_send_packet( - int fd, - int ifindex, - const struct in_addr *pa, - const struct ether_addr *ha, - bool announce) { - - union sockaddr_union link = { - .ll.sll_family = AF_PACKET, - .ll.sll_protocol = htobe16(ETH_P_ARP), - .ll.sll_ifindex = ifindex, - .ll.sll_halen = ETH_ALEN, - .ll.sll_addr = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, - }; - struct ether_arp arp = { - .ea_hdr.ar_hrd = htobe16(ARPHRD_ETHER), /* HTYPE */ - .ea_hdr.ar_pro = htobe16(ETHERTYPE_IP), /* PTYPE */ - .ea_hdr.ar_hln = ETH_ALEN, /* HLEN */ - .ea_hdr.ar_pln = sizeof(struct in_addr), /* PLEN */ - .ea_hdr.ar_op = htobe16(ARPOP_REQUEST), /* REQUEST */ - }; - ssize_t n; - - assert(fd >= 0); - assert(ifindex > 0); - assert(pa); - assert(in4_addr_is_set(pa)); - assert(ha); - assert(!ether_addr_is_null(ha)); - - memcpy(&arp.arp_sha, ha, ETH_ALEN); - memcpy(&arp.arp_tpa, pa, sizeof(struct in_addr)); - - if (announce) - memcpy(&arp.arp_spa, pa, sizeof(struct in_addr)); - - n = sendto(fd, &arp, sizeof(struct ether_arp), 0, &link.sa, sizeof(link.ll)); - if (n < 0) - return -errno; - if (n != sizeof(struct ether_arp)) - return -EIO; - - return 0; -} diff --git a/src/libnm-systemd-core/src/libsystemd-network/arp-util.h b/src/libnm-systemd-core/src/libsystemd-network/arp-util.h deleted file mode 100644 index b66a81bf9b..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/arp-util.h +++ /dev/null @@ -1,36 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright Ā© 2014 Axis Communications AB. All rights reserved. -***/ - -#include <net/ethernet.h> -#include <netinet/in.h> - -#include "socket-util.h" -#include "sparse-endian.h" - -int arp_update_filter(int fd, const struct in_addr *a, const struct ether_addr *mac); -int arp_network_bind_raw_socket(int ifindex, const struct in_addr *a, const struct ether_addr *mac); - -int arp_send_packet( - int fd, - int ifindex, - const struct in_addr *pa, - const struct ether_addr *ha, - bool announce); -static inline int arp_send_probe( - int fd, - int ifindex, - const struct in_addr *pa, - const struct ether_addr *ha) { - return arp_send_packet(fd, ifindex, pa, ha, false); -} -static inline int arp_send_announcement( - int fd, - int ifindex, - const struct in_addr *pa, - const struct ether_addr *ha) { - return arp_send_packet(fd, ifindex, pa, ha, true); -} diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h deleted file mode 100644 index 466d8e4b3f..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-internal.h +++ /dev/null @@ -1,84 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright Ā© 2013 Intel Corporation. All rights reserved. -***/ - -#include <linux/if_packet.h> -#include <net/ethernet.h> -#include <stdint.h> - -#include "sd-dhcp-client.h" - -#include "dhcp-protocol.h" -#include "network-common.h" -#include "socket-util.h" - -typedef struct sd_dhcp_option { - unsigned n_ref; - - uint8_t option; - void *data; - size_t length; -} sd_dhcp_option; - -typedef struct DHCPServerData { - struct in_addr *addr; - size_t size; -} DHCPServerData; - -extern const struct hash_ops dhcp_option_hash_ops; - -typedef struct sd_dhcp_client sd_dhcp_client; - -int dhcp_network_bind_raw_socket(int ifindex, union sockaddr_union *link, uint32_t xid, - const uint8_t *mac_addr, size_t mac_addr_len, - const uint8_t *bcast_addr, size_t bcast_addr_len, - uint16_t arp_type, uint16_t port); -int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type); -int dhcp_network_send_raw_socket(int s, const union sockaddr_union *link, - const void *packet, size_t len); -int dhcp_network_send_udp_socket(int s, be32_t address, uint16_t port, - const void *packet, size_t len); - -int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, uint8_t overload, - uint8_t code, size_t optlen, const void *optval); -int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t wanted_code, size_t *ret_offset); -int dhcp_option_remove_option(uint8_t *options, size_t buflen, uint8_t option_code); - -typedef int (*dhcp_option_callback_t)(uint8_t code, uint8_t len, - const void *option, void *userdata); - -int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **error_message); - -int dhcp_message_init(DHCPMessage *message, uint8_t op, uint32_t xid, - uint8_t type, uint16_t arp_type, uint8_t hlen, const uint8_t *chaddr, - size_t optlen, size_t *optoffset); - -uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len); - -void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, - uint16_t source, be32_t destination_addr, - uint16_t destination, uint16_t len, int ip_service_type); - -int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port); - -void dhcp_client_set_test_mode(sd_dhcp_client *client, bool test_mode); - -/* If we are invoking callbacks of a dhcp-client, ensure unreffing the - * client from the callback doesn't destroy the object we are working - * on */ -#define DHCP_CLIENT_DONT_DESTROY(client) \ - _cleanup_(sd_dhcp_client_unrefp) _unused_ sd_dhcp_client *_dont_destroy_##client = sd_dhcp_client_ref(client) - -#define log_dhcp_client_errno(client, error, fmt, ...) \ - log_interface_prefix_full_errno( \ - "DHCPv4 client: ", \ - sd_dhcp_client, client, \ - error, fmt, ##__VA_ARGS__) -#define log_dhcp_client(client, fmt, ...) \ - log_interface_prefix_full_errno_zerook( \ - "DHCPv4 client: ", \ - sd_dhcp_client, client, \ - 0, fmt, ##__VA_ARGS__) diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h deleted file mode 100644 index c67e9511a1..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-lease-internal.h +++ /dev/null @@ -1,90 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright Ā© 2013 Intel Corporation. All rights reserved. -***/ - -#include "sd-dhcp-client.h" - -#include "dhcp-internal.h" -#include "dhcp-protocol.h" -#include "list.h" -#include "util.h" - -struct sd_dhcp_route { - struct in_addr dst_addr; - struct in_addr gw_addr; - unsigned char dst_prefixlen; -}; - -struct sd_dhcp_raw_option { - LIST_FIELDS(struct sd_dhcp_raw_option, options); - - uint8_t tag; - uint8_t length; - void *data; -}; - -struct sd_dhcp_lease { - unsigned n_ref; - - /* each 0 if unset */ - uint32_t t1; - uint32_t t2; - uint32_t lifetime; - - /* each 0 if unset */ - be32_t address; - be32_t server_address; - be32_t next_server; - - bool have_subnet_mask; - be32_t subnet_mask; - - bool have_broadcast; - be32_t broadcast; - - struct in_addr *router; - size_t router_size; - - DHCPServerData servers[_SD_DHCP_LEASE_SERVER_TYPE_MAX]; - - struct sd_dhcp_route *static_routes; - size_t n_static_routes; - struct sd_dhcp_route *classless_routes; - size_t n_classless_routes; - - uint16_t mtu; /* 0 if unset */ - - char *domainname; - char **search_domains; - char *hostname; - char *root_path; - - void *client_id; - size_t client_id_len; - - void *vendor_specific; - size_t vendor_specific_len; - - char *timezone; - - uint8_t sixrd_ipv4masklen; - uint8_t sixrd_prefixlen; - struct in6_addr sixrd_prefix; - struct in_addr *sixrd_br_addresses; - size_t sixrd_n_br_addresses; - - LIST_HEAD(struct sd_dhcp_raw_option, private_options); -}; - -int dhcp_lease_new(sd_dhcp_lease **ret); - -int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata); -int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains); -int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len); - -int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease); - -int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len); diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c deleted file mode 100644 index 1c5f342754..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-network.c +++ /dev/null @@ -1,257 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright Ā© 2013 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include <errno.h> -#include <net/ethernet.h> -#include <net/if.h> -#include <net/if_arp.h> -#include <stdio.h> -#include <string.h> -#include <linux/filter.h> -#include <linux/if_infiniband.h> -#include <linux/if_packet.h> - -#include "dhcp-internal.h" -#include "fd-util.h" -#include "socket-util.h" -#include "unaligned.h" - -static int _bind_raw_socket(int ifindex, union sockaddr_union *link, - uint32_t xid, - const uint8_t *bcast_addr, - size_t bcast_addr_len, - const struct ether_addr *eth_mac, - uint16_t arp_type, uint8_t dhcp_hlen, - uint16_t port) { - struct sock_filter filter[] = { - BPF_STMT(BPF_LD + BPF_W + BPF_LEN, 0), /* A <- packet length */ - BPF_JUMP(BPF_JMP + BPF_JGE + BPF_K, sizeof(DHCPPacket), 1, 0), /* packet >= DHCPPacket ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.protocol)), /* A <- IP protocol */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 1, 0), /* IP protocol == UDP ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags */ - BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x20), /* A <- A & 0x20 (More Fragments bit) */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, ip.frag_off)), /* A <- Flags + Fragment offset */ - BPF_STMT(BPF_ALU + BPF_AND + BPF_K, 0x1fff), /* A <- A & 0x1fff (Fragment offset) */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 0, 1, 0), /* A == 0 ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, udp.dest)), /* A <- UDP destination port */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, port, 1, 0), /* UDP destination port == DHCP client port ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.op)), /* A <- DHCP op */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, BOOTREPLY, 1, 0), /* op == BOOTREPLY ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.htype)), /* A <- DHCP header type */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, arp_type, 1, 0), /* header type == arp_type ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.xid)), /* A <- client identifier */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, xid, 1, 0), /* client identifier == xid ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LD + BPF_B + BPF_ABS, offsetof(DHCPPacket, dhcp.hlen)), /* A <- MAC address length */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, dhcp_hlen, 1, 0), /* address length == dhcp_hlen ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - - /* We only support MAC address length to be either 0 or 6 (ETH_ALEN). Optionally - * compare chaddr for ETH_ALEN bytes. */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETH_ALEN, 0, 8), /* A (the MAC address length) == ETH_ALEN ? */ - BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be32(ð_mac->ether_addr_octet[0])), /* X <- 4 bytes of client's MAC */ - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr)), /* A <- 4 bytes of MAC from dhcp.chaddr */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_LDX + BPF_IMM, unaligned_read_be16(ð_mac->ether_addr_octet[4])), /* X <- remainder of client's MAC */ - BPF_STMT(BPF_LD + BPF_H + BPF_ABS, offsetof(DHCPPacket, dhcp.chaddr) + 4), /* A <- remainder of MAC from dhcp.chaddr */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_X, 0, 1, 0), /* A == X ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - - BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(DHCPPacket, dhcp.magic)), /* A <- DHCP magic cookie */ - BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, DHCP_MAGIC_COOKIE, 1, 0), /* cookie == DHCP magic cookie ? */ - BPF_STMT(BPF_RET + BPF_K, 0), /* ignore */ - BPF_STMT(BPF_RET + BPF_K, UINT32_MAX), /* accept */ - }; - struct sock_fprog fprog = { - .len = ELEMENTSOF(filter), - .filter = filter - }; - _cleanup_close_ int s = -1; - int r; - - assert(ifindex > 0); - assert(link); - - s = socket(AF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); - if (s < 0) - return -errno; - - r = setsockopt_int(s, SOL_PACKET, PACKET_AUXDATA, true); - if (r < 0) - return r; - - r = setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &fprog, sizeof(fprog)); - if (r < 0) - return -errno; - - link->ll = (struct sockaddr_ll) { - .sll_family = AF_PACKET, - .sll_protocol = htobe16(ETH_P_IP), - .sll_ifindex = ifindex, - .sll_hatype = htobe16(arp_type), - .sll_halen = bcast_addr_len, - }; - memcpy(link->ll.sll_addr, bcast_addr, bcast_addr_len); /* We may overflow link->ll. link->ll_buffer ensures we have enough space. */ - - r = bind(s, &link->sa, SOCKADDR_LL_LEN(link->ll)); - if (r < 0) - return -errno; - - return TAKE_FD(s); -} - -int dhcp_network_bind_raw_socket( - int ifindex, - union sockaddr_union *link, - uint32_t xid, - const uint8_t *mac_addr, - size_t mac_addr_len, - const uint8_t *bcast_addr, - size_t bcast_addr_len, - uint16_t arp_type, - uint16_t port) { - - static const uint8_t eth_bcast[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - /* Default broadcast address for IPoIB */ - static const uint8_t ib_bcast[] = { - 0x00, 0xff, 0xff, 0xff, 0xff, 0x12, 0x40, 0x1b, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xff, 0xff - }; - struct ether_addr eth_mac = { { 0, 0, 0, 0, 0, 0 } }; - const uint8_t *default_bcast_addr; - size_t expected_bcast_addr_len; - uint8_t dhcp_hlen = 0; - - if (arp_type == ARPHRD_ETHER) { - assert_return(mac_addr_len == ETH_ALEN, -EINVAL); - memcpy(ð_mac, mac_addr, ETH_ALEN); - dhcp_hlen = ETH_ALEN; - - default_bcast_addr = eth_bcast; - expected_bcast_addr_len = ETH_ALEN; - } else if (arp_type == ARPHRD_INFINIBAND) { - default_bcast_addr = ib_bcast; - expected_bcast_addr_len = INFINIBAND_ALEN; - } else - return -EINVAL; - - if (bcast_addr && bcast_addr_len > 0) - assert_return(bcast_addr_len == expected_bcast_addr_len, -EINVAL); - else { - bcast_addr = default_bcast_addr; - bcast_addr_len = expected_bcast_addr_len; - } - - return _bind_raw_socket(ifindex, link, xid, bcast_addr, bcast_addr_len, - ð_mac, arp_type, dhcp_hlen, port); -} - -int dhcp_network_bind_udp_socket(int ifindex, be32_t address, uint16_t port, int ip_service_type) { - union sockaddr_union src = { - .in.sin_family = AF_INET, - .in.sin_port = htobe16(port), - .in.sin_addr.s_addr = address, - }; - _cleanup_close_ int s = -1; - int r; - - s = socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0); - if (s < 0) - return -errno; - - if (ip_service_type >= 0) - r = setsockopt_int(s, IPPROTO_IP, IP_TOS, ip_service_type); - else - r = setsockopt_int(s, IPPROTO_IP, IP_TOS, IPTOS_CLASS_CS6); - if (r < 0) - return r; - - r = setsockopt_int(s, SOL_SOCKET, SO_REUSEADDR, true); - if (r < 0) - return r; - - if (ifindex > 0) { - r = socket_bind_to_ifindex(s, ifindex); - if (r < 0) - return r; - } - - if (port == DHCP_PORT_SERVER) { - r = setsockopt_int(s, SOL_SOCKET, SO_BROADCAST, true); - if (r < 0) - return r; - if (address == INADDR_ANY) { - /* IP_PKTINFO filter should not be applied when packets are - allowed to enter/leave through the interface other than - DHCP server sits on(BindToInterface option). */ - r = setsockopt_int(s, IPPROTO_IP, IP_PKTINFO, true); - if (r < 0) - return r; - } - } else { - r = setsockopt_int(s, IPPROTO_IP, IP_FREEBIND, true); - if (r < 0) - return r; - } - - if (bind(s, &src.sa, sizeof(src.in)) < 0) - return -errno; - - return TAKE_FD(s); -} - -int dhcp_network_send_raw_socket( - int s, - const union sockaddr_union *link, - const void *packet, - size_t len) { - - /* Do not add assert(s >= 0) here, as this is called in fuzz-dhcp-server, and in that case this - * function should fail with negative errno. */ - - assert(link); - assert(packet); - assert(len > 0); - - if (sendto(s, packet, len, 0, &link->sa, SOCKADDR_LL_LEN(link->ll)) < 0) - return -errno; - - return 0; -} - -int dhcp_network_send_udp_socket( - int s, - be32_t address, - uint16_t port, - const void *packet, - size_t len) { - - union sockaddr_union dest = { - .in.sin_family = AF_INET, - .in.sin_port = htobe16(port), - .in.sin_addr.s_addr = address, - }; - - assert(s >= 0); - assert(packet); - assert(len > 0); - - if (sendto(s, packet, len, 0, &dest.sa, sizeof(dest.in)) < 0) - return -errno; - - return 0; -} diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c deleted file mode 100644 index 712f609784..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c +++ /dev/null @@ -1,443 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright Ā© 2013 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include <errno.h> -#include <stdint.h> -#include <stdio.h> - -#include "alloc-util.h" -#include "dhcp-internal.h" -#include "dhcp-server-internal.h" -#include "memory-util.h" -#include "strv.h" -#include "utf8.h" - -/* Append type-length value structure to the options buffer */ -static int dhcp_option_append_tlv(uint8_t options[], size_t size, size_t *offset, uint8_t code, size_t optlen, const void *optval) { - assert(options); - assert(size > 0); - assert(offset); - assert(optlen <= UINT8_MAX); - assert(*offset < size); - - if (*offset + 2 + optlen > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = optlen; - - memcpy_safe(&options[*offset + 2], optval, optlen); - *offset += 2 + optlen; - return 0; -} - -static int option_append(uint8_t options[], size_t size, size_t *offset, - uint8_t code, size_t optlen, const void *optval) { - assert(options); - assert(size > 0); - assert(offset); - - int r; - - if (code != SD_DHCP_OPTION_END) - /* always make sure there is space for an END option */ - size--; - - switch (code) { - - case SD_DHCP_OPTION_PAD: - case SD_DHCP_OPTION_END: - if (*offset + 1 > size) - return -ENOBUFS; - - options[*offset] = code; - *offset += 1; - break; - - case SD_DHCP_OPTION_USER_CLASS: { - size_t total = 0; - - if (strv_isempty((char **) optval)) - return -EINVAL; - - STRV_FOREACH(s, (char **) optval) { - size_t len = strlen(*s); - - if (len > 255 || len == 0) - return -EINVAL; - - total += 1 + len; - } - - if (*offset + 2 + total > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = total; - *offset += 2; - - STRV_FOREACH(s, (char **) optval) { - size_t len = strlen(*s); - - options[*offset] = len; - memcpy(&options[*offset + 1], *s, len); - *offset += 1 + len; - } - - break; - } - case SD_DHCP_OPTION_SIP_SERVER: - if (*offset + 3 + optlen > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = optlen + 1; - options[*offset + 2] = 1; - - memcpy_safe(&options[*offset + 3], optval, optlen); - *offset += 3 + optlen; - - break; - case SD_DHCP_OPTION_VENDOR_SPECIFIC: { - OrderedSet *s = (OrderedSet *) optval; - struct sd_dhcp_option *p; - size_t l = 0; - - ORDERED_SET_FOREACH(p, s) - l += p->length + 2; - - if (*offset + l + 2 > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = l; - *offset += 2; - - ORDERED_SET_FOREACH(p, s) { - r = dhcp_option_append_tlv(options, size, offset, p->option, p->length, p->data); - if (r < 0) - return r; - } - break; - } - case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION: { -#if 0 /* NM_IGNORED */ - sd_dhcp_server *server = (sd_dhcp_server *) optval; - size_t current_offset = *offset + 2; - - if (server->agent_circuit_id) { - r = dhcp_option_append_tlv(options, size, ¤t_offset, SD_DHCP_RELAY_AGENT_CIRCUIT_ID, - strlen(server->agent_circuit_id), server->agent_circuit_id); - if (r < 0) - return r; - } - if (server->agent_remote_id) { - r = dhcp_option_append_tlv(options, size, ¤t_offset, SD_DHCP_RELAY_AGENT_REMOTE_ID, - strlen(server->agent_remote_id), server->agent_remote_id); - if (r < 0) - return r; - } - - options[*offset] = code; - options[*offset + 1] = current_offset - *offset - 2; - assert(current_offset - *offset - 2 <= UINT8_MAX); - *offset = current_offset; - break; -#endif /* NM_IGNORED */ - g_return_val_if_reached(-EINVAL); - } - default: - return dhcp_option_append_tlv(options, size, offset, code, optlen, optval); - } - return 0; -} - -static int option_length(uint8_t *options, size_t length, size_t offset) { - assert(options); - assert(offset < length); - - if (IN_SET(options[offset], SD_DHCP_OPTION_PAD, SD_DHCP_OPTION_END)) - return 1; - if (length < offset + 2) - return -ENOBUFS; - - /* validating that buffer is long enough */ - if (length < offset + 2 + options[offset + 1]) - return -ENOBUFS; - - return options[offset + 1] + 2; -} - -int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t code, size_t *ret_offset) { - int r; - - assert(options); - assert(ret_offset); - - for (size_t offset = 0; offset < length; offset += r) { - r = option_length(options, length, offset); - if (r < 0) - return r; - - if (code == options[offset]) { - *ret_offset = offset; - return r; - } - } - return -ENOENT; -} - -int dhcp_option_remove_option(uint8_t *options, size_t length, uint8_t option_code) { - int r; - size_t offset; - - assert(options); - - r = dhcp_option_find_option(options, length, option_code, &offset); - if (r < 0) - return r; - - memmove(options + offset, options + offset + r, length - offset - r); - return length - r; -} - -int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, - uint8_t overload, - uint8_t code, size_t optlen, const void *optval) { - const bool use_file = overload & DHCP_OVERLOAD_FILE; - const bool use_sname = overload & DHCP_OVERLOAD_SNAME; - int r; - - assert(message); - assert(offset); - - /* If *offset is in range [0, size), we are writing to ->options, - * if *offset is in range [size, size + sizeof(message->file)) and use_file, we are writing to ->file, - * if *offset is in range [size + use_file*sizeof(message->file), size + use_file*sizeof(message->file) + sizeof(message->sname)) - * and use_sname, we are writing to ->sname. - */ - - if (*offset < size) { - /* still space in the options array */ - r = option_append(message->options, size, offset, code, optlen, optval); - if (r >= 0) - return 0; - else if (r == -ENOBUFS && (use_file || use_sname)) { - /* did not fit, but we have more buffers to try - close the options array and move the offset to its end */ - r = option_append(message->options, size, offset, SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - *offset = size; - } else - return r; - } - - if (use_file) { - size_t file_offset = *offset - size; - - if (file_offset < sizeof(message->file)) { - /* still space in the 'file' array */ - r = option_append(message->file, sizeof(message->file), &file_offset, code, optlen, optval); - if (r >= 0) { - *offset = size + file_offset; - return 0; - } else if (r == -ENOBUFS && use_sname) { - /* did not fit, but we have more buffers to try - close the file array and move the offset to its end */ - r = option_append(message->file, sizeof(message->file), &file_offset, SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - *offset = size + sizeof(message->file); - } else - return r; - } - } - - if (use_sname) { - size_t sname_offset = *offset - size - use_file*sizeof(message->file); - - if (sname_offset < sizeof(message->sname)) { - /* still space in the 'sname' array */ - r = option_append(message->sname, sizeof(message->sname), &sname_offset, code, optlen, optval); - if (r >= 0) { - *offset = size + use_file*sizeof(message->file) + sname_offset; - return 0; - } else - /* no space, or other error, give up */ - return r; - } - } - - return -ENOBUFS; -} - -static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload, - uint8_t *message_type, char **error_message, dhcp_option_callback_t cb, - void *userdata) { - uint8_t code, len; - const uint8_t *option; - size_t offset = 0; - - while (offset < buflen) { - code = options[offset ++]; - - switch (code) { - case SD_DHCP_OPTION_PAD: - continue; - - case SD_DHCP_OPTION_END: - return 0; - } - - if (buflen < offset + 1) - return -ENOBUFS; - - len = options[offset ++]; - - if (buflen < offset + len) - return -EINVAL; - - option = &options[offset]; - - switch (code) { - case SD_DHCP_OPTION_MESSAGE_TYPE: - if (len != 1) - return -EINVAL; - - if (message_type) - *message_type = *option; - - break; - - case SD_DHCP_OPTION_ERROR_MESSAGE: - if (len == 0) - return -EINVAL; - - if (error_message) { - _cleanup_free_ char *string = NULL; - - /* Accept a trailing NUL byte */ - if (memchr(option, 0, len - 1)) - return -EINVAL; - - string = memdup_suffix0((const char *) option, len); - if (!string) - return -ENOMEM; - - if (!ascii_is_valid(string)) - return -EINVAL; - - free_and_replace(*error_message, string); - } - - break; - case SD_DHCP_OPTION_OVERLOAD: - if (len != 1) - return -EINVAL; - - if (overload) - *overload = *option; - - break; - - default: - if (cb) - cb(code, len, option, userdata); - - break; - } - - offset += len; - } - - if (offset < buflen) - return -EINVAL; - - return 0; -} - -int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **_error_message) { - _cleanup_free_ char *error_message = NULL; - uint8_t overload = 0; - uint8_t message_type = 0; - int r; - - if (!message) - return -EINVAL; - - if (len < sizeof(DHCPMessage)) - return -EINVAL; - - len -= sizeof(DHCPMessage); - - r = parse_options(message->options, len, &overload, &message_type, &error_message, cb, userdata); - if (r < 0) - return r; - - if (overload & DHCP_OVERLOAD_FILE) { - r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata); - if (r < 0) - return r; - } - - if (overload & DHCP_OVERLOAD_SNAME) { - r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata); - if (r < 0) - return r; - } - - if (message_type == 0) - return -ENOMSG; - - if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) - *_error_message = TAKE_PTR(error_message); - - return message_type; -} - -static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) { - if (!i) - return NULL; - - free(i->data); - return mfree(i); -} - -int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret) { - assert_return(ret, -EINVAL); - assert_return(length == 0 || data, -EINVAL); - - _cleanup_free_ void *q = memdup(data, length); - if (!q) - return -ENOMEM; - - sd_dhcp_option *p = new(sd_dhcp_option, 1); - if (!p) - return -ENOMEM; - - *p = (sd_dhcp_option) { - .n_ref = 1, - .option = option, - .length = length, - .data = TAKE_PTR(q), - }; - - *ret = TAKE_PTR(p); - return 0; -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_option, sd_dhcp_option, dhcp_option_free); -DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR( - dhcp_option_hash_ops, - void, - trivial_hash_func, - trivial_compare_func, - sd_dhcp_option, - sd_dhcp_option_unref); diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c deleted file mode 100644 index 25a69a616e..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c +++ /dev/null @@ -1,196 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright Ā© 2013 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include <errno.h> -#include <net/ethernet.h> -#include <net/if_arp.h> -#include <string.h> - -#include "dhcp-internal.h" -#include "dhcp-protocol.h" -#include "memory-util.h" - -#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312 - -int dhcp_message_init( - DHCPMessage *message, - uint8_t op, - uint32_t xid, - uint8_t type, - uint16_t arp_type, - uint8_t hlen, - const uint8_t *chaddr, - size_t optlen, - size_t *optoffset) { - - size_t offset = 0; - int r; - - assert(IN_SET(op, BOOTREQUEST, BOOTREPLY)); - assert(chaddr || hlen == 0); - - message->op = op; - message->htype = arp_type; - - /* RFC2131 section 4.1.1: - The client MUST include its hardware address in the āchaddrā field, if - necessary for delivery of DHCP reply messages. - - RFC 4390 section 2.1: - A DHCP client, when working over an IPoIB interface, MUST follow the - following rules: - "htype" (hardware address type) MUST be 32 [ARPPARAM]. - "hlen" (hardware address length) MUST be 0. - "chaddr" (client hardware address) field MUST be zeroed. - */ - message->hlen = (arp_type == ARPHRD_INFINIBAND) ? 0 : hlen; - memcpy_safe(message->chaddr, chaddr, message->hlen); - - message->xid = htobe32(xid); - message->magic = htobe32(DHCP_MAGIC_COOKIE); - - r = dhcp_option_append(message, optlen, &offset, 0, - SD_DHCP_OPTION_MESSAGE_TYPE, 1, &type); - if (r < 0) - return r; - - *optoffset = offset; - - return 0; -} - -uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) { - uint64_t *buf_64 = (uint64_t*)buf; - uint64_t *end_64 = buf_64 + (len / sizeof(uint64_t)); - uint64_t sum = 0; - - /* See RFC1071 */ - - while (buf_64 < end_64) { - sum += *buf_64; - if (sum < *buf_64) - /* wrap around in one's complement */ - sum++; - - buf_64++; - } - - if (len % sizeof(uint64_t)) { - /* If the buffer is not aligned to 64-bit, we need - to zero-pad the last few bytes and add them in */ - uint64_t buf_tail = 0; - - memcpy(&buf_tail, buf_64, len % sizeof(uint64_t)); - - sum += buf_tail; - if (sum < buf_tail) - /* wrap around */ - sum++; - } - - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); - - return ~sum; -} - -void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, - uint16_t source_port, be32_t destination_addr, - uint16_t destination_port, uint16_t len, int ip_service_type) { - packet->ip.version = IPVERSION; - packet->ip.ihl = DHCP_IP_SIZE / 4; - packet->ip.tot_len = htobe16(len); - - if (ip_service_type >= 0) - packet->ip.tos = ip_service_type; - else - packet->ip.tos = IPTOS_CLASS_CS6; - - packet->ip.protocol = IPPROTO_UDP; - packet->ip.saddr = source_addr; - packet->ip.daddr = destination_addr; - - packet->udp.source = htobe16(source_port); - packet->udp.dest = htobe16(destination_port); - - packet->udp.len = htobe16(len - DHCP_IP_SIZE); - - packet->ip.check = packet->udp.len; - packet->udp.check = dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, len - 8); - - packet->ip.ttl = IPDEFTTL; - packet->ip.check = 0; - packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE); -} - -int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port) { - size_t hdrlen; - - assert(packet); - - /* IP */ - - if (packet->ip.version != IPVERSION) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: not IPv4"); - - if (packet->ip.ihl < 5) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: IPv4 IHL (%u words) invalid", - packet->ip.ihl); - - hdrlen = packet->ip.ihl * 4; - if (hdrlen < 20) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: IPv4 IHL (%zu bytes) " - "smaller than minimum (20 bytes)", - hdrlen); - - if (len < hdrlen) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: packet (%zu bytes) " - "smaller than expected (%zu) by IP header", - len, hdrlen); - - /* UDP */ - - if (packet->ip.protocol != IPPROTO_UDP) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: not UDP"); - - if (len < hdrlen + be16toh(packet->udp.len)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: packet (%zu bytes) " - "smaller than expected (%zu) by UDP header", - len, hdrlen + be16toh(packet->udp.len)); - - if (be16toh(packet->udp.dest) != port) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: to port %u, which " - "is not the DHCP client port (%u)", - be16toh(packet->udp.dest), port); - - /* checksums - computing these is relatively expensive, so only do it - if all the other checks have passed - */ - - if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: invalid IP checksum"); - - if (checksum && packet->udp.check) { - packet->ip.check = packet->udp.len; - packet->ip.ttl = 0; - - if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, - be16toh(packet->udp.len) + 12)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: invalid UDP checksum"); - } - - return 0; -} diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h deleted file mode 100644 index dd54bcf6ee..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-protocol.h +++ /dev/null @@ -1,108 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/*** - Copyright Ā© 2013 Intel Corporation. All rights reserved. -***/ - -#include <netinet/ip.h> -#include <netinet/udp.h> -#include <stdint.h> - -#include "macro.h" -#include "sparse-endian.h" - -struct DHCPMessage { - uint8_t op; - uint8_t htype; - uint8_t hlen; - uint8_t hops; - be32_t xid; - be16_t secs; - be16_t flags; - be32_t ciaddr; - be32_t yiaddr; - be32_t siaddr; - be32_t giaddr; - uint8_t chaddr[16]; - uint8_t sname[64]; - uint8_t file[128]; - be32_t magic; - uint8_t options[0]; -} _packed_; - -typedef struct DHCPMessage DHCPMessage; - -struct DHCPPacket { - struct iphdr ip; - struct udphdr udp; - DHCPMessage dhcp; -} _packed_; - -typedef struct DHCPPacket DHCPPacket; - -#define DHCP_IP_SIZE (int32_t)(sizeof(struct iphdr)) -#define DHCP_IP_UDP_SIZE (int32_t)(sizeof(struct udphdr) + DHCP_IP_SIZE) -#define DHCP_MESSAGE_SIZE (int32_t)(sizeof(DHCPMessage)) -#define DHCP_DEFAULT_MIN_SIZE 576 /* the minimum internet hosts must be able to receive */ -#define DHCP_MIN_OPTIONS_SIZE (DHCP_DEFAULT_MIN_SIZE - DHCP_IP_UDP_SIZE - DHCP_MESSAGE_SIZE) -#define DHCP_MAGIC_COOKIE (uint32_t)(0x63825363) - -enum { - DHCP_PORT_SERVER = 67, - DHCP_PORT_CLIENT = 68, -}; - -enum DHCPState { - DHCP_STATE_INIT = 0, - DHCP_STATE_SELECTING = 1, - DHCP_STATE_INIT_REBOOT = 2, - DHCP_STATE_REBOOTING = 3, - DHCP_STATE_REQUESTING = 4, - DHCP_STATE_BOUND = 5, - DHCP_STATE_RENEWING = 6, - DHCP_STATE_REBINDING = 7, - DHCP_STATE_STOPPED = 8, -}; - -typedef enum DHCPState DHCPState; - -enum { - BOOTREQUEST = 1, - BOOTREPLY = 2, -}; - -enum { - DHCP_DISCOVER = 1, /* [RFC2132] */ - DHCP_OFFER = 2, /* [RFC2132] */ - DHCP_REQUEST = 3, /* [RFC2132] */ - DHCP_DECLINE = 4, /* [RFC2132] */ - DHCP_ACK = 5, /* [RFC2132] */ - DHCP_NAK = 6, /* [RFC2132] */ - DHCP_RELEASE = 7, /* [RFC2132] */ - DHCP_INFORM = 8, /* [RFC2132] */ - DHCP_FORCERENEW = 9, /* [RFC3203] */ - DHCPLEASEQUERY = 10, /* [RFC4388] */ - DHCPLEASEUNASSIGNED = 11, /* [RFC4388] */ - DHCPLEASEUNKNOWN = 12, /* [RFC4388] */ - DHCPLEASEACTIVE = 13, /* [RFC4388] */ - DHCPBULKLEASEQUERY = 14, /* [RFC6926] */ - DHCPLEASEQUERYDONE = 15, /* [RFC6926] */ - DHCPACTIVELEASEQUERY = 16, /* [RFC7724] */ - DHCPLEASEQUERYSTATUS = 17, /* [RFC7724] */ - DHCPTLS = 18, /* [RFC7724] */ -}; - -enum { - DHCP_OVERLOAD_FILE = 1, - DHCP_OVERLOAD_SNAME = 2, -}; - -#define DHCP_MAX_FQDN_LENGTH 255 - -enum { - DHCP_FQDN_FLAG_S = (1 << 0), - DHCP_FQDN_FLAG_O = (1 << 1), - DHCP_FQDN_FLAG_E = (1 << 2), - DHCP_FQDN_FLAG_N = (1 << 3), -}; diff --git a/src/libnm-systemd-core/src/libsystemd-network/network-internal.c b/src/libnm-systemd-core/src/libsystemd-network/network-internal.c deleted file mode 100644 index 60ce47eab1..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/network-internal.c +++ /dev/null @@ -1,243 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include "nm-sd-adapt-core.h" - -#include <arpa/inet.h> -#include <linux/if.h> -#include <netinet/ether.h> - -#include "sd-ndisc.h" - -#include "alloc-util.h" -#include "dhcp-lease-internal.h" -#include "extract-word.h" -#include "hexdecoct.h" -#include "log.h" -#include "network-internal.h" -#include "parse-util.h" - -size_t serialize_in_addrs(FILE *f, - const struct in_addr *addresses, - size_t size, - bool *with_leading_space, - bool (*predicate)(const struct in_addr *addr)) { - assert(f); - assert(addresses); - - size_t count = 0; - bool _space = false; - if (!with_leading_space) - with_leading_space = &_space; - - for (size_t i = 0; i < size; i++) { - char sbuf[INET_ADDRSTRLEN]; - - if (predicate && !predicate(&addresses[i])) - continue; - - if (*with_leading_space) - fputc(' ', f); - fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f); - count++; - *with_leading_space = true; - } - - return count; -} - -int deserialize_in_addrs(struct in_addr **ret, const char *string) { - _cleanup_free_ struct in_addr *addresses = NULL; - int size = 0; - - assert(ret); - assert(string); - - for (;;) { - _cleanup_free_ char *word = NULL; - struct in_addr *new_addresses; - int r; - - r = extract_first_word(&string, &word, NULL, 0); - if (r < 0) - return r; - if (r == 0) - break; - - new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr)); - if (!new_addresses) - return -ENOMEM; - else - addresses = new_addresses; - - r = inet_pton(AF_INET, word, &(addresses[size])); - if (r <= 0) - continue; - - size++; - } - - *ret = size > 0 ? TAKE_PTR(addresses) : NULL; - - return size; -} - -void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size, bool *with_leading_space) { - assert(f); - assert(addresses); - assert(size); - - bool _space = false; - if (!with_leading_space) - with_leading_space = &_space; - - for (size_t i = 0; i < size; i++) { - char buffer[INET6_ADDRSTRLEN]; - - if (*with_leading_space) - fputc(' ', f); - fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f); - *with_leading_space = true; - } -} - -int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { - _cleanup_free_ struct in6_addr *addresses = NULL; - int size = 0; - - assert(ret); - assert(string); - - for (;;) { - _cleanup_free_ char *word = NULL; - struct in6_addr *new_addresses; - int r; - - r = extract_first_word(&string, &word, NULL, 0); - if (r < 0) - return r; - if (r == 0) - break; - - new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr)); - if (!new_addresses) - return -ENOMEM; - else - addresses = new_addresses; - - r = inet_pton(AF_INET6, word, &(addresses[size])); - if (r <= 0) - continue; - - size++; - } - - *ret = TAKE_PTR(addresses); - - return size; -} - -void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) { - assert(f); - assert(key); - assert(routes); - assert(size); - - fprintf(f, "%s=", key); - - for (size_t i = 0; i < size; i++) { - char sbuf[INET_ADDRSTRLEN]; - struct in_addr dest, gw; - uint8_t length; - - assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0); - assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0); - assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0); - - fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof sbuf), length); - fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof sbuf), i < size - 1 ? " ": ""); - } - - fputs("\n", f); -} - -int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, const char *string) { - _cleanup_free_ struct sd_dhcp_route *routes = NULL; - size_t size = 0; - - assert(ret); - assert(ret_size); - assert(string); - - /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */ - for (;;) { - _cleanup_free_ char *word = NULL; - char *tok, *tok_end; - unsigned n; - int r; - - r = extract_first_word(&string, &word, NULL, 0); - if (r < 0) - return r; - if (r == 0) - break; - - if (!GREEDY_REALLOC(routes, size + 1)) - return -ENOMEM; - - tok = word; - - /* get the subnet */ - tok_end = strchr(tok, '/'); - if (!tok_end) - continue; - *tok_end = '\0'; - - r = inet_aton(tok, &routes[size].dst_addr); - if (r == 0) - continue; - - tok = tok_end + 1; - - /* get the prefixlen */ - tok_end = strchr(tok, ','); - if (!tok_end) - continue; - - *tok_end = '\0'; - - r = safe_atou(tok, &n); - if (r < 0 || n > 32) - continue; - - routes[size].dst_prefixlen = (uint8_t) n; - tok = tok_end + 1; - - /* get the gateway */ - r = inet_aton(tok, &routes[size].gw_addr); - if (r == 0) - continue; - - size++; - } - - *ret_size = size; - *ret = TAKE_PTR(routes); - - return 0; -} - -int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) { - _cleanup_free_ char *hex_buf = NULL; - - assert(f); - assert(key); - assert(data); - - hex_buf = hexmem(data, size); - if (!hex_buf) - return -ENOMEM; - - fprintf(f, "%s=%s\n", key, hex_buf); - - return 0; -} diff --git a/src/libnm-systemd-core/src/libsystemd-network/network-internal.h b/src/libnm-systemd-core/src/libsystemd-network/network-internal.h deleted file mode 100644 index 5aa225e977..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/network-internal.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -#include <stdbool.h> -#include <stdio.h> - -#include "sd-dhcp-lease.h" - -size_t serialize_in_addrs(FILE *f, - const struct in_addr *addresses, - size_t size, - bool *with_leading_space, - bool (*predicate)(const struct in_addr *addr)); -int deserialize_in_addrs(struct in_addr **addresses, const char *string); -void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, - size_t size, - bool *with_leading_space); -int deserialize_in6_addrs(struct in6_addr **addresses, const char *string); - -/* don't include "dhcp-lease-internal.h" as it causes conflicts between netinet/ip.h and linux/ip.h */ -struct sd_dhcp_route; -struct sd_dhcp_lease; - -void serialize_dhcp_routes(FILE *f, const char *key, struct sd_dhcp_route **routes, size_t size); -int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, const char *string); - -/* It is not necessary to add deserialize_dhcp_option(). Use unhexmem() instead. */ -int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size); - -int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file); -int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file); diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c deleted file mode 100644 index d56978adcd..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-client.c +++ /dev/null @@ -1,2285 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright Ā© 2013 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include <errno.h> -#include <net/ethernet.h> -#include <net/if_arp.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/ioctl.h> -#include <linux/if_infiniband.h> - -#include "sd-dhcp-client.h" - -#include "alloc-util.h" -#include "dhcp-identifier.h" -#include "dhcp-internal.h" -#include "dhcp-lease-internal.h" -#include "dhcp-protocol.h" -#include "dns-domain.h" -#include "event-util.h" -#include "fd-util.h" -#include "hostname-util.h" -#include "io-util.h" -#include "memory-util.h" -#include "network-common.h" -#include "random-util.h" -#include "set.h" -#include "sort-util.h" -#include "string-util.h" -#include "strv.h" -#include "time-util.h" -#include "utf8.h" -#include "web-util.h" - -#define MAX_CLIENT_ID_LEN (sizeof(uint32_t) + MAX_DUID_LEN) /* Arbitrary limit */ -#define MAX_MAC_ADDR_LEN CONST_MAX(INFINIBAND_ALEN, ETH_ALEN) - -#define RESTART_AFTER_NAK_MIN_USEC (1 * USEC_PER_SEC) -#define RESTART_AFTER_NAK_MAX_USEC (30 * USEC_PER_MINUTE) - -#define TRANSIENT_FAILURE_ATTEMPTS 3 /* Arbitrary limit: how many attempts are considered enough to report - * transient failure. */ - -typedef struct sd_dhcp_client_id { - uint8_t type; - union { - struct { - /* 0: Generic (non-LL) (RFC 2132) */ - uint8_t data[MAX_CLIENT_ID_LEN]; - } _packed_ gen; - struct { - /* 1: Ethernet Link-Layer (RFC 2132) */ - uint8_t haddr[ETH_ALEN]; - } _packed_ eth; - struct { - /* 2 - 254: ARP/Link-Layer (RFC 2132) */ - uint8_t haddr[0]; - } _packed_ ll; - struct { - /* 255: Node-specific (RFC 4361) */ - be32_t iaid; - struct duid duid; - } _packed_ ns; - struct { - uint8_t data[MAX_CLIENT_ID_LEN]; - } _packed_ raw; - }; -} _packed_ sd_dhcp_client_id; - -struct sd_dhcp_client { - unsigned n_ref; - - DHCPState state; - sd_event *event; - int event_priority; - sd_event_source *timeout_resend; - int ifindex; - char *ifname; - int fd; - uint16_t port; - union sockaddr_union link; - sd_event_source *receive_message; - bool request_broadcast; - Set *req_opts; - bool anonymize; - be32_t last_addr; - uint8_t mac_addr[MAX_MAC_ADDR_LEN]; - size_t mac_addr_len; - uint8_t bcast_addr[MAX_MAC_ADDR_LEN]; - size_t bcast_addr_len; - uint16_t arp_type; - sd_dhcp_client_id client_id; - size_t client_id_len; - char *hostname; - char *vendor_class_identifier; - char *mudurl; - char **user_class; - uint32_t mtu; - uint32_t fallback_lease_lifetime; - uint32_t xid; - usec_t start_time; - usec_t t1_time; - usec_t t2_time; - usec_t expire_time; - uint64_t attempt; - uint64_t max_attempts; - OrderedHashmap *extra_options; - OrderedHashmap *vendor_options; - usec_t request_sent; - sd_event_source *timeout_t1; - sd_event_source *timeout_t2; - sd_event_source *timeout_expire; - sd_dhcp_client_callback_t callback; - void *userdata; - sd_dhcp_lease *lease; - usec_t start_delay; - int ip_service_type; - - /* Ignore ifindex when generating iaid. See dhcp_identifier_set_iaid(). */ - bool test_mode; -}; - -static const uint8_t default_req_opts[] = { - SD_DHCP_OPTION_SUBNET_MASK, - SD_DHCP_OPTION_ROUTER, - SD_DHCP_OPTION_HOST_NAME, - SD_DHCP_OPTION_DOMAIN_NAME, - SD_DHCP_OPTION_DOMAIN_NAME_SERVER, -}; - -/* RFC7844 section 3: - MAY contain the Parameter Request List option. - RFC7844 section 3.6: - The client intending to protect its privacy SHOULD only request a - minimal number of options in the PRL and SHOULD also randomly shuffle - the ordering of option codes in the PRL. If this random ordering - cannot be implemented, the client MAY order the option codes in the - PRL by option code number (lowest to highest). -*/ -/* NOTE: using PRL options that Windows 10 RFC7844 implementation uses */ -static const uint8_t default_req_opts_anonymize[] = { - SD_DHCP_OPTION_SUBNET_MASK, /* 1 */ - SD_DHCP_OPTION_ROUTER, /* 3 */ - SD_DHCP_OPTION_DOMAIN_NAME_SERVER, /* 6 */ - SD_DHCP_OPTION_DOMAIN_NAME, /* 15 */ - SD_DHCP_OPTION_ROUTER_DISCOVERY, /* 31 */ - SD_DHCP_OPTION_STATIC_ROUTE, /* 33 */ - SD_DHCP_OPTION_VENDOR_SPECIFIC, /* 43 */ - SD_DHCP_OPTION_NETBIOS_NAME_SERVER, /* 44 */ - SD_DHCP_OPTION_NETBIOS_NODE_TYPE, /* 46 */ - SD_DHCP_OPTION_NETBIOS_SCOPE, /* 47 */ - SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE, /* 121 */ - SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE, /* 249 */ - SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY, /* 252 */ -}; - -static int client_receive_message_raw( - sd_event_source *s, - int fd, - uint32_t revents, - void *userdata); -static int client_receive_message_udp( - sd_event_source *s, - int fd, - uint32_t revents, - void *userdata); -static void client_stop(sd_dhcp_client *client, int error); - -int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret) { - const sd_dhcp_client_id *client_id = data; - _cleanup_free_ char *t = NULL; - int r = 0; - - assert_return(data, -EINVAL); - assert_return(len >= 1, -EINVAL); - assert_return(ret, -EINVAL); - - len -= 1; - if (len > MAX_CLIENT_ID_LEN) - return -EINVAL; - - switch (client_id->type) { - case 0: - if (utf8_is_printable((char *) client_id->gen.data, len)) - r = asprintf(&t, "%.*s", (int) len, client_id->gen.data); - else - r = asprintf(&t, "DATA"); - break; - case 1: - if (len != sizeof_field(sd_dhcp_client_id, eth)) - return -EINVAL; - - r = asprintf(&t, "%02x:%02x:%02x:%02x:%02x:%02x", - client_id->eth.haddr[0], - client_id->eth.haddr[1], - client_id->eth.haddr[2], - client_id->eth.haddr[3], - client_id->eth.haddr[4], - client_id->eth.haddr[5]); - break; - case 2 ... 254: - r = asprintf(&t, "ARP/LL"); - break; - case 255: - if (len < 6) - return -EINVAL; - - uint32_t iaid = be32toh(client_id->ns.iaid); - uint16_t duid_type = be16toh(client_id->ns.duid.type); - if (dhcp_validate_duid_len(duid_type, len - 6, true) < 0) - return -EINVAL; - - r = asprintf(&t, "IAID:0x%x/DUID", iaid); - break; - } - - if (r < 0) - return -ENOMEM; - *ret = TAKE_PTR(t); - return 0; -} - -int sd_dhcp_client_set_callback( - sd_dhcp_client *client, - sd_dhcp_client_callback_t cb, - void *userdata) { - - assert_return(client, -EINVAL); - - client->callback = cb; - client->userdata = userdata; - - return 0; -} - -int sd_dhcp_client_set_request_broadcast(sd_dhcp_client *client, int broadcast) { - assert_return(client, -EINVAL); - - client->request_broadcast = broadcast; - - return 0; -} - -int sd_dhcp_client_set_request_option(sd_dhcp_client *client, uint8_t option) { - assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); - - switch (option) { - - case SD_DHCP_OPTION_PAD: - case SD_DHCP_OPTION_OVERLOAD: - case SD_DHCP_OPTION_MESSAGE_TYPE: - case SD_DHCP_OPTION_PARAMETER_REQUEST_LIST: - case SD_DHCP_OPTION_END: - return -EINVAL; - - default: - break; - } - - return set_ensure_put(&client->req_opts, NULL, UINT8_TO_PTR(option)); -} - -int sd_dhcp_client_set_request_address( - sd_dhcp_client *client, - const struct in_addr *last_addr) { - - assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); - - if (last_addr) - client->last_addr = last_addr->s_addr; - else - client->last_addr = INADDR_ANY; - - return 0; -} - -int sd_dhcp_client_set_ifindex(sd_dhcp_client *client, int ifindex) { - assert_return(client, -EINVAL); - assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED), -EBUSY); - assert_return(ifindex > 0, -EINVAL); - - client->ifindex = ifindex; - return 0; -} - -int sd_dhcp_client_set_ifname(sd_dhcp_client *client, const char *ifname) { - assert_return(client, -EINVAL); - assert_return(ifname, -EINVAL); - - if (!ifname_valid_full(ifname, IFNAME_VALID_ALTERNATIVE)) - return -EINVAL; - - return free_and_strdup(&client->ifname, ifname); -} - -int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret) { - int r; - - assert_return(client, -EINVAL); - - r = get_ifname(client->ifindex, &client->ifname); - if (r < 0) - return r; - - if (ret) - *ret = client->ifname; - - return 0; -} - -int sd_dhcp_client_set_mac( - sd_dhcp_client *client, - const uint8_t *addr, - const uint8_t *bcast_addr, - size_t addr_len, - uint16_t arp_type) { - - DHCP_CLIENT_DONT_DESTROY(client); - bool need_restart = false; - int r; - - assert_return(client, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(addr_len > 0 && addr_len <= MAX_MAC_ADDR_LEN, -EINVAL); - assert_return(arp_type > 0, -EINVAL); - - if (arp_type == ARPHRD_ETHER) - assert_return(addr_len == ETH_ALEN, -EINVAL); - else if (arp_type == ARPHRD_INFINIBAND) - assert_return(addr_len == INFINIBAND_ALEN, -EINVAL); - else - return -EINVAL; - - if (client->mac_addr_len == addr_len && - memcmp(&client->mac_addr, addr, addr_len) == 0 && - (client->bcast_addr_len > 0) == !!bcast_addr && - (!bcast_addr || memcmp(&client->bcast_addr, bcast_addr, addr_len) == 0)) - return 0; - - if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Changing MAC address on running DHCP client, restarting"); - need_restart = true; - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - } - - memcpy(&client->mac_addr, addr, addr_len); - client->mac_addr_len = addr_len; - client->arp_type = arp_type; - client->bcast_addr_len = 0; - - if (bcast_addr) { - memcpy(&client->bcast_addr, bcast_addr, addr_len); - client->bcast_addr_len = addr_len; - } - - if (need_restart && client->state != DHCP_STATE_STOPPED) { - r = sd_dhcp_client_start(client); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); - } - - return 0; -} - -int sd_dhcp_client_get_client_id( - sd_dhcp_client *client, - uint8_t *type, - const uint8_t **data, - size_t *data_len) { - - assert_return(client, -EINVAL); - assert_return(type, -EINVAL); - assert_return(data, -EINVAL); - assert_return(data_len, -EINVAL); - - if (client->client_id_len) { - *type = client->client_id.type; - *data = client->client_id.raw.data; - *data_len = client->client_id_len - sizeof(client->client_id.type); - } else { - *type = 0; - *data = NULL; - *data_len = 0; - } - - return 0; -} - -int sd_dhcp_client_set_client_id( - sd_dhcp_client *client, - uint8_t type, - const uint8_t *data, - size_t data_len) { - - DHCP_CLIENT_DONT_DESTROY(client); - bool need_restart = false; - int r; - - assert_return(client, -EINVAL); - assert_return(data, -EINVAL); - assert_return(data_len > 0 && data_len <= MAX_CLIENT_ID_LEN, -EINVAL); - G_STATIC_ASSERT_EXPR (_NM_MAX_CLIENT_ID_LEN == MAX_CLIENT_ID_LEN); - - if (client->client_id_len == data_len + sizeof(client->client_id.type) && - client->client_id.type == type && - memcmp(&client->client_id.raw.data, data, data_len) == 0) - return 0; - - /* For hardware types, log debug message about unexpected data length. - * - * Note that infiniband's INFINIBAND_ALEN is 20 bytes long, but only - * the last 8 bytes of the address are stable and suitable to put into - * the client-id. The caller is advised to account for that. */ - if ((type == ARPHRD_ETHER && data_len != ETH_ALEN) || - (type == ARPHRD_INFINIBAND && data_len != 8)) - log_dhcp_client(client, "Changing client ID to hardware type %u with " - "unexpected address length %zu", - type, data_len); - - if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Changing client ID on running DHCP " - "client, restarting"); - need_restart = true; - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - } - - client->client_id.type = type; - memcpy(&client->client_id.raw.data, data, data_len); - client->client_id_len = data_len + sizeof (client->client_id.type); - - if (need_restart && client->state != DHCP_STATE_STOPPED) { - r = sd_dhcp_client_start(client); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); - } - - return 0; -} - -#if 0 /* NM_IGNORED */ -/** - * Sets IAID and DUID. If duid is non-null, the DUID is set to duid_type + duid - * without further modification. Otherwise, if duid_type is supported, DUID - * is set based on that type. Otherwise, an error is returned. - */ -static int dhcp_client_set_iaid_duid_internal( - sd_dhcp_client *client, - bool iaid_append, - bool iaid_set, - uint32_t iaid, - DUIDType duid_type, - const void *duid, - size_t duid_len, - usec_t llt_time) { - - DHCP_CLIENT_DONT_DESTROY(client); - int r; - size_t len; - - assert_return(client, -EINVAL); - assert_return(duid_len == 0 || duid, -EINVAL); - - if (duid) { - r = dhcp_validate_duid_len(duid_type, duid_len, true); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to validate length of DUID: %m"); - } - - zero(client->client_id); - client->client_id.type = 255; - - if (iaid_append) { - if (iaid_set) - client->client_id.ns.iaid = htobe32(iaid); - else { - r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, - client->mac_addr_len, - /* legacy_unstable_byteorder = */ true, - /* use_mac = */ client->test_mode, - &client->client_id.ns.iaid); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to set IAID: %m"); - } - } - - if (duid) { - client->client_id.ns.duid.type = htobe16(duid_type); - memcpy(&client->client_id.ns.duid.raw.data, duid, duid_len); - len = sizeof(client->client_id.ns.duid.type) + duid_len; - - } else { - r = dhcp_identifier_set_duid(duid_type, client->mac_addr, client->mac_addr_len, - client->arp_type, llt_time, client->test_mode, - &client->client_id.ns.duid, &len); - if (r == -EOPNOTSUPP) - return log_dhcp_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_dhcp_client_errno(client, r, "Failed to set %s: %m", - duid_type_to_string(duid_type)); - } - - client->client_id_len = sizeof(client->client_id.type) + len + - (iaid_append ? sizeof(client->client_id.ns.iaid) : 0); - - if (!IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED)) { - log_dhcp_client(client, "Configured %sDUID, restarting.", iaid_append ? "IAID+" : ""); - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - r = sd_dhcp_client_start(client); - if (r < 0) - return log_dhcp_client_errno(client, r, "Failed to restart DHCPv4 client: %m"); - } - - return 0; -} - -int sd_dhcp_client_set_iaid_duid( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - uint16_t duid_type, - const void *duid, - size_t duid_len) { - return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, duid_type, duid, duid_len, 0); -} - -int sd_dhcp_client_set_iaid_duid_llt( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - usec_t llt_time) { - return dhcp_client_set_iaid_duid_internal(client, true, iaid_set, iaid, DUID_TYPE_LLT, NULL, 0, llt_time); -} - -int sd_dhcp_client_set_duid( - sd_dhcp_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len) { - return dhcp_client_set_iaid_duid_internal(client, false, false, 0, duid_type, duid, duid_len, 0); -} - -int sd_dhcp_client_set_duid_llt( - sd_dhcp_client *client, - usec_t llt_time) { - return dhcp_client_set_iaid_duid_internal(client, false, false, 0, DUID_TYPE_LLT, NULL, 0, llt_time); -} -#endif /* NM_IGNORED */ - -void dhcp_client_set_test_mode(sd_dhcp_client *client, bool test_mode) { - assert(client); - - client->test_mode = test_mode; -} - -int sd_dhcp_client_set_hostname( - sd_dhcp_client *client, - const char *hostname) { - - assert_return(client, -EINVAL); - - /* Make sure hostnames qualify as DNS and as Linux hostnames */ - if (hostname && - !(hostname_is_valid(hostname, 0) && dns_name_is_valid(hostname) > 0)) - return -EINVAL; - - return free_and_strdup(&client->hostname, hostname); -} - -int sd_dhcp_client_set_vendor_class_identifier( - sd_dhcp_client *client, - const char *vci) { - - assert_return(client, -EINVAL); - - return free_and_strdup(&client->vendor_class_identifier, vci); -} - -int sd_dhcp_client_set_mud_url( - sd_dhcp_client *client, - const char *mudurl) { - - assert_return(client, -EINVAL); - assert_return(mudurl, -EINVAL); - assert_return(strlen(mudurl) <= 255, -EINVAL); - assert_return(http_url_is_valid(mudurl), -EINVAL); - - return free_and_strdup(&client->mudurl, mudurl); -} - -int sd_dhcp_client_set_user_class( - sd_dhcp_client *client, - char * const *user_class) { - - char **s = NULL; - - assert_return(client, -EINVAL); - assert_return(!strv_isempty(user_class), -EINVAL); - - STRV_FOREACH(p, user_class) { - size_t n = strlen(*p); - - if (n > 255 || n == 0) - return -EINVAL; - } - - s = strv_copy(user_class); - if (!s) - return -ENOMEM; - - return strv_free_and_replace(client->user_class, s); -} - -int sd_dhcp_client_set_client_port( - sd_dhcp_client *client, - uint16_t port) { - - assert_return(client, -EINVAL); - - client->port = port; - - return 0; -} - -int sd_dhcp_client_set_mtu(sd_dhcp_client *client, uint32_t mtu) { - assert_return(client, -EINVAL); - assert_return(mtu >= DHCP_DEFAULT_MIN_SIZE, -ERANGE); - - client->mtu = mtu; - - return 0; -} - -int sd_dhcp_client_set_max_attempts(sd_dhcp_client *client, uint64_t max_attempts) { - assert_return(client, -EINVAL); - - client->max_attempts = max_attempts; - - return 0; -} - -int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v) { - int r; - - assert_return(client, -EINVAL); - assert_return(v, -EINVAL); - - r = ordered_hashmap_ensure_put(&client->extra_options, &dhcp_option_hash_ops, UINT_TO_PTR(v->option), v); - if (r < 0) - return r; - - sd_dhcp_option_ref(v); - return 0; -} - -int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v) { - int r; - - assert_return(client, -EINVAL); - assert_return(v, -EINVAL); - - r = ordered_hashmap_ensure_allocated(&client->vendor_options, &dhcp_option_hash_ops); - if (r < 0) - return -ENOMEM; - - r = ordered_hashmap_put(client->vendor_options, v, v); - if (r < 0) - return r; - - sd_dhcp_option_ref(v); - - return 1; -} - -int sd_dhcp_client_get_lease(sd_dhcp_client *client, sd_dhcp_lease **ret) { - assert_return(client, -EINVAL); - - if (!IN_SET(client->state, DHCP_STATE_SELECTING, DHCP_STATE_BOUND, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING)) - return -EADDRNOTAVAIL; - - if (ret) - *ret = client->lease; - - return 0; -} - -int sd_dhcp_client_set_service_type(sd_dhcp_client *client, int type) { - assert_return(client, -EINVAL); - - client->ip_service_type = type; - - return 0; -} - -int sd_dhcp_client_set_fallback_lease_lifetime(sd_dhcp_client *client, uint32_t fallback_lease_lifetime) { - assert_return(client, -EINVAL); - assert_return(fallback_lease_lifetime > 0, -EINVAL); - - client->fallback_lease_lifetime = fallback_lease_lifetime; - - return 0; -} - -static int client_notify(sd_dhcp_client *client, int event) { - assert(client); - - if (client->callback) - return client->callback(client, event, client->userdata); - - return 0; -} - -static int client_initialize(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - - client->receive_message = sd_event_source_disable_unref(client->receive_message); - - client->fd = safe_close(client->fd); - - (void) event_source_disable(client->timeout_resend); - (void) event_source_disable(client->timeout_t1); - (void) event_source_disable(client->timeout_t2); - (void) event_source_disable(client->timeout_expire); - - client->attempt = 0; - - client->state = DHCP_STATE_INIT; - client->xid = 0; - - client->lease = sd_dhcp_lease_unref(client->lease); - - return 0; -} - -static void client_stop(sd_dhcp_client *client, int error) { - assert(client); - - if (error < 0) - log_dhcp_client_errno(client, error, "STOPPED: %m"); - else if (error == SD_DHCP_CLIENT_EVENT_STOP) - log_dhcp_client(client, "STOPPED"); - else - log_dhcp_client(client, "STOPPED: Unknown event"); - - client_notify(client, error); - - client_initialize(client); -} - -/* RFC2131 section 4.1: - * retransmission delays should include -1 to +1 sec of random 'fuzz'. */ -#define RFC2131_RANDOM_FUZZ \ - ((int64_t)(random_u64() % (2 * USEC_PER_SEC)) - (int64_t)USEC_PER_SEC) - -/* RFC2131 section 4.1: - * for retransmission delays, timeout should start at 4s then double - * each attempt with max of 64s, with -1 to +1 sec of random 'fuzz' added. - * This assumes the first call will be using attempt 1. */ -static usec_t client_compute_request_timeout(usec_t now, uint64_t attempt) { - usec_t timeout = (UINT64_C(1) << MIN(attempt + 1, UINT64_C(6))) * USEC_PER_SEC; - - return usec_sub_signed(usec_add(now, timeout), RFC2131_RANDOM_FUZZ); -} - -/* RFC2131 section 4.4.5: - * T1 defaults to (0.5 * duration_of_lease). - * T2 defaults to (0.875 * duration_of_lease). */ -#define T1_DEFAULT(lifetime) ((lifetime) / 2) -#define T2_DEFAULT(lifetime) (((lifetime) * 7) / 8) - -/* RFC2131 section 4.4.5: - * the client SHOULD wait one-half of the remaining time until T2 (in RENEWING state) - * and one-half of the remaining lease time (in REBINDING state), down to a minimum - * of 60 seconds. - * Note that while the default T1/T2 initial times do have random 'fuzz' applied, - * the RFC sec 4.4.5 does not mention adding any fuzz to retries. */ -static usec_t client_compute_reacquisition_timeout(usec_t now, usec_t expire) { - return now + MAX(usec_sub_unsigned(expire, now) / 2, 60 * USEC_PER_SEC); -} - -static int cmp_uint8(const uint8_t *a, const uint8_t *b) { - return CMP(*a, *b); -} - -static int client_message_init( - sd_dhcp_client *client, - DHCPPacket **ret, - uint8_t type, - size_t *_optlen, - size_t *_optoffset) { - - _cleanup_free_ DHCPPacket *packet = NULL; - size_t optlen, optoffset, size; - be16_t max_size; - usec_t time_now; - uint16_t secs; - int r; - - assert(client); - assert(client->start_time); - assert(ret); - assert(_optlen); - assert(_optoffset); - assert(IN_SET(type, DHCP_DISCOVER, DHCP_REQUEST, DHCP_RELEASE, DHCP_DECLINE)); - - optlen = DHCP_MIN_OPTIONS_SIZE; - size = sizeof(DHCPPacket) + optlen; - - packet = malloc0(size); - if (!packet) - return -ENOMEM; - - r = dhcp_message_init(&packet->dhcp, BOOTREQUEST, client->xid, type, - client->arp_type, client->mac_addr_len, client->mac_addr, - optlen, &optoffset); - if (r < 0) - return r; - - /* Although 'secs' field is a SHOULD in RFC 2131, certain DHCP servers - refuse to issue an DHCP lease if 'secs' is set to zero */ - r = sd_event_now(client->event, CLOCK_BOOTTIME, &time_now); - if (r < 0) - return r; - assert(time_now >= client->start_time); - - /* seconds between sending first and last DISCOVER - * must always be strictly positive to deal with broken servers */ - secs = ((time_now - client->start_time) / USEC_PER_SEC) ? : 1; - packet->dhcp.secs = htobe16(secs); - - /* RFC2131 section 4.1 - A client that cannot receive unicast IP datagrams until its protocol - software has been configured with an IP address SHOULD set the - BROADCAST bit in the 'flags' field to 1 in any DHCPDISCOVER or - DHCPREQUEST messages that client sends. The BROADCAST bit will - provide a hint to the DHCP server and BOOTP relay agent to broadcast - any messages to the client on the client's subnet. - - Note: some interfaces needs this to be enabled, but some networks - needs this to be disabled as broadcasts are filteretd, so this - needs to be configurable */ - if (client->request_broadcast || client->arp_type != ARPHRD_ETHER) - packet->dhcp.flags = htobe16(0x8000); - - /* If no client identifier exists, construct an RFC 4361-compliant one */ - if (client->client_id_len == 0) { - size_t duid_len; - - client->client_id.type = 255; - - r = dhcp_identifier_set_iaid(client->ifindex, client->mac_addr, client->mac_addr_len, - /* legacy_unstable_byteorder = */ true, - /* use_mac = */ client->test_mode, - &client->client_id.ns.iaid); - if (r < 0) - return r; - - r = dhcp_identifier_set_duid_en(client->test_mode, &client->client_id.ns.duid, &duid_len); - if (r < 0) - return r; - - client->client_id_len = sizeof(client->client_id.type) + sizeof(client->client_id.ns.iaid) + duid_len; - } - - /* Some DHCP servers will refuse to issue an DHCP lease if the Client - Identifier option is not set */ - if (client->client_id_len) { - r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_CLIENT_IDENTIFIER, - client->client_id_len, - &client->client_id); - if (r < 0) - return r; - } - - /* RFC2131 section 3.5: - in its initial DHCPDISCOVER or DHCPREQUEST message, a - client may provide the server with a list of specific - parameters the client is interested in. If the client - includes a list of parameters in a DHCPDISCOVER message, - it MUST include that list in any subsequent DHCPREQUEST - messages. - */ - - /* RFC7844 section 3: - MAY contain the Parameter Request List option. */ - /* NOTE: in case that there would be an option to do not send - * any PRL at all, the size should be checked before sending */ - if (!set_isempty(client->req_opts) && type != DHCP_RELEASE) { - _cleanup_free_ uint8_t *opts = NULL; - size_t n_opts, i = 0; - void *val; - - n_opts = set_size(client->req_opts); - opts = new(uint8_t, n_opts); - if (!opts) - return -ENOMEM; - - SET_FOREACH(val, client->req_opts) - opts[i++] = PTR_TO_UINT8(val); - assert(i == n_opts); - - /* For anonymizing the request, let's sort the options. */ - typesafe_qsort(opts, n_opts, cmp_uint8); - - r = dhcp_option_append(&packet->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_PARAMETER_REQUEST_LIST, - n_opts, opts); - if (r < 0) - return r; - } - - /* RFC2131 section 3.5: - The client SHOULD include the āmaximum DHCP message sizeā option to - let the server know how large the server may make its DHCP messages. - - Note (from ConnMan): Some DHCP servers will send bigger DHCP packets - than the defined default size unless the Maximum Message Size option - is explicitly set - - RFC3442 "Requirements to Avoid Sizing Constraints": - Because a full routing table can be quite large, the standard 576 - octet maximum size for a DHCP message may be too short to contain - some legitimate Classless Static Route options. Because of this, - clients implementing the Classless Static Route option SHOULD send a - Maximum DHCP Message Size [4] option if the DHCP client's TCP/IP - stack is capable of receiving larger IP datagrams. In this case, the - client SHOULD set the value of this option to at least the MTU of the - interface that the client is configuring. The client MAY set the - value of this option higher, up to the size of the largest UDP packet - it is prepared to accept. (Note that the value specified in the - Maximum DHCP Message Size option is the total maximum packet size, - including IP and UDP headers.) - */ - /* RFC7844 section 3: - SHOULD NOT contain any other option. */ - if (!client->anonymize && type != DHCP_RELEASE) { - max_size = htobe16(size); - r = dhcp_option_append(&packet->dhcp, client->mtu, &optoffset, 0, - SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE, - 2, &max_size); - if (r < 0) - return r; - } - - *_optlen = optlen; - *_optoffset = optoffset; - *ret = TAKE_PTR(packet); - - return 0; -} - -static int client_append_fqdn_option( - DHCPMessage *message, - size_t optlen, - size_t *optoffset, - const char *fqdn) { - - uint8_t buffer[3 + DHCP_MAX_FQDN_LENGTH]; - int r; - - buffer[0] = DHCP_FQDN_FLAG_S | /* Request server to perform A RR DNS updates */ - DHCP_FQDN_FLAG_E; /* Canonical wire format */ - buffer[1] = 0; /* RCODE1 (deprecated) */ - buffer[2] = 0; /* RCODE2 (deprecated) */ - - r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false); - if (r > 0) - r = dhcp_option_append(message, optlen, optoffset, 0, - SD_DHCP_OPTION_FQDN, 3 + r, buffer); - - return r; -} - -static int dhcp_client_send_raw( - sd_dhcp_client *client, - DHCPPacket *packet, - size_t len) { - - dhcp_packet_append_ip_headers(packet, INADDR_ANY, client->port, - INADDR_BROADCAST, DHCP_PORT_SERVER, len, client->ip_service_type); - - return dhcp_network_send_raw_socket(client->fd, &client->link, - packet, len); -} - -static int client_append_common_discover_request_options(sd_dhcp_client *client, DHCPPacket *packet, size_t *optoffset, size_t optlen) { - sd_dhcp_option *j; - int r; - - assert(client); - - if (client->hostname) { - /* According to RFC 4702 "clients that send the Client FQDN option in - their messages MUST NOT also send the Host Name option". Just send - one of the two depending on the hostname type. - */ - if (dns_name_is_single_label(client->hostname)) { - /* it is unclear from RFC 2131 if client should send hostname in - DHCPDISCOVER but dhclient does and so we do as well - */ - r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0, - SD_DHCP_OPTION_HOST_NAME, - strlen(client->hostname), client->hostname); - } else - r = client_append_fqdn_option(&packet->dhcp, optlen, optoffset, - client->hostname); - if (r < 0) - return r; - } - - if (client->vendor_class_identifier) { - r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0, - SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER, - strlen(client->vendor_class_identifier), - client->vendor_class_identifier); - if (r < 0) - return r; - } - - if (client->mudurl) { - r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0, - SD_DHCP_OPTION_MUD_URL, - strlen(client->mudurl), - client->mudurl); - if (r < 0) - return r; - } - - if (client->user_class) { - r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0, - SD_DHCP_OPTION_USER_CLASS, - strv_length(client->user_class), - client->user_class); - if (r < 0) - return r; - } - - ORDERED_HASHMAP_FOREACH(j, client->extra_options) { - r = dhcp_option_append(&packet->dhcp, optlen, optoffset, 0, - j->option, j->length, j->data); - if (r < 0) - return r; - } - - if (!ordered_hashmap_isempty(client->vendor_options)) { - r = dhcp_option_append( - &packet->dhcp, optlen, optoffset, 0, - SD_DHCP_OPTION_VENDOR_SPECIFIC, - ordered_hashmap_size(client->vendor_options), client->vendor_options); - if (r < 0) - return r; - } - - - return 0; -} - -static int client_send_discover(sd_dhcp_client *client) { - _cleanup_free_ DHCPPacket *discover = NULL; - size_t optoffset, optlen; - int r; - - assert(client); - assert(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_SELECTING)); - - r = client_message_init(client, &discover, DHCP_DISCOVER, - &optlen, &optoffset); - if (r < 0) - return r; - - /* the client may suggest values for the network address - and lease time in the DHCPDISCOVER message. The client may include - the ārequested IP addressā option to suggest that a particular IP - address be assigned, and may include the āIP address lease timeā - option to suggest the lease time it would like. - */ - /* RFC7844 section 3: - SHOULD NOT contain any other option. */ - if (!client->anonymize && client->last_addr != INADDR_ANY) { - r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, - 4, &client->last_addr); - if (r < 0) - return r; - } - - r = client_append_common_discover_request_options(client, discover, &optoffset, optlen); - if (r < 0) - return r; - - r = dhcp_option_append(&discover->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - /* We currently ignore: - The client SHOULD wait a random time between one and ten seconds to - desynchronize the use of DHCP at startup. - */ - r = dhcp_client_send_raw(client, discover, sizeof(DHCPPacket) + optoffset); - if (r < 0) - return r; - - log_dhcp_client(client, "DISCOVER"); - - return 0; -} - -static int client_send_request(sd_dhcp_client *client) { - _cleanup_free_ DHCPPacket *request = NULL; - size_t optoffset, optlen; - int r; - - assert(client); - - r = client_message_init(client, &request, DHCP_REQUEST, &optlen, &optoffset); - if (r < 0) - return r; - - switch (client->state) { - /* See RFC2131 section 4.3.2 (note that there is a typo in the RFC, - SELECTING should be REQUESTING) - */ - - case DHCP_STATE_REQUESTING: - /* Client inserts the address of the selected server in āserver - identifierā, āciaddrā MUST be zero, ārequested IP addressā MUST be - filled in with the yiaddr value from the chosen DHCPOFFER. - */ - - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_SERVER_IDENTIFIER, - 4, &client->lease->server_address); - if (r < 0) - return r; - - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, - 4, &client->lease->address); - if (r < 0) - return r; - - break; - - case DHCP_STATE_INIT_REBOOT: - /* āserver identifierā MUST NOT be filled in, ārequested IP addressā - option MUST be filled in with clientās notion of its previously - assigned address. āciaddrā MUST be zero. - */ - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_REQUESTED_IP_ADDRESS, - 4, &client->last_addr); - if (r < 0) - return r; - break; - - case DHCP_STATE_RENEWING: - /* āserver identifierā MUST NOT be filled in, ārequested IP addressā - option MUST NOT be filled in, āciaddrā MUST be filled in with - clientās IP address. - */ - - case DHCP_STATE_REBINDING: - /* āserver identifierā MUST NOT be filled in, ārequested IP addressā - option MUST NOT be filled in, āciaddrā MUST be filled in with - clientās IP address. - - This message MUST be broadcast to the 0xffffffff IP broadcast address. - */ - request->dhcp.ciaddr = client->lease->address; - - break; - - case DHCP_STATE_INIT: - case DHCP_STATE_SELECTING: - case DHCP_STATE_REBOOTING: - case DHCP_STATE_BOUND: - case DHCP_STATE_STOPPED: - return -EINVAL; - } - - r = client_append_common_discover_request_options(client, request, &optoffset, optlen); - if (r < 0) - return r; - - r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - if (client->state == DHCP_STATE_RENEWING) - r = dhcp_network_send_udp_socket(client->fd, - client->lease->server_address, - DHCP_PORT_SERVER, - &request->dhcp, - sizeof(DHCPMessage) + optoffset); - else - r = dhcp_client_send_raw(client, request, sizeof(DHCPPacket) + optoffset); - if (r < 0) - return r; - - switch (client->state) { - - case DHCP_STATE_REQUESTING: - log_dhcp_client(client, "REQUEST (requesting)"); - break; - - case DHCP_STATE_INIT_REBOOT: - log_dhcp_client(client, "REQUEST (init-reboot)"); - break; - - case DHCP_STATE_RENEWING: - log_dhcp_client(client, "REQUEST (renewing)"); - break; - - case DHCP_STATE_REBINDING: - log_dhcp_client(client, "REQUEST (rebinding)"); - break; - - default: - log_dhcp_client(client, "REQUEST (invalid)"); - break; - } - - return 0; -} - -static int client_start(sd_dhcp_client *client); - -static int client_timeout_resend( - sd_event_source *s, - uint64_t usec, - void *userdata) { - - sd_dhcp_client *client = userdata; - DHCP_CLIENT_DONT_DESTROY(client); - usec_t next_timeout; - uint64_t time_now; - int r; - - assert(s); - assert(client); - assert(client->event); - - r = sd_event_now(client->event, CLOCK_BOOTTIME, &time_now); - if (r < 0) - goto error; - - switch (client->state) { - - case DHCP_STATE_RENEWING: - next_timeout = client_compute_reacquisition_timeout(time_now, client->t2_time); - break; - - case DHCP_STATE_REBINDING: - next_timeout = client_compute_reacquisition_timeout(time_now, client->expire_time); - break; - - case DHCP_STATE_REBOOTING: - /* start over as we did not receive a timely ack or nak */ - r = client_initialize(client); - if (r < 0) - goto error; - - r = client_start(client); - if (r < 0) - goto error; - - log_dhcp_client(client, "REBOOTED"); - return 0; - - case DHCP_STATE_INIT: - case DHCP_STATE_INIT_REBOOT: - case DHCP_STATE_SELECTING: - case DHCP_STATE_REQUESTING: - case DHCP_STATE_BOUND: - if (client->attempt >= client->max_attempts) - goto error; - - client->attempt++; - next_timeout = client_compute_request_timeout(time_now, client->attempt); - break; - - case DHCP_STATE_STOPPED: - r = -EINVAL; - goto error; - - default: - assert_not_reached(); - } - - r = event_reset_time(client->event, &client->timeout_resend, - CLOCK_BOOTTIME, - next_timeout, 10 * USEC_PER_MSEC, - client_timeout_resend, client, - client->event_priority, "dhcp4-resend-timer", true); - if (r < 0) - goto error; - - switch (client->state) { - case DHCP_STATE_INIT: - r = client_send_discover(client); - if (r >= 0) { - client->state = DHCP_STATE_SELECTING; - client->attempt = 0; - } else if (client->attempt >= client->max_attempts) - goto error; - - break; - - case DHCP_STATE_SELECTING: - r = client_send_discover(client); - if (r < 0 && client->attempt >= client->max_attempts) - goto error; - - break; - - case DHCP_STATE_INIT_REBOOT: - case DHCP_STATE_REQUESTING: - case DHCP_STATE_RENEWING: - case DHCP_STATE_REBINDING: - r = client_send_request(client); - if (r < 0 && client->attempt >= client->max_attempts) - goto error; - - if (client->state == DHCP_STATE_INIT_REBOOT) - client->state = DHCP_STATE_REBOOTING; - - client->request_sent = time_now; - break; - - case DHCP_STATE_REBOOTING: - case DHCP_STATE_BOUND: - break; - - case DHCP_STATE_STOPPED: - r = -EINVAL; - goto error; - } - - if (client->attempt >= TRANSIENT_FAILURE_ATTEMPTS) - client_notify(client, SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE); - - return 0; - -error: - client_stop(client, r); - - /* Errors were dealt with when stopping the client, don't spill - errors into the event loop handler */ - return 0; -} - -static int client_initialize_io_events( - sd_dhcp_client *client, - sd_event_io_handler_t io_callback) { - - int r; - - assert(client); - assert(client->event); - - r = sd_event_add_io(client->event, &client->receive_message, - client->fd, EPOLLIN, io_callback, - client); - if (r < 0) - goto error; - - r = sd_event_source_set_priority(client->receive_message, - client->event_priority); - if (r < 0) - goto error; - - r = sd_event_source_set_description(client->receive_message, "dhcp4-receive-message"); - if (r < 0) - goto error; - -error: - if (r < 0) - client_stop(client, r); - - return 0; -} - -static int client_initialize_time_events(sd_dhcp_client *client) { - uint64_t usec = 0; - int r; - - assert(client); - assert(client->event); - - if (client->start_delay > 0) { - assert_se(sd_event_now(client->event, CLOCK_BOOTTIME, &usec) >= 0); - usec += client->start_delay; - } - - r = event_reset_time(client->event, &client->timeout_resend, - CLOCK_BOOTTIME, - usec, 0, - client_timeout_resend, client, - client->event_priority, "dhcp4-resend-timer", true); - if (r < 0) - client_stop(client, r); - - return 0; - -} - -static int client_initialize_events(sd_dhcp_client *client, sd_event_io_handler_t io_callback) { - client_initialize_io_events(client, io_callback); - client_initialize_time_events(client); - - return 0; -} - -static int client_start_delayed(sd_dhcp_client *client) { - int r; - - assert_return(client, -EINVAL); - assert_return(client->event, -EINVAL); - assert_return(client->ifindex > 0, -EINVAL); - assert_return(client->fd < 0, -EBUSY); - assert_return(client->xid == 0, -EINVAL); - assert_return(IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT), -EBUSY); - - client->xid = random_u32(); - - r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, - client->mac_addr, client->mac_addr_len, - client->bcast_addr, client->bcast_addr_len, - client->arp_type, client->port); - if (r < 0) { - client_stop(client, r); - return r; - } - client->fd = r; - - if (IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_INIT_REBOOT)) - client->start_time = now(CLOCK_BOOTTIME); - - return client_initialize_events(client, client_receive_message_raw); -} - -static int client_start(sd_dhcp_client *client) { - client->start_delay = 0; - return client_start_delayed(client); -} - -static int client_timeout_expire(sd_event_source *s, uint64_t usec, void *userdata) { - sd_dhcp_client *client = userdata; - DHCP_CLIENT_DONT_DESTROY(client); - - log_dhcp_client(client, "EXPIRED"); - - client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED); - - /* lease was lost, start over if not freed or stopped in callback */ - if (client->state != DHCP_STATE_STOPPED) { - client_initialize(client); - client_start(client); - } - - return 0; -} - -static int client_timeout_t2(sd_event_source *s, uint64_t usec, void *userdata) { - sd_dhcp_client *client = userdata; - DHCP_CLIENT_DONT_DESTROY(client); - int r; - - assert(client); - - client->receive_message = sd_event_source_disable_unref(client->receive_message); - client->fd = safe_close(client->fd); - - client->state = DHCP_STATE_REBINDING; - client->attempt = 0; - - r = dhcp_network_bind_raw_socket(client->ifindex, &client->link, client->xid, - client->mac_addr, client->mac_addr_len, - client->bcast_addr, client->bcast_addr_len, - client->arp_type, client->port); - if (r < 0) { - client_stop(client, r); - return 0; - } - client->fd = r; - - return client_initialize_events(client, client_receive_message_raw); -} - -static int client_timeout_t1(sd_event_source *s, uint64_t usec, void *userdata) { - sd_dhcp_client *client = userdata; - DHCP_CLIENT_DONT_DESTROY(client); - - if (client->lease) - client->state = DHCP_STATE_RENEWING; - else if (client->state != DHCP_STATE_INIT) - client->state = DHCP_STATE_INIT_REBOOT; - client->attempt = 0; - - return client_initialize_time_events(client); -} - -static int client_handle_offer(sd_dhcp_client *client, DHCPMessage *offer, size_t len) { - _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; - int r; - - r = dhcp_lease_new(&lease); - if (r < 0) - return r; - - if (client->client_id_len) { - r = dhcp_lease_set_client_id(lease, - (uint8_t *) &client->client_id, - client->client_id_len); - if (r < 0) - return r; - } - - r = dhcp_option_parse(offer, len, dhcp_lease_parse_options, lease, NULL); - if (r != DHCP_OFFER) { - log_dhcp_client(client, "received message was not an OFFER, ignoring"); - return -ENOMSG; - } - - lease->next_server = offer->siaddr; - lease->address = offer->yiaddr; - - if (lease->lifetime == 0 && client->fallback_lease_lifetime > 0) - lease->lifetime = client->fallback_lease_lifetime; - - if (lease->address == 0 || - lease->server_address == 0 || - lease->lifetime == 0) { - log_dhcp_client(client, "received lease lacks address, server address or lease lifetime, ignoring"); - return -ENOMSG; - } - - if (!lease->have_subnet_mask) { - r = dhcp_lease_set_default_subnet_mask(lease); - if (r < 0) { - log_dhcp_client(client, - "received lease lacks subnet mask, " - "and a fallback one cannot be generated, ignoring"); - return -ENOMSG; - } - } - - sd_dhcp_lease_unref(client->lease); - client->lease = TAKE_PTR(lease); - - if (client_notify(client, SD_DHCP_CLIENT_EVENT_SELECTING) < 0) - return -ENOMSG; - - log_dhcp_client(client, "OFFER"); - - return 0; -} - -static int client_handle_forcerenew(sd_dhcp_client *client, DHCPMessage *force, size_t len) { - int r; - - r = dhcp_option_parse(force, len, NULL, NULL, NULL); - if (r != DHCP_FORCERENEW) - return -ENOMSG; - -#if 0 - log_dhcp_client(client, "FORCERENEW"); - - return 0; -#else - /* FIXME: Ignore FORCERENEW requests until we implement RFC3118 (Authentication for DHCP - * Messages) and/or RFC6704 (Forcerenew Nonce Authentication), as unauthenticated FORCERENEW - * requests causes a security issue (TALOS-2020-1142, CVE-2020-13529). */ - log_dhcp_client(client, "Received FORCERENEW, ignoring."); - return -ENOMSG; -#endif -} - -static bool lease_equal(const sd_dhcp_lease *a, const sd_dhcp_lease *b) { - if (a->address != b->address) - return false; - - if (a->subnet_mask != b->subnet_mask) - return false; - - if (a->router_size != b->router_size) - return false; - - for (size_t i = 0; i < a->router_size; i++) - if (a->router[i].s_addr != b->router[i].s_addr) - return false; - - return true; -} - -static int client_handle_ack(sd_dhcp_client *client, DHCPMessage *ack, size_t len) { - _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; - _cleanup_free_ char *error_message = NULL; - int r; - - r = dhcp_lease_new(&lease); - if (r < 0) - return r; - - if (client->client_id_len) { - r = dhcp_lease_set_client_id(lease, - (uint8_t *) &client->client_id, - client->client_id_len); - if (r < 0) - return r; - } - - r = dhcp_option_parse(ack, len, dhcp_lease_parse_options, lease, &error_message); - if (r == DHCP_NAK) { - log_dhcp_client(client, "NAK: %s", strna(error_message)); - return -EADDRNOTAVAIL; - } - - if (r != DHCP_ACK) { - log_dhcp_client(client, "received message was not an ACK, ignoring"); - return -ENOMSG; - } - - lease->next_server = ack->siaddr; - - lease->address = ack->yiaddr; - - if (lease->address == INADDR_ANY || - lease->server_address == INADDR_ANY || - lease->lifetime == 0) { - log_dhcp_client(client, "received lease lacks address, server " - "address or lease lifetime, ignoring"); - return -ENOMSG; - } - - if (lease->subnet_mask == INADDR_ANY) { - r = dhcp_lease_set_default_subnet_mask(lease); - if (r < 0) { - log_dhcp_client(client, - "received lease lacks subnet mask, " - "and a fallback one cannot be generated, ignoring"); - return -ENOMSG; - } - } - - r = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE; - if (client->lease) { - if (lease_equal(client->lease, lease)) - r = SD_DHCP_CLIENT_EVENT_RENEW; - else - r = SD_DHCP_CLIENT_EVENT_IP_CHANGE; - - client->lease = sd_dhcp_lease_unref(client->lease); - } - - client->lease = TAKE_PTR(lease); - - log_dhcp_client(client, "ACK"); - - return r; -} - -static int client_set_lease_timeouts(sd_dhcp_client *client) { - usec_t time_now; - int r; - - assert(client); - assert(client->event); - assert(client->lease); - assert(client->lease->lifetime); - - /* don't set timers for infinite leases */ - if (client->lease->lifetime == 0xffffffff) { - (void) event_source_disable(client->timeout_t1); - (void) event_source_disable(client->timeout_t2); - (void) event_source_disable(client->timeout_expire); - - return 0; - } - - r = sd_event_now(client->event, CLOCK_BOOTTIME, &time_now); - if (r < 0) - return r; - assert(client->request_sent <= time_now); - - /* verify that 0 < t2 < lifetime */ - if (client->lease->t2 == 0 || client->lease->t2 >= client->lease->lifetime) - client->lease->t2 = T2_DEFAULT(client->lease->lifetime); - /* verify that 0 < t1 < lifetime */ - if (client->lease->t1 == 0 || client->lease->t1 >= client->lease->t2) - client->lease->t1 = T1_DEFAULT(client->lease->lifetime); - /* now, if t1 >= t2, t1 *must* be T1_DEFAULT, since the previous check - * could not evalate to false if t1 >= t2; so setting t2 to T2_DEFAULT - * guarantees t1 < t2. */ - if (client->lease->t1 >= client->lease->t2) - client->lease->t2 = T2_DEFAULT(client->lease->lifetime); - - client->expire_time = client->request_sent + client->lease->lifetime * USEC_PER_SEC; - client->t1_time = client->request_sent + client->lease->t1 * USEC_PER_SEC; - client->t2_time = client->request_sent + client->lease->t2 * USEC_PER_SEC; - - /* RFC2131 section 4.4.5: - * Times T1 and T2 SHOULD be chosen with some random "fuzz". - * Since the RFC doesn't specify here the exact 'fuzz' to use, - * we use the range from section 4.1: -1 to +1 sec. */ - client->t1_time = usec_sub_signed(client->t1_time, RFC2131_RANDOM_FUZZ); - client->t2_time = usec_sub_signed(client->t2_time, RFC2131_RANDOM_FUZZ); - - /* after fuzzing, ensure t2 is still >= t1 */ - client->t2_time = MAX(client->t1_time, client->t2_time); - - /* arm lifetime timeout */ - r = event_reset_time(client->event, &client->timeout_expire, - CLOCK_BOOTTIME, - client->expire_time, 10 * USEC_PER_MSEC, - client_timeout_expire, client, - client->event_priority, "dhcp4-lifetime", true); - if (r < 0) - return r; - - /* don't arm earlier timeouts if this has already expired */ - if (client->expire_time <= time_now) - return 0; - - log_dhcp_client(client, "lease expires in %s", - FORMAT_TIMESPAN(client->expire_time - time_now, USEC_PER_SEC)); - - /* arm T2 timeout */ - r = event_reset_time(client->event, &client->timeout_t2, - CLOCK_BOOTTIME, - client->t2_time, 10 * USEC_PER_MSEC, - client_timeout_t2, client, - client->event_priority, "dhcp4-t2-timeout", true); - if (r < 0) - return r; - - /* don't arm earlier timeout if this has already expired */ - if (client->t2_time <= time_now) - return 0; - - log_dhcp_client(client, "T2 expires in %s", - FORMAT_TIMESPAN(client->t2_time - time_now, USEC_PER_SEC)); - - /* arm T1 timeout */ - r = event_reset_time(client->event, &client->timeout_t1, - CLOCK_BOOTTIME, - client->t1_time, 10 * USEC_PER_MSEC, - client_timeout_t1, client, - client->event_priority, "dhcp4-t1-timer", true); - if (r < 0) - return r; - - if (client->t1_time > time_now) - log_dhcp_client(client, "T1 expires in %s", - FORMAT_TIMESPAN(client->t1_time - time_now, USEC_PER_SEC)); - - return 0; -} - -static int client_handle_message(sd_dhcp_client *client, DHCPMessage *message, int len) { - DHCP_CLIENT_DONT_DESTROY(client); - int r, notify_event; - - assert(client); - assert(client->event); - assert(message); - - switch (client->state) { - case DHCP_STATE_SELECTING: - - r = client_handle_offer(client, message, len); - if (r == -ENOMSG) - return 0; /* invalid message, let's ignore it */ - if (r < 0) - goto error; - - client->state = DHCP_STATE_REQUESTING; - client->attempt = 0; - - r = event_reset_time(client->event, &client->timeout_resend, - CLOCK_BOOTTIME, - 0, 0, - client_timeout_resend, client, - client->event_priority, "dhcp4-resend-timer", true); - break; - - case DHCP_STATE_REBOOTING: - case DHCP_STATE_REQUESTING: - case DHCP_STATE_RENEWING: - case DHCP_STATE_REBINDING: - - r = client_handle_ack(client, message, len); - if (r == -ENOMSG) - return 0; /* invalid message, let's ignore it */ - if (r == -EADDRNOTAVAIL) { - /* got a NAK, let's restart the client */ - client_notify(client, SD_DHCP_CLIENT_EVENT_EXPIRED); - - r = client_initialize(client); - if (r < 0) - goto error; - - r = client_start_delayed(client); - if (r < 0) - goto error; - - log_dhcp_client(client, "REBOOT in %s", FORMAT_TIMESPAN(client->start_delay, USEC_PER_SEC)); - - client->start_delay = CLAMP(client->start_delay * 2, - RESTART_AFTER_NAK_MIN_USEC, RESTART_AFTER_NAK_MAX_USEC); - return 0; - } - if (r < 0) - goto error; - - if (IN_SET(client->state, DHCP_STATE_REQUESTING, DHCP_STATE_REBOOTING)) - notify_event = SD_DHCP_CLIENT_EVENT_IP_ACQUIRE; - else - notify_event = r; - - client->start_delay = 0; - (void) event_source_disable(client->timeout_resend); - client->receive_message = sd_event_source_disable_unref(client->receive_message); - client->fd = safe_close(client->fd); - - client->state = DHCP_STATE_BOUND; - client->attempt = 0; - - client->last_addr = client->lease->address; - - r = client_set_lease_timeouts(client); - if (r < 0) { - log_dhcp_client(client, "could not set lease timeouts"); - goto error; - } - - r = dhcp_network_bind_udp_socket(client->ifindex, client->lease->address, client->port, client->ip_service_type); - if (r < 0) { - log_dhcp_client(client, "could not bind UDP socket"); - goto error; - } - - client->fd = r; - - client_initialize_io_events(client, client_receive_message_udp); - - if (IN_SET(client->state, DHCP_STATE_RENEWING, DHCP_STATE_REBINDING) && - notify_event == SD_DHCP_CLIENT_EVENT_IP_ACQUIRE) - /* FIXME: hmm, maybe this is a bug... */ - log_dhcp_client(client, "client_handle_ack() returned SD_DHCP_CLIENT_EVENT_IP_ACQUIRE while DHCP client is %s the address, skipping callback.", - client->state == DHCP_STATE_RENEWING ? "renewing" : "rebinding"); - else - client_notify(client, notify_event); - break; - - case DHCP_STATE_BOUND: - r = client_handle_forcerenew(client, message, len); - if (r == -ENOMSG) - return 0; /* invalid message, let's ignore it */ - if (r < 0) - goto error; - - r = client_timeout_t1(NULL, 0, client); - break; - - case DHCP_STATE_INIT: - case DHCP_STATE_INIT_REBOOT: - r = 0; - break; - - case DHCP_STATE_STOPPED: - r = -EINVAL; - goto error; - default: - assert_not_reached(); - } - -error: - if (r < 0) - client_stop(client, r); - - return r; -} - -static int client_receive_message_udp( - sd_event_source *s, - int fd, - uint32_t revents, - void *userdata) { - - sd_dhcp_client *client = userdata; - _cleanup_free_ DHCPMessage *message = NULL; - const uint8_t *expected_chaddr = NULL; - uint8_t expected_hlen = 0; - ssize_t len, buflen; - - assert(s); - assert(client); - - buflen = next_datagram_size_fd(fd); - if (buflen < 0) { - if (ERRNO_IS_TRANSIENT(buflen) || ERRNO_IS_DISCONNECT(buflen)) - return 0; - - log_dhcp_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m"); - return 0; - } - - message = malloc0(buflen); - if (!message) - return -ENOMEM; - - len = recv(fd, message, buflen, 0); - if (len < 0) { - if (ERRNO_IS_TRANSIENT(errno) || ERRNO_IS_DISCONNECT(errno)) - return 0; - - log_dhcp_client_errno(client, errno, "Could not receive message from UDP socket, ignoring: %m"); - return 0; - } - if ((size_t) len < sizeof(DHCPMessage)) { - log_dhcp_client(client, "Too small to be a DHCP message: ignoring"); - return 0; - } - - if (be32toh(message->magic) != DHCP_MAGIC_COOKIE) { - log_dhcp_client(client, "Not a DHCP message: ignoring"); - return 0; - } - - if (message->op != BOOTREPLY) { - log_dhcp_client(client, "Not a BOOTREPLY message: ignoring"); - return 0; - } - - if (message->htype != client->arp_type) { - log_dhcp_client(client, "Packet type does not match client type"); - return 0; - } - - if (client->arp_type == ARPHRD_ETHER) { - expected_hlen = ETH_ALEN; - expected_chaddr = &client->mac_addr[0]; - } - - if (message->hlen != expected_hlen) { - log_dhcp_client(client, "Unexpected packet hlen %d", message->hlen); - return 0; - } - - if (expected_hlen > 0 && memcmp(&message->chaddr[0], expected_chaddr, expected_hlen)) { - log_dhcp_client(client, "Received chaddr does not match expected: ignoring"); - return 0; - } - - if (client->state != DHCP_STATE_BOUND && - be32toh(message->xid) != client->xid) { - /* in BOUND state, we may receive FORCERENEW with xid set by server, - so ignore the xid in this case */ - log_dhcp_client(client, "Received xid (%u) does not match expected (%u): ignoring", - be32toh(message->xid), client->xid); - return 0; - } - - log_dhcp_client(client, "Received message from UDP socket, processing."); - (void) client_handle_message(client, message, len); - return 0; -} - -static int client_receive_message_raw( - sd_event_source *s, - int fd, - uint32_t revents, - void *userdata) { - - sd_dhcp_client *client = userdata; - _cleanup_free_ DHCPPacket *packet = NULL; - CMSG_BUFFER_TYPE(CMSG_SPACE(sizeof(struct tpacket_auxdata))) control; - struct iovec iov = {}; - struct msghdr msg = { - .msg_iov = &iov, - .msg_iovlen = 1, - .msg_control = &control, - .msg_controllen = sizeof(control), - }; - struct cmsghdr *cmsg; - bool checksum = true; - ssize_t buflen, len; - int r; - - assert(s); - assert(client); - - buflen = next_datagram_size_fd(fd); - if (buflen < 0) { - if (ERRNO_IS_TRANSIENT(buflen) || ERRNO_IS_DISCONNECT(buflen)) - return 0; - - log_dhcp_client_errno(client, buflen, "Failed to determine datagram size to read, ignoring: %m"); - return 0; - } - - packet = malloc0(buflen); - if (!packet) - return -ENOMEM; - - iov = IOVEC_MAKE(packet, buflen); - - len = recvmsg_safe(fd, &msg, 0); - if (len < 0) { - if (ERRNO_IS_TRANSIENT(len) || ERRNO_IS_DISCONNECT(len)) - return 0; - - log_dhcp_client_errno(client, len, "Could not receive message from raw socket, ignoring: %m"); - return 0; - } - if ((size_t) len < sizeof(DHCPPacket)) - return 0; - - cmsg = cmsg_find(&msg, SOL_PACKET, PACKET_AUXDATA, CMSG_LEN(sizeof(struct tpacket_auxdata))); - if (cmsg) { - struct tpacket_auxdata *aux = (struct tpacket_auxdata*) CMSG_DATA(cmsg); - checksum = !(aux->tp_status & TP_STATUS_CSUMNOTREADY); - } - - r = dhcp_packet_verify_headers(packet, len, checksum, client->port); - if (r < 0) - return 0; - - len -= DHCP_IP_UDP_SIZE; - - log_dhcp_client(client, "Received message from RAW socket, processing."); - (void) client_handle_message(client, &packet->dhcp, len); - return 0; -} - -int sd_dhcp_client_send_renew(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - assert_return(client->fd >= 0, -EINVAL); - - if (!client->lease) - return 0; - - client->start_delay = 0; - client->attempt = 1; - client->state = DHCP_STATE_RENEWING; - - return client_initialize_time_events(client); -} - -int sd_dhcp_client_is_running(sd_dhcp_client *client) { - if (!client) - return 0; - - return !IN_SET(client->state, DHCP_STATE_INIT, DHCP_STATE_STOPPED); -} - -int sd_dhcp_client_start(sd_dhcp_client *client) { - int r; - - assert_return(client, -EINVAL); - - r = client_initialize(client); - if (r < 0) - return r; - - /* RFC7844 section 3.3: - SHOULD perform a complete four-way handshake, starting with a - DHCPDISCOVER, to obtain a new address lease. If the client can - ascertain that this is exactly the same network to which it was - previously connected, and if the link-layer address did not change, - the client MAY issue a DHCPREQUEST to try to reclaim the current - address. */ - if (client->last_addr && !client->anonymize) - client->state = DHCP_STATE_INIT_REBOOT; - - r = client_start(client); - if (r >= 0) - log_dhcp_client(client, "STARTED on ifindex %i", client->ifindex); - - return r; -} - -int sd_dhcp_client_send_release(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE); - assert_return(client->lease, -EUNATCH); - - _cleanup_free_ DHCPPacket *release = NULL; - size_t optoffset, optlen; - int r; - - r = client_message_init(client, &release, DHCP_RELEASE, &optlen, &optoffset); - if (r < 0) - return r; - - /* Fill up release IP and MAC */ - release->dhcp.ciaddr = client->lease->address; - memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len); - - r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - r = dhcp_network_send_udp_socket(client->fd, - client->lease->server_address, - DHCP_PORT_SERVER, - &release->dhcp, - sizeof(DHCPMessage) + optoffset); - if (r < 0) - return r; - - log_dhcp_client(client, "RELEASE"); - - return 0; -} - -int sd_dhcp_client_send_decline(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - assert_return(client->state != DHCP_STATE_STOPPED, -ESTALE); - assert_return(client->lease, -EUNATCH); - - _cleanup_free_ DHCPPacket *release = NULL; - size_t optoffset, optlen; - int r; - - r = client_message_init(client, &release, DHCP_DECLINE, &optlen, &optoffset); - if (r < 0) - return r; - - release->dhcp.ciaddr = client->lease->address; - memcpy(&release->dhcp.chaddr, &client->mac_addr, client->mac_addr_len); - - r = dhcp_option_append(&release->dhcp, optlen, &optoffset, 0, - SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - r = dhcp_network_send_udp_socket(client->fd, - client->lease->server_address, - DHCP_PORT_SERVER, - &release->dhcp, - sizeof(DHCPMessage) + optoffset); - if (r < 0) - return r; - - log_dhcp_client(client, "DECLINE"); - - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - - if (client->state != DHCP_STATE_STOPPED) { - r = sd_dhcp_client_start(client); - if (r < 0) - return r; - } - - return 0; -} - -int sd_dhcp_client_stop(sd_dhcp_client *client) { - if (!client) - return 0; - - DHCP_CLIENT_DONT_DESTROY(client); - - client_stop(client, SD_DHCP_CLIENT_EVENT_STOP); - client->state = DHCP_STATE_STOPPED; - - return 0; -} - -int sd_dhcp_client_attach_event(sd_dhcp_client *client, sd_event *event, int64_t priority) { - int r; - - assert_return(client, -EINVAL); - assert_return(!client->event, -EBUSY); - - if (event) - client->event = sd_event_ref(event); - else { - r = sd_event_default(&client->event); - if (r < 0) - return 0; - } - - client->event_priority = priority; - - return 0; -} - -int sd_dhcp_client_detach_event(sd_dhcp_client *client) { - assert_return(client, -EINVAL); - - client->event = sd_event_unref(client->event); - - return 0; -} - -sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client) { - assert_return(client, NULL); - - return client->event; -} - -static sd_dhcp_client *dhcp_client_free(sd_dhcp_client *client) { - if (!client) - return NULL; - - log_dhcp_client(client, "FREE"); - - client_initialize(client); - - client->timeout_resend = sd_event_source_unref(client->timeout_resend); - client->timeout_t1 = sd_event_source_unref(client->timeout_t1); - client->timeout_t2 = sd_event_source_unref(client->timeout_t2); - client->timeout_expire = sd_event_source_unref(client->timeout_expire); - - sd_dhcp_client_detach_event(client); - - set_free(client->req_opts); - free(client->hostname); - free(client->vendor_class_identifier); - free(client->mudurl); - client->user_class = strv_free(client->user_class); - ordered_hashmap_free(client->extra_options); - ordered_hashmap_free(client->vendor_options); - free(client->ifname); - return mfree(client); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_client, sd_dhcp_client, dhcp_client_free); - -int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize) { - const uint8_t *opts; - size_t n_opts; - int r; - - assert_return(ret, -EINVAL); - - _cleanup_(sd_dhcp_client_unrefp) sd_dhcp_client *client = new(sd_dhcp_client, 1); - if (!client) - return -ENOMEM; - - *client = (sd_dhcp_client) { - .n_ref = 1, - .state = DHCP_STATE_INIT, - .ifindex = -1, - .fd = -1, - .mtu = DHCP_DEFAULT_MIN_SIZE, - .port = DHCP_PORT_CLIENT, - .anonymize = !!anonymize, - .max_attempts = UINT64_MAX, - .ip_service_type = -1, - }; - /* NOTE: this could be moved to a function. */ - if (anonymize) { - n_opts = ELEMENTSOF(default_req_opts_anonymize); - opts = default_req_opts_anonymize; - } else { - n_opts = ELEMENTSOF(default_req_opts); - opts = default_req_opts; - } - - for (size_t i = 0; i < n_opts; i++) { - r = sd_dhcp_client_set_request_option(client, opts[i]); - if (r < 0) - return r; - } - - *ret = TAKE_PTR(client); - - return 0; -} diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c deleted file mode 100644 index 5f83fa66ae..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c +++ /dev/null @@ -1,1508 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright Ā© 2013 Intel Corporation. All rights reserved. -***/ - -#include "nm-sd-adapt-core.h" - -#include <arpa/inet.h> -#include <errno.h> -#include <stdlib.h> -#include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h> - -#include "sd-dhcp-lease.h" - -#include "alloc-util.h" -#include "dhcp-lease-internal.h" -#include "dhcp-protocol.h" -#include "dns-domain.h" -#include "env-file.h" -#include "fd-util.h" -#include "fileio.h" -#include "fs-util.h" -#include "hexdecoct.h" -#include "hostname-util.h" -#include "in-addr-util.h" -#include "network-internal.h" -#include "parse-util.h" -#include "stdio-util.h" -#include "string-util.h" -#include "strv.h" -#include "tmpfile-util.h" -#include "unaligned.h" - -int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->address == 0) - return -ENODATA; - - addr->s_addr = lease->address; - return 0; -} - -int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (!lease->have_broadcast) - return -ENODATA; - - addr->s_addr = lease->broadcast; - return 0; -} - -int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) { - assert_return(lease, -EINVAL); - assert_return(lifetime, -EINVAL); - - if (lease->lifetime <= 0) - return -ENODATA; - - *lifetime = lease->lifetime; - return 0; -} - -int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) { - assert_return(lease, -EINVAL); - assert_return(t1, -EINVAL); - - if (lease->t1 <= 0) - return -ENODATA; - - *t1 = lease->t1; - return 0; -} - -int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) { - assert_return(lease, -EINVAL); - assert_return(t2, -EINVAL); - - if (lease->t2 <= 0) - return -ENODATA; - - *t2 = lease->t2; - return 0; -} - -int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) { - assert_return(lease, -EINVAL); - assert_return(mtu, -EINVAL); - - if (lease->mtu <= 0) - return -ENODATA; - - *mtu = lease->mtu; - return 0; -} - -int sd_dhcp_lease_get_servers( - sd_dhcp_lease *lease, - sd_dhcp_lease_server_type_t what, - const struct in_addr **addr) { - - assert_return(lease, -EINVAL); - assert_return(what >= 0, -EINVAL); - assert_return(what < _SD_DHCP_LEASE_SERVER_TYPE_MAX, -EINVAL); - - if (lease->servers[what].size <= 0) - return -ENODATA; - - if (addr) - *addr = lease->servers[what].addr; - - return (int) lease->servers[what].size; -} - -int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_DNS, addr); -} -int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_NTP, addr); -} -int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SIP, addr); -} -int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_POP3, addr); -} -int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SMTP, addr); -} -int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_LPR, addr); -} - -int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) { - assert_return(lease, -EINVAL); - assert_return(domainname, -EINVAL); - - if (!lease->domainname) - return -ENODATA; - - *domainname = lease->domainname; - return 0; -} - -int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) { - assert_return(lease, -EINVAL); - assert_return(hostname, -EINVAL); - - if (!lease->hostname) - return -ENODATA; - - *hostname = lease->hostname; - return 0; -} - -int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) { - assert_return(lease, -EINVAL); - assert_return(root_path, -EINVAL); - - if (!lease->root_path) - return -ENODATA; - - *root_path = lease->root_path; - return 0; -} - -int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->router_size <= 0) - return -ENODATA; - - *addr = lease->router; - return (int) lease->router_size; -} - -int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (!lease->have_subnet_mask) - return -ENODATA; - - addr->s_addr = lease->subnet_mask; - return 0; -} - -int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->server_address == 0) - return -ENODATA; - - addr->s_addr = lease->server_address; - return 0; -} - -int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->next_server == 0) - return -ENODATA; - - addr->s_addr = lease->next_server; - return 0; -} - -/* - * The returned routes array must be freed by the caller. - * Route objects have the same lifetime of the lease and must not be freed. - */ -static int dhcp_lease_get_routes(sd_dhcp_route *routes, size_t n_routes, sd_dhcp_route ***ret) { - assert(routes || n_routes == 0); - - if (n_routes <= 0) - return -ENODATA; - - if (ret) { - sd_dhcp_route **buf; - - buf = new(sd_dhcp_route*, n_routes); - if (!buf) - return -ENOMEM; - - for (size_t i = 0; i < n_routes; i++) - buf[i] = &routes[i]; - - *ret = buf; - } - - return (int) n_routes; -} - -int sd_dhcp_lease_get_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret) { - assert_return(lease, -EINVAL); - - return dhcp_lease_get_routes(lease->static_routes, lease->n_static_routes, ret); -} - -int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret) { - assert_return(lease, -EINVAL); - - return dhcp_lease_get_routes(lease->classless_routes, lease->n_classless_routes, ret); -} - -int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) { - size_t r; - - assert_return(lease, -EINVAL); - assert_return(domains, -EINVAL); - - r = strv_length(lease->search_domains); - if (r > 0) { - *domains = lease->search_domains; - return (int) r; - } - - return -ENODATA; -} - -int sd_dhcp_lease_get_6rd( - sd_dhcp_lease *lease, - uint8_t *ret_ipv4masklen, - uint8_t *ret_prefixlen, - struct in6_addr *ret_prefix, - const struct in_addr **ret_br_addresses, - size_t *ret_n_br_addresses) { - - assert_return(lease, -EINVAL); - - if (lease->sixrd_n_br_addresses <= 0) - return -ENODATA; - - if (ret_ipv4masklen) - *ret_ipv4masklen = lease->sixrd_ipv4masklen; - if (ret_prefixlen) - *ret_prefixlen = lease->sixrd_prefixlen; - if (ret_prefix) - *ret_prefix = lease->sixrd_prefix; - if (ret_br_addresses) - *ret_br_addresses = lease->sixrd_br_addresses; - if (ret_n_br_addresses) - *ret_n_br_addresses = lease->sixrd_n_br_addresses; - - return 0; -} - -int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) { - assert_return(lease, -EINVAL); - assert_return(data, -EINVAL); - assert_return(data_len, -EINVAL); - - if (lease->vendor_specific_len <= 0) - return -ENODATA; - - *data = lease->vendor_specific; - *data_len = lease->vendor_specific_len; - return 0; -} - -static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { - assert(lease); - - while (lease->private_options) { - struct sd_dhcp_raw_option *option = lease->private_options; - - LIST_REMOVE(options, lease->private_options, option); - - free(option->data); - free(option); - } - - free(lease->root_path); - free(lease->router); - free(lease->timezone); - free(lease->hostname); - free(lease->domainname); - - for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++) - free(lease->servers[i].addr); - - free(lease->static_routes); - free(lease->classless_routes); - free(lease->client_id); - free(lease->vendor_specific); - strv_free(lease->search_domains); - free(lease->sixrd_br_addresses); - return mfree(lease); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_lease, sd_dhcp_lease, dhcp_lease_free); - -static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { - assert(option); - assert(ret); - - if (len != 4) - return -EINVAL; - - *ret = unaligned_read_be32((be32_t*) option); - if (*ret < min) - *ret = min; - - return 0; -} - -static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) { - assert(option); - assert(ret); - - if (len != 2) - return -EINVAL; - - *ret = unaligned_read_be16((be16_t*) option); - if (*ret < min) - *ret = min; - - return 0; -} - -static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) { - assert(option); - assert(ret); - - if (len != 4) - return -EINVAL; - - memcpy(ret, option, 4); - return 0; -} - -static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { - assert(option); - assert(ret); - - if (len <= 0) - *ret = mfree(*ret); - else { - char *string; - - /* - * One trailing NUL byte is OK, we don't mind. See: - * https://github.com/systemd/systemd/issues/1337 - */ - if (memchr(option, 0, len - 1)) - return -EINVAL; - - string = memdup_suffix0((const char *) option, len); - if (!string) - return -ENOMEM; - - free_and_replace(*ret, string); - } - - return 0; -} - -static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) { - _cleanup_free_ char *name = NULL, *normalized = NULL; - int r; - - assert(option); - assert(ret); - - r = lease_parse_string(option, len, &name); - if (r < 0) - return r; - if (!name) { - *ret = mfree(*ret); - return 0; - } - - r = dns_name_normalize(name, 0, &normalized); - if (r < 0) - return r; - - if (is_localhost(normalized)) - return -EINVAL; - - if (dns_name_is_root(normalized)) - return -EINVAL; - - free_and_replace(*ret, normalized); - - return 0; -} - -static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { - assert(option || len == 0); - assert(ret); - assert(n_ret); - - if (len <= 0) { - *ret = mfree(*ret); - *n_ret = 0; - } else { - size_t n_addresses; - struct in_addr *addresses; - - if (len % 4 != 0) - return -EINVAL; - - n_addresses = len / 4; - - addresses = newdup(struct in_addr, option, n_addresses); - if (!addresses) - return -ENOMEM; - - free(*ret); - *ret = addresses; - *n_ret = n_addresses; - } - - return 0; -} - -static int lease_parse_sip_server(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { - assert(option || len == 0); - assert(ret); - assert(n_ret); - - if (len <= 0) - return -EINVAL; - - /* The SIP record is like the other, regular server records, but prefixed with a single "encoding" - * byte that is either 0 or 1. We only support it to be 1 for now. Let's drop it and parse it like - * the other fields */ - - if (option[0] != 1) { /* We only support IP address encoding for now */ - *ret = mfree(*ret); - *n_ret = 0; - return 0; - } - - return lease_parse_in_addrs(option + 1, len - 1, ret, n_ret); -} - -static int lease_parse_static_routes(sd_dhcp_lease *lease, const uint8_t *option, size_t len) { - int r; - - assert(lease); - assert(option || len <= 0); - - if (len % 8 != 0) - return -EINVAL; - - while (len >= 8) { - struct in_addr dst, gw; - uint8_t prefixlen; - - assert_se(lease_parse_be32(option, 4, &dst.s_addr) >= 0); - option += 4; - - assert_se(lease_parse_be32(option, 4, &gw.s_addr) >= 0); - option += 4; - - len -= 8; - - r = in4_addr_default_prefixlen(&dst, &prefixlen); - if (r < 0) { - log_debug("sd-dhcp-lease: cannot determine class of received static route, ignoring."); - continue; - } - - (void) in4_addr_mask(&dst, prefixlen); - - if (!GREEDY_REALLOC(lease->static_routes, lease->n_static_routes + 1)) - return -ENOMEM; - - lease->static_routes[lease->n_static_routes++] = (struct sd_dhcp_route) { - .dst_addr = dst, - .gw_addr = gw, - .dst_prefixlen = prefixlen, - }; - } - - return 0; -} - -/* parses RFC3442 Classless Static Route Option */ -static int lease_parse_classless_routes(sd_dhcp_lease *lease, const uint8_t *option, size_t len) { - assert(lease); - assert(option || len <= 0); - - /* option format: (subnet-mask-width significant-subnet-octets gateway-ip) */ - - while (len > 0) { - uint8_t prefixlen, dst_octets; - struct in_addr dst = {}, gw; - - prefixlen = *option; - option++; - len--; - - dst_octets = DIV_ROUND_UP(prefixlen, 8); - - /* can't have more than 4 octets in IPv4 */ - if (dst_octets > 4 || len < dst_octets) - return -EINVAL; - - memcpy(&dst, option, dst_octets); - option += dst_octets; - len -= dst_octets; - - if (len < 4) - return -EINVAL; - - assert_se(lease_parse_be32(option, 4, &gw.s_addr) >= 0); - option += 4; - len -= 4; - - if (!GREEDY_REALLOC(lease->classless_routes, lease->n_classless_routes + 1)) - return -ENOMEM; - - lease->classless_routes[lease->n_classless_routes++] = (struct sd_dhcp_route) { - .dst_addr = dst, - .gw_addr = gw, - .dst_prefixlen = prefixlen, - }; - } - - return 0; -} - -static int lease_parse_6rd(sd_dhcp_lease *lease, const uint8_t *option, size_t len) { - uint8_t ipv4masklen, prefixlen; - struct in6_addr prefix; - _cleanup_free_ struct in_addr *br_addresses = NULL; - size_t n_br_addresses; - - assert(lease); - assert(option); - - /* See RFC 5969 Section 7.1.1 */ - - if (lease->sixrd_n_br_addresses > 0) - /* Multiple 6rd option?? */ - return -EINVAL; - - /* option-length: The length of the DHCP option in octets (22 octets with one BR IPv4 address). */ - if (len < 2 + sizeof(struct in6_addr) + sizeof(struct in_addr) || - (len - 2 - sizeof(struct in6_addr)) % sizeof(struct in_addr) != 0) - return -EINVAL; - - /* IPv4MaskLen: The number of high-order bits that are identical across all CE IPv4 addresses - * within a given 6rd domain. This may be any value between 0 and 32. Any value - * greater than 32 is invalid. */ - ipv4masklen = option[0]; - if (ipv4masklen > 32) - return -EINVAL; - - /* 6rdPrefixLen: The IPv6 prefix length of the SP's 6rd IPv6 prefix in number of bits. For the - * purpose of bounds checking by DHCP option processing, the sum of - * (32 - IPv4MaskLen) + 6rdPrefixLen MUST be less than or equal to 128. */ - prefixlen = option[1]; - if (32 - ipv4masklen + prefixlen > 128) - return -EINVAL; - - /* 6rdPrefix: The service provider's 6rd IPv6 prefix represented as a 16-octet IPv6 address. - * The bits in the prefix after the 6rdPrefixlen number of bits are reserved and - * MUST be initialized to zero by the sender and ignored by the receiver. */ - memcpy(&prefix, option + 2, sizeof(struct in6_addr)); - (void) in6_addr_mask(&prefix, prefixlen); - - /* 6rdBRIPv4Address: One or more IPv4 addresses of the 6rd Border Relay(s) for a given 6rd domain. */ - n_br_addresses = (len - 2 - sizeof(struct in6_addr)) / sizeof(struct in_addr); - br_addresses = newdup(struct in_addr, option + 2 + sizeof(struct in6_addr), n_br_addresses); - if (!br_addresses) - return -ENOMEM; - - lease->sixrd_ipv4masklen = ipv4masklen; - lease->sixrd_prefixlen = prefixlen; - lease->sixrd_prefix = prefix; - lease->sixrd_br_addresses = TAKE_PTR(br_addresses); - lease->sixrd_n_br_addresses = n_br_addresses; - - return 0; -} - -int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) { - sd_dhcp_lease *lease = userdata; - int r; - - assert(lease); - - switch (code) { - - case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME: - r = lease_parse_u32(option, len, &lease->lifetime, 1); - if (r < 0) - log_debug_errno(r, "Failed to parse lease time, ignoring: %m"); - - break; - - case SD_DHCP_OPTION_SERVER_IDENTIFIER: - r = lease_parse_be32(option, len, &lease->server_address); - if (r < 0) - log_debug_errno(r, "Failed to parse server identifier, ignoring: %m"); - - break; - - case SD_DHCP_OPTION_SUBNET_MASK: - r = lease_parse_be32(option, len, &lease->subnet_mask); - if (r < 0) - log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m"); - else - lease->have_subnet_mask = true; - break; - - case SD_DHCP_OPTION_BROADCAST: - r = lease_parse_be32(option, len, &lease->broadcast); - if (r < 0) - log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m"); - else - lease->have_broadcast = true; - break; - - case SD_DHCP_OPTION_ROUTER: - r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size); - if (r < 0) - log_debug_errno(r, "Failed to parse router addresses, ignoring: %m"); - break; - - case SD_DHCP_OPTION_DOMAIN_NAME_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_DNS].addr, &lease->servers[SD_DHCP_LEASE_DNS].size); - if (r < 0) - log_debug_errno(r, "Failed to parse DNS server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_NTP_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_NTP].addr, &lease->servers[SD_DHCP_LEASE_NTP].size); - if (r < 0) - log_debug_errno(r, "Failed to parse NTP server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_SIP_SERVER: - r = lease_parse_sip_server(option, len, &lease->servers[SD_DHCP_LEASE_SIP].addr, &lease->servers[SD_DHCP_LEASE_SIP].size); - if (r < 0) - log_debug_errno(r, "Failed to parse SIP server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_POP3_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_POP3].addr, &lease->servers[SD_DHCP_LEASE_POP3].size); - if (r < 0) - log_debug_errno(r, "Failed to parse POP3 server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_SMTP_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_SMTP].addr, &lease->servers[SD_DHCP_LEASE_SMTP].size); - if (r < 0) - log_debug_errno(r, "Failed to parse SMTP server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_LPR_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_LPR].addr, &lease->servers[SD_DHCP_LEASE_LPR].size); - if (r < 0) - log_debug_errno(r, "Failed to parse LPR server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_STATIC_ROUTE: - r = lease_parse_static_routes(lease, option, len); - if (r < 0) - log_debug_errno(r, "Failed to parse static routes, ignoring: %m"); - break; - - case SD_DHCP_OPTION_MTU_INTERFACE: - r = lease_parse_u16(option, len, &lease->mtu, 68); - if (r < 0) - log_debug_errno(r, "Failed to parse MTU, ignoring: %m"); - if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) { - log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE); - lease->mtu = DHCP_DEFAULT_MIN_SIZE; - } - - break; - - case SD_DHCP_OPTION_DOMAIN_NAME: - r = lease_parse_domain(option, len, &lease->domainname); - if (r < 0) { - log_debug_errno(r, "Failed to parse domain name, ignoring: %m"); - return 0; - } - - break; - - case SD_DHCP_OPTION_DOMAIN_SEARCH: - r = dhcp_lease_parse_search_domains(option, len, &lease->search_domains); - if (r < 0) - log_debug_errno(r, "Failed to parse Domain Search List, ignoring: %m"); - break; - - case SD_DHCP_OPTION_HOST_NAME: - r = lease_parse_domain(option, len, &lease->hostname); - if (r < 0) { - log_debug_errno(r, "Failed to parse hostname, ignoring: %m"); - return 0; - } - - break; - - case SD_DHCP_OPTION_ROOT_PATH: - r = lease_parse_string(option, len, &lease->root_path); - if (r < 0) - log_debug_errno(r, "Failed to parse root path, ignoring: %m"); - break; - - case SD_DHCP_OPTION_RENEWAL_TIME: - r = lease_parse_u32(option, len, &lease->t1, 1); - if (r < 0) - log_debug_errno(r, "Failed to parse T1 time, ignoring: %m"); - break; - - case SD_DHCP_OPTION_REBINDING_TIME: - r = lease_parse_u32(option, len, &lease->t2, 1); - if (r < 0) - log_debug_errno(r, "Failed to parse T2 time, ignoring: %m"); - break; - - case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE: - r = lease_parse_classless_routes(lease, option, len); - if (r < 0) - log_debug_errno(r, "Failed to parse classless routes, ignoring: %m"); - break; - - case SD_DHCP_OPTION_TZDB_TIMEZONE: { - _cleanup_free_ char *tz = NULL; - - r = lease_parse_string(option, len, &tz); - if (r < 0) { - log_debug_errno(r, "Failed to parse timezone option, ignoring: %m"); - return 0; - } - - if (!timezone_is_valid(tz, LOG_DEBUG)) { - log_debug("Timezone is not valid, ignoring."); - return 0; - } - - free_and_replace(lease->timezone, tz); - - break; - } - - case SD_DHCP_OPTION_VENDOR_SPECIFIC: - - if (len <= 0) - lease->vendor_specific = mfree(lease->vendor_specific); - else { - void *p; - - p = memdup(option, len); - if (!p) - return -ENOMEM; - - free(lease->vendor_specific); - lease->vendor_specific = p; - } - - lease->vendor_specific_len = len; - break; - - case SD_DHCP_OPTION_6RD: - r = lease_parse_6rd(lease, option, len); - if (r < 0) - log_debug_errno(r, "Failed to parse 6rd option, ignoring: %m"); - break; - - case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST: - r = dhcp_lease_insert_private_option(lease, code, option, len); - if (r < 0) - return r; - - break; - - default: - log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code); - break; - } - - return 0; -} - -/* Parses compressed domain names. */ -int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains) { - _cleanup_strv_free_ char **names = NULL; - size_t pos = 0, cnt = 0; - int r; - - assert(domains); - assert_return(option && len > 0, -ENODATA); - - while (pos < len) { - _cleanup_free_ char *name = NULL; - size_t n = 0; - size_t jump_barrier = pos, next_chunk = 0; - bool first = true; - - for (;;) { - uint8_t c; - c = option[pos++]; - - if (c == 0) { - /* End of name */ - break; - } else if (c <= 63) { - const char *label; - - /* Literal label */ - label = (const char*) (option + pos); - pos += c; - if (pos >= len) - return -EBADMSG; - - if (!GREEDY_REALLOC(name, n + !first + DNS_LABEL_ESCAPED_MAX)) - return -ENOMEM; - - if (first) - first = false; - else - name[n++] = '.'; - - r = dns_label_escape(label, c, name + n, DNS_LABEL_ESCAPED_MAX); - if (r < 0) - return r; - - n += r; - } else if (FLAGS_SET(c, 0xc0)) { - /* Pointer */ - - uint8_t d; - uint16_t ptr; - - if (pos >= len) - return -EBADMSG; - - d = option[pos++]; - ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d; - - /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */ - if (ptr >= jump_barrier) - return -EBADMSG; - jump_barrier = ptr; - - /* Save current location so we don't end up re-parsing what's parsed so far. */ - if (next_chunk == 0) - next_chunk = pos; - - pos = ptr; - } else - return -EBADMSG; - } - - if (!GREEDY_REALLOC(name, n + 1)) - return -ENOMEM; - name[n] = 0; - - r = strv_extend(&names, name); - if (r < 0) - return r; - - cnt++; - - if (next_chunk != 0) - pos = next_chunk; - } - - strv_free_and_replace(*domains, names); - - return cnt; -} - -int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) { - struct sd_dhcp_raw_option *option, *before = NULL; - - assert(lease); - - LIST_FOREACH(options, cur, lease->private_options) { - if (tag < cur->tag) { - before = cur; - break; - } - if (tag == cur->tag) { - log_debug("Ignoring duplicate option, tagged %i.", tag); - return 0; - } - } - - option = new(struct sd_dhcp_raw_option, 1); - if (!option) - return -ENOMEM; - - option->tag = tag; - option->length = len; - option->data = memdup(data, len); - if (!option->data) { - free(option); - return -ENOMEM; - } - - LIST_INSERT_BEFORE(options, lease->private_options, before, option); - return 0; -} - -int dhcp_lease_new(sd_dhcp_lease **ret) { - sd_dhcp_lease *lease; - - lease = new0(sd_dhcp_lease, 1); - if (!lease) - return -ENOMEM; - - lease->n_ref = 1; - - *ret = lease; - return 0; -} - -int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { - _cleanup_(unlink_and_freep) char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - struct in_addr address; - const struct in_addr *addresses; - const void *client_id, *data; - size_t client_id_len, data_len; - char sbuf[INET_ADDRSTRLEN]; - const char *string; - uint16_t mtu; - _cleanup_free_ sd_dhcp_route **routes = NULL; - char **search_domains; - uint32_t t1, t2, lifetime; - int r; - - assert(lease); - assert(lease_file); - - r = fopen_temporary(lease_file, &f, &temp_path); - if (r < 0) - return r; - - (void) fchmod(fileno(f), 0644); - - fprintf(f, - "# This is private data. Do not parse.\n"); - - r = sd_dhcp_lease_get_address(lease, &address); - if (r >= 0) - fprintf(f, "ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_netmask(lease, &address); - if (r >= 0) - fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_router(lease, &addresses); - if (r > 0) { - fputs("ROUTER=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_server_identifier(lease, &address); - if (r >= 0) - fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_next_server(lease, &address); - if (r >= 0) - fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_broadcast(lease, &address); - if (r >= 0) - fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_mtu(lease, &mtu); - if (r >= 0) - fprintf(f, "MTU=%" PRIu16 "\n", mtu); - - r = sd_dhcp_lease_get_t1(lease, &t1); - if (r >= 0) - fprintf(f, "T1=%" PRIu32 "\n", t1); - - r = sd_dhcp_lease_get_t2(lease, &t2); - if (r >= 0) - fprintf(f, "T2=%" PRIu32 "\n", t2); - - r = sd_dhcp_lease_get_lifetime(lease, &lifetime); - if (r >= 0) - fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime); - - r = sd_dhcp_lease_get_dns(lease, &addresses); - if (r > 0) { - fputs("DNS=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_ntp(lease, &addresses); - if (r > 0) { - fputs("NTP=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_sip(lease, &addresses); - if (r > 0) { - fputs("SIP=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_domainname(lease, &string); - if (r >= 0) - fprintf(f, "DOMAINNAME=%s\n", string); - - r = sd_dhcp_lease_get_search_domains(lease, &search_domains); - if (r > 0) { - fputs("DOMAIN_SEARCH_LIST=", f); - fputstrv(f, search_domains, NULL, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_hostname(lease, &string); - if (r >= 0) - fprintf(f, "HOSTNAME=%s\n", string); - - r = sd_dhcp_lease_get_root_path(lease, &string); - if (r >= 0) - fprintf(f, "ROOT_PATH=%s\n", string); - - r = sd_dhcp_lease_get_static_routes(lease, &routes); - if (r > 0) - serialize_dhcp_routes(f, "STATIC_ROUTES", routes, r); - - routes = mfree(routes); - r = sd_dhcp_lease_get_classless_routes(lease, &routes); - if (r > 0) - serialize_dhcp_routes(f, "CLASSLESS_ROUTES", routes, r); - - r = sd_dhcp_lease_get_timezone(lease, &string); - if (r >= 0) - fprintf(f, "TIMEZONE=%s\n", string); - - r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len); - if (r >= 0) { - _cleanup_free_ char *client_id_hex = NULL; - - client_id_hex = hexmem(client_id, client_id_len); - if (!client_id_hex) - return -ENOMEM; - fprintf(f, "CLIENTID=%s\n", client_id_hex); - } - - r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len); - if (r >= 0) { - _cleanup_free_ char *option_hex = NULL; - - option_hex = hexmem(data, data_len); - if (!option_hex) - return -ENOMEM; - fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex); - } - - LIST_FOREACH(options, option, lease->private_options) { - char key[STRLEN("OPTION_000")+1]; - - xsprintf(key, "OPTION_%" PRIu8, option->tag); - r = serialize_dhcp_option(f, key, option->data, option->length); - if (r < 0) - return r; - } - - r = fflush_and_check(f); - if (r < 0) - return r; - - r = conservative_rename(temp_path, lease_file); - if (r < 0) - return r; - - temp_path = mfree(temp_path); - - return 0; -} - -static char **private_options_free(char **options) { - if (!options) - return NULL; - - for (unsigned i = 0; i < SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1; i++) - free(options[i]); - - return mfree(options); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(char**, private_options_free); - -int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { - _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; - _cleanup_free_ char - *address = NULL, - *router = NULL, - *netmask = NULL, - *server_address = NULL, - *next_server = NULL, - *broadcast = NULL, - *dns = NULL, - *ntp = NULL, - *sip = NULL, - *pop3 = NULL, - *smtp = NULL, - *lpr = NULL, - *mtu = NULL, - *static_routes = NULL, - *classless_routes = NULL, - *domains = NULL, - *client_id_hex = NULL, - *vendor_specific_hex = NULL, - *lifetime = NULL, - *t1 = NULL, - *t2 = NULL; - _cleanup_(private_options_freep) char **options = NULL; - - int r, i; - - assert(lease_file); - assert(ret); - - r = dhcp_lease_new(&lease); - if (r < 0) - return r; - - options = new0(char*, SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1); - if (!options) - return -ENOMEM; - - r = parse_env_file(NULL, lease_file, - "ADDRESS", &address, - "ROUTER", &router, - "NETMASK", &netmask, - "SERVER_ADDRESS", &server_address, - "NEXT_SERVER", &next_server, - "BROADCAST", &broadcast, - "DNS", &dns, - "NTP", &ntp, - "SIP", &sip, - "POP3", &pop3, - "SMTP", &smtp, - "LPR", &lpr, - "MTU", &mtu, - "DOMAINNAME", &lease->domainname, - "HOSTNAME", &lease->hostname, - "DOMAIN_SEARCH_LIST", &domains, - "ROOT_PATH", &lease->root_path, - "STATIC_ROUTES", &static_routes, - "CLASSLESS_ROUTES", &classless_routes, - "CLIENTID", &client_id_hex, - "TIMEZONE", &lease->timezone, - "VENDOR_SPECIFIC", &vendor_specific_hex, - "LIFETIME", &lifetime, - "T1", &t1, - "T2", &t2, - "OPTION_224", &options[0], - "OPTION_225", &options[1], - "OPTION_226", &options[2], - "OPTION_227", &options[3], - "OPTION_228", &options[4], - "OPTION_229", &options[5], - "OPTION_230", &options[6], - "OPTION_231", &options[7], - "OPTION_232", &options[8], - "OPTION_233", &options[9], - "OPTION_234", &options[10], - "OPTION_235", &options[11], - "OPTION_236", &options[12], - "OPTION_237", &options[13], - "OPTION_238", &options[14], - "OPTION_239", &options[15], - "OPTION_240", &options[16], - "OPTION_241", &options[17], - "OPTION_242", &options[18], - "OPTION_243", &options[19], - "OPTION_244", &options[20], - "OPTION_245", &options[21], - "OPTION_246", &options[22], - "OPTION_247", &options[23], - "OPTION_248", &options[24], - "OPTION_249", &options[25], - "OPTION_250", &options[26], - "OPTION_251", &options[27], - "OPTION_252", &options[28], - "OPTION_253", &options[29], - "OPTION_254", &options[30]); - if (r < 0) - return r; - - if (address) { - r = inet_pton(AF_INET, address, &lease->address); - if (r <= 0) - log_debug("Failed to parse address %s, ignoring.", address); - } - - if (router) { - r = deserialize_in_addrs(&lease->router, router); - if (r < 0) - log_debug_errno(r, "Failed to deserialize router addresses %s, ignoring: %m", router); - else - lease->router_size = r; - } - - if (netmask) { - r = inet_pton(AF_INET, netmask, &lease->subnet_mask); - if (r <= 0) - log_debug("Failed to parse netmask %s, ignoring.", netmask); - else - lease->have_subnet_mask = true; - } - - if (server_address) { - r = inet_pton(AF_INET, server_address, &lease->server_address); - if (r <= 0) - log_debug("Failed to parse server address %s, ignoring.", server_address); - } - - if (next_server) { - r = inet_pton(AF_INET, next_server, &lease->next_server); - if (r <= 0) - log_debug("Failed to parse next server %s, ignoring.", next_server); - } - - if (broadcast) { - r = inet_pton(AF_INET, broadcast, &lease->broadcast); - if (r <= 0) - log_debug("Failed to parse broadcast address %s, ignoring.", broadcast); - else - lease->have_broadcast = true; - } - - if (dns) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_DNS].addr, dns); - if (r < 0) - log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns); - else - lease->servers[SD_DHCP_LEASE_DNS].size = r; - } - - if (ntp) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_NTP].addr, ntp); - if (r < 0) - log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp); - else - lease->servers[SD_DHCP_LEASE_NTP].size = r; - } - - if (sip) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_SIP].addr, sip); - if (r < 0) - log_debug_errno(r, "Failed to deserialize SIP servers %s, ignoring: %m", sip); - else - lease->servers[SD_DHCP_LEASE_SIP].size = r; - } - - if (pop3) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_POP3].addr, pop3); - if (r < 0) - log_debug_errno(r, "Failed to deserialize POP3 server %s, ignoring: %m", pop3); - else - lease->servers[SD_DHCP_LEASE_POP3].size = r; - } - - if (smtp) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_SMTP].addr, smtp); - if (r < 0) - log_debug_errno(r, "Failed to deserialize SMTP server %s, ignoring: %m", smtp); - else - lease->servers[SD_DHCP_LEASE_SMTP].size = r; - } - - if (lpr) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_LPR].addr, lpr); - if (r < 0) - log_debug_errno(r, "Failed to deserialize LPR server %s, ignoring: %m", lpr); - else - lease->servers[SD_DHCP_LEASE_LPR].size = r; - } - - if (mtu) { - r = safe_atou16(mtu, &lease->mtu); - if (r < 0) - log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu); - } - - if (domains) { - _cleanup_strv_free_ char **a = NULL; - a = strv_split(domains, " "); - if (!a) - return -ENOMEM; - - if (!strv_isempty(a)) - lease->search_domains = TAKE_PTR(a); - } - - if (static_routes) { - r = deserialize_dhcp_routes( - &lease->static_routes, - &lease->n_static_routes, - static_routes); - if (r < 0) - log_debug_errno(r, "Failed to parse DHCP static routes %s, ignoring: %m", static_routes); - } - - if (classless_routes) { - r = deserialize_dhcp_routes( - &lease->classless_routes, - &lease->n_classless_routes, - classless_routes); - if (r < 0) - log_debug_errno(r, "Failed to parse DHCP classless routes %s, ignoring: %m", classless_routes); - } - - if (lifetime) { - r = safe_atou32(lifetime, &lease->lifetime); - if (r < 0) - log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime); - } - - if (t1) { - r = safe_atou32(t1, &lease->t1); - if (r < 0) - log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1); - } - - if (t2) { - r = safe_atou32(t2, &lease->t2); - if (r < 0) - log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2); - } - - if (client_id_hex) { - r = unhexmem(client_id_hex, SIZE_MAX, &lease->client_id, &lease->client_id_len); - if (r < 0) - log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex); - } - - if (vendor_specific_hex) { - r = unhexmem(vendor_specific_hex, SIZE_MAX, &lease->vendor_specific, &lease->vendor_specific_len); - if (r < 0) - log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex); - } - - for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) { - _cleanup_free_ void *data = NULL; - size_t len; - - if (!options[i]) - continue; - - r = unhexmem(options[i], SIZE_MAX, &data, &len); - if (r < 0) { - log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]); - continue; - } - - r = dhcp_lease_insert_private_option(lease, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len); - if (r < 0) - return r; - } - - *ret = TAKE_PTR(lease); - - return 0; -} - -int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { - struct in_addr address, mask; - int r; - - assert(lease); - - if (lease->address == 0) - return -ENODATA; - - address.s_addr = lease->address; - - /* fall back to the default subnet masks based on address class */ - r = in4_addr_default_subnet_mask(&address, &mask); - if (r < 0) - return r; - - lease->subnet_mask = mask.s_addr; - lease->have_subnet_mask = true; - - return 0; -} - -int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) { - assert_return(lease, -EINVAL); - assert_return(client_id, -EINVAL); - assert_return(client_id_len, -EINVAL); - - if (!lease->client_id) - return -ENODATA; - - *client_id = lease->client_id; - *client_id_len = lease->client_id_len; - - return 0; -} - -int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) { - assert_return(lease, -EINVAL); - assert_return(client_id || client_id_len <= 0, -EINVAL); - - if (client_id_len <= 0) - lease->client_id = mfree(lease->client_id); - else { - void *p; - - p = memdup(client_id, client_id_len); - if (!p) - return -ENOMEM; - - free(lease->client_id); - lease->client_id = p; - lease->client_id_len = client_id_len; - } - - return 0; -} - -int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) { - assert_return(lease, -EINVAL); - assert_return(tz, -EINVAL); - - if (!lease->timezone) - return -ENODATA; - - *tz = lease->timezone; - return 0; -} - -int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) { - assert_return(route, -EINVAL); - assert_return(destination, -EINVAL); - - *destination = route->dst_addr; - return 0; -} - -int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) { - assert_return(route, -EINVAL); - assert_return(length, -EINVAL); - - *length = route->dst_prefixlen; - return 0; -} - -int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) { - assert_return(route, -EINVAL); - assert_return(gateway, -EINVAL); - - *gateway = route->gw_addr; - return 0; -} diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h deleted file mode 100644 index 834f80b421..0000000000 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h +++ /dev/null @@ -1,345 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcpclienthfoo -#define foosddhcpclienthfoo - -/*** - 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 <http://www.gnu.org/licenses/>. -***/ - -#include <inttypes.h> -#include <net/ethernet.h> -#include <netinet/in.h> -#include <sys/types.h> -#include <stdbool.h> - -#include "sd-dhcp-lease.h" -#include "sd-dhcp-option.h" -#include "sd-event.h" - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -enum { - SD_DHCP_CLIENT_EVENT_STOP = 0, - SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1, - SD_DHCP_CLIENT_EVENT_IP_CHANGE = 2, - SD_DHCP_CLIENT_EVENT_EXPIRED = 3, - SD_DHCP_CLIENT_EVENT_RENEW = 4, - SD_DHCP_CLIENT_EVENT_SELECTING = 5, - SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts. - * The client may want to start acquiring link-local addresses. */ -}; - -/* https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options */ -enum { - SD_DHCP_OPTION_PAD = 0, /* [RFC2132] */ - SD_DHCP_OPTION_SUBNET_MASK = 1, /* [RFC2132] */ - SD_DHCP_OPTION_TIME_OFFSET = 2, /* [RFC2132], deprecated by 100 and 101 */ - SD_DHCP_OPTION_ROUTER = 3, /* [RFC2132] */ - SD_DHCP_OPTION_TIME_SERVER = 4, /* [RFC2132] */ - SD_DHCP_OPTION_NAME_SERVER = 5, /* [RFC2132] */ - SD_DHCP_OPTION_DOMAIN_NAME_SERVER = 6, /* [RFC2132] */ - SD_DHCP_OPTION_LOG_SERVER = 7, /* [RFC2132] */ - SD_DHCP_OPTION_QUOTES_SERVER = 8, /* [RFC2132] */ - SD_DHCP_OPTION_LPR_SERVER = 9, /* [RFC2132] */ - SD_DHCP_OPTION_IMPRESS_SERVER = 10, /* [RFC2132] */ - SD_DHCP_OPTION_RLP_SERVER = 11, /* [RFC2132] */ - SD_DHCP_OPTION_HOST_NAME = 12, /* [RFC2132] */ - SD_DHCP_OPTION_BOOT_FILE_SIZE = 13, /* [RFC2132] */ - SD_DHCP_OPTION_MERIT_DUMP_FILE = 14, /* [RFC2132] */ - SD_DHCP_OPTION_DOMAIN_NAME = 15, /* [RFC2132] */ - SD_DHCP_OPTION_SWAP_SERVER = 16, /* [RFC2132] */ - SD_DHCP_OPTION_ROOT_PATH = 17, /* [RFC2132] */ - SD_DHCP_OPTION_EXTENSION_FILE = 18, /* [RFC2132] */ - SD_DHCP_OPTION_FORWARD = 19, /* [RFC2132] */ - SD_DHCP_OPTION_SOURCE_ROUTE = 20, /* [RFC2132] */ - SD_DHCP_OPTION_POLICY_FILTER = 21, /* [RFC2132] */ - SD_DHCP_OPTION_MAX_DATAGRAM_ASSEMBLY = 22, /* [RFC2132] */ - SD_DHCP_OPTION_DEFAULT_IP_TTL = 23, /* [RFC2132] */ - SD_DHCP_OPTION_MTU_TIMEOUT = 24, /* [RFC2132] */ - SD_DHCP_OPTION_MTU_PLATEAU = 25, /* [RFC2132] */ - SD_DHCP_OPTION_MTU_INTERFACE = 26, /* [RFC2132] */ - SD_DHCP_OPTION_MTU_SUBNET = 27, /* [RFC2132] */ - SD_DHCP_OPTION_BROADCAST = 28, /* [RFC2132] */ - SD_DHCP_OPTION_MASK_DISCOVERY = 29, /* [RFC2132] */ - SD_DHCP_OPTION_MASK_SUPPLIER = 30, /* [RFC2132] */ - SD_DHCP_OPTION_ROUTER_DISCOVERY = 31, /* [RFC2132] */ - SD_DHCP_OPTION_ROUTER_REQUEST = 32, /* [RFC2132] */ - SD_DHCP_OPTION_STATIC_ROUTE = 33, /* [RFC2132] */ - SD_DHCP_OPTION_TRAILERS = 34, /* [RFC2132] */ - SD_DHCP_OPTION_ARP_TIMEOUT = 35, /* [RFC2132] */ - SD_DHCP_OPTION_ETHERNET = 36, /* [RFC2132] */ - SD_DHCP_OPTION_DEFAULT_TCP_TTL = 37, /* [RFC2132] */ - SD_DHCP_OPTION_KEEPALIVE_TIME = 38, /* [RFC2132] */ - SD_DHCP_OPTION_KEEPALIVE_DATA = 39, /* [RFC2132] */ - SD_DHCP_OPTION_NIS_DOMAIN = 40, /* [RFC2132] */ - SD_DHCP_OPTION_NIS_SERVER = 41, /* [RFC2132] */ - SD_DHCP_OPTION_NTP_SERVER = 42, /* [RFC2132] */ - SD_DHCP_OPTION_VENDOR_SPECIFIC = 43, /* [RFC2132] */ - SD_DHCP_OPTION_NETBIOS_NAME_SERVER = 44, /* [RFC2132] */ - SD_DHCP_OPTION_NETBIOS_DIST_SERVER = 45, /* [RFC2132] */ - SD_DHCP_OPTION_NETBIOS_NODE_TYPE = 46, /* [RFC2132] */ - SD_DHCP_OPTION_NETBIOS_SCOPE = 47, /* [RFC2132] */ - SD_DHCP_OPTION_X_WINDOW_FONT = 48, /* [RFC2132] */ - SD_DHCP_OPTION_X_WINDOW_MANAGER = 49, /* [RFC2132] */ - SD_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, /* [RFC2132] */ - SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, /* [RFC2132] */ - SD_DHCP_OPTION_OVERLOAD = 52, /* [RFC2132] */ - SD_DHCP_OPTION_MESSAGE_TYPE = 53, /* [RFC2132] */ - SD_DHCP_OPTION_SERVER_IDENTIFIER = 54, /* [RFC2132] */ - SD_DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, /* [RFC2132] */ - SD_DHCP_OPTION_ERROR_MESSAGE = 56, /* [RFC2132] */ - SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, /* [RFC2132] */ - SD_DHCP_OPTION_RENEWAL_TIME = 58, /* [RFC2132] */ - SD_DHCP_OPTION_REBINDING_TIME = 59, /* [RFC2132] */ - SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, /* [RFC2132] */ - SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61, /* [RFC2132] */ - SD_DHCP_OPTION_NETWARE_IP_DOMAIN = 62, /* [RFC2242] */ - SD_DHCP_OPTION_NETWARE_IP_OPTION = 63, /* [RFC2242] */ - SD_DHCP_OPTION_NIS_DOMAIN_NAME = 64, /* [RFC2132] */ - SD_DHCP_OPTION_NIS_SERVER_ADDR = 65, /* [RFC2132] */ - SD_DHCP_OPTION_BOOT_SERVER_NAME = 66, /* [RFC2132] */ - SD_DHCP_OPTION_BOOT_FILENAME = 67, /* [RFC2132] */ - SD_DHCP_OPTION_HOME_AGENT_ADDRESSES = 68, /* [RFC2132] */ - SD_DHCP_OPTION_SMTP_SERVER = 69, /* [RFC2132] */ - SD_DHCP_OPTION_POP3_SERVER = 70, /* [RFC2132] */ - SD_DHCP_OPTION_NNTP_SERVER = 71, /* [RFC2132] */ - SD_DHCP_OPTION_WWW_SERVER = 72, /* [RFC2132] */ - SD_DHCP_OPTION_FINGER_SERVER = 73, /* [RFC2132] */ - SD_DHCP_OPTION_IRC_SERVER = 74, /* [RFC2132] */ - SD_DHCP_OPTION_STREETTALK_SERVER = 75, /* [RFC2132] */ - SD_DHCP_OPTION_STDA_SERVER = 76, /* [RFC2132] */ - SD_DHCP_OPTION_USER_CLASS = 77, /* [RFC3004] */ - SD_DHCP_OPTION_DIRECTORY_AGENT = 78, /* [RFC2610] */ - SD_DHCP_OPTION_SERVICE_SCOPE = 79, /* [RFC2610] */ - SD_DHCP_OPTION_RAPID_COMMIT = 80, /* [RFC4039] */ - SD_DHCP_OPTION_FQDN = 81, /* [RFC4702] */ - SD_DHCP_OPTION_RELAY_AGENT_INFORMATION = 82, /* [RFC3046] */ - SD_DHCP_OPTION_ISNS = 83, /* [RFC4174] */ - /* option code 84 is unassigned [RFC3679] */ - SD_DHCP_OPTION_NDS_SERVER = 85, /* [RFC2241] */ - SD_DHCP_OPTION_NDS_TREE_NAME = 86, /* [RFC2241] */ - SD_DHCP_OPTION_NDS_CONTEXT = 87, /* [RFC2241] */ - SD_DHCP_OPTION_BCMCS_CONTROLLER_DOMAIN_NAM = 88, /* [RFC4280] */ - SD_DHCP_OPTION_BCMCS_CONTROLLER_ADDRESS = 89, /* [RFC4280] */ - SD_DHCP_OPTION_AUTHENTICATION = 90, /* [RFC3118] */ - SD_DHCP_OPTION_CLIENT_LAST_TRANSACTION_TIME = 91, /* [RFC4388] */ - SD_DHCP_OPTION_ASSOCIATED_IP = 92, /* [RFC4388] */ - SD_DHCP_OPTION_CLIENT_SYSTEM = 93, /* [RFC4578] */ - SD_DHCP_OPTION_CLIENT_NDI = 94, /* [RFC4578] */ - SD_DHCP_OPTION_LDAP = 95, /* [RFC3679] */ - /* option code 96 is unassigned [RFC3679] */ - SD_DHCP_OPTION_UUID = 97, /* [RFC4578] */ - SD_DHCP_OPTION_USER_AUTHENTICATION = 98, /* [RFC2485] */ - SD_DHCP_OPTION_GEOCONF_CIVIC = 99, /* [RFC4776] */ - SD_DHCP_OPTION_POSIX_TIMEZONE = 100, /* [RFC4833] */ - SD_DHCP_OPTION_TZDB_TIMEZONE = 101, /* [RFC4833] */ - /* option codes 102-107 are unassigned [RFC3679] */ - SD_DHCP_OPTION_IPV6_ONLY_PREFERRED = 108, /* [RFC8925] */ - SD_DHCP_OPTION_DHCP4O6_SOURCE_ADDRESS = 109, /* [RFC8539] */ - /* option codes 110-111 are unassigned [RFC3679] */ - SD_DHCP_OPTION_NETINFO_ADDRESS = 112, /* [RFC3679] */ - SD_DHCP_OPTION_NETINFO_TAG = 113, /* [RFC3679] */ - SD_DHCP_OPTION_DHCP_CAPTIVE_PORTAL = 114, /* [RFC8910] */ - /* option code 115 is unassigned [RFC3679] */ - SD_DHCP_OPTION_AUTO_CONFIG = 116, /* [RFC2563] */ - SD_DHCP_OPTION_NAME_SERVICE_SEARCH = 117, /* [RFC2937] */ - SD_DHCP_OPTION_SUBNET_SELECTION = 118, /* [RFC3011] */ - SD_DHCP_OPTION_DOMAIN_SEARCH = 119, /* [RFC3397] */ - SD_DHCP_OPTION_SIP_SERVER = 120, /* [RFC3361] */ - SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, /* [RFC3442] */ - SD_DHCP_OPTION_CABLELABS_CLIENT_CONFIGURATION = 122, /* [RFC3495] */ - SD_DHCP_OPTION_GEOCONF = 123, /* [RFC6225] */ - SD_DHCP_OPTION_VENDOR_CLASS = 124, /* [RFC3925] */ - SD_DHCP_OPTION_VENDOR_SPECIFIC_INFORMATION = 125, /* [RFC3925] */ - /* option codes 126-127 are unassigned [RFC3679] */ - /* option codes 128-135 are assigned to use by PXE, but they are vendor specific [RFC4578] */ - SD_DHCP_OPTION_PANA_AGENT = 136, /* [RFC5192] */ - SD_DHCP_OPTION_LOST_SERVER_FQDN = 137, /* [RFC5223] */ - SD_DHCP_OPTION_CAPWAP_AC_ADDRESS = 138, /* [RFC5417] */ - SD_DHCP_OPTION_MOS_ADDRESS = 139, /* [RFC5678] */ - SD_DHCP_OPTION_MOS_FQDN = 140, /* [RFC5678] */ - SD_DHCP_OPTION_SIP_SERVICE_DOMAINS = 141, /* [RFC6011] */ - SD_DHCP_OPTION_ANDSF_ADDRESS = 142, /* [RFC6153] */ - SD_DHCP_OPTION_SZTP_REDIRECT = 143, /* [RFC8572] */ - SD_DHCP_OPTION_GEOLOC = 144, /* [RFC6225] */ - SD_DHCP_OPTION_FORCERENEW_NONCE_CAPABLE = 145, /* [RFC6704] */ - SD_DHCP_OPTION_RDNSS_SELECTION = 146, /* [RFC6731] */ - SD_DHCP_OPTION_DOTS_RI = 147, /* [RFC8973] */ - SD_DHCP_OPTION_DOTS_ADDRESS = 148, /* [RFC8973] */ - /* option code 149 is unassigned [RFC3942] */ - SD_DHCP_OPTION_TFTP_SERVER_ADDRESS = 150, /* [RFC5859] */ - SD_DHCP_OPTION_STATUS_CODE = 151, /* [RFC6926] */ - SD_DHCP_OPTION_BASE_TIME = 152, /* [RFC6926] */ - SD_DHCP_OPTION_START_TIME_OF_STATE = 153, /* [RFC6926] */ - SD_DHCP_OPTION_QUERY_START_TIME = 154, /* [RFC6926] */ - SD_DHCP_OPTION_QUERY_END_TIME = 155, /* [RFC6926] */ - SD_DHCP_OPTION_DHCP_STATE = 156, /* [RFC6926] */ - SD_DHCP_OPTION_DATA_SOURCE = 157, /* [RFC6926] */ - SD_DHCP_OPTION_PCP_SERVER = 158, /* [RFC7291] */ - SD_DHCP_OPTION_PORT_PARAMS = 159, /* [RFC7618] */ - /* option code 160 is unassigned [RFC7710][RFC8910] */ - SD_DHCP_OPTION_MUD_URL = 161, /* [RFC8520] */ - /* option codes 162-174 are unassigned [RFC3942] */ - /* option codes 175-177 are temporary assigned. */ - /* option codes 178-207 are unassigned [RFC3942] */ - SD_DHCP_OPTION_PXELINUX_MAGIC = 208, /* [RFC5071] Deprecated */ - SD_DHCP_OPTION_CONFIGURATION_FILE = 209, /* [RFC5071] */ - SD_DHCP_OPTION_PATH_PREFIX = 210, /* [RFC5071] */ - SD_DHCP_OPTION_REBOOT_TIME = 211, /* [RFC5071] */ - SD_DHCP_OPTION_6RD = 212, /* [RFC5969] */ - SD_DHCP_OPTION_ACCESS_DOMAIN = 213, /* [RFC5986] */ - /* option codes 214-219 are unassigned */ - SD_DHCP_OPTION_SUBNET_ALLOCATION = 220, /* [RFC6656] */ - SD_DHCP_OPTION_VIRTUAL_SUBNET_SELECTION = 221, /* [RFC6607] */ - /* option codes 222-223 are unassigned [RFC3942] */ - /* option codes 224-254 are reserved for private use */ - SD_DHCP_OPTION_PRIVATE_BASE = 224, - SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249, /* [RFC7844] */ - SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY = 252, /* [RFC7844] */ - SD_DHCP_OPTION_PRIVATE_LAST = 254, - SD_DHCP_OPTION_END = 255, /* [RFC2132] */ -}; - -/* Suboptions for SD_DHCP_OPTION_RELAY_AGENT_INFORMATION option */ -enum { - SD_DHCP_RELAY_AGENT_CIRCUIT_ID = 1, - SD_DHCP_RELAY_AGENT_REMOTE_ID = 2, -}; - -typedef struct sd_dhcp_client sd_dhcp_client; - -typedef int (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata); -int sd_dhcp_client_set_callback( - sd_dhcp_client *client, - sd_dhcp_client_callback_t cb, - void *userdata); - -int sd_dhcp_client_set_request_option( - sd_dhcp_client *client, - uint8_t option); -int sd_dhcp_client_set_request_address( - sd_dhcp_client *client, - const struct in_addr *last_address); -int sd_dhcp_client_set_request_broadcast( - sd_dhcp_client *client, - int broadcast); -int sd_dhcp_client_set_ifindex( - sd_dhcp_client *client, - int interface_index); -int sd_dhcp_client_set_ifname( - sd_dhcp_client *client, - const char *interface_name); -int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret); -int sd_dhcp_client_set_mac( - sd_dhcp_client *client, - const uint8_t *addr, - const uint8_t *bcast_addr, - size_t addr_len, - uint16_t arp_type); -int sd_dhcp_client_set_client_id( - sd_dhcp_client *client, - uint8_t type, - const uint8_t *data, - size_t data_len); -int sd_dhcp_client_set_iaid_duid( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - uint16_t duid_type, - const void *duid, - size_t duid_len); -int sd_dhcp_client_set_iaid_duid_llt( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - uint64_t llt_time); -int sd_dhcp_client_set_duid( - sd_dhcp_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len); -int sd_dhcp_client_set_duid_llt( - sd_dhcp_client *client, - uint64_t llt_time); -int sd_dhcp_client_get_client_id( - sd_dhcp_client *client, - uint8_t *type, - const uint8_t **data, - size_t *data_len); -int sd_dhcp_client_set_mtu( - sd_dhcp_client *client, - uint32_t mtu); -int sd_dhcp_client_set_max_attempts( - sd_dhcp_client *client, - uint64_t attempt); -int sd_dhcp_client_set_client_port( - sd_dhcp_client *client, - uint16_t port); -int sd_dhcp_client_set_hostname( - sd_dhcp_client *client, - const char *hostname); -int sd_dhcp_client_set_vendor_class_identifier( - sd_dhcp_client *client, - const char *vci); -int sd_dhcp_client_set_mud_url( - sd_dhcp_client *client, - const char *mudurl); -int sd_dhcp_client_set_user_class( - sd_dhcp_client *client, - char * const *user_class); -int sd_dhcp_client_get_lease( - sd_dhcp_client *client, - sd_dhcp_lease **ret); -int sd_dhcp_client_set_service_type( - sd_dhcp_client *client, - int type); -int sd_dhcp_client_set_fallback_lease_lifetime( - sd_dhcp_client *client, - uint32_t fallback_lease_lifetime); - -int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v); -int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v); - -int sd_dhcp_client_is_running(sd_dhcp_client *client); -int sd_dhcp_client_stop(sd_dhcp_client *client); -int sd_dhcp_client_start(sd_dhcp_client *client); -int sd_dhcp_client_send_release(sd_dhcp_client *client); -int sd_dhcp_client_send_decline(sd_dhcp_client *client); -int sd_dhcp_client_send_renew(sd_dhcp_client *client); - -sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client); -sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client); - -/* NOTE: anonymize parameter is used to initialize PRL memory with different - * options when using RFC7844 Anonymity Profiles */ -int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize); - -int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret); - -int sd_dhcp_client_attach_event( - sd_dhcp_client *client, - sd_event *event, - int64_t priority); -int sd_dhcp_client_detach_event(sd_dhcp_client *client); -sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_client, sd_dhcp_client_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h deleted file mode 100644 index 578ac6d4db..0000000000 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcpleasehfoo -#define foosddhcpleasehfoo - -/*** - 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 <http://www.gnu.org/licenses/>. -***/ - -#include <errno.h> -#include <inttypes.h> -#include <net/ethernet.h> -#include <netinet/in.h> -#include <sys/types.h> - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -typedef struct sd_dhcp_lease sd_dhcp_lease; -typedef struct sd_dhcp_route sd_dhcp_route; - -sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease); -sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease); - -typedef enum sd_dhcp_lease_server_type_t { - SD_DHCP_LEASE_DNS, - SD_DHCP_LEASE_NTP, - SD_DHCP_LEASE_SIP, - SD_DHCP_LEASE_POP3, - SD_DHCP_LEASE_SMTP, - SD_DHCP_LEASE_LPR, - _SD_DHCP_LEASE_SERVER_TYPE_MAX, - _SD_DHCP_LEASE_SERVER_TYPE_INVALID = -EINVAL, - _SD_ENUM_FORCE_S64(DHCP_LEASE_SERVER_TYPE), -} sd_dhcp_lease_server_type_t; - -int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime); -int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1); -int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2); -int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr); -int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu); -int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); -int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains); -int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname); -int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path); -int sd_dhcp_lease_get_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret); -int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret); -int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len); -int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len); -int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone); -int sd_dhcp_lease_get_6rd( - sd_dhcp_lease *lease, - uint8_t *ret_ipv4masklen, - uint8_t *ret_prefixlen, - struct in6_addr *ret_prefix, - const struct in_addr **ret_br_addresses, - size_t *ret_n_br_addresses); - -int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination); -int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length); -int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-option.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-option.h deleted file mode 100644 index 71aa479b5e..0000000000 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp-option.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcpoptionhfoo -#define foosddhcpoptionhfoo - -/*** - 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 <http://www.gnu.org/licenses/>. -***/ - -#include <inttypes.h> -#include <sys/types.h> - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -typedef struct sd_dhcp_option sd_dhcp_option; - -int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret); -sd_dhcp_option *sd_dhcp_option_ref(sd_dhcp_option *ra); -sd_dhcp_option *sd_dhcp_option_unref(sd_dhcp_option *ra); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_option, sd_dhcp_option_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/libnm-systemd-shared/nm-sd-utils-shared.c b/src/libnm-systemd-shared/nm-sd-utils-shared.c index 0a35016a40..dad21596cf 100644 --- a/src/libnm-systemd-shared/nm-sd-utils-shared.c +++ b/src/libnm-systemd-shared/nm-sd-utils-shared.c @@ -21,58 +21,6 @@ const bool mempool_use_allowed = true; /*****************************************************************************/ -gboolean -nm_sd_utils_path_equal(const char *a, const char *b) -{ - return path_equal(a, b); -} - -char * -nm_sd_utils_path_simplify(char *path) -{ - return path_simplify(path); -} - -const char * -nm_sd_utils_path_startswith(const char *path, const char *prefix) -{ - return path_startswith(path, prefix); -} - -/*****************************************************************************/ - -int -nm_sd_utils_unbase64char(char ch, gboolean accept_padding_equal) -{ - if (ch == '=' && accept_padding_equal) - return G_MAXINT; - return unbase64char(ch); -} - -/** - * nm_sd_utils_unbase64mem: - * @p: a valid base64 string. Whitespace is ignored, but invalid encodings - * will cause the function to fail. - * @l: the length of @p. @p is not treated as NUL terminated string but - * merely as a buffer of ascii characters. - * @secure: whether the temporary memory will be cleared to avoid leaving - * secrets in memory (see also nm_explicit_bzero()). - * @mem: (transfer full): the decoded buffer on success. - * @len: the length of @mem on success. - * - * glib provides g_base64_decode(), but that does not report any errors - * from invalid encodings. Expose systemd's implementation which does - * reject invalid inputs. - * - * Returns: a non-negative code on success. Invalid encoding let the - * function fail. - */ -int -nm_sd_utils_unbase64mem(const char *p, size_t l, gboolean secure, guint8 **mem, size_t *len) -{ - return unbase64mem_full(p, l, secure, (void **) mem, len); -} - int nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gboolean canonical) { @@ -85,14 +33,6 @@ nm_sd_dns_name_is_valid(const char *s) return dns_name_is_valid(s); } -gboolean -nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot) -{ - return hostname_is_valid(s, - allow_trailing_dot ? VALID_HOSTNAME_TRAILING_DOT - : (ValidHostnameFlags) 0); -} - char * nm_sd_dns_name_normalize(const char *s) { diff --git a/src/libnm-systemd-shared/nm-sd-utils-shared.h b/src/libnm-systemd-shared/nm-sd-utils-shared.h index 82a5067863..fefb8a1cdf 100644 --- a/src/libnm-systemd-shared/nm-sd-utils-shared.h +++ b/src/libnm-systemd-shared/nm-sd-utils-shared.h @@ -8,25 +8,10 @@ /*****************************************************************************/ -gboolean nm_sd_utils_path_equal(const char *a, const char *b); - -char *nm_sd_utils_path_simplify(char *path); - -const char *nm_sd_utils_path_startswith(const char *path, const char *prefix); - -/*****************************************************************************/ - -int nm_sd_utils_unbase64char(char ch, gboolean accept_padding_equal); - -int nm_sd_utils_unbase64mem(const char *p, size_t l, gboolean secure, guint8 **mem, size_t *len); - -/*****************************************************************************/ - int nm_sd_dns_name_to_wire_format(const char *domain, guint8 *buffer, size_t len, gboolean canonical); -int nm_sd_dns_name_is_valid(const char *s); -gboolean nm_sd_hostname_is_valid(const char *s, bool allow_trailing_dot); +int nm_sd_dns_name_is_valid(const char *s); char *nm_sd_dns_name_normalize(const char *s); diff --git a/src/libnmc-base/nm-polkit-listener.c b/src/libnmc-base/nm-polkit-listener.c index 39a06bc6d4..e7972faa48 100644 --- a/src/libnmc-base/nm-polkit-listener.c +++ b/src/libnmc-base/nm-polkit-listener.c @@ -393,7 +393,7 @@ queue_string_to_helper(AuthRequest *request, const char *response) g_return_if_fail(response); if (!nm_str_buf_is_initalized(&request->out_buffer)) - nm_str_buf_init(&request->out_buffer, strlen(response) + 2u, TRUE); + request->out_buffer = NM_STR_BUF_INIT(strlen(response) + 2u, TRUE); nm_str_buf_append(&request->out_buffer, response); nm_str_buf_ensure_trailing_c(&request->out_buffer, '\n'); @@ -587,10 +587,9 @@ create_request(NMPolkitListener *listener, .cookie = g_strdup(cookie), .request_any_response = FALSE, .request_is_completed = FALSE, + .in_buffer = NM_STR_BUF_INIT(NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE), }; - nm_str_buf_init(&request->in_buffer, NM_UTILS_GET_NEXT_REALLOC_SIZE_1000, FALSE); - c_list_link_tail(&listener->request_lst_head, &request->request_lst); return request; } diff --git a/src/n-dhcp4/src/libndhcp4.sym b/src/n-dhcp4/src/libndhcp4.sym index 4d11734e4d..c6e0dd8672 100644 --- a/src/n-dhcp4/src/libndhcp4.sym +++ b/src/n-dhcp4/src/libndhcp4.sym @@ -35,6 +35,7 @@ global: n_dhcp4_client_lease_unref; n_dhcp4_client_lease_get_yiaddr; n_dhcp4_client_lease_get_siaddr; + n_dhcp4_client_lease_get_basetime; n_dhcp4_client_lease_get_lifetime; n_dhcp4_client_lease_get_server_identifier; n_dhcp4_client_lease_get_file; diff --git a/src/n-dhcp4/src/n-dhcp4-c-lease.c b/src/n-dhcp4/src/n-dhcp4-c-lease.c index bae2f674cd..eaa9627652 100644 --- a/src/n-dhcp4/src/n-dhcp4-c-lease.c +++ b/src/n-dhcp4/src/n-dhcp4-c-lease.c @@ -251,7 +251,7 @@ _c_public_ void n_dhcp4_client_lease_get_lifetime(NDhcp4ClientLease *lease, uint * * Return: 0 on success, * N_DHCP4_E_UNSET if the lease doesn't contain a server-identifier, or - * N_DCHP4_E_INTERNAL if the server-identifier is not valid. + * N_DHCP4_E_INTERNAL if the server-identifier is not valid. */ _c_public_ int n_dhcp4_client_lease_get_server_identifier(NDhcp4ClientLease *lease, struct in_addr *addr) { uint8_t *data; @@ -279,25 +279,25 @@ _c_public_ int n_dhcp4_client_lease_get_server_identifier(NDhcp4ClientLease *lea * * Return: 0 on success, * N_DHCP4_E_UNSET if the lease does not contain a file name, or - * N_DCHP4_E_INTERNAL if the file name is invalid. + * N_DHCP4_E_INTERNAL if the file name is invalid. */ _c_public_ int n_dhcp4_client_lease_get_file(NDhcp4ClientLease *lease, const char **file) { NDhcp4Message *message; if (lease->message->options[N_DHCP4_OPTION_OVERLOAD].size > 0 && ((*lease->message->options[N_DHCP4_OPTION_OVERLOAD].value) & N_DHCP4_OVERLOAD_FILE)) { - /* The field is overloaded to contain other options */ - return N_DHCP4_E_UNSET; + /* The field is overloaded to contain other options */ + return N_DHCP4_E_UNSET; } message = &lease->message->message; if (message->file[0] == '\0') - return N_DHCP4_E_UNSET; + return N_DHCP4_E_UNSET; if (!memchr(message->file, '\0', sizeof(message->file))) { - /* The field is NULL-terminated (RFC 2131 section 2) */ - return N_DHCP4_E_INTERNAL; + /* The field is NULL-terminated (RFC 2131 section 2) */ + return N_DHCP4_E_INTERNAL; } *file = (const char *) message->file; @@ -316,7 +316,7 @@ _c_public_ int n_dhcp4_client_lease_get_file(NDhcp4ClientLease *lease, const cha * be queried, and only options that were explicitly requested can be queried. * * Return: 0 on success, - * N_DCHP4_E_INTERNAL if an invalid option is queried, + * N_DHCP4_E_INTERNAL if an invalid option is queried, * N_DHCP4_E_UNSET if the lease did not contain the option, or * a negative error code on failure. */ diff --git a/src/n-dhcp4/src/test-api.c b/src/n-dhcp4/src/test-api.c index db3ff935ce..fac3300883 100644 --- a/src/n-dhcp4/src/test-api.c +++ b/src/n-dhcp4/src/test-api.c @@ -107,6 +107,7 @@ static void test_api_functions(void) { (void *)n_dhcp4_client_lease_get_siaddr, (void *)n_dhcp4_client_lease_get_lifetime, (void *)n_dhcp4_client_lease_get_server_identifier, + (void *)n_dhcp4_client_lease_get_file, (void *)n_dhcp4_client_lease_query, (void *)n_dhcp4_client_lease_select, (void *)n_dhcp4_client_lease_accept, diff --git a/src/nm-daemon-helper/nm-daemon-helper.c b/src/nm-daemon-helper/nm-daemon-helper.c index 21a71e3c4a..a101bf9b4f 100644 --- a/src/nm-daemon-helper/nm-daemon-helper.c +++ b/src/nm-daemon-helper/nm-daemon-helper.c @@ -2,6 +2,8 @@ /* Copyright (C) 2021 Red Hat, Inc. */ +#include "libnm-std-aux/nm-default-std.h" + #include <stdio.h> #include <stdlib.h> #include <arpa/inet.h> @@ -10,8 +12,6 @@ #include <nss.h> #endif -#include "libnm-std-aux/nm-std-aux.h" - enum { RETURN_SUCCESS = 0, RETURN_INVALID_CMD = 1, diff --git a/src/nm-initrd-generator/nmi-cmdline-reader.c b/src/nm-initrd-generator/nmi-cmdline-reader.c index 412c751067..88760f7574 100644 --- a/src/nm-initrd-generator/nmi-cmdline-reader.c +++ b/src/nm-initrd-generator/nmi-cmdline-reader.c @@ -12,7 +12,6 @@ #include "libnm-log-core/nm-logging.h" #include "libnm-core-intern/nm-core-internal.h" #include "nm-initrd-generator.h" -#include "libnm-systemd-shared/nm-sd-utils-shared.h" /*****************************************************************************/ @@ -586,7 +585,7 @@ reader_parse_ip(Reader *reader, const char *sysfs_dir, char *argument) } } - if (client_hostname && !nm_sd_hostname_is_valid(client_hostname, FALSE)) + if (client_hostname && !nm_hostname_is_valid(client_hostname, FALSE)) client_hostname = NULL; if (client_hostname) { diff --git a/src/nm-priv-helper/nm-priv-helper.c b/src/nm-priv-helper/nm-priv-helper.c index ec064bca2d..e29113b112 100644 --- a/src/nm-priv-helper/nm-priv-helper.c +++ b/src/nm-priv-helper/nm-priv-helper.c @@ -9,7 +9,6 @@ #include "libnm-glib-aux/nm-dbus-aux.h" #include "libnm-glib-aux/nm-io-utils.h" #include "libnm-glib-aux/nm-logging-base.h" -#include "libnm-glib-aux/nm-shared-utils.h" #include "libnm-glib-aux/nm-time-utils.h" /* nm-priv-helper doesn't link with libnm-core nor libnm-base, but these diff --git a/src/nmcli/common.c b/src/nmcli/common.c index f42f76e4c2..710914e211 100644 --- a/src/nmcli/common.c +++ b/src/nmcli/common.c @@ -16,6 +16,8 @@ #include <readline/history.h> #include <readline/readline.h> #endif +#include <gio/gunixinputstream.h> + #include "libnm-client-aux-extern/nm-libnm-aux.h" #include "libnmc-base/nm-vpn-helpers.h" @@ -469,7 +471,8 @@ nmc_find_connection(const GPtrArray *connections, goto found; } - if (NM_IN_STRSET(filter_type, NULL, "filename")) { + if (NM_IS_REMOTE_CONNECTION(connections->pdata[i]) + && NM_IN_STRSET(filter_type, NULL, "filename")) { v = nm_remote_connection_get_filename(NM_REMOTE_CONNECTION(connections->pdata[i])); if (complete && (filter_type || *filter_val)) nmc_complete_strings(filter_val, v); @@ -1273,12 +1276,157 @@ got_client(GObject *source_object, GAsyncResult *res, gpointer user_data) nm_g_slice_free(call); } +typedef struct { + GString *str; + char buf[512]; + CmdCall *call; +} CmdStdinData; + +static void read_offline_connection_next(GInputStream *stream, CmdStdinData *data); + +static void +read_offline_connection_chunk(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GInputStream *stream = G_INPUT_STREAM(source_object); + CmdStdinData *data = user_data; + CmdCall *call = data->call; + gs_unref_object GTask *task = NULL; + nm_auto_unref_keyfile GKeyFile *keyfile = NULL; + gs_free char *base_dir = NULL; + GError *error = NULL; + gssize bytes_read; + NMConnection *connection; + NmCli *nmc; + + bytes_read = g_input_stream_read_finish(stream, res, &error); + if (bytes_read > 0) { + /* We need to read more. */ + g_string_append_len(data->str, data->buf, bytes_read); + read_offline_connection_next(stream, data); + return; + } + + /* End reached. */ + + task = g_steal_pointer(&call->task); + nmc = g_task_get_task_data(task); + nmc->should_wait--; + + if (bytes_read == -1) { + g_task_return_error(task, error); + goto finish; + } + + keyfile = g_key_file_new(); + if (!g_key_file_load_from_data(keyfile, + data->str->str, + data->str->len, + G_KEY_FILE_NONE, + &error)) { + g_task_return_error(task, error); + goto finish; + } + + base_dir = g_get_current_dir(); + connection = + nm_keyfile_read(keyfile, base_dir, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error); + if (!connection) { + g_task_return_error(task, error); + goto finish; + } + + g_ptr_array_add(nmc->offline_connections, connection); + call->cmd->func(call->cmd, nmc, call->argc, (const char *const *) call->argv); + g_task_return_boolean(task, TRUE); + +finish: + g_strfreev(call->argv); + nm_g_slice_free(call); + g_string_free(data->str, TRUE); + nm_g_slice_free(data); +} + +static void +read_offline_connection_next(GInputStream *stream, CmdStdinData *data) +{ + g_input_stream_read_async(stream, + data->buf, + sizeof(data->buf), + G_PRIORITY_DEFAULT, + NULL, + read_offline_connection_chunk, + data); +} + +static void +read_offline_connection(CmdCall *call) +{ + gs_unref_object GInputStream *stream = NULL; + CmdStdinData *data; + + stream = g_unix_input_stream_new(STDIN_FILENO, TRUE); + data = g_slice_new(CmdStdinData); + data->call = call; + data->str = g_string_new_len(NULL, sizeof(data->buf)); + + read_offline_connection_next(stream, data); +} + +static NMConnection * +dummy_offline_connection(void) +{ + NMConnection *connection; + + connection = nm_simple_connection_new(); + nm_connection_add_setting(connection, nm_setting_connection_new()); + return connection; +} + static void call_cmd(NmCli *nmc, GTask *task, const NMCCommand *cmd, int argc, const char *const *argv) { CmdCall *call; - if (nmc->client || !cmd->needs_client) { + if (nmc->offline) { + if (!cmd->supports_offline) { + g_task_return_new_error(task, + NMCLI_ERROR, + NMC_RESULT_ERROR_USER_INPUT, + _("Error: command doesn't support --offline mode.")); + g_object_unref(task); + return; + } + + if (!nmc->offline_connections) + nmc->offline_connections = g_ptr_array_new_full(1, g_object_unref); + + if (cmd->needs_offline_conn) { + g_return_if_fail(nmc->offline_connections->len == 0); + + if (nmc->complete) { + g_ptr_array_add(nmc->offline_connections, dummy_offline_connection()); + cmd->func(cmd, nmc, argc, argv); + g_task_return_boolean(task, TRUE); + g_object_unref(task); + return; + } + + nmc->should_wait++; + call = g_slice_new(CmdCall); + *call = (CmdCall){ + .cmd = cmd, + .argc = argc, + .argv = nm_strv_dup(argv, argc, TRUE), + .task = task, + }; + read_offline_connection(call); + return; + } else { + cmd->func(cmd, nmc, argc, argv); + g_task_return_boolean(task, TRUE); + g_object_unref(task); + } + } else if (nmc->client || !cmd->needs_client) { /* Check whether NetworkManager is running */ if (cmd->needs_nm_running && !nm_client_get_nm_running(nmc->client)) { g_task_return_new_error(task, diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c index d093823b27..4d9f662bf5 100644 --- a/src/nmcli/connections.c +++ b/src/nmcli/connections.c @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright (C) 2010 - 2018 Red Hat, Inc. + * Copyright (C) 2010 - 2022 Red Hat, Inc. */ #include "libnm-client-aux-extern/nm-default-client.h" @@ -18,6 +18,7 @@ #include <readline/history.h> #endif #include <fcntl.h> +#include <gio/gunixoutputstream.h> #include "libnm-glib-aux/nm-dbus-aux.h" #include "libnmc-base/nm-client-utils.h" @@ -137,6 +138,131 @@ NM_AUTO_DEFINE_FCN(AddConnectionInfo *, /*****************************************************************************/ +static guint progress_id = 0; /* ID of event source for displaying progress */ + +static void +quit(void) +{ + if (nm_clear_g_source(&progress_id)) + nmc_terminal_erase_line(); + g_main_loop_quit(loop); +} + +typedef struct { + char *data; + gsize written; + gsize length; + NmCli *nmc; +} PrintConnData; + +static void print_connection_chunk(GOutputStream *stream, PrintConnData *print_conn_data); + +static void +print_connection_done(GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GOutputStream *stream = G_OUTPUT_STREAM(source_object); + PrintConnData *print_conn_data = user_data; + NmCli *nmc = print_conn_data->nmc; + GError *error = NULL; + gssize written; + + written = g_output_stream_write_finish(stream, res, &error); + if (written == -1) { + g_string_printf(nmc->return_text, + _("Error: Error writting connection: %s"), + error->message); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + nmc->should_wait--; + quit(); + return; + } + + print_conn_data->written += written; + if (print_conn_data->written != print_conn_data->length) { + g_return_if_fail(written); + g_return_if_fail(print_conn_data->written < print_conn_data->length); + + print_connection_chunk(stream, print_conn_data); + return; + } + + g_free(print_conn_data->data); + g_slice_free(PrintConnData, print_conn_data); + + nmc->should_wait--; + quit(); +} + +static void +print_connection_chunk(GOutputStream *stream, PrintConnData *print_conn_data) +{ + g_output_stream_write_async(stream, + print_conn_data->data + print_conn_data->written, + print_conn_data->length - print_conn_data->written, + G_PRIORITY_DEFAULT, + NULL, + print_connection_done, + print_conn_data); +} + +static void +nmc_print_connection_and_quit(NmCli *nmc, NMConnection *connection) +{ + gs_free_error GError *error = NULL; + nm_auto_unref_keyfile GKeyFile *keyfile = NULL; + gs_unref_object GOutputStream *stream = NULL; + PrintConnData *print_conn_data; + + if (!nm_connection_normalize(connection, NULL, NULL, &error)) + goto error; + + keyfile = nm_keyfile_write(connection, NM_KEYFILE_HANDLER_FLAGS_NONE, NULL, NULL, &error); + if (!keyfile) + goto error; + + stream = g_unix_output_stream_new(STDOUT_FILENO, FALSE); + print_conn_data = g_slice_new(PrintConnData); + print_conn_data->data = g_key_file_to_data(keyfile, &print_conn_data->length, NULL); + print_conn_data->written = 0; + print_conn_data->nmc = nmc; + print_connection_chunk(stream, print_conn_data); + return; + +error: + g_string_printf(nmc->return_text, _("Error: Error writting connection: %s"), error->message); + nmc->return_value = NMC_RESULT_ERROR_UNKNOWN; + nmc->should_wait--; + quit(); +} + +static const GPtrArray * +nmc_get_connections(const NmCli *nmc) +{ + if (nmc->offline) { + g_return_val_if_fail(!nmc->client, nmc->offline_connections); + return nmc->offline_connections; + } else { + g_return_val_if_fail(nmc->client, NULL); + return nm_client_get_connections(nmc->client); + } +} + +static const GPtrArray * +nmc_get_active_connections(const NmCli *nmc) +{ + static const GPtrArray offline_active_connections = {.len = 0}; + + if (nmc->offline) { + g_return_val_if_fail(!nmc->client, &offline_active_connections); + return &offline_active_connections; + } else { + g_return_val_if_fail(nmc->client, &offline_active_connections); + return nm_client_get_active_connections(nmc->client); + } +} + +/*****************************************************************************/ + /* Essentially a version of nm_setting_connection_get_connection_type() that * prefers an alias instead of the settings name when in pretty print mode. * That is so that we print "wifi" instead of "802-11-wireless" in "nmcli c". */ @@ -942,8 +1068,6 @@ const NmcMetaGenericInfo *const nmc_fields_con_active_details_groups[] = { #define CON_SHOW_DETAIL_GROUP_PROFILE "profile" #define CON_SHOW_DETAIL_GROUP_ACTIVE "active" -static guint progress_id = 0; /* ID of event source for displaying progress */ - /* for readline TAB completion in editor */ typedef struct { NmCli *nmc; @@ -1305,14 +1429,6 @@ usage_connection_migrate(void) "such as \"keyfile\" (default) or \"ifcfg-rh\".\n\n")); } -static void -quit(void) -{ - if (nm_clear_g_source(&progress_id)) - nmc_terminal_erase_line(); - g_main_loop_quit(loop); -} - static char * construct_header_name(const char *base, const char *spec) { @@ -1952,7 +2068,7 @@ con_show_get_items(NmCli *nmc, gboolean active_only, gboolean show_active_fields row_hash = g_hash_table_new(nm_direct_hash, NULL); - arr = nm_client_get_connections(nmc->client); + arr = nmc_get_connections(nmc); for (i = 0; i < arr->len; i++) { /* Note: libnm will not expose connection that are invisible * to the user but currently inactive. @@ -1971,7 +2087,7 @@ con_show_get_items(NmCli *nmc, gboolean active_only, gboolean show_active_fields _metagen_con_show_row_data_new_for_connection(c, show_active_fields)); } - arr = nm_client_get_active_connections(nmc->client); + arr = nmc_get_active_connections(nmc); for (i = 0; i < arr->len; i++) { NMActiveConnection *ac = arr->pdata[i]; @@ -2119,6 +2235,11 @@ get_connection(NmCli *nmc, NM_SET_OUT(out_selector, NULL); NM_SET_OUT(out_value, NULL); + if (nmc->offline_connections && nmc->offline_connections->len) + return nmc->offline_connections->pdata[0]; + + g_return_val_if_fail(!nmc->offline, NULL); + if (*argc == 0) { g_set_error_literal(error, NMCLI_ERROR, @@ -2259,7 +2380,7 @@ do_connections_show(const NMCCommand *cmd, NmCli *nmc, int argc, const char *con } else { gboolean new_line = FALSE; gboolean without_fields = (nmc->required_fields == NULL); - const GPtrArray *active_cons = nm_client_get_active_connections(nmc->client); + const GPtrArray *active_cons = nmc_get_active_connections(nmc); /* multiline mode is default for 'connection show <ID>' */ if (!nmc->mode_specified) @@ -2315,7 +2436,7 @@ do_connections_show(const NMCCommand *cmd, NmCli *nmc, int argc, const char *con } /* Try to find connection by id, uuid or path first */ - connections = nm_client_get_connections(nmc->client); + connections = nmc_get_connections(nmc); con = nmc_find_connection(connections, selector, *argv, @@ -2452,7 +2573,7 @@ get_default_active_connection(NmCli *nmc, NMDevice **device) g_return_val_if_fail(device, NULL); g_return_val_if_fail(*device == NULL, NULL); - connections = nm_client_get_active_connections(nmc->client); + connections = nmc_get_active_connections(nmc); for (i = 0; i < connections->len; i++) { NMActiveConnection *candidate = g_ptr_array_index(connections, i); const GPtrArray *devices; @@ -3276,7 +3397,7 @@ do_connection_down(const NMCCommand *cmd, NmCli *nmc, int argc, const char *cons } /* Get active connections */ - active_cons = nm_client_get_active_connections(nmc->client); + active_cons = nmc_get_active_connections(nmc); while (arg_num > 0) { const char *selector = NULL; @@ -3926,7 +4047,7 @@ set_default_interface_name(NmCli *nmc, NMSettingConnection *s_con) const GPtrArray *connections; gs_free char *ifname = NULL; - connections = nm_client_get_connections(nmc->client); + connections = nmc_get_connections(nmc); ifname = unique_master_iface_ifname(connections, default_name); g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, ifname, NULL); } @@ -4489,7 +4610,7 @@ set_connection_master(NmCli *nmc, } slave_type = nm_setting_connection_get_slave_type(s_con); - connections = nm_client_get_connections(nmc->client); + connections = nmc_get_connections(nmc); value = normalized_master_for_slave(connections, value, slave_type, &slave_type); if (!set_property(nmc->client, @@ -5265,12 +5386,9 @@ connection_warnings(NmCli *nmc, NMConnection *connection) if (deprecated) g_printerr(_("Warning: %s.\n"), deprecated); - connections = nm_client_get_connections(nmc->client); - if (!connections) - return; - - id = nm_connection_get_id(connection); - found = 0; + connections = nmc_get_connections(nmc); + id = nm_connection_get_id(connection); + found = 0; for (i = 0; i < connections->len; i++) { NMConnection *candidate = NM_CONNECTION(connections->pdata[i]); @@ -5348,15 +5466,6 @@ add_connection(NMClient *client, user_data); } -static void -update_connection(NMRemoteConnection *connection, - gboolean temporary, - GAsyncReadyCallback callback, - gpointer user_data) -{ - nm_remote_connection_commit_changes_async(connection, !temporary, NULL, callback, user_data); -} - static gboolean is_single_word(const char *line) { @@ -5662,6 +5771,20 @@ again: } static void +nmc_add_connection(NmCli *nmc, NMConnection *connection, gboolean temporary) +{ + if (nmc->offline) { + nmc_print_connection_and_quit(nmc, connection); + } else { + add_connection(nmc->client, + connection, + temporary, + add_connection_cb, + _add_connection_info_new(nmc, NULL, connection)); + } +} + +static void do_connection_add(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) { gs_unref_object NMConnection *connection = NULL; @@ -5748,7 +5871,7 @@ read_properties: gs_free char *default_name = NULL; const GPtrArray *connections; - connections = nm_client_get_connections(nmc->client); + connections = nmc_get_connections(nmc); try_name = ifname ? g_strdup_printf("%s-%s", get_name_alias_toplevel(type, slave_type), ifname) : g_strdup(get_name_alias_toplevel(type, slave_type)); @@ -5813,11 +5936,7 @@ read_properties: } } - add_connection(nmc->client, - connection, - !save_bool, - add_connection_cb, - _add_connection_info_new(nmc, NULL, connection)); + nmc_add_connection(nmc, connection, !save_bool); nmc->should_wait++; finish: @@ -5839,7 +5958,7 @@ uuid_display_hook(char **array, int len, int max_len) char *tmp; const char *id; for (i = 1; i <= len; i++) { - connections = nm_client_get_connections(nmc_tab_completion.nmc->client); + connections = nmc_get_connections(nmc_tab_completion.nmc); con = nmc_find_connection(connections, "uuid", array[i], NULL, FALSE); id = con ? nm_connection_get_id(con) : NULL; if (id) { @@ -6173,7 +6292,7 @@ gen_vpn_uuids(const char *text, int state) const char **uuids; char *ret; - connections = nm_client_get_connections(nm_cli_global_readline->client); + connections = nmc_get_connections(nm_cli_global_readline); if (connections->len < 1) return NULL; @@ -6190,7 +6309,7 @@ gen_vpn_ids(const char *text, int state) const char **ids; char *ret; - connections = nm_client_get_connections(nm_cli_global_readline->client); + connections = nmc_get_connections(nm_cli_global_readline); if (connections->len < 1) return NULL; @@ -8336,7 +8455,11 @@ editor_menu_main(NmCli *nmc, NMConnection *connection, const char *connection_ty /* Save/update already saved (existing) connection */ nm_connection_replace_settings_from_connection(NM_CONNECTION(rem_con), connection); - update_connection(rem_con, temporary, update_connection_editor_cb, NULL); + nm_remote_connection_commit_changes_async(rem_con, + !temporary, + NULL, + update_connection_editor_cb, + NULL); handler_id = g_signal_connect(rem_con, NM_CONNECTION_CHANGED, @@ -8750,7 +8873,7 @@ do_connection_edit(const NMCCommand *cmd, NmCli *nmc, int argc, const char *cons /* Use ' ' and '.' as word break characters */ rl_completer_word_break_characters = ". "; - connections = nm_client_get_connections(nmc->client); + connections = nmc_get_connections(nmc); if (!con) { if (con_id && !con_uuid && !con_path && !con_filename) { @@ -8932,10 +9055,23 @@ modify_connection_cb(GObject *connection, GAsyncResult *result, gpointer user_da } static void +nmc_update_connection(NmCli *nmc, NMConnection *connection, gboolean temporary) +{ + if (nmc->offline) { + nmc_print_connection_and_quit(nmc, connection); + } else { + nm_remote_connection_commit_changes_async(NM_REMOTE_CONNECTION(connection), + !temporary, + NULL, + modify_connection_cb, + nmc); + } +} + +static void do_connection_modify(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv) { NMConnection *connection = NULL; - NMRemoteConnection *rc = NULL; gs_free_error GError *error = NULL; gboolean temporary = FALSE; @@ -8951,25 +9087,19 @@ do_connection_modify(const NMCCommand *cmd, NmCli *nmc, int argc, const char *co return; } - rc = nm_client_get_connection_by_uuid(nmc->client, nm_connection_get_uuid(connection)); - if (!rc) { - g_string_printf(nmc->return_text, - _("Error: Unknown connection '%s'."), - nm_connection_get_uuid(connection)); - nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND; - return; - } - - if (!nmc_process_connection_properties(nmc, NM_CONNECTION(rc), &argc, &argv, TRUE, &error)) { - g_string_assign(nmc->return_text, error->message); - nmc->return_value = error->code; - return; + /* Don't insist on having argument if we're running in offline mode. */ + if (!nmc->offline || argc > 0) { + if (!nmc_process_connection_properties(nmc, connection, &argc, &argv, TRUE, &error)) { + g_string_assign(nmc->return_text, error->message); + nmc->return_value = error->code; + return; + } } if (nmc->complete) return; - update_connection(rc, temporary, modify_connection_cb, nmc); + nmc_update_connection(nmc, connection, temporary); nmc->should_wait++; } @@ -9267,7 +9397,7 @@ do_connection_monitor(const NMCCommand *cmd, NmCli *nmc, int argc, const char *c /* nmc_do_cmd() should not call this with argc=0. */ g_return_if_fail(!nmc->complete); - connections = nm_client_get_connections(nmc->client); + connections = nmc_get_connections(nmc); } else { while (argc > 0) { if (!get_connection(nmc, &argc, &argv, NULL, NULL, &found_cons, &error)) { @@ -9768,7 +9898,7 @@ do_connection_migrate(const NMCCommand *cmd, NmCli *nmc, int argc, const char *c if (!found_cons) { /* No connections specified explicitly? Fine, add all. */ found_cons = g_ptr_array_new(); - connections = nm_client_get_connections(nmc->client); + connections = nmc_get_connections(nmc); for (i = 0; i < connections->len; i++) { connection = connections->pdata[i]; g_ptr_array_add(found_cons, connection); @@ -9815,7 +9945,7 @@ gen_func_connection_names(const char *text, int state) const char **connection_names; char *ret; - connections = nm_client_get_connections(nm_cli_global_readline->client); + connections = nmc_get_connections(nm_cli_global_readline); if (connections->len == 0) return NULL; @@ -9841,7 +9971,7 @@ gen_func_active_connection_names(const char *text, int state) if (!nm_cli_global_readline->client) return NULL; - acs = nm_client_get_active_connections(nm_cli_global_readline->client); + acs = nmc_get_active_connections(nm_cli_global_readline); if (!acs || acs->len == 0) return NULL; @@ -9905,12 +10035,12 @@ nmc_command_func_connection(const NMCCommand *cmd, NmCli *nmc, int argc, const c {"show", do_connections_show, usage_connection_show, TRUE, TRUE}, {"up", do_connection_up, usage_connection_up, TRUE, TRUE}, {"down", do_connection_down, usage_connection_down, TRUE, TRUE}, - {"add", do_connection_add, usage_connection_add, TRUE, TRUE}, + {"add", do_connection_add, usage_connection_add, TRUE, TRUE, TRUE}, {"edit", do_connection_edit, usage_connection_edit, TRUE, TRUE}, {"delete", do_connection_delete, usage_connection_delete, TRUE, TRUE}, {"reload", do_connection_reload, usage_connection_reload, FALSE, FALSE}, {"load", do_connection_load, usage_connection_load, TRUE, TRUE}, - {"modify", do_connection_modify, usage_connection_modify, TRUE, TRUE}, + {"modify", do_connection_modify, usage_connection_modify, TRUE, TRUE, TRUE, TRUE}, {"clone", do_connection_clone, usage_connection_clone, TRUE, TRUE}, {"import", do_connection_import, usage_connection_import, TRUE, TRUE}, {"export", do_connection_export, usage_connection_export, TRUE, TRUE}, diff --git a/src/nmcli/meson.build b/src/nmcli/meson.build index fab7329ea0..a122e2af3a 100644 --- a/src/nmcli/meson.build +++ b/src/nmcli/meson.build @@ -2,12 +2,10 @@ if enable_nmcli -# The file is called "nmcli-completion" but should be installed with -# name "nmcli". Currently it gets renamed by "tools/meson-post-install.sh", -# but if we depend on meson 0.46.0, we could use "rename" option. install_data( 'nmcli-completion', install_dir: join_paths(nm_datadir, 'bash-completion', 'completions'), + rename: 'nmcli', ) executable( diff --git a/src/nmcli/nmcli.c b/src/nmcli/nmcli.c index 96b8ec4a13..bc37a7f0f8 100644 --- a/src/nmcli/nmcli.c +++ b/src/nmcli/nmcli.c @@ -726,7 +726,7 @@ process_command_line(NmCli *nmc, int argc, char **argv_orig) {"monitor", nmc_command_func_monitor, NULL, TRUE, FALSE}, {"networking", nmc_command_func_networking, NULL, FALSE, FALSE}, {"radio", nmc_command_func_radio, NULL, FALSE, FALSE}, - {"connection", nmc_command_func_connection, NULL, FALSE, FALSE}, + {"connection", nmc_command_func_connection, NULL, FALSE, FALSE, TRUE}, {"device", nmc_command_func_device, NULL, FALSE, FALSE}, {"agent", nmc_command_func_agent, NULL, FALSE, FALSE}, {NULL, nmc_command_func_overview, usage, TRUE, TRUE}, @@ -761,15 +761,16 @@ process_command_line(NmCli *nmc, int argc, char **argv_orig) if (argc == 1 && nmc->complete) { nmc_complete_strings(argv[0], + "--overview", + "--offline", "--terse", "--pretty", "--mode", - "--overview", "--colors", "--escape", "--fields", - "--nocheck", "--get-values", + "--nocheck", "--wait", "--version", "--help"); @@ -783,6 +784,8 @@ process_command_line(NmCli *nmc, int argc, char **argv_orig) if (matches_arg(nmc, &argc, &argv, "-overview", NULL)) { nmc->nmc_config_mutable.overview = TRUE; + } else if (matches_arg(nmc, &argc, &argv, "-offline", NULL)) { + nmc->offline = TRUE; } else if (matches_arg(nmc, &argc, &argv, "-terse", NULL)) { if (nmc->nmc_config.print_output == NMC_PRINT_TERSE) { g_string_printf(nmc->return_text, @@ -1011,6 +1014,8 @@ nmc_cleanup(NmCli *nmc) nm_clear_g_free(&nmc->palette_buffer); + nm_clear_pointer(&nmc->offline_connections, g_ptr_array_unref); + nmc_polkit_agent_fini(nmc); } diff --git a/src/nmcli/nmcli.h b/src/nmcli/nmcli.h index 157aae9982..922e501418 100644 --- a/src/nmcli/nmcli.h +++ b/src/nmcli/nmcli.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ /* - * Copyright (C) 2010 - 2018 Red Hat, Inc. + * Copyright (C) 2010 - 2022 Red Hat, Inc. */ #ifndef NMC_NMCLI_H @@ -84,23 +84,26 @@ typedef struct _NmcMetaGenericInfo NmcMetaGenericInfo; struct _NmcOutputField { const NMMetaAbstractInfo *info; - int width; /* Width in screen columns */ - void *value; /* Value of current field - char* or char** (NULL-terminated array) */ - gboolean value_is_array; /* Whether value is char** instead of char* */ - gboolean free_value; /* Whether to free the value */ - NmcOfFlags flags; /* Flags - whether and how to print values/field names/headers */ - NMMetaColor color; /* Use this color to print value */ + + int width; /* Width in screen columns */ + void *value; /* Value of current field - char* or + * char** (NULL-terminated array) */ + bool value_is_array : 1; /* Whether value is char** instead of char* */ + bool free_value : 1; /* Whether to free the value */ + + NmcOfFlags flags; /* Flags - whether and how to print values/field names/headers */ + NMMetaColor color; /* Use this color to print value */ }; typedef struct _NmcConfig { - NMCPrintOutput print_output; /* Output mode */ - bool use_colors; /* Whether to use colors for output: option '--color' */ - bool multiline_output; /* Multiline output instead of default tabular */ - bool escape_values; /* Whether to escape ':' and '\' in terse tabular mode */ - bool in_editor; /* Whether running the editor - nmcli con edit' */ - bool - show_secrets; /* Whether to display secrets (both input and output): option '--show-secrets' */ - bool overview; /* Overview mode (hide default values) */ + NMCPrintOutput print_output; /* Output mode */ + bool use_colors; /* Whether to use colors for output: option '--color' */ + bool multiline_output : 1; /* Multiline output instead of default tabular */ + bool escape_values : 1; /* Whether to escape ':' and '\' in terse tabular mode */ + bool in_editor : 1; /* Whether running the editor - nmcli con edit' */ + bool show_secrets : 1; /* Whether to display secrets (both input + * and output): option '--show-secrets' */ + bool overview : 1; /* Overview mode (hide default values) */ NmcColorPalette palette; } NmcConfig; @@ -128,21 +131,27 @@ typedef struct _NmCli { GHashTable *pwds_hash; /* Hash table with passwords in passwd-file */ struct _NMPolkitListener *pk_listener; /* polkit agent listener */ - int should_wait; /* Semaphore indicating whether nmcli should not end or not yet */ - gboolean nowait_flag; /* '--nowait' option; used for passing to callbacks */ - gboolean mode_specified; /* Whether tabular/multiline mode was specified via '--mode' option */ + int should_wait; /* Semaphore indicating whether nmcli should not end or not yet */ + + bool nowait_flag : 1; /* '--nowait' option; used for passing to callbacks */ + bool mode_specified : 1; /* Whether tabular/multiline mode was specified via '--mode' option */ + bool offline : 1; /* Communicate the connection data over stdin/stdout + * instead of talking to the daemon. */ + bool ask : 1; /* Ask for missing parameters: option '--ask' */ + bool complete : 1; /* Autocomplete the command line */ + bool editor_status_line : 1; /* Whether to display status line in connection editor */ + bool editor_save_confirmation : 1; /* Whether to ask for confirmation on + * saving connections with 'autoconnect=yes' */ + union { const NmcConfig nmc_config; NmcConfig nmc_config_mutable; }; - char *required_fields; /* Required fields in output: '--fields' option */ - gboolean ask; /* Ask for missing parameters: option '--ask' */ - gboolean complete; /* Autocomplete the command line */ - gboolean editor_status_line; /* Whether to display status line in connection editor */ - gboolean - editor_save_confirmation; /* Whether to ask for confirmation on saving connections with 'autoconnect=yes' */ + char *required_fields; /* Required fields in output: '--fields' option */ char *palette_buffer; /* Buffer with sequences for terminal-colors.d(5)-based coloring. */ + + GPtrArray *offline_connections; } NmCli; extern const NmCli *const nm_cli_global_readline; @@ -176,8 +185,15 @@ typedef struct _NMCCommand { const char *cmd; void (*func)(const struct _NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv); void (*usage)(void); - bool needs_client; - bool needs_nm_running; + + bool needs_client : 1; /* Ensure a client instance is there before calling + * the handler (unless --offline has been given). */ + bool needs_nm_running : 1; /* Client instance exists *and* the service is + * actually present on the bus. */ + bool supports_offline : 1; /* Run the handler without a client even if the + * comand usually requires one if --offline option was used. */ + bool needs_offline_conn : 1; /* With --online, read in a keyfile from + * standard input before dispatching the handler. */ } NMCCommand; void nmc_command_func_agent(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv); diff --git a/src/nmtui/nmt-connect-connection-list.c b/src/nmtui/nmt-connect-connection-list.c index 535cf8fd26..f3197544b5 100644 --- a/src/nmtui/nmt-connect-connection-list.c +++ b/src/nmtui/nmt-connect-connection-list.c @@ -101,6 +101,7 @@ static const char *device_sort_order[] = {"NMDeviceEthernet", NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_IP_TUNNEL_SETTING_NAME, NM_SETTING_WIREGUARD_SETTING_NAME, + NM_SETTING_TUN_SETTING_NAME, "NMDeviceModem", "NMDeviceBt"}; static const int device_sort_order_len = G_N_ELEMENTS(device_sort_order); diff --git a/src/tests/client/test-client.check-on-disk/test_offline.expected b/src/tests/client/test-client.check-on-disk/test_offline.expected new file mode 100644 index 0000000000..f6f11ba443 --- /dev/null +++ b/src/tests/client/test-client.check-on-disk/test_offline.expected @@ -0,0 +1,137 @@ +size: 258 +location: src/tests/client/test-client.py:test_offline()/1 +cmd: $NMCLI g +lang: C +returncode: 1 +stderr: 136 bytes +>>> +Error: Could not create NMClient object: Key/Value pair 0, 'invalid', in address element 'very:invalid' does not contain an equal sign. + +<<< +size: 319 +location: src/tests/client/test-client.py:test_offline()/2 +cmd: $NMCLI --offline c add type ethernet +lang: C +returncode: 0 +stdout: 169 bytes +>>> +[connection] +id=ethernet +uuid=UUID-WAS-HERE-BUT-IS-NO-MORE-SADLY +type=ethernet + +[ethernet] + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=stable-privacy +method=auto + +[proxy] + +<<< +size: 183 +location: src/tests/client/test-client.py:test_offline()/3 +cmd: $NMCLI --offline c show +lang: C +returncode: 2 +stderr: 47 bytes +>>> +Error: command doesn't support --offline mode. + +<<< +size: 178 +location: src/tests/client/test-client.py:test_offline()/4 +cmd: $NMCLI --offline g +lang: C +returncode: 2 +stderr: 47 bytes +>>> +Error: command doesn't support --offline mode. + +<<< +size: 176 +location: src/tests/client/test-client.py:test_offline()/5 +cmd: $NMCLI --offline +lang: C +returncode: 2 +stderr: 47 bytes +>>> +Error: command doesn't support --offline mode. + +<<< +size: 443 +location: src/tests/client/test-client.py:test_offline()/6 +cmd: $NMCLI --offline c add type wifi ssid lala 802-1x.eap pwd 802-1x.identity foo 802-1x.password bar +lang: C +returncode: 0 +stdout: 232 bytes +>>> +[connection] +id=wifi +uuid=UUID-WAS-HERE-BUT-IS-NO-MORE-SADLY +type=wifi + +[wifi] +mode=infrastructure +ssid=lala + +[802-1x] +eap=pwd; +identity=foo +password=bar + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=stable-privacy +method=auto + +[proxy] + +<<< +size: 481 +location: src/tests/client/test-client.py:test_offline()/7 +cmd: $NMCLI --offline c add type wifi ssid lala 802-1x.eap pwd 802-1x.identity foo 802-1x.password bar 802-1x.password-flags agent-owned +lang: C +returncode: 0 +stdout: 236 bytes +>>> +[connection] +id=wifi +uuid=UUID-WAS-HERE-BUT-IS-NO-MORE-SADLY +type=wifi + +[wifi] +mode=infrastructure +ssid=lala + +[802-1x] +eap=pwd; +identity=foo +password-flags=1 + +[ipv4] +method=auto + +[ipv6] +addr-gen-mode=stable-privacy +method=auto + +[proxy] + +<<< +size: 199 +location: src/tests/client/test-client.py:test_offline()/8 +cmd: $NMCLI --complete-args --offline conn modify ipv6.ad +lang: C +returncode: 0 +stdout: 34 bytes +>>> +ipv6.addresses +ipv6.addr-gen-mode + +<<< diff --git a/src/tests/client/test-client.py b/src/tests/client/test-client.py index d025d12ead..f322a94def 100755 --- a/src/tests/client/test-client.py +++ b/src/tests/client/test-client.py @@ -1,4 +1,5 @@ #!/usr/bin/env python +# coding: utf-8 from __future__ import print_function @@ -16,7 +17,7 @@ from __future__ import print_function # When adjusting the tests, or when making changes to nmcli that intentionally # change the output, the expected output must be regenerated. # -# For that, you'd setup your system correctly (see below) and then simply: +# For that, you'd setup your system correctly (see SETUP below) and then simply: # # $ NM_TEST_REGENERATE=1 make check-local-tests-client # # Or `NM_TEST_REGENERATE=1 make check -j 10` @@ -24,7 +25,17 @@ from __future__ import print_function # # The previous step regenerated the expected output. Review the changes # # and consider whether they are correct. Then commit the changes to git. # -# Setup: For regenerating the output, the translations must work. First: +# With meson, you can do +# $ meson -Ddocs=true --prefix=/tmp/nm1 build +# $ ninja -C build +# $ ninja -C build install +# $ NM_TEST_REGENERATE=1 ninja -C build test +# +# Beware that you need to install the sources, and beware to choose a prefix that doesn't +# mess up your system (see SETUP below). +# +# SETUP: For regenerating the output, the translations must work. First +# test whether the following works: # # 1) LANG=pl_PL.UTF-8 /usr/bin/nmcli --version # # Ensure that Polish output works for the system-installed nmcli. @@ -35,6 +46,7 @@ from __future__ import print_function # # On Debian, you might do: # # sed -i 's/^# \(pl_PL.UTF-8 .*\)$/\1/p' /etc/locale.gen # # locale-gen pl_PL.UTF-8 +# # On Fedora, you might install `glibc-langpack-pl` package. # # 2) LANG=pl_PL.UTF-8 ./src/nmcli/nmcli --version # # Ensure that the built nmcli has Polish locale working. If not, @@ -203,6 +215,13 @@ class Util: return isinstance(s, t) @staticmethod + def as_bytes(s): + if Util.is_string(s): + return s.encode("utf-8") + assert isinstance(s, bytes) + return s + + @staticmethod def memoize_nullary(nullary_func): result = [] @@ -335,6 +354,48 @@ class Util: return None @staticmethod + def _replace_text_match_join(split_arr, replacement): + yield split_arr[0] + for t in split_arr[1:]: + yield (replacement,) + yield t + + @staticmethod + def ReplaceTextSimple(search, replacement): + # This gives a function that can be used by Util.replace_text(). + # The function replaces an input bytes string @t. It must either return + # a bytes string, a list containing bytes strings and/or 1-tuples (the + # latter containing one bytes string). + # The 1-tuple acts as a placeholder for atomic text, that cannot be replaced + # a second time. + # + # Search for replace_text_fcn in Util.replace_text() where this is called. + replacement = Util.as_bytes(replacement) + + if callable(search): + search_fcn = search + else: + search_fcn = lambda: search + + def replace_fcn(t): + assert isinstance(t, bytes) + search_txt = search_fcn() + if search_txt is None: + return t + search_txt = Util.as_bytes(search_txt) + return Util._replace_text_match_join(t.split(search_txt), replacement) + + return replace_fcn + + @staticmethod + def ReplaceTextRegex(pattern, replacement): + # See ReplaceTextSimple. + pattern = Util.as_bytes(pattern) + replacement = Util.as_bytes(replacement) + p = re.compile(pattern) + return lambda t: Util._replace_text_match_join(p.split(t), replacement) + + @staticmethod def replace_text(text, replace_arr): if not replace_arr: return text @@ -342,27 +403,17 @@ class Util: if needs_encode: text = text.encode("utf-8") text = [text] - for replace in replace_arr: - try: - v_search = replace[0]() - except TypeError: - v_search = replace[0] - assert v_search is None or Util.is_string(v_search) - if not v_search: - continue - v_replace = replace[1] - v_search = v_search.encode("utf-8") - v_replace = v_replace.encode("utf-8") + for replace_text_fcn in replace_arr: text2 = [] for t in text: - if isinstance(t, tuple): + # tuples are markers for atomic strings. They won't be replaced a second + # time. + if not isinstance(t, tuple): + t = replace_text_fcn(t) + if isinstance(t, bytes) or isinstance(t, tuple): text2.append(t) - continue - t2 = t.split(v_search) - text2.append(t2[0]) - for t3 in t2[1:]: - text2.append((v_replace,)) - text2.append(t3) + else: + text2.extend(t) text = text2 bb = b"".join([(t[0] if isinstance(t, tuple) else t) for t in text]) if needs_encode: @@ -657,13 +708,25 @@ class AsyncProcess: class NmTestBase(unittest.TestCase): - pass + def __init__(self, *args, **kwargs): + self._calling_num = {} + self._skip_test_for_l10n_diff = [] + self._async_jobs = [] + self._results = [] + self.srv = None + return unittest.TestCase.__init__(self, *args, **kwargs) MAX_JOBS = 15 class TestNmcli(NmTestBase): + def ReplaceTextConUuid(self, con_name, replacement): + return Util.ReplaceTextSimple( + Util.memoize_nullary(lambda: self.srv.findConnectionUuid(con_name)), + replacement, + ) + @staticmethod def _read_expected(filename): results_expect = [] @@ -837,9 +900,6 @@ class TestNmcli(NmTestBase): self.fail("invalid language %s" % (lang)) env = {} - if extra_env is not None: - for k, v in extra_env.items(): - env[k] = v for k in ["LD_LIBRARY_PATH", "DBUS_SESSION_BUS_ADDRESS"]: val = os.environ.get(k, None) if val is not None: @@ -856,6 +916,9 @@ class TestNmcli(NmTestBase): env["NM_TEST_CALLING_NUM"] = str(calling_num) if fatal_warnings is _DEFAULT_ARG or fatal_warnings: env["G_DEBUG"] = "fatal-warnings" + if extra_env is not None: + for k, v in extra_env.items(): + env[k] = v args = [conf.get(ENV_NM_TEST_CLIENT_NMCLI_PATH)] + list(args) @@ -1012,20 +1075,13 @@ class TestNmcli(NmTestBase): def async_wait(self): return self.async_start(wait_all=True) - def _nm_test_pre(self): - self._calling_num = {} - self._skip_test_for_l10n_diff = [] - self._async_jobs = [] - self._results = [] - - self.srv = NMStubServer(self._testMethodName) - def _nm_test_post(self): self.async_wait() - self.srv.shutdown() - self.srv = None + if self.srv is not None: + self.srv.shutdown() + self.srv = None self._calling_num = None @@ -1130,7 +1186,14 @@ class TestNmcli(NmTestBase): def nm_test(func): def f(self): - self._nm_test_pre() + self.srv = NMStubServer(self._testMethodName) + func(self) + self._nm_test_post() + + return f + + def nm_test_no_dbus(func): + def f(self): func(self) self._nm_test_post() @@ -1229,10 +1292,7 @@ class TestNmcli(NmTestBase): replace_uuids = [] replace_uuids.append( - ( - Util.memoize_nullary(lambda: self.srv.findConnectionUuid("con-xx1")), - "UUID-con-xx1-REPLACED-REPLACED-REPLA", - ) + self.ReplaceTextConUuid("con-xx1", "UUID-con-xx1-REPLACED-REPLACED-REPLA") ) self.call_nmcli( @@ -1245,9 +1305,8 @@ class TestNmcli(NmTestBase): for con_name, apn in con_gsm_list: replace_uuids.append( - ( - Util.memoize_nullary(lambda: self.srv.findConnectionUuid(con_name)), - "UUID-" + con_name + "-REPLACED-REPLACED-REPL", + self.ReplaceTextConUuid( + con_name, "UUID-" + con_name + "-REPLACED-REPLACED-REPL" ) ) @@ -1278,10 +1337,7 @@ class TestNmcli(NmTestBase): ) replace_uuids.append( - ( - Util.memoize_nullary(lambda: self.srv.findConnectionUuid("ethernet")), - "UUID-ethernet-REPLACED-REPLACED-REPL", - ) + self.ReplaceTextConUuid("ethernet", "UUID-ethernet-REPLACED-REPLACED-REPL") ) self.call_nmcli( @@ -1410,10 +1466,7 @@ class TestNmcli(NmTestBase): replace_uuids = [] replace_uuids.append( - ( - Util.memoize_nullary(lambda: self.srv.findConnectionUuid("con-xx1")), - "UUID-con-xx1-REPLACED-REPLACED-REPLA", - ) + self.ReplaceTextConUuid("con-xx1", "UUID-con-xx1-REPLACED-REPLACED-REPLA") ) self.call_nmcli( @@ -1459,10 +1512,7 @@ class TestNmcli(NmTestBase): self.async_wait() replace_uuids.append( - ( - Util.memoize_nullary(lambda: self.srv.findConnectionUuid("con-vpn-1")), - "UUID-con-vpn-1-REPLACED-REPLACED-REP", - ) + self.ReplaceTextConUuid("con-vpn-1", "UUID-con-vpn-1-REPLACED-REPLACED-REP") ) self.call_nmcli( @@ -1672,6 +1722,104 @@ class TestNmcli(NmTestBase): replace_cmd=replace_uuids, ) + @nm_test_no_dbus + def test_offline(self): + + # Make sure we're not using D-Bus + no_dbus_env = { + "DBUS_SYSTEM_BUS_ADDRESS": "very:invalid", + "DBUS_SESSION_BUS_ADDRESS": "very:invalid", + } + + # This check just makes sure the above works and the + # "nmcli g" command indeed fails talking to D-Bus + self.call_nmcli( + ["g"], + extra_env=no_dbus_env, + replace_stderr=[ + Util.ReplaceTextRegex( + # depending on glib version, it prints `%s', '%s', or ā%sā. + # depending on libc version, it converts unicode to ? or *. + r"Key/Value pair 0, [`*?']invalid[*?'], in address element [`*?']very:invalid[*?'] does not contain an equal sign", + "Key/Value pair 0, 'invalid', in address element 'very:invalid' does not contain an equal sign", + ) + ], + ) + + replace_uuids = [ + Util.ReplaceTextRegex( + r"\buuid=[-a-f0-9]+\b", "uuid=UUID-WAS-HERE-BUT-IS-NO-MORE-SADLY" + ) + ] + + self.call_nmcli( + ["--offline", "c", "add", "type", "ethernet"], + extra_env=no_dbus_env, + replace_stdout=replace_uuids, + ) + + self.call_nmcli( + ["--offline", "c", "show"], + extra_env=no_dbus_env, + ) + + self.call_nmcli( + ["--offline", "g"], + extra_env=no_dbus_env, + ) + + self.call_nmcli( + ["--offline"], + extra_env=no_dbus_env, + ) + + self.call_nmcli( + [ + "--offline", + "c", + "add", + "type", + "wifi", + "ssid", + "lala", + "802-1x.eap", + "pwd", + "802-1x.identity", + "foo", + "802-1x.password", + "bar", + ], + extra_env=no_dbus_env, + replace_stdout=replace_uuids, + ) + + self.call_nmcli( + [ + "--offline", + "c", + "add", + "type", + "wifi", + "ssid", + "lala", + "802-1x.eap", + "pwd", + "802-1x.identity", + "foo", + "802-1x.password", + "bar", + "802-1x.password-flags", + "agent-owned", + ], + extra_env=no_dbus_env, + replace_stdout=replace_uuids, + ) + + self.call_nmcli( + ["--complete-args", "--offline", "conn", "modify", "ipv6.ad"], + extra_env=no_dbus_env, + ) + ############################################################################### diff --git a/tools/meson-post-install.sh b/tools/meson-post-install.sh index 897a8c5c76..88e30ccfc1 100755 --- a/tools/meson-post-install.sh +++ b/tools/meson-post-install.sh @@ -14,11 +14,6 @@ install_systemdunitdir="${11}" [ -n "$DESTDIR" ] && DESTDIR="${DESTDIR%%/}/" -if [ -f "${DESTDIR}${nm_datadir}/bash-completion/completions/nmcli-completion" ]; then - mv "${DESTDIR}${nm_datadir}/bash-completion/completions/nmcli-completion" \ - "${DESTDIR}${nm_datadir}/bash-completion/completions/nmcli" -fi - if [ -x "${DESTDIR}${nm_bindir}/nmtui" ]; then for alias in nmtui-connect nmtui-edit nmtui-hostname; do ln -sf nmtui "${DESTDIR}${nm_bindir}/$alias" |