From 4bfb86649d6861f1e761c602af90618ab1ec133e Mon Sep 17 00:00:00 2001 From: Ian Stakenvicius Date: Thu, 24 Sep 2015 14:01:15 -0400 Subject: [PATCH] sys-fs/eudev: add rule-generator suport for eudev-3 This commit restores rule-generator support with a patch developed upstream but not yet part of a release. If testing succeeds, the ebuild with this patch will be stabilized. A new release for ~arch will follow soon with this patch integrated. Package-Manager: portage-2.2.20.1 --- sys-fs/eudev/eudev-3.1.2-r1.ebuild | 290 +++++++ .../eudev/files/eudev-3-rule-generator.patch | 712 ++++++++++++++++++ .../eudev-3.1.2-pre-rule-generator.patch | 28 + 3 files changed, 1030 insertions(+) create mode 100644 sys-fs/eudev/eudev-3.1.2-r1.ebuild create mode 100644 sys-fs/eudev/files/eudev-3-rule-generator.patch create mode 100644 sys-fs/eudev/files/eudev-3.1.2-pre-rule-generator.patch diff --git a/sys-fs/eudev/eudev-3.1.2-r1.ebuild b/sys-fs/eudev/eudev-3.1.2-r1.ebuild new file mode 100644 index 000000000000..f999da127ad3 --- /dev/null +++ b/sys-fs/eudev/eudev-3.1.2-r1.ebuild @@ -0,0 +1,290 @@ +# Copyright 1999-2015 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id$ + +EAPI="5" + +KV_min=2.6.39 +WANT_AUTOMAKE=1.13 + +inherit autotools eutils linux-info multilib multilib-minimal user + +if [[ ${PV} = 9999* ]]; then + EGIT_REPO_URI="git://github.com/gentoo/eudev.git" + inherit git-2 +else + SRC_URI="https://dev.gentoo.org/~blueness/${PN}/${P}.tar.gz" + KEYWORDS="~alpha ~amd64 ~arm ~hppa ~ia64 ~mips ~ppc ~ppc64 ~sparc ~x86" +fi + +DESCRIPTION="Linux dynamic and persistent device naming support (aka userspace devfs)" +HOMEPAGE="https://github.com/gentoo/eudev" + +LICENSE="LGPL-2.1 MIT GPL-2" +SLOT="0" +IUSE="doc gudev +hwdb +kmod introspection rule-generator selinux static-libs test" + +COMMON_DEPEND=">=sys-apps/util-linux-2.20 + gudev? ( >=dev-libs/glib-2.34.3:2[${MULTILIB_USEDEP}] ) + introspection? ( >=dev-libs/gobject-introspection-1.38 ) + kmod? ( >=sys-apps/kmod-16 ) + selinux? ( >=sys-libs/libselinux-2.1.9 ) + !/dev/null + if [[ -d ${EROOT}dev/loop ]]; then + ewarn "Please make sure your remove /dev/loop," + ewarn "else losetup may be confused when looking for unused devices." + fi + + if use hwdb && has_version 'sys-apps/hwids[udev]'; then + udevadm hwdb --update --root="${ROOT%/}" + + # http://cgit.freedesktop.org/systemd/systemd/commit/?id=1fab57c209035f7e66198343074e9cee06718bda + # reload database after it has be rebuilt, but only if we are not upgrading + # also pass if we are -9999 since who knows what hwdb related changes there might be + if [[ ${REPLACING_VERSIONS%-r*} == ${PV} || -z ${REPLACING_VERSIONS} ]] && \ + [[ ${ROOT%/} == "" ]] && [[ ${PV} != "9999" ]]; then + udevadm control --reload + fi + fi + + ewarn + ewarn "You need to restart eudev as soon as possible to make the" + ewarn "upgrade go into effect:" + ewarn "\t/etc/init.d/udev --nodeps restart" + + if use rule-generator && \ + [[ -x $(type -P rc-update) ]] && rc-update show | grep udev-postmount | grep -qsv 'boot\|default\|sysinit'; then + ewarn + ewarn "Please add the udev-postmount init script to your default runlevel" + ewarn "to ensure the legacy rule-generator functionality works as reliably" + ewarn "as possible." + ewarn "\trc-update add udev-postmount default" + fi + + elog + elog "For more information on eudev on Gentoo, writing udev rules, and" + elog "fixing known issues visit:" + elog " https://www.gentoo.org/doc/en/udev-guide.xml" + elog + + # http://cgit.freedesktop.org/systemd/systemd/commit/rules/50-udev-default.rules?id=3dff3e00e044e2d53c76fa842b9a4759d4a50e69 + # https://bugs.gentoo.org/246847 + # https://bugs.gentoo.org/514174 + enewgroup input + + # Update hwdb database in case the format is changed by udev version. + if has_version 'sys-apps/hwids[udev]'; then + udevadm hwdb --update --root="${ROOT%/}" + # Only reload when we are not upgrading to avoid potential race w/ incompatible hwdb.bin and the running udevd + if [[ -z ${REPLACING_VERSIONS} ]]; then + # http://cgit.freedesktop.org/systemd/systemd/commit/?id=1fab57c209035f7e66198343074e9cee06718bda + if [[ ${ROOT} != "" ]] && [[ ${ROOT} != "/" ]]; then + return 0 + fi + udevadm control --reload + fi + fi +} diff --git a/sys-fs/eudev/files/eudev-3-rule-generator.patch b/sys-fs/eudev/files/eudev-3-rule-generator.patch new file mode 100644 index 000000000000..b9130663fbdd --- /dev/null +++ b/sys-fs/eudev/files/eudev-3-rule-generator.patch @@ -0,0 +1,712 @@ +commit c3e2fc597a6ba92ab9fcfd4cd7db10bc6fb5b34b +Author: Ian Stakenvicius +Date: Tue Sep 22 13:53:41 2015 -0400 + + Forward-ported network rule-generator code from eudev-1.10 + +diff --git a/Makefile.am b/Makefile.am +index 2932690..0c6429d 100644 +--- a/Makefile.am ++++ b/Makefile.am +@@ -15,3 +15,7 @@ SUBDIRS += \ + hwdb + endif + ++if ENABLE_RULE_GENERATOR ++SUBDIRS += \ ++ rule_generator ++endif +diff --git a/configure.ac b/configure.ac +index ccb1012..56d37fa 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -269,10 +269,25 @@ AC_ARG_ENABLE([hwdb], AS_HELP_STRING([--enable-hwdb],[install hwdb.d files]),[], + AM_CONDITIONAL(ENABLE_HWDB, [test "x$enable_hwdb" = "xyes"]) + + # ------------------------------------------------------------------------------ ++# rule-generator - persistent network and optical device rule generator ++# ------------------------------------------------------------------------------ ++AC_ARG_ENABLE([rule-generator], ++ AS_HELP_STRING([--enable-rule-generator], [enable legacy persistent network, cdrom support]), ++ [], [enable_rule_generator=no]) ++ ++if test "x${enable_rule_generator}" != xno; then ++ AC_DEFINE([ENABLE_RULE_GENERATOR], [1], [Define if we are enabling rule generator]) ++fi ++ ++AM_CONDITIONAL([ENABLE_RULE_GENERATOR], [test "x$enable_rule_generator" = xyes]) ++ ++# ------------------------------------------------------------------------------ + + AC_CONFIG_FILES([Makefile + hwdb/Makefile + man/Makefile ++ rule_generator/Makefile ++ rule_generator/write_net_rules + rules/Makefile + src/Makefile + src/ata_id/Makefile +diff --git a/rule_generator/75-persistent-net-generator.rules b/rule_generator/75-persistent-net-generator.rules +new file mode 100644 +index 0000000..ce59e5d +--- /dev/null ++++ b/rule_generator/75-persistent-net-generator.rules +@@ -0,0 +1,100 @@ ++# do not edit this file, it will be overwritten on update ++ ++# these rules generate rules for persistent network device naming ++# ++# variables used to communicate: ++# MATCHADDR MAC address used for the match ++# MATCHID bus_id used for the match ++# MATCHDRV driver name used for the match ++# MATCHIFTYPE interface type match ++# COMMENT comment to add to the generated rule ++# INTERFACE_NAME requested name supplied by external tool ++# INTERFACE_NEW new interface name returned by rule writer ++ ++ACTION!="add", GOTO="persistent_net_generator_end" ++SUBSYSTEM!="net", GOTO="persistent_net_generator_end" ++ ++# ignore the interface if a name has already been set ++NAME=="?*", GOTO="persistent_net_generator_end" ++ ++# device name whitelist ++KERNEL!="eth*|ath*|wlan*[0-9]|msh*|ra*|sta*|ctc*|lcs*|hsi*", GOTO="persistent_net_generator_end" ++ ++# ignore Xen virtual interfaces ++SUBSYSTEMS=="xen", GOTO="persistent_net_generator_end" ++ ++# read MAC address ++ENV{MATCHADDR}="$attr{address}" ++ ++# match interface type ++ENV{MATCHIFTYPE}="$attr{type}" ++ ++# ignore KVM virtual interfaces ++ENV{MATCHADDR}=="52:54:00:*", GOTO="persistent_net_generator_end" ++# ignore VMWare virtual interfaces ++ENV{MATCHADDR}=="00:0c:29:*|00:50:56:*", GOTO="persistent_net_generator_end" ++# ignore Hyper-V virtual interfaces ++ENV{MATCHADDR}=="00:15:5d:*", GOTO="persistent_net_generator_end" ++ ++# These vendors are known to violate the local MAC address assignment scheme ++# Interlan, DEC (UNIBUS or QBUS), Apollo, Cisco, Racal-Datacom ++ENV{MATCHADDR}=="02:07:01:*", GOTO="globally_administered_whitelist" ++# 3Com ++ENV{MATCHADDR}=="02:60:60:*", GOTO="globally_administered_whitelist" ++# 3Com IBM PC; Imagen; Valid; Cisco; Apple ++ENV{MATCHADDR}=="02:60:8c:*", GOTO="globally_administered_whitelist" ++# Intel ++ENV{MATCHADDR}=="02:a0:c9:*", GOTO="globally_administered_whitelist" ++# Olivetti ++ENV{MATCHADDR}=="02:aa:3c:*", GOTO="globally_administered_whitelist" ++# CMC Masscomp; Silicon Graphics; Prime EXL ++ENV{MATCHADDR}=="02:cf:1f:*", GOTO="globally_administered_whitelist" ++# Prominet Corporation Gigabit Ethernet Switch ++ENV{MATCHADDR}=="02:e0:3b:*", GOTO="globally_administered_whitelist" ++# BTI (Bus-Tech, Inc.) IBM Mainframes ++ENV{MATCHADDR}=="02:e6:d3:*", GOTO="globally_administered_whitelist" ++# Realtek ++ENV{MATCHADDR}=="52:54:00:*", GOTO="globally_administered_whitelist" ++# Novell 2000 ++ENV{MATCHADDR}=="52:54:4c:*", GOTO="globally_administered_whitelist" ++# Realtec ++ENV{MATCHADDR}=="52:54:ab:*", GOTO="globally_administered_whitelist" ++# Kingston Technologies ++ENV{MATCHADDR}=="e2:0c:0f:*", GOTO="globally_administered_whitelist" ++ ++# match interface dev_id ++ATTR{dev_id}=="?*", ENV{MATCHDEVID}="$attr{dev_id}" ++ ++# do not use "locally administered" MAC address ++ENV{MATCHADDR}=="?[2367abef]:*", ENV{MATCHADDR}="" ++ ++# do not use empty address ++ENV{MATCHADDR}=="00:00:00:00:00:00", ENV{MATCHADDR}="" ++ ++LABEL="globally_administered_whitelist" ++ ++# build comment line for generated rule: ++SUBSYSTEMS=="pci", ENV{COMMENT}="PCI device $attr{vendor}:$attr{device} ($driver)" ++SUBSYSTEMS=="usb", ATTRS{idVendor}=="?*", ENV{COMMENT}="USB device 0x$attr{idVendor}:0x$attr{idProduct} ($driver)" ++SUBSYSTEMS=="pcmcia", ENV{COMMENT}="PCMCIA device $attr{card_id}:$attr{manf_id} ($driver)" ++SUBSYSTEMS=="ieee1394", ENV{COMMENT}="Firewire device $attr{host_id})" ++ ++# ibmveth likes to use "locally administered" MAC addresses ++DRIVERS=="ibmveth", ENV{MATCHADDR}="$attr{address}", ENV{COMMENT}="ibmveth ($id)" ++ ++# S/390 uses id matches only, do not use MAC address match ++SUBSYSTEMS=="ccwgroup", ENV{COMMENT}="S/390 $driver device at $id", ENV{MATCHID}="$id", ENV{MATCHDRV}="$driver", ENV{MATCHADDR}="" ++ ++# see if we got enough data to create a rule ++ENV{MATCHADDR}=="", ENV{MATCHID}=="", ENV{INTERFACE_NAME}=="", GOTO="persistent_net_generator_end" ++ ++# default comment ++ENV{COMMENT}=="", ENV{COMMENT}="net device ($attr{driver})" ++ ++# write rule ++DRIVERS=="?*", IMPORT{program}="write_net_rules" ++ ++# rename interface if needed ++ENV{INTERFACE_NEW}=="?*", NAME="$env{INTERFACE_NEW}" ++ ++LABEL="persistent_net_generator_end" +diff --git a/rule_generator/Makefile.am b/rule_generator/Makefile.am +new file mode 100644 +index 0000000..8ed69f7 +--- /dev/null ++++ b/rule_generator/Makefile.am +@@ -0,0 +1,13 @@ ++ACLOCAL_AMFLAGS = -I m4 ${ACLOCAL_FLAGS} ++ ++# ------------------------------------------------------------------------------ ++# rule_generator - persistent network rule generator ++# ------------------------------------------------------------------------------ ++dist_udevlibexec_SCRIPTS = \ ++ write_net_rules ++ ++udevhomedir = $(udevlibexecdir) ++dist_udevhome_DATA = rule_generator.functions ++ ++dist_udevrules_DATA = \ ++ 75-persistent-net-generator.rules +diff --git a/rule_generator/rule_generator.functions b/rule_generator/rule_generator.functions +new file mode 100644 +index 0000000..ea02acc +--- /dev/null ++++ b/rule_generator/rule_generator.functions +@@ -0,0 +1,120 @@ ++# functions used by the udev rule generator ++ ++# Copyright (C) 2006 Marco d'Itri ++ ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 2 of the License, or ++# (at your option) any later version. ++ ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++ ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++PATH='/sbin:/bin' ++# ++ ++PATH='/sbin:/bin' ++ ++# Read a single line from file $1 in the $DEVPATH directory. ++# The function must not return an error even if the file does not exist. ++sysread() { ++ local file="$1" ++ [ -e "/sys$DEVPATH/$file" ] || return 0 ++ local value ++ read value < "/sys$DEVPATH/$file" || return 0 ++ echo "$value" ++} ++ ++sysreadlink() { ++ local file="$1" ++ [ -e "/sys$DEVPATH/$file" ] || return 0 ++ readlink -f /sys$DEVPATH/$file 2> /dev/null || true ++} ++ ++# Return true if a directory is writeable. ++writeable() { ++ if ln -s test-link $1/.is-writeable 2> /dev/null; then ++ rm -f $1/.is-writeable ++ return 0 ++ else ++ return 1 ++ fi ++} ++ ++# Create a lock file for the current rules file. ++lock_rules_file() { ++ RUNDIR="/run/udev/" ++ ++ RULES_LOCK="$RUNDIR/.lock-${RULES_FILE##*/}" ++ ++ retry=30 ++ while ! mkdir $RULES_LOCK 2> /dev/null; do ++ if [ $retry -eq 0 ]; then ++ echo "Cannot lock $RULES_FILE!" >&2 ++ exit 2 ++ fi ++ sleep 1 ++ retry=$(($retry - 1)) ++ done ++} ++ ++unlock_rules_file() { ++ [ "$RULES_LOCK" ] || return 0 ++ rmdir $RULES_LOCK || true ++} ++ ++# Choose the real rules file if it is writeable or a temporary file if not. ++# Both files should be checked later when looking for existing rules. ++choose_rules_file() { ++ RUNDIR="/run/udev/" ++ ++ local tmp_rules_file="$RUNDIR/tmp-rules--${RULES_FILE##*/}" ++ [ -e "$RULES_FILE" -o -e "$tmp_rules_file" ] || PRINT_HEADER=1 ++ ++ [ -d "${RULES_FILE%/*}" ] || if writeable ${RULES_FILE%/rules.d/*}; then ++ mkdir -p "${RULES_FILE%/*}" ++ fi ++ ++ if writeable ${RULES_FILE%/*}; then ++ RO_RULES_FILE='/dev/null' ++ else ++ RO_RULES_FILE=$RULES_FILE ++ RULES_FILE=$tmp_rules_file ++ fi ++} ++ ++# Return the name of the first free device. ++raw_find_next_available() { ++ local links="$1" ++ ++ local basename=${links%%[ 0-9]*} ++ local max=-1 ++ for name in $links; do ++ local num=${name#$basename} ++ [ "$num" ] || num=0 ++ [ $num -gt $max ] && max=$num ++ done ++ ++ local max=$(($max + 1)) ++ # "name0" actually is just "name" ++ [ $max -eq 0 ] && return ++ echo "$max" ++} ++ ++# Find all rules matching a key (with action) and a pattern. ++find_all_rules() { ++ local key="$1" ++ local linkre="$2" ++ local match="$3" ++ ++ local search='.*[[:space:],]'"$key"'"('"$linkre"')".*' ++ echo $(sed -n -r -e 's/^#.*//' -e "${match}s/${search}/\1/p" \ ++ $RO_RULES_FILE \ ++ $([ -e $RULES_FILE ] && echo $RULES_FILE) \ ++ 2>/dev/null) ++} +diff --git a/rule_generator/write_net_rules.in b/rule_generator/write_net_rules.in +new file mode 100644 +index 0000000..324e978 +--- /dev/null ++++ b/rule_generator/write_net_rules.in +@@ -0,0 +1,141 @@ ++#!/bin/sh -e ++ ++# This script is run to create persistent network device naming rules ++# based on properties of the device. ++# If the interface needs to be renamed, INTERFACE_NEW= will be printed ++# on stdout to allow udev to IMPORT it. ++ ++# variables used to communicate: ++# MATCHADDR MAC address used for the match ++# MATCHID bus_id used for the match ++# MATCHDEVID dev_id used for the match ++# MATCHDRV driver name used for the match ++# MATCHIFTYPE interface type match ++# COMMENT comment to add to the generated rule ++# INTERFACE_NAME requested name supplied by external tool ++# INTERFACE_NEW new interface name returned by rule writer ++ ++# Copyright (C) 2006 Marco d'Itri ++# Copyright (C) 2007 Kay Sievers ++# ++# This program is free software: you can redistribute it and/or modify ++# it under the terms of the GNU General Public License as published by ++# the Free Software Foundation, either version 2 of the License, or ++# (at your option) any later version. ++# ++# This program is distributed in the hope that it will be useful, ++# but WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++# GNU General Public License for more details. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program. If not, see . ++ ++# debug, if UDEV_LOG= ++if [ -n "$UDEV_LOG" ]; then ++ if [ "$UDEV_LOG" -ge 7 ]; then ++ set -x ++ fi ++fi ++ ++RULES_FILE='@udevconfdir@/rules.d/70-persistent-net.rules' ++ ++. @udevlibexecdir@/rule_generator.functions ++ ++interface_name_taken() { ++ local value="$(find_all_rules 'NAME=' $INTERFACE)" ++ if [ "$value" ]; then ++ return 0 ++ else ++ return 1 ++ fi ++} ++ ++find_next_available() { ++ raw_find_next_available "$(find_all_rules 'NAME=' "$1")" ++} ++ ++write_rule() { ++ local match="$1" ++ local name="$2" ++ local comment="$3" ++ ++ { ++ if [ "$PRINT_HEADER" ]; then ++ PRINT_HEADER= ++ echo "# This file was automatically generated by the $0" ++ echo "# program, run by the persistent-net-generator.rules rules file." ++ echo "#" ++ echo "# You can modify it, as long as you keep each rule on a single" ++ echo "# line, and change only the value of the NAME= key." ++ fi ++ ++ echo "" ++ [ "$comment" ] && echo "# $comment" ++ echo "SUBSYSTEM==\"net\", ACTION==\"add\"$match, NAME=\"$name\"" ++ } >> $RULES_FILE ++} ++ ++if [ -z "$INTERFACE" ]; then ++ echo "missing \$INTERFACE" >&2 ++ exit 1 ++fi ++ ++# Prevent concurrent processes from modifying the file at the same time. ++lock_rules_file ++ ++# Check if the rules file is writeable. ++choose_rules_file ++ ++# the DRIVERS key is needed to not match bridges and VLAN sub-interfaces ++if [ "$MATCHADDR" ]; then ++ match="$match, DRIVERS==\"?*\", ATTR{address}==\"$MATCHADDR\"" ++fi ++ ++if [ "$MATCHDRV" ]; then ++ match="$match, DRIVERS==\"$MATCHDRV\"" ++fi ++ ++if [ "$MATCHDEVID" ]; then ++ match="$match, ATTR{dev_id}==\"$MATCHDEVID\"" ++fi ++ ++if [ "$MATCHID" ]; then ++ match="$match, KERNELS==\"$MATCHID\"" ++fi ++ ++if [ "$MATCHIFTYPE" ]; then ++ match="$match, ATTR{type}==\"$MATCHIFTYPE\"" ++fi ++ ++if [ -z "$match" ]; then ++ echo "missing valid match" >&2 ++ unlock_rules_file ++ exit 1 ++fi ++ ++basename=${INTERFACE%%[0-9]*} ++match="$match, KERNEL==\"$basename*\"" ++ ++if [ "$INTERFACE_NAME" ]; then ++ # external tools may request a custom name ++ COMMENT="$COMMENT (custom name provided by external tool)" ++ if [ "$INTERFACE_NAME" != "$INTERFACE" ]; then ++ INTERFACE=$INTERFACE_NAME; ++ echo "INTERFACE_NEW=$INTERFACE" ++ fi ++else ++ # if a rule using the current name already exists, find a new name ++ if interface_name_taken; then ++ INTERFACE="$basename$(find_next_available "$basename[0-9]*")" ++ # prevent INTERFACE from being "eth" instead of "eth0" ++ [ "$INTERFACE" = "${INTERFACE%%[ \[\]0-9]*}" ] && INTERFACE=${INTERFACE}0 ++ echo "INTERFACE_NEW=$INTERFACE" ++ fi ++fi ++ ++write_rule "$match" "$INTERFACE" "$COMMENT" ++ ++unlock_rules_file ++ ++exit 0 +diff --git a/rules/Makefile.am b/rules/Makefile.am +index 2c8624f..24c099c 100644 +--- a/rules/Makefile.am ++++ b/rules/Makefile.am +@@ -15,8 +15,12 @@ dist_udevrules_DATA = \ + 70-mouse.rules \ + 75-net-description.rules \ + 75-probe_mtd.rules \ +- 78-sound-card.rules \ ++ 78-sound-card.rules ++ ++if !ENABLE_RULE_GENERATOR ++dist_udevrules_DATA += \ + 80-net-name-slot.rules ++endif + + if HAVE_BLKID + dist_udevrules_DATA += \ +diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c +index ed6f203..897f98b 100644 +--- a/src/udev/udev-event.c ++++ b/src/udev/udev-event.c +@@ -771,17 +771,17 @@ out: + return err; + } + +-static int rename_netif(struct udev_event *event) { +- struct udev_device *dev = event->dev; +- char name[IFNAMSIZ]; +- const char *oldname; ++#ifdef ENABLE_RULE_GENERATOR ++/* function to return the count of rules that assign NAME= to a value matching arg#2 , defined in udev-rules.c */ ++int udev_rules_assigning_name_to(struct udev_rules *rules,const char *match_name); ++#endif ++ ++static int rename_netif_dev_fromname_toname(struct udev_device *dev,const char *oldname,const char *name) { + int r; + int sk; + struct ifreq ifr; + +- oldname = udev_device_get_sysname(dev); +- +- strscpy(name, IFNAMSIZ, event->name); ++ log_debug("changing net interface name from '%s' to '%s'\n",oldname,name); + + sk = socket(PF_INET, SOCK_DGRAM, 0); + if (sk < 0) +@@ -791,13 +791,52 @@ static int rename_netif(struct udev_event *event) { + strscpy(ifr.ifr_name, IFNAMSIZ, oldname); + strscpy(ifr.ifr_newname, IFNAMSIZ, name); + r = ioctl(sk, SIOCSIFNAME, &ifr); +- if (r < 0) +- return log_error_errno(-errno, "Error changing net interface name '%s' to '%s': %m", oldname, name); + +- log_debug("renamed network interface '%s' to '%s'", oldname, name); ++#ifdef ENABLE_RULE_GENERATOR ++ int loop; ++ ++ if (r == 0) { ++ log_info("renamed network interface %s to %s\n", ifr.ifr_name, ifr.ifr_newname); ++ goto out; ++ } ++ /* keep trying if the destination interface name already exists */ ++ log_debug("collision on rename of network interface %s to %s , retrying until timeout\n", ++ ifr.ifr_name, ifr.ifr_newname); ++ ++ r = -errno; ++ if (r != -EEXIST) ++ goto out; ++ ++ /* wait a maximum of 90 seconds for our target to become available */ ++ loop = 90 * 20; ++ while (loop--) { ++ const struct timespec duration = { 0, 1000 * 1000 * 1000 / 20 }; ++ ++ nanosleep(&duration, NULL); ++ ++ r = ioctl(sk, SIOCSIFNAME, &ifr); ++ if (r == 0) { ++ log_info("renamed network interface %s to %s\n", ifr.ifr_name, ifr.ifr_newname); ++ break; ++ } ++ r = -errno; ++ if (r != -EEXIST) ++ break; ++ } ++ ++out: ++#endif ++ if (r < 0) ++ log_error_errno(-errno, "Error changing net interface name %s to %s: %m\n", ifr.ifr_name, ifr.ifr_newname); ++ else ++ log_debug("renamed network interface '%s' to '%s'", oldname, name); + + close(sk); +- return 0; ++ return r; ++} ++ ++static int rename_netif(struct udev_event *event) { ++ return rename_netif_dev_fromname_toname(event->dev,udev_device_get_sysname(event->dev),event->name); + } + + void udev_event_execute_rules(struct udev_event *event, +@@ -843,6 +882,79 @@ void udev_event_execute_rules(struct udev_event *event, + sigmask); + + /* rename a new network interface, if needed */ ++ ++ /* ENABLE_RULE_GENERATOR conditional: ++ * if this is a net iface, and it is an add event, ++ * and as long as all of the following are FALSE: ++ * - no NAME target and the current name is not being used ++ * - there is a NAME target and it is the same as the current name ++ * - the rules can successfully be searched for the current name (not really part of the conditional) ++ * the run the rename. ++ * ++ * note - udev_rules_assigning_name_to is run when event->name is NULL to ensure renames happen, ++ * but also on its own to check if a temp-rename is necessary when event->name exists. ++ * ++ * A temp-rename is necessary when: ++ * - there is no rule renaming the current iface but the current name IS used in some other rule ++ * - there is a rule renaming the current iface, ++ * the current name IS used AND the target name != the current name ++ */ ++ ++#ifdef ENABLE_RULE_GENERATOR ++ int r; ++ if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") && ++ (event->name == NULL && (r=udev_rules_assigning_name_to(rules,udev_device_get_sysname(dev))) > 0 || ++ event->name != NULL && !streq(event->name, udev_device_get_sysname(dev)))) { ++ char syspath[UTIL_PATH_SIZE]; ++ char *pos; ++ char *finalifname = event->name; ++ char newifname[IFNAMSIZ]; ++ ++ /* r is the number of rules that assign a device with NAME= this sysname */ ++ if (r > 0 || (r=udev_rules_assigning_name_to(rules,udev_device_get_sysname(dev))) > 0) { ++ /* have a conflict, rename to a temp name */ ++ char *newpos; ++ int ifidnum; ++ ++ /* build the temporary iface name */ ++ strscpy(newifname, IFNAMSIZ, udev_device_get_sysname(dev)); ++ newpos=pos=&newifname[strcspn(newifname,"0123456789")]; ++ ifidnum=(int)strtol(pos,&newpos,10); ++ *pos='\0'; ++ if (newpos > pos && *newpos == '\0') /* append new iface num to name */ ++ /* use udev_device_get_ifindex(dev) as it is unique to every iface */ ++ snprintf(pos,IFNAMSIZ+(newifname-pos), "%d", 128 - udev_device_get_ifindex(dev)); ++ ++ /* note, r > 0, which will skip the post-rename stuff if no rename occurs */ ++ ++ /* if sysname isn't already the tmpname (ie there is no numeric component), do the rename */ ++ if (!streq(newifname,udev_device_get_sysname(dev))) { ++ r = rename_netif_dev_fromname_toname(dev,udev_device_get_sysname(dev),newifname); ++ if (r == 0) { ++ finalifname = newifname; ++ log_debug("renamed netif to '%s' for collision avoidance\n", newifname); ++ } else { ++ log_error("could not rename netif to '%s' for collision avoidance\n",newifname); ++ } ++ } ++ /* rename it now to its final target if its not already there */ ++ if (event->name != NULL && !streq(event->name, newifname)) { ++ r = rename_netif_dev_fromname_toname(dev,newifname,event->name); ++ if (r == 0) ++ finalifname = event->name; ++ } ++ ++ } else { /* no need to rename to a tempname first, do a regular direct rename to event->name */ ++ ++ r = 1; /* skip the post-rename stuff if no rename occurs */ ++ if (!streq(event->name, udev_device_get_sysname(dev))) ++ r = rename_netif(event); ++ } ++ ++ if (r == 0) { ++ log_debug("renamed netif to '%s'\n", finalifname); ++ r = udev_device_rename(dev, finalifname); ++#else + if (udev_device_get_ifindex(dev) > 0 && streq(udev_device_get_action(dev), "add") && + event->name != NULL && !streq(event->name, udev_device_get_sysname(dev))) { + int r; +@@ -853,6 +965,7 @@ void udev_event_execute_rules(struct udev_event *event, + udev_device_get_sysname(dev), event->name); + else { + r = udev_device_rename(dev, event->name); ++#endif + if (r < 0) + log_warning_errno(r, "renamed interface '%d' from '%s' to '%s', but could not update udev_device: %m", + udev_device_get_ifindex(dev), udev_device_get_sysname(dev), event->name); +diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c +index c5e85fa..e2bb99c 100644 +--- a/src/udev/udev-rules.c ++++ b/src/udev/udev-rules.c +@@ -2755,3 +2755,69 @@ finish: + + return r; + } ++ ++#ifdef ENABLE_RULE_GENERATOR ++/* function to return the count of rules that assign NAME= to a value matching arg#2 - returns 0,1 */ ++int udev_rules_assigning_name_to(struct udev_rules *rules, const char *match_name) ++{ ++ struct token *cur; ++ struct token *rule; ++ enum escape_type esc = ESCAPE_UNSET; ++ bool name_final = false; ++ ++ if (rules->tokens == NULL) ++ return 0; ++ ++ /* loop through token list, match, run actions or forward to next rule */ ++ cur = &rules->tokens[0]; ++ rule = cur; ++ for (;;) { ++ dump_token(rules, cur); ++ switch (cur->type) { ++ case TK_RULE: ++ /* current rule */ ++ rule = cur; ++ if (!rule->rule.can_set_name) ++ goto nomatch; ++ break; ++ case TK_M_SUBSYSTEM: ++ if (match_key(rules, cur, "net") != 0) ++ goto nomatch; ++ break; ++ case TK_M_ACTION: ++ if (match_key(rules, cur, "add") != 0) ++ goto nomatch; ++ break; ++ case TK_A_NAME: { ++ const char *name = rules_str(rules, cur->key.value_off); ++ char name_str[UTIL_PATH_SIZE]; ++ int count; ++ ++ strscpy(name_str,UTIL_PATH_SIZE,name); ++ count = util_replace_chars(name_str, "/"); ++ if (count > 0) ++ log_debug("%i character(s) replaced\n", count); ++ if (streq(name_str,match_name)) { ++ log_debug("found a match! NAME assigns %s in: %s:%u\n", ++ name, ++ rules_str(rules, rule->rule.filename_off), ++ rule->rule.filename_line); ++ return 1; /* no need to find more than one */ ++ } ++ ++ /* skip to next rule */ ++ goto nomatch; ++ } ++ case TK_END: ++ return 0; ++ } ++ ++ cur++; ++ continue; ++ nomatch: ++ /* fast-forward to next rule */ ++ cur = rule + rule->rule.token_count; ++ } ++} ++#endif ++ diff --git a/sys-fs/eudev/files/eudev-3.1.2-pre-rule-generator.patch b/sys-fs/eudev/files/eudev-3.1.2-pre-rule-generator.patch new file mode 100644 index 000000000000..d66d33457296 --- /dev/null +++ b/sys-fs/eudev/files/eudev-3.1.2-pre-rule-generator.patch @@ -0,0 +1,28 @@ +Move some entries further down so that the eudev rule-generator patch applies + +--- a/configure.ac 2015-06-19 12:32:53.000000000 -0400 ++++ b/configure.ac 2015-09-24 10:41:34.630153037 -0400 +@@ -287,11 +287,6 @@ + # ------------------------------------------------------------------------------ + + AC_CONFIG_FILES([Makefile +- docs/Makefile +- docs/gudev/Makefile +- docs/gudev/version.xml +- docs/libudev/Makefile +- docs/libudev/version.xml + hwdb/Makefile + man/Makefile + rules/Makefile +@@ -310,6 +305,11 @@ + src/libudev/libudev.pc + src/udev/Makefile + src/udev/udev.pc ++ docs/Makefile ++ docs/gudev/Makefile ++ docs/gudev/version.xml ++ docs/libudev/Makefile ++ docs/libudev/version.xml + test/Makefile]) + + AC_OUTPUT -- 2.26.2