diff --git a/SOURCES/0496-ci-PowerTools-repo-was-renamed-to-powertools-in-RHEL.patch b/SOURCES/0496-ci-PowerTools-repo-was-renamed-to-powertools-in-RHEL.patch
new file mode 100644
index 0000000..cd054ce
--- /dev/null
+++ b/SOURCES/0496-ci-PowerTools-repo-was-renamed-to-powertools-in-RHEL.patch
@@ -0,0 +1,26 @@
+From 07b154fbc817e93f58c597644570a633c38d1c72 Mon Sep 17 00:00:00 2001
+From: Frantisek Sumsal <frantisek@sumsal.cz>
+Date: Fri, 15 Jan 2021 12:51:02 +0100
+Subject: [PATCH] ci: PowerTools repo was renamed to powertools in RHEL 8.3
+
+See: https://wiki.centos.org/Manuals/ReleaseNotes/CentOS8.2011#Yum_repo_file_and_repoid_changes
+
+rhel-only
+Related: #1871827
+---
+ ci/travis-centos-rhel8.sh | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/ci/travis-centos-rhel8.sh b/ci/travis-centos-rhel8.sh
+index cd0857fd29..43e2cb2585 100755
+--- a/ci/travis-centos-rhel8.sh
++++ b/ci/travis-centos-rhel8.sh
+@@ -95,7 +95,7 @@ for phase in "${PHASES[@]}"; do
+             # Upgrade the container to get the most recent environment
+             $DOCKER_EXEC dnf -y upgrade
+             # Install systemd's build dependencies
+-            $DOCKER_EXEC dnf -q -y --enablerepo "PowerTools" builddep systemd
++            $DOCKER_EXEC dnf -q -y --enablerepo "powertools" builddep systemd
+             ;;
+         RUN)
+             info "Run phase"
diff --git a/SOURCES/0497-ci-use-quay.io-instead-of-Docker-Hub-to-avoid-rate-l.patch b/SOURCES/0497-ci-use-quay.io-instead-of-Docker-Hub-to-avoid-rate-l.patch
new file mode 100644
index 0000000..db85595
--- /dev/null
+++ b/SOURCES/0497-ci-use-quay.io-instead-of-Docker-Hub-to-avoid-rate-l.patch
@@ -0,0 +1,33 @@
+From 2dd82aad646bde5a0d49df8562e2578c8b3d04f4 Mon Sep 17 00:00:00 2001
+From: Frantisek Sumsal <frantisek@sumsal.cz>
+Date: Fri, 15 Jan 2021 13:00:33 +0100
+Subject: [PATCH] ci: use quay.io instead of Docker Hub to avoid rate limits
+
+Docker Hub introduced rate limits for anonymous users (100 requests per
+six hours), which break our CI in the busier periods. Let's try to use
+the quay.io CentOS image to mitigate this.
+
+rhel-only
+Related: #1871827
+---
+ ci/travis-centos-rhel8.sh | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/ci/travis-centos-rhel8.sh b/ci/travis-centos-rhel8.sh
+index 43e2cb2585..ffe5813b1a 100755
+--- a/ci/travis-centos-rhel8.sh
++++ b/ci/travis-centos-rhel8.sh
+@@ -81,11 +81,11 @@ for phase in "${PHASES[@]}"; do
+             info "Setup phase"
+             info "Using Travis $CENTOS_RELEASE"
+             # Pull a Docker image and start a new container
+-            docker pull centos:$CENTOS_RELEASE
++            docker pull quay.io/centos/centos:$CENTOS_RELEASE
+             info "Starting container $CONT_NAME"
+             $DOCKER_RUN -v $REPO_ROOT:/build:rw \
+                         -w /build --privileged=true --name $CONT_NAME \
+-                        -dit --net=host centos:$CENTOS_RELEASE /sbin/init
++                        -dit --net=host quay.io/centos/centos:$CENTOS_RELEASE /sbin/init
+             # Beautiful workaround for Fedora's version of Docker
+             sleep 1
+             $DOCKER_EXEC dnf makecache
diff --git a/SOURCES/0498-ci-move-jobs-from-Travis-CI-to-GH-Actions.patch b/SOURCES/0498-ci-move-jobs-from-Travis-CI-to-GH-Actions.patch
new file mode 100644
index 0000000..70ba33f
--- /dev/null
+++ b/SOURCES/0498-ci-move-jobs-from-Travis-CI-to-GH-Actions.patch
@@ -0,0 +1,338 @@
+From 88ac207cc619935c64923e6f8fdef324a5b733d8 Mon Sep 17 00:00:00 2001
+From: Frantisek Sumsal <frantisek@sumsal.cz>
+Date: Fri, 15 Jan 2021 15:13:53 +0100
+Subject: [PATCH] ci: move jobs from Travis CI to GH Actions
+
+The OSS version of Travis CI is going to be merged with the commercial
+one soon, essentially dropping the free tier, so let's move the CI jobs
+to GitHub Actions to keep them up.
+
+rhel-only
+Related: #1871827
+---
+ .../workflows/unit_tests.sh                   | 28 +++----
+ .github/workflows/unit_tests.yml              | 28 +++++++
+ .travis.yml                                   | 48 ------------
+ ci/travis-centos-rhel7.sh                     | 73 -------------------
+ ci/travis_wait.bash                           | 61 ----------------
+ 5 files changed, 37 insertions(+), 201 deletions(-)
+ rename ci/travis-centos-rhel8.sh => .github/workflows/unit_tests.sh (82%)
+ create mode 100644 .github/workflows/unit_tests.yml
+ delete mode 100644 .travis.yml
+ delete mode 100755 ci/travis-centos-rhel7.sh
+ delete mode 100644 ci/travis_wait.bash
+
+diff --git a/ci/travis-centos-rhel8.sh b/.github/workflows/unit_tests.sh
+similarity index 82%
+rename from ci/travis-centos-rhel8.sh
+rename to .github/workflows/unit_tests.sh
+index ffe5813b1a..ea4f7e7592 100755
+--- a/ci/travis-centos-rhel8.sh
++++ b/.github/workflows/unit_tests.sh
+@@ -1,18 +1,9 @@
+ #!/bin/bash
+ 
+-# Run this script from the root of the systemd's git repository
+-# or set REPO_ROOT to a correct path.
+-#
+-# Example execution on Fedora:
+-# dnf install docker
+-# systemctl start docker
+-# export CONT_NAME="my-fancy-container"
+-# ci/travis-centos.sh SETUP RUN CLEANUP
+-
+ PHASES=(${@:-SETUP RUN CLEANUP})
+ CENTOS_RELEASE="${CENTOS_RELEASE:-latest}"
+ CONT_NAME="${CONT_NAME:-centos-$CENTOS_RELEASE-$RANDOM}"
+-DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
++DOCKER_EXEC="${DOCKER_EXEC:-docker exec $CONT_NAME}"
+ DOCKER_RUN="${DOCKER_RUN:-docker run}"
+ REPO_ROOT="${REPO_ROOT:-$PWD}"
+ ADDITIONAL_DEPS=(libasan libubsan net-tools strace nc e2fsprogs quota dnsmasq diffutils)
+@@ -71,9 +62,7 @@ function info() {
+     echo -e "\033[33;1m$1\033[0m"
+ }
+ 
+-set -e
+-
+-source "$(dirname $0)/travis_wait.bash"
++set -ex
+ 
+ for phase in "${PHASES[@]}"; do
+     case $phase in
+@@ -86,6 +75,7 @@ for phase in "${PHASES[@]}"; do
+             $DOCKER_RUN -v $REPO_ROOT:/build:rw \
+                         -w /build --privileged=true --name $CONT_NAME \
+                         -dit --net=host quay.io/centos/centos:$CENTOS_RELEASE /sbin/init
++
+             # Beautiful workaround for Fedora's version of Docker
+             sleep 1
+             $DOCKER_EXEC dnf makecache
+@@ -97,10 +87,10 @@ for phase in "${PHASES[@]}"; do
+             # Install systemd's build dependencies
+             $DOCKER_EXEC dnf -q -y --enablerepo "powertools" builddep systemd
+             ;;
+-        RUN)
++        RUN|RUN_GCC)
+             info "Run phase"
+             # Build systemd
+-            docker exec -it -e CFLAGS='-g -O0 -ftrapv' $CONT_NAME meson build -Dtests=unsafe -Dslow-tests=true "${CONFIGURE_OPTS[@]}"
++            docker exec -e CFLAGS='-g -O0 -ftrapv' $CONT_NAME meson build -Dtests=unsafe -Dslow-tests=true "${CONFIGURE_OPTS[@]}"
+             $DOCKER_EXEC ninja -v -C build
+             # Let's install the new systemd and "reboot" the container to avoid
+             # unexpected fails due to incompatibilities with older systemd
+@@ -108,16 +98,16 @@ for phase in "${PHASES[@]}"; do
+             docker restart $CONT_NAME
+             $DOCKER_EXEC ninja -C build test
+             ;;
+-        RUN_ASAN|RUN_CLANG_ASAN)
++        RUN_ASAN|RUN_GCC_ASAN|RUN_CLANG_ASAN)
+             if [[ "$phase" = "RUN_CLANG_ASAN" ]]; then
+                 ENV_VARS="-e CC=clang -e CXX=clang++"
+                 MESON_ARGS="-Db_lundef=false" # See https://github.com/mesonbuild/meson/issues/764
+             fi
+-            docker exec $ENV_VARS -it $CONT_NAME meson build --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS "${CONFIGURE_OPTS[@]}"
+-            docker exec -it $CONT_NAME ninja -v -C build
++            docker exec $ENV_VARS $CONT_NAME meson build --werror -Dtests=unsafe -Db_sanitize=address,undefined $MESON_ARGS "${CONFIGURE_OPTS[@]}"
++            docker exec $CONT_NAME ninja -v -C build
+ 
+             # Never remove halt_on_error from UBSAN_OPTIONS. See https://github.com/systemd/systemd/commit/2614d83aa06592aedb.
+-            travis_wait docker exec --interactive=false \
++            docker exec --interactive=false \
+                 -e UBSAN_OPTIONS=print_stacktrace=1:print_summary=1:halt_on_error=1 \
+                 -e ASAN_OPTIONS=strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1 \
+                 -e "TRAVIS=$TRAVIS" \
+diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml
+new file mode 100644
+index 0000000000..15f5127a75
+--- /dev/null
++++ b/.github/workflows/unit_tests.yml
+@@ -0,0 +1,28 @@
++---
++# vi: ts=2 sw=2 et:
++#
++name: Unit tests
++on:
++  pull_request:
++    branches:
++      - master
++
++jobs:
++  build:
++    runs-on: ubuntu-20.04
++    env:
++      CENTOS_RELEASE: "centos8"
++      CONT_NAME:      "systemd-centos8-ci"
++    strategy:
++      fail-fast: false
++      matrix:
++        run_phase: [GCC, GCC_ASAN]
++    steps:
++      - name: Repository checkout
++        uses: actions/checkout@v1
++      - name: Install build dependencies
++        run: sudo -E .github/workflows/unit_tests.sh SETUP
++      - name: Build & test (${{ matrix.run_phase }})
++        run: sudo -E .github/workflows/unit_tests.sh RUN_${{ matrix.run_phase }}
++      - name: Cleanup
++        run: sudo -E .github/workflows/unit_tests.sh CLEANUP
+diff --git a/.travis.yml b/.travis.yml
+deleted file mode 100644
+index 70c60cf24e..0000000000
+--- a/.travis.yml
++++ /dev/null
+@@ -1,48 +0,0 @@
+-sudo: required
+-dist: xenial
+-services:
+-    - docker
+-
+-env:
+-    global:
+-        - CI_ROOT="$TRAVIS_BUILD_DIR/ci/"
+-
+-jobs:
+-    include:
+-        - name: CentOS 8
+-          language: bash
+-          env:
+-              - CENTOS_RELEASE="centos8"
+-              - CONT_NAME="systemd-centos-$CENTOS_RELEASE"
+-              - DOCKER_EXEC="docker exec -ti $CONT_NAME"
+-          before_install:
+-              - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
+-              - docker --version
+-          install:
+-              - $CI_ROOT/travis-centos-rhel8.sh SETUP
+-          script:
+-              - set -e
+-              # Build systemd
+-              - $CI_ROOT/travis-centos-rhel8.sh RUN
+-              - set +e
+-          after_script:
+-              - $CI_ROOT/travis-centos-rhel8.sh CLEANUP
+-
+-        - name: CentOS 8 (ASan+UBSan)
+-          language: bash
+-          env:
+-              - CENTOS_RELEASE="centos8"
+-              - CONT_NAME="systemd-centos-$CENTOS_RELEASE"
+-              - DOCKER_EXEC="docker exec -ti $CONT_NAME"
+-          before_install:
+-              - sudo apt-get -y -o Dpkg::Options::="--force-confnew" install docker-ce
+-              - docker --version
+-          install:
+-              - $CI_ROOT/travis-centos-rhel8.sh SETUP
+-          script:
+-              - set -e
+-              # Build systemd
+-              - $CI_ROOT/travis-centos-rhel8.sh RUN_ASAN
+-              - set +e
+-          after_script:
+-              - $CI_ROOT/travis-centos-rhel8.sh CLEANUP
+diff --git a/ci/travis-centos-rhel7.sh b/ci/travis-centos-rhel7.sh
+deleted file mode 100755
+index 73416798ed..0000000000
+--- a/ci/travis-centos-rhel7.sh
++++ /dev/null
+@@ -1,73 +0,0 @@
+-#!/bin/bash
+-
+-# Run this script from the root of the systemd's git repository
+-# or set REPO_ROOT to a correct path.
+-#
+-# Example execution on Fedora:
+-# dnf install docker
+-# systemctl start docker
+-# export CONT_NAME="my-fancy-container"
+-# ci/travis-centos.sh SETUP RUN CLEANUP
+-
+-PHASES=(${@:-SETUP RUN CLEANUP})
+-CENTOS_RELEASE="${CENTOS_RELEASE:-latest}"
+-CONT_NAME="${CONT_NAME:-centos-$CENTOS_RELEASE-$RANDOM}"
+-DOCKER_EXEC="${DOCKER_EXEC:-docker exec -it $CONT_NAME}"
+-DOCKER_RUN="${DOCKER_RUN:-docker run}"
+-REPO_ROOT="${REPO_ROOT:-$PWD}"
+-ADDITIONAL_DEPS=(yum-utils iputils hostname libasan libubsan clang llvm)
+-
+-function info() {
+-    echo -e "\033[33;1m$1\033[0m"
+-}
+-
+-set -e
+-
+-source "$(dirname $0)/travis_wait.bash"
+-
+-for phase in "${PHASES[@]}"; do
+-    case $phase in
+-        SETUP)
+-            info "Setup phase"
+-            info "Using Travis $CENTOS_RELEASE"
+-            # Pull a Docker image and start a new container
+-            docker pull centos:$CENTOS_RELEASE
+-            info "Starting container $CONT_NAME"
+-            $DOCKER_RUN -v $REPO_ROOT:/build:rw \
+-                        -w /build --privileged=true --name $CONT_NAME \
+-                        -dit --net=host centos:$CENTOS_RELEASE /sbin/init
+-            # Beautiful workaround for Fedora's version of Docker
+-            sleep 1
+-            $DOCKER_EXEC yum makecache
+-            # Install necessary build/test requirements
+-            $DOCKER_EXEC yum -y upgrade
+-            $DOCKER_EXEC yum -y install "${ADDITIONAL_DEPS[@]}"
+-            $DOCKER_EXEC yum-builddep -y systemd
+-            ;;
+-        RUN)
+-            info "Run phase"
+-            # Build systemd
+-            $DOCKER_EXEC ./autogen.sh
+-            $DOCKER_EXEC ./configure --disable-timesyncd --disable-kdbus --disable-terminal \
+-                                     --enable-gtk-doc --enable-compat-libs --disable-sysusers \
+-                                     --disable-ldconfig --enable-lz4 --with-sysvinit-path=/etc/rc.d/init.d
+-            $DOCKER_EXEC make
+-            # Let's install the new systemd and "reboot" the container to avoid
+-            # unexpected fails due to incompatibilities with older systemd
+-            $DOCKER_EXEC make install
+-            docker restart $CONT_NAME
+-            if ! $DOCKER_EXEC make check; then
+-                $DOCKER_EXEC cat test-suite.log
+-                exit 1
+-            fi
+-            ;;
+-        CLEANUP)
+-            info "Cleanup phase"
+-            docker stop $CONT_NAME
+-            docker rm -f $CONT_NAME
+-            ;;
+-        *)
+-            echo >&2 "Unknown phase '$phase'"
+-            exit 1
+-    esac
+-done
+diff --git a/ci/travis_wait.bash b/ci/travis_wait.bash
+deleted file mode 100644
+index acf6ad15e4..0000000000
+--- a/ci/travis_wait.bash
++++ /dev/null
+@@ -1,61 +0,0 @@
+-# This was borrowed from https://github.com/travis-ci/travis-build/tree/master/lib/travis/build/bash
+-# to get around https://github.com/travis-ci/travis-ci/issues/9979. It should probably be removed
+-# as soon as Travis CI has started to provide an easy way to export the functions to bash scripts.
+-
+-travis_jigger() {
+-  local cmd_pid="${1}"
+-  shift
+-  local timeout="${1}"
+-  shift
+-  local count=0
+-
+-  echo -e "\\n"
+-
+-  while [[ "${count}" -lt "${timeout}" ]]; do
+-    count="$((count + 1))"
+-    echo -ne "Still running (${count} of ${timeout}): ${*}\\r"
+-    sleep 60
+-  done
+-
+-  echo -e "\\n${ANSI_RED}Timeout (${timeout} minutes) reached. Terminating \"${*}\"${ANSI_RESET}\\n"
+-  kill -9 "${cmd_pid}"
+-}
+-
+-travis_wait() {
+-  local timeout="${1}"
+-
+-  if [[ "${timeout}" =~ ^[0-9]+$ ]]; then
+-    shift
+-  else
+-    timeout=20
+-  fi
+-
+-  local cmd=("${@}")
+-  local log_file="travis_wait_${$}.log"
+-
+-  "${cmd[@]}" &>"${log_file}" &
+-  local cmd_pid="${!}"
+-
+-  travis_jigger "${!}" "${timeout}" "${cmd[@]}" &
+-  local jigger_pid="${!}"
+-  local result
+-
+-  {
+-    set +e
+-    wait "${cmd_pid}" 2>/dev/null
+-    result="${?}"
+-    ps -p"${jigger_pid}" &>/dev/null && kill "${jigger_pid}"
+-    set -e
+-  }
+-
+-  if [[ "${result}" -eq 0 ]]; then
+-    echo -e "\\n${ANSI_GREEN}The command ${cmd[*]} exited with ${result}.${ANSI_RESET}"
+-  else
+-    echo -e "\\n${ANSI_RED}The command ${cmd[*]} exited with ${result}.${ANSI_RESET}"
+-  fi
+-
+-  echo -e "\\n${ANSI_GREEN}Log:${ANSI_RESET}\\n"
+-  cat "${log_file}"
+-
+-  return "${result}"
+-}
diff --git a/SOURCES/0499-unit-make-UNIT-cast-function-deal-with-NULL-pointers.patch b/SOURCES/0499-unit-make-UNIT-cast-function-deal-with-NULL-pointers.patch
new file mode 100644
index 0000000..9f2143b
--- /dev/null
+++ b/SOURCES/0499-unit-make-UNIT-cast-function-deal-with-NULL-pointers.patch
@@ -0,0 +1,31 @@
+From a11334f0eae67b5159a416193e2e37634281000a Mon Sep 17 00:00:00 2001
+From: Lennart Poettering <lennart@poettering.net>
+Date: Thu, 8 Nov 2018 09:33:31 +0100
+Subject: [PATCH] unit: make UNIT() cast function deal with NULL pointers
+
+Fixes: #10681
+(cherry picked from commit bbf11206230d1b089118971f98a047151cb5c4fa)
+
+Related: #1871827
+---
+ src/core/unit.h | 7 ++++++-
+ 1 file changed, 6 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/unit.h b/src/core/unit.h
+index 6e37fd6f5a..ec45b5fb48 100644
+--- a/src/core/unit.h
++++ b/src/core/unit.h
+@@ -597,7 +597,12 @@ extern const UnitVTable * const unit_vtable[_UNIT_TYPE_MAX];
+         }
+ 
+ /* For casting the various unit types into a unit */
+-#define UNIT(u) (&(u)->meta)
++#define UNIT(u)                                         \
++        ({                                              \
++                typeof(u) _u_ = (u);                    \
++                Unit *_w_ = _u_ ? &(_u_)->meta : NULL;  \
++                _w_;                                    \
++        })
+ 
+ #define UNIT_HAS_EXEC_CONTEXT(u) (UNIT_VTABLE(u)->exec_context_offset > 0)
+ #define UNIT_HAS_CGROUP_CONTEXT(u) (UNIT_VTABLE(u)->cgroup_context_offset > 0)
diff --git a/SOURCES/0500-use-link-to-RHEL-8-docs.patch b/SOURCES/0500-use-link-to-RHEL-8-docs.patch
new file mode 100644
index 0000000..ecc4968
--- /dev/null
+++ b/SOURCES/0500-use-link-to-RHEL-8-docs.patch
@@ -0,0 +1,25 @@
+From 6fb6c218fda0d5c3404049243b9392e9b0c7d537 Mon Sep 17 00:00:00 2001
+From: David Tardon <dtardon@redhat.com>
+Date: Fri, 11 Dec 2020 09:34:19 +0100
+Subject: [PATCH] use link to RHEL-8 docs
+
+RHEL-only
+
+Related: #1623116
+---
+ man/systemctl.xml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/man/systemctl.xml b/man/systemctl.xml
+index 56f94d084c..ed60a0739f 100644
+--- a/man/systemctl.xml
++++ b/man/systemctl.xml
+@@ -2005,7 +2005,7 @@ Jan 12 10:46:45 example.com bluetoothd[8900]: gatt-time-server: Input/output err
+     <para>
+             For examples how to use systemctl in comparsion
+             with old service and chkconfig command please see:
+-            <ulink url="https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/System_Administrators_Guide/sect-Managing_Services_with_systemd-Services.html">
++            <ulink url="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/8/html/configuring_basic_system_settings/managing-services-with-systemd_configuring-basic-system-settings">
+                     Managing System Services
+             </ulink>
+     </para>
diff --git a/SOURCES/0501-cgroup-Also-set-blkio.bfq.weight.patch b/SOURCES/0501-cgroup-Also-set-blkio.bfq.weight.patch
new file mode 100644
index 0000000..88ad896
--- /dev/null
+++ b/SOURCES/0501-cgroup-Also-set-blkio.bfq.weight.patch
@@ -0,0 +1,37 @@
+From af9f03ba48dd75be8c6a923f70da9804b3a3a2c3 Mon Sep 17 00:00:00 2001
+From: Pavel Hrdina <phrdina@redhat.com>
+Date: Wed, 25 Nov 2020 09:05:36 +0100
+Subject: [PATCH] cgroup: Also set blkio.bfq.weight
+
+Commit [1] added a workaround when unified cgroups are used but missed
+legacy cgroups where there is the same issue.
+
+[1] <https://github.com/systemd/systemd/commit/2dbc45aea747f25cc1c3848fded2ec0062f96bcf>
+
+Signed-off-by: Pavel Hrdina <phrdina@redhat.com>
+(cherry picked from commit 35e7a62ca32a30169a94693b831e53c832251984)
+
+Resolves: #1657810
+---
+ src/core/cgroup.c | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/src/core/cgroup.c b/src/core/cgroup.c
+index f1ce070f9a..71e30fd4db 100644
+--- a/src/core/cgroup.c
++++ b/src/core/cgroup.c
+@@ -1063,6 +1063,14 @@ static void cgroup_context_apply(
+                                 log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
+                                               "Failed to set blkio.weight: %m");
+ 
++                        /* FIXME: drop this when distro kernels properly support BFQ through "blkio.weight"
++                         * See also: https://github.com/systemd/systemd/pull/13335 */
++                        xsprintf(buf, "%" PRIu64 "\n", weight);
++                        r = cg_set_attribute("blkio", path, "blkio.bfq.weight", buf);
++                        if (r < 0)
++                                log_unit_full(u, IN_SET(r, -ENOENT, -EROFS, -EACCES) ? LOG_DEBUG : LOG_WARNING, r,
++                                              "Failed to set blkio.bfq.weight: %m");
++
+                         if (has_io) {
+                                 CGroupIODeviceWeight *w;
+ 
diff --git a/SOURCES/0502-units-make-sure-initrd-cleanup.service-terminates-be.patch b/SOURCES/0502-units-make-sure-initrd-cleanup.service-terminates-be.patch
new file mode 100644
index 0000000..3fdb46f
--- /dev/null
+++ b/SOURCES/0502-units-make-sure-initrd-cleanup.service-terminates-be.patch
@@ -0,0 +1,37 @@
+From ea425381a675a2ce4d9519d534fe27c1012ac92e Mon Sep 17 00:00:00 2001
+From: Franck Bui <fbui@suse.com>
+Date: Mon, 28 Jan 2019 12:07:37 +0100
+Subject: [PATCH] units: make sure initrd-cleanup.service terminates before
+ switching to rootfs
+
+A follow-up for commit a8cb1dc3e0fa81aff.
+
+Commit a8cb1dc3e0fa81aff made sure that initrd-cleanup.service won't be stopped
+when initrd-switch-root.target is isolated.
+
+However even with this change, it might happen that initrd-cleanup.service
+survives the switch to rootfs (since it has no ordering constraints against
+initrd-switch-root.target) and is stopped right after when default.target is
+isolated. This led to initrd-cleanup.service entering in failed state as it
+happens when oneshot services are stopped.
+
+This patch along with a8cb1dc3e0fa81aff should fix issue #4343.
+
+Fixes: #4343
+(cherry picked from commit e2c7c94ea35fe7e669afb51bfc2251158b522ea5)
+
+Related: #1657810
+---
+ units/initrd-switch-root.target | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/units/initrd-switch-root.target b/units/initrd-switch-root.target
+index ad82245121..ea4f02618f 100644
+--- a/units/initrd-switch-root.target
++++ b/units/initrd-switch-root.target
+@@ -15,4 +15,4 @@ Requires=initrd-switch-root.service
+ Before=initrd-switch-root.service
+ AllowIsolate=yes
+ Wants=initrd-udevadm-cleanup-db.service initrd-root-fs.target initrd-fs.target systemd-journald.service initrd-cleanup.service
+-After=initrd-udevadm-cleanup-db.service initrd-root-fs.target initrd-fs.target emergency.service emergency.target
++After=initrd-udevadm-cleanup-db.service initrd-root-fs.target initrd-fs.target emergency.service emergency.target initrd-cleanup.service
diff --git a/SOURCES/0503-core-reload-SELinux-label-cache-on-daemon-reload.patch b/SOURCES/0503-core-reload-SELinux-label-cache-on-daemon-reload.patch
new file mode 100644
index 0000000..5e5d3d4
--- /dev/null
+++ b/SOURCES/0503-core-reload-SELinux-label-cache-on-daemon-reload.patch
@@ -0,0 +1,73 @@
+From c67be1c7d69a0662ab85720aa0209110c39479f9 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
+Date: Wed, 27 Nov 2019 19:43:47 +0100
+Subject: [PATCH] core: reload SELinux label cache on daemon-reload
+
+Reloading the SELinux label cache here enables a light-wight follow-up of a SELinux policy change, e.g. adding a label for a RuntimeDirectory.
+
+Closes: #13363
+(cherry picked from commit a9dfac21ec850eb5dcaf1ae9ef729389e4c12802)
+
+Resolves: #1888912
+---
+ src/basic/selinux-util.c | 20 ++++++++++++++++++++
+ src/basic/selinux-util.h |  1 +
+ src/core/main.c          |  2 ++
+ 3 files changed, 23 insertions(+)
+
+diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
+index e15bd7e1fa..f69d88eb1e 100644
+--- a/src/basic/selinux-util.c
++++ b/src/basic/selinux-util.c
+@@ -105,6 +105,26 @@ void mac_selinux_finish(void) {
+ #endif
+ }
+ 
++void mac_selinux_reload(void) {
++
++#if HAVE_SELINUX
++        struct selabel_handle *backup_label_hnd;
++
++        if (!label_hnd)
++                return;
++
++        backup_label_hnd = TAKE_PTR(label_hnd);
++
++        /* try to initialize new handle
++         *    on success close backup
++         *    on failure restore backup */
++        if (mac_selinux_init() == 0)
++                selabel_close(backup_label_hnd);
++        else
++                label_hnd = backup_label_hnd;
++#endif
++}
++
+ int mac_selinux_fix(const char *path, LabelFixFlags flags) {
+ 
+ #if HAVE_SELINUX
+diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h
+index 08314057fb..abcfabe777 100644
+--- a/src/basic/selinux-util.h
++++ b/src/basic/selinux-util.h
+@@ -13,6 +13,7 @@ void mac_selinux_retest(void);
+ 
+ int mac_selinux_init(void);
+ void mac_selinux_finish(void);
++void mac_selinux_reload(void);
+ 
+ int mac_selinux_fix(const char *path, LabelFixFlags flags);
+ int mac_selinux_apply(const char *path, const char *label);
+diff --git a/src/core/main.c b/src/core/main.c
+index d897155644..d5c41da0c4 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -1682,6 +1682,8 @@ static int invoke_main_loop(
+                         saved_log_level = m->log_level_overridden ? log_get_max_level() : -1;
+                         saved_log_target = m->log_target_overridden ? log_get_target() : _LOG_TARGET_INVALID;
+ 
++                        mac_selinux_reload();
++
+                         (void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
+ 
+                         set_manager_defaults(m);
diff --git a/SOURCES/0504-selinux-introduce-mac_selinux_create_file_prepare_at.patch b/SOURCES/0504-selinux-introduce-mac_selinux_create_file_prepare_at.patch
new file mode 100644
index 0000000..4b51123
--- /dev/null
+++ b/SOURCES/0504-selinux-introduce-mac_selinux_create_file_prepare_at.patch
@@ -0,0 +1,140 @@
+From 4f4e8bbd9ad46fc146a36f52790bc4920f42ef1f Mon Sep 17 00:00:00 2001
+From: Franck Bui <fbui@suse.com>
+Date: Mon, 2 Jul 2018 10:22:56 +0200
+Subject: [PATCH] selinux: introduce mac_selinux_create_file_prepare_at()
+
+(cherry picked from commit 7e531a5265687aef5177b070c36ca4ceab42e768)
+
+Related: #1888912
+---
+ src/basic/selinux-util.c | 83 ++++++++++++++++++++++++++++++----------
+ src/basic/selinux-util.h |  1 +
+ 2 files changed, 63 insertions(+), 21 deletions(-)
+
+diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
+index f69d88eb1e..a078ce23ef 100644
+--- a/src/basic/selinux-util.c
++++ b/src/basic/selinux-util.c
+@@ -336,48 +336,89 @@ char* mac_selinux_free(char *label) {
+         return NULL;
+ }
+ 
+-int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
+-
+ #if HAVE_SELINUX
++static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode) {
+         _cleanup_freecon_ char *filecon = NULL;
++        _cleanup_free_ char *path = NULL;
+         int r;
+ 
+-        assert(path);
+-
+-        if (!label_hnd)
+-                return 0;
+-
+-        if (path_is_absolute(path))
+-                r = selabel_lookup_raw(label_hnd, &filecon, path, mode);
+-        else {
+-                _cleanup_free_ char *newpath = NULL;
+-
+-                r = path_make_absolute_cwd(path, &newpath);
+-                if (r < 0)
+-                        return r;
+-
+-                r = selabel_lookup_raw(label_hnd, &filecon, newpath, mode);
+-        }
++        assert(abspath);
++        assert(path_is_absolute(abspath));
+ 
++        r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode);
+         if (r < 0) {
+                 /* No context specified by the policy? Proceed without setting it. */
+                 if (errno == ENOENT)
+                         return 0;
+ 
+-                log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", path);
++                log_enforcing_errno(errno, "Failed to determine SELinux security context for %s: %m", abspath);
+         } else {
+                 if (setfscreatecon_raw(filecon) >= 0)
+                         return 0; /* Success! */
+ 
+-                log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, path);
++                log_enforcing_errno(errno, "Failed to set SELinux security context %s for %s: %m", filecon, abspath);
+         }
+ 
+         if (security_getenforce() > 0)
+                 return -errno;
+ 
+-#endif
+         return 0;
+ }
++#endif
++
++int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode) {
++        int r = 0;
++
++#if HAVE_SELINUX
++        _cleanup_free_ char *abspath = NULL;
++        _cleanup_close_ int fd = -1;
++
++        assert(path);
++
++        if (!label_hnd)
++                return 0;
++
++        if (!path_is_absolute(path)) {
++                _cleanup_free_ char *p = NULL;
++
++                if (dirfd == AT_FDCWD)
++                        r = safe_getcwd(&p);
++                else
++                        r = fd_get_path(dirfd, &p);
++                if (r < 0)
++                        return r;
++
++                abspath = path_join(NULL, p, path);
++                if (!abspath)
++                        return -ENOMEM;
++
++                path = abspath;
++        }
++
++        r = selinux_create_file_prepare_abspath(path, mode);
++#endif
++        return r;
++}
++
++int mac_selinux_create_file_prepare(const char *path, mode_t mode) {
++        int r = 0;
++
++#if HAVE_SELINUX
++        _cleanup_free_ char *abspath = NULL;
++
++        assert(path);
++
++        if (!label_hnd)
++                return 0;
++
++        r = path_make_absolute_cwd(path, &abspath);
++        if (r < 0)
++                return r;
++
++        r = selinux_create_file_prepare_abspath(abspath, mode);
++#endif
++        return r;
++}
+ 
+ void mac_selinux_create_file_clear(void) {
+ 
+diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h
+index abcfabe777..639c35b687 100644
+--- a/src/basic/selinux-util.h
++++ b/src/basic/selinux-util.h
+@@ -24,6 +24,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *
+ char* mac_selinux_free(char *label);
+ 
+ int mac_selinux_create_file_prepare(const char *path, mode_t mode);
++int mac_selinux_create_file_prepare_at(int dirfd, const char *path, mode_t mode);
+ void mac_selinux_create_file_clear(void);
+ 
+ int mac_selinux_create_socket_prepare(const char *label);
diff --git a/SOURCES/0505-selinux-add-trigger-for-policy-reload-to-refresh-int.patch b/SOURCES/0505-selinux-add-trigger-for-policy-reload-to-refresh-int.patch
new file mode 100644
index 0000000..4bba960
--- /dev/null
+++ b/SOURCES/0505-selinux-add-trigger-for-policy-reload-to-refresh-int.patch
@@ -0,0 +1,135 @@
+From 4e48673172b012a06575e4f5b681d3554eded2e2 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= <cgzones@googlemail.com>
+Date: Mon, 6 Jan 2020 15:27:23 +0100
+Subject: [PATCH] selinux: add trigger for policy reload to refresh internal
+ selabel cache
+
+Reload the internal selabel cache automatically on SELinux policy reloads so non pid-1 daemons are participating.
+
+Run the reload function `mac_selinux_reload()` not manually on daemon-reload, but rather pass it as callback to libselinux.
+Trigger the callback prior usage of the systemd internal selabel cache by depleting the selinux netlink socket via `avc_netlink_check_nb()`.
+
+Improves: a9dfac21ec85 ("core: reload SELinux label cache on daemon-reload")
+Improves: #13363
+(cherry picked from commit 61f3e897f13101f29fb8027e8839498a469ad58e)
+
+Related: #1888912
+---
+ src/basic/selinux-util.c | 23 +++++++++++++++++++----
+ src/basic/selinux-util.h |  1 -
+ src/core/main.c          |  2 --
+ 3 files changed, 19 insertions(+), 7 deletions(-)
+
+diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c
+index a078ce23ef..bfe3d015aa 100644
+--- a/src/basic/selinux-util.c
++++ b/src/basic/selinux-util.c
+@@ -10,6 +10,7 @@
+ #include <syslog.h>
+ 
+ #if HAVE_SELINUX
++#include <selinux/avc.h>
+ #include <selinux/context.h>
+ #include <selinux/label.h>
+ #include <selinux/selinux.h>
+@@ -32,6 +33,8 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(context_t, context_free);
+ #define _cleanup_freecon_ _cleanup_(freeconp)
+ #define _cleanup_context_free_ _cleanup_(context_freep)
+ 
++static int mac_selinux_reload(int seqno);
++
+ static int cached_use = -1;
+ static struct selabel_handle *label_hnd = NULL;
+ 
+@@ -63,6 +66,8 @@ int mac_selinux_init(void) {
+         usec_t before_timestamp, after_timestamp;
+         struct mallinfo before_mallinfo, after_mallinfo;
+ 
++        selinux_set_callback(SELINUX_CB_POLICYLOAD, (union selinux_callback) mac_selinux_reload);
++
+         if (label_hnd)
+                 return 0;
+ 
+@@ -105,13 +110,12 @@ void mac_selinux_finish(void) {
+ #endif
+ }
+ 
+-void mac_selinux_reload(void) {
+-
+ #if HAVE_SELINUX
++static int mac_selinux_reload(int seqno) {
+         struct selabel_handle *backup_label_hnd;
+ 
+         if (!label_hnd)
+-                return;
++                return 0;
+ 
+         backup_label_hnd = TAKE_PTR(label_hnd);
+ 
+@@ -122,8 +126,10 @@ void mac_selinux_reload(void) {
+                 selabel_close(backup_label_hnd);
+         else
+                 label_hnd = backup_label_hnd;
+-#endif
++
++        return 0;
+ }
++#endif
+ 
+ int mac_selinux_fix(const char *path, LabelFixFlags flags) {
+ 
+@@ -152,6 +158,9 @@ int mac_selinux_fix(const char *path, LabelFixFlags flags) {
+         if (fstat(fd, &st) < 0)
+                 return -errno;
+ 
++        /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
++        (void) avc_netlink_check_nb();
++
+         if (selabel_lookup_raw(label_hnd, &fcon, path, st.st_mode) < 0) {
+                 r = -errno;
+ 
+@@ -345,6 +354,9 @@ static int selinux_create_file_prepare_abspath(const char *abspath, mode_t mode)
+         assert(abspath);
+         assert(path_is_absolute(abspath));
+ 
++        /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
++        (void) avc_netlink_check_nb();
++
+         r = selabel_lookup_raw(label_hnd, &filecon, abspath, mode);
+         if (r < 0) {
+                 /* No context specified by the policy? Proceed without setting it. */
+@@ -496,6 +508,9 @@ int mac_selinux_bind(int fd, const struct sockaddr *addr, socklen_t addrlen) {
+ 
+         path = strndupa(un->sun_path, addrlen - offsetof(struct sockaddr_un, sun_path));
+ 
++        /* Check for policy reload so 'label_hnd' is kept up-to-date by callbacks */
++        (void) avc_netlink_check_nb();
++
+         if (path_is_absolute(path))
+                 r = selabel_lookup_raw(label_hnd, &fcon, path, S_IFSOCK);
+         else {
+diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h
+index 639c35b687..bd5207c318 100644
+--- a/src/basic/selinux-util.h
++++ b/src/basic/selinux-util.h
+@@ -13,7 +13,6 @@ void mac_selinux_retest(void);
+ 
+ int mac_selinux_init(void);
+ void mac_selinux_finish(void);
+-void mac_selinux_reload(void);
+ 
+ int mac_selinux_fix(const char *path, LabelFixFlags flags);
+ int mac_selinux_apply(const char *path, const char *label);
+diff --git a/src/core/main.c b/src/core/main.c
+index d5c41da0c4..d897155644 100644
+--- a/src/core/main.c
++++ b/src/core/main.c
+@@ -1682,8 +1682,6 @@ static int invoke_main_loop(
+                         saved_log_level = m->log_level_overridden ? log_get_max_level() : -1;
+                         saved_log_target = m->log_target_overridden ? log_get_target() : _LOG_TARGET_INVALID;
+ 
+-                        mac_selinux_reload();
+-
+                         (void) parse_configuration(saved_rlimit_nofile, saved_rlimit_memlock);
+ 
+                         set_manager_defaults(m);
diff --git a/SOURCES/0506-udev-net_id-give-RHEL-8.4-naming-scheme-a-name.patch b/SOURCES/0506-udev-net_id-give-RHEL-8.4-naming-scheme-a-name.patch
new file mode 100644
index 0000000..0ce9150
--- /dev/null
+++ b/SOURCES/0506-udev-net_id-give-RHEL-8.4-naming-scheme-a-name.patch
@@ -0,0 +1,24 @@
+From fb58a56c6c1c2749ba634abd9ad76f4e718269a1 Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Tue, 5 Jan 2021 12:30:15 +0100
+Subject: [PATCH] udev/net_id: give RHEL-8.4 naming scheme a name
+
+Follow-up for bb6114af097da0cd9c5081e42db718559130687f
+
+Related: #1827462
+---
+ src/udev/udev-builtin-net_id.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c
+index d8c56b62bb..7c153f0aef 100644
+--- a/src/udev/udev-builtin-net_id.c
++++ b/src/udev/udev-builtin-net_id.c
+@@ -150,6 +150,7 @@ static const NamingScheme naming_schemes[] = {
+         { "rhel-8.1", NAMING_RHEL_8_1 },
+         { "rhel-8.2", NAMING_RHEL_8_2 },
+         { "rhel-8.3", NAMING_RHEL_8_3 },
++        { "rhel-8.4", NAMING_RHEL_8_4 },
+         /* … add more schemes here, as the logic to name devices is updated … */
+ };
+ 
diff --git a/SOURCES/0507-basic-stat-util-make-mtime-check-stricter-and-use-en.patch b/SOURCES/0507-basic-stat-util-make-mtime-check-stricter-and-use-en.patch
new file mode 100644
index 0000000..e9ac657
--- /dev/null
+++ b/SOURCES/0507-basic-stat-util-make-mtime-check-stricter-and-use-en.patch
@@ -0,0 +1,63 @@
+From 29c5b8dd6228c4401f034ca0aa85f99ac42cf8dd Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Michal=20Sekleta=CC=81r?= <msekleta@redhat.com>
+Date: Thu, 5 Nov 2020 17:55:25 +0100
+Subject: [PATCH] basic/stat-util: make mtime check stricter and use entire
+ timestamp
+
+Note that st_mtime member of struct stat is defined as follows,
+
+ #define st_mtime st_mtim.tv_sec
+
+Hence we omitted checking nanosecond part of the timestamp (struct
+timespec) and possibly would miss modifications that happened within the
+same second.
+
+(cherry picked from commit a59b0a9f768f6e27b25f4f1bab6de08842e78d74)
+
+Related: #1642728
+---
+ src/basic/stat-util.c | 22 ++++++++++++++++++++++
+ src/basic/stat-util.h |  2 ++
+ 2 files changed, 24 insertions(+)
+
+diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c
+index 26aee9bad6..c61c4c0517 100644
+--- a/src/basic/stat-util.c
++++ b/src/basic/stat-util.c
+@@ -287,3 +287,25 @@ int fd_verify_regular(int fd) {
+ 
+         return stat_verify_regular(&st);
+ }
++
++bool stat_inode_unmodified(const struct stat *a, const struct stat *b) {
++
++        /* Returns if the specified stat structures reference the same, unmodified inode. This check tries to
++         * be reasonably careful when detecting changes: we check both inode and mtime, to cater for file
++         * systems where mtimes are fixed to 0 (think: ostree/nixos type installations). We also check file
++         * size, backing device, inode type and if this refers to a device not the major/minor.
++         *
++         * Note that we don't care if file attributes such as ownership or access mode change, this here is
++         * about contents of the file. The purpose here is to detect file contents changes, and nothing
++         * else. */
++
++        return a && b &&
++                (a->st_mode & S_IFMT) != 0 && /* We use the check for .st_mode if the structure was ever initialized */
++                ((a->st_mode ^ b->st_mode) & S_IFMT) == 0 &&  /* same inode type */
++                a->st_mtim.tv_sec == b->st_mtim.tv_sec &&
++                a->st_mtim.tv_nsec == b->st_mtim.tv_nsec &&
++                (!S_ISREG(a->st_mode) || a->st_size == b->st_size) && /* if regular file, compare file size */
++                a->st_dev == b->st_dev &&
++                a->st_ino == b->st_ino &&
++                (!(S_ISCHR(a->st_mode) || S_ISBLK(a->st_mode)) || a->st_rdev == b->st_rdev); /* if device node, also compare major/minor, because we can */
++}
+\ No newline at end of file
+diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h
+index f8014ed30b..9e1a2b70da 100644
+--- a/src/basic/stat-util.h
++++ b/src/basic/stat-util.h
+@@ -58,3 +58,5 @@ int path_is_temporary_fs(const char *path);
+ 
+ int stat_verify_regular(const struct stat *st);
+ int fd_verify_regular(int fd);
++
++bool stat_inode_unmodified(const struct stat *a, const struct stat *b);
diff --git a/SOURCES/0508-udev-make-algorithm-that-selects-highest-priority-de.patch b/SOURCES/0508-udev-make-algorithm-that-selects-highest-priority-de.patch
new file mode 100644
index 0000000..e20137b
--- /dev/null
+++ b/SOURCES/0508-udev-make-algorithm-that-selects-highest-priority-de.patch
@@ -0,0 +1,457 @@
+From 1d5f966c1758eb620755fcae54abd07a1ac36d3d Mon Sep 17 00:00:00 2001
+From: Michal Sekletar <msekleta@redhat.com>
+Date: Wed, 6 Jan 2021 11:43:50 +0100
+Subject: [PATCH] udev: make algorithm that selects highest priority devlink
+ less susceptible to race conditions
+
+Previously it was very likely, when multiple contenders for the symlink
+appear in parallel, that algorithm would select wrong symlink (i.e. one
+with lower-priority).
+
+Now the algorithm is much more defensive and when we detect change in
+set of contenders for the symlink we reevaluate the selection. Same
+happens when new symlink replaces already existing symlink that points
+to different device node.
+
+Resolves: #1642728
+---
+ src/udev/udev-event.c |  71 +++++++-----
+ src/udev/udev-node.c  | 244 ++++++++++++++++++++++++++++++------------
+ 2 files changed, 216 insertions(+), 99 deletions(-)
+
+diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c
+index fd8406d959..9004634f65 100644
+--- a/src/udev/udev-event.c
++++ b/src/udev/udev-event.c
+@@ -833,6 +833,41 @@ static int rename_netif(struct udev_event *event) {
+         return 0;
+ }
+ 
++static void update_devnode(struct udev_event *event) {
++        struct udev_device *dev = event->dev;
++
++        if (major(udev_device_get_devnum(dev)) > 0) {
++                bool apply;
++
++                /* remove/update possible left-over symlinks from old database entry */
++                if (event->dev_db != NULL)
++                        udev_node_update_old_links(dev, event->dev_db);
++
++                if (!event->owner_set)
++                        event->uid = udev_device_get_devnode_uid(dev);
++
++                if (!event->group_set)
++                        event->gid = udev_device_get_devnode_gid(dev);
++
++                if (!event->mode_set) {
++                        if (udev_device_get_devnode_mode(dev) > 0) {
++                                /* kernel supplied value */
++                                event->mode = udev_device_get_devnode_mode(dev);
++                        } else if (event->gid > 0) {
++                                /* default 0660 if a group is assigned */
++                                event->mode = 0660;
++                        }
++                        else {
++                                /* default 0600 */
++                                event->mode = 0600;
++                        }
++                }
++
++                apply = streq(udev_device_get_action(dev), "add") || event->owner_set || event->group_set || event->mode_set;
++                udev_node_add(dev, apply, event->mode, event->uid, event->gid, &event->seclabel_list);
++        }
++}
++
+ void udev_event_execute_rules(struct udev_event *event,
+                               usec_t timeout_usec, usec_t timeout_warn_usec,
+                               struct udev_list *properties_list,
+@@ -891,35 +926,7 @@ void udev_event_execute_rules(struct udev_event *event,
+                         }
+                 }
+ 
+-                if (major(udev_device_get_devnum(dev)) > 0) {
+-                        bool apply;
+-
+-                        /* remove/update possible left-over symlinks from old database entry */
+-                        if (event->dev_db != NULL)
+-                                udev_node_update_old_links(dev, event->dev_db);
+-
+-                        if (!event->owner_set)
+-                                event->uid = udev_device_get_devnode_uid(dev);
+-
+-                        if (!event->group_set)
+-                                event->gid = udev_device_get_devnode_gid(dev);
+-
+-                        if (!event->mode_set) {
+-                                if (udev_device_get_devnode_mode(dev) > 0) {
+-                                        /* kernel supplied value */
+-                                        event->mode = udev_device_get_devnode_mode(dev);
+-                                } else if (event->gid > 0) {
+-                                        /* default 0660 if a group is assigned */
+-                                        event->mode = 0660;
+-                                } else {
+-                                        /* default 0600 */
+-                                        event->mode = 0600;
+-                                }
+-                        }
+-
+-                        apply = streq(udev_device_get_action(dev), "add") || event->owner_set || event->group_set || event->mode_set;
+-                        udev_node_add(dev, apply, event->mode, event->uid, event->gid, &event->seclabel_list);
+-                }
++                update_devnode(event);
+ 
+                 /* preserve old, or get new initialization timestamp */
+                 udev_device_ensure_usec_initialized(event->dev, event->dev_db);
+@@ -927,6 +934,12 @@ void udev_event_execute_rules(struct udev_event *event,
+                 /* (re)write database file */
+                 udev_device_tag_index(dev, event->dev_db, true);
+                 udev_device_update_db(dev);
++
++                /* Yes, we run update_devnode() twice, because in the first invocation, that is before update of udev database,
++                 * it could happen that two contenders are replacing each other's symlink. Hence we run it again to make sure
++                 * symlinks point to devices that claim them with the highest priority. */
++                update_devnode(event);
++
+                 udev_device_set_is_initialized(dev);
+ 
+                 event->dev_db = udev_device_unref(event->dev_db);
+diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c
+index 333dcae6b9..2eeeccdd3a 100644
+--- a/src/udev/udev-node.c
++++ b/src/udev/udev-node.c
+@@ -13,19 +13,27 @@
+ #include <unistd.h>
+ 
+ #include "device-nodes.h"
++#include "device-private.h"
+ #include "dirent-util.h"
++#include "fd-util.h"
+ #include "format-util.h"
+ #include "fs-util.h"
++#include "sd-device.h"
+ #include "selinux-util.h"
+ #include "smack-util.h"
++#include "stat-util.h"
+ #include "stdio-util.h"
+ #include "string-util.h"
+ #include "udev.h"
++#include "libudev-device-internal.h"
+ 
+-static int node_symlink(struct udev_device *dev, const char *node, const char *slink) {
++#define LINK_UPDATE_MAX_RETRIES 128
++
++static int node_symlink(sd_device *dev, const char *node, const char *slink) {
+         struct stat stats;
+         char target[UTIL_PATH_SIZE];
+         char *s;
++        const char *id_filename;
+         size_t l;
+         char slink_tmp[UTIL_PATH_SIZE + 32];
+         int i = 0;
+@@ -89,7 +97,10 @@ static int node_symlink(struct udev_device *dev, const char *node, const char *s
+         }
+ 
+         log_debug("atomically replace '%s'", slink);
+-        strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", udev_device_get_id_filename(dev), NULL);
++        err = device_get_id_filename(dev, &id_filename);
++        if (err < 0)
++                return log_error_errno(err, "Failed to get id_filename: %m");
++        strscpyl(slink_tmp, sizeof(slink_tmp), slink, ".tmp-", id_filename, NULL);
+         unlink(slink_tmp);
+         do {
+                 err = mkdir_parents_label(slink_tmp, 0755);
+@@ -109,104 +120,187 @@ static int node_symlink(struct udev_device *dev, const char *node, const char *s
+         if (err != 0) {
+                 log_error_errno(errno, "rename '%s' '%s' failed: %m", slink_tmp, slink);
+                 unlink(slink_tmp);
+-        }
++        } else
++                /* Tell caller that we replaced already existing symlink. */
++                return 1;
+ exit:
+         return err;
+ }
+ 
+ /* find device node of device with highest priority */
+-static const char *link_find_prioritized(struct udev_device *dev, bool add, const char *stackdir, char *buf, size_t bufsize) {
+-        struct udev *udev = udev_device_get_udev(dev);
+-        DIR *dir;
++static int link_find_prioritized(sd_device *dev, bool add, const char *stackdir, char **ret) {
++        _cleanup_closedir_ DIR *dir = NULL;
++        _cleanup_free_ char *target = NULL;
+         struct dirent *dent;
+-        int priority = 0;
+-        const char *target = NULL;
++        int r, priority = 0;
++
++        assert(!add || dev);
++        assert(stackdir);
++        assert(ret);
+ 
+         if (add) {
+-                priority = udev_device_get_devlink_priority(dev);
+-                strscpy(buf, bufsize, udev_device_get_devnode(dev));
+-                target = buf;
++                const char *devnode;
++
++                r = device_get_devlink_priority(dev, &priority);
++                if (r < 0)
++                        return r;
++
++                r = sd_device_get_devname(dev, &devnode);
++                if (r < 0)
++                        return r;
++
++                target = strdup(devnode);
++                if (!target)
++                        return -ENOMEM;
+         }
+ 
+         dir = opendir(stackdir);
+-        if (dir == NULL)
+-                return target;
++        if (!dir) {
++                if (target) {
++                        *ret = TAKE_PTR(target);
++                        return 0;
++                }
++
++                return -errno;
++        }
++
+         FOREACH_DIRENT_ALL(dent, dir, break) {
+-                struct udev_device *dev_db;
++                _cleanup_(sd_device_unrefp) sd_device *dev_db = NULL;
++                const char *devnode, *id_filename;
++                int db_prio = 0;
+ 
+                 if (dent->d_name[0] == '\0')
+                         break;
+                 if (dent->d_name[0] == '.')
+                         continue;
+ 
+-                log_debug("found '%s' claiming '%s'", dent->d_name, stackdir);
++                log_debug("Found '%s' claiming '%s'", dent->d_name, stackdir);
++
++                if (device_get_id_filename(dev, &id_filename) < 0)
++                        continue;
+ 
+                 /* did we find ourself? */
+-                if (streq(dent->d_name, udev_device_get_id_filename(dev)))
++                if (streq(dent->d_name, id_filename))
+                         continue;
+ 
+-                dev_db = udev_device_new_from_device_id(udev, dent->d_name);
+-                if (dev_db != NULL) {
+-                        const char *devnode;
+-
+-                        devnode = udev_device_get_devnode(dev_db);
+-                        if (devnode != NULL) {
+-                                if (target == NULL || udev_device_get_devlink_priority(dev_db) > priority) {
+-                                        log_debug("'%s' claims priority %i for '%s'",
+-                                                  udev_device_get_syspath(dev_db), udev_device_get_devlink_priority(dev_db), stackdir);
+-                                        priority = udev_device_get_devlink_priority(dev_db);
+-                                        strscpy(buf, bufsize, devnode);
+-                                        target = buf;
+-                                }
+-                        }
+-                        udev_device_unref(dev_db);
++                if (sd_device_new_from_device_id(&dev_db, dent->d_name) < 0)
++                        continue;
++
++                if (sd_device_get_devname(dev_db, &devnode) < 0)
++                        continue;
++
++                if (device_get_devlink_priority(dev_db, &db_prio) < 0)
++                        continue;
++
++                if (target && db_prio <= priority)
++                        continue;
++
++                if (DEBUG_LOGGING) {
++                        const char *syspath = NULL;
++
++                        (void) sd_device_get_syspath(dev_db, &syspath);
++                        log_debug("Device '%s' claims priority %i for '%s'", strnull(syspath), db_prio, stackdir);
+                 }
++
++                r = free_and_strdup(&target, devnode);
++                if (r < 0)
++                        return r;
++                priority = db_prio;
+         }
+-        closedir(dir);
+-        return target;
++
++        if (!target)
++                return -ENOENT;
++
++        *ret = TAKE_PTR(target);
++        return 0;
+ }
+ 
++
+ /* manage "stack of names" with possibly specified device priorities */
+-static void link_update(struct udev_device *dev, const char *slink, bool add) {
+-        char name_enc[UTIL_PATH_SIZE];
+-        char filename[UTIL_PATH_SIZE * 2];
+-        char dirname[UTIL_PATH_SIZE];
+-        const char *target;
+-        char buf[UTIL_PATH_SIZE];
++static int link_update(sd_device *dev, const char *slink, bool add) {
++        _cleanup_free_ char *filename = NULL, *dirname = NULL;
++        char name_enc[PATH_MAX];
++        const char *id_filename;
++        int i, r, retries;
++
++        assert(dev);
++        assert(slink);
++
++        r = device_get_id_filename(dev, &id_filename);
++        if (r < 0)
++                return log_debug_errno(r, "Failed to get id_filename: %m");
+ 
+         util_path_encode(slink + STRLEN("/dev"), name_enc, sizeof(name_enc));
+-        strscpyl(dirname, sizeof(dirname), "/run/udev/links/", name_enc, NULL);
+-        strscpyl(filename, sizeof(filename), dirname, "/", udev_device_get_id_filename(dev), NULL);
++        dirname = path_join(NULL, "/run/udev/links/", name_enc);
++        if (!dirname)
++                return log_oom();
++        filename = path_join(NULL, dirname, id_filename);
++        if (!filename)
++                return log_oom();
++
++        if (!add) {
++                if (unlink(filename) == 0)
++                        (void) rmdir(dirname);
++        } else
++                for (;;) {
++                        _cleanup_close_ int fd = -1;
++
++                        r = mkdir_parents(filename, 0755);
++                        if (!IN_SET(r, 0, -ENOENT))
++                                return r;
+ 
+-        if (!add && unlink(filename) == 0)
+-                rmdir(dirname);
++                        fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
++                        if (fd >= 0)
++                                break;
++                        if (errno != ENOENT)
++                                return -errno;
++                }
+ 
+-        target = link_find_prioritized(dev, add, dirname, buf, sizeof(buf));
+-        if (target == NULL) {
+-                log_debug("no reference left, remove '%s'", slink);
+-                if (unlink(slink) == 0)
+-                        rmdir_parents(slink, "/");
+-        } else {
+-                log_debug("creating link '%s' to '%s'", slink, target);
+-                node_symlink(dev, target, slink);
+-        }
++        /* If the database entry is not written yet we will just do one iteration and possibly wrong symlink
++         * will be fixed in the second invocation. */
++        (void) sd_device_get_is_initialized(dev, &r);
++        retries = r > 0 ? LINK_UPDATE_MAX_RETRIES : 1;
+ 
+-        if (add) {
+-                int err;
++        for (i = 0; i < retries; i++) {
++                _cleanup_free_ char *target = NULL;
++                struct stat st1 = {}, st2 = {};
+ 
+-                do {
+-                        int fd;
++                r = stat(dirname, &st1);
++                if (r < 0 && errno != ENOENT)
++                        return -errno;
+ 
+-                        err = mkdir_parents(filename, 0755);
+-                        if (!IN_SET(err, 0, -ENOENT))
++                r = link_find_prioritized(dev, add, dirname, &target);
++                if (r == -ENOENT) {
++                        log_debug("No reference left, removing '%s'", slink);
++                        if (unlink(slink) == 0)
++                                (void) rmdir_parents(slink, "/");
++
++                        break;
++                } else if (r < 0)
++                        return log_error_errno(r, "Failed to determine highest priority symlink: %m");
++
++                r = node_symlink(dev, target, slink);
++                if (r < 0) {
++                        (void) unlink(filename);
++                        break;
++                } else if (r == 1)
++                        /* We have replaced already existing symlink, possibly there is some other device trying
++                         * to claim the same symlink. Let's do one more iteration to give us a chance to fix
++                         * the error if other device actually claims the symlink with higher priority. */
++                        continue;
++
++               /* Skip the second stat() if the first failed, stat_inode_unmodified() would return false regardless. */
++                if ((st1.st_mode & S_IFMT) != 0) {
++                        r = stat(dirname, &st2);
++                        if (r < 0 && errno != ENOENT)
++                                return -errno;
++
++                        if (stat_inode_unmodified(&st1, &st2))
+                                 break;
+-                        fd = open(filename, O_WRONLY|O_CREAT|O_CLOEXEC|O_TRUNC|O_NOFOLLOW, 0444);
+-                        if (fd >= 0)
+-                                close(fd);
+-                        else
+-                                err = -errno;
+-                } while (err == -ENOENT);
++                }
+         }
++
++        return i < LINK_UPDATE_MAX_RETRIES ? 0 : -ELOOP;
+ }
+ 
+ void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev_old) {
+@@ -233,7 +327,7 @@ void udev_node_update_old_links(struct udev_device *dev, struct udev_device *dev
+ 
+                 log_debug("update old name, '%s' no longer belonging to '%s'",
+                      name, udev_device_get_devpath(dev));
+-                link_update(dev, name, false);
++                link_update(dev->device, name, false);
+         }
+ }
+ 
+@@ -338,11 +432,16 @@ void udev_node_add(struct udev_device *dev, bool apply,
+         xsprintf_dev_num_path(filename,
+                               streq(udev_device_get_subsystem(dev), "block") ? "block" : "char",
+                               udev_device_get_devnum(dev));
+-        node_symlink(dev, udev_device_get_devnode(dev), filename);
++        node_symlink(dev->device, udev_device_get_devnode(dev), filename);
+ 
+         /* create/update symlinks, add symlinks to name index */
+-        udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev))
+-                        link_update(dev, udev_list_entry_get_name(list_entry), true);
++        udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
++                int r;
++
++                r = link_update(dev->device, udev_list_entry_get_name(list_entry), true);
++                if (r < 0)
++                        log_info_errno(r, "Failed to update device symlinks: %m");
++        }
+ }
+ 
+ void udev_node_remove(struct udev_device *dev) {
+@@ -350,8 +449,13 @@ void udev_node_remove(struct udev_device *dev) {
+         char filename[DEV_NUM_PATH_MAX];
+ 
+         /* remove/update symlinks, remove symlinks from name index */
+-        udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev))
+-                link_update(dev, udev_list_entry_get_name(list_entry), false);
++        udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
++                int r;
++
++                r = link_update(dev->device, udev_list_entry_get_name(list_entry), false);
++                if (r < 0)
++                        log_info_errno(r, "Failed to update device symlinks: %m");
++        }
+ 
+         /* remove /dev/{block,char}/$major:$minor */
+         xsprintf_dev_num_path(filename,
diff --git a/SOURCES/0509-test-create-dev-null-in-test-udev.pl.patch b/SOURCES/0509-test-create-dev-null-in-test-udev.pl.patch
new file mode 100644
index 0000000..4dccdbc
--- /dev/null
+++ b/SOURCES/0509-test-create-dev-null-in-test-udev.pl.patch
@@ -0,0 +1,32 @@
+From 6a908a38135d050b7c271fdea9c061d7e7ad8ef7 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Tue, 23 Oct 2018 07:23:01 +0900
+Subject: [PATCH] test: create /dev/null in test-udev.pl
+
+(cherry picked from commit a41ff38b0999fb83464309a29b8f39450b8d4b85)
+
+Related: #1642728
+---
+ test/udev-test.pl | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 0433629c7c..a1c24f49b4 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1537,13 +1537,14 @@ sub udev_setup {
+         system("umount", $udev_tmpfs);
+         rmdir($udev_tmpfs);
+         mkdir($udev_tmpfs) || die "unable to create udev_tmpfs: $udev_tmpfs\n";
+-        system("mount", "-o", "rw,mode=755,nosuid,noexec,nodev", "-t", "tmpfs", "tmpfs", $udev_tmpfs) && die "unable to mount tmpfs";
++        system("mount", "-o", "rw,mode=755,nosuid,noexec", "-t", "tmpfs", "tmpfs", $udev_tmpfs) && die "unable to mount tmpfs";
+ 
+         mkdir($udev_dev) || die "unable to create udev_dev: $udev_dev\n";
+         # setting group and mode of udev_dev ensures the tests work
+         # even if the parent directory has setgid bit enabled.
+         chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n";
+         chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n";
++        system("mknod", $udev_dev . "/null", "c", "1", "3") && "unable to create $udev_dev/null";
+ 
+         system("cp", "-r", "test/sys/", $udev_sys) && die "unable to copy test/sys";
+ 
diff --git a/SOURCES/0510-test-missing-die.patch b/SOURCES/0510-test-missing-die.patch
new file mode 100644
index 0000000..959a689
--- /dev/null
+++ b/SOURCES/0510-test-missing-die.patch
@@ -0,0 +1,27 @@
+From 70bf708d5360372aa541e25ff512609230781dd6 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 7 Nov 2018 14:56:20 +0900
+Subject: [PATCH] test: missing "die"
+
+Follow-up for a41ff38b0999fb83464309a29b8f39450b8d4b85.
+
+(cherry picked from commit 11d93952ea806de2b6e9fb381153115cccc7b5e8)
+
+Related: #1642728
+---
+ test/udev-test.pl | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index a1c24f49b4..61bd3d703a 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1544,7 +1544,7 @@ sub udev_setup {
+         # even if the parent directory has setgid bit enabled.
+         chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n";
+         chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n";
+-        system("mknod", $udev_dev . "/null", "c", "1", "3") && "unable to create $udev_dev/null";
++        system("mknod", $udev_dev . "/null", "c", "1", "3") && die "unable to create $udev_dev/null";
+ 
+         system("cp", "-r", "test/sys/", $udev_sys) && die "unable to copy test/sys";
+ 
diff --git a/SOURCES/0511-udev-test-remove-a-check-for-whether-the-test-is-run.patch b/SOURCES/0511-udev-test-remove-a-check-for-whether-the-test-is-run.patch
new file mode 100644
index 0000000..eeadbda
--- /dev/null
+++ b/SOURCES/0511-udev-test-remove-a-check-for-whether-the-test-is-run.patch
@@ -0,0 +1,33 @@
+From 1b133f2ca15f0a15b05407b2c04521d7de88dfa2 Mon Sep 17 00:00:00 2001
+From: Evgeny Vereshchagin <evvers@ya.ru>
+Date: Fri, 9 Nov 2018 03:14:04 +0100
+Subject: [PATCH] udev-test: remove a check for whether the test is run in a
+ container
+
+It's too broad a check that prevents the test from running on Travis CI.
+
+(cherry picked from commit 881886ef08d50951159633248b0f73977c5d6924)
+
+Related: #1642728
+---
+ test/udev-test.pl | 7 -------
+ 1 file changed, 7 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 61bd3d703a..05b3e17188 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1646,13 +1646,6 @@ if ($? >> 8 == 0) {
+         exit($EXIT_TEST_SKIP);
+ }
+ 
+-# skip the test when running in a container
+-system("systemd-detect-virt", "-c", "-q");
+-if ($? >> 8 == 0) {
+-        print "Running in a container, skipping the test.\n";
+-        exit($EXIT_TEST_SKIP);
+-}
+-
+ udev_setup();
+ 
+ my $test_num = 1;
diff --git a/SOURCES/0512-udev-test-skip-the-test-only-if-it-can-t-setup-its-e.patch b/SOURCES/0512-udev-test-skip-the-test-only-if-it-can-t-setup-its-e.patch
new file mode 100644
index 0000000..37970ab
--- /dev/null
+++ b/SOURCES/0512-udev-test-skip-the-test-only-if-it-can-t-setup-its-e.patch
@@ -0,0 +1,94 @@
+From 8c82f3a4aa2d029dcc303cbf95a71194aa5ac9c3 Mon Sep 17 00:00:00 2001
+From: Evgeny Vereshchagin <evvers@ya.ru>
+Date: Fri, 9 Nov 2018 04:01:15 +0100
+Subject: [PATCH] udev-test: skip the test only if it can't setup its
+ environment
+
+This is basically a replacement for 0eb3cc88504b5d8f74.
+
+(cherry picked from commit 110a13202eab6d92678abcde08372d4afac1cc45)
+
+Related: #1642728
+---
+ src/test/test-udev.c |  8 ++++++++
+ test/udev-test.pl    | 24 +++++++++++++++++++++---
+ 2 files changed, 29 insertions(+), 3 deletions(-)
+
+diff --git a/src/test/test-udev.c b/src/test/test-udev.c
+index bed51c1270..f098fab721 100644
+--- a/src/test/test-udev.c
++++ b/src/test/test-udev.c
+@@ -65,6 +65,11 @@ int main(int argc, char *argv[]) {
+         log_parse_environment();
+         log_open();
+ 
++        if (!IN_SET(argc, 2, 3)) {
++                log_error("This program needs one or two arguments, %d given", argc - 1);
++                return EXIT_FAILURE;
++        }
++
+         err = fake_filesystems();
+         if (err < 0)
+                 return EXIT_FAILURE;
+@@ -73,6 +78,9 @@ int main(int argc, char *argv[]) {
+         if (udev == NULL)
+                 return EXIT_FAILURE;
+ 
++        if (argc == 2)
++                return EXIT_SUCCESS;
++
+         log_debug("version %s", PACKAGE_VERSION);
+         mac_selinux_init();
+ 
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 05b3e17188..aa38bae0b1 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1537,18 +1537,28 @@ sub udev_setup {
+         system("umount", $udev_tmpfs);
+         rmdir($udev_tmpfs);
+         mkdir($udev_tmpfs) || die "unable to create udev_tmpfs: $udev_tmpfs\n";
+-        system("mount", "-o", "rw,mode=755,nosuid,noexec", "-t", "tmpfs", "tmpfs", $udev_tmpfs) && die "unable to mount tmpfs";
++
++        if (system("mount", "-o", "rw,mode=755,nosuid,noexec", "-t", "tmpfs", "tmpfs", $udev_tmpfs)) {
++                warn "unable to mount tmpfs";
++                return 0;
++        }
+ 
+         mkdir($udev_dev) || die "unable to create udev_dev: $udev_dev\n";
+         # setting group and mode of udev_dev ensures the tests work
+         # even if the parent directory has setgid bit enabled.
+         chown (0, 0, $udev_dev) || die "unable to chown $udev_dev\n";
+         chmod (0755, $udev_dev) || die "unable to chmod $udev_dev\n";
+-        system("mknod", $udev_dev . "/null", "c", "1", "3") && die "unable to create $udev_dev/null";
++
++        if (system("mknod", $udev_dev . "/null", "c", "1", "3")) {
++                warn "unable to create $udev_dev/null";
++                return 0;
++        }
+ 
+         system("cp", "-r", "test/sys/", $udev_sys) && die "unable to copy test/sys";
+ 
+         system("rm", "-rf", "$udev_run");
++
++        return 1;
+ }
+ 
+ sub run_test {
+@@ -1646,7 +1656,15 @@ if ($? >> 8 == 0) {
+         exit($EXIT_TEST_SKIP);
+ }
+ 
+-udev_setup();
++if (!udev_setup()) {
++        warn "Failed to set up the environment, skipping the test";
++        exit($EXIT_TEST_SKIP);
++}
++
++if (!system($udev_bin, "check")) {
++        warn "$udev_bin failed to set up the environment, skipping the test";
++        exit($EXIT_TEST_SKIP);
++}
+ 
+ my $test_num = 1;
+ my @list;
diff --git a/SOURCES/0513-udev-test-fix-test-skip-condition.patch b/SOURCES/0513-udev-test-fix-test-skip-condition.patch
new file mode 100644
index 0000000..165aadb
--- /dev/null
+++ b/SOURCES/0513-udev-test-fix-test-skip-condition.patch
@@ -0,0 +1,33 @@
+From f44fcdde656036f0388fc8244b8960c1873a3a08 Mon Sep 17 00:00:00 2001
+From: Alexey Bogdanenko <alexey@bogdanenko.com>
+Date: Sat, 8 Dec 2018 11:02:30 +0300
+Subject: [PATCH] udev-test: fix test skip condition
+
+When there is a failure to setup the environment, the following happens:
+
+1. Command "./test-udev check" exits with non-zero code.
+2. Perl function "system" returns the code.
+3. The code is evaluated as true by Perl.
+
+Then we stop the test.
+
+(cherry picked from commit 7935dae547caf164d807237f1009a9e9fa510337)
+
+Related: #1642728
+---
+ test/udev-test.pl | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index aa38bae0b1..3517feab15 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1661,7 +1661,7 @@ if (!udev_setup()) {
+         exit($EXIT_TEST_SKIP);
+ }
+ 
+-if (!system($udev_bin, "check")) {
++if (system($udev_bin, "check")) {
+         warn "$udev_bin failed to set up the environment, skipping the test";
+         exit($EXIT_TEST_SKIP);
+ }
diff --git a/SOURCES/0514-udev-test-fix-missing-directory-test-run.patch b/SOURCES/0514-udev-test-fix-missing-directory-test-run.patch
new file mode 100644
index 0000000..5714a16
--- /dev/null
+++ b/SOURCES/0514-udev-test-fix-missing-directory-test-run.patch
@@ -0,0 +1,35 @@
+From 974431a70775d5127cd973c4b4705d2cf8884011 Mon Sep 17 00:00:00 2001
+From: Alexey Bogdanenko <alexey@bogdanenko.com>
+Date: Sat, 8 Dec 2018 15:35:30 +0300
+Subject: [PATCH] udev-test: fix missing directory test/run
+
+Fixes the following error:
+
+    Failed to mount test /run: No such file or directory
+
+By the time command "./test-udev check" calls function "fake_filesystems",
+directory "test/run" must be present.
+
+(cherry picked from commit 1e5548c0e0962424b6ca5fdfd35c866b70760c8f)
+
+Related: #1642728
+---
+ test/udev-test.pl | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 3517feab15..eb76ebd72e 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1558,6 +1558,11 @@ sub udev_setup {
+ 
+         system("rm", "-rf", "$udev_run");
+ 
++        if (!mkdir($udev_run)) {
++                warn "unable to create directory $udev_run";
++                return 0;
++        }
++
+         return 1;
+ }
+ 
diff --git a/SOURCES/0515-udev-test-check-if-permitted-to-create-block-device-.patch b/SOURCES/0515-udev-test-check-if-permitted-to-create-block-device-.patch
new file mode 100644
index 0000000..67037a2
--- /dev/null
+++ b/SOURCES/0515-udev-test-check-if-permitted-to-create-block-device-.patch
@@ -0,0 +1,31 @@
+From 57e9ee0f19098d56995955f6692437affdf94041 Mon Sep 17 00:00:00 2001
+From: Alexey Bogdanenko <alexey@bogdanenko.com>
+Date: Tue, 11 Dec 2018 16:55:34 +0300
+Subject: [PATCH] udev-test: check if permitted to create block device nodes
+
+(cherry picked from commit dbfbc6c4e34366033cb340e8b0c3cbca683ff6f5)
+
+Related: #1642728
+---
+ test/udev-test.pl | 8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index eb76ebd72e..957cda541c 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1554,6 +1554,14 @@ sub udev_setup {
+                 return 0;
+         }
+ 
++        # check if we are permitted to create block device nodes
++        my $block_device_filename = $udev_dev . "/sda";
++        if (system("mknod", $block_device_filename, "b", "8", "0")) {
++                warn "unable to create $block_device_filename";
++                return 0;
++        }
++        unlink $block_device_filename;
++
+         system("cp", "-r", "test/sys/", $udev_sys) && die "unable to copy test/sys";
+ 
+         system("rm", "-rf", "$udev_run");
diff --git a/SOURCES/0516-test-udev-add-a-testcase-of-too-long-line.patch b/SOURCES/0516-test-udev-add-a-testcase-of-too-long-line.patch
new file mode 100644
index 0000000..7f712d8
--- /dev/null
+++ b/SOURCES/0516-test-udev-add-a-testcase-of-too-long-line.patch
@@ -0,0 +1,45 @@
+From 527d43064a93fae9a4490e5d152b120e91f5eade Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Mon, 18 Feb 2019 10:38:29 +0900
+Subject: [PATCH] test-udev: add a testcase of too long line
+
+(cherry picked from commit 1e797cf596df50a6bdd8cbf8e9b2467a3a934171)
+
+Related: #1642728
+---
+ test/udev-test.pl | 15 +++++++++++++++
+ 1 file changed, 15 insertions(+)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 957cda541c..3a50694fa9 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -39,6 +39,11 @@ for (my $i = 1; $i <= 10000; ++$i) {
+         $rules_10k_tags .= 'KERNEL=="sda", TAG+="test' . $i . "\"\n";
+ }
+ 
++my $rules_10k_tags_continuation = "";
++for (my $i = 1; $i <= 10000; ++$i) {
++        $rules_10k_tags_continuation .= 'KERNEL=="sda", TAG+="test' . $i . "\"\\\n";
++}
++
+ my @tests = (
+         {
+                 desc            => "no rules",
+@@ -1444,6 +1449,16 @@ EOF
+                 exp_name        => "found",
+                 rules           => $rules_10k_tags . <<EOF
+ TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found"
++EOF
++        },
++        {
++                desc            => "don't crash with lots of tags with continuation",
++                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                exp_name        => "found",
++                not_exp_name    => "bad" ,
++                rules           => $rules_10k_tags_continuation . <<EOF
++TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="bad"
++KERNEL=="sda", SYMLINK+="found"
+ EOF
+         },
+ );
diff --git a/SOURCES/0517-test-udev-use-proper-semantics-for-too-long-line-wit.patch b/SOURCES/0517-test-udev-use-proper-semantics-for-too-long-line-wit.patch
new file mode 100644
index 0000000..493d6b9
--- /dev/null
+++ b/SOURCES/0517-test-udev-use-proper-semantics-for-too-long-line-wit.patch
@@ -0,0 +1,34 @@
+From 4fb6b699b3d69341093830e92838336c0dbd7ea9 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Tue, 19 Feb 2019 09:21:42 +0900
+Subject: [PATCH] test-udev: use proper semantics for too long line with
+ continuation
+
+Follow-up for 1e797cf596df50a6bdd8cbf8e9b2467a3a934171.
+
+(cherry picked from commit e37a5d90b0c624b95f8d0c3400288fec60417ec4)
+
+Related: #1642728
+---
+ test/udev-test.pl | 7 ++++---
+ 1 file changed, 4 insertions(+), 3 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 3a50694fa9..58b5dc85e1 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -39,10 +39,11 @@ for (my $i = 1; $i <= 10000; ++$i) {
+         $rules_10k_tags .= 'KERNEL=="sda", TAG+="test' . $i . "\"\n";
+ }
+ 
+-my $rules_10k_tags_continuation = "";
+-for (my $i = 1; $i <= 10000; ++$i) {
+-        $rules_10k_tags_continuation .= 'KERNEL=="sda", TAG+="test' . $i . "\"\\\n";
++my $rules_10k_tags_continuation = "KERNEL==\"sda\", \\\n";
++for (my $i = 1; $i < 10000; ++$i) {
++        $rules_10k_tags_continuation .= 'TAG+="test' . $i . "\",\\\n";
+ }
++$rules_10k_tags_continuation .= "TAG+=\"test10000\"\\n";
+ 
+ my @tests = (
+         {
diff --git a/SOURCES/0518-test-udev-add-more-tests-for-line-continuations-and-.patch b/SOURCES/0518-test-udev-add-more-tests-for-line-continuations-and-.patch
new file mode 100644
index 0000000..9689d81
--- /dev/null
+++ b/SOURCES/0518-test-udev-add-more-tests-for-line-continuations-and-.patch
@@ -0,0 +1,40 @@
+From 66c41fbbeb472563993724352b1984aa3e7e47db Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Tue, 19 Feb 2019 09:22:45 +0900
+Subject: [PATCH] test-udev: add more tests for line continuations and comments
+
+(cherry picked from commit d35976c670b0e5c2d4081b781e5af88c0689ff00)
+
+Related: #1642728
+---
+ test/udev-test.pl | 12 ++++++++++--
+ 1 file changed, 10 insertions(+), 2 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 58b5dc85e1..a5e1f8cda3 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1453,13 +1453,21 @@ TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test1
+ EOF
+         },
+         {
+-                desc            => "don't crash with lots of tags with continuation",
++                desc            => "continuations",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                 exp_name        => "found",
+                 not_exp_name    => "bad" ,
+                 rules           => $rules_10k_tags_continuation . <<EOF
+ TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="bad"
+-KERNEL=="sda", SYMLINK+="found"
++KERNEL=="sda",\\
++# comment in continuation
++TAG+="hoge1",\\
++  # space before comment
++TAG+="hoge2",\\
++# spaces before and after token are dropped
++  TAG+="hoge3",   \\
++TAG+="hoge4"
++TAGS=="hoge1", TAGS=="hoge2", TAGS=="hoge3", TAGS=="hoge4", SYMLINK+="found"
+ EOF
+         },
+ );
diff --git a/SOURCES/0519-test-udev-add-more-tests-for-line-continuation.patch b/SOURCES/0519-test-udev-add-more-tests-for-line-continuation.patch
new file mode 100644
index 0000000..82482c3
--- /dev/null
+++ b/SOURCES/0519-test-udev-add-more-tests-for-line-continuation.patch
@@ -0,0 +1,59 @@
+From ac0def8fb2b51a17b7ef256c5c0edf786fffff2a Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Thu, 21 Feb 2019 18:03:32 +0900
+Subject: [PATCH] test-udev: add more tests for line continuation
+
+(cherry picked from commit 84a0819c9d89a2ddb195a5d975ae1fd5c62fde3c)
+
+Related: #1642728
+---
+ test/udev-test.pl | 34 ++++++++++++++++++++++++++++++++++
+ 1 file changed, 34 insertions(+)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index a5e1f8cda3..002fabd9fd 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1466,8 +1466,42 @@ TAG+="hoge1",\\
+ TAG+="hoge2",\\
+ # spaces before and after token are dropped
+   TAG+="hoge3",   \\
++\\
++ \\
+ TAG+="hoge4"
+ TAGS=="hoge1", TAGS=="hoge2", TAGS=="hoge3", TAGS=="hoge4", SYMLINK+="found"
++EOF
++        },
++        {
++                desc            => "continuations with empty line",
++                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                exp_name        => "found",
++                not_exp_name    => "bad",
++                rules           => <<EOF
++# empty line finishes continuation
++KERNEL=="sda", TAG+="foo" \\
++
++KERNEL=="sdb", TAG+="hoge"
++KERNEL=="sda", TAG+="aaa" \\
++KERNEL=="sdb", TAG+="bbb"
++TAGS=="foo", SYMLINK+="found"
++TAGS=="aaa", SYMLINK+="bad"
++EOF
++        },
++        {
++                desc            => "continuations with white only line",
++                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                exp_name        => "found",
++                not_exp_name    => "bad",
++                rules           => <<EOF
++# space only line finishes continuation
++KERNEL=="sda", TAG+="foo" \\
++   \t
++KERNEL=="sdb", TAG+="hoge"
++KERNEL=="sda", TAG+="aaa" \\
++KERNEL=="sdb", TAG+="bbb"
++TAGS=="foo", SYMLINK+="found"
++TAGS=="aaa", SYMLINK+="bad"
+ EOF
+         },
+ );
diff --git a/SOURCES/0520-test-udev-fix-alignment-and-drop-unnecessary-white-s.patch b/SOURCES/0520-test-udev-fix-alignment-and-drop-unnecessary-white-s.patch
new file mode 100644
index 0000000..e17bb97
--- /dev/null
+++ b/SOURCES/0520-test-udev-fix-alignment-and-drop-unnecessary-white-s.patch
@@ -0,0 +1,501 @@
+From 7898cd7e75f40627651cec134e3ac3a80176759a Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Thu, 21 Feb 2019 18:04:12 +0900
+Subject: [PATCH] test-udev: fix alignment and drop unnecessary white spaces
+
+(cherry picked from commit 3dd2d524141d09d57443ae339e1a77d7ce40f847)
+
+Related: #1642728
+---
+ test/udev-test.pl | 114 +++++++++++++++++++++++-----------------------
+ 1 file changed, 57 insertions(+), 57 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 002fabd9fd..122359e377 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -49,7 +49,7 @@ my @tests = (
+         {
+                 desc            => "no rules",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "sda" ,
++                exp_name        => "sda",
+                 exp_rem_error   => "yes",
+                 rules           => <<EOF
+ #
+@@ -58,7 +58,7 @@ EOF
+         {
+                 desc            => "label test of scsi disc",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "boot_disk" ,
++                exp_name        => "boot_disk",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -67,7 +67,7 @@ EOF
+         {
+                 desc            => "label test of scsi disc",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "boot_disk" ,
++                exp_name        => "boot_disk",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -76,7 +76,7 @@ EOF
+         {
+                 desc            => "label test of scsi disc",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "boot_disk" ,
++                exp_name        => "boot_disk",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -85,7 +85,7 @@ EOF
+         {
+                 desc            => "label test of scsi partition",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "boot_disk1" ,
++                exp_name        => "boot_disk1",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+ EOF
+@@ -93,7 +93,7 @@ EOF
+         {
+                 desc            => "label test of pattern match",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "boot_disk1" ,
++                exp_name        => "boot_disk1",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="?ATA", SYMLINK+="boot_disk%n-1"
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA?", SYMLINK+="boot_disk%n-2"
+@@ -104,7 +104,7 @@ EOF
+         {
+                 desc            => "label test of multiple sysfs files",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "boot_disk1" ,
++                exp_name        => "boot_disk1",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS X ", SYMLINK+="boot_diskX%n"
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="boot_disk%n"
+@@ -113,7 +113,7 @@ EOF
+         {
+                 desc            => "label test of max sysfs files (skip invalid rule)",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "boot_disk1" ,
++                exp_name        => "boot_disk1",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="32", SYMLINK+="boot_diskXX%n"
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n"
+@@ -122,7 +122,7 @@ EOF
+         {
+                 desc            => "catch device by *",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem/0" ,
++                exp_name        => "modem/0",
+                 rules           => <<EOF
+ KERNEL=="ttyACM*", SYMLINK+="modem/%n"
+ EOF
+@@ -130,7 +130,7 @@ EOF
+         {
+                 desc            => "catch device by * - take 2",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem/0" ,
++                exp_name        => "modem/0",
+                 rules           => <<EOF
+ KERNEL=="*ACM1", SYMLINK+="bad"
+ KERNEL=="*ACM0", SYMLINK+="modem/%n"
+@@ -139,7 +139,7 @@ EOF
+         {
+                 desc            => "catch device by ?",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem/0" ,
++                exp_name        => "modem/0",
+                 rules           => <<EOF
+ KERNEL=="ttyACM??*", SYMLINK+="modem/%n-1"
+ KERNEL=="ttyACM??", SYMLINK+="modem/%n-2"
+@@ -149,7 +149,7 @@ EOF
+         {
+                 desc            => "catch device by character class",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem/0" ,
++                exp_name        => "modem/0",
+                 rules           => <<EOF
+ KERNEL=="ttyACM[A-Z]*", SYMLINK+="modem/%n-1"
+ KERNEL=="ttyACM?[0-9]", SYMLINK+="modem/%n-2"
+@@ -159,7 +159,7 @@ EOF
+         {
+                 desc            => "replace kernel name",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem" ,
++                exp_name        => "modem",
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+ EOF
+@@ -167,7 +167,7 @@ EOF
+         {
+                 desc            => "Handle comment lines in config file (and replace kernel name)",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem" ,
++                exp_name        => "modem",
+                 rules           => <<EOF
+ # this is a comment
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -177,7 +177,7 @@ EOF
+         {
+                 desc            => "Handle comment lines in config file with whitespace (and replace kernel name)",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem" ,
++                exp_name        => "modem",
+                 rules           => <<EOF
+  # this is a comment with whitespace before the comment
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -187,7 +187,7 @@ EOF
+         {
+                 desc            => "Handle whitespace only lines (and replace kernel name)",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "whitespace" ,
++                exp_name        => "whitespace",
+                 rules           => <<EOF
+ 
+ 
+@@ -202,7 +202,7 @@ EOF
+         {
+                 desc            => "Handle empty lines in config file (and replace kernel name)",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem" ,
++                exp_name        => "modem",
+                 rules           => <<EOF
+ 
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -212,7 +212,7 @@ EOF
+         {
+                 desc            => "Handle backslashed multi lines in config file (and replace kernel name)",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem" ,
++                exp_name        => "modem",
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", \\
+ SYMLINK+="modem"
+@@ -230,7 +230,7 @@ EOF
+         {
+                 desc            => "Handle stupid backslashed multi lines in config file (and replace kernel name)",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem" ,
++                exp_name        => "modem",
+                 rules           => <<EOF
+ 
+ #
+@@ -248,7 +248,7 @@ EOF
+         {
+                 desc            => "subdirectory handling",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "sub/direct/ory/modem" ,
++                exp_name        => "sub/direct/ory/modem",
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK+="sub/direct/ory/modem"
+ EOF
+@@ -256,7 +256,7 @@ EOF
+         {
+                 desc            => "parent device name match of scsi partition",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "first_disk5" ,
++                exp_name        => "first_disk5",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="first_disk%n"
+ EOF
+@@ -264,7 +264,7 @@ EOF
+         {
+                 desc            => "test substitution chars",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "Major:8:minor:5:kernelnumber:5:id:0:0:0:0" ,
++                exp_name        => "Major:8:minor:5:kernelnumber:5:id:0:0:0:0",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:%M:minor:%m:kernelnumber:%n:id:%b"
+ EOF
+@@ -281,7 +281,7 @@ EOF
+         {
+                 desc            => "sustitution of sysfs value (%s{file})",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "disk-ATA-sda" ,
++                exp_name        => "disk-ATA-sda",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="disk-%s{vendor}-%k"
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -290,8 +290,8 @@ EOF
+         {
+                 desc            => "program result substitution",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "special-device-5" ,
+-                not_exp_name    => "not" ,
++                exp_name        => "special-device-5",
++                not_exp_name    => "not",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not"
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%c-%n"
+@@ -300,7 +300,7 @@ EOF
+         {
+                 desc            => "program result substitution (newline removal)",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "newline_removed" ,
++                exp_name        => "newline_removed",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", SYMLINK+="newline_removed"
+ EOF
+@@ -308,7 +308,7 @@ EOF
+         {
+                 desc            => "program result substitution",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "test-0:0:0:0" ,
++                exp_name        => "test-0:0:0:0",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", SYMLINK+="%c"
+ EOF
+@@ -316,7 +316,7 @@ EOF
+         {
+                 desc            => "program with lots of arguments",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "foo9" ,
++                exp_name        => "foo9",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="%c{7}"
+ EOF
+@@ -324,7 +324,7 @@ EOF
+         {
+                 desc            => "program with subshell",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "bar9" ,
++                exp_name        => "bar9",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed  s/foo9/bar9/'", KERNEL=="sda5", SYMLINK+="%c{7}"
+ EOF
+@@ -332,7 +332,7 @@ EOF
+         {
+                 desc            => "program arguments combined with apostrophes",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "foo7" ,
++                exp_name        => "foo7",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4'   'foo5   foo6   foo7 foo8'", KERNEL=="sda5", SYMLINK+="%c{5}"
+ EOF
+@@ -340,7 +340,7 @@ EOF
+         {
+                 desc            => "program arguments combined with escaped double quotes, part 1",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "foo2" ,
++                exp_name        => "foo2",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf %%s \\\"foo1 foo2\\\" | grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
+ EOF
+@@ -348,7 +348,7 @@ EOF
+         {
+                 desc            => "program arguments combined with escaped double quotes, part 2",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "foo2" ,
++                exp_name        => "foo2",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \\\"printf %%s 'foo1 foo2' | grep 'foo1 foo2'\\\"", KERNEL=="sda5", SYMLINK+="%c{2}"
+ EOF
+@@ -356,7 +356,7 @@ EOF
+         {
+                 desc            => "program arguments combined with escaped double quotes, part 3",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "foo2" ,
++                exp_name        => "foo2",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf \\\"%%s %%s\\\" \\\"foo1 foo2\\\" \\\"foo3\\\"| grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
+ EOF
+@@ -364,7 +364,7 @@ EOF
+         {
+                 desc            => "characters before the %c{N} substitution",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "my-foo9" ,
++                exp_name        => "my-foo9",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{7}"
+ EOF
+@@ -372,7 +372,7 @@ EOF
+         {
+                 desc            => "substitute the second to last argument",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "my-foo8" ,
++                exp_name        => "my-foo8",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{6}"
+ EOF
+@@ -396,7 +396,7 @@ EOF
+         {
+                 desc            => "test substitution by variable name 3",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "850:0:0:05" ,
++                exp_name        => "850:0:0:05",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="%M%m%b%n"
+ EOF
+@@ -404,7 +404,7 @@ EOF
+         {
+                 desc            => "test substitution by variable name 4",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "855" ,
++                exp_name        => "855",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major\$minor\$number"
+ EOF
+@@ -412,7 +412,7 @@ EOF
+         {
+                 desc            => "test substitution by variable name 5",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "8550:0:0:0" ,
++                exp_name        => "8550:0:0:0",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major%m%n\$id"
+ EOF
+@@ -429,7 +429,7 @@ EOF
+         {
+                 desc            => "non matching SUBSYSTEMS",
+                 devpath         => "/devices/virtual/tty/console",
+-                exp_name        => "TTY" ,
++                exp_name        => "TTY",
+                 rules                => <<EOF
+ SUBSYSTEMS=="foo", ATTRS{dev}=="5:1", SYMLINK+="foo"
+ KERNEL=="console", SYMLINK+="TTY"
+@@ -438,7 +438,7 @@ EOF
+         {
+                 desc            => "ATTRS match",
+                 devpath         => "/devices/virtual/tty/console",
+-                exp_name        => "foo" ,
++                exp_name        => "foo",
+                 rules           => <<EOF
+ KERNEL=="console", SYMLINK+="TTY"
+ ATTRS{dev}=="5:1", SYMLINK+="foo"
+@@ -447,7 +447,7 @@ EOF
+         {
+                 desc            => "ATTR (empty file)",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "empty" ,
++                exp_name        => "empty",
+                 rules           => <<EOF
+ KERNEL=="sda", ATTR{test_empty_file}=="?*", SYMLINK+="something"
+ KERNEL=="sda", ATTR{test_empty_file}!="", SYMLINK+="not-empty"
+@@ -458,7 +458,7 @@ EOF
+         {
+                 desc            => "ATTR (non-existent file)",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "non-existent" ,
++                exp_name        => "non-existent",
+                 rules           => <<EOF
+ KERNEL=="sda", ATTR{nofile}=="?*", SYMLINK+="something"
+ KERNEL=="sda", ATTR{nofile}!="", SYMLINK+="not-empty"
+@@ -471,7 +471,7 @@ EOF
+         {
+                 desc            => "program and bus type match",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "scsi-0:0:0:0" ,
++                exp_name        => "scsi-0:0:0:0",
+                 rules           => <<EOF
+ SUBSYSTEMS=="usb", PROGRAM=="/bin/echo -n usb-%b", SYMLINK+="%c"
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", SYMLINK+="%c"
+@@ -481,7 +481,7 @@ EOF
+         {
+                 desc            => "sysfs parent hierarchy",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem" ,
++                exp_name        => "modem",
+                 rules           => <<EOF
+ ATTRS{idProduct}=="007b", SYMLINK+="modem"
+ EOF
+@@ -489,7 +489,7 @@ EOF
+         {
+                 desc            => "name test with ! in the name",
+                 devpath         => "/devices/virtual/block/fake!blockdev0",
+-                exp_name        => "is/a/fake/blockdev0" ,
++                exp_name        => "is/a/fake/blockdev0",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", SYMLINK+="is/not/a/%k"
+ SUBSYSTEM=="block", SYMLINK+="is/a/%k"
+@@ -499,7 +499,7 @@ EOF
+         {
+                 desc            => "name test with ! in the name, but no matching rule",
+                 devpath         => "/devices/virtual/block/fake!blockdev0",
+-                exp_name        => "fake/blockdev0" ,
++                exp_name        => "fake/blockdev0",
+                 exp_rem_error   => "yes",
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -542,7 +542,7 @@ EOF
+                 desc            => "KERNELS wildcard partial 2",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                 exp_name        => "scsi-0:0:0:0",
+-                rules                => <<EOF
++                rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
+ SUBSYSTEMS=="scsi", KERNELS=="*:0:0:0", SYMLINK+="scsi-0:0:0:0"
+ EOF
+@@ -739,7 +739,7 @@ EOF
+                 devpath         => "/devices/virtual/misc/misc-fake1",
+                 exp_name        => "node",
+                 exp_majorminor  => "4095:1",
+-                rules                => <<EOF
++                rules           => <<EOF
+ KERNEL=="misc-fake1", SYMLINK+="node"
+ EOF
+         },
+@@ -764,7 +764,7 @@ EOF
+                 desc            => "multiple symlinks with a lot of s p a c e s",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+                 exp_name        => "one",
+-                not_exp_name        => " ",
++                not_exp_name    => " ",
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK="  one     two        "
+ EOF
+@@ -860,7 +860,7 @@ EOF
+         {
+                 desc            => "multiple symlinks",
+                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "second-0" ,
++                exp_name        => "second-0",
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK="first-%n second-%n third-%n"
+ EOF
+@@ -869,8 +869,8 @@ EOF
+                 desc            => "symlink name '.'",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                 exp_name        => ".",
+-                exp_add_error        => "yes",
+-                exp_rem_error        => "yes",
++                exp_add_error   => "yes",
++                exp_rem_error   => "yes",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="."
+ EOF
+@@ -879,9 +879,9 @@ EOF
+                 desc            => "symlink node to itself",
+                 devpath         => "/devices/virtual/tty/tty0",
+                 exp_name        => "link",
+-                exp_add_error        => "yes",
+-                exp_rem_error        => "yes",
+-                option                => "clean",
++                exp_add_error   => "yes",
++                exp_rem_error   => "yes",
++                option          => "clean",
+                 rules           => <<EOF
+ KERNEL=="tty0", SYMLINK+="tty0"
+ EOF
+@@ -1437,7 +1437,7 @@ EOF
+                 desc            => "add and match tag",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                 exp_name        => "found",
+-                not_exp_name    => "bad" ,
++                not_exp_name    => "bad",
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", TAG+="green"
+ TAGS=="green", SYMLINK+="found"
+@@ -1456,7 +1456,7 @@ EOF
+                 desc            => "continuations",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                 exp_name        => "found",
+-                not_exp_name    => "bad" ,
++                not_exp_name    => "bad",
+                 rules           => $rules_10k_tags_continuation . <<EOF
+ TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="bad"
+ KERNEL=="sda",\\
diff --git a/SOURCES/0521-test-udev-test.pl-cleanup-if-skipping-test.patch b/SOURCES/0521-test-udev-test.pl-cleanup-if-skipping-test.patch
new file mode 100644
index 0000000..1500d54
--- /dev/null
+++ b/SOURCES/0521-test-udev-test.pl-cleanup-if-skipping-test.patch
@@ -0,0 +1,73 @@
+From dc50d1cc5bf445f1a26dbc646ff52421563e677f Mon Sep 17 00:00:00 2001
+From: Dan Streetman <ddstreet@canonical.com>
+Date: Fri, 5 Jul 2019 11:24:55 -0400
+Subject: [PATCH] test/udev-test.pl: cleanup if skipping test
+
+In Ubuntu CI, udev-test.pl is run from the debian/test/udev script,
+in a test dir created for it; but udev-test.pl setup mounts a
+dir, so if it doesn't cleanup/unmount before exiting, the test dir
+autopkgtest created for it can't be removed, and autopkgtest
+aborts the entire test suite, for example this output (from a
+test run inside an armhf container):
+
+autopkgtest [12:45:36]: test udev: [-----------------------
+umount: test/tmpfs: no mount point specified.
+mknod: test/tmpfs/dev/null: Operation not permitted
+unable to create test/tmpfs/dev/null at ./udev-test.pl line 1611.
+Failed to set up the environment, skipping the test at ./udev-test.pl line 1731.
+autopkgtest [12:45:41]: test udev: -----------------------]
+autopkgtest [12:45:44]: test udev:  - - - - - - - - - - results - - - - - - - - - -
+udev                 FAIL non-zero exit status 77
+rm: cannot remove '/tmp/autopkgtest.ocPFA6/autopkgtest_tmp/test/tmpfs': Device or resource busy
+autopkgtest [12:46:22]: ERROR: "rm -rf /tmp/autopkgtest.ocPFA6/udev-artifacts /tmp/autopkgtest.ocPFA6/autopkgtest_tmp" failed with stderr "rm:
+
+(cherry picked from commit abb9cc50afb3949c442849f43301fb33578f3888)
+
+Related: #1642728
+---
+ test/udev-test.pl | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 122359e377..2fea72875b 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1713,6 +1713,12 @@ sub run_test {
+ 
+ }
+ 
++sub cleanup {
++        system("rm", "-rf", "$udev_run");
++        system("umount", "$udev_tmpfs");
++        rmdir($udev_tmpfs);
++}
++
+ # only run if we have root permissions
+ # due to mknod restrictions
+ if (!($<==0)) {
+@@ -1729,11 +1735,13 @@ if ($? >> 8 == 0) {
+ 
+ if (!udev_setup()) {
+         warn "Failed to set up the environment, skipping the test";
++        cleanup();
+         exit($EXIT_TEST_SKIP);
+ }
+ 
+ if (system($udev_bin, "check")) {
+         warn "$udev_bin failed to set up the environment, skipping the test";
++        cleanup();
+         exit($EXIT_TEST_SKIP);
+ }
+ 
+@@ -1776,10 +1784,7 @@ if ($list[0]) {
+ 
+ print "$error errors occurred\n\n";
+ 
+-# cleanup
+-system("rm", "-rf", "$udev_run");
+-system("umount", "$udev_tmpfs");
+-rmdir($udev_tmpfs);
++cleanup();
+ 
+ if ($error > 0) {
+         exit(1);
diff --git a/SOURCES/0522-test-add-test-cases-for-empty-string-match.patch b/SOURCES/0522-test-add-test-cases-for-empty-string-match.patch
new file mode 100644
index 0000000..acf7479
--- /dev/null
+++ b/SOURCES/0522-test-add-test-cases-for-empty-string-match.patch
@@ -0,0 +1,89 @@
+From 03bc565e6e3249385c4e1ca0ae27670ca2ad9a41 Mon Sep 17 00:00:00 2001
+From: Yu Watanabe <watanabe.yu+github@gmail.com>
+Date: Wed, 11 Sep 2019 09:06:15 +0900
+Subject: [PATCH] test: add test cases for empty string match
+
+(cherry picked from commit 48d26c90852c22ec94be961f5fbdcf462bb9a6e8)
+
+Related: #1642728
+---
+ test/udev-test.pl | 66 +++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 66 insertions(+)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 2fea72875b..50d978391b 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1256,6 +1256,72 @@ KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
+ KERNEL=="X|attyACM0|dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong2"
+ KERNEL=="all|dontknow|ttyACM0", SYMLINK+="right"
+ KERNEL=="ttyACM0a|nothing", SYMLINK+="wrong3"
++EOF
++        },
++        {
++                desc            => "test multi matches 5",
++                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                exp_name        => "found",
++                not_exp_name    => "bad",
++                rules           => <<EOF
++KERNEL=="sda", TAG="foo"
++TAGS=="|foo", SYMLINK+="found"
++TAGS=="|aaa", SYMLINK+="bad"
++EOF
++        },
++        {
++                desc            => "test multi matches 6",
++                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                exp_name        => "found",
++                not_exp_name    => "bad",
++                rules           => <<EOF
++KERNEL=="sda", TAG=""
++TAGS=="|foo", SYMLINK+="found"
++TAGS=="aaa|bbb", SYMLINK+="bad"
++EOF
++        },
++        {
++                desc            => "test multi matches 7",
++                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                exp_name        => "found",
++                not_exp_name    => "bad",
++                rules           => <<EOF
++KERNEL=="sda", TAG="foo"
++TAGS=="foo||bar", SYMLINK+="found"
++TAGS=="aaa||bbb", SYMLINK+="bad"
++EOF
++        },
++        {
++                desc            => "test multi matches 8",
++                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                exp_name        => "found",
++                not_exp_name    => "bad",
++                rules           => <<EOF
++KERNEL=="sda", TAG=""
++TAGS=="foo||bar", SYMLINK+="found"
++TAGS=="aaa|bbb", SYMLINK+="bad"
++EOF
++        },
++        {
++                desc            => "test multi matches 9",
++                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                exp_name        => "found",
++                not_exp_name    => "bad",
++                rules           => <<EOF
++KERNEL=="sda", TAG="foo"
++TAGS=="foo|", SYMLINK+="found"
++TAGS=="aaa|", SYMLINK+="bad"
++EOF
++        },
++        {
++                desc            => "test multi matches 10",
++                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                exp_name        => "found",
++                not_exp_name    => "bad",
++                rules           => <<EOF
++KERNEL=="sda", TAG=""
++TAGS=="foo|", SYMLINK+="found"
++TAGS=="aaa|bbb", SYMLINK+="bad"
+ EOF
+         },
+         {
diff --git a/SOURCES/0523-test-add-test-case-for-multi-matches-when-use.patch b/SOURCES/0523-test-add-test-case-for-multi-matches-when-use.patch
new file mode 100644
index 0000000..d7d60b3
--- /dev/null
+++ b/SOURCES/0523-test-add-test-case-for-multi-matches-when-use.patch
@@ -0,0 +1,35 @@
+From 03b766cc937ffa4dcb7cfb25b2ac20d8a00cb6db Mon Sep 17 00:00:00 2001
+From: gaoyi <ymuemc@163.com>
+Date: Sun, 12 Jul 2020 03:27:45 -0400
+Subject: [PATCH] test: add test case for multi matches when use "||"
+
+Signed-off-by: gaoyi <ymuemc@163.com>
+(cherry picked from commit 0d3a8bc7ebd76591e14f7098b4266fd2065ac4db)
+
+Related: #1642728
+---
+ test/udev-test.pl | 11 +++++++++++
+ 1 file changed, 11 insertions(+)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 50d978391b..4bf97d82bb 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1322,6 +1322,17 @@ EOF
+ KERNEL=="sda", TAG=""
+ TAGS=="foo|", SYMLINK+="found"
+ TAGS=="aaa|bbb", SYMLINK+="bad"
++EOF
++        },
++        {
++                desc            => "test multi matches 11",
++                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                exp_name        => "found",
++                not_exp_name    => "bad",
++                rules           => <<EOF
++KERNEL=="sda", TAG="c"
++TAGS=="foo||bar||c", SYMLINK+="found"
++TAGS=="aaa||bbb||ccc", SYMLINK+="bad"
+ EOF
+         },
+         {
diff --git a/SOURCES/0524-udev-test-do-not-rely-on-mail-group-being-defined.patch b/SOURCES/0524-udev-test-do-not-rely-on-mail-group-being-defined.patch
new file mode 100644
index 0000000..a048469
--- /dev/null
+++ b/SOURCES/0524-udev-test-do-not-rely-on-mail-group-being-defined.patch
@@ -0,0 +1,33 @@
+From c68da72231d5c502acd4e79791d0810790f3231b Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Fri, 4 Sep 2020 18:09:20 +0200
+Subject: [PATCH] udev-test: do not rely on "mail" group being defined
+
+"audio" should be there, at least we declare it. "mail" nowadays is less
+likely to exist than in the past.
+
+Fixes one of the items in #16942.
+
+(cherry picked from commit a9030b81c154c3ec92227d04cad6b13cc1125608)
+
+Related: #1642728
+---
+ test/udev-test.pl | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 4bf97d82bb..a4deffacb9 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -629,9 +629,9 @@ EOF
+                 desc            => "textual user/group id",
+                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                 exp_name        => "node",
+-                exp_perms       => "root:mail:0660",
++                exp_perms       => "root:audio:0660",
+                 rules           => <<EOF
+-SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="root", GROUP="mail"
++SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="root", GROUP="audio"
+ EOF
+         },
+         {
diff --git a/SOURCES/0525-test-udev-test.pl-allow-multiple-devices-per-test.patch b/SOURCES/0525-test-udev-test.pl-allow-multiple-devices-per-test.patch
new file mode 100644
index 0000000..25887e2
--- /dev/null
+++ b/SOURCES/0525-test-udev-test.pl-allow-multiple-devices-per-test.patch
@@ -0,0 +1,2452 @@
+From 3f90eeef6a8469de6ad490efb62a5be80188f41f Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Fri, 20 Apr 2018 22:38:30 +0200
+Subject: [PATCH] test/udev-test.pl: allow multiple devices per test
+
+Allow testing cases where multiple devices are added and removed.
+This implies a change of the data structure: every test allows
+for multiple devices to be added, and "exp_name" etc. are now properties
+of the device, not of the test.
+
+(cherry picked from commit 255c05b72455dcad1b5552d12a813b31f68201a7)
+
+Related: #1642728
+---
+ test/udev-test.pl | 1352 +++++++++++++++++++++++++++++++--------------
+ 1 file changed, 929 insertions(+), 423 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index a4deffacb9..bd5401da75 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -48,17 +48,28 @@ $rules_10k_tags_continuation .= "TAG+=\"test10000\"\\n";
+ my @tests = (
+         {
+                 desc            => "no rules",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "sda",
+-                exp_rem_error   => "yes",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "sda" ,
++                                exp_rem_error   => "yes",
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "sda1" ,
++                                exp_rem_error   => "yes",
++                        }],
+                 rules           => <<EOF
+ #
+ EOF
+         },
+         {
+                 desc            => "label test of scsi disc",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "boot_disk",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "boot_disk" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -66,8 +77,11 @@ EOF
+         },
+         {
+                 desc            => "label test of scsi disc",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "boot_disk",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "boot_disk" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -75,8 +89,11 @@ EOF
+         },
+         {
+                 desc            => "label test of scsi disc",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "boot_disk",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "boot_disk" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -84,16 +101,22 @@ EOF
+         },
+         {
+                 desc            => "label test of scsi partition",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "boot_disk1",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "boot_disk1" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+ EOF
+         },
+         {
+                 desc            => "label test of pattern match",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "boot_disk1",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "boot_disk1" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="?ATA", SYMLINK+="boot_disk%n-1"
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA?", SYMLINK+="boot_disk%n-2"
+@@ -103,8 +126,11 @@ EOF
+         },
+         {
+                 desc            => "label test of multiple sysfs files",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "boot_disk1",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "boot_disk1" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS X ", SYMLINK+="boot_diskX%n"
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="boot_disk%n"
+@@ -112,8 +138,11 @@ EOF
+         },
+         {
+                 desc            => "label test of max sysfs files (skip invalid rule)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "boot_disk1",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "boot_disk1" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="32", SYMLINK+="boot_diskXX%n"
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n"
+@@ -121,16 +150,22 @@ EOF
+         },
+         {
+                 desc            => "catch device by *",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem/0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem/0" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM*", SYMLINK+="modem/%n"
+ EOF
+         },
+         {
+                 desc            => "catch device by * - take 2",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem/0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem/0" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="*ACM1", SYMLINK+="bad"
+ KERNEL=="*ACM0", SYMLINK+="modem/%n"
+@@ -138,8 +173,11 @@ EOF
+         },
+         {
+                 desc            => "catch device by ?",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem/0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem/0" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM??*", SYMLINK+="modem/%n-1"
+ KERNEL=="ttyACM??", SYMLINK+="modem/%n-2"
+@@ -148,8 +186,11 @@ EOF
+         },
+         {
+                 desc            => "catch device by character class",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem/0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem/0" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[A-Z]*", SYMLINK+="modem/%n-1"
+ KERNEL=="ttyACM?[0-9]", SYMLINK+="modem/%n-2"
+@@ -158,16 +199,22 @@ EOF
+         },
+         {
+                 desc            => "replace kernel name",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+ EOF
+         },
+         {
+                 desc            => "Handle comment lines in config file (and replace kernel name)",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem" ,
++                        }],
+                 rules           => <<EOF
+ # this is a comment
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -176,8 +223,11 @@ EOF
+         },
+         {
+                 desc            => "Handle comment lines in config file with whitespace (and replace kernel name)",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem" ,
++                        }],
+                 rules           => <<EOF
+  # this is a comment with whitespace before the comment
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -186,8 +236,11 @@ EOF
+         },
+         {
+                 desc            => "Handle whitespace only lines (and replace kernel name)",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "whitespace",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "whitespace" ,
++                        }],
+                 rules           => <<EOF
+ 
+ 
+@@ -201,8 +254,11 @@ EOF
+         },
+         {
+                 desc            => "Handle empty lines in config file (and replace kernel name)",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem" ,
++                        }],
+                 rules           => <<EOF
+ 
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -211,8 +267,11 @@ EOF
+         },
+         {
+                 desc            => "Handle backslashed multi lines in config file (and replace kernel name)",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", \\
+ SYMLINK+="modem"
+@@ -221,16 +280,22 @@ EOF
+         },
+         {
+                 desc            => "preserve backslashes, if they are not for a newline",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "aaa",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "aaa",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", PROGRAM=="/bin/echo -e \\101", RESULT=="A", SYMLINK+="aaa"
+ EOF
+         },
+         {
+                 desc            => "Handle stupid backslashed multi lines in config file (and replace kernel name)",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem" ,
++                        }],
+                 rules           => <<EOF
+ 
+ #
+@@ -247,41 +312,56 @@ EOF
+         },
+         {
+                 desc            => "subdirectory handling",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "sub/direct/ory/modem",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "sub/direct/ory/modem" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK+="sub/direct/ory/modem"
+ EOF
+         },
+         {
+                 desc            => "parent device name match of scsi partition",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "first_disk5",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "first_disk5" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="first_disk%n"
+ EOF
+         },
+         {
+                 desc            => "test substitution chars",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "Major:8:minor:5:kernelnumber:5:id:0:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "Major:8:minor:5:kernelnumber:5:id:0:0:0:0" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:%M:minor:%m:kernelnumber:%n:id:%b"
+ EOF
+         },
+         {
+                 desc            => "import of shell-value returned from program",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node12345678",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node12345678",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", IMPORT{program}="/bin/echo -e \' TEST_KEY=12345678\\n  TEST_key2=98765\'", SYMLINK+="node\$env{TEST_KEY}"
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+ EOF
+         },
+         {
+-                desc            => "sustitution of sysfs value (%s{file})",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "disk-ATA-sda",
++                desc            => "substitution of sysfs value (%s{file})",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "disk-ATA-sda" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="disk-%s{vendor}-%k"
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -289,9 +369,12 @@ EOF
+         },
+         {
+                 desc            => "program result substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "special-device-5",
+-                not_exp_name    => "not",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "special-device-5" ,
++                                not_exp_name    => "not" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not"
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="special-*", SYMLINK+="%c-%n"
+@@ -299,128 +382,176 @@ EOF
+         },
+         {
+                 desc            => "program result substitution (newline removal)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "newline_removed",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "newline_removed" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", SYMLINK+="newline_removed"
+ EOF
+         },
+         {
+                 desc            => "program result substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "test-0:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "test-0:0:0:0" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", SYMLINK+="%c"
+ EOF
+         },
+         {
+                 desc            => "program with lots of arguments",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "foo9",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "foo9" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="%c{7}"
+ EOF
+         },
+         {
+                 desc            => "program with subshell",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "bar9",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "bar9" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed  s/foo9/bar9/'", KERNEL=="sda5", SYMLINK+="%c{7}"
+ EOF
+         },
+         {
+                 desc            => "program arguments combined with apostrophes",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "foo7",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "foo7" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4'   'foo5   foo6   foo7 foo8'", KERNEL=="sda5", SYMLINK+="%c{5}"
+ EOF
+         },
+         {
+                 desc            => "program arguments combined with escaped double quotes, part 1",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "foo2",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "foo2" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf %%s \\\"foo1 foo2\\\" | grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
+ EOF
+         },
+         {
+                 desc            => "program arguments combined with escaped double quotes, part 2",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "foo2",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "foo2" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \\\"printf %%s 'foo1 foo2' | grep 'foo1 foo2'\\\"", KERNEL=="sda5", SYMLINK+="%c{2}"
+ EOF
+         },
+         {
+                 desc            => "program arguments combined with escaped double quotes, part 3",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "foo2",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "foo2" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf \\\"%%s %%s\\\" \\\"foo1 foo2\\\" \\\"foo3\\\"| grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
+ EOF
+         },
+         {
+                 desc            => "characters before the %c{N} substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "my-foo9",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "my-foo9" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{7}"
+ EOF
+         },
+         {
+                 desc            => "substitute the second to last argument",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "my-foo8",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "my-foo8" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{6}"
+ EOF
+         },
+         {
+                 desc            => "test substitution by variable name",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:\$major-minor:\$minor-kernelnumber:\$number-id:\$id"
+ EOF
+         },
+         {
+                 desc            => "test substitution by variable name 2",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="Major:\$major-minor:%m-kernelnumber:\$number-id:\$id"
+ EOF
+         },
+         {
+                 desc            => "test substitution by variable name 3",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "850:0:0:05",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "850:0:0:05" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="%M%m%b%n"
+ EOF
+         },
+         {
+                 desc            => "test substitution by variable name 4",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "855",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "855" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major\$minor\$number"
+ EOF
+         },
+         {
+                 desc            => "test substitution by variable name 5",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "8550:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "8550:0:0:0" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major%m%n\$id"
+ EOF
+         },
+         {
+                 desc            => "non matching SUBSYSTEMS for device with no parent",
+-                devpath         => "/devices/virtual/tty/console",
+-                exp_name        => "TTY",
++                devices => [
++                        {
++                                devpath         => "/devices/virtual/tty/console",
++                                exp_name        => "TTY",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo", RESULT=="foo", SYMLINK+="foo"
+ KERNEL=="console", SYMLINK+="TTY"
+@@ -428,8 +559,11 @@ EOF
+         },
+         {
+                 desc            => "non matching SUBSYSTEMS",
+-                devpath         => "/devices/virtual/tty/console",
+-                exp_name        => "TTY",
++                devices => [
++                        {
++                                devpath         => "/devices/virtual/tty/console",
++                                exp_name        => "TTY" ,
++                        }],
+                 rules                => <<EOF
+ SUBSYSTEMS=="foo", ATTRS{dev}=="5:1", SYMLINK+="foo"
+ KERNEL=="console", SYMLINK+="TTY"
+@@ -437,8 +571,11 @@ EOF
+         },
+         {
+                 desc            => "ATTRS match",
+-                devpath         => "/devices/virtual/tty/console",
+-                exp_name        => "foo",
++                devices => [
++                        {
++                                devpath         => "/devices/virtual/tty/console",
++                                exp_name        => "foo" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="console", SYMLINK+="TTY"
+ ATTRS{dev}=="5:1", SYMLINK+="foo"
+@@ -446,8 +583,11 @@ EOF
+         },
+         {
+                 desc            => "ATTR (empty file)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "empty",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "empty" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", ATTR{test_empty_file}=="?*", SYMLINK+="something"
+ KERNEL=="sda", ATTR{test_empty_file}!="", SYMLINK+="not-empty"
+@@ -457,8 +597,11 @@ EOF
+         },
+         {
+                 desc            => "ATTR (non-existent file)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "non-existent",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "non-existent" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", ATTR{nofile}=="?*", SYMLINK+="something"
+ KERNEL=="sda", ATTR{nofile}!="", SYMLINK+="not-empty"
+@@ -470,8 +613,11 @@ EOF
+         },
+         {
+                 desc            => "program and bus type match",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "scsi-0:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "scsi-0:0:0:0" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="usb", PROGRAM=="/bin/echo -n usb-%b", SYMLINK+="%c"
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n scsi-%b", SYMLINK+="%c"
+@@ -480,16 +626,22 @@ EOF
+         },
+         {
+                 desc            => "sysfs parent hierarchy",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem" ,
++                        }],
+                 rules           => <<EOF
+ ATTRS{idProduct}=="007b", SYMLINK+="modem"
+ EOF
+         },
+         {
+                 desc            => "name test with ! in the name",
+-                devpath         => "/devices/virtual/block/fake!blockdev0",
+-                exp_name        => "is/a/fake/blockdev0",
++                devices => [
++                        {
++                                devpath         => "/devices/virtual/block/fake!blockdev0",
++                                exp_name        => "is/a/fake/blockdev0" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", SYMLINK+="is/not/a/%k"
+ SUBSYSTEM=="block", SYMLINK+="is/a/%k"
+@@ -498,17 +650,23 @@ EOF
+         },
+         {
+                 desc            => "name test with ! in the name, but no matching rule",
+-                devpath         => "/devices/virtual/block/fake!blockdev0",
+-                exp_name        => "fake/blockdev0",
+-                exp_rem_error   => "yes",
++                devices => [
++                        {
++                                devpath         => "/devices/virtual/block/fake!blockdev0",
++                                exp_name        => "fake/blockdev0" ,
++                                exp_rem_error   => "yes",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+ EOF
+         },
+         {
+                 desc            => "KERNELS rule",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "scsi-0:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "scsi-0:0:0:0",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="usb", KERNELS=="0:0:0:0", SYMLINK+="not-scsi"
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:1", SYMLINK+="no-match"
+@@ -519,8 +677,11 @@ EOF
+         },
+         {
+                 desc            => "KERNELS wildcard all",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "scsi-0:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "scsi-0:0:0:0",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="*:1", SYMLINK+="no-match"
+ SUBSYSTEMS=="scsi", KERNELS=="*:0:1", SYMLINK+="no-match"
+@@ -531,8 +692,11 @@ EOF
+         },
+         {
+                 desc            => "KERNELS wildcard partial",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "scsi-0:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "scsi-0:0:0:0",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
+ SUBSYSTEMS=="scsi", KERNELS=="*:0", SYMLINK+="scsi-0:0:0:0"
+@@ -540,41 +704,56 @@ EOF
+         },
+         {
+                 desc            => "KERNELS wildcard partial 2",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "scsi-0:0:0:0",
+-                rules           => <<EOF
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "scsi-0:0:0:0",
++                        }],
++                rules                => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
+ SUBSYSTEMS=="scsi", KERNELS=="*:0:0:0", SYMLINK+="scsi-0:0:0:0"
+ EOF
+         },
+         {
+                 desc            => "substitute attr with link target value (first match)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "driver-is-sd",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "driver-is-sd",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", SYMLINK+="driver-is-\$attr{driver}"
+ EOF
+         },
+         {
+                 desc            => "substitute attr with link target value (currently selected device)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "driver-is-ahci",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "driver-is-ahci",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="pci", SYMLINK+="driver-is-\$attr{driver}"
+ EOF
+         },
+         {
+                 desc            => "ignore ATTRS attribute whitespace",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "ignored",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "ignored",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE  SPACE", SYMLINK+="ignored"
+ EOF
+         },
+         {
+                 desc            => "do not ignore ATTRS attribute whitespace",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "matched-with-space",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "matched-with-space",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE  SPACE ", SYMLINK+="wrong-to-ignore"
+ SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE  SPACE   ", SYMLINK+="matched-with-space"
+@@ -582,117 +761,156 @@ EOF
+         },
+         {
+                 desc            => "permissions USER=bad GROUP=name",
+-                devpath         => "/devices/virtual/tty/tty33",
+-                exp_name        => "tty33",
+-                exp_perms       => "0:0:0600",
++                devices => [
++                        {
++                                devpath         => "/devices/virtual/tty/tty33",
++                                exp_name        => "tty33",
++                                exp_perms       => "0:0:0600",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="tty33", OWNER="bad", GROUP="name"
+ EOF
+         },
+         {
+                 desc            => "permissions OWNER=1",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
+-                exp_perms       => "1::0600",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                                exp_perms       => "1::0600",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="1"
+ EOF
+         },
+         {
+                 desc            => "permissions GROUP=1",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
+-                exp_perms       => ":1:0660",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                                exp_perms       => ":1:0660",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="1"
+ EOF
+         },
+         {
+                 desc            => "textual user id",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
+-                exp_perms       => "daemon::0600",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                                exp_perms       => "daemon::0600",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="daemon"
+ EOF
+         },
+         {
+                 desc            => "textual group id",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
+-                exp_perms       => ":daemon:0660",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                                exp_perms       => ":daemon:0660",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", GROUP="daemon"
+ EOF
+         },
+         {
+                 desc            => "textual user/group id",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
+-                exp_perms       => "root:audio:0660",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                                exp_perms       => "root:audio:0660",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="root", GROUP="audio"
+ EOF
+         },
+         {
+                 desc            => "permissions MODE=0777",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
+-                exp_perms       => "::0777",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                                exp_perms       => "::0777",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", MODE="0777"
+ EOF
+         },
+         {
+                 desc            => "permissions OWNER=1 GROUP=1 MODE=0777",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
+-                exp_perms       => "1:1:0777",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                                exp_perms       => "1:1:0777",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", OWNER="1", GROUP="1", MODE="0777"
+ EOF
+         },
+         {
+                 desc            => "permissions OWNER to 1",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "ttyACM0",
+-                exp_perms       => "1::",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "ttyACM0",
++                                exp_perms       => "1::",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="1"
+ EOF
+         },
+         {
+                 desc            => "permissions GROUP to 1",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "ttyACM0",
+-                exp_perms       => ":1:0660",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "ttyACM0",
++                                exp_perms       => ":1:0660",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", GROUP="1"
+ EOF
+         },
+         {
+                 desc            => "permissions MODE to 0060",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "ttyACM0",
+-                exp_perms       => "::0060",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "ttyACM0",
++                                exp_perms       => "::0060",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", MODE="0060"
+ EOF
+         },
+         {
+                 desc            => "permissions OWNER, GROUP, MODE",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "ttyACM0",
+-                exp_perms       => "1:1:0777",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "ttyACM0",
++                                exp_perms       => "1:1:0777",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", OWNER="1", GROUP="1", MODE="0777"
+ EOF
+         },
+         {
+                 desc            => "permissions only rule",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "ttyACM0",
+-                exp_perms       => "1:1:0777",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "ttyACM0",
++                                exp_perms       => "1:1:0777",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", OWNER="1", GROUP="1", MODE="0777"
+ KERNEL=="ttyUSX[0-9]*", OWNER="2", GROUP="2", MODE="0444"
+@@ -701,9 +919,12 @@ EOF
+         },
+         {
+                 desc            => "multiple permissions only rule",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "ttyACM0",
+-                exp_perms       => "1:1:0777",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "ttyACM0",
++                                exp_perms       => "1:1:0777",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEM=="tty", OWNER="1"
+ SUBSYSTEM=="tty", GROUP="1"
+@@ -714,9 +935,12 @@ EOF
+         },
+         {
+                 desc            => "permissions only rule with override at SYMLINK+ rule",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "ttyACM0",
+-                exp_perms       => "1:2:0777",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "ttyACM0",
++                                exp_perms       => "1:2:0777",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEM=="tty", OWNER="1"
+ SUBSYSTEM=="tty", GROUP="1"
+@@ -727,53 +951,71 @@ EOF
+         },
+         {
+                 desc            => "major/minor number test",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
+-                exp_majorminor  => "8:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                                exp_majorminor  => "8:0",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node"
+ EOF
+         },
+         {
+                 desc            => "big major number test",
+-                devpath         => "/devices/virtual/misc/misc-fake1",
+-                exp_name        => "node",
+-                exp_majorminor  => "4095:1",
+-                rules           => <<EOF
++                devices => [
++                        {
++                                devpath         => "/devices/virtual/misc/misc-fake1",
++                                exp_name        => "node",
++                                exp_majorminor  => "4095:1",
++                        }],
++                rules                => <<EOF
+ KERNEL=="misc-fake1", SYMLINK+="node"
+ EOF
+         },
+         {
+                 desc            => "big major and big minor number test",
+-                devpath         => "/devices/virtual/misc/misc-fake89999",
+-                exp_name        => "node",
+-                exp_majorminor  => "4095:89999",
++                devices => [
++                        {
++                                devpath         => "/devices/virtual/misc/misc-fake89999",
++                                exp_name        => "node",
++                                exp_majorminor  => "4095:89999",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="misc-fake89999", SYMLINK+="node"
+ EOF
+         },
+         {
+                 desc            => "multiple symlinks with format char",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "symlink2-ttyACM0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "symlink2-ttyACM0",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
+ EOF
+         },
+         {
+                 desc            => "multiple symlinks with a lot of s p a c e s",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "one",
+-                not_exp_name    => " ",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "one",
++                                not_exp_name        => " ",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK="  one     two        "
+ EOF
+         },
+         {
+                 desc            => "symlink with spaces in substituted variable",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "name-one_two_three-end",
+-                not_exp_name    => " ",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "name-one_two_three-end",
++                                not_exp_name    => " ",
++                        }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="one two three"
+ SYMLINK="name-\$env{WITH_WS}-end"
+@@ -781,9 +1023,12 @@ EOF
+         },
+         {
+                 desc            => "symlink with leading space in substituted variable",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "name-one_two_three-end",
+-                not_exp_name    => " ",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "name-one_two_three-end",
++                                not_exp_name    => " ",
++                        }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one two three"
+ SYMLINK="name-\$env{WITH_WS}-end"
+@@ -791,9 +1036,12 @@ EOF
+         },
+         {
+                 desc            => "symlink with trailing space in substituted variable",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "name-one_two_three-end",
+-                not_exp_name    => " ",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "name-one_two_three-end",
++                                not_exp_name    => " ",
++                        }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="one two three   "
+ SYMLINK="name-\$env{WITH_WS}-end"
+@@ -801,9 +1049,12 @@ EOF
+         },
+         {
+                 desc            => "symlink with lots of space in substituted variable",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "name-one_two_three-end",
+-                not_exp_name    => " ",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "name-one_two_three-end",
++                                not_exp_name    => " ",
++                        }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one two three   "
+ SYMLINK="name-\$env{WITH_WS}-end"
+@@ -811,9 +1062,12 @@ EOF
+         },
+         {
+                 desc            => "symlink with multiple spaces in substituted variable",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "name-one_two_three-end",
+-                not_exp_name    => " ",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "name-one_two_three-end",
++                                not_exp_name    => " ",
++                        }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one  two  three   "
+ SYMLINK="name-\$env{WITH_WS}-end"
+@@ -821,9 +1075,12 @@ EOF
+         },
+         {
+                 desc            => "symlink with space and var with space, part 1",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "first",
+-                not_exp_name    => " ",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "first",
++                                not_exp_name    => " ",
++                        }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one  two  three   "
+ SYMLINK="  first  name-\$env{WITH_WS}-end another_symlink a b c "
+@@ -831,9 +1088,12 @@ EOF
+         },
+         {
+                 desc            => "symlink with space and var with space, part 2",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "name-one_two_three-end",
+-                not_exp_name    => " ",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "name-one_two_three-end",
++                                not_exp_name    => " ",
++                        }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one  two  three   "
+ SYMLINK="  first  name-\$env{WITH_WS}-end another_symlink a b c "
+@@ -841,9 +1101,12 @@ EOF
+         },
+         {
+                 desc            => "symlink with space and var with space, part 3",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "another_symlink",
+-                not_exp_name    => " ",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "another_symlink",
++                                not_exp_name    => " ",
++                        }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one  two  three   "
+ SYMLINK="  first  name-\$env{WITH_WS}-end another_symlink a b c "
+@@ -851,133 +1114,181 @@ EOF
+         },
+         {
+                 desc            => "symlink creation (same directory)",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "modem0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "modem0",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK="modem%n"
+ EOF
+         },
+         {
+                 desc            => "multiple symlinks",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "second-0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "second-0" ,
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK="first-%n second-%n third-%n"
+ EOF
+         },
+         {
+                 desc            => "symlink name '.'",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => ".",
+-                exp_add_error   => "yes",
+-                exp_rem_error   => "yes",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => ".",
++                                exp_add_error        => "yes",
++                                exp_rem_error        => "yes",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="."
+ EOF
+         },
+         {
+                 desc            => "symlink node to itself",
+-                devpath         => "/devices/virtual/tty/tty0",
+-                exp_name        => "link",
+-                exp_add_error   => "yes",
+-                exp_rem_error   => "yes",
+-                option          => "clean",
++                devices => [
++                        {
++                                devpath         => "/devices/virtual/tty/tty0",
++                                exp_name        => "link",
++                                exp_add_error        => "yes",
++                                exp_rem_error        => "yes",
++                        }],
++                option                => "clean",
+                 rules           => <<EOF
+ KERNEL=="tty0", SYMLINK+="tty0"
+ EOF
+         },
+         {
+                 desc            => "symlink %n substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "symlink0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "symlink0",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink%n"
+ EOF
+         },
+         {
+                 desc            => "symlink %k substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "symlink-ttyACM0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "symlink-ttyACM0",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink-%k"
+ EOF
+         },
+         {
+                 desc            => "symlink %M:%m substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "major-166:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "major-166:0",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="major-%M:%m"
+ EOF
+         },
+         {
+                 desc            => "symlink %b substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "symlink-0:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "symlink-0:0:0:0",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="symlink-%b"
+ EOF
+         },
+         {
+                 desc            => "symlink %c substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "test",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "test",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo test", SYMLINK+="%c"
+ EOF
+         },
+         {
+                 desc            => "symlink %c{N} substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "test",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "test",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2}"
+ EOF
+         },
+         {
+                 desc            => "symlink %c{N+} substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "this",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "this",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2+}"
+ EOF
+         },
+         {
+                 desc            => "symlink only rule with %c{N+}",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "test",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "test",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK+="%c{2+}"
+ EOF
+         },
+         {
+                 desc            => "symlink %s{filename} substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "166:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "166:0",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="%s{dev}"
+ EOF
+         },
+         {
+                 desc            => "program result substitution (numbered part of)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "link1",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "link1",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", SYMLINK+="%c{2} %c{3}"
+ EOF
+         },
+         {
+                 desc            => "program result substitution (numbered part of+)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                exp_name        => "link4",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_name        => "link4",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", SYMLINK+="%c{2+}"
+ EOF
+         },
+         {
+                 desc            => "SUBSYSTEM match test",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", SUBSYSTEM=="vc"
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", SUBSYSTEM=="block"
+@@ -986,8 +1297,11 @@ EOF
+         },
+         {
+                 desc            => "DRIVERS match test",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", DRIVERS=="sd-wrong"
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="node", DRIVERS=="sd"
+@@ -995,32 +1309,44 @@ EOF
+         },
+         {
+                 desc            => "devnode substitution test",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/usr/bin/test -b %N" SYMLINK+="node"
+ EOF
+         },
+         {
+                 desc            => "parent node name substitution test",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "sda-part-1",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "sda-part-1",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="%P-part-1"
+ EOF
+         },
+         {
+                 desc            => "udev_root substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "start-/dev-end",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "start-/dev-end",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="start-%r-end"
+ EOF
+         },
+         {
+                 desc            => "last_rule option",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "last",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "last",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="last", OPTIONS="last_rule"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="very-last"
+@@ -1028,8 +1354,11 @@ EOF
+         },
+         {
+                 desc            => "negation KERNEL!=",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "match",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "match",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
+@@ -1038,8 +1367,11 @@ EOF
+         },
+         {
+                 desc            => "negation SUBSYSTEM!=",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "not-anything",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "not-anything",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", SUBSYSTEM=="block", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
+@@ -1048,8 +1380,11 @@ EOF
+         },
+         {
+                 desc            => "negation PROGRAM!= exit code",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "nonzero-program",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "nonzero-program",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
+ KERNEL=="sda1", PROGRAM!="/bin/false", SYMLINK+="nonzero-program"
+@@ -1057,8 +1392,11 @@ EOF
+         },
+         {
+                 desc            => "ENV{} test",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "true",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "true",
++                        }],
+                 rules           => <<EOF
+ ENV{ENV_KEY_TEST}="test"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
+@@ -1068,8 +1406,11 @@ EOF
+         },
+         {
+                 desc            => "ENV{} test",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "true",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "true",
++                        }],
+                 rules           => <<EOF
+ ENV{ENV_KEY_TEST}="test"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ENV_KEY_TEST}=="go", SYMLINK+="wrong"
+@@ -1080,8 +1421,11 @@ EOF
+         },
+         {
+                 desc            => "ENV{} test (assign)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "true",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "true",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
+@@ -1091,8 +1435,11 @@ EOF
+         },
+         {
+                 desc            => "ENV{} test (assign 2 times)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "true",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "true",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="absolutely-\$env{ASSIGN}"
+@@ -1103,8 +1450,11 @@ EOF
+         },
+         {
+                 desc            => "ENV{} test (assign2)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "part",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "part",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEM=="block", KERNEL=="*[0-9]", ENV{PARTITION}="true", ENV{MAINDEVICE}="false"
+ SUBSYSTEM=="block", KERNEL=="*[!0-9]", ENV{PARTITION}="false", ENV{MAINDEVICE}="true"
+@@ -1115,40 +1465,55 @@ EOF
+         },
+         {
+                 desc            => "untrusted string sanitize",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "sane",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "sane",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e name; (/usr/bin/badprogram)", RESULT=="name_ _/usr/bin/badprogram_", SYMLINK+="sane"
+ EOF
+         },
+         {
+                 desc            => "untrusted string sanitize (don't replace utf8)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "uber",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "uber",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xc3\\xbcber" RESULT=="\xc3\xbcber", SYMLINK+="uber"
+ EOF
+         },
+         {
+                 desc            => "untrusted string sanitize (replace invalid utf8)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "replaced",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "replaced",
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xef\\xe8garbage", RESULT=="__garbage", SYMLINK+="replaced"
+ EOF
+         },
+         {
+                 desc            => "read sysfs value from parent device",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "serial-354172020305000",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "serial-354172020305000",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM*", ATTRS{serial}=="?*", SYMLINK+="serial-%s{serial}"
+ EOF
+         },
+         {
+                 desc            => "match against empty key string",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "ok",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "ok",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", ATTRS{nothing}!="", SYMLINK+="not-1-ok"
+ KERNEL=="sda", ATTRS{nothing}=="", SYMLINK+="not-2-ok"
+@@ -1158,8 +1523,11 @@ EOF
+         },
+         {
+                 desc            => "check ACTION value",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "ok",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "ok",
++                        }],
+                 rules           => <<EOF
+ ACTION=="unknown", KERNEL=="sda", SYMLINK+="unknown-not-ok"
+ ACTION=="add", KERNEL=="sda", SYMLINK+="ok"
+@@ -1167,9 +1535,12 @@ EOF
+         },
+         {
+                 desc            => "final assignment",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "ok",
+-                exp_perms       => "root:tty:0640",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "ok",
++                                exp_perms       => "root:tty:0640",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", GROUP:="tty"
+ KERNEL=="sda", GROUP="not-ok", MODE="0640", SYMLINK+="ok"
+@@ -1177,9 +1548,12 @@ EOF
+         },
+         {
+                 desc            => "final assignment 2",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "ok",
+-                exp_perms       => "root:tty:0640",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "ok",
++                                exp_perms       => "root:tty:0640",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", GROUP:="tty"
+ SUBSYSTEM=="block", MODE:="640"
+@@ -1188,17 +1562,23 @@ EOF
+         },
+         {
+                 desc            => "env substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "node-add-me",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "node-add-me",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", MODE="0666", SYMLINK+="node-\$env{ACTION}-me"
+ EOF
+         },
+         {
+                 desc            => "reset list to current value",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "three",
+-                not_exp_name    => "two",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "three",
++                                not_exp_name    => "two",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="one"
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="two"
+@@ -1207,9 +1587,12 @@ EOF
+         },
+         {
+                 desc            => "test empty SYMLINK+ (empty override)",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "right",
+-                not_exp_name    => "wrong",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "right",
++                                not_exp_name    => "wrong",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="wrong"
+ KERNEL=="ttyACM[0-9]*", SYMLINK=""
+@@ -1218,8 +1601,11 @@ EOF
+         },
+         {
+                 desc            => "test multi matches",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "right",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "right",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM*", SYMLINK+="before"
+ KERNEL=="ttyACM*|nothing", SYMLINK+="right"
+@@ -1227,8 +1613,11 @@ EOF
+         },
+         {
+                 desc            => "test multi matches 2",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "right",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "right",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="dontknow*|*nothing", SYMLINK+="nomatch"
+ KERNEL=="ttyACM*", SYMLINK+="before"
+@@ -1237,8 +1626,11 @@ EOF
+         },
+         {
+                 desc            => "test multi matches 3",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "right",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "right",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
+ KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
+@@ -1248,8 +1640,11 @@ EOF
+         },
+         {
+                 desc            => "test multi matches 4",
+-                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                exp_name        => "right",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
++                                exp_name        => "right",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
+ KERNEL=="dontknow|ttyACM0a|nothing|attyACM0", SYMLINK+="wrong1"
+@@ -1259,10 +1654,13 @@ KERNEL=="ttyACM0a|nothing", SYMLINK+="wrong3"
+ EOF
+         },
+         {
+-                desc            => "test multi matches 5",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++               desc            => "test multi matches 5",
++               devices => [
++                       {
++                               devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                               exp_name        => "found",
++                               not_exp_name    => "bad",
++                       }],
+                 rules           => <<EOF
+ KERNEL=="sda", TAG="foo"
+ TAGS=="|foo", SYMLINK+="found"
+@@ -1271,9 +1669,12 @@ EOF
+         },
+         {
+                 desc            => "test multi matches 6",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                                not_exp_name    => "bad",
++                       }],
+                 rules           => <<EOF
+ KERNEL=="sda", TAG=""
+ TAGS=="|foo", SYMLINK+="found"
+@@ -1282,9 +1683,12 @@ EOF
+         },
+         {
+                 desc            => "test multi matches 7",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                                not_exp_name    => "bad",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", TAG="foo"
+ TAGS=="foo||bar", SYMLINK+="found"
+@@ -1293,9 +1697,12 @@ EOF
+         },
+         {
+                 desc            => "test multi matches 8",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                                not_exp_name    => "bad",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", TAG=""
+ TAGS=="foo||bar", SYMLINK+="found"
+@@ -1304,9 +1711,12 @@ EOF
+         },
+         {
+                 desc            => "test multi matches 9",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                                not_exp_name    => "bad",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", TAG="foo"
+ TAGS=="foo|", SYMLINK+="found"
+@@ -1315,9 +1725,12 @@ EOF
+         },
+         {
+                 desc            => "test multi matches 10",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                                not_exp_name    => "bad",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", TAG=""
+ TAGS=="foo|", SYMLINK+="found"
+@@ -1326,9 +1739,12 @@ EOF
+         },
+         {
+                 desc            => "test multi matches 11",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                                not_exp_name    => "bad",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", TAG="c"
+ TAGS=="foo||bar||c", SYMLINK+="found"
+@@ -1337,8 +1753,11 @@ EOF
+         },
+         {
+                 desc            => "IMPORT parent test sequence 1/2 (keep)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "parent",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "parent",
++                        }],
+                 option          => "keep",
+                 rules           => <<EOF
+ KERNEL=="sda", IMPORT{program}="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'"
+@@ -1347,8 +1766,11 @@ EOF
+         },
+         {
+                 desc            => "IMPORT parent test sequence 2/2 (keep)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "parentenv-parent_right",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "parentenv-parent_right",
++                        }],
+                 option          => "clean",
+                 rules           => <<EOF
+ KERNEL=="sda1", IMPORT{parent}="PARENT*", SYMLINK+="parentenv-\$env{PARENT_KEY}\$env{WRONG_PARENT_KEY}"
+@@ -1356,8 +1778,11 @@ EOF
+         },
+         {
+                 desc            => "GOTO test",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "right",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "right",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda1", GOTO="TEST"
+ KERNEL=="sda1", SYMLINK+="wrong"
+@@ -1370,8 +1795,11 @@ EOF
+         },
+         {
+                 desc            => "GOTO label does not exist",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "right",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "right",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda1", GOTO="does-not-exist"
+ KERNEL=="sda1", SYMLINK+="right",
+@@ -1380,9 +1808,12 @@ EOF
+         },
+         {
+                 desc            => "SYMLINK+ compare test",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "right",
+-                not_exp_name    => "wrong",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "right",
++                                not_exp_name    => "wrong",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda1", SYMLINK+="link"
+ KERNEL=="sda1", SYMLINK=="link*", SYMLINK+="right"
+@@ -1391,8 +1822,11 @@ EOF
+         },
+         {
+                 desc            => "invalid key operation",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "yes",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "yes",
++                        }],
+                 rules           => <<EOF
+ KERNEL="sda1", SYMLINK+="no"
+ KERNEL=="sda1", SYMLINK+="yes"
+@@ -1400,16 +1834,22 @@ EOF
+         },
+         {
+                 desc            => "operator chars in attribute",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "yes",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "yes",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", ATTR{test:colon+plus}=="?*", SYMLINK+="yes"
+ EOF
+         },
+         {
+                 desc            => "overlong comment line",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                exp_name        => "yes",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_name        => "yes",
++                        }],
+                 rules           => <<EOF
+ # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+    # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+@@ -1419,16 +1859,22 @@ EOF
+         },
+         {
+                 desc            => "magic subsys/kernel lookup",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "00:16:41:e2:8d:ff",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "00:16:41:e2:8d:ff",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", SYMLINK+="\$attr{[net/eth0]address}"
+ EOF
+         },
+         {
+                 desc            => "TEST absolute path",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "there",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "there",
++                        }],
+                 rules           => <<EOF
+ TEST=="/etc/machine-id", SYMLINK+="there"
+ TEST!="/etc/machine-id", SYMLINK+="notthere"
+@@ -1436,44 +1882,59 @@ EOF
+         },
+         {
+                 desc            => "TEST subsys/kernel lookup",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "yes",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "yes",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", TEST=="[net/eth0]", SYMLINK+="yes"
+ EOF
+         },
+         {
+                 desc            => "TEST relative path",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "relative",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "relative",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", TEST=="size", SYMLINK+="relative"
+ EOF
+         },
+         {
+                 desc            => "TEST wildcard substitution (find queue/nr_requests)",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found-subdir",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found-subdir",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", TEST=="*/nr_requests", SYMLINK+="found-subdir"
+ EOF
+         },
+         {
+                 desc            => "TEST MODE=0000",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "sda",
+-                exp_perms       => "0:0:0000",
+-                exp_rem_error   => "yes",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "sda",
++                                exp_perms       => "0:0:0000",
++                                exp_rem_error   => "yes",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", MODE="0000"
+ EOF
+         },
+         {
+                 desc            => "TEST PROGRAM feeds OWNER, GROUP, MODE",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "sda",
+-                exp_perms       => "1:1:0400",
+-                exp_rem_error   => "yes",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "sda",
++                                exp_perms       => "1:1:0400",
++                                exp_rem_error   => "yes",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", MODE="666"
+ KERNEL=="sda", PROGRAM=="/bin/echo 1 1 0400", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
+@@ -1481,10 +1942,13 @@ EOF
+         },
+         {
+                 desc            => "TEST PROGRAM feeds MODE with overflow",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "sda",
+-                exp_perms       => "0:0:0440",
+-                exp_rem_error   => "yes",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "sda",
++                                exp_perms       => "0:0:0440",
++                                exp_rem_error   => "yes",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", MODE="440"
+ KERNEL=="sda", PROGRAM=="/bin/echo 0 0 0400letsdoabuffferoverflow0123456789012345789012345678901234567890", OWNER="%c{1}", GROUP="%c{2}", MODE="%c{3}"
+@@ -1492,9 +1956,12 @@ EOF
+         },
+         {
+                 desc            => "magic [subsys/sysname] attribute substitution",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "sda-8741C4G-end",
+-                exp_perms       => "0:0:0600",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "sda-8741C4G-end",
++                                exp_perms       => "0:0:0600",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", PROGRAM="/bin/true create-envp"
+ KERNEL=="sda", ENV{TESTENV}="change-envp"
+@@ -1503,8 +1970,11 @@ EOF
+         },
+         {
+                 desc            => "builtin path_id",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0",
++                        }],
+                 rules           => <<EOF
+ KERNEL=="sda", IMPORT{builtin}="path_id"
+ KERNEL=="sda", ENV{ID_PATH}=="?*", SYMLINK+="disk/by-path/\$env{ID_PATH}"
+@@ -1512,9 +1982,12 @@ EOF
+         },
+         {
+                 desc            => "add and match tag",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                                not_exp_name    => "bad" ,
++                        }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", TAG+="green"
+ TAGS=="green", SYMLINK+="found"
+@@ -1523,17 +1996,23 @@ EOF
+         },
+         {
+                 desc            => "don't crash with lots of tags",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                        }],
+                 rules           => $rules_10k_tags . <<EOF
+ TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found"
+ EOF
+         },
+         {
+                 desc            => "continuations",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                                not_exp_name    => "bad",
++                        }],
+                 rules           => $rules_10k_tags_continuation . <<EOF
+ TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="bad"
+ KERNEL=="sda",\\
+@@ -1551,9 +2030,13 @@ EOF
+         },
+         {
+                 desc            => "continuations with empty line",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                                not_exp_name    => "bad",
++
++                        }],
+                 rules           => <<EOF
+ # empty line finishes continuation
+ KERNEL=="sda", TAG+="foo" \\
+@@ -1563,13 +2046,16 @@ KERNEL=="sda", TAG+="aaa" \\
+ KERNEL=="sdb", TAG+="bbb"
+ TAGS=="foo", SYMLINK+="found"
+ TAGS=="aaa", SYMLINK+="bad"
+-EOF
++                    EOF
+         },
+         {
+                 desc            => "continuations with white only line",
+-                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                exp_name        => "found",
+-                not_exp_name    => "bad",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_name        => "found",
++                                not_exp_name    => "bad",
++                        }],
+                 rules           => <<EOF
+ # space only line finishes continuation
+ KERNEL=="sda", TAG+="foo" \\
+@@ -1709,43 +2195,33 @@ sub udev_setup {
+         return 1;
+ }
+ 
+-sub run_test {
+-        my ($rules, $number) = @_;
+-        my $rc;
+-
+-        print "TEST $number: $rules->{desc}\n";
+-        print "device \'$rules->{devpath}\' expecting node/link \'$rules->{exp_name}\'\n";
++sub check_add {
++        my ($device) = @_;
+ 
+-        $rc = udev("add", $rules->{devpath}, \$rules->{rules});
+-        if ($rc != 0) {
+-                print "$udev_bin add failed with code $rc\n";
+-                $error++;
+-        }
+-        if (defined($rules->{not_exp_name})) {
+-                if ((-e "$udev_dev/$rules->{not_exp_name}") ||
+-                    (-l "$udev_dev/$rules->{not_exp_name}")) {
+-                        print "nonexistent: error \'$rules->{not_exp_name}\' not expected to be there\n";
++        if (defined($device->{not_exp_name})) {
++                if ((-e "$udev_dev/$device->{not_exp_name}") ||
++                    (-l "$udev_dev/$device->{not_exp_name}")) {
++                        print "nonexistent: error \'$device->{not_exp_name}\' not expected to be there\n";
+                         $error++;
+                         sleep(1);
+                 }
+         }
+-
+-        if ((-e "$udev_dev/$rules->{exp_name}") ||
+-            (-l "$udev_dev/$rules->{exp_name}")) {
++        if ((-e "$udev_dev/$device->{exp_name}") ||
++            (-l "$udev_dev/$device->{exp_name}")) {
+ 
+                 my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
+-                    $atime, $mtime, $ctime, $blksize, $blocks) = stat("$udev_dev/$rules->{exp_name}");
++                    $atime, $mtime, $ctime, $blksize, $blocks) = stat("$udev_dev/$device->{exp_name}");
+ 
+-                if (defined($rules->{exp_perms})) {
+-                        permissions_test($rules, $uid, $gid, $mode);
++                if (defined($device->{exp_perms})) {
++                        permissions_test($device, $uid, $gid, $mode);
+                 }
+-                if (defined($rules->{exp_majorminor})) {
+-                        major_minor_test($rules, $rdev);
++                if (defined($device->{exp_majorminor})) {
++                        major_minor_test($device, $rdev);
+                 }
+-                print "add:         ok\n";
++                print "add $device->{devpath}:         ok\n";
+         } else {
+-                print "add:         error";
+-                if ($rules->{exp_add_error}) {
++                print "add  $device->{devpath}:         error";
++                if ($device->{exp_add_error}) {
+                         print " as expected\n";
+                 } else {
+                         print "\n";
+@@ -1755,21 +2231,15 @@ sub run_test {
+                         sleep(1);
+                 }
+         }
++}
+ 
+-        if (defined($rules->{option}) && $rules->{option} eq "keep") {
+-                print "\n\n";
+-                return;
+-        }
++sub check_remove {
++        my ($device) = @_;
+ 
+-        $rc = udev("remove", $rules->{devpath}, \$rules->{rules});
+-        if ($rc != 0) {
+-                print "$udev_bin remove failed with code $rc\n";
+-                $error++;
+-        }
+-        if ((-e "$udev_dev/$rules->{exp_name}") ||
+-            (-l "$udev_dev/$rules->{exp_name}")) {
+-                print "remove:      error";
+-                if ($rules->{exp_rem_error}) {
++        if ((-e "$udev_dev/$device->{exp_name}") ||
++            (-l "$udev_dev/$device->{exp_name}")) {
++                print "remove  $device->{devpath}:      error";
++                if ($device->{exp_rem_error}) {
+                         print " as expected\n";
+                 } else {
+                         print "\n";
+@@ -1779,7 +2249,43 @@ sub run_test {
+                         sleep(1);
+                 }
+         } else {
+-                print "remove:      ok\n";
++                print "remove  $device->{devpath}:      ok\n";
++        }
++}
++
++sub run_test {
++        my ($rules, $number) = @_;
++        my $rc;
++        my @devices = @{$rules->{devices}};
++
++        print "TEST $number: $rules->{desc}\n";
++        foreach my $dev (@devices) {
++                print "device \'$dev->{devpath}\' expecting node/link \'$dev->{exp_name}\'\n";
++                $rc = udev("add", $dev->{devpath}, \$rules->{rules});
++                if ($rc != 0) {
++                        print "$udev_bin add failed with code $rc\n";
++                        $error++;
++                }
++        }
++
++        foreach my $dev (@devices) {
++                check_add($dev);
++        }
++
++        if (defined($rules->{option}) && $rules->{option} eq "keep") {
++                print "\n\n";
++                return;
++        }
++
++        foreach my $dev (@devices) {
++                $rc = udev("remove", $dev->{devpath}, \$rules->{rules});
++                if ($rc != 0) {
++                        print "$udev_bin remove failed with code $rc\n";
++                        $error++;
++                }
++        }
++        foreach my $dev (@devices) {
++                check_remove($dev);
+         }
+ 
+         print "\n";
diff --git a/SOURCES/0526-test-udev-test.pl-create-rules-only-once.patch b/SOURCES/0526-test-udev-test.pl-create-rules-only-once.patch
new file mode 100644
index 0000000..b394455
--- /dev/null
+++ b/SOURCES/0526-test-udev-test.pl-create-rules-only-once.patch
@@ -0,0 +1,61 @@
+From 9aa12f2f564c208c4c1eaef613d18d1c0b481a16 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Mon, 23 Apr 2018 21:58:12 +0200
+Subject: [PATCH] test/udev-test.pl: create rules only once
+
+It's not necessary to write the rules for every udev run, as we
+now may have many (rather than just 2) per test.
+
+(cherry picked from commit af7ee3eae689f9c31b49ea13758ad9c901918ce3)
+
+Related: #1642728
+---
+ test/udev-test.pl | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index bd5401da75..8b5a97ad61 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -2069,14 +2069,18 @@ EOF
+         },
+ );
+ 
+-sub udev {
+-        my ($action, $devpath, $rules) = @_;
++sub create_rules {
++        my ($rules) = @_;
+ 
+         # create temporary rules
+         system("mkdir", "-p", "$udev_rules_dir");
+         open CONF, ">$udev_rules" || die "unable to create rules file: $udev_rules";
+         print CONF $$rules;
+         close CONF;
++}
++
++sub udev {
++        my ($action, $devpath) = @_;
+ 
+         if ($valgrind > 0) {
+                 return system("$udev_bin_valgrind $action $devpath");
+@@ -2259,9 +2263,10 @@ sub run_test {
+         my @devices = @{$rules->{devices}};
+ 
+         print "TEST $number: $rules->{desc}\n";
++        create_rules(\$rules->{rules});
+         foreach my $dev (@devices) {
+                 print "device \'$dev->{devpath}\' expecting node/link \'$dev->{exp_name}\'\n";
+-                $rc = udev("add", $dev->{devpath}, \$rules->{rules});
++                $rc = udev("add", $dev->{devpath});
+                 if ($rc != 0) {
+                         print "$udev_bin add failed with code $rc\n";
+                         $error++;
+@@ -2278,7 +2283,7 @@ sub run_test {
+         }
+ 
+         foreach my $dev (@devices) {
+-                $rc = udev("remove", $dev->{devpath}, \$rules->{rules});
++                $rc = udev("remove", $dev->{devpath});
+                 if ($rc != 0) {
+                         print "$udev_bin remove failed with code $rc\n";
+                         $error++;
diff --git a/SOURCES/0527-test-udev-test.pl-allow-concurrent-additions-and-rem.patch b/SOURCES/0527-test-udev-test.pl-allow-concurrent-additions-and-rem.patch
new file mode 100644
index 0000000..f87307f
--- /dev/null
+++ b/SOURCES/0527-test-udev-test.pl-allow-concurrent-additions-and-rem.patch
@@ -0,0 +1,169 @@
+From 618d56c7ac8bd8cd701344a0eaca8373a78dea95 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Mon, 23 Apr 2018 21:59:05 +0200
+Subject: [PATCH] test/udev-test.pl: allow concurrent additions and removals
+
+Allow testing cases where multiple devices are added and removed
+simultaneously. Tests are started as synchronously as possible using a
+semaphore, in order to test possible race conditions. If this isn't desired,
+the test parameter "sleep_us" can be set to the number of microseconds to wait
+between udev invocations.
+
+(cherry picked from commit 09a4062d70b3a10d022e40066e2adf09df05bbbc)
+
+Related: #1642728
+---
+ test/udev-test.pl | 90 +++++++++++++++++++++++++++++++++++++----------
+ 1 file changed, 72 insertions(+), 18 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 8b5a97ad61..db25ef13c1 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -18,6 +18,10 @@
+ 
+ use warnings;
+ use strict;
++use POSIX qw(WIFEXITED WEXITSTATUS);
++use IPC::SysV qw(IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT);
++use IPC::Semaphore;
++use Time::HiRes qw(usleep);
+ 
+ my $udev_bin            = "./test-udev";
+ my $valgrind            = 0;
+@@ -2210,6 +2214,8 @@ sub check_add {
+                         sleep(1);
+                 }
+         }
++
++        print "device \'$device->{devpath}\' expecting node/link \'$device->{exp_name}\'\n";
+         if ((-e "$udev_dev/$device->{exp_name}") ||
+             (-l "$udev_dev/$device->{exp_name}")) {
+ 
+@@ -2257,21 +2263,72 @@ sub check_remove {
+         }
+ }
+ 
++sub run_udev {
++        my ($action, $dev, $sleep_us, $sema) = @_;
++
++        # Notify main process that this worker has started
++        $sema->op(0, 1, 0);
++
++        # Wait for start
++        $sema->op(0, 0, 0);
++        usleep($sleep_us) if defined ($sleep_us);
++        my $rc = udev($action, $dev->{devpath});
++        exit $rc;
++}
++
++sub fork_and_run_udev {
++        my ($action, $rules, $sema) = @_;
++        my @devices = @{$rules->{devices}};
++        my $dev;
++        my $k = 0;
++
++        $sema->setval(0, 1);
++        foreach $dev (@devices) {
++                my $pid = fork();
++
++                if (!$pid) {
++                        run_udev($action, $dev,
++                                 defined($rules->{sleep_us}) ? $k * $rules->{sleep_us} : undef,
++                                 $sema);
++                } else {
++                        $dev->{pid} = $pid;
++                }
++                $k++;
++        }
++
++        # This operation waits for all workers to become ready, and
++        # starts them off when that's the case.
++        $sema->op(0, -($#devices + 2), 0);
++
++        foreach $dev (@devices) {
++                my $rc;
++                my $pid;
++
++                $pid = waitpid($dev->{pid}, 0);
++                if ($pid == -1) {
++                        print "error waiting for pid dev->{pid}\n";
++                        $error += 1;
++                }
++                if (WIFEXITED($?)) {
++                        $rc = WEXITSTATUS($?);
++
++                        if ($rc) {
++                                print "$udev_bin $action for $dev->{devpath} failed with code $rc\n";
++                                $error += 1;
++                        }
++                }
++        }
++}
++
+ sub run_test {
+-        my ($rules, $number) = @_;
++        my ($rules, $number, $sema) = @_;
+         my $rc;
+         my @devices = @{$rules->{devices}};
+ 
+         print "TEST $number: $rules->{desc}\n";
+         create_rules(\$rules->{rules});
+-        foreach my $dev (@devices) {
+-                print "device \'$dev->{devpath}\' expecting node/link \'$dev->{exp_name}\'\n";
+-                $rc = udev("add", $dev->{devpath});
+-                if ($rc != 0) {
+-                        print "$udev_bin add failed with code $rc\n";
+-                        $error++;
+-                }
+-        }
++
++        fork_and_run_udev("add", $rules, $sema);
+ 
+         foreach my $dev (@devices) {
+                 check_add($dev);
+@@ -2282,13 +2339,8 @@ sub run_test {
+                 return;
+         }
+ 
+-        foreach my $dev (@devices) {
+-                $rc = udev("remove", $dev->{devpath});
+-                if ($rc != 0) {
+-                        print "$udev_bin remove failed with code $rc\n";
+-                        $error++;
+-                }
+-        }
++        fork_and_run_udev("remove", $rules, $sema);
++
+         foreach my $dev (@devices) {
+                 check_remove($dev);
+         }
+@@ -2350,12 +2402,13 @@ foreach my $arg (@ARGV) {
+                 push(@list, $arg);
+         }
+ }
++my $sema = IPC::Semaphore->new(IPC_PRIVATE, 1, S_IRUSR | S_IWUSR | IPC_CREAT);
+ 
+ if ($list[0]) {
+         foreach my $arg (@list) {
+                 if (defined($tests[$arg-1]->{desc})) {
+                         print "udev-test will run test number $arg:\n\n";
+-                        run_test($tests[$arg-1], $arg);
++                        run_test($tests[$arg-1], $arg, $sema);
+                 } else {
+                         print "test does not exist.\n";
+                 }
+@@ -2365,11 +2418,12 @@ if ($list[0]) {
+         print "\nudev-test will run ".($#tests + 1)." tests:\n\n";
+ 
+         foreach my $rules (@tests) {
+-                run_test($rules, $test_num);
++                run_test($rules, $test_num, $sema);
+                 $test_num++;
+         }
+ }
+ 
++$sema->remove;
+ print "$error errors occurred\n\n";
+ 
+ cleanup();
diff --git a/SOURCES/0528-test-udev-test.pl-use-computed-devnode-name.patch b/SOURCES/0528-test-udev-test.pl-use-computed-devnode-name.patch
new file mode 100644
index 0000000..a20ebbd
--- /dev/null
+++ b/SOURCES/0528-test-udev-test.pl-use-computed-devnode-name.patch
@@ -0,0 +1,260 @@
+From 5f34ea55a8c6723240eb1641a655db7df3c428a2 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 09:38:26 +0200
+Subject: [PATCH] test/udev-test.pl: use computed devnode name
+
+More often than not, the created devnode is the basename of the
+sysfs entry. The "devnode" device may be used to override the
+auto-detected node name.
+
+Permissions and major/minor number are now verified on the devnode
+itself, not on symlinks.
+
+For those tests where exp_name is set to the computed devnode name,
+the explicit "exp_name" can be removed. "exp_name" is only required for
+symlinks.
+
+This allows separate testing for devnodes and symlinks an a follow-up
+patch.
+
+(cherry picked from commit f0dccf01a7b4e72278e14effd74782ea83d0a73b)
+
+Related: #1642728
+---
+ test/udev-test.pl | 92 +++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 66 insertions(+), 26 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index db25ef13c1..aa9a8dc2ff 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -55,12 +55,10 @@ my @tests = (
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "sda" ,
+                                 exp_rem_error   => "yes",
+                         },
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "sda1" ,
+                                 exp_rem_error   => "yes",
+                         }],
+                 rules           => <<EOF
+@@ -644,6 +642,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/virtual/block/fake!blockdev0",
++                                devnode         => "fake/blockdev0",
+                                 exp_name        => "is/a/fake/blockdev0" ,
+                         }],
+                 rules           => <<EOF
+@@ -657,7 +656,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/virtual/block/fake!blockdev0",
+-                                exp_name        => "fake/blockdev0" ,
++                                devnode         => "fake/blockdev0",
+                                 exp_rem_error   => "yes",
+                         }],
+                 rules           => <<EOF
+@@ -768,7 +767,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/virtual/tty/tty33",
+-                                exp_name        => "tty33",
+                                 exp_perms       => "0:0:0600",
+                         }],
+                 rules           => <<EOF
+@@ -864,7 +862,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "ttyACM0",
+                                 exp_perms       => "1::",
+                         }],
+                 rules           => <<EOF
+@@ -876,7 +873,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "ttyACM0",
+                                 exp_perms       => ":1:0660",
+                         }],
+                 rules           => <<EOF
+@@ -888,7 +884,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "ttyACM0",
+                                 exp_perms       => "::0060",
+                         }],
+                 rules           => <<EOF
+@@ -900,7 +895,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "ttyACM0",
+                                 exp_perms       => "1:1:0777",
+                         }],
+                 rules           => <<EOF
+@@ -912,7 +906,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "ttyACM0",
+                                 exp_perms       => "1:1:0777",
+                         }],
+                 rules           => <<EOF
+@@ -926,7 +919,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "ttyACM0",
+                                 exp_perms       => "1:1:0777",
+                         }],
+                 rules           => <<EOF
+@@ -942,7 +934,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "ttyACM0",
+                                 exp_perms       => "1:2:0777",
+                         }],
+                 rules           => <<EOF
+@@ -1922,7 +1913,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "sda",
+                                 exp_perms       => "0:0:0000",
+                                 exp_rem_error   => "yes",
+                         }],
+@@ -1935,7 +1925,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "sda",
+                                 exp_perms       => "1:1:0400",
+                                 exp_rem_error   => "yes",
+                         }],
+@@ -1949,7 +1938,6 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "sda",
+                                 exp_perms       => "0:0:0440",
+                                 exp_rem_error   => "yes",
+                         }],
+@@ -2203,6 +2191,44 @@ sub udev_setup {
+         return 1;
+ }
+ 
++sub get_devnode {
++        my ($device) = @_;
++        my $devnode;
++
++        if (defined($device->{devnode})) {
++                $devnode = "$udev_dev/$device->{devnode}";
++        } else {
++                $devnode = "$device->{devpath}";
++                $devnode =~ s!.*/!$udev_dev/!;
++        }
++        return $devnode;
++}
++
++sub check_devnode {
++        my ($device) = @_;
++        my $devnode = get_devnode($device);
++
++        my @st = lstat("$devnode");
++        if (! (-b _  || -c _)) {
++                print "add $devnode:         error\n";
++                system("tree", "$udev_dev");
++                $error++;
++                return undef;
++        }
++
++        my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
++            $atime, $mtime, $ctime, $blksize, $blocks) = @st;
++
++        if (defined($device->{exp_perms})) {
++                permissions_test($device, $uid, $gid, $mode);
++        }
++        if (defined($device->{exp_majorminor})) {
++                major_minor_test($device, $rdev);
++        }
++        print "add $devnode:         ok\n";
++        return $devnode;
++}
++
+ sub check_add {
+         my ($device) = @_;
+ 
+@@ -2215,19 +2241,13 @@ sub check_add {
+                 }
+         }
+ 
++        my $devnode = check_devnode($device);
++
+         print "device \'$device->{devpath}\' expecting node/link \'$device->{exp_name}\'\n";
++        return if (!defined($device->{exp_name}));
++
+         if ((-e "$udev_dev/$device->{exp_name}") ||
+             (-l "$udev_dev/$device->{exp_name}")) {
+-
+-                my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size,
+-                    $atime, $mtime, $ctime, $blksize, $blocks) = stat("$udev_dev/$device->{exp_name}");
+-
+-                if (defined($device->{exp_perms})) {
+-                        permissions_test($device, $uid, $gid, $mode);
+-                }
+-                if (defined($device->{exp_majorminor})) {
+-                        major_minor_test($device, $rdev);
+-                }
+                 print "add $device->{devpath}:         ok\n";
+         } else {
+                 print "add  $device->{devpath}:         error";
+@@ -2243,12 +2263,32 @@ sub check_add {
+         }
+ }
+ 
++sub check_remove_devnode {
++        my ($device) = @_;
++        my $devnode = get_devnode($device);
++
++        if (-e "$devnode") {
++                print "remove  $devnode:      error";
++                print "\n";
++                system("tree", "$udev_dev");
++                print "\n";
++                $error++;
++                sleep(1);
++        } else {
++                print "remove $devnode:         ok\n";
++        }
++}
++
+ sub check_remove {
+         my ($device) = @_;
+ 
++        check_remove_devnode($device);
++
++        return if (!defined($device->{exp_name}));
++
+         if ((-e "$udev_dev/$device->{exp_name}") ||
+             (-l "$udev_dev/$device->{exp_name}")) {
+-                print "remove  $device->{devpath}:      error";
++                print "remove  $device->{exp_name}:      error";
+                 if ($device->{exp_rem_error}) {
+                         print " as expected\n";
+                 } else {
+@@ -2259,7 +2299,7 @@ sub check_remove {
+                         sleep(1);
+                 }
+         } else {
+-                print "remove  $device->{devpath}:      ok\n";
++                print "remove  $device->{exp_name}:      ok\n";
+         }
+ }
+ 
diff --git a/SOURCES/0529-test-udev-test.pl-test-correctness-of-symlink-target.patch b/SOURCES/0529-test-udev-test.pl-test-correctness-of-symlink-target.patch
new file mode 100644
index 0000000..3c6e624
--- /dev/null
+++ b/SOURCES/0529-test-udev-test.pl-test-correctness-of-symlink-target.patch
@@ -0,0 +1,61 @@
+From 8ee1cc626f616a2022d641a464fbde9108dd8ad9 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 10:50:24 +0200
+Subject: [PATCH] test/udev-test.pl: test correctness of symlink targets
+
+Test if symlinks are created correctly by comparing the symlink
+targets to the devnode path. This implies (for the symlink) that
+major/minor numbers and permissions are correct, as we have tested
+that on the devnode already.
+
+(cherry picked from commit 997683c8f152e1c139a7ce537de81a0aeae4627f)
+
+Related: #1642728
+---
+ test/udev-test.pl | 23 ++++++++++++++++++-----
+ 1 file changed, 18 insertions(+), 5 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index aa9a8dc2ff..2e3089c5e0 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -22,6 +22,7 @@ use POSIX qw(WIFEXITED WEXITSTATUS);
+ use IPC::SysV qw(IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT);
+ use IPC::Semaphore;
+ use Time::HiRes qw(usleep);
++use Cwd qw(getcwd abs_path);
+ 
+ my $udev_bin            = "./test-udev";
+ my $valgrind            = 0;
+@@ -2243,14 +2244,26 @@ sub check_add {
+ 
+         my $devnode = check_devnode($device);
+ 
+-        print "device \'$device->{devpath}\' expecting node/link \'$device->{exp_name}\'\n";
+         return if (!defined($device->{exp_name}));
+ 
+-        if ((-e "$udev_dev/$device->{exp_name}") ||
+-            (-l "$udev_dev/$device->{exp_name}")) {
+-                print "add $device->{devpath}:         ok\n";
++        my @st = lstat("$udev_dev/$device->{exp_name}");
++        if (-l _) {
++                my $cwd = getcwd();
++                my $dir = "$udev_dev/$device->{exp_name}";
++                $dir =~ s!/[^/]*$!!;
++                my $tgt = readlink("$udev_dev/$device->{exp_name}");
++                $tgt = abs_path("$dir/$tgt");
++                $tgt =~ s!^$cwd/!!;
++
++                if ($tgt ne $devnode) {
++                        print "symlink $device->{exp_name}:         error, found -> $tgt\n";
++                        $error++;
++                        system("tree", "$udev_dev");
++                } else {
++                        print "symlink $device->{exp_name}:         ok\n";
++                }
+         } else {
+-                print "add  $device->{devpath}:         error";
++                print "symlink $device->{exp_name}:         error";
+                 if ($device->{exp_add_error}) {
+                         print " as expected\n";
+                 } else {
diff --git a/SOURCES/0530-test-udev-test.pl-allow-checking-multiple-symlinks.patch b/SOURCES/0530-test-udev-test.pl-allow-checking-multiple-symlinks.patch
new file mode 100644
index 0000000..f004054
--- /dev/null
+++ b/SOURCES/0530-test-udev-test.pl-allow-checking-multiple-symlinks.patch
@@ -0,0 +1,1607 @@
+From fb8d10456d7d5a085e1adb5bfd45f1cda813ac22 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 17:15:58 +0200
+Subject: [PATCH] test/udev-test.pl: allow checking multiple symlinks
+
+Instead of testing the existence or non-exisitence of just a single
+symlink, allow testing of several links per device.
+
+Change the test definitions accordingly.
+
+(cherry picked from commit e62acc3159935781f05fa59c48e5a74e85c61ce2)
+
+Related: #1642728
+---
+ test/udev-test.pl | 495 +++++++++++++++++++++++++++-------------------
+ 1 file changed, 296 insertions(+), 199 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 2e3089c5e0..f5edecefd0 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -71,7 +71,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "boot_disk" ,
++                                exp_links       => ["boot_disk"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+@@ -83,7 +83,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "boot_disk" ,
++                                exp_links       => ["boot_disk"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+@@ -95,7 +95,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "boot_disk" ,
++                                exp_links       => ["boot_disk"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+@@ -107,7 +107,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "boot_disk1" ,
++                                exp_links       => ["boot_disk1"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="boot_disk%n"
+@@ -118,13 +118,16 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "boot_disk1" ,
++                                exp_links       => ["boot_disk1", "boot_disk1-4", "boot_disk1-5"],
++                                not_exp_links   => ["boot_disk1-1", "boot_disk1-2", "boot_disk1-3"]
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="?ATA", SYMLINK+="boot_disk%n-1"
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA?", SYMLINK+="boot_disk%n-2"
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="A??", SYMLINK+="boot_disk%n"
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATAS", SYMLINK+="boot_disk%n-3"
++SUBSYSTEMS=="scsi", ATTRS{vendor}=="AT?", SYMLINK+="boot_disk%n-4"
++SUBSYSTEMS=="scsi", ATTRS{vendor}=="??A", SYMLINK+="boot_disk%n-5"
+ EOF
+         },
+         {
+@@ -132,7 +135,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "boot_disk1" ,
++                                exp_links       => ["boot_disk1"],
++                                not_exp_links   => ["boot_diskX1"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS X ", SYMLINK+="boot_diskX%n"
+@@ -144,10 +148,12 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "boot_disk1" ,
++                                exp_links       => ["boot_disk1", "boot_diskXY1"],
++                                not_exp_links   => ["boot_diskXX1"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="32", SYMLINK+="boot_diskXX%n"
++SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="1", SYMLINK+="boot_diskXY%n"
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n"
+ EOF
+         },
+@@ -156,18 +162,21 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem/0" ,
++                                exp_links       => ["modem/0", "catch-all"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM*", SYMLINK+="modem/%n"
++KERNEL=="*", SYMLINK+="catch-all"
+ EOF
+         },
++        # 10
+         {
+                 desc            => "catch device by * - take 2",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem/0" ,
++                                exp_links       => ["modem/0"],
++                                not_exp_links   => ["bad"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="*ACM1", SYMLINK+="bad"
+@@ -179,7 +188,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem/0" ,
++                                exp_links       => ["modem/0"],
++                                not_exp_links   => ["modem/0-1", "modem/0-2"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM??*", SYMLINK+="modem/%n-1"
+@@ -192,7 +202,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem/0" ,
++                                exp_links       => ["modem/0"],
++                                not_exp_links   => ["modem/0-1", "modem/0-2"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[A-Z]*", SYMLINK+="modem/%n-1"
+@@ -205,7 +216,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem" ,
++                                exp_links       => ["modem"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -216,7 +227,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem" ,
++                                exp_links       => ["modem"],
+                         }],
+                 rules           => <<EOF
+ # this is a comment
+@@ -229,7 +240,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem" ,
++                                exp_links       => ["modem"],
+                         }],
+                 rules           => <<EOF
+  # this is a comment with whitespace before the comment
+@@ -242,7 +253,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "whitespace" ,
++                                exp_links       => ["whitespace"],
+                         }],
+                 rules           => <<EOF
+ 
+@@ -260,7 +271,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem" ,
++                                exp_links       => ["modem"],
+                         }],
+                 rules           => <<EOF
+ 
+@@ -273,7 +284,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem" ,
++                                exp_links       => ["modem"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", \\
+@@ -286,7 +297,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "aaa",
++                                exp_links       => ["aaa"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", PROGRAM=="/bin/echo -e \\101", RESULT=="A", SYMLINK+="aaa"
+@@ -297,7 +308,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem" ,
++                                exp_links       => ["modem"],
+                         }],
+                 rules           => <<EOF
+ 
+@@ -318,7 +329,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "sub/direct/ory/modem" ,
++                                exp_links       => ["sub/direct/ory/modem"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK+="sub/direct/ory/modem"
+@@ -329,7 +340,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "first_disk5" ,
++                                exp_links       => ["first_disk5"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="first_disk%n"
+@@ -340,7 +351,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "Major:8:minor:5:kernelnumber:5:id:0:0:0:0" ,
++                                exp_links       => ["Major:8:minor:5:kernelnumber:5:id:0:0:0:0"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:%M:minor:%m:kernelnumber:%n:id:%b"
+@@ -351,7 +362,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node12345678",
++                                exp_links       => ["node12345678"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", IMPORT{program}="/bin/echo -e \' TEST_KEY=12345678\\n  TEST_key2=98765\'", SYMLINK+="node\$env{TEST_KEY}"
+@@ -363,7 +374,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "disk-ATA-sda" ,
++                                exp_links       => ["disk-ATA-sda"],
++                                not_exp_links   => ["modem"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", SYMLINK+="disk-%s{vendor}-%k"
+@@ -375,8 +387,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "special-device-5" ,
+-                                not_exp_name    => "not" ,
++                                exp_links       => ["special-device-5"],
++                                not_exp_links   => ["not"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n special-device", RESULT=="-special-*", SYMLINK+="not"
+@@ -388,7 +400,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "newline_removed" ,
++                                exp_links       => ["newline_removed"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo test", RESULT=="test", SYMLINK+="newline_removed"
+@@ -399,7 +411,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "test-0:0:0:0" ,
++                                exp_links       => ["test-0:0:0:0"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n test-%b", RESULT=="test-0:0*", SYMLINK+="%c"
+@@ -410,7 +422,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "foo9" ,
++                                exp_links       => ["foo9"],
++                                not_exp_links   => ["foo3", "foo4", "foo5", "foo6", "foo7", "foo8"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="%c{7}"
+@@ -421,7 +434,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "bar9" ,
++                                exp_links       => ["bar9"],
++                                not_exp_links   => ["foo3", "foo4", "foo5", "foo6", "foo7", "foo8"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'echo foo3 foo4 foo5 foo6 foo7 foo8 foo9 | sed  s/foo9/bar9/'", KERNEL=="sda5", SYMLINK+="%c{7}"
+@@ -432,7 +446,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "foo7" ,
++                                exp_links       => ["foo7"],
++                                not_exp_links   => ["foo3", "foo4", "foo5", "foo6", "foo8"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n 'foo3 foo4'   'foo5   foo6   foo7 foo8'", KERNEL=="sda5", SYMLINK+="%c{5}"
+@@ -443,7 +458,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "foo2" ,
++                                exp_links       => ["foo2"],
++                                not_exp_links   => ["foo1"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf %%s \\\"foo1 foo2\\\" | grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
+@@ -454,7 +470,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "foo2" ,
++                                exp_links       => ["foo2"],
++                                not_exp_links   => ["foo1"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c \\\"printf %%s 'foo1 foo2' | grep 'foo1 foo2'\\\"", KERNEL=="sda5", SYMLINK+="%c{2}"
+@@ -465,7 +482,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "foo2" ,
++                                exp_links       => ["foo2"],
++                                not_exp_links   => ["foo1", "foo3"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/sh -c 'printf \\\"%%s %%s\\\" \\\"foo1 foo2\\\" \\\"foo3\\\"| grep \\\"foo1 foo2\\\"'", KERNEL=="sda5", SYMLINK+="%c{2}"
+@@ -476,7 +494,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "my-foo9" ,
++                                exp_links       => ["my-foo9"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{7}"
+@@ -487,7 +505,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "my-foo8" ,
++                                exp_links       => ["my-foo8"],
++                                not_exp_links   => ["my-foo3", "my-foo4", "my-foo5", "my-foo6", "my-foo7", "my-foo9"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo3 foo4 foo5 foo6 foo7 foo8 foo9", KERNEL=="sda5", SYMLINK+="my-%c{6}"
+@@ -498,7 +517,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0",
++                                exp_links       => ["Major:8-minor:5-kernelnumber:5-id:0:0:0:0"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="Major:\$major-minor:\$minor-kernelnumber:\$number-id:\$id"
+@@ -509,7 +528,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "Major:8-minor:5-kernelnumber:5-id:0:0:0:0",
++                                exp_links       => ["Major:8-minor:5-kernelnumber:5-id:0:0:0:0"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="Major:\$major-minor:%m-kernelnumber:\$number-id:\$id"
+@@ -520,7 +539,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "850:0:0:05" ,
++                                exp_links       => ["850:0:0:05"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="%M%m%b%n"
+@@ -531,7 +550,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "855" ,
++                                exp_links       => ["855"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major\$minor\$number"
+@@ -542,7 +561,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "8550:0:0:0" ,
++                                exp_links       => ["8550:0:0:0"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", DEVPATH=="*/sda/*", SYMLINK+="\$major%m%n\$id"
+@@ -553,7 +572,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/virtual/tty/console",
+-                                exp_name        => "TTY",
++                                exp_links       => ["TTY"],
++                                not_exp_links   => ["foo"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n foo", RESULT=="foo", SYMLINK+="foo"
+@@ -565,7 +585,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/virtual/tty/console",
+-                                exp_name        => "TTY" ,
++                                exp_links       => ["TTY"],
++                                not_exp_links   => ["foo"],
+                         }],
+                 rules                => <<EOF
+ SUBSYSTEMS=="foo", ATTRS{dev}=="5:1", SYMLINK+="foo"
+@@ -577,7 +598,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/virtual/tty/console",
+-                                exp_name        => "foo" ,
++                                exp_links       => ["foo", "TTY"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="console", SYMLINK+="TTY"
+@@ -589,7 +610,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "empty" ,
++                                exp_links       => ["empty", "not-something"],
++                                not_exp_links   => ["something", "not-empty"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", ATTR{test_empty_file}=="?*", SYMLINK+="something"
+@@ -603,7 +625,9 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "non-existent" ,
++                                exp_links       => ["non-existent", "wrong"],
++                                not_exp_links   => ["something", "empty", "not-empty",
++                                                    "not-something", "something"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", ATTR{nofile}=="?*", SYMLINK+="something"
+@@ -619,7 +643,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "scsi-0:0:0:0" ,
++                                exp_links       => ["scsi-0:0:0:0"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="usb", PROGRAM=="/bin/echo -n usb-%b", SYMLINK+="%c"
+@@ -632,7 +656,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem" ,
++                                exp_links       => ["modem"],
+                         }],
+                 rules           => <<EOF
+ ATTRS{idProduct}=="007b", SYMLINK+="modem"
+@@ -644,7 +668,8 @@ EOF
+                         {
+                                 devpath         => "/devices/virtual/block/fake!blockdev0",
+                                 devnode         => "fake/blockdev0",
+-                                exp_name        => "is/a/fake/blockdev0" ,
++                                exp_links       => ["is/a/fake/blockdev0"],
++                                not_exp_links       => ["is/not/a/fake/blockdev0", "modem"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", SYMLINK+="is/not/a/%k"
+@@ -658,7 +683,7 @@ EOF
+                         {
+                                 devpath         => "/devices/virtual/block/fake!blockdev0",
+                                 devnode         => "fake/blockdev0",
+-                                exp_rem_error   => "yes",
++                                not_exp_links       => ["modem"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK+="modem"
+@@ -669,7 +694,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "scsi-0:0:0:0",
++                                exp_links       => ["scsi-0:0:0:0"],
++                                not_exp_links       => ["no-match", "short-id", "not-scsi"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="usb", KERNELS=="0:0:0:0", SYMLINK+="not-scsi"
+@@ -684,7 +710,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "scsi-0:0:0:0",
++                                exp_links       => ["scsi-0:0:0:0"],
++                                not_exp_links   => ["no-match", "before"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="*:1", SYMLINK+="no-match"
+@@ -699,7 +726,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "scsi-0:0:0:0",
++                                exp_links       => ["scsi-0:0:0:0", "before"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
+@@ -711,7 +738,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "scsi-0:0:0:0",
++                                exp_links       => ["scsi-0:0:0:0", "before"],
+                         }],
+                 rules                => <<EOF
+ SUBSYSTEMS=="scsi", KERNELS=="0:0:0:0", SYMLINK+="before"
+@@ -723,7 +750,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "driver-is-sd",
++                                exp_links       => ["driver-is-sd"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", SYMLINK+="driver-is-\$attr{driver}"
+@@ -734,7 +761,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "driver-is-ahci",
++                                exp_links       => ["driver-is-ahci"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="pci", SYMLINK+="driver-is-\$attr{driver}"
+@@ -745,7 +772,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "ignored",
++                                exp_links       => ["ignored"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE  SPACE", SYMLINK+="ignored"
+@@ -756,7 +783,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "matched-with-space",
++                                exp_links       => ["matched-with-space"],
++                                not_exp_links   => ["wrong-to-ignore"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{whitespace_test}=="WHITE  SPACE ", SYMLINK+="wrong-to-ignore"
+@@ -779,7 +807,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                                 exp_perms       => "1::0600",
+                         }],
+                 rules           => <<EOF
+@@ -791,7 +819,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                                 exp_perms       => ":1:0660",
+                         }],
+                 rules           => <<EOF
+@@ -803,7 +831,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                                 exp_perms       => "daemon::0600",
+                         }],
+                 rules           => <<EOF
+@@ -815,7 +843,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                                 exp_perms       => ":daemon:0660",
+                         }],
+                 rules           => <<EOF
+@@ -827,7 +855,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                                 exp_perms       => "root:audio:0660",
+                         }],
+                 rules           => <<EOF
+@@ -839,7 +867,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                                 exp_perms       => "::0777",
+                         }],
+                 rules           => <<EOF
+@@ -851,7 +879,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                                 exp_perms       => "1:1:0777",
+                         }],
+                 rules           => <<EOF
+@@ -950,7 +978,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                                 exp_majorminor  => "8:0",
+                         }],
+                 rules           => <<EOF
+@@ -962,7 +990,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/virtual/misc/misc-fake1",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                                 exp_majorminor  => "4095:1",
+                         }],
+                 rules                => <<EOF
+@@ -974,7 +1002,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/virtual/misc/misc-fake89999",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                                 exp_majorminor  => "4095:89999",
+                         }],
+                 rules           => <<EOF
+@@ -986,7 +1014,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "symlink2-ttyACM0",
++                                exp_links       => ["symlink1-0", "symlink2-ttyACM0", "symlink3-"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK="symlink1-%n symlink2-%k symlink3-%b"
+@@ -997,8 +1025,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "one",
+-                                not_exp_name        => " ",
++                                exp_links       => ["one", "two"],
++                                not_exp_links       => [" "],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK="  one     two        "
+@@ -1009,8 +1037,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "name-one_two_three-end",
+-                                not_exp_name    => " ",
++                                exp_links       => ["name-one_two_three-end"],
++                                not_exp_links   => [" "],
+                         }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="one two three"
+@@ -1022,8 +1050,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "name-one_two_three-end",
+-                                not_exp_name    => " ",
++                                exp_links       => ["name-one_two_three-end"],
++                                not_exp_links   => [" "],
+                         }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one two three"
+@@ -1035,8 +1063,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "name-one_two_three-end",
+-                                not_exp_name    => " ",
++                                exp_links       => ["name-one_two_three-end"],
++                                not_exp_links   => [" "],
+                         }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="one two three   "
+@@ -1048,8 +1076,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "name-one_two_three-end",
+-                                not_exp_name    => " ",
++                                exp_links       => ["name-one_two_three-end"],
++                                not_exp_links   => [" "],
+                         }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one two three   "
+@@ -1061,8 +1089,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "name-one_two_three-end",
+-                                not_exp_name    => " ",
++                                exp_links       => ["name-one_two_three-end"],
++                                not_exp_links   => [" "],
+                         }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one  two  three   "
+@@ -1070,12 +1098,12 @@ SYMLINK="name-\$env{WITH_WS}-end"
+ EOF
+         },
+         {
+-                desc            => "symlink with space and var with space, part 1",
++                desc            => "symlink with space and var with space",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "first",
+-                                not_exp_name    => " ",
++                                exp_links        => ["first"],
++                                not_exp_links    => [" "],
+                         }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one  two  three   "
+@@ -1087,8 +1115,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "name-one_two_three-end",
+-                                not_exp_name    => " ",
++                                exp_links        => ["name-one_two_three-end"],
++                                not_exp_links    => [" "],
+                         }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one  two  three   "
+@@ -1100,8 +1128,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "another_symlink",
+-                                not_exp_name    => " ",
++                                exp_links        => ["another_symlink"],
++                                not_exp_links    => [" "],
+                         }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one  two  three   "
+@@ -1113,7 +1141,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "modem0",
++                                exp_links       => ["modem0"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK="modem%n"
+@@ -1124,7 +1152,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "second-0" ,
++                                exp_links       => ["first-0", "second-0", "third-0"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM0", SYMLINK="first-%n second-%n third-%n"
+@@ -1135,7 +1163,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => ".",
++                                exp_links       => ["."],
+                                 exp_add_error        => "yes",
+                                 exp_rem_error        => "yes",
+                         }],
+@@ -1148,7 +1176,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/virtual/tty/tty0",
+-                                exp_name        => "link",
++                                exp_links       => ["link"],
+                                 exp_add_error        => "yes",
+                                 exp_rem_error        => "yes",
+                         }],
+@@ -1162,7 +1190,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "symlink0",
++                                exp_links       => ["symlink0"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink%n"
+@@ -1173,7 +1201,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "symlink-ttyACM0",
++                                exp_links       => ["symlink-ttyACM0"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="symlink-%k"
+@@ -1184,7 +1212,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "major-166:0",
++                                exp_links       => ["major-166:0"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="ttyACM%n", SYMLINK+="major-%M:%m"
+@@ -1195,7 +1223,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "symlink-0:0:0:0",
++                                exp_links       => ["symlink-0:0:0:0"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="symlink-%b"
+@@ -1206,7 +1234,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "test",
++                                exp_links       => ["test"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo test", SYMLINK+="%c"
+@@ -1217,7 +1245,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "test",
++                                exp_links       => ["test"],
++                                not_exp_links   => ["symlink", "this"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2}"
+@@ -1228,7 +1257,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "this",
++                                exp_links       => ["test", "this"],
++                                not_exp_links   => ["symlink"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", PROGRAM=="/bin/echo symlink test this", SYMLINK+="%c{2+}"
+@@ -1239,7 +1269,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "test",
++                                exp_links       => ["test", "this"],
++                                not_exp_links   => ["symlink"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/bin/echo link test this" SYMLINK+="%c{2+}"
+@@ -1250,7 +1281,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "166:0",
++                                exp_links       => ["166:0"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="%s{dev}"
+@@ -1261,7 +1292,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "link1",
++                                exp_links       => ["link1", "link2"],
++                                not_exp_links   => ["node"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2", RESULT=="node *", SYMLINK+="%c{2} %c{3}"
+@@ -1272,7 +1304,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
+-                                exp_name        => "link4",
++                                exp_links       => ["link1", "link2", "link3", "link4"],
++                                not_exp_links   => ["node"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", PROGRAM=="/bin/echo -n node link1 link2 link3 link4", RESULT=="node *", SYMLINK+="%c{2+}"
+@@ -1283,7 +1316,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
++                                not_exp_links   => ["should_not_match", "should_not_match2"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", SUBSYSTEM=="vc"
+@@ -1296,7 +1330,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
++                                not_exp_links   => ["should_not_match"]
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", SYMLINK+="should_not_match", DRIVERS=="sd-wrong"
+@@ -1308,7 +1343,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node",
++                                exp_links       => ["node"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda", PROGRAM=="/usr/bin/test -b %N" SYMLINK+="node"
+@@ -1319,7 +1354,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "sda-part-1",
++                                exp_links       => ["sda-part-1"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="%P-part-1"
+@@ -1330,7 +1365,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "start-/dev-end",
++                                exp_links       => ["start-/dev-end"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="start-%r-end"
+@@ -1341,7 +1376,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "last",
++                                exp_links       => ["last"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="last", OPTIONS="last_rule"
+@@ -1353,7 +1388,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "match",
++                                exp_links       => ["match", "before"],
++                                not_exp_links   => ["matches-but-is-negated"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
+@@ -1366,7 +1402,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "not-anything",
++                                exp_links       => ["before", "not-anything"],
++                                not_exp_links   => ["matches-but-is-negated"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", SUBSYSTEM=="block", KERNEL!="sda1", SYMLINK+="matches-but-is-negated"
+@@ -1379,7 +1416,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "nonzero-program",
++                                exp_links       => ["before", "nonzero-program"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
+@@ -1391,7 +1428,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "true",
++                                exp_links       => ["true"],
++                                not_exp_links   => ["bad", "wrong"],
+                         }],
+                 rules           => <<EOF
+ ENV{ENV_KEY_TEST}="test"
+@@ -1405,7 +1443,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "true",
++                                exp_links       => ["true"],
++                                not_exp_links   => ["bad", "wrong", "no"],
+                         }],
+                 rules           => <<EOF
+ ENV{ENV_KEY_TEST}="test"
+@@ -1420,7 +1459,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "true",
++                                exp_links       => ["true", "before"],
++                                not_exp_links   => ["no"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
+@@ -1434,7 +1474,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "true",
++                                exp_links       => ["true", "before"],
++                                not_exp_links   => ["no", "bad"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
+@@ -1449,8 +1490,10 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "part",
+-                        }],
++                                exp_links       => ["part"],
++                                not_exp_links   => ["disk"],
++                        },
++                    ],
+                 rules           => <<EOF
+ SUBSYSTEM=="block", KERNEL=="*[0-9]", ENV{PARTITION}="true", ENV{MAINDEVICE}="false"
+ SUBSYSTEM=="block", KERNEL=="*[!0-9]", ENV{PARTITION}="false", ENV{MAINDEVICE}="true"
+@@ -1464,7 +1507,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "sane",
++                                exp_links       => ["sane"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e name; (/usr/bin/badprogram)", RESULT=="name_ _/usr/bin/badprogram_", SYMLINK+="sane"
+@@ -1475,7 +1518,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "uber",
++                                exp_links       => ["uber"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xc3\\xbcber" RESULT=="\xc3\xbcber", SYMLINK+="uber"
+@@ -1486,7 +1529,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "replaced",
++                                exp_links       => ["replaced"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", PROGRAM=="/bin/echo -e \\xef\\xe8garbage", RESULT=="__garbage", SYMLINK+="replaced"
+@@ -1497,7 +1540,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "serial-354172020305000",
++                                exp_links       => ["serial-354172020305000"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM*", ATTRS{serial}=="?*", SYMLINK+="serial-%s{serial}"
+@@ -1508,7 +1551,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "ok",
++                                exp_links       => ["ok"],
++                                not_exp_links   => ["not-1-ok", "not-2-ok", "not-3-ok"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", ATTRS{nothing}!="", SYMLINK+="not-1-ok"
+@@ -1522,7 +1566,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "ok",
++                                exp_links       => ["ok"],
++                                not_exp_links   => ["unknown-not-ok"],
+                         }],
+                 rules           => <<EOF
+ ACTION=="unknown", KERNEL=="sda", SYMLINK+="unknown-not-ok"
+@@ -1534,7 +1579,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "ok",
++                                exp_links       => ["ok"],
+                                 exp_perms       => "root:tty:0640",
+                         }],
+                 rules           => <<EOF
+@@ -1547,7 +1592,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "ok",
++                                exp_links       => ["ok"],
+                                 exp_perms       => "root:tty:0640",
+                         }],
+                 rules           => <<EOF
+@@ -1561,7 +1606,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "node-add-me",
++                                exp_links       => ["node-add-me"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", MODE="0666", SYMLINK+="node-\$env{ACTION}-me"
+@@ -1572,8 +1617,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "three",
+-                                not_exp_name    => "two",
++                                exp_links       => ["three"],
++                                not_exp_links   => ["two", "one"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="one"
+@@ -1586,8 +1631,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "right",
+-                                not_exp_name    => "wrong",
++                                exp_links       => ["right"],
++                                not_exp_links   => ["wrong"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM[0-9]*", SYMLINK+="wrong"
+@@ -1600,7 +1645,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "right",
++                                exp_links       => ["right", "before"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="ttyACM*", SYMLINK+="before"
+@@ -1612,7 +1657,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "right",
++                                exp_links       => ["right", "before"],
++                                not_exp_links   => ["nomatch"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="dontknow*|*nothing", SYMLINK+="nomatch"
+@@ -1625,7 +1671,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "right",
++                                exp_links       => ["right"],
++                                not_exp_links   => ["nomatch", "wrong1", "wrong2"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
+@@ -1639,7 +1686,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_name        => "right",
++                                exp_links       => ["right"],
++                                not_exp_links   => ["nomatch", "wrong1", "wrong2", "wrong3"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="dontknow|nothing", SYMLINK+="nomatch"
+@@ -1654,7 +1702,7 @@ EOF
+                devices => [
+                        {
+                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                               exp_name        => "found",
++                               exp_links       => ["found"],
+                                not_exp_name    => "bad",
+                        }],
+                 rules           => <<EOF
+@@ -1668,7 +1716,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
++                                exp_links       => ["found"],
+                                 not_exp_name    => "bad",
+                        }],
+                 rules           => <<EOF
+@@ -1682,7 +1730,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
++                                exp_links       => ["found"],
+                                 not_exp_name    => "bad",
+                         }],
+                 rules           => <<EOF
+@@ -1696,7 +1744,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
++                                exp_links       => ["found"],
+                                 not_exp_name    => "bad",
+                         }],
+                 rules           => <<EOF
+@@ -1710,7 +1758,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
++                                exp_links       => ["found"],
+                                 not_exp_name    => "bad",
+                         }],
+                 rules           => <<EOF
+@@ -1724,7 +1772,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
++                                exp_links       => ["found"],
+                                 not_exp_name    => "bad",
+                         }],
+                 rules           => <<EOF
+@@ -1738,7 +1786,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
++                                exp_links       => ["found"],
+                                 not_exp_name    => "bad",
+                         }],
+                 rules           => <<EOF
+@@ -1752,7 +1800,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "parent",
++                                exp_links       => ["parent"],
+                         }],
+                 option          => "keep",
+                 rules           => <<EOF
+@@ -1765,7 +1813,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "parentenv-parent_right",
++                                exp_links       => ["parentenv-parent_right"],
+                         }],
+                 option          => "clean",
+                 rules           => <<EOF
+@@ -1777,7 +1825,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "right",
++                                exp_links       => ["right"],
++                                not_exp_test    => ["wrong", "wrong2"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda1", GOTO="TEST"
+@@ -1794,7 +1843,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "right",
++                                exp_links       => ["right"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda1", GOTO="does-not-exist"
+@@ -1807,8 +1856,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "right",
+-                                not_exp_name    => "wrong",
++                                exp_links       => ["right", "link"],
++                                not_exp_links   => ["wrong"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda1", SYMLINK+="link"
+@@ -1821,7 +1870,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "yes",
++                                exp_links       => ["yes"],
++                                not_exp_links   => ["no"],
+                         }],
+                 rules           => <<EOF
+ KERNEL="sda1", SYMLINK+="no"
+@@ -1833,7 +1883,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "yes",
++                                exp_links       => ["yes"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", ATTR{test:colon+plus}=="?*", SYMLINK+="yes"
+@@ -1844,7 +1894,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+-                                exp_name        => "yes",
++                                exp_links       => ["yes"],
++                                not_exp_links   => ["no"],
+                         }],
+                 rules           => <<EOF
+ # 012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
+@@ -1858,7 +1909,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "00:16:41:e2:8d:ff",
++                                exp_links       => ["00:16:41:e2:8d:ff"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", SYMLINK+="\$attr{[net/eth0]address}"
+@@ -1869,7 +1920,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "there",
++                                exp_links       => ["there"],
++                                not_exp_links   => ["notthere"],
+                         }],
+                 rules           => <<EOF
+ TEST=="/etc/machine-id", SYMLINK+="there"
+@@ -1881,7 +1933,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "yes",
++                                exp_links       => ["yes"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", TEST=="[net/eth0]", SYMLINK+="yes"
+@@ -1892,7 +1944,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "relative",
++                                exp_links       => ["relative"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", TEST=="size", SYMLINK+="relative"
+@@ -1903,7 +1955,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found-subdir",
++                                exp_links       => ["found-subdir"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", TEST=="*/nr_requests", SYMLINK+="found-subdir"
+@@ -1952,7 +2004,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "sda-8741C4G-end",
++                                exp_links       => ["sda-8741C4G-end"],
+                                 exp_perms       => "0:0:0600",
+                         }],
+                 rules           => <<EOF
+@@ -1966,7 +2018,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0",
++                                exp_links       => ["disk/by-path/pci-0000:00:1f.2-scsi-0:0:0:0"],
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", IMPORT{builtin}="path_id"
+@@ -1978,8 +2030,8 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
+-                                not_exp_name    => "bad" ,
++                                exp_links       => ["found"],
++                                not_exp_links   => ["bad"],
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", TAG+="green"
+@@ -1992,7 +2044,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
++                                exp_links       => ["found"],
+                         }],
+                 rules           => $rules_10k_tags . <<EOF
+ TAGS=="test1", TAGS=="test500", TAGS=="test1234", TAGS=="test9999", TAGS=="test10000", SYMLINK+="found"
+@@ -2003,7 +2055,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
++                                exp_links       => ["found"],
+                                 not_exp_name    => "bad",
+                         }],
+                 rules           => $rules_10k_tags_continuation . <<EOF
+@@ -2026,7 +2078,7 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
++                                exp_links       => ["found"],
+                                 not_exp_name    => "bad",
+ 
+                         }],
+@@ -2046,7 +2098,7 @@ TAGS=="aaa", SYMLINK+="bad"
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+-                                exp_name        => "found",
++                                exp_links       => ["found"],
+                                 not_exp_name    => "bad",
+                         }],
+                 rules           => <<EOF
+@@ -2230,41 +2282,35 @@ sub check_devnode {
+         return $devnode;
+ }
+ 
+-sub check_add {
+-        my ($device) = @_;
+-
+-        if (defined($device->{not_exp_name})) {
+-                if ((-e "$udev_dev/$device->{not_exp_name}") ||
+-                    (-l "$udev_dev/$device->{not_exp_name}")) {
+-                        print "nonexistent: error \'$device->{not_exp_name}\' not expected to be there\n";
+-                        $error++;
+-                        sleep(1);
+-                }
+-        }
++sub get_link_target {
++        my ($link) = @_;
+ 
+-        my $devnode = check_devnode($device);
++        my $cwd = getcwd();
++        my $dir = "$udev_dev/$link";
++        my $tgt = readlink("$udev_dev/$link");
++        $dir =~ s!/[^/]*$!!;
++        $tgt = abs_path("$dir/$tgt");
++        $tgt =~ s!^$cwd/!!;
++        return $tgt;
++}
+ 
+-        return if (!defined($device->{exp_name}));
++sub check_link_add {
++        my ($link, $devnode, $err_expected) = @_;
+ 
+-        my @st = lstat("$udev_dev/$device->{exp_name}");
++        my @st = lstat("$udev_dev/$link");
+         if (-l _) {
+-                my $cwd = getcwd();
+-                my $dir = "$udev_dev/$device->{exp_name}";
+-                $dir =~ s!/[^/]*$!!;
+-                my $tgt = readlink("$udev_dev/$device->{exp_name}");
+-                $tgt = abs_path("$dir/$tgt");
+-                $tgt =~ s!^$cwd/!!;
++                my $tgt = get_link_target($link);
+ 
+                 if ($tgt ne $devnode) {
+-                        print "symlink $device->{exp_name}:         error, found -> $tgt\n";
++                        print "symlink $link:         error, found -> $tgt\n";
+                         $error++;
+                         system("tree", "$udev_dev");
+                 } else {
+-                        print "symlink $device->{exp_name}:         ok\n";
++                        print "symlink $link:         ok\n";
+                 }
+         } else {
+-                print "symlink $device->{exp_name}:         error";
+-                if ($device->{exp_add_error}) {
++                print "symlink $link:         error";
++                if ($err_expected) {
+                         print " as expected\n";
+                 } else {
+                         print "\n";
+@@ -2276,6 +2322,49 @@ sub check_add {
+         }
+ }
+ 
++sub check_link_nonexistent {
++        my ($link, $devnode, $err_expected) = @_;
++
++        if ((-e "$udev_dev/$link") || (-l "$udev_dev/$link")) {
++                my $tgt = get_link_target($link);
++
++                if ($tgt ne $devnode) {
++                        print "nonexistent: '$link' points to other device (ok)\n";
++                } else {
++                        print "nonexistent: error \'$link\' should not be there";
++                        if ($err_expected) {
++                                print " (as expected)\n";
++                        } else {
++                                print "\n";
++                                system("tree", "$udev_dev");
++                                print "\n";
++                                $error++;
++                                sleep(1);
++                        }
++                }
++        } else {
++                print "nonexistent $link:         ok\n";
++        }
++}
++
++sub check_add {
++        my ($device) = @_;
++        my $devnode = check_devnode($device);
++
++        if (defined($device->{exp_links})) {
++                foreach my $link (@{$device->{exp_links}}) {
++                        check_link_add($link, $devnode,
++                                       $device->{exp_add_error});
++                }
++        }
++        if (defined $device->{not_exp_links}) {
++                foreach my $link (@{$device->{not_exp_links}}) {
++                        check_link_nonexistent($link, $devnode,
++                                               $device->{exp_nodev_error});
++                }
++        }
++}
++
+ sub check_remove_devnode {
+         my ($device) = @_;
+         my $devnode = get_devnode($device);
+@@ -2292,17 +2381,13 @@ sub check_remove_devnode {
+         }
+ }
+ 
+-sub check_remove {
+-        my ($device) = @_;
++sub check_link_remove {
++        my ($link, $err_expected) = @_;
+ 
+-        check_remove_devnode($device);
+-
+-        return if (!defined($device->{exp_name}));
+-
+-        if ((-e "$udev_dev/$device->{exp_name}") ||
+-            (-l "$udev_dev/$device->{exp_name}")) {
+-                print "remove  $device->{exp_name}:      error";
+-                if ($device->{exp_rem_error}) {
++        if ((-e "$udev_dev/$link") ||
++            (-l "$udev_dev/$link")) {
++                print "remove  $link:      error";
++                if ($err_expected) {
+                         print " as expected\n";
+                 } else {
+                         print "\n";
+@@ -2312,7 +2397,19 @@ sub check_remove {
+                         sleep(1);
+                 }
+         } else {
+-                print "remove  $device->{exp_name}:      ok\n";
++                print "remove  $link:      ok\n";
++        }
++}
++
++sub check_remove {
++        my ($device) = @_;
++
++        check_remove_devnode($device);
++
++        return if (!defined($device->{exp_links}));
++
++        foreach my $link (@{$device->{exp_links}}) {
++                check_link_remove($link, $device->{exp_rem_error});
+         }
+ }
+ 
diff --git a/SOURCES/0531-test-udev-test.pl-fix-wrong-test-descriptions.patch b/SOURCES/0531-test-udev-test.pl-fix-wrong-test-descriptions.patch
new file mode 100644
index 0000000..9c2ee94
--- /dev/null
+++ b/SOURCES/0531-test-udev-test.pl-fix-wrong-test-descriptions.patch
@@ -0,0 +1,83 @@
+From 0e0b90ffcf0731865846bfa2754a809cc2b8c53e Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 17:57:47 +0200
+Subject: [PATCH] test/udev-test.pl: fix wrong test descriptions
+
+udev hasn't supported renaming device nodes for some time.
+
+(cherry picked from commit 46bc71b2b73f8a1e27dc5e142730e9877dd05e3e)
+
+Related: #1642728
+---
+ test/udev-test.pl | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index f5edecefd0..d5d0e130e3 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -212,7 +212,7 @@ KERNEL=="ttyACM[0-9]*", SYMLINK+="modem/%n"
+ EOF
+         },
+         {
+-                desc            => "replace kernel name",
++                desc            => "don't replace kernel name",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+@@ -223,7 +223,7 @@ KERNEL=="ttyACM0", SYMLINK+="modem"
+ EOF
+         },
+         {
+-                desc            => "Handle comment lines in config file (and replace kernel name)",
++                desc            => "Handle comment lines in config file (and don't replace kernel name)",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+@@ -236,7 +236,7 @@ KERNEL=="ttyACM0", SYMLINK+="modem"
+ EOF
+         },
+         {
+-                desc            => "Handle comment lines in config file with whitespace (and replace kernel name)",
++                desc            => "Handle comment lines in config file with whitespace (and don't replace kernel name)",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+@@ -249,7 +249,7 @@ KERNEL=="ttyACM0", SYMLINK+="modem"
+ EOF
+         },
+         {
+-                desc            => "Handle whitespace only lines (and replace kernel name)",
++                desc            => "Handle whitespace only lines (and don't replace kernel name)",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+@@ -267,7 +267,7 @@ KERNEL=="ttyACM0", SYMLINK+="whitespace"
+ EOF
+         },
+         {
+-                desc            => "Handle empty lines in config file (and replace kernel name)",
++                desc            => "Handle empty lines in config file (and don't replace kernel name)",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+@@ -280,7 +280,7 @@ KERNEL=="ttyACM0", SYMLINK+="modem"
+ EOF
+         },
+         {
+-                desc            => "Handle backslashed multi lines in config file (and replace kernel name)",
++                desc            => "Handle backslashed multi lines in config file (and don't replace kernel name)",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+@@ -303,8 +303,9 @@ EOF
+ KERNEL=="ttyACM0", PROGRAM=="/bin/echo -e \\101", RESULT=="A", SYMLINK+="aaa"
+ EOF
+         },
++        # 20
+         {
+-                desc            => "Handle stupid backslashed multi lines in config file (and replace kernel name)",
++                desc            => "Handle stupid backslashed multi lines in config file (and don't replace kernel name)",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
diff --git a/SOURCES/0532-test-udev-test.pl-last_rule-is-unsupported.patch b/SOURCES/0532-test-udev-test.pl-last_rule-is-unsupported.patch
new file mode 100644
index 0000000..72021fb
--- /dev/null
+++ b/SOURCES/0532-test-udev-test.pl-last_rule-is-unsupported.patch
@@ -0,0 +1,35 @@
+From 2d0b828715e67f7accda6f73481deb74febebcb6 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 18:08:18 +0200
+Subject: [PATCH] test/udev-test.pl: last_rule is unsupported
+
+the "last_rule" option hasn't been supported for some time.
+Therefore this test fails if a "not_exp_links" attribute is added,
+as it should be. Mark it appropriately.
+
+(cherry picked from commit 17cce031531a5d3f38a27374c99d1bdba5959dbd)
+
+Related: #1642728
+---
+ test/udev-test.pl | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index d5d0e130e3..a9c2dd95f1 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1373,11 +1373,14 @@ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="start-%r-end"
+ EOF
+         },
+         {
++                # This is not supported any more
+                 desc            => "last_rule option",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+                                 exp_links       => ["last"],
++                                not_exp_links   => ["very-last"],
++                                exp_nodev_error => "yes",
+                         }],
+                 rules           => <<EOF
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="last", OPTIONS="last_rule"
diff --git a/SOURCES/0533-test-udev-test.pl-Make-some-tests-a-little-harder.patch b/SOURCES/0533-test-udev-test.pl-Make-some-tests-a-little-harder.patch
new file mode 100644
index 0000000..5206096
--- /dev/null
+++ b/SOURCES/0533-test-udev-test.pl-Make-some-tests-a-little-harder.patch
@@ -0,0 +1,74 @@
+From 134a415c2d690e57d0f1add23e900e60bcef4627 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 18:09:50 +0200
+Subject: [PATCH] test/udev-test.pl: Make some tests a little harder
+
+Add some rules that make it a bit harder to pass, mainly the
+non-existence checks.
+
+(cherry picked from commit 06d4d4e24e7d0b51120b165e540d278842e8b1a3)
+
+Related: #1642728
+---
+ test/udev-test.pl | 13 +++++++++----
+ 1 file changed, 9 insertions(+), 4 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index a9c2dd95f1..7465b5859e 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1358,7 +1358,7 @@ EOF
+                                 exp_links       => ["sda-part-1"],
+                         }],
+                 rules           => <<EOF
+-SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="%P-part-1"
++SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="%P-part-%n"
+ EOF
+         },
+         {
+@@ -1486,6 +1486,7 @@ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="true"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}="absolutely-\$env{ASSIGN}"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", SYMLINK+="before"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="yes", SYMLINK+="no"
++SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="true", SYMLINK+="bad"
+ SUBSYSTEMS=="scsi", KERNEL=="sda1", ENV{ASSIGN}=="absolutely-true", SYMLINK+="true"
+ EOF
+         },
+@@ -1497,6 +1498,11 @@ EOF
+                                 exp_links       => ["part"],
+                                 not_exp_links   => ["disk"],
+                         },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
++                                exp_links       => ["disk"],
++                                not_exp_links   => ["part"],
++                        },
+                     ],
+                 rules           => <<EOF
+ SUBSYSTEM=="block", KERNEL=="*[0-9]", ENV{PARTITION}="true", ENV{MAINDEVICE}="false"
+@@ -1588,7 +1594,7 @@ EOF
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", GROUP:="tty"
+-KERNEL=="sda", GROUP="not-ok", MODE="0640", SYMLINK+="ok"
++KERNEL=="sda", GROUP="root", MODE="0640", SYMLINK+="ok"
+ EOF
+         },
+         {
+@@ -1602,7 +1608,7 @@ EOF
+                 rules           => <<EOF
+ KERNEL=="sda", GROUP:="tty"
+ SUBSYSTEM=="block", MODE:="640"
+-KERNEL=="sda", GROUP="not-ok", MODE="0666", SYMLINK+="ok"
++KERNEL=="sda", GROUP="root", MODE="0666", SYMLINK+="ok"
+ EOF
+         },
+         {
+@@ -1983,7 +1989,6 @@ EOF
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                                 exp_perms       => "1:1:0400",
+-                                exp_rem_error   => "yes",
+                         }],
+                 rules           => <<EOF
+ KERNEL=="sda", MODE="666"
diff --git a/SOURCES/0534-test-udev-test.pl-remove-bogus-rules-from-magic-subs.patch b/SOURCES/0534-test-udev-test.pl-remove-bogus-rules-from-magic-subs.patch
new file mode 100644
index 0000000..2694d31
--- /dev/null
+++ b/SOURCES/0534-test-udev-test.pl-remove-bogus-rules-from-magic-subs.patch
@@ -0,0 +1,28 @@
+From c63273de445789ffeea961448fda51d21c924f8c Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 18:16:59 +0200
+Subject: [PATCH] test/udev-test.pl: remove bogus rules from magic subsys test
+
+These rules have survived from an ancient version of the code
+and save no purpose any more.
+
+(cherry picked from commit 86634df43b715f3f77c7de73a3ef6566e5cdf571)
+
+Related: #1642728
+---
+ test/udev-test.pl | 2 --
+ 1 file changed, 2 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 7465b5859e..6928439d14 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -2017,8 +2017,6 @@ EOF
+                                 exp_perms       => "0:0:0600",
+                         }],
+                 rules           => <<EOF
+-KERNEL=="sda", PROGRAM="/bin/true create-envp"
+-KERNEL=="sda", ENV{TESTENV}="change-envp"
+ KERNEL=="sda", SYMLINK+="%k-%s{[dmi/id]product_name}-end"
+ EOF
+         },
diff --git a/SOURCES/0535-test-udev-test.pl-merge-space-and-var-with-space-tes.patch b/SOURCES/0535-test-udev-test.pl-merge-space-and-var-with-space-tes.patch
new file mode 100644
index 0000000..bc81f1c
--- /dev/null
+++ b/SOURCES/0535-test-udev-test.pl-merge-space-and-var-with-space-tes.patch
@@ -0,0 +1,57 @@
+From 7821ecc0b35c422bc8ed26e0e44c841d067f88d7 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 18:27:25 +0200
+Subject: [PATCH] test/udev-test.pl: merge "space and var with space" tests
+
+As we can check multiple links in a single test now, these 3
+tests can be merged into one.
+
+(cherry picked from commit 2084fe0d3290c525ecb9faa07d07c3abc2488e59)
+
+Related: #1642728
+---
+ test/udev-test.pl | 31 +++----------------------------
+ 1 file changed, 3 insertions(+), 28 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 6928439d14..880a73b10b 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1103,34 +1103,9 @@ EOF
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_links        => ["first"],
+-                                not_exp_links    => [" "],
+-                        }],
+-                rules           => <<EOF
+-ENV{WITH_WS}="   one  two  three   "
+-SYMLINK="  first  name-\$env{WITH_WS}-end another_symlink a b c "
+-EOF
+-        },
+-        {
+-                desc            => "symlink with space and var with space, part 2",
+-                devices => [
+-                        {
+-                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_links        => ["name-one_two_three-end"],
+-                                not_exp_links    => [" "],
+-                        }],
+-                rules           => <<EOF
+-ENV{WITH_WS}="   one  two  three   "
+-SYMLINK="  first  name-\$env{WITH_WS}-end another_symlink a b c "
+-EOF
+-        },
+-        {
+-                desc            => "symlink with space and var with space, part 3",
+-                devices => [
+-                        {
+-                                devpath         => "/devices/pci0000:00/0000:00:1d.7/usb5/5-2/5-2:1.0/tty/ttyACM0",
+-                                exp_links        => ["another_symlink"],
+-                                not_exp_links    => [" "],
++                                exp_links       => ["first", "name-one_two_three-end",
++                                                    "another_symlink", "a", "b", "c"],
++                                not_exp_links   => [" "],
+                         }],
+                 rules           => <<EOF
+ ENV{WITH_WS}="   one  two  three   "
diff --git a/SOURCES/0536-test-udev-test.pl-merge-import-parent-tests-into-one.patch b/SOURCES/0536-test-udev-test.pl-merge-import-parent-tests-into-one.patch
new file mode 100644
index 0000000..9713034
--- /dev/null
+++ b/SOURCES/0536-test-udev-test.pl-merge-import-parent-tests-into-one.patch
@@ -0,0 +1,53 @@
+From 06e937177bf23d8ea8e5060a856cce02d5436eb4 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 18:30:09 +0200
+Subject: [PATCH] test/udev-test.pl: merge import parent tests into one
+
+As we can test multiple devices and multiple links per device
+in one test now, these two tests can be merged into one.
+
+(cherry picked from commit a96cd21d31cb7af211862768e133b50b085634e7)
+
+Related: #1642728
+---
+ test/udev-test.pl | 17 +++++------------
+ 1 file changed, 5 insertions(+), 12 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 880a73b10b..0344d2e89c 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -1781,28 +1781,21 @@ TAGS=="aaa||bbb||ccc", SYMLINK+="bad"
+ EOF
+         },
+         {
+-                desc            => "IMPORT parent test sequence 1/2 (keep)",
++                desc            => "IMPORT parent test",
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda",
+                                 exp_links       => ["parent"],
+-                        }],
+-                option          => "keep",
+-                rules           => <<EOF
+-KERNEL=="sda", IMPORT{program}="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'"
+-KERNEL=="sda", SYMLINK+="parent"
+-EOF
+-        },
+-        {
+-                desc            => "IMPORT parent test sequence 2/2 (keep)",
+-                devices => [
++                        },
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+                                 exp_links       => ["parentenv-parent_right"],
+                         }],
+-                option          => "clean",
++                sleep_us        => 500000,  # Serialized! We need to sleep here after adding sda
+                 rules           => <<EOF
+ KERNEL=="sda1", IMPORT{parent}="PARENT*", SYMLINK+="parentenv-\$env{PARENT_KEY}\$env{WRONG_PARENT_KEY}"
++KERNEL=="sda", IMPORT{program}="/bin/echo -e \'PARENT_KEY=parent_right\\nWRONG_PARENT_KEY=parent_wrong'"
++KERNEL=="sda", SYMLINK+="parent"
+ EOF
+         },
+         {
diff --git a/SOURCES/0537-test-udev-test.pl-count-good-results.patch b/SOURCES/0537-test-udev-test.pl-count-good-results.patch
new file mode 100644
index 0000000..7a8a727
--- /dev/null
+++ b/SOURCES/0537-test-udev-test.pl-count-good-results.patch
@@ -0,0 +1,136 @@
+From 7913cdbdfe6ca3fa0a1221c60702806eb51aa707 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 20:55:01 +0200
+Subject: [PATCH] test/udev-test.pl: count "good" results
+
+This is helpful to catch possible regressions in the test.
+Also, don't count wait() errors, they are likely not udev errors.
+
+(cherry picked from commit b95c43982ab7d0253b552ad56cffb3d68fcbb4f6)
+
+Related: #1642728
+---
+ test/udev-test.pl | 17 +++++++++++++++--
+ 1 file changed, 15 insertions(+), 2 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 0344d2e89c..813be70739 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -2114,6 +2114,7 @@ sub udev {
+ }
+ 
+ my $error = 0;
++my $good = 0;
+ 
+ sub permissions_test {
+         my($rules, $uid, $gid, $mode) = @_;
+@@ -2144,6 +2145,7 @@ sub permissions_test {
+         }
+         if ($wrong == 0) {
+                 print "permissions: ok\n";
++                $good++;
+         } else {
+                 printf "  expected permissions are: %s:%s:%#o\n", $1, $2, oct($3);
+                 printf "  created permissions are : %i:%i:%#o\n", $uid, $gid, $mode & 07777;
+@@ -2169,6 +2171,7 @@ sub major_minor_test {
+         }
+         if ($wrong == 0) {
+                 print "major:minor: ok\n";
++                $good++;
+         } else {
+                 printf "  expected major:minor is: %i:%i\n", $1, $2;
+                 printf "  created major:minor is : %i:%i\n", $major, $minor;
+@@ -2254,6 +2257,7 @@ sub check_devnode {
+                 major_minor_test($device, $rdev);
+         }
+         print "add $devnode:         ok\n";
++        $good++;
+         return $devnode;
+ }
+ 
+@@ -2282,11 +2286,13 @@ sub check_link_add {
+                         system("tree", "$udev_dev");
+                 } else {
+                         print "symlink $link:         ok\n";
++                        $good++;
+                 }
+         } else {
+                 print "symlink $link:         error";
+                 if ($err_expected) {
+                         print " as expected\n";
++                        $good++;
+                 } else {
+                         print "\n";
+                         system("tree", "$udev_dev");
+@@ -2305,10 +2311,12 @@ sub check_link_nonexistent {
+ 
+                 if ($tgt ne $devnode) {
+                         print "nonexistent: '$link' points to other device (ok)\n";
++                        $good++;
+                 } else {
+                         print "nonexistent: error \'$link\' should not be there";
+                         if ($err_expected) {
+                                 print " (as expected)\n";
++                                $good++;
+                         } else {
+                                 print "\n";
+                                 system("tree", "$udev_dev");
+@@ -2319,6 +2327,7 @@ sub check_link_nonexistent {
+                 }
+         } else {
+                 print "nonexistent $link:         ok\n";
++                $good++;
+         }
+ }
+ 
+@@ -2353,6 +2362,7 @@ sub check_remove_devnode {
+                 sleep(1);
+         } else {
+                 print "remove $devnode:         ok\n";
++                $good++;
+         }
+ }
+ 
+@@ -2364,6 +2374,7 @@ sub check_link_remove {
+                 print "remove  $link:      error";
+                 if ($err_expected) {
+                         print " as expected\n";
++                        $good++;
+                 } else {
+                         print "\n";
+                         system("tree", "$udev_dev");
+@@ -2373,6 +2384,7 @@ sub check_link_remove {
+                 }
+         } else {
+                 print "remove  $link:      ok\n";
++                $good++;
+         }
+ }
+ 
+@@ -2432,7 +2444,6 @@ sub fork_and_run_udev {
+                 $pid = waitpid($dev->{pid}, 0);
+                 if ($pid == -1) {
+                         print "error waiting for pid dev->{pid}\n";
+-                        $error += 1;
+                 }
+                 if (WIFEXITED($?)) {
+                         $rc = WEXITSTATUS($?);
+@@ -2440,6 +2451,8 @@ sub fork_and_run_udev {
+                         if ($rc) {
+                                 print "$udev_bin $action for $dev->{devpath} failed with code $rc\n";
+                                 $error += 1;
++                        } else {
++                                $good++;
+                         }
+                 }
+         }
+@@ -2549,7 +2562,7 @@ if ($list[0]) {
+ }
+ 
+ $sema->remove;
+-print "$error errors occurred\n\n";
++print "$error errors occurred. $good good results.\n\n";
+ 
+ cleanup();
+ 
diff --git a/SOURCES/0538-tests-udev-test.pl-add-multiple-device-test.patch b/SOURCES/0538-tests-udev-test.pl-add-multiple-device-test.patch
new file mode 100644
index 0000000..e01add4
--- /dev/null
+++ b/SOURCES/0538-tests-udev-test.pl-add-multiple-device-test.patch
@@ -0,0 +1,199 @@
+From 8ab9d11b925e7f39b350ce69a1e28752de411b35 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 22:04:55 +0200
+Subject: [PATCH] tests/udev-test.pl: add multiple device test
+
+Add 4 new tests using multiple devices. Number 2-4 use many
+devices claiming the same symlink, where only one device has
+a higher priority thatn the others. They fail sporadically with
+the current code, if a race condition causes the symlink to point
+to the wrong device. Test 4 is like test 2 with sleeps in between,
+it's much less likely to fail.
+
+(cherry picked from commit 4a0ec82daf32446519e1d86329bb802325b82104)
+
+Related: #1642728
+---
+ test/udev-test.pl | 169 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 169 insertions(+)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 813be70739..d964c664b6 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -2085,6 +2085,175 @@ KERNEL=="sda", TAG+="aaa" \\
+ KERNEL=="sdb", TAG+="bbb"
+ TAGS=="foo", SYMLINK+="found"
+ TAGS=="aaa", SYMLINK+="bad"
++EOF
++        },
++        {
++                desc            => "multiple devices",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_links       => ["part-1"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_links       => ["part-5"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
++                                exp_links       => ["part-6"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
++                                exp_links       => ["part-7"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
++                                exp_links       => ["part-8"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
++                                exp_links       => ["part-9"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
++                                exp_links       => ["part-10"],
++                        },
++                    ],
++                rules          => <<EOF
++SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
++EOF
++        },
++        {
++                desc            => "multiple devices, same link name, positive prio",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_links       => ["part-1"],
++                                not_exp_links   => ["partition"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_links       => ["part-5"],
++                                not_exp_links   => ["partition"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-6"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
++                                exp_links       => ["part-7", "partition"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-8"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-9"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-10"],
++                        },
++                    ],
++                rules          => <<EOF
++SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
++SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="partition"
++KERNEL=="*7", OPTIONS+="link_priority=10"
++EOF
++        },
++        {
++                desc            => "multiple devices, same link name, negative prio",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_links       => ["part-1"],
++                                not_exp_links   => ["partition"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_links       => ["part-5"],
++                                not_exp_links   => ["partition"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-6"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
++                                exp_links       => ["part-7", "partition"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-8"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-9"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-10"],
++                        },
++                    ],
++                rules          => <<EOF
++SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
++SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="partition"
++KERNEL!="*7", OPTIONS+="link_priority=-10"
++EOF
++        },
++        {
++                desc            => "multiple devices, same link name, positive prio, sleep",
++                devices => [
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
++                                exp_links       => ["part-1"],
++                                not_exp_links   => ["partition"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda5",
++                                exp_links       => ["part-5"],
++                                not_exp_links   => ["partition"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda6",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-6"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda7",
++                                exp_links       => ["part-7", "partition"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda8",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-8"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda9",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-9"],
++                        },
++                        {
++                                devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda10",
++                                not_exp_links   => ["partition"],
++                                exp_links       => ["part-10"],
++                        },
++                    ],
++                sleep_us       => 10000,
++                rules          => <<EOF
++SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="part-%n"
++SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partition", SYMLINK+="partition"
++KERNEL=="*7", OPTIONS+="link_priority=10"
+ EOF
+         },
+ );
diff --git a/SOURCES/0539-test-udev-test.pl-add-repeat-count.patch b/SOURCES/0539-test-udev-test.pl-add-repeat-count.patch
new file mode 100644
index 0000000..725f7b2
--- /dev/null
+++ b/SOURCES/0539-test-udev-test.pl-add-repeat-count.patch
@@ -0,0 +1,44 @@
+From 6fba8e9a94026ee7b8791844ed1e7c6d464f7666 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Tue, 24 Apr 2018 22:24:43 +0200
+Subject: [PATCH] test/udev-test.pl: add repeat count
+
+for easier reproduction of sporadic test failures.
+
+(cherry picked from commit 2ab0a8d00bc48d3531e953d938db889d8a932d65)
+
+Related: #1642728
+---
+ test/udev-test.pl | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index d964c664b6..8b1ab3c06c 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -2125,6 +2125,7 @@ EOF
+         },
+         {
+                 desc            => "multiple devices, same link name, positive prio",
++                repeat          => 100,
+                 devices => [
+                         {
+                                 devpath         => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+@@ -2635,6 +2636,7 @@ sub run_test {
+         print "TEST $number: $rules->{desc}\n";
+         create_rules(\$rules->{rules});
+ 
++      REPEAT:
+         fork_and_run_udev("add", $rules, $sema);
+ 
+         foreach my $dev (@devices) {
+@@ -2653,6 +2655,9 @@ sub run_test {
+         }
+ 
+         print "\n";
++        if (defined($rules->{repeat}) && --($rules->{repeat}) > 0) {
++                goto REPEAT;
++        }
+ 
+         if (defined($rules->{option}) && $rules->{option} eq "clean") {
+                 udev_setup();
diff --git a/SOURCES/0540-test-udev-test.pl-generator-for-large-list-of-block-.patch b/SOURCES/0540-test-udev-test.pl-generator-for-large-list-of-block-.patch
new file mode 100644
index 0000000..02e407d
--- /dev/null
+++ b/SOURCES/0540-test-udev-test.pl-generator-for-large-list-of-block-.patch
@@ -0,0 +1,101 @@
+From 6c3191e979165700f98903b76621c214186a110c Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Wed, 25 Apr 2018 09:54:26 +0200
+Subject: [PATCH] test/udev-test.pl: generator for large list of block devices
+
+Manually listing all devices in the test definition becomes cumbersome with
+lots of devices. Add a function that scans on all block devices in
+the test sysfs and generates a list of devices to test.
+
+(cherry picked from commit eb44d715ebee2fe11288433b99f8e1dc5fdac84a)
+
+Related: #1642728
+---
+ test/udev-test.pl | 60 ++++++++++++++++++++++++++++++++++++++++++++++-
+ 1 file changed, 59 insertions(+), 1 deletion(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 8b1ab3c06c..2866fdb77a 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -50,6 +50,50 @@ for (my $i = 1; $i < 10000; ++$i) {
+ }
+ $rules_10k_tags_continuation .= "TAG+=\"test10000\"\\n";
+ 
++# Create a device list with all block devices under /sys
++# (except virtual devices and cd-roms)
++# the optional argument exp_func returns expected and non-expected
++# symlinks for the device.
++sub all_block_devs {
++        my ($exp_func) = @_;
++        my @devices;
++
++        foreach my $bd (glob "$udev_sys/dev/block/*") {
++                my $tgt = readlink($bd);
++                my ($exp, $notexp) = (undef, undef);
++
++                next if ($tgt =~ m!/virtual/! || $tgt =~ m!/sr[0-9]*$!);
++
++                $tgt =~ s!^\.\./\.\.!!;
++                ($exp, $notexp) = $exp_func->($tgt) if defined($exp_func);
++                my $device = {
++                        devpath => $tgt,
++                        exp_links => $exp,
++                        not_exp_links => $notexp,
++                };
++                push(@devices, $device);
++        }
++        return \@devices;
++}
++
++# This generator returns a suitable exp_func for use with
++# all_block_devs().
++sub expect_for_some {
++        my ($pattern, $links, $donot) = @_;
++        my $_expect = sub {
++                my ($name) = @_;
++
++                if ($name =~ /$pattern/) {
++                        return ($links, undef);
++                } elsif ($donot) {
++                        return (undef, $links);
++                } else {
++                        return (undef, undef);
++                }
++        };
++        return $_expect;
++}
++
+ my @tests = (
+         {
+                 desc            => "no rules",
+@@ -2257,6 +2301,15 @@ SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sda?*", ENV{DEVTYPE}=="partitio
+ KERNEL=="*7", OPTIONS+="link_priority=10"
+ EOF
+         },
++        {
++                desc           => 'all_block_devs',
++                generator      => expect_for_some("\\/sda6\$", ["blockdev"]),
++                repeat         => 10,
++                rules          => <<EOF
++SUBSYSTEM=="block", SUBSYSTEMS=="scsi", KERNEL=="sd*", SYMLINK+="blockdev"
++KERNEL=="sda6", OPTIONS+="link_priority=10"
++EOF
++        }
+ );
+ 
+ sub create_rules {
+@@ -2631,7 +2684,12 @@ sub fork_and_run_udev {
+ sub run_test {
+         my ($rules, $number, $sema) = @_;
+         my $rc;
+-        my @devices = @{$rules->{devices}};
++        my @devices;
++
++        if (!defined $rules->{devices}) {
++                $rules->{devices} = all_block_devs($rules->{generator});
++        }
++        @devices = @{$rules->{devices}};
+ 
+         print "TEST $number: $rules->{desc}\n";
+         create_rules(\$rules->{rules});
diff --git a/SOURCES/0541-test-udev-test.pl-suppress-umount-error-message-at-s.patch b/SOURCES/0541-test-udev-test.pl-suppress-umount-error-message-at-s.patch
new file mode 100644
index 0000000..fbe9d4b
--- /dev/null
+++ b/SOURCES/0541-test-udev-test.pl-suppress-umount-error-message-at-s.patch
@@ -0,0 +1,29 @@
+From 453df9eb2bbfa34f3e4b78e917812f0ac6958010 Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Thu, 26 Apr 2018 13:25:11 +0200
+Subject: [PATCH] test/udev-test.pl: suppress umount error message at startup
+
+umount emits an error message "no mount point specified" if the
+tmpfs isn't mounted yet, which is the normal case.
+Suppress that by redirecting stderr.
+
+(cherry picked from commit f1cb0860549e775be5f91237b5a3b97698dd14dd)
+
+Related: #1642728
+---
+ test/udev-test.pl | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 2866fdb77a..33a76ad292 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -2405,7 +2405,7 @@ sub major_minor_test {
+ }
+ 
+ sub udev_setup {
+-        system("umount", $udev_tmpfs);
++        system("umount \"$udev_tmpfs\" 2>/dev/null");
+         rmdir($udev_tmpfs);
+         mkdir($udev_tmpfs) || die "unable to create udev_tmpfs: $udev_tmpfs\n";
+ 
diff --git a/SOURCES/0542-test-udev_test.pl-add-expected-good-count.patch b/SOURCES/0542-test-udev_test.pl-add-expected-good-count.patch
new file mode 100644
index 0000000..d1f61ca
--- /dev/null
+++ b/SOURCES/0542-test-udev_test.pl-add-expected-good-count.patch
@@ -0,0 +1,78 @@
+From e0cee95e0cc401ce120a1b56cdb7a8b9afbd6bcf Mon Sep 17 00:00:00 2001
+From: Martin Wilck <mwilck@suse.com>
+Date: Thu, 26 Apr 2018 14:07:27 +0200
+Subject: [PATCH] test/udev_test.pl: add "expected good" count
+
+Since 'test/udev-test.pl: count "good" results', we know how many
+checks succeeded. Add an "expected good" count to make that number
+more meaningful.
+
+(cherry picked from commit cbeb23d863d540408cd1fb274d78213f59639df2)
+
+Related: #1642728
+---
+ test/udev-test.pl | 21 +++++++++++++++++++--
+ 1 file changed, 19 insertions(+), 2 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index 33a76ad292..cf6ca6b80c 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -2338,6 +2338,7 @@ sub udev {
+ 
+ my $error = 0;
+ my $good = 0;
++my $exp_good = 0;
+ 
+ sub permissions_test {
+         my($rules, $uid, $gid, $mode) = @_;
+@@ -2685,12 +2686,27 @@ sub run_test {
+         my ($rules, $number, $sema) = @_;
+         my $rc;
+         my @devices;
++        my $ntests;
++        my $cur_good = $good;
++        my $cur_error = $error;
+ 
+         if (!defined $rules->{devices}) {
+                 $rules->{devices} = all_block_devs($rules->{generator});
+         }
+         @devices = @{$rules->{devices}};
++        # For each device: exit status and devnode test for add & remove
++        $ntests += 4 * ($#devices + 1);
+ 
++        foreach my $dev (@devices) {
++                $ntests += 2 * ($#{$dev->{exp_links}} + 1)
++                    + ($#{$dev->{not_exp_links}} + 1)
++                    + (defined $dev->{exp_perms} ? 1 : 0)
++                    + (defined $dev->{exp_majorminor} ? 1 : 0);
++        }
++        if (defined $rules->{repeat}) {
++                $ntests *= $rules->{repeat};
++        }
++        $exp_good += $ntests;
+         print "TEST $number: $rules->{desc}\n";
+         create_rules(\$rules->{rules});
+ 
+@@ -2712,10 +2728,11 @@ sub run_test {
+                 check_remove($dev);
+         }
+ 
+-        print "\n";
+         if (defined($rules->{repeat}) && --($rules->{repeat}) > 0) {
+                 goto REPEAT;
+         }
++        printf "TEST $number: errors: %d good: %d/%d\n\n", $error-$cur_error,
++            $good-$cur_good, $ntests;
+ 
+         if (defined($rules->{option}) && $rules->{option} eq "clean") {
+                 udev_setup();
+@@ -2794,7 +2811,7 @@ if ($list[0]) {
+ }
+ 
+ $sema->remove;
+-print "$error errors occurred. $good good results.\n\n";
++print "$error errors occurred. $good/$exp_good good results.\n\n";
+ 
+ cleanup();
+ 
diff --git a/SOURCES/0543-test-udev-test-gracefully-exit-when-imports-fail.patch b/SOURCES/0543-test-udev-test-gracefully-exit-when-imports-fail.patch
new file mode 100644
index 0000000..3e5c348
--- /dev/null
+++ b/SOURCES/0543-test-udev-test-gracefully-exit-when-imports-fail.patch
@@ -0,0 +1,48 @@
+From 2e50a00f6930f1c65ca804b78f4a853e2ae2d2c0 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= <zbyszek@in.waw.pl>
+Date: Tue, 17 Nov 2020 17:13:31 +0100
+Subject: [PATCH] test/udev-test: gracefully exit when imports fail
+
+In Fedora rawhide various perl modules are now available as separate
+packages that are not pulled in by dependencies. If we don't have some
+package, skip the tests.
+
+This ugly code is apparently the way to do conditional imports:
+https://www.cs.ait.ac.th/~on/O/oreilly/perl/cookbook/ch12_03.htm.
+
+(cherry picked from commit d40763838278246e2073d15ca927ee700e583afc)
+
+Related: #1642728
+---
+ test/udev-test.pl | 18 +++++++++++++-----
+ 1 file changed, 13 insertions(+), 5 deletions(-)
+
+diff --git a/test/udev-test.pl b/test/udev-test.pl
+index cf6ca6b80c..5b1e33504e 100755
+--- a/test/udev-test.pl
++++ b/test/udev-test.pl
+@@ -18,11 +18,19 @@
+ 
+ use warnings;
+ use strict;
+-use POSIX qw(WIFEXITED WEXITSTATUS);
+-use IPC::SysV qw(IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT);
+-use IPC::Semaphore;
+-use Time::HiRes qw(usleep);
+-use Cwd qw(getcwd abs_path);
++
++BEGIN {
++    my $EXIT_TEST_SKIP = 77;
++
++    unless (eval "use POSIX qw(WIFEXITED WEXITSTATUS);
++                  use Cwd qw(getcwd abs_path);
++                  use IPC::Semaphore;
++                  use IPC::SysV qw(IPC_PRIVATE S_IRUSR S_IWUSR IPC_CREAT);
++                  use Time::HiRes qw(usleep); 1") {
++        warn "Failed to import dependencies, skipping the test: $@";
++        exit($EXIT_TEST_SKIP);
++    }
++}
+ 
+ my $udev_bin            = "./test-udev";
+ my $valgrind            = 0;
diff --git a/SPECS/systemd.spec b/SPECS/systemd.spec
index b4ce6a3..a3c4fe1 100644
--- a/SPECS/systemd.spec
+++ b/SPECS/systemd.spec
@@ -13,7 +13,7 @@
 Name:           systemd
 Url:            http://www.freedesktop.org/wiki/Software/systemd
 Version:        239
-Release:        43%{?dist}
+Release:        44%{?dist}
 # For a breakdown of the licensing, see README
 License:        LGPLv2+ and MIT and GPLv2+
 Summary:        System and Service Manager
@@ -545,6 +545,54 @@ Patch0492: 0492-introduce-setsockopt_int-helper.patch
 Patch0493: 0493-socket-util-add-generic-socket_pass_pktinfo-helper.patch
 Patch0494: 0494-core-add-new-PassPacketInfo-socket-unit-property.patch
 Patch0495: 0495-resolved-tweak-cmsg-calculation.patch
+Patch0496: 0496-ci-PowerTools-repo-was-renamed-to-powertools-in-RHEL.patch
+Patch0497: 0497-ci-use-quay.io-instead-of-Docker-Hub-to-avoid-rate-l.patch
+Patch0498: 0498-ci-move-jobs-from-Travis-CI-to-GH-Actions.patch
+Patch0499: 0499-unit-make-UNIT-cast-function-deal-with-NULL-pointers.patch
+Patch0500: 0500-use-link-to-RHEL-8-docs.patch
+Patch0501: 0501-cgroup-Also-set-blkio.bfq.weight.patch
+Patch0502: 0502-units-make-sure-initrd-cleanup.service-terminates-be.patch
+Patch0503: 0503-core-reload-SELinux-label-cache-on-daemon-reload.patch
+Patch0504: 0504-selinux-introduce-mac_selinux_create_file_prepare_at.patch
+Patch0505: 0505-selinux-add-trigger-for-policy-reload-to-refresh-int.patch
+Patch0506: 0506-udev-net_id-give-RHEL-8.4-naming-scheme-a-name.patch
+Patch0507: 0507-basic-stat-util-make-mtime-check-stricter-and-use-en.patch
+Patch0508: 0508-udev-make-algorithm-that-selects-highest-priority-de.patch
+Patch0509: 0509-test-create-dev-null-in-test-udev.pl.patch
+Patch0510: 0510-test-missing-die.patch
+Patch0511: 0511-udev-test-remove-a-check-for-whether-the-test-is-run.patch
+Patch0512: 0512-udev-test-skip-the-test-only-if-it-can-t-setup-its-e.patch
+Patch0513: 0513-udev-test-fix-test-skip-condition.patch
+Patch0514: 0514-udev-test-fix-missing-directory-test-run.patch
+Patch0515: 0515-udev-test-check-if-permitted-to-create-block-device-.patch
+Patch0516: 0516-test-udev-add-a-testcase-of-too-long-line.patch
+Patch0517: 0517-test-udev-use-proper-semantics-for-too-long-line-wit.patch
+Patch0518: 0518-test-udev-add-more-tests-for-line-continuations-and-.patch
+Patch0519: 0519-test-udev-add-more-tests-for-line-continuation.patch
+Patch0520: 0520-test-udev-fix-alignment-and-drop-unnecessary-white-s.patch
+Patch0521: 0521-test-udev-test.pl-cleanup-if-skipping-test.patch
+Patch0522: 0522-test-add-test-cases-for-empty-string-match.patch
+Patch0523: 0523-test-add-test-case-for-multi-matches-when-use.patch
+Patch0524: 0524-udev-test-do-not-rely-on-mail-group-being-defined.patch
+Patch0525: 0525-test-udev-test.pl-allow-multiple-devices-per-test.patch
+Patch0526: 0526-test-udev-test.pl-create-rules-only-once.patch
+Patch0527: 0527-test-udev-test.pl-allow-concurrent-additions-and-rem.patch
+Patch0528: 0528-test-udev-test.pl-use-computed-devnode-name.patch
+Patch0529: 0529-test-udev-test.pl-test-correctness-of-symlink-target.patch
+Patch0530: 0530-test-udev-test.pl-allow-checking-multiple-symlinks.patch
+Patch0531: 0531-test-udev-test.pl-fix-wrong-test-descriptions.patch
+Patch0532: 0532-test-udev-test.pl-last_rule-is-unsupported.patch
+Patch0533: 0533-test-udev-test.pl-Make-some-tests-a-little-harder.patch
+Patch0534: 0534-test-udev-test.pl-remove-bogus-rules-from-magic-subs.patch
+Patch0535: 0535-test-udev-test.pl-merge-space-and-var-with-space-tes.patch
+Patch0536: 0536-test-udev-test.pl-merge-import-parent-tests-into-one.patch
+Patch0537: 0537-test-udev-test.pl-count-good-results.patch
+Patch0538: 0538-tests-udev-test.pl-add-multiple-device-test.patch
+Patch0539: 0539-test-udev-test.pl-add-repeat-count.patch
+Patch0540: 0540-test-udev-test.pl-generator-for-large-list-of-block-.patch
+Patch0541: 0541-test-udev-test.pl-suppress-umount-error-message-at-s.patch
+Patch0542: 0542-test-udev_test.pl-add-expected-good-count.patch
+Patch0543: 0543-test-udev-test-gracefully-exit-when-imports-fail.patch
 
 
 %ifarch %{ix86} x86_64 aarch64
@@ -1173,6 +1221,56 @@ fi
 %files tests -f .file-list-tests
 
 %changelog
+* Thu Jan 28 2021 systemd maintenance team <systemd-maint@redhat.com> - 239-44
+- ci: PowerTools repo was renamed to powertools in RHEL 8.3 (#1871827)
+- ci: use quay.io instead of Docker Hub to avoid rate limits (#1871827)
+- ci: move jobs from Travis CI to GH Actions (#1871827)
+- unit: make UNIT() cast function deal with NULL pointers (#1871827)
+- use link to RHEL-8 docs (#1623116)
+- cgroup: Also set blkio.bfq.weight (#1657810)
+- units: make sure initrd-cleanup.service terminates before switching to rootfs (#1657810)
+- core: reload SELinux label cache on daemon-reload (#1888912)
+- selinux: introduce mac_selinux_create_file_prepare_at() (#1888912)
+- selinux: add trigger for policy reload to refresh internal selabel cache (#1888912)
+- udev/net_id: give RHEL-8.4 naming scheme a name (#1827462)
+- basic/stat-util: make mtime check stricter and use entire timestamp (#1642728)
+- udev: make algorithm that selects highest priority devlink less susceptible to race conditions (#1642728)
+- test: create /dev/null in test-udev.pl (#1642728)
+- test: missing "die" (#1642728)
+- udev-test: remove a check for whether the test is run in a container (#1642728)
+- udev-test: skip the test only if it can't setup its environment (#1642728)
+- udev-test: fix test skip condition (#1642728)
+- udev-test: fix missing directory test/run (#1642728)
+- udev-test: check if permitted to create block device nodes (#1642728)
+- test-udev: add a testcase of too long line (#1642728)
+- test-udev: use proper semantics for too long line with continuation (#1642728)
+- test-udev: add more tests for line continuations and comments (#1642728)
+- test-udev: add more tests for line continuation (#1642728)
+- test-udev: fix alignment and drop unnecessary white spaces (#1642728)
+- test/udev-test.pl: cleanup if skipping test (#1642728)
+- test: add test cases for empty string match (#1642728)
+- test: add test case for multi matches when use "||" (#1642728)
+- udev-test: do not rely on "mail" group being defined (#1642728)
+- test/udev-test.pl: allow multiple devices per test (#1642728)
+- test/udev-test.pl: create rules only once (#1642728)
+- test/udev-test.pl: allow concurrent additions and removals (#1642728)
+- test/udev-test.pl: use computed devnode name (#1642728)
+- test/udev-test.pl: test correctness of symlink targets (#1642728)
+- test/udev-test.pl: allow checking multiple symlinks (#1642728)
+- test/udev-test.pl: fix wrong test descriptions (#1642728)
+- test/udev-test.pl: last_rule is unsupported (#1642728)
+- test/udev-test.pl: Make some tests a little harder (#1642728)
+- test/udev-test.pl: remove bogus rules from magic subsys test (#1642728)
+- test/udev-test.pl: merge "space and var with space" tests (#1642728)
+- test/udev-test.pl: merge import parent tests into one (#1642728)
+- test/udev-test.pl: count "good" results (#1642728)
+- tests/udev-test.pl: add multiple device test (#1642728)
+- test/udev-test.pl: add repeat count (#1642728)
+- test/udev-test.pl: generator for large list of block devices (#1642728)
+- test/udev-test.pl: suppress umount error message at startup (#1642728)
+- test/udev_test.pl: add "expected good" count (#1642728)
+- test/udev-test: gracefully exit when imports fail (#1642728)
+
 * Thu Nov 26 2020 systemd maintenance team <systemd-maint@redhat.com> - 239-43
 - man: mention System Administrator's Guide in systemctl manpage (#1623116)
 - udev: introduce udev net_id "naming schemes" (#1827462)