summary refs log tree commit diff
path: root/contrib/fedora
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/fedora')
-rwxr-xr-xcontrib/fedora/REQUIRED_PACKAGES108
-rw-r--r--contrib/fedora/rpm/00-server.conf14
-rw-r--r--contrib/fedora/rpm/20-connectivity-fedora.conf10
-rw-r--r--contrib/fedora/rpm/20-connectivity-redhat.conf10
-rw-r--r--contrib/fedora/rpm/22-wifi-mac-addr.conf31
-rw-r--r--contrib/fedora/rpm/70-nm-connectivity.conf15
-rw-r--r--contrib/fedora/rpm/NetworkManager.conf52
-rw-r--r--contrib/fedora/rpm/NetworkManager.spec1307
-rw-r--r--contrib/fedora/rpm/README27
-rwxr-xr-xcontrib/fedora/rpm/build.sh288
-rwxr-xr-xcontrib/fedora/rpm/build_clean.sh303
-rwxr-xr-xcontrib/fedora/rpm/configure-for-system.sh526
-rwxr-xr-xcontrib/fedora/rpm/mockbuild.sh20
-rw-r--r--contrib/fedora/rpm/readme-ifcfg-rh-migrated.txt84
-rw-r--r--contrib/fedora/rpm/readme-ifcfg-rh.txt63
-rwxr-xr-xcontrib/fedora/rpm/release.sh604
-rwxr-xr-xcontrib/fedora/utils/makerepo.sh698
17 files changed, 4160 insertions, 0 deletions
diff --git a/contrib/fedora/REQUIRED_PACKAGES b/contrib/fedora/REQUIRED_PACKAGES
new file mode 100755
index 00000000..38ca9026
--- /dev/null
+++ b/contrib/fedora/REQUIRED_PACKAGES
@@ -0,0 +1,108 @@
+#!/bin/bash
+
+# A list of packages useful/needed to build and develop
+# NetworkManager on Fedora and RHEL.
+#
+# Not all of these packages are available, depending
+# on your distribution/release. But yum will happily
+# skip them.
+#
+# Not all of these packages are strictly speaking necessary.
+# This is a generous list of related packages.
+
+set -xe
+
+DNF="$(command -v dnf &>/dev/null && echo dnf || echo yum)"
+
+SUDO=
+[ "$EUID" -eq 0 ] || SUDO=sudo
+
+install() {
+    if [ "$NM_INSTALL" != "" ]; then
+        $NM_INSTALL "$@"
+    else
+        $SUDO "$DNF" install -y "$@"
+    fi
+}
+
+install_ignore_missing() {
+    for p; do
+        install "$p" || :
+    done
+}
+
+if test "$NM_NO_EXTRA" != 1; then
+    # these packages are convenient for developing, but not necessary
+    # for CI testing.
+    EXTRA_PACKAGES=(
+        bash-completion \
+        cscope \
+    )
+else
+    EXTRA_PACKAGES=()
+fi
+
+install \
+    /usr/bin/clang-format \
+    /usr/bin/xargs \
+    ModemManager-devel \
+    ModemManager-glib-devel \
+    audit-libs-devel \
+    bluez-libs-devel \
+    clang \
+    dbus-devel \
+    dbus-x11 \
+    dhclient \
+    firewalld-filesystem \
+    gcc-c++ \
+    gettext-devel \
+    git \
+    glib2-doc \
+    gnutls-devel \
+    gobject-introspection-devel \
+    gtk-doc \
+    iptables \
+    jansson-devel \
+    jq \
+    libcurl-devel \
+    libndp-devel \
+    libselinux-devel \
+    libtool \
+    libuuid-devel \
+    make \
+    meson \
+    mobile-broadband-provider-info-devel \
+    newt-devel \
+    nss-devel \
+    polkit-devel \
+    ppp \
+    ppp-devel \
+    python3-dbus \
+    python3-gobject \
+    python3-pexpect \
+    readline-devel \
+    rpm-build \
+    systemd-devel \
+    teamd-devel \
+    util-linux \
+    vala \
+    valgrind \
+    which \
+    "${EXTRA_PACKAGES[@]}"
+
+# some packages don't exist in certain distributions. Install them one-by-one, and ignore errors.
+install_ignore_missing \
+    black \
+    dbus-python \
+    iproute-tc \
+    libasan \
+    libpsl-devel \
+    libubsan \
+    libvala-devel \
+    pexpect \
+    pygobject3-base \
+    python-gobject-base \
+    python36-pexpect \
+    qt-devel \
+    vala-devel \
+    #end
diff --git a/contrib/fedora/rpm/00-server.conf b/contrib/fedora/rpm/00-server.conf
new file mode 100644
index 00000000..ba3d29fb
--- /dev/null
+++ b/contrib/fedora/rpm/00-server.conf
@@ -0,0 +1,14 @@
+# This configuration file changes NetworkManager's behavior to
+# what's expected on "traditional UNIX server" type deployments.
+#
+# See "man NetworkManager.conf" for more information about these
+# and other keys.
+
+[main]
+# Do not do automatic (DHCP/SLAAC) configuration on ethernet devices
+# with no other matching connections.
+no-auto-default=*
+
+# Ignore the carrier (cable plugged in) state when attempting to
+# activate static-IP connections.
+ignore-carrier=*
diff --git a/contrib/fedora/rpm/20-connectivity-fedora.conf b/contrib/fedora/rpm/20-connectivity-fedora.conf
new file mode 100644
index 00000000..5c9476a0
--- /dev/null
+++ b/contrib/fedora/rpm/20-connectivity-fedora.conf
@@ -0,0 +1,10 @@
+# Enable connectivity checking for NetworkManager.
+# See `man NetworkManager.conf`.
+#
+# Note that connectivity checking works badly with rp_filter set to
+# strict. Check "/proc/sys/net/ipv4/conf/*/rp_filter".
+[connectivity]
+enabled=true
+uri=http://fedoraproject.org/static/hotspot.txt
+response=OK
+interval=300
diff --git a/contrib/fedora/rpm/20-connectivity-redhat.conf b/contrib/fedora/rpm/20-connectivity-redhat.conf
new file mode 100644
index 00000000..070f030b
--- /dev/null
+++ b/contrib/fedora/rpm/20-connectivity-redhat.conf
@@ -0,0 +1,10 @@
+# Enable connectivity checking for NetworkManager.
+# See `man NetworkManager.conf`.
+#
+# Note that connectivity checking works badly with rp_filter set to
+# strict. Check "/proc/sys/net/ipv4/conf/*/rp_filter".
+[connectivity]
+enabled=true
+uri=http://static.redhat.com/test/rhel-networkmanager.txt
+response=OK
+interval=300
diff --git a/contrib/fedora/rpm/22-wifi-mac-addr.conf b/contrib/fedora/rpm/22-wifi-mac-addr.conf
new file mode 100644
index 00000000..2e329c88
--- /dev/null
+++ b/contrib/fedora/rpm/22-wifi-mac-addr.conf
@@ -0,0 +1,31 @@
+# This sets defaults for Wi-Fi profiles to set a generated, stable MAC address.
+#
+# Do not modify this file. You can hide/overwrite this file by placing a file
+# to "/etc/NetworkManager/conf.d/22-wifi-mac-addr.conf". You can also add
+# configuration snippets with higher priority that override this setting (see
+# `man 5 NetworkManager.conf`). Most importantly, this snippet only sets
+# default values for the profile. You can explicitly set the value for each
+# profile, so that this default value is not used.
+#
+# For example, on a particular profile/network set
+#
+#   $ nmcli connection modify "$PROFILE" wifi.cloned-mac-address permanent
+#
+# to use the hardware MAC address. This prevents the default from this file
+# to take effect.
+#
+# Or
+#
+#   $ nmcli connection modify "$PROFILE" wifi.cloned-mac-address stable connection.stable-id '${NETWORK_SSID}/${BOOT}'
+#
+# to get a generated MAC address that changes on each boot. Note how setting
+# "connection.stable-id" also affects other aspects of the profile.
+#
+# See `man 5 nm-settings` for "wifi.cloned-mac-address" and "connection.stable-id".
+
+[connection.22-wifi-mac-addr]
+match-device=type:wifi
+wifi.cloned-mac-address=stable-ssid
+
+[.config]
+enable=nm-version-min:1.45
diff --git a/contrib/fedora/rpm/70-nm-connectivity.conf b/contrib/fedora/rpm/70-nm-connectivity.conf
new file mode 100644
index 00000000..0e4b0e27
--- /dev/null
+++ b/contrib/fedora/rpm/70-nm-connectivity.conf
@@ -0,0 +1,15 @@
+# The Strict mode of RFC3704 Reverse Path filtering breaks some pretty
+# common and reasonable use cases.
+#
+# Notably, it makes it impossible for NetworkManager to do connectivity
+# check on a newly arriving default route (it starts with a higher metric
+# and is bumped lower if there's connectivity).
+#
+# Kernel's default is 0 (no filter), systemd configures a Loose filter since
+# commit 230450d4e4f1 ('sysctl.d: switch net.ipv4.conf.all.rp_filter from 1
+# to 2'). However, RHEL systemd package happens to default to Strict mode
+# for historic reasons. Let's override it if we're doing connectivity
+# checking.
+
+# Source route verification
+net.ipv4.conf.all.rp_filter = 0
diff --git a/contrib/fedora/rpm/NetworkManager.conf b/contrib/fedora/rpm/NetworkManager.conf
new file mode 100644
index 00000000..287c9d01
--- /dev/null
+++ b/contrib/fedora/rpm/NetworkManager.conf
@@ -0,0 +1,52 @@
+# Configuration file for NetworkManager.
+#
+# See "man 5 NetworkManager.conf" for details.
+#
+# The directories /usr/lib/NetworkManager/conf.d/ and /run/NetworkManager/conf.d/
+# can contain additional .conf snippets installed by packages. These files are
+# read before NetworkManager.conf and have thus lowest priority.
+# The directory /etc/NetworkManager/conf.d/ can contain additional .conf
+# snippets. Those snippets are merged last and overwrite the settings from this main
+# file.
+#
+# The files within one conf.d/ directory are read in asciibetical order.
+#
+# You can prevent loading a file /usr/lib/NetworkManager/conf.d/NAME.conf
+# by having a file NAME.conf in either /run/NetworkManager/conf.d/ or /etc/NetworkManager/conf.d/.
+# Likewise, snippets from /run can be prevented from loading by placing
+# a file with the same name in /etc/NetworkManager/conf.d/.
+#
+# If two files define the same key, the one that is read afterwards will overwrite
+# the previous one.
+
+[main]
+#plugins=keyfile,ifcfg-rh
+
+
+[logging]
+# When debugging NetworkManager, enabling debug logging is of great help.
+#
+# Logfiles contain no passwords and little sensitive information. But please
+# check before posting the file online. You can also personally hand over the
+# logfile to a NM developer to treat it confidential. Meet us on #nm on Libera.Chat.
+#
+# You can also change the log-level at runtime via
+#   $ nmcli general logging level TRACE domains ALL
+# However, usually it's cleaner to enable debug logging
+# in the configuration and restart NetworkManager so that
+# debug logging is enabled from the start.
+#
+# You will find the logfiles in syslog, for example via
+#   $ journalctl -u NetworkManager
+#
+# Please post full logfiles for bug reports without pre-filtering or truncation.
+# Also, for debugging the entire `journalctl` output can be interesting. Don't
+# limit unnecessarily with `journalctl -u`. Exceptions are if you are worried
+# about private data. Check before posting logfiles!
+#
+# Note that debug logging of NetworkManager can be quite verbose. Some messages
+# might be rate-limited by the logging daemon (see RateLimitIntervalSec, RateLimitBurst
+# in man journald.conf). Please disable rate-limiting before collecting debug logs!
+#
+#level=TRACE
+#domains=ALL
diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec
new file mode 100644
index 00000000..f55d243d
--- /dev/null
+++ b/contrib/fedora/rpm/NetworkManager.spec
@@ -0,0 +1,1307 @@
+# SPEC file to build NetworkManager for testing. It aims for a similar
+# configuration as rhel-7.0 and Fedora rawhide
+#
+# This spec file is not used as is to create official packages for RHEL, Fedora or any
+# other distribution.
+#
+# Note that it contains __PLACEHOLDERS__ that will be replaced by the accompanying 'build.sh' script.
+
+
+%global wpa_supplicant_version 1:1.1
+
+%global ppp_version %(pkg-config --modversion pppd 2>/dev/null || sed -n 's/^#define\\s*VERSION\\s*"\\([^\\s]*\\)"$/\\1/p' %{_includedir}/pppd/patchlevel.h 2>/dev/null | grep . || echo bad)
+%global glib2_version %(pkg-config --modversion glib-2.0 2>/dev/null || echo bad)
+
+%global epoch_version 1
+%global real_version __VERSION__
+%global rpm_version %{real_version}
+%global release_version __RELEASE_VERSION__
+%global snapshot __SNAPSHOT__
+%global git_sha __COMMIT__
+%global bcond_default_debug __BCOND_DEFAULT_DEBUG__
+%global bcond_default_lto __BCOND_DEFAULT_LTO__
+%global bcond_default_test __BCOND_DEFAULT_TEST__
+
+%global obsoletes_device_plugins     1:0.9.9.95-1
+%global obsoletes_ppp_plugin         1:1.5.3
+%global obsoletes_initscripts_updown 1:1.36.0-0.6
+%global obsoletes_ifcfg_rh           1:1.36.2
+
+%global nmlibdir %{_prefix}/lib/%{name}
+%global nmplugindir %{_libdir}/%{name}/%{version}-%{release}
+
+%global _hardened_build 1
+
+%if "x%{?snapshot}" != "x"
+%global snapshot_dot .%{snapshot}
+%endif
+%if "x%{?git_sha}" != "x"
+%global git_sha_dot .%{git_sha}
+%endif
+
+%global snap %{?snapshot_dot}%{?git_sha_dot}
+
+%global real_version_major %(printf '%s' '%{real_version}' | sed -n 's/^\\([1-9][0-9]*\\.[0-9][0-9]*\\)\\.[0-9][0-9]*$/\\1/p')
+
+%global systemd_units NetworkManager.service NetworkManager-wait-online.service NetworkManager-dispatcher.service nm-priv-helper.service
+
+%global systemd_units_cloud_setup nm-cloud-setup.service nm-cloud-setup.timer
+
+###############################################################################
+%if 0%{?fedora} > 40
+%bcond_without meson
+%else
+%bcond_with    meson
+%endif
+%bcond_without adsl
+%bcond_without bluetooth
+%bcond_without wwan
+%if 0%{?rhel} >= 10
+%bcond_with team
+%else
+%bcond_without team
+%endif
+%bcond_without wifi
+%bcond_without ovs
+%bcond_without ppp
+%bcond_without nmtui
+%bcond_without nm_cloud_setup
+%bcond_without regen_docs
+%if %{bcond_default_debug}
+%bcond_without debug
+%else
+%bcond_with    debug
+%endif
+%if %{bcond_default_test}
+%bcond_without test
+%else
+%bcond_with    test
+%endif
+%if "%{?bcond_default_lto}" == ""
+%if 0%{?fedora} >= 33 || 0%{?rhel} >= 9
+%bcond_without lto
+%else
+%bcond_with    lto
+%endif
+%else
+%if %{bcond_default_lto}
+%bcond_without lto
+%else
+%bcond_with    lto
+%endif
+%endif
+%bcond_with    sanitizer
+%if 0%{?fedora}
+%bcond_without connectivity_fedora
+%else
+%bcond_with connectivity_fedora
+%endif
+%if 0%{?rhel} && 0%{?rhel} >= 8
+%bcond_without connectivity_redhat
+%else
+%bcond_with connectivity_redhat
+%endif
+%if 0%{?fedora} >= 29 || 0%{?rhel} >= 8
+%bcond_without crypto_gnutls
+%else
+%bcond_with crypto_gnutls
+%endif
+%if 0%{?rhel}
+%bcond_with iwd
+%else
+%bcond_without iwd
+%endif
+%if 0%{?fedora} >= 32 || 0%{?rhel} >= 8
+%bcond_without firewalld_zone
+%else
+%bcond_with firewalld_zone
+%endif
+
+###############################################################################
+
+%if 0%{?fedora} || 0%{?rhel} >= 8
+%global dbus_version 1.9.18
+%global dbus_sys_dir %{_datadir}/dbus-1/system.d
+%else
+%global dbus_version 1.1
+%global dbus_sys_dir %{_sysconfdir}/dbus-1/system.d
+%endif
+
+# Older libndp versions use select() (rh#1933041). On well known distros,
+# choose a version that has the necessary fix.
+%if 0%{?rhel} && 0%{?rhel} == 8
+%global libndp_version 1.7-4
+%else
+%global libndp_version %{nil}
+%endif
+
+%if %{with bluetooth} || %{with wwan}
+%global with_modem_manager_1 1
+%else
+%global with_modem_manager_1 0
+%endif
+
+%if 0%{?fedora} >= 31 || 0%{?rhel} >= 8
+%global dhcp_default internal
+%else
+%global dhcp_default dhclient
+%endif
+
+%if 0%{?fedora} || 0%{?rhel} >= 8
+%global logging_backend_default journal
+%if 0%{?fedora} || 0%{?rhel} >= 9
+%global dns_rc_manager_default auto
+%else
+%global dns_rc_manager_default symlink
+%endif
+%else
+%global logging_backend_default syslog
+%global dns_rc_manager_default file
+%endif
+
+%if 0%{?fedora} >= 33 || 0%{?rhel} >= 9
+%global config_plugins_default_ifcfg_rh 0
+%else
+%global config_plugins_default_ifcfg_rh 1
+%endif
+
+%if 0%{?rhel} >= 10
+%global with_ifcfg_rh 0
+%global split_ifcfg_rh 0
+%elif 0%{?fedora} >= 36
+%global with_ifcfg_rh 1
+%global split_ifcfg_rh 1
+%else
+%global with_ifcfg_rh 1
+%global split_ifcfg_rh 0
+%endif
+
+%if (0%{?fedora} >= 36 && 0%{?fedora} < 39) || 0%{?rhel} == 9
+%global ifcfg_warning 1
+%else
+%global ifcfg_warning 0
+%endif
+
+%if 0%{?fedora} >= 39
+%global ifcfg_migrate 1
+%else
+%global ifcfg_migrate 0
+%endif
+
+%if 0%{?fedora}
+# Although eBPF would be available on Fedora's kernel, it seems
+# we often get SELinux denials (rh#1651654). But even aside them,
+# bpf(BPF_MAP_CREATE, ...) randomly fails with EPERM. That might
+# be related to `ulimit -l`. Anyway, this is not usable at the
+# moment.
+%global ebpf_enabled "no"
+%else
+%global ebpf_enabled "no"
+%endif
+
+# Fedora 33 enables LTO by default by setting CFLAGS="-flto -ffat-lto-objects".
+# However, we also require "-flto -flto-partition=none", so disable Fedora's
+# default and use our configure option --with-lto instead.
+%define _lto_cflags %{nil}
+
+###############################################################################
+
+Name: NetworkManager
+Summary: Network connection manager and user applications
+Epoch: %{epoch_version}
+Version: %{rpm_version}
+Release: %{release_version}%{?snap}%{?dist}
+Group: System Environment/Base
+License: GPL-2.0-or-later AND LGPL-2.1-or-later
+URL: https://networkmanager.dev/
+
+#Source: https://download.gnome.org/sources/NetworkManager/%{real_version_major}/%{name}-%{real_version}.tar.xz
+Source: __SOURCE1__
+Source1: NetworkManager.conf
+Source2: 00-server.conf
+Source4: 20-connectivity-fedora.conf
+Source5: 20-connectivity-redhat.conf
+Source6: 22-wifi-mac-addr.conf
+Source7: 70-nm-connectivity.conf
+Source8: readme-ifcfg-rh.txt
+Source9: readme-ifcfg-rh-migrated.txt
+
+#Patch1: 0001-some.patch
+
+Requires(post): systemd
+%if 0%{?fedora} || 0%{?rhel} >= 8
+Requires(post): systemd-udev
+%endif
+Requires(post): /usr/sbin/update-alternatives
+Requires(preun): systemd
+Requires(preun): /usr/sbin/update-alternatives
+Requires(postun): systemd
+
+Requires: dbus >= %{dbus_version}
+Requires: glib2 >= %{glib2_version}
+Requires: %{name}-libnm%{?_isa} = %{epoch}:%{version}-%{release}
+%if "%{libndp_version}" != ""
+Requires: libndp >= %{libndp_version}
+%endif
+Obsoletes: NetworkManager < %{obsoletes_device_plugins}
+Obsoletes: NetworkManager < %{obsoletes_ppp_plugin}
+Obsoletes: NetworkManager-wimax < 1:1.2
+%if 0%{?rhel} && 0%{?rhel} == 8
+Suggests: NetworkManager-initscripts-updown
+%endif
+Obsoletes: NetworkManager < %{obsoletes_initscripts_updown}
+%if 0%{?split_ifcfg_rh}
+Obsoletes: NetworkManager < %{obsoletes_ifcfg_rh}
+%endif
+
+%if 0%{?rhel} && 0%{?rhel} <= 7
+# Kept for RHEL to ensure that wired 802.1x works out of the box
+Requires: wpa_supplicant >= 1:1.1
+%endif
+
+Conflicts: NetworkManager-vpnc < 1:0.7.0.99-1
+Conflicts: NetworkManager-openvpn < 1:0.7.0.99-1
+Conflicts: NetworkManager-pptp < 1:0.7.0.99-1
+Conflicts: NetworkManager-openconnect < 0:0.7.0.99-1
+Conflicts: kde-plasma-networkmanagement < 1:0.9-0.49.20110527git.nm09
+
+BuildRequires: make
+BuildRequires: gcc
+BuildRequires: libtool
+BuildRequires: pkgconfig
+%if %{with meson}
+BuildRequires: meson
+%else
+BuildRequires: automake
+BuildRequires: autoconf
+%endif
+BuildRequires: gettext-devel >= 0.19.8
+
+BuildRequires: dbus-devel >= %{dbus_version}
+BuildRequires: glib2-devel >= 2.40.0
+BuildRequires: gobject-introspection-devel >= 0.10.3
+%if %{with ppp}
+BuildRequires: ppp-devel >= 2.4.5
+%endif
+%if %{with crypto_gnutls}
+BuildRequires: gnutls-devel >= 2.12
+%else
+BuildRequires: nss-devel >= 3.11.7
+%endif
+BuildRequires: readline-devel
+BuildRequires: audit-libs-devel
+%if %{with regen_docs}
+BuildRequires: gtk-doc
+%endif
+BuildRequires: libudev-devel
+BuildRequires: libuuid-devel
+BuildRequires: /usr/bin/valac
+BuildRequires: libxslt
+%if %{with bluetooth}
+BuildRequires: bluez-libs-devel
+%endif
+BuildRequires: systemd >= 200-3 systemd-devel
+%if 0%{?fedora}
+BuildRequires: libpsl-devel >= 0.1
+%endif
+BuildRequires: libcurl-devel
+BuildRequires: libndp-devel >= 1.0
+%if 0%{?with_modem_manager_1}
+BuildRequires: ModemManager-glib-devel >= 1.0
+%endif
+%if %{with wwan}
+BuildRequires: mobile-broadband-provider-info-devel
+%endif
+%if %{with nmtui}
+BuildRequires: newt-devel
+%endif
+BuildRequires: /usr/bin/dbus-launch
+BuildRequires: python3
+BuildRequires: python3-gobject-base
+BuildRequires: python3-dbus
+BuildRequires: python3-pexpect
+BuildRequires: libselinux-devel
+BuildRequires: polkit-devel
+BuildRequires: jansson-devel
+%if %{with sanitizer}
+BuildRequires: libasan
+%if 0%{?fedora} || 0%{?rhel} >= 8
+BuildRequires: libubsan
+%endif
+%endif
+%if %{with firewalld_zone}
+BuildRequires: firewalld-filesystem
+%endif
+BuildRequires: iproute
+%if 0%{?fedora} || 0%{?rhel} >= 8
+BuildRequires: iproute-tc
+%endif
+
+Provides: %{name}-dispatcher%{?_isa} = %{epoch}:%{version}-%{release}
+
+# NetworkManager uses various parts of systemd-networkd internally, including
+# DHCP client, IPv4 Link-Local address negotiation or LLDP support.
+# This provide is essentially here so that NetworkManager shows on Security
+# Response Team's radar in case a flaw is found. The code is frequently
+# synchronized and thus it's not easy to establish a good version number
+# here. The version of zero is there just to have something conservative so
+# that the scripts that would parse the SPEC file naively would be unlikely
+# to fail. Refer to git log for the real date and commit number of last
+# synchronization:
+# https://gitlab.freedesktop.org/NetworkManager/NetworkManager/commits/main/src/
+Provides: bundled(systemd) = 0
+
+
+%description
+NetworkManager is a system service that manages network interfaces and
+connections based on user or automatic configuration. It supports
+Ethernet, Bridge, Bond, VLAN, Team, InfiniBand, Wi-Fi, mobile broadband
+(WWAN), PPPoE and other devices, and supports a variety of different VPN
+services.
+
+
+%if %{with adsl}
+%package adsl
+Summary: ADSL device plugin for NetworkManager
+Group: System Environment/Base
+Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release}
+Obsoletes: NetworkManager < %{obsoletes_device_plugins}
+
+%description adsl
+This package contains NetworkManager support for ADSL devices.
+%endif
+
+
+%if %{with bluetooth}
+%package bluetooth
+Summary: Bluetooth device plugin for NetworkManager
+Group: System Environment/Base
+Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release}
+Requires: NetworkManager-wwan = %{epoch}:%{version}-%{release}
+%if 0%{?rhel} && 0%{?rhel} <= 7
+# No Requires:bluez to prevent it being installed when updating
+# to the split NM package
+%else
+Requires: bluez >= 4.101-5
+%endif
+Obsoletes: NetworkManager < %{obsoletes_device_plugins}
+
+%description bluetooth
+This package contains NetworkManager support for Bluetooth devices.
+%endif
+
+
+%if %{with team}
+%package team
+Summary: Team device plugin for NetworkManager
+Group: System Environment/Base
+BuildRequires: teamd-devel
+Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release}
+Obsoletes: NetworkManager < %{obsoletes_device_plugins}
+%if 0%{?fedora} || 0%{?rhel} >= 8
+# Team was split from main NM binary between 0.9.10 and 1.0
+# We need this Obsoletes in addition to the one above
+# (git:3aede801521ef7bff039e6e3f1b3c7b566b4338d).
+Obsoletes: NetworkManager < 1:1.0.0
+%endif
+
+%description team
+This package contains NetworkManager support for team devices.
+%endif
+
+
+%if %{with wifi}
+%package wifi
+Summary: Wifi plugin for NetworkManager
+Group: System Environment/Base
+Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release}
+
+%if 0%{?fedora} >= 29 || 0%{?rhel} >= 9
+Requires: wireless-regdb
+%else
+Requires: crda
+%endif
+
+%if %{with iwd} && (0%{?fedora} >= 25 || 0%{?rhel} >= 8)
+Requires: (wpa_supplicant >= %{wpa_supplicant_version} or iwd)
+Suggests: wpa_supplicant
+%else
+# Just require wpa_supplicant on platforms that don't support boolean
+# dependencies even though the plugin supports both supplicant and
+# iwd backend.
+Requires: wpa_supplicant >= %{wpa_supplicant_version}
+%endif
+
+Obsoletes: NetworkManager < %{obsoletes_device_plugins}
+
+%description wifi
+This package contains NetworkManager support for Wifi and OLPC devices.
+%endif
+
+
+%if %{with wwan}
+%package wwan
+Summary: Mobile broadband device plugin for NetworkManager
+Group: System Environment/Base
+Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release}
+%if 0%{?rhel} && 0%{?rhel} <= 7
+# No Requires:ModemManager to prevent it being installed when updating
+# to the split NM package
+%else
+Requires: ModemManager
+%endif
+Obsoletes: NetworkManager < %{obsoletes_device_plugins}
+
+%description wwan
+This package contains NetworkManager support for mobile broadband (WWAN)
+devices.
+%endif
+
+
+%if %{with ovs}
+%package ovs
+Summary: Open vSwitch device plugin for NetworkManager
+Group: System Environment/Base
+Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release}
+%if 0%{?rhel} == 0
+Requires: openvswitch
+%endif
+
+%description ovs
+This package contains NetworkManager support for Open vSwitch bridges.
+%endif
+
+
+%if %{with ppp}
+%package ppp
+Summary: PPP plugin for NetworkManager
+Group: System Environment/Base
+Requires: %{name}%{?_isa} = %{epoch}:%{version}-%{release}
+Requires: ppp = %{ppp_version}
+Requires: NetworkManager = %{epoch}:%{version}-%{release}
+Obsoletes: NetworkManager < %{obsoletes_ppp_plugin}
+
+%description ppp
+This package contains NetworkManager support for PPP.
+%endif
+
+
+%package libnm
+Summary: Libraries for adding NetworkManager support to applications.
+Group: Development/Libraries
+Conflicts: NetworkManager-glib < 1:1.31.0
+License: LGPL-2.1-or-later
+
+%description libnm
+This package contains the libraries that make it easier to use some
+NetworkManager functionality from applications.
+
+
+%package libnm-devel
+Summary: Header files for adding NetworkManager support to applications.
+Group: Development/Libraries
+Requires: %{name}-libnm%{?_isa} = %{epoch}:%{version}-%{release}
+Requires: glib2-devel
+Requires: pkgconfig
+License: LGPL-2.1-or-later
+
+%description libnm-devel
+This package contains the header and pkg-config files for development
+applications using NetworkManager functionality from applications.
+
+
+%if %{with connectivity_fedora}
+%package config-connectivity-fedora
+Summary: NetworkManager config file for connectivity checking via Fedora servers
+Group: System Environment/Base
+BuildArch: noarch
+Provides: NetworkManager-config-connectivity = %{epoch}:%{version}-%{release}
+
+%description config-connectivity-fedora
+This adds a NetworkManager configuration file to enable connectivity checking
+via Fedora infrastructure.
+%endif
+
+
+%if %{with connectivity_redhat}
+%package config-connectivity-redhat
+Summary: NetworkManager config file for connectivity checking via Red Hat servers
+Group: System Environment/Base
+BuildArch: noarch
+Provides: NetworkManager-config-connectivity = %{epoch}:%{version}-%{release}
+
+%description config-connectivity-redhat
+This adds a NetworkManager configuration file to enable connectivity checking
+via Red Hat infrastructure.
+%endif
+
+
+%package config-server
+Summary: NetworkManager config file for "server-like" defaults
+Group: System Environment/Base
+BuildArch: noarch
+
+%description config-server
+This adds a NetworkManager configuration file to make it behave more
+like the old "network" service. In particular, it stops NetworkManager
+from automatically running DHCP on unconfigured ethernet devices, and
+allows connections with static IP addresses to be brought up even on
+ethernet devices with no carrier.
+
+This package is intended to be installed by default for server
+deployments.
+
+
+%if %{?with_ifcfg_rh}
+%package dispatcher-routing-rules
+Summary: NetworkManager dispatcher file for advanced routing rules
+Group: System Environment/Base
+%if 0%{?split_ifcfg_rh}
+Requires: %{name}-initscripts-ifcfg-rh
+%endif
+BuildArch: noarch
+Provides: %{name}-config-routing-rules = %{epoch}:%{version}-%{release}
+Obsoletes: %{name}-config-routing-rules < 1:1.31.0
+
+%description dispatcher-routing-rules
+This adds a NetworkManager dispatcher file to support networking
+configurations using "/etc/sysconfig/network-scripts/rule-NAME" files
+(eg, to do policy-based routing).
+%endif
+
+
+%if %{with nmtui}
+%package tui
+Summary: NetworkManager curses-based UI
+Group: System Environment/Base
+Requires: %{name} = %{epoch}:%{version}-%{release}
+Requires: %{name}-libnm%{?_isa} = %{epoch}:%{version}-%{release}
+
+%description tui
+This adds a curses-based "TUI" (Text User Interface) to
+NetworkManager, to allow performing some of the operations supported
+by nm-connection-editor and nm-applet in a non-graphical environment.
+%endif
+
+
+%if 0%{?split_ifcfg_rh}
+%package initscripts-ifcfg-rh
+Summary: NetworkManager plugin for reading and writing connections in ifcfg-rh format
+Group: System Environment/Base
+Requires: %{name} = %{epoch}:%{version}-%{release}
+Obsoletes: NetworkManager < %{obsoletes_ifcfg_rh}
+
+%description initscripts-ifcfg-rh
+Installs a plugin for reading and writing connection profiles using
+the Red Hat ifcfg format in /etc/sysconfig/network-scripts/.
+%endif
+
+
+%if %{with nm_cloud_setup}
+%package cloud-setup
+Summary: Automatically configure NetworkManager in cloud
+Group: System Environment/Base
+Requires: %{name} = %{epoch}:%{version}-%{release}
+Requires: %{name}-libnm%{?_isa} = %{epoch}:%{version}-%{release}
+
+%description cloud-setup
+Installs a nm-cloud-setup tool that can automatically configure
+NetworkManager in cloud environment. Only certain cloud providers
+like Aliyun, Azure, EC2, GCP are supported.
+%endif
+
+
+%if %{?with_ifcfg_rh}
+%package initscripts-updown
+Summary: Legacy ifup/ifdown scripts for NetworkManager that replace initscripts (network-scripts)
+Group: System Environment/Base
+BuildArch: noarch
+Requires: NetworkManager
+Requires: /usr/bin/nmcli
+Obsoletes: NetworkManager < %{obsoletes_initscripts_updown}
+
+%description initscripts-updown
+Installs alternative ifup/ifdown scripts that talk to NetworkManager.
+This is only for backward compatibility with initscripts (network-scripts).
+Preferably use nmcli instead.
+%endif
+
+%prep
+%autosetup -p1 -n NetworkManager-%{real_version}
+
+
+%build
+%if %{with meson}
+%meson \
+	-Db_ndebug=false \
+	--warnlevel 2 \
+%if %{with test}
+	--werror \
+%endif
+	-Dnft=%{_sbindir}/nft \
+	-Diptables=%{_sbindir}/iptables \
+	-Ddhclient=%{_sbindir}/dhclient \
+	-Ddhcpcanon=no \
+	-Ddhcpcd=no \
+	-Dconfig_dhcp_default=%{dhcp_default} \
+%if %{with crypto_gnutls}
+	-Dcrypto=gnutls \
+%else
+	-Dcrypto=nss \
+%endif
+%if %{with debug}
+	-Dmore_logging=true \
+	-Dmore_asserts=10000 \
+%else
+	-Dmore_logging=false \
+	-Dmore_asserts=0 \
+%endif
+	-Dld_gc=true \
+%if %{with lto}
+	-D b_lto=true \
+%else
+	-D b_lto=false \
+%endif
+	-Dlibaudit=yes-disabled-by-default \
+%if 0%{?with_modem_manager_1}
+	-Dmodem_manager=true \
+%else
+	-Dmodem_manager=false \
+%endif
+%if %{with wifi}
+	-Dwifi=true \
+%if 0%{?fedora}
+	-Dwext=true \
+%else
+	-Dwext=false \
+%endif
+%else
+	-Dwifi=false \
+%endif
+%if %{with iwd}
+	-Diwd=true \
+%else
+	-Diwd=false \
+%endif
+%if %{with bluetooth}
+	-Dbluez5_dun=true \
+%else
+	-Dbluez5_dun=false \
+%endif
+%if %{with nmtui}
+	-Dnmtui=true \
+%else
+	-Dnmtui=false \
+%endif
+%if %{with nm_cloud_setup}
+	-Dnm_cloud_setup=true \
+%else
+	-Dnm_cloud_setup=false \
+%endif
+	-Dvapi=true \
+	-Dintrospection=true \
+%if %{with regen_docs}
+	-Ddocs=true \
+%else
+	-Ddocs=false \
+%endif
+	-Dqt=false \
+%if %{with team}
+	-Dteamdctl=true \
+%else
+	-Dteamdctl=false \
+%endif
+%if %{with ovs}
+	-Dovs=true \
+%else
+	-Dovs=false \
+%endif
+	-Dselinux=true \
+	-Dpolkit=true  \
+	-Dconfig_auth_polkit_default=true \
+	-Dmodify_system=true \
+	-Dconcheck=true \
+%if 0%{?fedora}
+	-Dlibpsl=true \
+%else
+	-Dlibpsl=false \
+%endif
+%if %{ebpf_enabled} != "yes"
+	-Debpf=false \
+%else
+	-Debpf=true \
+%endif
+	-Dsession_tracking=systemd \
+	-Dsuspend_resume=systemd \
+	-Dsystemdsystemunitdir=%{_unitdir} \
+	-Dsystem_ca_path=/etc/pki/tls/cert.pem \
+	-Ddbus_conf_dir=%{dbus_sys_dir} \
+	-Dtests=yes \
+	-Dvalgrind=no \
+%if %{?with_ifcfg_rh}
+	-Difcfg_rh=true \
+%else
+	-Difcfg_rh=false \
+%endif
+	-Difupdown=false \
+%if %{with ppp}
+	-Dppp=true \
+	-Dpppd="%{_sbindir}/pppd" \
+	-Dpppd_plugin_dir="%{_libdir}/pppd/%{ppp_version}" \
+%else
+	-Dppp=false \
+%endif
+%if %{with firewalld_zone}
+	-Dfirewalld_zone=true \
+%else
+	-Dfirewalld_zone=false \
+%endif
+	-Ddist_version=%{version}-%{release} \
+%if %{?config_plugins_default_ifcfg_rh}
+	-Dconfig_plugins_default=ifcfg-rh \
+%endif
+%if %{?ifcfg_migrate}
+	-Dconfig_migrate_ifcfg_rh_default=true \
+%endif
+	-Dresolvconf=no \
+	-Dnetconfig=no \
+	-Dconfig_dns_rc_manager_default=%{dns_rc_manager_default} \
+	-Dconfig_logging_backend_default=%{logging_backend_default}
+
+%meson_build
+
+%else
+# autotools
+%if %{with regen_docs}
+gtkdocize
+%endif
+autoreconf --install --force
+%configure \
+	--with-runstatedir=%{_rundir} \
+	--enable-silent-rules=no \
+	--enable-static=no \
+	--with-nft=%{_sbindir}/nft \
+	--with-iptables=%{_sbindir}/iptables \
+	--with-dhclient=%{_sbindir}/dhclient \
+	--with-dhcpcd=no \
+	--with-dhcpcanon=no \
+	--with-config-dhcp-default=%{dhcp_default} \
+%if %{with crypto_gnutls}
+	--with-crypto=gnutls \
+%else
+	--with-crypto=nss \
+%endif
+%if %{with sanitizer}
+	--with-address-sanitizer=exec \
+%if 0%{?fedora} || 0%{?rhel} >= 8
+	--enable-undefined-sanitizer=yes \
+%else
+	--enable-undefined-sanitizer=no \
+%endif
+%else
+	--with-address-sanitizer=no \
+	--enable-undefined-sanitizer=no \
+%endif
+%if %{with debug}
+	--enable-more-logging=yes \
+	--with-more-asserts=10000 \
+%else
+	--enable-more-logging=no \
+	--with-more-asserts=0 \
+%endif
+	--enable-ld-gc=yes \
+%if %{with lto}
+	--enable-lto=yes \
+%else
+	--enable-lto=no \
+%endif
+	--with-libaudit=yes-disabled-by-default \
+%if 0%{?with_modem_manager_1}
+	--with-modem-manager-1=yes \
+%else
+	--with-modem-manager-1=no \
+%endif
+%if %{with wifi}
+	--enable-wifi=yes \
+%if 0%{?fedora}
+	--with-wext=yes \
+%else
+	--with-wext=no \
+%endif
+%else
+	--enable-wifi=no \
+%endif
+%if %{with iwd}
+	--with-iwd=yes \
+%else
+	--with-iwd=no \
+%endif
+%if %{with bluetooth}
+	--enable-bluez5-dun=yes \
+%else
+	--enable-bluez5-dun=no \
+%endif
+%if %{with nmtui}
+	--with-nmtui=yes \
+%else
+	--with-nmtui=no \
+%endif
+%if %{with nm_cloud_setup}
+	--with-nm-cloud-setup=yes \
+%else
+	--with-nm-cloud-setup=no \
+%endif
+	--enable-vala=yes \
+	--enable-introspection=yes \
+%if %{with regen_docs}
+	--enable-gtk-doc=yes \
+%else
+	--enable-gtk-doc=no \
+%endif
+%if %{with team}
+	--enable-teamdctl=yes \
+%else
+	--enable-teamdctl=no \
+%endif
+%if %{with ovs}
+	--enable-ovs=yes \
+%else
+	--enable-ovs=no \
+%endif
+	--with-selinux=yes \
+	--enable-polkit=yes \
+	--enable-modify-system=yes \
+	--enable-concheck=yes \
+%if 0%{?fedora}
+	--with-libpsl=yes \
+%else
+	--with-libpsl=no \
+%endif
+	--with-ebpf=%{ebpf_enabled} \
+	--with-session-tracking=systemd \
+	--with-suspend-resume=systemd \
+	--with-systemdsystemunitdir=%{_unitdir} \
+	--with-system-ca-path=/etc/pki/tls/cert.pem \
+	--with-dbus-sys-dir=%{dbus_sys_dir} \
+	--with-tests=yes \
+%if %{with test}
+	--enable-more-warnings=error \
+%else
+	--enable-more-warnings=yes \
+%endif
+	--with-valgrind=no \
+%if %{?with_ifcfg_rh}
+	--enable-ifcfg-rh=yes \
+%else
+        --enable-ifcfg-rh=no \
+%endif
+	--enable-ifupdown=no \
+%if %{with ppp}
+	--enable-ppp=yes \
+	--with-pppd="%{_sbindir}/pppd" \
+	--with-pppd-plugin-dir="%{_libdir}/pppd/%{ppp_version}" \
+%else
+	--enable-ppp=no \
+%endif
+%if %{with firewalld_zone}
+	--enable-firewalld-zone=yes \
+%else
+	--enable-firewalld-zone=no \
+%endif
+	--with-dist-version=%{version}-%{release} \
+%if %{?config_plugins_default_ifcfg_rh}
+	--with-config-plugins-default=ifcfg-rh \
+%endif
+%if %{?ifcfg_migrate}
+	--with-config-migrate-ifcfg-rh-default=yes \
+%endif
+	--with-resolvconf=no \
+	--with-netconfig=no \
+	--with-config-dns-rc-manager-default=%{dns_rc_manager_default} \
+	--with-config-logging-backend-default=%{logging_backend_default}
+
+%make_build
+
+%endif
+
+%install
+%if %{with meson}
+%meson_install
+%else
+%make_install
+%endif
+
+cp %{SOURCE1} %{buildroot}%{_sysconfdir}/%{name}/
+
+cp %{SOURCE2} %{buildroot}%{nmlibdir}/conf.d/
+
+%if %{with connectivity_fedora}
+cp %{SOURCE4} %{buildroot}%{nmlibdir}/conf.d/
+%endif
+
+%if %{with connectivity_redhat}
+cp %{SOURCE5} %{buildroot}%{nmlibdir}/conf.d/
+mkdir -p %{buildroot}%{_sysctldir}
+cp %{SOURCE7} %{buildroot}%{_sysctldir}
+%endif
+
+%if 0%{?fedora} >= 40
+cp %{SOURCE6} %{buildroot}%{nmlibdir}/conf.d/
+%endif
+
+%if 0%{?ifcfg_warning}
+cp %{SOURCE8} %{buildroot}%{_sysconfdir}/sysconfig/network-scripts
+%endif
+%if 0%{?ifcfg_migrate}
+cp %{SOURCE9} %{buildroot}%{_sysconfdir}/sysconfig/network-scripts/readme-ifcfg-rh.txt
+%endif
+
+%if %{?with_ifcfg_rh}
+cp examples/dispatcher/10-ifcfg-rh-routes.sh %{buildroot}%{nmlibdir}/dispatcher.d/
+ln -s ../no-wait.d/10-ifcfg-rh-routes.sh %{buildroot}%{nmlibdir}/dispatcher.d/pre-up.d/
+ln -s ../10-ifcfg-rh-routes.sh %{buildroot}%{nmlibdir}/dispatcher.d/no-wait.d/
+%endif
+
+%find_lang %{name}
+
+rm -f %{buildroot}%{_libdir}/*.la
+rm -f %{buildroot}%{_libdir}/pppd/%{ppp_version}/*.la
+rm -f %{buildroot}%{nmplugindir}/*.la
+
+# Ensure the documentation timestamps are constant to avoid multilib conflicts
+find %{buildroot}%{_datadir}/gtk-doc -exec touch --reference configure.ac '{}' \+
+
+%if 0%{?__debug_package} && ! 0%{?flatpak}
+mkdir -p %{buildroot}%{_prefix}/src/debug/NetworkManager-%{real_version}
+cp valgrind.suppressions %{buildroot}%{_prefix}/src/debug/NetworkManager-%{real_version}
+%endif
+
+%if %{?with_ifcfg_rh}
+touch %{buildroot}%{_sbindir}/ifup
+touch %{buildroot}%{_sbindir}/ifdown
+%endif
+
+%check
+%if %{with meson}
+%if %{with test}
+%meson_test
+%else
+%ninja_test -C %{_vpath_builddir} || :
+%endif
+%else
+# autotools
+%if %{with test}
+make -k %{?_smp_mflags} check
+%else
+make -k %{?_smp_mflags} check || :
+%endif
+%endif
+
+
+%pre
+if [ -f "%{_unitdir}/network-online.target.wants/NetworkManager-wait-online.service" ] ; then
+    # older versions used to install this file, effectively always enabling
+    # NetworkManager-wait-online.service. We no longer do that and rely on
+    # preset.
+    # But on package upgrade we must explicitly enable it (rh#1455704).
+    systemctl enable NetworkManager-wait-online.service || :
+fi
+
+
+%post
+# skip triggering if udevd isn't even accessible, e.g. containers or
+# rpm-ostree-based systems
+if [ -S /run/udev/control ]; then
+    /usr/bin/udevadm control --reload-rules || :
+    /usr/bin/udevadm trigger --subsystem-match=net || :
+fi
+%if %{with firewalld_zone}
+%firewalld_reload
+%endif
+
+%systemd_post %{systemd_units}
+
+
+%if %{?with_ifcfg_rh}
+%post initscripts-updown
+if [ -f %{_sbindir}/ifup -a ! -L %{_sbindir}/ifup ]; then
+    # initscripts package too old, won't let us set an alternative
+    /usr/sbin/update-alternatives --remove ifup %{_libexecdir}/nm-ifup >/dev/null 2>&1 || :
+else
+    /usr/sbin/update-alternatives --install %{_sbindir}/ifup ifup %{_libexecdir}/nm-ifup 50 \
+        --slave %{_sbindir}/ifdown ifdown %{_libexecdir}/nm-ifdown
+fi
+%endif
+
+
+%if %{with nm_cloud_setup}
+%post cloud-setup
+%systemd_post %{systemd_units_cloud_setup}
+%endif
+
+
+%preun
+if [ $1 -eq 0 ]; then
+    # Package removal, not upgrade
+    /bin/systemctl --no-reload disable NetworkManager.service >/dev/null 2>&1 || :
+
+    # Don't kill networking entirely just on package remove
+    #/bin/systemctl stop NetworkManager.service >/dev/null 2>&1 || :
+fi
+%systemd_preun NetworkManager-wait-online.service NetworkManager-dispatcher.service nm-priv-helper.service
+
+
+%if %{?with_ifcfg_rh}
+%preun initscripts-updown
+if [ $1 -eq 0 ]; then
+    /usr/sbin/update-alternatives --remove ifup %{_libexecdir}/nm-ifup >/dev/null 2>&1 || :
+fi
+%endif
+
+
+%if %{with nm_cloud_setup}
+%preun cloud-setup
+%systemd_preun %{systemd_units_cloud_setup}
+%endif
+
+
+%postun
+/usr/bin/udevadm control --reload-rules || :
+/usr/bin/udevadm trigger --subsystem-match=net || :
+%if %{with firewalld_zone}
+%firewalld_reload
+%endif
+
+%systemd_postun %{systemd_units}
+
+
+%if (0%{?fedora} && 0%{?fedora} < 28) || 0%{?rhel}
+%post   libnm -p /sbin/ldconfig
+%postun libnm -p /sbin/ldconfig
+%endif
+
+
+%if %{with nm_cloud_setup}
+%postun cloud-setup
+%systemd_postun %{systemd_units_cloud_setup}
+%endif
+
+
+%files
+%{dbus_sys_dir}/org.freedesktop.NetworkManager.conf
+%{dbus_sys_dir}/nm-dispatcher.conf
+%{dbus_sys_dir}/nm-priv-helper.conf
+%if %{?with_ifcfg_rh} && 0%{?split_ifcfg_rh} == 0
+%{dbus_sys_dir}/nm-ifcfg-rh.conf
+%endif
+%{_sbindir}/%{name}
+%{_bindir}/nmcli
+%{_datadir}/bash-completion/completions/nmcli
+%dir %{_sysconfdir}/%{name}
+%dir %{_sysconfdir}/%{name}/conf.d
+%dir %{_sysconfdir}/%{name}/dispatcher.d
+%dir %{_sysconfdir}/%{name}/dispatcher.d/pre-down.d
+%dir %{_sysconfdir}/%{name}/dispatcher.d/pre-up.d
+%dir %{_sysconfdir}/%{name}/dispatcher.d/no-wait.d
+%dir %{_sysconfdir}/%{name}/dnsmasq.d
+%dir %{_sysconfdir}/%{name}/dnsmasq-shared.d
+%dir %{_sysconfdir}/%{name}/system-connections
+%config(noreplace) %{_sysconfdir}/%{name}/NetworkManager.conf
+%if 0%{?fedora} >= 40
+%{nmlibdir}/conf.d/22-wifi-mac-addr.conf
+%endif
+%ghost %{_sysconfdir}/%{name}/VPN
+%{_bindir}/nm-online
+%{_libexecdir}/nm-dhcp-helper
+%{_libexecdir}/nm-dispatcher
+%{_libexecdir}/nm-initrd-generator
+%{_libexecdir}/nm-daemon-helper
+%{_libexecdir}/nm-priv-helper
+%dir %{_libdir}/%{name}
+%dir %{nmplugindir}
+%if %{?with_ifcfg_rh} && 0%{?split_ifcfg_rh} == 0
+%{nmplugindir}/libnm-settings-plugin-ifcfg-rh.so
+%endif
+%if %{with nmtui}
+%exclude %{_mandir}/man1/nmtui*
+%endif
+%dir %{nmlibdir}
+%dir %{nmlibdir}/conf.d
+%dir %{nmlibdir}/dispatcher.d
+%dir %{nmlibdir}/dispatcher.d/pre-down.d
+%dir %{nmlibdir}/dispatcher.d/pre-up.d
+%dir %{nmlibdir}/dispatcher.d/no-wait.d
+%dir %{nmlibdir}/VPN
+%dir %{nmlibdir}/system-connections
+%{_mandir}/man1/*
+%{_mandir}/man5/*
+%{_mandir}/man7/nmcli-examples.7*
+%{_mandir}/man8/nm-initrd-generator.8*
+%{_mandir}/man8/NetworkManager.8*
+%{_mandir}/man8/NetworkManager-dispatcher.8*
+%{_mandir}/man8/NetworkManager-wait-online.service.8*
+%dir %{_localstatedir}/lib/NetworkManager
+%if %{?with_ifcfg_rh}
+%dir %{_sysconfdir}/sysconfig/network-scripts
+%endif
+%{_datadir}/dbus-1/system-services/org.freedesktop.nm_dispatcher.service
+%{_datadir}/dbus-1/system-services/org.freedesktop.nm_priv_helper.service
+%{_datadir}/polkit-1/actions/*.policy
+%{_prefix}/lib/udev/rules.d/*.rules
+%if %{with firewalld_zone}
+%{_prefix}/lib/firewalld/zones/nm-shared.xml
+%endif
+# systemd stuff
+%{_unitdir}/NetworkManager.service
+%{_unitdir}/NetworkManager-wait-online.service
+%{_unitdir}/NetworkManager-dispatcher.service
+%{_unitdir}/nm-priv-helper.service
+%dir %{_datadir}/doc/NetworkManager/examples
+%{_datadir}/doc/NetworkManager/examples/server.conf
+%if 0%{?ifcfg_warning} || 0%{?ifcfg_migrate}
+%{_sysconfdir}/sysconfig/network-scripts/readme-ifcfg-rh.txt
+%endif
+%doc NEWS AUTHORS README.md CONTRIBUTING.md
+%license COPYING
+%license COPYING.LGPL
+%license COPYING.GFDL
+
+
+%if %{with adsl}
+%files adsl
+%{nmplugindir}/libnm-device-plugin-adsl.so
+%else
+%exclude %{nmplugindir}/libnm-device-plugin-adsl.so
+%endif
+
+
+%if %{with bluetooth}
+%files bluetooth
+%{nmplugindir}/libnm-device-plugin-bluetooth.so
+%endif
+
+
+%if %{with team}
+%files team
+%{nmplugindir}/libnm-device-plugin-team.so
+%endif
+
+
+%if %{with wifi}
+%files wifi
+%{nmplugindir}/libnm-device-plugin-wifi.so
+%endif
+
+
+%if %{with wwan}
+%files wwan
+%{nmplugindir}/libnm-device-plugin-wwan.so
+%{nmplugindir}/libnm-wwan.so
+%endif
+
+
+%if %{with ovs}
+%files ovs
+%{nmplugindir}/libnm-device-plugin-ovs.so
+%{_unitdir}/NetworkManager.service.d/NetworkManager-ovs.conf
+%{_mandir}/man7/nm-openvswitch.7*
+%endif
+
+
+%if %{with ppp}
+%files ppp
+%{_libdir}/pppd/%{ppp_version}/nm-pppd-plugin.so
+%{nmplugindir}/libnm-ppp-plugin.so
+%endif
+
+
+%files libnm -f %{name}.lang
+%{_libdir}/libnm.so.*
+%{_libdir}/girepository-1.0/NM-1.0.typelib
+
+
+%files libnm-devel
+%dir %{_includedir}/libnm
+%{_includedir}/libnm/*.h
+%{_libdir}/pkgconfig/libnm.pc
+%{_libdir}/libnm.so
+%{_datadir}/gir-1.0/NM-1.0.gir
+%dir %{_datadir}/gtk-doc/html/libnm
+%{_datadir}/gtk-doc/html/libnm/*
+%dir %{_datadir}/gtk-doc/html/NetworkManager
+%{_datadir}/gtk-doc/html/NetworkManager/*
+%{_datadir}/vala/vapi/libnm.deps
+%{_datadir}/vala/vapi/libnm.vapi
+%{_datadir}/dbus-1/interfaces/*.xml
+
+
+%if %{with connectivity_fedora}
+%files config-connectivity-fedora
+%dir %{nmlibdir}
+%dir %{nmlibdir}/conf.d
+%{nmlibdir}/conf.d/20-connectivity-fedora.conf
+%endif
+
+
+%if %{with connectivity_redhat}
+%files config-connectivity-redhat
+%dir %{nmlibdir}
+%dir %{nmlibdir}/conf.d
+%{nmlibdir}/conf.d/20-connectivity-redhat.conf
+%{_sysctldir}/70-nm-connectivity.conf
+%endif
+
+
+%files config-server
+%dir %{nmlibdir}
+%dir %{nmlibdir}/conf.d
+%{nmlibdir}/conf.d/00-server.conf
+
+
+%if %{?with_ifcfg_rh}
+%files dispatcher-routing-rules
+%{nmlibdir}/dispatcher.d/10-ifcfg-rh-routes.sh
+%{nmlibdir}/dispatcher.d/no-wait.d/10-ifcfg-rh-routes.sh
+%{nmlibdir}/dispatcher.d/pre-up.d/10-ifcfg-rh-routes.sh
+%endif
+
+%if %{with nmtui}
+%files tui
+%{_bindir}/nmtui
+%{_bindir}/nmtui-edit
+%{_bindir}/nmtui-connect
+%{_bindir}/nmtui-hostname
+%{_mandir}/man1/nmtui*
+%endif
+
+
+%if 0%{?split_ifcfg_rh}
+%files initscripts-ifcfg-rh
+%{nmplugindir}/libnm-settings-plugin-ifcfg-rh.so
+%{dbus_sys_dir}/nm-ifcfg-rh.conf
+%endif
+
+
+%if %{with nm_cloud_setup}
+%files cloud-setup
+%{_libexecdir}/nm-cloud-setup
+%{_unitdir}/nm-cloud-setup.service
+%{_unitdir}/nm-cloud-setup.timer
+%{nmlibdir}/dispatcher.d/90-nm-cloud-setup.sh
+%{nmlibdir}/dispatcher.d/no-wait.d/90-nm-cloud-setup.sh
+%{nmlibdir}/dispatcher.d/pre-up.d/90-nm-cloud-setup.sh
+%{_mandir}/man8/nm-cloud-setup.8*
+%endif
+
+
+%if %{?with_ifcfg_rh}
+%files initscripts-updown
+%{_libexecdir}/nm-ifup
+%ghost %attr(755, root, root) %{_sbindir}/ifup
+%{_libexecdir}/nm-ifdown
+%ghost %attr(755, root, root) %{_sbindir}/ifdown
+%endif
+
+
+%changelog
+__CHANGELOG__
diff --git a/contrib/fedora/rpm/README b/contrib/fedora/rpm/README
new file mode 100644
index 00000000..7982a1ef
--- /dev/null
+++ b/contrib/fedora/rpm/README
@@ -0,0 +1,27 @@
+# To build RPM packages for Fedora derivates directly from git, just do:
+
+
+#
+# preparation:
+#
+git clone https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
+cd NetworkManager
+git checkout $WHATEVER
+./contrib/fedora/REQUIRED_PACKAGES
+
+
+#
+# build the packages. Pass --help for usage help.
+#
+./contrib/fedora/rpm/build_clean.sh
+
+
+#
+# install
+#
+sudo dnf install ./contrib/fedora/rpm/latest/RPMS/x86_64/*rpm
+
+
+
+# To generate a clean build from git using mock, run:
+./contrib/fedora/rpm/mockbuild.sh
diff --git a/contrib/fedora/rpm/build.sh b/contrib/fedora/rpm/build.sh
new file mode 100755
index 00000000..8160b915
--- /dev/null
+++ b/contrib/fedora/rpm/build.sh
@@ -0,0 +1,288 @@
+#!/bin/bash
+
+#set -vx
+
+# Set arguments via environment variables.
+# Argument can be omitted and defaults will be detected.
+#
+#   BUILDTYPE=|SRPM
+#   NM_RPMBUILD_ARGS=<additional argus for rpmbuild>
+#   RELEASE_VERSION=
+#   SNAPSHOT=
+#   VERSION=
+#   COMMIT_FULL=
+#   COMMIT=
+#   USERNAME=
+#   SPECFILE=
+#   SOURCE=<path>
+#   SOURCE_FROM_GIT=|1|0
+#   SOURCE_NETWORKMANAGER_CONF=
+#   SOURCE_CONFIG_SERVER=
+#   SOURCE_CONFIG_CONNECTIVITY_FEDORA=
+#   SOURCE_CONFIG_CONNECTIVITY_REDHAT=
+#   SOURCE_SYSCTL_RP_FILTER_REDHAT=
+#   SOURCE_README_IFCFG_FILES=
+#   SOURCE_README_IFCFG_MIGRATED=
+#   SIGN_SOURCE=
+#   DO_RELEASE=
+#   BCOND_DEFAULT_DEBUG=
+#   BCOND_DEFAULT_LTO=
+#   BCOND_DEFAULT_TEST=
+
+die() {
+    echo "$*" >&2
+    exit 1
+}
+
+# copy output also to logfile
+LOG() {
+    echo "$*"
+}
+
+coerce_bool() {
+    case "$1" in
+        no|n|NO|N|0)
+            echo 0
+            ;;
+        yes|y|YES|Y|1)
+            echo 1
+            ;;
+        "")
+            printf '%s' "$2"
+            ;;
+    esac
+}
+
+in_set() {
+    local v="$1"
+    shift
+    for v2; do
+        test "$v" = "$v2" && return 0
+    done
+    return 1
+}
+
+abs_path() {
+    local F="$1"
+
+    if [[ "$F" != "" ]]; then
+        F="$(cd "$ORIGDIR" && readlink -f "$F")" || exit 55
+        [[ -f "$F" ]] || exit 55
+    else
+        F="$2"
+    fi
+    printf '%s' "$F"
+    exit 0
+}
+
+get_version() {
+    local major minor micro
+    local F="${1:-"$GITDIR/configure.ac"}"
+
+    vars="$(sed -n 's/^m4_define(\[nm_\(major\|minor\|micro\)_version\], *\[\([0-9]\+\)\]) *$/local \1='\''\2'\''/p' "$F" 2>/dev/null)"
+    eval "$vars"
+
+    [[ -n "$major" && -n "$minor" && "$micro" ]] || return 1
+    echo "$major.$minor.$micro"
+}
+
+write_changelog() {
+    if [[ "x$CHANGELOG" == x ]]; then
+        cat <<- EOF
+	* $(LC_TIME=C date '+%a %b %d %Y') $USERNAME - %{epoch_version}:%{version}-%{release_version}%{?snap}
+	- build of NetworkManager ($DATE, uuid: $UUID, git: $COMMIT_FULL)
+	$(git log -n20 --date=local --format='- %h %s [%an] (%ci)')
+	- ...
+	EOF
+    else
+        echo "$CHANGELOG"
+    fi > "$TEMP/SOURCES/CHANGELOG"
+}
+
+ORIGDIR="$(readlink -f "$PWD")"
+SCRIPTDIR="$(dirname "$(readlink -f "$0")")"
+LOG "Change to directory \"$SCRIPTDIR\""
+cd "$SCRIPTDIR" || die "could not change into $SCRIPTDIR"
+GITDIR="$(cd "$SCRIPTDIR" && git rev-parse --show-toplevel || die "Could not get GITDIR")"
+
+DATE="$(date '+%Y%m%d-%H%M%S')"
+
+BUILDLOG="$(mktemp ./.build.log.XXXXXXX)"
+chmod +r "$BUILDLOG"
+
+exec > >(tee "$BUILDLOG")
+exec 2>&1
+
+UUID=`uuidgen`
+RELEASE_VERSION="${RELEASE_VERSION:-$(git rev-list HEAD | wc -l)}"
+SNAPSHOT="${SNAPSHOT:-%{nil\}}"
+VERSION="${VERSION:-$(get_version || die "Could not read $VERSION")}"
+COMMIT_FULL="${COMMIT_FULL:-$(git rev-parse --verify HEAD || die "Error reading HEAD revision")}"
+COMMIT="${COMMIT:-$(printf '%s' "$COMMIT_FULL" | sed 's/^\(.\{10\}\).*/\1/' || die "Error reading HEAD revision")}"
+BCOND_DEFAULT_DEBUG="${BCOND_DEFAULT_DEBUG:-0}"
+BCOND_DEFAULT_TEST="${BCOND_DEFAULT_TEST:-0}"
+BCOND_DEFAULT_LTO="${BCOND_DEFAULT_LTO}"
+USERNAME="${USERNAME:-"$(git config user.name) <$(git config user.email)>"}"
+SPECFILE="$(abs_path "$SPECFILE" "$SCRIPTDIR/NetworkManager.spec")" || die "invalid \$SPECFILE argument"
+SOURCE_FROM_GIT="$(coerce_bool "$SOURCE_FROM_GIT" "")"
+SOURCE="$(abs_path "$SOURCE")" || die "invalid \$SOURCE argument"
+DO_RELEASE="$(coerce_bool "$DO_RELEASE" "0")"
+SIGN_SOURCE="$(coerce_bool "$SIGN_SOURCE" "$DO_RELEASE")"
+if [ -n "$SOURCE" ]; then
+    [[ "$SOURCE_FROM_GIT" == 1 ]] && die "Cannot set both \$SOURCE and \$SOURCE_FROM_GIT=1"
+    SOURCE_FROM_GIT=0
+elif [[ "$SOURCE_FROM_GIT" != "1" ]]; then
+    SOURCE="$(ls -1 "$GITDIR/NetworkManager-${VERSION}.tar."* 2>/dev/null | head -n1)"
+    if [[ -z "$SOURCE" ]]; then
+        [[ "$SOURCE_FROM_GIT" == "0" ]] && die "Either set \$SOURCE or set \$SOURCE_FROM_GIT=1"
+        SOURCE_FROM_GIT=1
+    else
+        SOURCE_FROM_GIT=0
+    fi
+fi
+
+SOURCE_NETWORKMANAGER_CONF="$(abs_path "$SOURCE_NETWORKMANAGER_CONF" "$SCRIPTDIR/NetworkManager.conf")" || die "invalid \$SOURCE_NETWORKMANAGER_CONF argument"
+SOURCE_CONFIG_SERVER="$(abs_path "$SOURCE_CONFIG_SERVER" "$SCRIPTDIR/00-server.conf")" || die "invalid \$SOURCE_CONFIG_SERVER argument"
+SOURCE_CONFIG_CONNECTIVITY_FEDORA="$(abs_path "$SOURCE_CONFIG_CONNECTIVITY_FEDORA" "$SCRIPTDIR/20-connectivity-fedora.conf")" || die "invalid \$SOURCE_CONFIG_CONNECTIVITY_FEDORA argument"
+SOURCE_CONFIG_CONNECTIVITY_REDHAT="$(abs_path "$SOURCE_CONFIG_CONNECTIVITY_REDHAT" "$SCRIPTDIR/20-connectivity-redhat.conf")" || die "invalid \$SOURCE_CONFIG_CONNECTIVITY_REDHAT argument"
+SOURCE_CONFIG_WIFI_MAC_ADDR="$(abs_path "$SOURCE_CONFIG_WIFI_MAC_ADDR" "$SCRIPTDIR/22-wifi-mac-addr.conf")" || die "invalid \$SOURCE_CONFIG_WIFI_MAC_ADDR argument"
+SOURCE_SYSCTL_RP_FILTER_REDHAT="$(abs_path "$SOURCE_SYSCTL_RP_FILTER_REDHAT" "$SCRIPTDIR/70-nm-connectivity.conf")" || die "invalid \$SOURCE_SYSCTL_RP_FILTER_REDHAT argument"
+SOURCE_README_IFCFG_FILES="$(abs_path "$SOURCE_README_IFCFG_FILES" "$SCRIPTDIR/readme-ifcfg-rh.txt")" || die "invalid \$SOURCE_README_IFCFG_FILES argument"
+SOURCE_README_IFCFG_MIGRATED="$(abs_path "$SOURCE_README_IFCFG_MIGRATED" "$SCRIPTDIR/readme-ifcfg-rh-migrated.txt")" || die "invalid \$SOURCE_README_IFCFG_MIGRATED argument"
+
+TEMP="$(mktemp -d "$SCRIPTDIR/NetworkManager.$DATE.XXXXXX")"
+TEMPBASE="$(basename "$TEMP")"
+
+if [[ "$SOURCE_FROM_GIT" == "1" ]]; then
+    mkdir -p "$TEMP/SOURCES"
+    SOURCE="$TEMP/SOURCES/NetworkManager-${VERSION}.tar.xz"
+    (cd "$GITDIR" && git archive --prefix="NetworkManager-$VERSION"/ "$COMMIT_FULL") | xz > "$SOURCE"
+fi
+
+LOG "VERSION=$VERSION"
+LOG "RELEASE_VERSION=$RELEASE_VERSION"
+LOG "SNAPSHOT=$SNAPSHOT"
+LOG "COMMIT_FULL=$COMMIT_FULL"
+LOG "COMMIT=$COMMIT"
+LOG "USERNAME=$USERNAME"
+LOG "SPECFILE=$SPECFILE"
+LOG "SOURCE=$SOURCE"
+LOG "SIGN_SOURCE=$SIGN_SOURCE"
+LOG "DO_RELEASE=$DO_RELEASE"
+LOG "SOURCE_FROM_GIT=$SOURCE_FROM_GIT"
+LOG "SOURCE_NETWORKMANAGER_CONF=$SOURCE_NETWORKMANAGER_CONF"
+LOG "SOURCE_CONFIG_SERVER=$SOURCE_CONFIG_SERVER"
+LOG "SOURCE_CONFIG_CONNECTIVITY_FEDORA=$SOURCE_CONFIG_CONNECTIVITY_FEDORA"
+LOG "SOURCE_CONFIG_CONNECTIVITY_REDHAT=$SOURCE_CONFIG_CONNECTIVITY_REDHAT"
+LOG "SOURCE_SYSCTL_RP_FILTER_REDHAT=$SOURCE_SYSCTL_RP_FILTER_REDHAT"
+LOG "SOURCE_README_IFCFG_FILES=$SOURCE_README_IFCFG_FILES"
+LOG "SOURCE_README_IFCFG_MIGRATED=$SOURCE_README_IFCFG_MIGRATED"
+LOG "BUILDTYPE=$BUILDTYPE"
+LOG "NM_RPMBUILD_ARGS=$NM_RPMBUILD_ARGS"
+LOG "BCOND_DEFAULT_DEBUG=$BCOND_DEFAULT_DEBUG"
+LOG "BCOND_DEFAULT_LTO=$BCOND_DEFAULT_LTO"
+LOG "BCOND_DEFAULT_TEST=$BCOND_DEFAULT_TEST"
+LOG ""
+LOG "UUID=$UUID"
+LOG "BASEDIR=$TEMP"
+
+in_set "$BCOND_DEFAULT_DEBUG" 0 1 || die "Invalid value for \$BCOND_DEFAULT_DEBUG: \"$BCOND_DEFAULT_DEBUG\""
+in_set "$BCOND_DEFAULT_LTO" '' 0 1 || die "Invalid value for \$BCOND_DEFAULT_LTO: \"$BCOND_DEFAULT_LTO\""
+in_set "$BCOND_DEFAULT_TEST" 0 1 || die "Invalid value for \$BCOND_DEFAULT_TEST: \"$BCOND_DEFAULT_TEST\""
+
+ln -snf "$TEMPBASE" ./latest0
+ln "$BUILDLOG" "$TEMPBASE/build.log"
+rm -f "$BUILDLOG"
+
+TEMPSPEC="$TEMP/SPECS/NetworkManager.spec"
+mkdir -p "$TEMP/SOURCES/" "$TEMP/SPECS/" || die "error creating SPECS directory"
+
+if [[ "$(dirname "$SOURCE")" != "$TEMP/SOURCES" ]]; then
+    cp "$SOURCE" "$TEMP/SOURCES/" || die "Could not copy source $SOURCE to $TEMP/SOURCES"
+fi
+cp "$SOURCE_NETWORKMANAGER_CONF" "$TEMP/SOURCES/NetworkManager.conf" || die "Could not copy source $SOURCE_NETWORKMANAGER_CONF to $TEMP/SOURCES"
+cp "$SOURCE_CONFIG_SERVER" "$TEMP/SOURCES/00-server.conf" || die "Could not copy source $SOURCE_CONFIG_SERVER to $TEMP/SOURCES"
+cp "$SOURCE_CONFIG_CONNECTIVITY_FEDORA" "$TEMP/SOURCES/20-connectivity-fedora.conf" || die "Could not copy source $SOURCE_CONFIG_CONNECTIVITY_FEDORA to $TEMP/SOURCES"
+cp "$SOURCE_CONFIG_CONNECTIVITY_REDHAT" "$TEMP/SOURCES/20-connectivity-redhat.conf" || die "Could not copy source $SOURCE_CONFIG_CONNECTIVITY_REDHAT to $TEMP/SOURCES"
+cp "$SOURCE_CONFIG_WIFI_MAC_ADDR" "$TEMP/SOURCES/22-wifi-mac-addr.conf" || die "Could not copy source $SOURCE_CONFIG_WIFI_MAC_ADDR to $TEMP/SOURCES"
+cp "$SOURCE_SYSCTL_RP_FILTER_REDHAT" "$TEMP/SOURCES/70-nm-connectivity.conf" || die "Could not copy source $SOURCE_SYSCTL_RP_FILTER_REDHAT to $TEMP/SOURCES"
+cp "$SOURCE_README_IFCFG_FILES" "$TEMP/SOURCES/readme-ifcfg-rh.txt" || die "Could not copy source $SOURCE_README_IFCFG_FILES to $TEMP/SOURCES"
+cp "$SOURCE_README_IFCFG_MIGRATED" "$TEMP/SOURCES/readme-ifcfg-rh-migrated.txt" || die "Could not copy source $SOURCE_README_IFCFG_MIGRATED to $TEMP/SOURCES"
+
+write_changelog
+
+sed -e "s/__VERSION__/$VERSION/g" \
+    -e "s/__RELEASE_VERSION__/$RELEASE_VERSION/g" \
+    -e "s/__SNAPSHOT__/$SNAPSHOT/g" \
+    -e "s/__COMMIT__/$COMMIT/g" \
+    -e "s/__COMMIT_FULL__/$COMMIT_FULL/g" \
+    -e "s/__SNAPSHOT__/$SNAPSHOT/g" \
+    -e "s/__SOURCE1__/$(basename "$SOURCE")/g" \
+    -e "s/__BCOND_DEFAULT_DEBUG__/$BCOND_DEFAULT_DEBUG/g" \
+    -e "s/__BCOND_DEFAULT_LTO__/${BCOND_DEFAULT_LTO:-"%{nil}"}/g" \
+    -e "s/__BCOND_DEFAULT_TEST__/$BCOND_DEFAULT_TEST/g" \
+   "$SPECFILE" |
+sed -e "/^__CHANGELOG__$/ \
+        {
+            r $TEMPBASE/SOURCES/CHANGELOG
+            d
+        }" > "$TEMPSPEC" || die "Error reading spec file"
+
+case "$BUILDTYPE" in
+    "SRPM")
+        RPM_BUILD_OPTION=-bs
+        ;;
+    *)
+        RPM_BUILD_OPTION=-ba
+        ;;
+esac
+
+rpmbuild --define "_topdir $TEMP" $RPM_BUILD_OPTION "$TEMPSPEC" $NM_RPMBUILD_ARGS || die "ERROR: rpmbuild FAILED"
+
+LS_EXTRA=()
+
+if [ "$SIGN_SOURCE" = 1 ]; then
+    SIGNKEY="$(git config --get user.signingkey)"
+    if [ "$SIGNKEY" != "" ]; then
+        SIGNKEY="--local-user $(printf '%q' "$SIGNKEY")"
+    fi
+    gpg $SIGNKEY --output "$SOURCE.sig" --armor --detach-sig "$SOURCE" || die "ERROR: failure to sign $SOURCE"
+    LS_EXTRA+=("$SOURCE.sig")
+fi
+
+ln -snf "$TEMPBASE" ./latest
+TEMP_LATEST="$(readlink -f .)"/latest
+
+LOG
+LOG
+LOG "Finished with success."
+LOG
+LOG "See \"$TEMP_LATEST/\" which symlinks to \"$TEMPBASE\""
+LOG
+LOG "Result:"
+ls -dla \
+    "$TEMP_LATEST" \
+    "$SOURCE" \
+    "${LS_EXTRA[@]}" \
+    "$(dirname "$TEMP_LATEST")/$TEMPBASE/" \
+    "$TEMP_LATEST"/RPMS/*/ \
+    "$TEMP_LATEST"/RPMS/*/*.rpm \
+    "$TEMP_LATEST"/SRPMS/ \
+    "$TEMP_LATEST"/SRPMS/*.rpm \
+    2>/dev/null | sed 's/^/    /'
+LOG
+if [[ "$BUILDTYPE" == "SRPM" ]]; then
+    LOG sudo $(command -v dnf &>/dev/null && echo dnf builddep || echo yum-builddep) $TEMP_LATEST/SRPMS/*.src.rpm
+    LOG
+else
+    LOG "sudo $(command -v dnf &>/dev/null && echo dnf || echo yum) install '$TEMP_LATEST/RPMS'/*/*.rpm"
+    LOG
+fi
+
+if [[ "$DO_RELEASE" == 1 ]]; then
+    LOG "RELEASE \"$SOURCE\" :"
+    for c in md5 sha1 sha256 sha512; do
+        LOG "$(printf '%8s: %s' "$c" $("${c}sum" "$SOURCE" | sed 's/ .*//'))"
+    done
+    LOG
+fi
diff --git a/contrib/fedora/rpm/build_clean.sh b/contrib/fedora/rpm/build_clean.sh
new file mode 100755
index 00000000..d06d4341
--- /dev/null
+++ b/contrib/fedora/rpm/build_clean.sh
@@ -0,0 +1,303 @@
+#!/bin/bash
+
+
+die() {
+    echo "$*" >&2
+    exit 1
+}
+
+usage() {
+    echo "USAGE: $0 [-h|--help|-?|help] [-f|--force] [-c|--clean] [-S|--srpm] [-g|--git] [-Q|--quick] [-N|--no-dist] [[-w|--with OPTION] ...] [[-W|--without OPTION] ...]"
+    echo
+    echo "Does all the steps from a clean git working directory to an RPM of NetworkManager"
+    echo
+    echo "This is also the preferred way to create a distribution tarball for release:"
+    echo "  $ $0 -r"
+    echo
+    echo "Options:"
+    echo "  -f|--force: force build, even if working directory is not clean and has local modifications"
+    echo "  -c|--clean: run \`git-clean -fdx :/\` before build"
+    echo "  -S|--srpm: only build the SRPM"
+    echo "  -g|--git: create tarball from current git HEAD (skips make dist)"
+    echo "  -Q|--quick: only create the distribution tarball, without running checks"
+    echo "  -N|--no-dist: skip creating the source tarball if you already did \`make dist\`"
+    echo "  -m|--meson: (default) use meson to create the source tarball"
+    echo "  -A|--autotools: use autotools to create the source tarball"
+    echo "  -w|--with \$OPTION: pass --with \$OPTION to rpmbuild. For example --with debug"
+    echo "  -W|--without \$OPTION: pass --without \$OPTION to rpmbuild. For example --without debug"
+    echo "  -s|--snapshot TEXT: use TEXT as the snapshot version for the new package (overwrites \$NM_BUILD_SNAPSHOT environment)"
+    echo "  -r|--release: built a release tarball (this option must be alone)"
+    echo "  --default-for-debug \$OPTION: set the default for "debug" option in the generated spec file"
+    echo "  --default-for-lto \$OPTION: set the default for "lto" option in the generated spec file"
+    echo "  --default-for-test \$OPTION: set the default for "test" option in the generated spec file"
+}
+
+in_set() {
+    local v="$1"
+    shift
+    for v2; do
+        test "$v" = "$v2" && return 0
+    done
+    return 1
+}
+
+ORIGDIR="$(readlink -f "$PWD")"
+SCRIPTDIR="$(dirname "$(readlink -f "$0")")"
+GITDIR="$(cd "$SCRIPTDIR" && git rev-parse --show-toplevel || die "Could not get GITDIR")"
+
+
+[[ -x "$SCRIPTDIR"/build.sh ]] || die "could not find \"$SCRIPTDIR/build.sh\""
+
+cd "$GITDIR" || die "could not change to $GITDIR"
+
+IGNORE_DIRTY=0
+GIT_CLEAN=0
+QUICK=0
+NO_DIST=0
+WITH_LIST=()
+SOURCE_FROM_GIT=0
+SNAPSHOT="$NM_BUILD_SNAPSHOT"
+DO_RELEASE=0
+unset BCOND_DEFAULT_DEBUG
+unset BCOND_DEFAULT_LTO
+unset BCOND_DEFAULT_TEST
+
+ADD_WITH_TEST=1
+
+NARGS=$#
+
+while [[ $# -gt 0 ]]; do
+    A="$1"
+    shift
+    case "$A" in
+        -h|--help|-\?|help)
+            usage
+            exit 0
+            ;;
+        -f|--force)
+            IGNORE_DIRTY=1
+            ;;
+        -r|--release)
+            [[ $NARGS -eq 1 ]] || die "--release option must be alone"
+            export NMTST_CHECK_GTK_DOC=1
+            BUILDTYPE=SRPM
+            DO_RELEASE=1
+            ;;
+        -c|--clean)
+            GIT_CLEAN=1
+            ;;
+        -S|--srpm)
+            BUILDTYPE=SRPM
+            ;;
+        -s|--snapshot)
+            [[ $# -gt 0 ]] || die "Missing argument to $A"
+            SNAPSHOT="$1"
+            shift
+            ;;
+        -g|--git)
+            NO_DIST=1
+            IGNORE_DIRTY=1
+            SOURCE_FROM_GIT=1
+            ;;
+        -m|--meson)
+            [ "$USE_AUTOTOOLS" = 1 ] && die "conflicting argument: $A when building with autotools is requested";
+            USE_MESON=1
+            ;;
+        -A|--autotools)
+            [ "$USE_MESON" = 1 ] && die "conflicting argument: $A when building with meson is explicitly requested";
+            USE_AUTOTOOLS=1
+            ;;
+        -Q|--quick)
+            QUICK=1
+            ;;
+        -N|--no-dist)
+            NO_DIST=1
+            IGNORE_DIRTY=1
+            SOURCE_FROM_GIT=0
+            ;;
+        -w|--with)
+            [[ $# -gt 0 ]] || die "Missing argument to $A"
+            WITH_LIST=("${WITH_LIST[@]}" "--with" "$1")
+            case "$1" in
+                debug)
+                    [[ -z ${BCOND_DEFAULT_DEBUG+.} ]] && BCOND_DEFAULT_DEBUG=1
+                    ;;
+                lto)
+                    [[ -z ${BCOND_DEFAULT_LTO+.} ]] && BCOND_DEFAULT_LTO=1
+                    ;;
+                test)
+                    ADD_WITH_TEST=0
+                    [[ -z ${BCOND_DEFAULT_TEST+.} ]] && BCOND_DEFAULT_TEST=1
+                    ;;
+            esac
+            shift
+            ;;
+        -W|--without)
+            [[ $# -gt 0 ]] || die "Missing argument to $A"
+            WITH_LIST=("${WITH_LIST[@]}" "--without" "$1")
+            case "$1" in
+                debug)
+                    [[ -z ${BCOND_DEFAULT_DEBUG+.} ]] && BCOND_DEFAULT_DEBUG=0
+                    ;;
+                lto)
+                    [[ -z ${BCOND_DEFAULT_LTO+.} ]] && BCOND_DEFAULT_LTO=0
+                    ;;
+                test)
+                    ADD_WITH_TEST=0
+                    [[ -z ${BCOND_DEFAULT_TEST+.} ]] && BCOND_DEFAULT_TEST=0
+                    ;;
+            esac
+            shift
+            ;;
+        --no-auto-with-test)
+            # by default, the script adds "-w test" (unless the command line contains
+            # "-w test" or "-W test"). This flags allows to suppress that automatism.
+            # It's really only useful to test the spec file's internal default for the
+            # "test" option. Otherwise, you can always just explicitly select "-w test"
+            # or "-W test".
+            ADD_WITH_TEST=0
+            ;;
+        --default-for-debug)
+            [[ $# -gt 0 ]] || die "Missing argument to $A"
+            in_set "$1" "" 0 1 || die "invalid argument $A \"$1\""
+            BCOND_DEFAULT_DEBUG="$1"
+            shift
+            ;;
+        --default-for-lto)
+            [[ $# -gt 0 ]] || die "Missing argument to $A"
+            in_set "$1" "" 0 1 || die "invalid argument $A \"$1\""
+            BCOND_DEFAULT_LTO="$1"
+            shift
+            ;;
+        --default-for-test)
+            [[ $# -gt 0 ]] || die "Missing argument to $A"
+            in_set "$1" "" 0 1 || die "invalid argument $A \"$1\""
+            BCOND_DEFAULT_TEST="$1"
+            shift
+            ;;
+        *)
+            usage
+            die "Unexpected argument \"$A\""
+            ;;
+    esac
+done
+
+if [[ $GIT_CLEAN == 1 ]]; then
+    git clean -fdx :/
+fi
+
+if [[ $IGNORE_DIRTY != 1 ]]; then
+    # check for a clean working directory.
+    # We ignore the /contrib directory, because this is where the automation
+    # scripts and the build results will be.
+    if [[ "x$(LANG=C git clean -ndx | grep '^Would \(remove contrib/\|skip repository libgsystem/\).*$' -v)" != x ]]; then
+        die "The working directory is not clean. Refuse to run. Try \`$0 --force\`, \`$0 --clean\`, or \`git clean -e :/contrib -dx -n\`"
+    fi
+    if [[ "x$(git status --porcelain)" != x ]]; then
+        die "The working directory has local changes. Refuse to run. Try \`$0 --force\`"
+    fi
+fi
+
+get_version_meson() {
+    meson introspect "$GITDIR/build" --projectinfo | jq -r .version
+}
+
+if [[ $NO_DIST != 1 ]]; then
+    if [[ $USE_AUTOTOOLS != 1 ]]; then
+            meson setup "$GITDIR/build" \
+                --prefix=/usr \
+                --bindir=/usr/bin \
+                --sbindir=/usr/sbin \
+                --sysconfdir=/etc \
+                --datadir=/usr/share \
+                --includedir=/usr/include \
+                --libdir=/usr/lib \
+                --libexecdir=/usr/libexec \
+                --localstatedir=/var \
+                --sharedstatedir=/var/lib \
+                --mandir=/usr/share/man \
+                --infodir=/usr/share/info \
+                -Ddocs=true \
+                -Dintrospection=true \
+                -Difcfg_rh=true \
+                -Difupdown=true \
+                -Dconfig_logging_backend_default=syslog \
+                -Dconfig_wifi_backend_default=wpa_supplicant \
+                -Dlibaudit=yes-disabled-by-default \
+                -Dpolkit=true \
+                -Dnm_cloud_setup=true \
+                -Dconfig_dhcp_default=internal \
+                -Dconfig_dns_rc_manager_default=auto \
+                -Diptables=/usr/sbin/iptables \
+                -Dnft=/usr/bin/nft \
+                || die "Error meson setup"
+
+            VERSION="${VERSION:-$(get_version_meson || die "Could not read $VERSION")}"
+            if [[ $QUICK == 1 ]]; then
+                meson dist --allow-dirty -C "$GITDIR/build/" --no-tests || die "Error meson dist"
+            else
+                meson dist --allow-dirty -C "$GITDIR/build/" || die "Error meson dist with tests"
+            fi
+            export SOURCE="$(ls -1 "$GITDIR/build/meson-dist/NetworkManager-${VERSION}.tar.xz" 2>/dev/null | head -n1)"
+    else
+        ./autogen.sh \
+            --with-runstatedir=/run \
+            --program-prefix= \
+            --prefix=/usr \
+            --exec-prefix=/usr \
+            --bindir=/usr/bin \
+            --sbindir=/usr/sbin \
+            --sysconfdir=/etc \
+            --datadir=/usr/share \
+            --includedir=/usr/include \
+            --libdir=/usr/lib \
+            --libexecdir=/usr/libexec \
+            --localstatedir=/var \
+            --sharedstatedir=/var/lib \
+            --mandir=/usr/share/man \
+            --infodir=/usr/share/info \
+            \
+            --disable-dependency-tracking \
+            --enable-gtk-doc \
+            --enable-introspection \
+            --enable-ifcfg-rh \
+            --enable-ifupdown \
+            --with-config-logging-backend-default=syslog \
+            --with-config-wifi-backend-default=wpa_supplicant \
+            --with-libaudit=yes-disabled-by-default \
+            --enable-polkit=yes \
+            --with-nm-cloud-setup=yes \
+            --with-config-dhcp-default=internal \
+            --with-config-dns-rc-manager-default=auto \
+            \
+            --with-iptables=/usr/sbin/iptables \
+            --with-nft=/usr/sbin/nft \
+            \
+            || die "Error autogen.sh"
+        if [[ $QUICK == 1 ]]; then
+            make dist -j 7 || die "Error make dist"
+        else
+            make distcheck -j 7 || die "Error make distcheck"
+        fi
+    fi
+fi
+
+if [[ "$ADD_WITH_TEST" == 1 ]]; then
+    WITH_LIST=("${WITH_LIST[@]}" "--with" "test")
+fi
+
+if [[ "$USE_AUTOTOOLS" != 1 ]]; then
+    WITH_LIST=("${WITH_LIST[@]}" "--with" "meson")
+fi
+
+export SOURCE_FROM_GIT
+export BUILDTYPE
+export NM_RPMBUILD_ARGS="${WITH_LIST[@]}"
+export SNAPSHOT
+export DO_RELEASE
+export BCOND_DEFAULT_DEBUG="$BCOND_DEFAULT_DEBUG"
+export BCOND_DEFAULT_LTO="$BCOND_DEFAULT_LTO"
+export BCOND_DEFAULT_TEST="$BCOND_DEFAULT_TEST"
+
+"$SCRIPTDIR"/build.sh
+
diff --git a/contrib/fedora/rpm/configure-for-system.sh b/contrib/fedora/rpm/configure-for-system.sh
new file mode 100755
index 00000000..acf5eb9c
--- /dev/null
+++ b/contrib/fedora/rpm/configure-for-system.sh
@@ -0,0 +1,526 @@
+#!/bin/bash
+
+# Run configure/meson for NetworkManager in a way similar to how an RPM build does it.
+# The effect is, that if you do `make install`, that it will overwrite the files that
+# you'd usually get by installing the NetworkManager RPM. Also, it means you can afterwards
+# systemctl restart NetworkManager.
+
+die() {
+    printf "%s\n" "$*"
+    exit 1
+}
+
+BASE_DIR="$(cd "$(dirname "$BASH_SOURCE")"; git rev-parse --show-toplevel)"
+
+cd "$BASE_DIR" || die "Cannot cd to base directory"
+
+vars() {
+    sed -e '1,/[P]VARS/!d' "$BASH_SOURCE" | sed -n 's/^'"$1"'_\([^=]*\)=.*/\1/p'
+}
+
+vars_with_vals() {
+    echo "Variables:"
+    for v in $(vars P); do
+        printf "  %s=%q\n" "$v" "$(eval "echo \"\$P_$v\"")"
+    done
+    echo "Directories:"
+    for v in $(vars D); do
+        printf "  %s=%q\n" "$v" "$(eval "echo \"\$D_$v\"")"
+    done
+}
+
+usage() {
+    echo "$ $0 [-m|--meson] [-a|--autotools] [-s|--show] [-B|--no-build] [-h|--help]"
+    echo ""
+    echo "Configure NetworkManager in a way that is similar to when building"
+    echo "RPMs of NetworkManager for Fedora/RHEL. The effect is that \`make install\`"
+    echo "will overwrite the files in /usr that you installed via the package management"
+    echo "systemd. Also, subsequent \`systemctl restart NetworkManager\` works."
+    echo "You don't want to do this on your real system, because it messes up your"
+    echo "installation"
+    echo
+
+    vars_with_vals
+}
+
+get_version() {
+    local major minor micro
+    local F="./configure.ac"
+
+    vars="$(sed -n 's/^m4_define(\[nm_\(major\|minor\|micro\)_version\], *\[\([0-9]\+\)\]) *$/local \1='\''\2'\''/p' "$F" 2>/dev/null)"
+    eval "$vars"
+
+    [[ -n "$major" && -n "$minor" && "$micro" ]] || return 1
+    echo "$major.$minor.$micro"
+}
+
+bool() {
+    case "$1" in
+        1|y|Y|yes|Yes|YES|true|True|TRUE)
+            return 0
+            ;;
+        0|n|N|no|No|NO|false|False|FALSE)
+            return 1
+            ;;
+        *)
+            local re='^[0-9]+$'
+            [[ $1 =~ $re ]] && test "$1" -gt 0 && return 0
+            [ "$#" -le "1" ] && return 1
+            shift
+            bool "$@"
+            return $?
+            ;;
+    esac
+}
+
+bool_true() {
+    if bool "$@"; then
+        echo true
+    else
+        echo false
+    fi
+}
+
+bool_not_true() {
+    if bool "$@"; then
+        echo false
+    else
+        echo true
+    fi
+}
+
+bool_enable() {
+    if bool "$@"; then
+        echo enable
+    else
+        echo disable
+    fi
+}
+
+bool_not_enable() {
+    if bool "$@"; then
+        echo disable
+    else
+        echo enable
+    fi
+}
+
+bool_yes() {
+    if bool "$@"; then
+        echo yes
+    else
+        echo no
+    fi
+}
+
+bool_not_yes() {
+    if bool "$@"; then
+        echo no
+    else
+        echo yes
+    fi
+}
+
+args_enable() {
+    local cond="$1"
+    local a
+    shift
+    if bool "$cond" ; then
+        for a; do
+            printf "%q\n" "$a"
+        done
+    fi
+}
+
+show_cmd() {
+    local a
+    local sep=
+
+    for a; do
+        printf '%s%q' "$sep" "$a"
+        sep=' '
+    done
+    printf '\n'
+}
+
+SHOW_CMD=
+
+P_NOBUILD="${NOBUILD-0}"
+
+P_DEBUG="${DEBUG-1}"
+
+P_BUILD_TYPE="${BUILD_TYPE-}"
+P_CFLAGS="${CFLAGS-}"
+P_CC="${CC-$((! command -v gcc && command -v clang) &>/dev/null && echo clang || echo gcc)}"
+
+P_RHEL="${RHEL-}"
+P_FEDORA="${FEDORA-}"
+
+P_CONFIG_PLUGINS_DEFAULT_IFCFG_RH="${CONFIG_PLUGINS_DEFAULT_IFCFG_RH-}"
+P_CRYPTO="${CRYPTO-}"
+P_DBUS_SYS_DIR="${DBUS_SYS_DIR-}"
+P_DHCP_DEFAULT="${DHCP_DEFAULT-}"
+P_DNS_RC_MANAGER_DEFAULT="${DNS_RC_MANAGER_DEFAULT-}"
+P_EBPF_ENABLED="${EBPF_ENABLED-no}"
+P_FIREWALLD_ZONE="${FIREWALLD_ZONE-}"
+P_IWD="${IWD-}"
+P_LOGGING_BACKEND_DEFAULT="${LOGGING_BACKEND_DEFAULT-}"
+P_LTO="${LTO-0}"
+P_MODEM_MANAGER_1="${MODEM_MANAGER_1-}"
+P_TEST="${TEST-1}"
+P_SILENT_RULES="${SILENT_RULES-1}"
+
+P_VERSION="${VERSION:-$(get_version)}"
+P_RELEASE="${RELEASE:-$(git rev-list HEAD | wc -l).test}"
+
+P_REGEN_DOCS="${REGEN_DOCS-1}"
+P_SANITIZER="${SANITIZER-0}"
+
+P_WIFI="${WIFI-1}"
+P_WWAN="${WWAN-1}"
+P_TEAM="${TEAM-1}"
+P_BLUETOOTH="${BLUETOOTH-1}"
+P_NMTUI="${NMTUI-1}"
+P_NM_CLOUD_SETUP="${NM_CLOUD_SETUP-1}"
+P_OVS="${OVS-1}"
+P_PPP="${PPP-1}"
+
+P_PPP_VERSION="${PPP_VERSION-}"
+
+D_PREFIX="$(rpm --eval "%{_prefix}")"
+D_BINDIR="$(rpm --eval "%{_bindir}")"
+D_SBINDIR="$(rpm --eval "%{_sbindir}")"
+D_LIBDIR="$(rpm --eval "%{_libdir}")"
+D_LIBEXECDIR="$(rpm --eval "%{_libexecdir}")"
+D_INCLUDEDIR="$(rpm --eval "%{_includedir}")"
+D_DATADIR="$(rpm --eval "%{_datadir}")"
+D_RUNDIR="$(rpm --eval "%{_rundir}")"
+D_MANDIR="$(rpm --eval "%{_mandir}")"
+D_INFODIR="$(rpm --eval "%{_infodir}")"
+D_SYSCONFDIR="$(rpm --eval "%{_sysconfdir}")"
+D_LOCALSTATEDIR="$(rpm --eval "%{_localstatedir}")"
+D_SHAREDSTATEDIR="$(rpm --eval "%{_sharedstatedir}")"
+
+#PVARS
+
+if [ -z "$P_FEDORA" -a -z "$P_RHEL" ] ; then
+    x="$(grep -q "ID=fedora" /etc/os-release && sed -n 's/VERSION_ID=//p' /etc/os-release)"
+    if test "$x" -gt 0 ; then
+        P_FEDORA="$x"
+        P_RHEL=0
+    else
+        x="$(grep -q "ID=fedora" /etc/os-release && sed -n 's/VERSION_ID=//p' /etc/os-release)"
+        if test "$x" -gt 0 ; then
+            P_FEDORA=0
+            P_RHEL="$x"
+        fi
+    fi
+fi
+test -z "$P_FEDORA" && P_FEDORA=0
+test -z "$P_RHEL" && P_RHEL=0
+
+test "$P_FEDORA" -gt 0 -o "$P_RHEL" -gt 0 || die "FEDORA/RHEL variables unset"
+
+if [ -z "$P_PPP_VERSION" ] ; then
+    P_PPP_VERSION="$(sed -n 's/^#define\s*VERSION\s*"\([^\s]*\)"$/\1/p' "$D_INCLUDEDIR/pppd/patchlevel.h" 2>/dev/null | grep . || echo bad)"
+fi
+
+if [ -z "$P_CRYPTO" ] ; then
+    if [ "$P_FEDORA" -ge 29 -o "$P_RHEL" -ge 8  ] ; then
+        P_CRYPTO=gnutls
+    else
+        P_CRYPTO=nss
+    fi
+fi
+
+if [ -z "$P_CONFIG_PLUGINS_DEFAULT_IFCFG_RH" ] ; then
+    if [ "$P_FEDORA" -ge 33 -o  "$P_RHEL" -ge 9 ] ; then
+        P_CONFIG_PLUGINS_DEFAULT_IFCFG_RH=0
+    else
+        P_CONFIG_PLUGINS_DEFAULT_IFCFG_RH=1
+    fi
+fi
+
+
+if [ -z "$P_DBUS_SYS_DIR" ] ; then
+    if [ "$P_FEDORA" -ge 1 -o  "$P_RHEL" -ge 8 ] ; then
+        P_DBUS_SYS_DIR="$D_DATADIR/dbus-1/system.d"
+    else
+        P_DBUS_SYS_DIR="$D_SYSCONFDIR/dbus-1/system.d"
+    fi
+fi
+
+if [ -z "$P_DNS_RC_MANAGER_DEFAULT" ] ; then
+    if [ "$P_FEDORA" -ge 1 -o  "$P_RHEL" -ge 9 ] ; then
+        P_DNS_RC_MANAGER_DEFAULT=auto
+    elif [ "$P_FEDORA" -ge 1 -o  "$P_RHEL" -ge 8 ] ; then
+        P_DNS_RC_MANAGER_DEFAULT=symlink
+    else
+        P_DNS_RC_MANAGER_DEFAULT=file
+    fi
+fi
+
+if [ -z "$P_LOGGING_BACKEND_DEFAULT" ] ; then
+    if [ "$P_FEDORA" -ge 1 -o  "$P_RHEL" -ge 8 ] ; then
+        P_LOGGING_BACKEND_DEFAULT=journal
+    else
+        P_LOGGING_BACKEND_DEFAULT=syslog
+    fi
+fi
+
+if [ -z "$P_DHCP_DEFAULT" ] ; then
+    if [ "$P_FEDORA" -ge 31 -o "$P_RHEL" -ge 8 ] ; then
+        P_DHCP_DEFAULT=internal
+    else
+        P_DHCP_DEFAULT=dhclient
+    fi
+fi
+
+if [ -z "$P_FIREWALLD_ZONE" ] ; then
+    if [ "$P_FEDORA" -ge 32 -o "$P_RHEL" -ge 8 ] ; then
+        P_FIREWALLD_ZONE=1
+    else
+        P_FIREWALLD_ZONE=0
+    fi
+fi
+
+if [ -z "$P_IWD" ] ; then
+    if [ "$P_RHEL" -ge 1 ] ; then
+        P_IWD=0
+    else
+        P_IWD=1
+    fi
+fi
+
+if [ -z "$P_MODEM_MANAGER_1" ] ; then
+    if bool "$P_BLUETOOTH" || bool "$P_WWAN" ; then
+        P_MODEM_MANAGER_1=1
+    else
+        P_MODEM_MANAGER_1=0
+    fi
+fi
+
+if bool "$P_DEBUG" ; then
+    P_CFLAGS="-g -Og -fexceptions${P_CFLAGS:+ }$P_CFLAGS"
+else
+    P_CFLAGS="-g -O2 -fexceptions${P_CFLAGS:+ }$P_CFLAGS"
+fi
+
+if [ -z "$P_BUILD_TYPE" ] ; then
+    if [ -d ./build -a ! -f ./configure ] ; then
+        P_BUILD_TYPE=meson
+    elif [ ! -d ./build -a -f ./configure ] ; then
+        P_BUILD_TYPE=autotools
+    else
+        P_BUILD_TYPE=autotools
+    fi
+fi
+
+while [[ $# -gt 0 ]] ; do
+    A="$1"
+    shift
+    case "$A" in
+        --meson|-m)
+            P_BUILD_TYPE=meson
+            ;;
+        --autotools|-a)
+            P_BUILD_TYPE=autotools
+            ;;
+        -s|--show)
+            SHOW_CMD=show_cmd
+            ;;
+        -h|help|-help|--help)
+            usage
+            exit 0
+            ;;
+        -B|--no-build)
+            P_NOBUILD=1
+            ;;
+        *)
+            usage
+            exit 1
+            ;;
+    esac
+done
+
+vars_with_vals
+
+if [ "$P_BUILD_TYPE" == meson ] ; then
+    MESON_RECONFIGURE=
+    if test -d "./build/" ; then
+        MESON_RECONFIGURE="--reconfigure"
+    fi
+
+    $SHOW_CMD \
+    env \
+    CC="$P_CC" \
+    CFLAGS="$P_CFLAGS" \
+    meson \
+        --buildtype=plain \
+        --prefix="$D_PREFIX" \
+        --libdir="$D_LIBDIR" \
+        --libexecdir="$D_LIBEXECDIR" \
+        --bindir="$D_BINDIR" \
+        --sbindir="$D_SBINDIR" \
+        --includedir="$D_INCLUDEDIR" \
+        --datadir="$D_DATADIR" \
+        --mandir="$D_MANDIR" \
+        --infodir="$D_INFODIR" \
+        --localedir="$D_DATADIR"/locale \
+        --sysconfdir="$D_SYSCONFDIR" \
+        --localstatedir="$D_LOCALSTATEDIR" \
+        --sharedstatedir="$D_SHAREDSTATEDIR" \
+        --wrap-mode=nodownload \
+        --auto-features=enabled \
+        \
+        build \
+        \
+        $MESON_RECONFIGURE \
+        \
+        -Db_ndebug=false \
+        --warnlevel 2 \
+        $(args_enable "$P_TEST" --werror) \
+        -Dnft="${D_SBINDIR}/nft" \
+        -Diptables="${D_SBINDIR}/iptables" \
+        -Ddhclient="${D_SBINDIR}/dhclient" \
+        -Ddhcpcanon=no \
+        -Ddhcpcd=no \
+        -Dconfig_dhcp_default="$P_DHCP_DEFAULT" \
+        "-Dcrypto=$P_CRYPTO" \
+        $(args_enable "$P_DEBUG"                    -Dmore_logging=true  -Dmore_asserts=10000) \
+        $(args_enable "$(bool_not_true "$P_DEBUG")" -Dmore_logging=false -Dmore_asserts=0    ) \
+        -Dld_gc=true \
+        -Db_lto="$(bool_true "$P_LTO")" \
+        -Dlibaudit=yes-disabled-by-default \
+        -Dmodem_manager="$(bool_true "$P_MODEM_MANAGER_1")" \
+        $(args_enable "$P_WIFI"                    -Dwifi=true  -Dwext="$(bool_true "$P_FEDORA")") \
+        $(args_enable "$(bool_not_true "$P_WIFI")" -Dwifi=false                                  ) \
+        -Diwd="$(bool_true "$P_IWD")" \
+        -Dbluez5_dun="$(bool_true "$P_BLUETOOTH")" \
+        -Dnmtui="$(bool_true "$P_NMTUI")" \
+        -Dnm_cloud_setup="$(bool_true "$P_NM_CLOUD_SETUP")" \
+        -Dvapi=true \
+        -Dintrospection=true \
+        -Ddocs="$(bool_true "$P_REGEN_DOCS")" \
+        -Dteamdctl="$(bool_true "$P_TEAM")" \
+        -Dovs="$(bool_true "$P_OVS")" \
+        -Dselinux=true \
+        -Dpolkit=true  \
+        -Dconfig_auth_polkit_default=true \
+        -Dmodify_system=true \
+        -Dconcheck=true \
+        -Dlibpsl="$(bool_true "$P_FEDORA")" \
+        -Debpf="$(bool_true "$P_EBPF_ENABLED")" \
+        -Dsession_tracking=systemd \
+        -Dsuspend_resume=systemd \
+        -Dsystemdsystemunitdir=/usr/lib/systemd/system \
+        -Dsystem_ca_path=/etc/pki/tls/cert.pem \
+        -Ddbus_conf_dir="$P_DBUS_SYS_DIR" \
+        -Dtests=yes \
+        -Dvalgrind=no \
+        -Difcfg_rh=true \
+        -Difupdown=false \
+        $(args_enable "$P_PPP"                    -Dppp=true  -Dpppd="$D_SBINDIR/pppd" -Dpppd_plugin_dir="$D_LIBDIR/pppd/$P_PPP_VERSION") \
+        $(args_enable "$(bool_not_true "$P_PPP")" -Dppp=false                                                                           ) \
+        -Dfirewalld_zone="$(bool_true "$P_FIREWALLD_ZONE}")" \
+        -Ddist_version="$P_VERSION-$P_RELEASE" \
+        $(args_enable "$P_CONFIG_PLUGINS_DEFAULT_IFCFG_RH" -Dconfig_plugins_default=ifcfg-rh) \
+        -Dresolvconf=no \
+        -Dnetconfig=no \
+        -Dconfig_dns_rc_manager_default="$P_DNS_RC_MANAGER_DEFAULT" \
+        -Dconfig_logging_backend_default="$P_LOGGING_BACKEND_DEFAULT" \
+        ;
+else
+    if ! test -x ./configure ; then
+        if [ -z "$SHOW_CMD" ]; then
+            NOCONFIGURE=yes ./autogen.sh
+        fi
+    fi
+    $SHOW_CMD \
+    ./configure \
+        --build=x86_64-redhat-linux-gnu \
+        --host=x86_64-redhat-linux-gnu \
+        --program-prefix= \
+        --prefix="$D_PREFIX" \
+        --exec-prefix=/usr \
+        --bindir="$D_BINDIR" \
+        --sbindir="$D_SBINDIR" \
+        --sysconfdir="$D_SYSCONFDIR" \
+        --datadir="$D_DATADIR" \
+        --includedir="$D_INCLUDEDIR" \
+        --libdir="$D_LIBDIR" \
+        --libexecdir="$D_LIBEXECDIR" \
+        --localstatedir="$D_LOCALSTATEDIR" \
+        --sharedstatedir="$D_SHAREDSTATEDIR" \
+        --mandir="$D_MANDIR" \
+        --infodir="$D_INFODIR" \
+        \
+        CC="$P_CC" \
+        CFLAGS="$P_CFLAGS" \
+        \
+        --enable-dependency-tracking=yes \
+        \
+        --with-runstatedir="$D_RUNDIR" \
+        --enable-silent-rules="$(bool_yes "$P_SILENT_RULES")" \
+        --enable-static=no \
+        --with-nft="${D_SBINDIR}/nft" \
+        --with-iptables="${D_SBINDIR}/iptables" \
+        --with-dhclient="${D_SBINDIR}/dhclient" \
+        --with-dhcpcd=no \
+        --with-dhcpcanon=no \
+        --with-config-dhcp-default="$P_DHCP_DEFAULT" \
+        --with-crypto="$P_CRYPTO" \
+        $(args_enable "$P_SANITIZER"                    --with-address-sanitizer=exec --enable-undefined-sanitizer="$( (bool "$P_FEDORA" || test "$P_RHEL" -ge 8) && echo yes || echo no)" ) \
+        $(args_enable "$(bool_not_true "$P_SANITIZER")" --with-address-sanitizer=no   --enable-undefined-sanitizer=no                                                                            ) \
+        $(args_enable "$P_DEBUG"                    --enable-more-logging=yes --with-more-asserts=10000) \
+        $(args_enable "$(bool_not_true "$P_DEBUG")" --enable-more-logging=no  --with-more-asserts=0    ) \
+        --enable-ld-gc=yes \
+        --enable-lto="$(bool_yes "$P_LTO")" \
+        --with-libaudit=yes-disabled-by-default \
+        --with-modem-manager-1="$(bool_yes "$P_MODEM_MANAGER_1")" \
+        $(args_enable "$P_WIFI"                    --enable-wifi=yes --with-wext="$(bool_yes "$P_FEDORA")") \
+        $(args_enable "$(bool_not_true "$P_WIFI")" --enable-wifi=no                                       ) \
+        --with-iwd="$(bool_yes "$P_IWD")" \
+        --enable-bluez5-dun="$(bool_yes "$P_BLUETOOTH")" \
+        --with-nmtui="$(bool_yes "$P_NMTUI")" \
+        --with-nm-cloud-setup="$(bool_yes "$P_NM_CLOUD_SETUP")" \
+        --enable-vala=yes \
+        --enable-introspection=yes \
+        --enable-gtk-doc="$(bool_yes "$P_REGEN_DOCS")" \
+        --enable-teamdctl="$(bool_yes "$P_TEAM")" \
+        --enable-ovs="$(bool_yes "$P_OVS")" \
+        --with-selinux=yes \
+        --enable-polkit=yes \
+        --enable-modify-system=yes \
+        --enable-concheck=yes \
+        --with-libpsl="$(bool_yes "$P_FEDORA")" \
+        --with-ebpf="$(bool_yes "$P_EBPF_ENABLED")" \
+        --with-session-tracking=systemd \
+        --with-suspend-resume=systemd \
+        --with-systemdsystemunitdir=/usr/lib/systemd/system \
+        --with-system-ca-path=/etc/pki/tls/cert.pem \
+        --with-dbus-sys-dir="$P_DBUS_SYS_DIR" \
+        --with-tests=yes \
+        --enable-more-warnings="$(bool "$P_TEST" && echo error || echo yes)" \
+        --with-valgrind=no \
+        --enable-ifcfg-rh=yes \
+        --enable-ifupdown=no \
+        $(args_enable "$P_PPP"                    --enable-ppp=yes --with-pppd="$D_SBINDIR/pppd" --with-pppd-plugin-dir="$D_LIBDIR/pppd/$P_PPP_VERSION") \
+        $(args_enable "$(bool_not_true "$P_PPP")" --enable-ppp=no                                                                                      ) \
+        --enable-firewalld-zone="$(bool_yes "$P_FIREWALLD_ZONE")" \
+        --with-dist-version="$P_VERSION-$P_RELEASE" \
+        $(args_enable "$P_CONFIG_PLUGINS_DEFAULT_IFCFG_RH" --with-config-plugins-default=ifcfg-rh) \
+        --with-resolvconf=no \
+        --with-netconfig=no \
+        --with-config-dns-rc-manager-default="$P_DNS_RC_MANAGER_DEFAULT" \
+        --with-config-logging-backend-default="$P_LOGGING_BACKEND_DEFAULT" \
+        ;
+fi
+
+if ! bool "$P_NOBUILD" ; then
+    if [ "$P_BUILD_TYPE" == meson ] ; then
+        $SHOW_CMD ninja -C build
+    else
+        $SHOW_CMD make -j 10
+    fi
+fi
diff --git a/contrib/fedora/rpm/mockbuild.sh b/contrib/fedora/rpm/mockbuild.sh
new file mode 100755
index 00000000..785aa254
--- /dev/null
+++ b/contrib/fedora/rpm/mockbuild.sh
@@ -0,0 +1,20 @@
+#!/bin/sh
+#
+# mockbuild.sh
+#
+# Generate SRPM from git tree and rebuild it using mock.
+
+SCRIPTDIR="$(dirname "$(readlink -f "$0")")"
+FEDORAVER=$(sed -E 's/.*([0-9]{2}).*/\1/g' /etc/fedora-release)
+ARCH=$(uname -m)
+SRPM=${SCRIPTDIR}/latest/SRPMS/NetworkManager*.src.rpm
+
+alias mock="mock -r fedora-${FEDORAVER}-${ARCH}"
+
+# Generate SRPM
+${SCRIPTDIR}/build_clean.sh --srpm --git
+
+# Rebuild SRPM
+mock --rebuild ${SRPM}
+
+exit
diff --git a/contrib/fedora/rpm/readme-ifcfg-rh-migrated.txt b/contrib/fedora/rpm/readme-ifcfg-rh-migrated.txt
new file mode 100644
index 00000000..aabbcc86
--- /dev/null
+++ b/contrib/fedora/rpm/readme-ifcfg-rh-migrated.txt
@@ -0,0 +1,84 @@
+NetworkManager was built to automatically migrate connection profiles in
+this directory to equivalent ones in keyfile format in directory
+/etc/NetworkManager/system-connections.
+
+You can check whether the migration is enabled via:
+
+ $ NetworkManager --print-config | grep migrate-ifcfg-rh
+
+In case it is enabled, all files in this directory are migrated at startup.
+
+To inspect where your connection files are currently stored use:
+
+ $ nmcli -f name,uuid,filename connection
+
+Background
+==========
+
+The ifcfg format is deprecated and will be removed in future releases. For
+more information see:
+
+https://lists.freedesktop.org/archives/networkmanager/2023-May/000103.html
+
+Connection profiles in keyfile format have many benefits. For example, this
+format is INI file-based and can easily be parsed and generated.
+
+Each section in NetworkManager keyfiles corresponds to a NetworkManager
+setting name as described in the nm-settings(5) and nm-settings-keyfile(5)
+man pages. Each key-value pair in a section is one of the properties listed
+in the settings specification of the man page.
+
+How to keep using ifcfg
+=======================
+
+If you want to keep using connection profiles in ifcfg format, you need to:
+
+ - disable the automatic migration to keyfile by setting
+   "migrate-ifcfg-rh=false" in the [main] section of NetworkManager
+   configuration;
+
+ - optionally, set "plugins=ifcfg-rh" in the [main] section of
+   NetworkManager configuration so that new profiles are created in ifcfg
+   format.
+
+At this point, you can migrate all your files back via
+
+  nmcli connection migrate --plugin ifcfg-rh
+
+Or, if you prefer to migrate only specific connections:
+
+  nmcli connection migrate --plugin ifcfg-rh <profile_name|UUID>
+
+Note that some connection types are not supported by the ifcfg plugin.
+
+Interface renaming
+==================
+
+Connection profiles stored in ifcfg-rh format support the renaming of
+interfaces via udev. This is done via a helper tool
+/usr/lib/udev/rename_device that is invoked by udev to parse the files
+in /etc/sysconfig/network-scripts; when the HWADDR and DEVICE
+variables are set, the interface that matches the MAC address in
+HWADDR is renamed to the name specified in DEVICE.
+
+Connections in keyfile format don't provide the same integration with
+udev. The renaming of interfaces must be configured directly in udev,
+for example by creating a file:
+
+  /etc/systemd/network/70-rename.link
+
+with content:
+
+  [Match]
+  MACAddress=00:11:22:33:44:56
+
+  [Link]
+  Name=ethernet1
+
+Alternatively, a udev rule can also be used, such as:
+
+  /etc/udev/rules.d/70-interface-names.rules
+
+with content:
+
+  SUBSYSTEM=="net",ACTION=="add",ATTR{address}=="00:11:22:33:44:56",ATTR{type}=="1",NAME="ethernet1"
diff --git a/contrib/fedora/rpm/readme-ifcfg-rh.txt b/contrib/fedora/rpm/readme-ifcfg-rh.txt
new file mode 100644
index 00000000..56c373d4
--- /dev/null
+++ b/contrib/fedora/rpm/readme-ifcfg-rh.txt
@@ -0,0 +1,63 @@
+NetworkManager stores new network profiles in keyfile format in the
+/etc/NetworkManager/system-connections/ directory.
+
+Previously, NetworkManager stored network profiles in ifcfg format
+in this directory (/etc/sysconfig/network-scripts/). However, the ifcfg
+format is deprecated. By default, NetworkManager no longer creates
+new profiles in this format.
+
+Connection profiles in keyfile format have many benefits. For example,
+this format is INI file-based and can easily be parsed and generated.
+
+Each section in NetworkManager keyfiles corresponds to a NetworkManager
+setting name as described in the nm-settings(5) and nm-settings-keyfile(5)
+man pages. Each key-value-pair in a section is one of the properties
+listed in the settings specification of the man page.
+
+If you still use network profiles in ifcfg format, consider migrating
+them to keyfile format. To migrate all profiles at once, enter:
+
+# nmcli connection migrate
+
+This command migrates all profiles from ifcfg format to keyfile
+format and stores them in /etc/NetworkManager/system-connections/.
+
+Alternatively, to migrate only a specific profile, enter:
+
+# nmcli connection migrate <profile_name|UUID|D-Bus_path>
+
+For further details, see:
+* nm-settings-keyfile(5)
+* nmcli(1)
+
+Interface renaming
+==================
+
+Connection profiles stored in ifcfg-rh format support the renaming of
+interfaces via udev. This is done via a helper tool
+/usr/lib/udev/rename_device that is invoked by udev to parse the files
+in /etc/sysconfig/network-scripts; when the HWADDR and DEVICE
+variables are set, the interface that matches the MAC address in
+HWADDR is renamed to the name specified in DEVICE.
+
+Connections in keyfile format don't provide the same integration with
+udev. The renaming of interfaces must be configured directly in udev,
+for example by creating a file:
+
+  /etc/systemd/network/70-rename.link
+
+with content:
+
+  [Match]
+  MACAddress=00:11:22:33:44:56
+
+  [Link]
+  Name=ethernet1
+
+Alternatively, a udev rule can also be used, such as:
+
+  /etc/udev/rules.d/70-interface-names.rules
+
+with content:
+
+  SUBSYSTEM=="net",ACTION=="add",ATTR{address}=="00:11:22:33:44:56",ATTR{type}=="1",NAME="ethernet1"
diff --git a/contrib/fedora/rpm/release.sh b/contrib/fedora/rpm/release.sh
new file mode 100755
index 00000000..809810f0
--- /dev/null
+++ b/contrib/fedora/rpm/release.sh
@@ -0,0 +1,604 @@
+#!/bin/bash
+
+# Script for doing NetworkManager releases.
+#
+# Run with --help for usage.
+#
+# There are 6 modes:
+#
+#  - "devel" : on main branch to tag a devel release (e.g. "1.25.2-dev").
+#  - "rc1"   : the first release candidate on "main" branch which branches off
+#              a new "nm-1-X" branch (e.g. tag "1.26-rc1" (1.25.90) and branch
+#              off "nm-1-26"). On main this also bumps the version number
+#              and creates a new devel release (e.g. "1.27.0-dev").
+#  - "rc"    : further release candidates on RC branch (e.g. from "nm-1-26" branch
+#              tag "1.26-rc2" with version number 1.25.91).
+#  - "major" : on stable branch do a major release (e.g. on "nm-1-26" branch
+#              release "1.26.0", followed by "1.26.1-dev").
+#              You should do a "major-post" release right a "major" release.
+#  - "major-post": after a "major" release, merge the release branch with main and
+#              do another devel snapshot on main (e.g. do "1.27.1-dev" release).
+#  - "minor" : on a stable branch do a minor release (e.g. "1.26.4" on "nm-1-26"
+#              branch and bump to "1.26.5-dev").
+#
+# Requisites:
+#
+#   * You need to start with a clean working directory (git clean -fdx)
+#
+#   * Run in a "clean" environment, i.e. no unusual environment variables set, on a recent
+#     Fedora, with suitable dependencies installed.
+#
+#   * First, ensure that you have ssh keys for "master.gnome.org" installed (and ssh-agent running).
+#     Also, ensure you have a GPG key that you want to use for signing. Also, have gpg-agent running
+#     and possibly configure `git config --get user.signingkey` for the proper key.
+#
+#   * Your git repository needs a remote "origin" that points to the upstream git repository
+#     (or set $ORIGIN) and use the standard git refs/remotes/$ORIGIN/ branch names.
+#
+#   * All your (relevant) local branches (main and nm-1-*) must be up to date with their
+#     remote tracking branches for origin.
+#
+# Run with --no-test to do the actual release.
+
+die() {
+    echo -n "FAIL: "
+    echo_color 31 "$@"
+    exit 1
+}
+
+echo_color() {
+    local color="$1"
+    shift
+    echo -e -n "\033[0;${color}m"
+    echo "$@"
+    echo -e -n '\033[0m'
+}
+
+print_usage() {
+    echo "Usage:"
+    echo "  $BASH_SOURCE [devel|rc1|rc|major|major-post|minor]"
+    echo "     [--no-test] \\"
+    echo "     [--no-find-backports] \\"
+    echo "     [--no-cleanup] \\"
+    echo "     [--allow-local-branches] \\"
+    echo "     [--no-check-gitlab] \\"
+    echo "     [--no-check-news] \\"
+    echo "     [--no-warn-publish-docs] \\"
+}
+
+die_help() {
+    print_usage
+    echo
+    sed -e '/^# /,/# Run with --no-test/!d' -e 's/^#\($\| \)/  /' "$BASH_SOURCE"
+    exit 0
+}
+
+die_usage() {
+    echo -n "FAIL: "
+    echo_color 31 "$@"
+    echo
+    print_usage
+    exit 1
+}
+
+do_command() {
+    local color=36
+    if [ "$DRY_RUN" = 0 ]; then
+        color=31
+    fi
+    echo -n "COMMAND: "
+    echo_color $color -n "$@"
+    echo
+    if [ "$DRY_RUN" = 0 ]; then
+        "$@"
+    fi
+}
+
+parse_version() {
+    local MAJ="$(sed -n '1,20 s/^m4_define(\[nm_major_version\], \[\([0-9]\+\)\])$/\1/p' ./configure.ac)"
+    local MIN="$(sed -n '1,20 s/^m4_define(\[nm_minor_version\], \[\([0-9]\+\)\])$/\1/p' ./configure.ac)"
+    local MIC="$(sed -n '1,20 s/^m4_define(\[nm_micro_version\], \[\([0-9]\+\)\])$/\1/p' ./configure.ac)"
+
+    re='^(0|[1-9][0-9]*) (0|[1-9][0-9]*) (0|[1-9][0-9]*)$'
+    [[ "$MAJ $MIN $MIC" =~ $re ]] || return 1
+    echo "$MAJ $MIN $MIC"
+}
+
+number_is_even() {
+    local re='^[0-9]*[02468]$'
+    [[ "$1" =~ $re ]]
+}
+
+number_is_odd() {
+    local re='^[0-9]*[13579]$'
+    [[ "$1" =~ $re ]]
+}
+
+git_same_ref() {
+    local a="$(git rev-parse "$1" 2>/dev/null)" || return 1
+    local b="$(git rev-parse "$2" 2>/dev/null)" || return 1
+    [ "$a" = "$b" ]
+}
+
+check_gitlab_pipeline() {
+    local BRANCH="$1"
+    local SHA="$2"
+    local PIPELINE_ID
+
+    PIPELINE_ID="$(curl --no-progress-meter "https://gitlab.freedesktop.org/api/v4/projects/411/pipelines?ref=$BRANCH&sha=$SHA&order_by=id" 2>/dev/null | jq '.[0].id')"
+    if ! [[ $PIPELINE_ID =~ [0-9]+ ]] ; then
+        echo "Cannot find pipeline for branch $BRANCH. Check \"https://gitlab.freedesktop.org/NetworkManager/NetworkManager/pipelines?page=1&scope=branches&ref=$BRANCH\""
+        return 1
+    fi
+
+    PIPELINE_STATUSES="$(curl --no-progress-meter "https://gitlab.freedesktop.org/api/v4/projects/411/pipelines/$PIPELINE_ID/jobs?per_page=100" 2>/dev/null | jq '.[] | select(.stage!="prep" and .stage!="tier3") | .status')"
+
+    if ! echo "$PIPELINE_STATUSES" | grep -q '^"success"$' ; then
+        echo "Cannot find successful jobs for branch $BRANCH. Check \"https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/pipelines/$PIPELINE_ID\""
+        return 1
+    fi
+    if echo "$PIPELINE_STATUSES" | grep -q -v '^"success"$' ; then
+        echo "Seems not all jobs for $BRANCH ran (or were successfull). Check \"https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/pipelines/$PIPELINE_ID\""
+        return 1
+    fi
+
+    return 0
+}
+
+set_version_number_autotools() {
+    sed -i \
+        -e '1,20 s/^m4_define(\[nm_major_version\], \[\([0-9]\+\)\])$/m4_define([nm_major_version], ['"$1"'])/' \
+        -e '1,20 s/^m4_define(\[nm_minor_version\], \[\([0-9]\+\)\])$/m4_define([nm_minor_version], ['"$2"'])/' \
+        -e '1,20 s/^m4_define(\[nm_micro_version\], \[\([0-9]\+\)\])$/m4_define([nm_micro_version], ['"$3"'])/' \
+        ./configure.ac
+}
+
+set_version_number_meson() {
+    sed -i \
+        -e '1,20 s/^\( *version: *'\''\)[0-9]\+\.[0-9]\+\.[0-9]\+\('\'',\)$/\1'"$1.$2.$3"'\2/' \
+        meson.build
+}
+
+set_version_number() {
+    set_version_number_autotools "$@" &&
+    set_version_number_meson "$@"
+}
+
+check_news() {
+    local mode="$1"
+    shift
+    local ver_arr=("$@")
+
+    case "$mode" in
+        major|minor)
+            if git grep -q 'NOT RECOMMENDED FOR PRODUCTION USE' -- ./NEWS ; then
+                return 1
+            fi
+            ;;
+        *)
+            ;;
+    esac
+    return 0
+}
+
+DO_CLEANUP=1
+CLEANUP_CHECKOUT_BRANCH=
+CLEANUP_REFS=()
+cleanup() {
+    if [ $DO_CLEANUP = 1 ]; then
+        [ -n "$CLEANUP_CHECKOUT_BRANCH" ] && git checkout -f "$CLEANUP_CHECKOUT_BRANCH"
+        for c in "${CLEANUP_REFS[@]}"; do
+            echo "delete reference. Restore with $(echo_color 36 -n git update-ref \"$c\" $(git rev-parse "$c"))"
+            git update-ref -d "$c"
+        done
+    fi
+}
+
+trap cleanup EXIT
+
+DIR="$(git rev-parse --show-toplevel)"
+
+ORIGIN=origin
+
+BASH_SOURCE_ABSOLUTE="$(readlink -f "$BASH_SOURCE")"
+
+test -d "$DIR" &&
+cd "$DIR" &&
+test -f ./contrib/fedora/rpm/build_clean.sh || die "cannot find NetworkManager base directory"
+
+RELEASE_MODE=""
+DRY_RUN=1
+FIND_BACKPORTS=1
+ALLOW_LOCAL_BRANCHES=0
+HELP_AND_EXIT=1
+CHECK_GITLAB=1
+WARN_PUBLISH_DOCS=1
+CHECK_NEWS=1
+while [ "$#" -ge 1 ]; do
+    A="$1"
+    shift
+    HELP_AND_EXIT=0
+    case "$A" in
+        --no-test)
+            DRY_RUN=0
+            ;;
+        --no-find-backports)
+            FIND_BACKPORTS=0
+            ;;
+        --no-cleanup)
+            DO_CLEANUP=0
+            ;;
+        --allow-local-branches)
+            # by default, the script errors out if the relevant branch (main, nm-1-Y) are not the same
+            # as the remote branch on origin. You should not do a release if you have local changes
+            # that differ from upstream. Set this flag to override that check.
+            ALLOW_LOCAL_BRANCHES=1
+            ;;
+        --no-check-gitlab)
+            CHECK_GITLAB=0
+            ;;
+        --no-warn-publish-docs)
+            WARN_PUBLISH_DOCS=0
+            ;;
+        --no-check-news)
+            CHECK_NEWS=0
+            ;;
+        --help|-h)
+            die_help
+            ;;
+        devel|rc1|rc|major|major-post|minor)
+            [ -z "$RELEASE_MODE" ] || die_usage "duplicate release-mode"
+            RELEASE_MODE="$A"
+            ;;
+        *)
+            die_usage "unknown argument \"$A\""
+            ;;
+    esac
+done
+[ "$HELP_AND_EXIT" = 1 ] && die_help
+
+[ -n "$RELEASE_MODE" ] || die_usage "specify the desired release mode"
+
+VERSION_ARR=( $(parse_version) ) || die "cannot detect NetworkManager version"
+VERSION_STR="$(IFS=.; echo "${VERSION_ARR[*]}")"
+
+echo "Current version before release: $VERSION_STR (do \"$RELEASE_MODE\" release)"
+
+grep -q "version: '${VERSION_ARR[0]}.${VERSION_ARR[1]}.${VERSION_ARR[2]}'," ./meson.build || die "meson.build does not have expected version"
+
+TMP="$(git status --porcelain)" || die "git status failed"
+test -z "$TMP" || die "git working directory is not clean (git status --porcelain)"
+
+TMP="$(LANG=C git clean -ndx)" || die "git clean -ndx failed"
+test -z "$TMP" || die "git working directory is not clean? (git clean -ndx)"
+
+CUR_BRANCH="$(git rev-parse --abbrev-ref HEAD)"
+CUR_HEAD="$(git rev-parse HEAD)"
+TMP_BRANCH=release-branch
+
+if [ "$CUR_BRANCH" = main ]; then
+    number_is_odd "${VERSION_ARR[1]}" || die "Unexpected version number on main. Should be an odd development version"
+    [ "$RELEASE_MODE" = devel -o "$RELEASE_MODE" = rc1 -o "$RELEASE_MODE" = major-post ] || die "Unexpected branch name \"$CUR_BRANCH\" for \"$RELEASE_MODE\""
+else
+    re='^nm-[0-9]+-[0-9]+$'
+    [[ "$CUR_BRANCH" =~ $re ]] || die "Unexpected current branch $CUR_BRANCH. Should be main or nm-?-??"
+    if number_is_odd "${VERSION_ARR[1]}"; then
+        # we are on a release candiate branch.
+        [ "$RELEASE_MODE" = rc -o "$RELEASE_MODE" = major ] || die "Unexpected branch name \"$CUR_BRANCH\" for \"$RELEASE_MODE\""
+        [ "$CUR_BRANCH" == "nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))" ] || die "Unexpected current branch $CUR_BRANCH. Should be nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))"
+    else
+        [ "$RELEASE_MODE" = minor ] || die "Unexpected branch name \"$CUR_BRANCH\" for \"$RELEASE_MODE\""
+        [ "$CUR_BRANCH" == "nm-${VERSION_ARR[0]}-${VERSION_ARR[1]}" ] || die "Unexpected current branch $CUR_BRANCH. Should be nm-${VERSION_ARR[0]}-${VERSION_ARR[1]}"
+    fi
+fi
+
+RC_VERSION=
+RELEASE_BRANCH=
+case "$RELEASE_MODE" in
+    minor)
+        number_is_even "${VERSION_ARR[1]}" &&
+        number_is_odd  "${VERSION_ARR[2]}" || die "cannot do minor release on top of version $VERSION_STR"
+        [ "$CUR_BRANCH" != main ] || die "cannot do a minor release on main"
+        ;;
+    devel)
+        number_is_odd "${VERSION_ARR[1]}" || die "cannot do devel release on top of version $VERSION_STR"
+        [ "$((${VERSION_ARR[2]} + 1))" -lt 90 ] || die "devel release must have a micro version smaller than 90 but current version is $VERSION_STR"
+        [ "$CUR_BRANCH" == main ] || die "devel release can only be on main"
+        ;;
+    rc)
+        number_is_odd "${VERSION_ARR[1]}" || die "cannot do rc release on top of version $VERSION_STR"
+        [ "${VERSION_ARR[2]}" -ge 90 ] || die "rc release must have a micro version larger than ${VERSION_ARR[0]}.90 but current version is $VERSION_STR"
+        RC_VERSION="$((${VERSION_ARR[2]} - 88))"
+        [ "$CUR_BRANCH" == "nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))" ] || die "devel release can only be on \"nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))\" branch"
+        ;;
+    rc1)
+        number_is_odd "${VERSION_ARR[1]}" || die "cannot do rc release on top of version $VERSION_STR"
+        [ "${VERSION_ARR[2]}" -lt 90 ] || die "rc release must have a micro version smaller than ${VERSION_ARR[0]}.${VERSION_ARR[1]}.90 but current version is $VERSION_STR"
+        [ "$CUR_BRANCH" == main ] || die "rc1 release can only be on main"
+        RELEASE_BRANCH="nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))"
+        ;;
+    major)
+        number_is_odd "${VERSION_ARR[1]}" || die "cannot do major release on top of version $VERSION_STR"
+        [ "${VERSION_ARR[2]}" -ge 90 ] || die "parent version for major release must have a micro version larger than ${VERSION_ARR[0]}.90 but current version is $VERSION_STR"
+        [ "$CUR_BRANCH" == "nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))" ] || die "major release can only be on \"nm-${VERSION_ARR[0]}-$((${VERSION_ARR[1]} + 1))\" branch"
+        ;;
+    major-post)
+        number_is_odd "${VERSION_ARR[1]}" || die "cannot do major-post release on top of version $VERSION_STR"
+        [ "$((${VERSION_ARR[2]} + 1))" -lt 90 ] || die "major-post release must have a micro version smaller than 90 but current version is $VERSION_STR"
+        [ "$CUR_BRANCH" == main ] || die "major-post release can only be on main"
+        ;;
+    *)
+        die "Release mode $RELEASE_MODE not yet implemented"
+        ;;
+esac
+
+git fetch "$ORIGIN" || die "git fetch failed"
+
+if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then
+    git_same_ref "$CUR_BRANCH" "refs/heads/$CUR_BRANCH" || die "Current branch $CUR_BRANCH is not a branch??"
+    git_same_ref "$CUR_BRANCH" "refs/remotes/$ORIGIN/$CUR_BRANCH" || die "Current branch $CUR_BRANCH seems not up to date with refs/remotes/$ORIGIN/$CUR_BRANCH. Git pull or --allow-local-branches?"
+fi
+
+NEWER_BRANCHES=()
+if [ "$CUR_BRANCH" != main ]; then
+    i="${VERSION_ARR[1]}"
+    while : ; do
+        i=$((i + 2))
+        b="nm-${VERSION_ARR[0]}-$i"
+        if ! git show-ref --verify --quiet "refs/remotes/$ORIGIN/$b"; then
+            git show-ref --verify --quiet "refs/heads/$b" && die "unexpectedly branch $b exists"
+            break
+        fi
+        if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then
+            git_same_ref "$b" "refs/heads/$b" || die "branch $b is not a branch??"
+            git_same_ref "$b" "refs/remotes/$ORIGIN/$b" || die "branch $b seems not up to date with refs/remotes/$ORIGIN/$b. Git pull or --allow-local-branches?"
+        fi
+        NEWER_BRANCHES+=("refs/heads/$b")
+    done
+    b=main
+    if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then
+        git_same_ref "$b" "refs/heads/$b" || die "branch $b is not a branch??"
+        git_same_ref "$b" "refs/remotes/$ORIGIN/$b" || die "branch $b seems not up to date with refs/remotes/$ORIGIN/$b. Git pull or --allow-local-branches?"
+    fi
+fi
+
+if [ -n "$RELEASE_BRANCH" ]; then
+    git show-ref --verify --quiet "refs/remotes/$ORIGIN/$RELEASE_BRANCH" && die "release branch refs/remotes/$ORIGIN/$RELEASE_BRANCH unexpectedly exists already"
+    git show-ref --verify --quiet "refs/heads/$RELEASE_BRANCH" && die "release branch refs/heads/$RELEASE_BRANCH unexpectedly exists already"
+fi
+
+if [ "$ALLOW_LOCAL_BRANCHES" != 1 ]; then
+    cmp <(git show "$ORIGIN/main:contrib/fedora/rpm/release.sh") "$BASH_SOURCE_ABSOLUTE" || die "$BASH_SOURCE is not identical to \`git show \"$ORIGIN/main:contrib/fedora/rpm/release.sh\"\`"
+fi
+
+if ! check_news "$RELEASE_MODE" "@{VERSION_ARR[@]}" ; then
+    if [ "$CHECK_NEWS" == 1 ]; then
+        die "NEWS file needs update to mention stable release (skip check with --no-check-news)"
+    fi
+    echo "WARNING: NEWS file needs update to mention stable release (test skipped with --no-check-news)"
+fi
+
+if [ "$RELEASE_MODE" = major -o "$RELEASE_MODE" = minor ]; then
+    echo
+    latest=
+    if [ "$RELEASE_MODE" = major ]; then
+        echo "Note that after the new major you have to publish the new documentation on"
+        latest=" -l"
+    else
+        echo "Note that after the stable release you maybe should publish the new documentation on"
+        latest=" [-l]"
+    fi
+    echo "$(echo_color 36 -n "https://gitlab.freedesktop.org/NetworkManager/networkmanager.pages.freedesktop.org.git") by running"
+    if [ "$RELEASE_MODE" = major ]; then
+        v="${VERSION_ARR[0]}.$((${VERSION_ARR[1]} + 1)).0"
+    else
+        v="${VERSION_ARR[0]}.${VERSION_ARR[1]}.$((${VERSION_ARR[2]} + 1))"
+    fi
+    echo "  \`$(echo_color 36 -n "./scripts/import-docs.sh $v$latest")\`"
+    echo
+    if [ $WARN_PUBLISH_DOCS = 1 ]; then
+        echo "Avoid this prompt via \"--no-warn-publish-docs\""
+        read -p "Please confirm that you know [ENTER] "
+    fi
+fi
+
+if [ $FIND_BACKPORTS = 1 ]; then
+    git show "$ORIGIN/main:contrib/scripts/find-backports" > ./.git/nm-find-backports \
+    && chmod +x ./.git/nm-find-backports \
+    || die "cannot get contrib/scripts/find-backports"
+
+    TMP="$(./.git/nm-find-backports "$CUR_BRANCH" main "${NEWER_BRANCHES[@]}" 2>/dev/null)" || die "nm-find-backports failed"
+    test -z "$TMP" || die "nm-find-backports returned patches that need to be backported (ignore with --no-find-backports): ./.git/nm-find-backports \"$CUR_BRANCH\" main ${NEWER_BRANCHES[@]}"
+fi
+
+if [ $CHECK_GITLAB = 1 ]; then
+    if ! check_gitlab_pipeline "$CUR_BRANCH" "$CUR_HEAD" ; then
+        echo "Check the pipelines for branch \"$CUR_BRANCH\" at https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/pipelines?ref=$CUR_BRANCH"
+        echo "Wait for pipeline with \`ci-fairy wait-for-pipeline --project NetworkManager/NetworkManager --sha \"$CUR_HEAD\"\`"
+        die "It seems not all gitlab-ci jobs were running/succeeding. Skip this check with --no-check-gitlab"
+    fi
+fi
+
+BRANCHES=()
+BUILD_TAG=
+
+CLEANUP_CHECKOUT_BRANCH="$CUR_BRANCH"
+
+git checkout -B "$TMP_BRANCH"
+CLEANUP_REFS+=("refs/heads/$TMP_BRANCH")
+
+case "$RELEASE_MODE" in
+    minor)
+        set_version_number "${VERSION_ARR[0]}" "${VERSION_ARR[1]}" $(("${VERSION_ARR[2]}" + 1))
+        git commit -m "release: bump version to ${VERSION_ARR[0]}.${VERSION_ARR[1]}.$(("${VERSION_ARR[2]}" + 1))" -a || die "failed to commit release"
+        set_version_number "${VERSION_ARR[0]}" "${VERSION_ARR[1]}" $(("${VERSION_ARR[2]}" + 2))
+        git commit -m "release: bump version to ${VERSION_ARR[0]}.${VERSION_ARR[1]}.$(("${VERSION_ARR[2]}" + 2)) (development)" -a || die "failed to commit devel version bump"
+
+        b="${VERSION_ARR[0]}.${VERSION_ARR[1]}.$(("${VERSION_ARR[2]}" + 1))"
+        git tag -s -a -m "Tag $b" "$b" HEAD~ || die "failed to tag release"
+        BRANCHES+=("$b")
+        CLEANUP_REFS+=("refs/tags/$b")
+        BUILD_TAG="$b"
+        b="${VERSION_ARR[0]}.${VERSION_ARR[1]}.$(("${VERSION_ARR[2]}" + 2))"
+        git tag -s -a -m "Tag $b (development)" "$b-dev" HEAD || die "failed to tag devel version"
+        BRANCHES+=("$b-dev")
+        CLEANUP_REFS+=("refs/tags/$b-dev")
+        TAR_VERSION="$BUILD_TAG"
+        ;;
+    devel)
+        set_version_number "${VERSION_ARR[0]}" "${VERSION_ARR[1]}" $(("${VERSION_ARR[2]}" + 1))
+        git commit -m "release: bump version to ${VERSION_ARR[0]}.${VERSION_ARR[1]}.$(("${VERSION_ARR[2]}" + 1)) (development)" -a || die "failed to commit devel version bump"
+
+        b="${VERSION_ARR[0]}.${VERSION_ARR[1]}.$(("${VERSION_ARR[2]}" + 1))"
+        git tag -s -a -m "Tag $b (development)" "$b-dev" HEAD || die "failed to tag release"
+        BRANCHES+=("$b-dev")
+        CLEANUP_REFS+=("refs/tags/$b-dev")
+        BUILD_TAG="$b-dev"
+        TAR_VERSION="$b"
+        ;;
+    rc)
+        b="${VERSION_ARR[0]}.${VERSION_ARR[1]}.$(("${VERSION_ARR[2]}" + 1))"
+        t="${VERSION_ARR[0]}.$(("${VERSION_ARR[1]}" + 1))-rc$RC_VERSION"
+        set_version_number "${VERSION_ARR[0]}" "${VERSION_ARR[1]}" $(("${VERSION_ARR[2]}" + 1))
+        git commit -m "release: bump version to $b ($t) (development)" -a || die "failed to commit rc version bump"
+
+        git tag -s -a -m "Tag $b ($t) (development)" "$t" HEAD || die "failed to tag release"
+        BRANCHES+=("$t")
+        CLEANUP_REFS+=("refs/tags/$t")
+        BUILD_TAG="$t"
+        TAR_VERSION="$b"
+        ;;
+    rc1)
+        set_version_number "${VERSION_ARR[0]}" "${VERSION_ARR[1]}" 90
+        b="${VERSION_ARR[0]}.${VERSION_ARR[1]}.90"
+        t="${VERSION_ARR[0]}.$(("${VERSION_ARR[1]}" + 1))-rc1"
+        git commit -m "release: bump version to $b ($t)" -a || die "failed to commit rc1 version bump"
+
+        git tag -s -a -m "Tag $b ($t) (development)" "$t" HEAD || die "failed to tag release $t"
+        BRANCHES+=("$t")
+        CLEANUP_REFS+=("refs/tags/$t")
+        BUILD_TAG="$t"
+        TAR_VERSION="$b"
+        ;;
+    major)
+        b="${VERSION_ARR[0]}.$((${VERSION_ARR[1]} + 1)).0"
+        b2="${VERSION_ARR[0]}.$((${VERSION_ARR[1]} + 1)).1"
+
+        set_version_number "${VERSION_ARR[0]}" "$((${VERSION_ARR[1]} + 1))" 0
+        git commit -m "release: bump version to $b" -a || die "failed to commit major version bump"
+        git tag -s -a -m "Tag $b" "$b" HEAD || die "failed to tag release"
+        BRANCHES+=("$b")
+        CLEANUP_REFS+=("refs/tags/$b")
+
+        set_version_number "${VERSION_ARR[0]}" "$((${VERSION_ARR[1]} + 1))" 1
+        git commit -m "release: bump version to $b2 (development)" -a || die "failed to commit another bump after major version bump"
+        git tag -s -a -m "Tag $b (development)" "$b2-dev" HEAD || die "failed to tag release"
+        BRANCHES+=("$b2-dev")
+        CLEANUP_REFS+=("refs/tags/$b2-dev")
+
+        BUILD_TAG="$b"
+        TAR_VERSION="$b"
+        ;;
+    major-post)
+        # We create a merge commit with the content of current "main", with two
+        # parent commits $THE_RELEASE and "main". But we want that the first parent
+        # is the release, so that `git log --first-parent` follows the path with the
+        # release candidates, and not the devel part during that time. Hence this
+        # switcheroo here.
+        git checkout -B "$TMP_BRANCH" "${VERSION_ARR[0]}.$((${VERSION_ARR[1]} - 1)).0" || die "merge0"
+        git merge -Xours --commit -m tmp main || die "merge1"
+        git rm --cached -r . || die "merge2"
+        git checkout main -- . || die "merge3"
+        b="${VERSION_ARR[0]}.${VERSION_ARR[1]}.$((${VERSION_ARR[2]} + 1))"
+        git commit --amend -m tmp -a || die "failed to commit major version bump"
+        test x = "x$(git diff main HEAD)" || die "there is a diff after merge!"
+
+        set_version_number "${VERSION_ARR[0]}" "${VERSION_ARR[1]}" "$((${VERSION_ARR[2]} + 1))"
+        git commit --amend -m "release: bump version to $b (development)" -a || die "failed to commit major version bump"
+        git tag -s -a -m "Tag $b (development)" "$b-dev" HEAD || die "failed to tag release"
+        BRANCHES+=("$b-dev")
+        CLEANUP_REFS+=("refs/tags/$b-dev")
+        BUILD_TAG="$b-dev"
+        TAR_VERSION="$b"
+        ;;
+    *)
+        die "Release mode $RELEASE_MODE not yet implemented"
+        ;;
+esac
+
+build_tag() {
+    git checkout "$BUILD_TAG" || die "failed to checkout $BUILD_TAG"
+
+    ./contrib/fedora/rpm/build_clean.sh -r || die "build release failed"
+
+    test -f "./build/meson-dist/$RELEASE_FILE" \
+    || die "release file \"./build/meson-dist/$RELEASE_FILE\" not found"
+
+    cp "./build/meson-dist/$RELEASE_FILE" /tmp/ || die "failed to copy release tarball to /tmp"
+
+    if test -f "./build/meson-dist/$RELEASE_FILE.sig" ; then
+        cp "./build/meson-dist/$RELEASE_FILE.sig" /tmp/ || die "failed to copy signature for tarball to /tmp"
+    fi
+
+    git clean -fdx
+}
+
+RELEASE_FILES=()
+if [ -n "$BUILD_TAG" ]; then
+    RELEASE_FILE="NetworkManager-$TAR_VERSION.tar.xz"
+    RELEASE_FILES+=("$RELEASE_FILE")
+    build_tag
+fi
+git checkout -B "$CUR_BRANCH" "$TMP_BRANCH" || die "cannot checkout $CUR_BRANCH"
+
+BRANCHES+=( "$CUR_BRANCH" )
+
+if [ "$RELEASE_MODE" = rc1 ]; then
+    git branch "$RELEASE_BRANCH" "$TMP_BRANCH" || die "cannot checkout $CUR_BRANCH"
+    BRANCHES+=( "$RELEASE_BRANCH" )
+    CLEANUP_REFS+=( "refs/heads/$RELEASE_BRANCH" )
+fi
+
+if [ "$RELEASE_MODE" = rc1 ]; then
+    git checkout "$TMP_BRANCH"
+    b="${VERSION_ARR[0]}.$((${VERSION_ARR[1]} + 2)).0"
+    set_version_number "${VERSION_ARR[0]}" "$((${VERSION_ARR[1]} + 2))" 0
+    git commit -m "release: bump version to $b (development)" -a || die "failed to commit devel version bump"
+    git tag -s -a -m "Tag $b (development)" "$b-dev" HEAD || die "failed to tag release"
+    BRANCHES+=("$b-dev")
+    CLEANUP_REFS+=("refs/tags/$b-dev")
+    BUILD_TAG="$b-dev"
+    TAR_VERSION="$b"
+    RELEASE_FILE="NetworkManager-$TAR_VERSION.tar.xz"
+    RELEASE_FILES+=("$RELEASE_FILE")
+    build_tag
+    git checkout -B "$CUR_BRANCH" "$TMP_BRANCH" || die "cannot checkout $CUR_BRANCH"
+fi
+
+if ! [ "$DRY_RUN" = 0 ]; then
+    ssh master.gnome.org true || die "failed to \`ssh master.gnome.org\`"
+fi
+
+for r in "${RELEASE_FILES[@]}"; do
+    do_command rsync -va --append-verify -P "/tmp/$r" master.gnome.org: || die "failed to rsync \"/tmp/$r\""
+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" || 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
+    CLEANUP_REFS=()
+    git branch -D "$TMP_BRANCH"
+else
+    H="$(git rev-parse "$CUR_BRANCH")"
+    git checkout -B "$CUR_BRANCH" "$CUR_HEAD" || die "cannot reset $CUR_BRANCH to $CUR_HEAD"
+    echo "delete reference. Restore with $(echo_color 36 -n git checkout -B "\"$CUR_BRANCH\"" "$H")"
+fi
diff --git a/contrib/fedora/utils/makerepo.sh b/contrib/fedora/utils/makerepo.sh
new file mode 100755
index 00000000..266aac8f
--- /dev/null
+++ b/contrib/fedora/utils/makerepo.sh
@@ -0,0 +1,698 @@
+#!/bin/bash
+
+#
+# The script is ugly but is here to help to create a git-repository
+# based on dist-git.
+#
+#  * Works with fedpkg and rhpkg
+#  * Different packages are supported. See detect_build_type below.
+#  * Creates first an initial commit of the source directory (after "fedpkg prep")
+#  * Excludes files and creates a gitignore file. It does so by .git/makerepo.gitignore
+#    which can be edited manually. Also, after a `$0 local`, it will record all files
+#    with modifications to be ignored in the future.
+#  * Revert each patch from the spec file
+#  * Reapply each patch until you are where were originally (sans ignored files)
+#  * Restore again the original state, i.e. replying the patches (including ignored
+#    files -- that are no longer part of master-tip).
+#  * Fetch from upstream origin (and add as remote)
+#  * Fetch from a local git repository (and add as remote)
+#  * It can detect the parent commit where the package branched of
+#    and rebase the created history on top of that.
+#  * optionally, do `fedpkg local`.
+#
+# ONE-TIME SETUP:
+#   - clone the dist-git package
+#       $ PACKAGE=libnl3
+#       $ fedpkg clone $PACKAGE
+#       $ cd $PACKAGE
+#
+#   - configure local git-repository (optional)
+#       $ ln -s /path/to/local/clone .git/local
+#
+#   - create initial gitignore file (optional)
+#       $ edit .git/makerepo.gitignore
+#     or
+#       $ edit .git/makerepo.gitignore.$BRANCHNAME
+#
+# USAGE:
+#       $ cd $PACKAGE
+#       $ makerepo.sh
+#       $ makerepo.sh local
+#
+
+
+#set -vx
+
+die() {
+	echo "$@" >&2
+	exit 1
+}
+
+containsElement () {
+    local e
+    local name="$1"
+    shift
+    local i=0
+
+    for e in "${@:2}"; do
+        if [[ "$e" == "$1" ]]; then
+            eval "$name=$i"
+            return 0;
+        fi
+        i=$((i+1))
+    done
+    return 1
+}
+
+git_remote_add_gnome() {
+    git remote add "${2-origin}" "https://gitlab.gnome.org/GNOME/$1.git" && \
+    git remote 'set-url' --push "${2-origin}" "git@gitlab.gnome.org:GNOME/$1.git"
+}
+
+git_remote_add_github() {
+    git remote add "${2-origin}" "https://github.com/$1.git"
+    git remote 'set-url' --push "${2-origin}" "git@github.com:$1.git"
+}
+
+srcdir="$(readlink -f "$(git rev-parse --show-toplevel 2>/dev/null)")"
+[[ "x$srcdir" != x ]] || die "Could not detect dist-git directory (are you inside the git working directory?)"
+cd "$srcdir" || die "Could not switch to dist-git directory"
+
+
+if [[ "x$(ls -1d ./*.spec 2>/dev/null)" == x || ! -f "./sources" ]]; then
+    die "**Error**: Directory "\`$srcdir\'" does not look like the dist-git pkg dir."
+fi
+
+if [[ "$FEDPKG" == "" ]]; then
+    REMOTE="$(git config --get "branch.$(git branch --show-current).remote" 2>/dev/null)"
+    URL="$(git config --get "remote.$REMOTE.url")"
+    if [[ "$URL" = *'pkgs.devel.redhat.com'* ]]; then
+        FEDPKG=rhpkg
+    elif [[ "$URL" = *'gitlab.com'*'redhat/centos-stream'* ]]; then
+        FEDPKG=centpkg
+    elif [[ "$URL" = *'pkgs.fedoraproject.org/'* || "$URL" = *'src.fedoraproject.org/'* ]]; then
+        FEDPKG=fedpkg
+    else
+        die "not inside dist-git repository? Check out a branch that has the dist-git remote tracking branch >>$PWD<<"
+    fi
+fi
+
+split_patch() {
+    # patches created with git-format-patch that contain more then one
+    # commit, cannot be easily reverted with patch, because patch works
+    # the patches from top down. In case of -R however, we have to apply
+    # the latest patches first.
+
+    read -r -d '' PERL_PROG <<-'EOF'
+		use strict;
+		use warnings;
+
+		open FILE, $ARGV[0]  or die "Can't open $ARGV[0] for reading: $!\n";
+
+		local $/ = undef;
+		my $file = <FILE>;
+		close FILE;
+
+		my @patches = split(/\n\nFrom /,$file);
+
+		my $i = $#patches + 1;
+		my $patch;
+		my $first = 1;
+		foreach $patch (@patches){
+			if ($first) {
+				$first = 0;
+			} else {
+				$patch = "From $patch"
+			}
+			my $o = sprintf("%s%s%03d", $ARGV[0], $ARGV[1], $i);
+			open(my $OUT, ">", $o) or die "Can't open $o for writing: $!";
+			$i--;
+
+			print $OUT "$patch";
+
+			close $OUT;
+		}
+	EOF
+
+    perl -e "$PERL_PROG" "$1" "$2"
+}
+
+spec_parse_patch_p() {
+    local SPEC="$1"
+    local NUM="$2"
+
+    local P="$(sed -n "s/^%\<patch$NUM\>.* -p\([0-9]\+\) .*$/\1/p" "$SPEC")"
+
+    echo "${P:-1}"
+}
+
+get_patch_origin() {
+    local PATCH="$1"
+
+    (
+        cd "$srcdir"
+
+        local HASH="$(git log -n1 --format="%H" HEAD -- "$PATCH")"
+
+        if [[ "$HASH" == "" ]]; then
+            return
+        fi
+
+        printf "\n\nPatch \"%s\" was last modified in commit:\n\n" "$PATCH"
+        git log -n1 "$HASH" | sed 's/^[^ ]/    \0/'
+    )
+}
+
+print_synopsis() {
+    echo "SYNOPSIS: $(basename "$0") [--dist|-d DIST] [local|--local|-l] [-?|-h|--help|help] [NUM]"
+    echo "  - If [NUM] is omitted, it will revert all patches from the spec file,"
+    echo "    otherwise only the last NUM patches."
+    echo "  - When specifying 'local', it will also call \`$FEDPKG local\` to configure"
+    echo "    and build the output directory."
+    echo "  - '--dist' implies '--local'. This argument is passed to ${FEDPKG}."
+    echo "  TIP: symlink your local git clone of upstream to './.git/local'."
+}
+
+unset REVERT_COUNT
+LOCAL=0
+DIST=""
+while [ $# -ne 0 ]; do
+    ARG="$1"
+    shift
+    case "$ARG" in
+        -h|'-?'|help|--help)
+            print_synopsis
+            exit 0
+            ;;
+        local|--local|-l)
+            LOCAL=1
+            ;;
+        --dist|-d)
+            DIST="$1"
+            shift
+            if [ "x$DIST" = x ]; then
+                print_synopsis
+                die "--dist needs an argument"
+            fi
+            ;;
+        *)
+            if [ -n "${REVERT_COUNT+x}" ]; then
+                print_synopsis
+                die "invalid argument \"$ARG\""
+            fi
+            case "$ARG" in
+                ''|*[!0-9]*)
+                    print_synopsis
+                    die "invalid argument \"$ARG\": should be an integer (number of patches to revert)"
+                    ;;
+            esac
+            REVERT_COUNT="$ARG"
+            ;;
+    esac
+done
+
+if [ "x$DIST" != x ]; then
+    DIST=" --dist $DIST"
+fi
+
+# generate the clean dir
+$FEDPKG $DIST prep || die "error while \`$FEDPKG$DIST prep\`"
+
+detect_build_type() {
+    local TEST_DIR="./$1/"
+    local TEST_SPEC="$2"
+    local TEST_BUILD_TYPE="$3"
+    local DIRNAME
+
+    if [[ -n "$BUILD_TYPE" || -z "$1" || "x$(ls -1d $TEST_DIR 2>/dev/null)" == x || ! -f "$TEST_SPEC" ]]; then
+        return 1
+    fi
+
+    DIRNAME="$(ls -1d $TEST_DIR)" || die "could not find directory"
+    DIRNAME="$(basename "$DIRNAME")"
+    SPEC="$TEST_SPEC"
+
+    if [[ -n "$TEST_BUILD_TYPE" ]]; then
+        BUILD_TYPE="$TEST_BUILD_TYPE"
+    else
+        BUILD_TYPE="${TEST_SPEC%.spec}"
+    fi
+}
+
+detect_dirname() {
+    local BUILD_TYPE="$1"
+    local DIRS=()
+    local SOURCES
+    local D suffix T
+
+    SOURCES="$(sed 's/^\(SHA512 (\(.*\)) = [0-9a-f]\{128\}\|\([0-9a-f]\{32\} \+\(.*\)\)\)$/\2\4/' ./sources 2>/dev/null)"
+
+    for suffix in .tar.gz .tar.bz .tar.xz .tgz .tar.bz2 ; do
+        for T in ${SOURCES[@]}; do
+            if [[ "$T" == *$suffix ]]; then
+                D="${T%$suffix}"
+                [[ -d "$D" ]] && DIRS=("${DIRS[@]}" "$D")
+                D="$(tar -tf "$T" | sed 's#/.*##' | sort | uniq)"
+                [[ -d "$D" ]] && DIRS=("${DIRS[@]}" "$D")
+            fi
+        done
+
+        # iterate over all tarballs that start with "$BUILD_TYPE" and
+        # see if there exists a directory with the same name as
+        # the unpacked tarball (that is, stripping the suffix).
+        for T in $(ls -1 "$BUILD_TYPE"*"$suffix" 2>/dev/null); do
+            D="${T%$suffix}"
+            [[ -d "$D" ]] && DIRS=("${DIRS[@]}" "$D")
+        done
+    done
+
+    D=
+    if [[ ${#DIRS[@]} -ge 1 ]]; then
+        # return the newest directory.
+        D="$(ls -1d --sort=time --time=ctime "${DIRS[@]}" 2>/dev/null | head -n1)"
+    fi
+    if [[ "$D" != "" ]]; then
+        printf "%s" "$D"
+        return 0
+    fi
+    return 1
+}
+
+BUILD_TYPE=
+detect_build_type 'NetworkManager-[0-9]*' NetworkManager.spec
+detect_build_type 'network-manager-applet-[0-9]*' network-manager-applet.spec
+detect_build_type 'libnl-[0-9]*' libnl3.spec
+detect_build_type 'NetworkManager-openvpn-[0-9]*' NetworkManager-openvpn.spec
+detect_build_type 'NetworkManager-openswan-[0-9]*' NetworkManager-openswan.spec
+detect_build_type 'NetworkManager-libreswan-[0-9]*' NetworkManager-libreswan.spec
+detect_build_type 'NetworkManager-vpnc-[0-9]*' NetworkManager-vpnc.spec
+detect_build_type 'ModemManager-[0-9]*' ModemManager.spec
+detect_build_type 'wireless_tools.[0-9]*' wireless-tools.spec
+detect_build_type 'umip-[0-9]*' mipv6-daemon.spec
+detect_build_type 'initscripts-[0-9]*' initscripts.spec
+detect_build_type 'libqmi-[0-9]*' libqmi.spec
+detect_build_type 'libibverbs-[0-9]*' libibverbs.spec
+detect_build_type 'iproute2-*' iproute.spec
+detect_build_type 'glib-2*' glib2.spec
+detect_build_type 'vpnc-*' vpnc.spec
+detect_build_type 'gnome-control-center-*' control-center.spec gnome-control-center
+
+if [[ -z "$BUILD_TYPE" ]]; then
+    SPEC="$(ls -1 *.spec 2>/dev/null | head -n1)"
+    BUILD_TYPE="${SPEC%.spec}"
+    [[ -n "$BUILD_TYPE" ]] || die "Failed to detect repository type (no spec file)"
+
+    [[ -f sources ]] || die "Failed to detect repository type (no sources file)"
+fi
+
+DIRNAME="$(detect_dirname "$BUILD_TYPE")" || die "Failed to detect repository type (no directory)."
+
+CURRENT_BRANCH="$(git rev-parse --abbrev-ref HEAD 2>/dev/null)"
+if [[ "x$CURRENT_BRANCH" != x && -f "./.git/makerepo.gitignore-$CURRENT_BRANCH" ]]; then
+    MAKEREPO_GIT_IGNORE_MY="makerepo.gitignore-$CURRENT_BRANCH"
+elif [[ -f ./.git/makerepo.gitignore ]]; then
+    MAKEREPO_GIT_IGNORE_MY=makerepo.gitignore
+else
+    MAKEREPO_GIT_IGNORE_MY=""
+fi
+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
+
+    [[ -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
+            return
+        fi
+        git clone --mirror --bare "$URL" "$FULLNAME/"
+    fi
+    (
+        cd "$FULLNAME"
+        git fetch origin --prune
+        git gc
+    )
+    echo "$FULLNAME"
+}
+
+pushd "$DIRNAME"
+    git init .
+    # if you have a local clone of upstream, symlink it as ../.git/local.
+    if [[ "$BUILD_TYPE" == "NetworkManager" ]]; then
+        git remote add origin "https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git"
+        git remote 'set-url' --push origin "git@gitlab.freedesktop.org:NetworkManager/NetworkManager.git"
+        git config notes.displayRef refs/notes/bugs
+        git config --add remote.origin.fetch refs/tags/*:refs/tags/*
+        git config --add remote.origin.fetch refs/notes/bugs:refs/notes/bugs
+    elif [[ "$BUILD_TYPE" == "ModemManager" ]]; then
+        git remote add origin "git://anongit.freedesktop.org/ModemManager/ModemManager"
+        git remote 'set-url' --push origin "ssh://$USER@git.freedesktop.org/git/ModemManager/ModemManager"
+        git config --add remote.origin.fetch refs/tags/*:refs/tags/*
+    elif [[ "$BUILD_TYPE" == "libnl3" ]]; then
+        git_remote_add_github thom311/libnl
+    elif [[ "$BUILD_TYPE" == "network-manager-applet" ||
+            "$BUILD_TYPE" == "gnome-control-center" ||
+            "$BUILD_TYPE" == "libnma" ||
+            "$BUILD_TYPE" == "NetworkManager-fortisslvpn" ||
+            "$BUILD_TYPE" == "NetworkManager-libreswan" ||
+            "$BUILD_TYPE" == "NetworkManager-openconnect" ||
+            "$BUILD_TYPE" == "NetworkManager-openvpn" ||
+            "$BUILD_TYPE" == "NetworkManager-pptp" ||
+            "$BUILD_TYPE" == "NetworkManager-vpnc" ]]; then
+        git_remote_add_gnome "$BUILD_TYPE"
+    elif [[ "$BUILD_TYPE" == "glib2" ]]; then
+        git_remote_add_gnome glib
+    elif [[ "$BUILD_TYPE" == "NetworkManager-openswan" ]]; then
+        git remote add origin "git://git.gnome.org/network-manager-openswan";
+        git remote 'set-url' --push origin "ssh://$USER@git.gnome.org/git/network-manager-openswan"
+    elif [[ "$BUILD_TYPE" == "wpa_supplicant" ]]; then
+        git remote add origin "git://w1.fi/hostap.git"
+        git_remote_add_github NetworkManager/hostap nm
+    elif [[ "$BUILD_TYPE" == "mipv6-daemon" ]]; then
+        git remote add origin "git://git.umip.org/umip.git";
+    elif [[ "$BUILD_TYPE" == "libqmi" ]]; then
+        git remote add origin 'git://anongit.freedesktop.org/libqmi';
+    elif [[ "$BUILD_TYPE" == "libibverbs" ]]; then
+        git remote add origin 'git://git.kernel.org/pub/scm/libs/infiniband/libibverbs.git';
+    elif [[ "$BUILD_TYPE" == "initscripts" ]]; then
+        git remote add origin "https://git.fedorahosted.org/git/initscripts.git";
+    elif [[ "$BUILD_TYPE" == "iproute" ]]; then
+        git remote add origin "git://git.kernel.org/pub/scm/linux/kernel/git/shemminger/iproute2.git"
+    elif [[ "$BUILD_TYPE" == "dracut" ]]; then
+        git remote add origin "https://github.com/dracutdevs/dracut.git"
+    elif [[ "$BUILD_TYPE" == "systemd" ]]; then
+        git remote add origin "https://github.com/systemd/systemd.git"
+    elif [[ "$BUILD_TYPE" == "vpnc" ]]; then
+        git_remote_add_github ndpgroup/vpnc
+    elif [[ "$BUILD_TYPE" == "cloud-init" ]]; then
+        git remote add origin "https://git.launchpad.net/cloud-init"
+    elif [[ "$BUILD_TYPE" == "firewalld" ]]; then
+        git remote add origin "https://github.com/firewalld/firewalld.git"
+    elif [[ "$BUILD_TYPE" == "nftables" ]]; then
+        git remote add origin "git://git.netfilter.org/nftables"
+    elif [[ "$BUILD_TYPE" == "ulogd" ]]; then
+        git remote add origin "https://git.netfilter.org/ulogd2"
+    elif [[ "$BUILD_TYPE" == "libnetfilter_log" ]]; then
+        git remote add origin "https://git.netfilter.org/$BUILD_TYPE"
+    fi
+    LOCAL_MIRROR_URL="$(LANG=C git remote -v | sed -n 's/^origin\t*\([^\t].*\) (fetch)/\1/p')"
+    LOCAL_MIRROR="$(get_local_mirror "$LOCAL_MIRROR_URL")"
+    if [[ -n "$LOCAL_MIRROR" ]]; then
+        git remote add local-mirror "$LOCAL_MIRROR"
+        git fetch local-mirror
+    fi
+    LOCAL_GIT="$(readlink -f ../.git/local/)"
+    if [[ -d "$LOCAL_GIT" ]]; then
+        git remote add local "$LOCAL_GIT/"
+        git fetch local
+    fi
+    if [[ "$(git remote | grep '^origin$')x" != x && -z "$NO_REMOTE" ]]; then
+        git fetch origin
+        if [[ -n "$LOCAL_MIRROR" ]]; then
+            git remote rm local-mirror
+        fi
+    fi
+    git commit --allow-empty -m '*** empty initial commit'  # useful, to rebase the following commit
+    git add -f -A .
+    git commit -m '*** add all'
+    git tag -f ALL
+    ORIG_HEAD="`git rev-parse HEAD`"
+    if [[ "x$RELEASE_BASE_COMMIT" == x ]]; then
+        # if RELEASE_BASE_COMMIT is not set, try detecting the BASE_COMMIT...
+
+        if [[ "$BUILD_TYPE" == "NetworkManager" ||
+              "$BUILD_TYPE" == "NetworkManager-fortisslvpn" ||
+              "$BUILD_TYPE" == "NetworkManager-libreswan" ||
+              "$BUILD_TYPE" == "NetworkManager-pptp" ||
+              "$BUILD_TYPE" == "NetworkManager-openconnect" ||
+              "$BUILD_TYPE" == "NetworkManager-vpnc" ]]; then
+            RELEASE_BASE_COMMIT="$(sed -n 's/^NM_GIT_SHA=\(.*\)/\1/p' configure 2>/dev/null)"
+        elif [[ "$BUILD_TYPE" == "libnl3" ]]; then
+            RELEASE_BASE_COMMIT="$(sed -n 's/^LIBNL_GIT_SHA=\(.*\)/\1/p' configure 2>/dev/null)"
+            if [[ "$RELEASE_BASE_COMMIT" == "23c44dad998f72f39fd1fc24aa9579fd0a7f05c0" ]]; then
+                RELEASE_BASE_COMMIT="e01b9df629e2f4f833fdc4fe0bda460bb738d136"
+            fi
+        elif [[ "$BUILD_TYPE" == "network-manager-applet" ||
+                "$BUILD_TYPE" == "libnma" ]]; then
+            RELEASE_BASE_COMMIT="$(sed -n 's/^NMA_GIT_SHA=\(.*\)/\1/p' configure 2>/dev/null)"
+            if [[ "$RELEASE_BASE_COMMIT" == "8d8e34f22d5fae476eda96cf36d828c3ae8b63d3" ]]; then
+                RELEASE_BASE_COMMIT="a2377d7534780b96a32405cce2e5548e81bbd081"
+            fi
+        elif [[ "$BUILD_TYPE" == "glib2" ]]; then
+            RELEASE_BASE_COMMIT="$(git rev-parse --verify -q "$(sed 's/.*\<glib-\([0-9]\+\.[0-9]\+\.[0-9]\+\)\.[a-z0-9_.]\+\>.*$/\1/' ../sources)^{commit}" 2>/dev/null)"
+        elif [[ "$BUILD_TYPE" == "iproute" ]]; then
+            RELEASE_BASE_COMMIT="$(git rev-parse --verify -q "$(sed 's/.*\<iproute2-\([0-9]\+\.[0-9]\+\.[0-9]\+\)\..*/v\1/' ../sources)^{commit}" 2>/dev/null)"
+        elif [[ "$BUILD_TYPE" == "NetworkManager-openvpn" ]]; then
+            RELEASE_BASE_COMMIT="$(sed -n 's/^NM_GIT_SHA=\(.*\)/\1/p' configure 2>/dev/null)"
+            if [[ "x$RELEASE_BASE_COMMIT" == x ]]; then
+                DATE="$(sed -n 's/%global snapshot .git\(20[0-3][0-9]\)\([0-1][0-9]\)\([0-3][0-9]\)/\1-\2-\3/p' "../$SPEC")"
+                if [[ "x$DATE" != x ]]; then
+                    RELEASE_BASE_COMMIT="$(git rev-list -n1 --date-order --before="$DATE" origin/master 2>/dev/null)"
+                fi
+            fi
+        fi
+        if [[ "x$RELEASE_BASE_COMMIT" == x ]]; then
+            KNOWN_BASE_COMMITS="$(cat <<EOF
+# NetworkManager
+08670c9163a5d0f15c57c7891ef899eb125d9423  7251704430cb206f2c29bfebc45bd0fb *NetworkManager-0.9.9.0.git20131003.tar.bz2
+
+# ModemManager
+397761c9758c3a8c2d130afaf36dab645d6e0ecf  d9d93d2961ee35b4cd8a75a6a8631cb4  ModemManager-1.6.0.tar.xz
+b23413a064f03fb2f2214fb32164bcb4b7037c45  67160b94c0eda90ebf95d1b620229ca1  ModemManager-1.6.10.tar.xz
+526ec556bdf440fce3c48d3127836cf9d0b4501b  SHA512 (ModemManager-1.10.8.tar.xz) = c021939322be39e102371219e648d6acb3bc5b48cf570e02113ce559321155bfe5476b4012fd95f878c0a5c5d3b9d88fb19e95adec16a5b62a01581915a39f71
+
+# libnl3
+1a510c57e905c4beb06122b9688162c82d9b044f  d1111959652bd6ad87b2071f61c8c20c *libnl-doc-3.2.24.tar.gz
+83c762d7cf6a6c54831e8d684b22804f497704c4  6fe7136558a9071e70673dcda38545b3 *libnl-3.2.21.tar.gz
+c4d846f239036c05f516c1c71789e980b64b1e70  2e1c889494d274aca24ce5f6a748e66e *libnl-3.2.22.tar.gz
+0446731124bea8c1b447cc52a5ad5ae5750810ff  636769646f5b81b0caead81eab151b45 *libnl-3.2.25-rc1.tar.gz
+bd0e87b3d81d2498c3f35d5497771828bf04e017  e34999eaa184c84b315a8dff8afa4219  libnl-3.2.28-rc1.tar.gz
+656f381ccf58785319bb0236595c896125d33ed0  bab12db1eb94a42129f712a44be91a67  libnl-3.2.28.tar.gz
+
+# NetworkManager-applet
+5d4f17e205f71972d4143f9760426a366b4129d7  9cc0e383c216d4bc31622a0cfb53aaa7 *network-manager-applet-0.9.9.0.git20140123.5d4f17e.tar.bz2
+36c868498f09eacafcdce9d6b68ca5aeffaae899  3146f3ac3c30996a96cd2c602fbc81e1 *network-manager-applet-0.9.10.3.git20150511.36c8684.tar.bz2
+2d5b36cf69ea6d5e11726d479012c8ad7d6fd9fc  7fc2ed3f0c46ed41ddabe99d51513b1c *network-manager-applet-1.0.4.tar.xz
+
+# NetworkManager-libreswan, NetworkManager-openswan
+64c90fd50e57854a3fff3784b92814ffa8159b05  6a373868f85ac3b7c953f7fd6c76e637 *NetworkManager-openswan-0.9.8.0.tar.xz
+78555150e4df29eb39fa4a105f884f53b0f4523f  df9144805f37dc30dfaeab8da762f615 *NetworkManager-openswan-1.0.6.tar.xz
+3ef831cf25e86675f9838bf58b1cd6e592c6e14f  01248eb95a1e1d647057a45aed85a3af *NetworkManager-libreswan-1.2.4.tar.xz
+
+# NetworkManager-vpnc
+89bdcd324f2e257eca59168a7d0be5608438aab0  abb26a6c3c8d6c1d91c78471aff86b3a *NetworkManager-vpnc-0.9.8.2.tar.xz
+c37a79d43ebe1192ba8dcc5036cd668631b6473e  d87db7021629cef7c110a371dd42b7a8 *NetworkManager-vpnc-0.9.9.0.git20140131.tar.bz2
+68ca41550f9289835ea9d80e1ee059322ebe749a  4c16379738264a117d09c171c645ff23 *NetworkManager-vpnc-1.2.2.tar.xz
+
+# NetworkManager-openvpn
+1f159f30617e4a3b8121074b8bf238312941370d  511eae0d4ac17c6d2659a3da2646296f *NetworkManager-openvpn-1.0.2.tar.xz
+75585a94b394c04e45a28d2b032fe83dcdaeebee  ee4c09a8896eab3e1740f7c7bc1434f9  NetworkManager-openvpn-1.2.4.tar.xz
+
+# mipv6-daemon
+428974c2d0d8e75a2750a3ab0488708c5dfdd8e3  8e3ebd242e7926822bbdf5ce77c1d076 *mipv6-daemon-1.0.tar.gz
+
+# libqmi
+7d688f382f9756027bf92338e413e425365d2835  17d6c2b404ee1eb4d1e60050fef64491 *libqmi-1.6.0.tar.xz
+49abf405f5e9f16542476dceeb20de6029edcf1c  SHA512 (libqmi-1.24.0.tar.xz) = e899765e67c1db0f758030e78b296015c476f938bb2afa01594b3e71a0b8d5fc2237c8272497aec891d5555523ecf0fecd69c4d0e14165c07072780621b3b502
+
+# gnome-control-center
+e87e0361b117f055ace2aa47cdddd0dc62a852f9  da949e268254af6aafdda0e8c1702384 *gnome-control-center-3.22.1.tar.xz
+
+# wpa_supplicant
+22760dd94722a61175ff90c59d88c4cda1ed5e23  3be2ebfdcced52e00eda0afe2889839d *wpa_supplicant-2.0.tar.gz
+
+# libibverbs
+990ca025d0ad967b6f266bae700bf82a4ceaff1a  1fe85889c8bbc4968b1feba6524ca408 *libibverbs-1.1.8.tar.gz
+
+# initscripts
+cc304f05edab6c408a0f061eb1a104f9f06b8587  86ef789876b65c61751ce854835b91d4  initscripts-9.49.35.tar.bz2
+
+# dracut
+00efe708cab023bfe6eaf530d8ac8ea97b440de2  SHA512 (dracut-050.tar.xz) = 9d9a66acfd6b9d2fd50855a59a2393e0602c2ef97119db046f68d6167ea84d1423fa465b8b4d96339febb38d5a96df26dec7862c4b3397c3d726db18d280eee4
+
+# systemd
+903dd65b5eb63257393955cb79777beb8c71afc1  SHA512 (systemd-253-rc1.tar.gz) = aaf0a6bf21bbc50a42015c9cb17f69d1aaf6cab6cabfba5140a94212fb864e38d638dace9a70447f62b4d2a817a0d3bd6f4ae8d9b3c2e741cdeb1cb332f70b65
+
+# libnetfilter_log
+97866a0a7482ca518bad39536c7c667bfb9604b2  2a4bb0654ae675a52d2e8d1c06090b94  libnetfilter_log-1.0.1.tar.bz2
+b0e4be94c0b8f68d4e912402b93a130063c34e17  SHA512 (libnetfilter_log-1.0.2.tar.bz2) = 6b33718b1dd7f4504bceae14001da3a652cec46a6725a5dee83a7b55028cfa8e768cba917f968a5d5b60fd9ff04edf6040ef271a68e5fb65858bf73f4f9ccf23
+
+# ulogd
+79aa980f2df9dda0c097e8f883a62f414b9e5138  SHA512 (ulogd-2.0.8.tar.bz2) = 9f99f6f35bad5da4559d788dc3ba3dae17d4ae972737cae3313ecf68f08eaf5f55514fce6f30503437e4158fd30a06438b9249d5d20f6343964cbf690f87309d
+EOF
+)"
+            OLDIFS="$IFS"
+            IFS=$'\n'
+            for KNOWN_BASE_COMMIT in $KNOWN_BASE_COMMITS; do
+                MATCH="$(echo "$KNOWN_BASE_COMMIT" | sed -n 's/^[0-9a-f]\{40\} \+\(.*\)$/\1/p')"
+                if [[ "x$MATCH" == x ]]; then
+                    continue
+                fi
+                if grep -q "$MATCH" ../sources; then
+                    RELEASE_BASE_COMMIT="$(echo "$KNOWN_BASE_COMMIT" | awk '{print $1}')"
+                    break
+                fi
+            done
+            IFS="$OLDIFS"
+        fi
+    fi
+    if [[ x != "x$RELEASE_BASE_COMMIT" ]]; then
+        if [[ "$RELEASE_BASE_COMMIT" == "-" ]]; then
+            # you can disable detection of the RELEASE_BASE_COMMIT by setting it to '-'
+            RELEASE_BASE_COMMIT=
+        else
+            # verify the base commit...
+            RELEASE_BASE_COMMIT2="$(git rev-parse --verify -q "$RELEASE_BASE_COMMIT^{commit}" 2>/dev/null)"
+            [[ x == "x$RELEASE_BASE_COMMIT2" ]] && test -z "$NO_REMOTE" && die "error detecting RELEASE_BASE_COMMIT=$RELEASE_BASE_COMMIT"
+            RELEASE_BASE_COMMIT="$RELEASE_BASE_COMMIT2"
+        fi
+    fi
+    if [[ x != "x$RELEASE_BASE_COMMIT" ]]; then
+        git checkout -B master "$RELEASE_BASE_COMMIT" || die "could not checkout master"
+        git tag -f BASE
+        git rm --cached -r :/
+        git checkout "$ORIG_HEAD" -- :/
+        git clean -fdx :/
+        git commit -m '*** add all'
+        git tag -f ALL
+        [[ x == "x$(git diff HEAD "$ORIG_HEAD")" ]] || die "error recreating initial tarball"
+    fi
+    (
+        if [[ -n "$MAKEREPO_GIT_IGNORE_MY" ]]; then
+            cat "../.git/$MAKEREPO_GIT_IGNORE_MY"
+        fi
+        if [[ -f "../.git/$MAKEREPO_GIT_IGNORE_LAST" ]]; then
+            cat "../.git/$MAKEREPO_GIT_IGNORE_LAST"
+        fi
+        sed -n 's/^%patch\([0-9]\+\) \+.*-b \+\([^ ]\+\).*$/*\2/p' ../"$SPEC";
+        echo '*.[0-9][0-9][0-9][0-9][-.]*.orig'
+    ) | LANG=C sort | LANG=C uniq > .gitignore
+
+    git rm --cached -r .
+    git add --all .
+    git commit -m "*** clean state (ignored files removed)"
+    git tag -f CLEAN
+
+    if [[ "$REVERT_COUNT" == "" || $REVERT_COUNT -gt 0 ]]; then
+
+        # parse the list of patches
+        IFS=$'\n' read -rd '' -a PATCH_LIST <<<"$(sed -n 's/^Patch\([0-9]\+\):[ 	]\+\(.*\)$/\1 \2/p' ../"$SPEC" | sort -n)"
+
+        if [[ "$BUILD_TYPE" == "NetworkManager" ]]; then
+            if containsElement idx "123 rh1085015-applet-translations.patch" "${PATCH_LIST[@]}"; then
+                # for rhel-6, NetworkManager contains some patches that break the script. In this
+                # case, truncate the list of what we would normally revert.
+                PATCH_LIST=("${PATCH_LIST[@]:$((idx+1))}")
+            fi
+        fi
+
+        # truncate the list of patches to revert/reapply
+        if [[ "$REVERT_COUNT" == "" || "$REVERT_COUNT" -gt ${#PATCH_LIST[@]} ]]; then
+            echo "revert all ${#PATCH_LIST[@]} patches"
+        else
+            echo "revert the last $REVERT_COUNT patches of ${#PATCH_LIST[@]}"
+            PATCH_LIST=("${PATCH_LIST[@]:$((${#PATCH_LIST[@]} - $REVERT_COUNT))}")
+        fi
+
+        # split the list in index and patch file name
+        PATCH_LIST_N=()
+        for i in ${!PATCH_LIST[@]}; do
+            LAST_PATCH_N[$i]=$(echo "${PATCH_LIST[$i]}" | sed -n 's/^\([0-9]\+\) \+.*$/\1/p')
+            LAST_PATCH[$i]=$(  echo "${PATCH_LIST[$i]}" | sed -n 's/^\([0-9]\+\) \+\(.*\)$/\2/p')
+        done
+
+        # revert and patches in reverse order...
+        BASECOMMIT=("`git rev-parse HEAD`")
+        for j in "${!PATCH_LIST[@]}"; do
+            i=$((${#PATCH_LIST[@]} - $j - 1))
+            echo "revert Patch${LAST_PATCH_N[$i]} \"${LAST_PATCH[$i]}\"..."
+            PNUM="$(spec_parse_patch_p "../$SPEC" "${LAST_PATCH_N[$i]}")"
+            patch -f --no-backup-if-mismatch -R "-p$PNUM" < "../${LAST_PATCH[$i]}" || (
+                # error applying patch. Maybe we have a multi line patch...
+
+                rm -f "../${LAST_PATCH[$i]}".makerepo-split.*
+                split_patch "../${LAST_PATCH[$i]}" ".makerepo-split."
+
+                git reset --hard
+                git clean -fdx
+                for p in "../${LAST_PATCH[$i]}".makerepo-split.*; do
+                    echo ">>> try split part $p for ${LAST_PATCH[$i]}"
+                    patch --no-backup-if-mismatch -R "-p$PNUM" < "$p" || die "error reverting Patch${LAST_PATCH_N[$i]} ${LAST_PATCH[$i]}"
+                done
+            )
+            git add --all .
+            git commit --allow-empty -a -m "<< revert Patch${LAST_PATCH_N[$i]} \"${LAST_PATCH[$i]}\"$(get_patch_origin "${LAST_PATCH[$i]}")"
+            BASECOMMIT=("`git rev-parse HEAD`" "${BASECOMMIT[@]}")
+            git tag -f REVERT"${LAST_PATCH_N[$i]}"
+        done
+
+        # reapply the patches
+        for i in ${!PATCH_LIST[@]}; do
+            echo "reapply Patch${LAST_PATCH_N[$i]} \"${LAST_PATCH[$i]}\"..."
+
+            # create an empty commit, indicating the commit before starting to reapply
+            BASECOMMIT_REVERT="${BASECOMMIT[$((i))]}"
+            COMMIT_MSG="$(git log -n1 --format='%s%n%n%b' "$BASECOMMIT_REVERT" | sed '1s/<< revert \(Patch.*"\)$/-- before reapplying \1/')"
+            git commit --allow-empty -m "$COMMIT_MSG"
+            git tag -f "BEFORE_PATCH${LAST_PATCH_N[$i]}"
+            git tag -f "LAST0"
+
+            # first try git-am to preserve the commit message, otherwise just revert the last commit
+            if git am "../${LAST_PATCH[$i]}"; then
+                # The tree to the version before should be identical after reapplying the patch.
+                # Just to be sure, reset the commit.
+                git reset "${BASECOMMIT[$((i+1))]}" -- .
+                COMMIT_MSG="$(git log -n1 --format='%s%n%n%b' "$BASECOMMIT_REVERT" | sed '1s/<< revert \(Patch.*"\)$/-- after reapplying \1\n\ngit-am did not fully restore the previous state/')"
+                git commit -m "$COMMIT_MSG" || echo "NOTHING TO COMMIT"
+            else
+                git am --abort
+                git reset "${BASECOMMIT[$((i+1))]}" -- .
+                COMMIT_MSG="$(git log -n1 --format='%s%n%n%b' "$BASECOMMIT_REVERT" | sed '1s/<< revert \(Patch.*"\)$/>> reapply \1/')"
+                git commit --allow-empty -m "$COMMIT_MSG"
+            fi
+            git reset --hard HEAD
+            git clean -fdx
+            [[ x = "x$(git diff "${BASECOMMIT[$((i+1))]}" HEAD)" ]] || die "error reverting patch"
+            git tag -f PATCH"${LAST_PATCH_N[$i]}"
+        done
+        git tag -f LAST
+    fi
+    git checkout "$ORIG_HEAD" -- .
+    git checkout HEAD~ -- .gitignore
+    git reset
+
+    git gc
+popd
+
+if [[ $LOCAL != 0 ]]; then
+    rm -rf ./.makerepo.git/
+    mv "$DIRNAME/.git" ./.makerepo.git/
+    $FEDPKG $DIST local -- --noclean
+    mv ./.makerepo.git/ "$DIRNAME/.git"
+    pushd "$DIRNAME"
+        git checkout -- .gitignore
+
+        # write git-ignore file...
+        git status --porcelain | sed 's/^...//' >> "../.git/$MAKEREPO_GIT_IGNORE_LAST"
+    popd
+fi
+
+echo SUCCESS;