summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac15
-rw-r--r--rule_generator/75-persistent-net-generator.rules100
-rw-r--r--rule_generator/Makefile.am13
-rw-r--r--rule_generator/rule_generator.functions120
-rw-r--r--rule_generator/write_net_rules.in141
-rw-r--r--rules/Makefile.am6
-rw-r--r--src/udev/udev-event.c135
-rw-r--r--src/udev/udev-rules.c66
9 files changed, 588 insertions, 12 deletions
diff --git a/Makefile.am b/Makefile.am
index 29326906a3..0c6429df60 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 ccb1012d57..56d37fa113 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 0000000000..ce59e5d82b
--- /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 0000000000..8ed69f70eb
--- /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 0000000000..ea02acc4c7
--- /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 <md@Linux.IT>
+
+# 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 <http://www.gnu.org/licenses/>.
+
+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 0000000000..324e97821c
--- /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=<name> 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 <md@Linux.IT>
+# Copyright (C) 2007 Kay Sievers <kay.sievers@vrfy.org>
+#
+# 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 <http://www.gnu.org/licenses/>.
+
+# debug, if UDEV_LOG=<debug>
+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 2c8624fff1..24c099ca72 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 ed6f203ce7..897f98b321 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 c5e85faaaf..e2bb99ca7d 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
+