mirror of
https://github.com/AuxXxilium/eudev.git
synced 2024-11-23 23:10:57 +07:00
Forward-ported network rule-generator code from eudev-1.10
This commit is contained in:
parent
389b9ce228
commit
305f0eef4d
@ -15,3 +15,7 @@ SUBDIRS += \
|
||||
hwdb
|
||||
endif
|
||||
|
||||
if ENABLE_RULE_GENERATOR
|
||||
SUBDIRS += \
|
||||
rule_generator
|
||||
endif
|
||||
|
15
configure.ac
15
configure.ac
@ -268,11 +268,26 @@ AM_CONDITIONAL(HAVE_KMOD, [test "$have_kmod" = "yes"])
|
||||
AC_ARG_ENABLE([hwdb], AS_HELP_STRING([--enable-hwdb],[install hwdb.d files]),[],[enable_hwdb=yes])
|
||||
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
|
||||
|
100
rule_generator/75-persistent-net-generator.rules
Normal file
100
rule_generator/75-persistent-net-generator.rules
Normal file
@ -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"
|
13
rule_generator/Makefile.am
Normal file
13
rule_generator/Makefile.am
Normal file
@ -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
|
120
rule_generator/rule_generator.functions
Normal file
120
rule_generator/rule_generator.functions
Normal file
@ -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)
|
||||
}
|
141
rule_generator/write_net_rules.in
Normal file
141
rule_generator/write_net_rules.in
Normal file
@ -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
|
@ -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 += \
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user