#!/bin/sh -e # # This script is run if the interface (recognized by its MAC address) lacks # a rule for persistent naming. # # If there is already a persistent rule with that interface name then the # current interface needs to be renamed. # If the interface needs to be renamed, a NAME=value pair will be printed # on stdout to allow udev to IMPORT it # # Then a rule for the MAC address and interface name is written. RULES_FILE='/etc/udev/rules.d/z25_persistent-net.rules' . /lib/udev/hotplug.functions ############################################################################## device_description() { local bus=$(sysreadlink device/bus) bus=${bus##*/} if [ "$bus" = pci ]; then local vendor_id=$(sysread device/vendor) local device_id=$(sysread device/device) echo -n "PCI device ${vendor_id#0x}:${device_id#0x}" elif [ "$bus" = usb ]; then local device=$(sysreadlink device) if [ "$device" -a -e $device/../idVendor ]; then local idVendor idProduct read idVendor < $device/../idVendor || true read idProduct < $device/../idProduct || true printf 'USB device %x/%x' 0x$idVendor 0x$idProduct else echo -n "UNKNOWN USB device ($DEVPATH)" fi elif [ "$bus" = ieee1394 ]; then local hostid=$(sysreadlink device/host_id) if [ "$hostid" ]; then hostid=${hostid##*/} echo -n "FireWire host adapter $hostid ($DEVPATH)" else echo -n "UNKNOWN FireWire device ($DEVPATH)" fi elif [ "$bus" = xen ]; then echo -n "Xen virtual interface" elif [ "$bus" ]; then echo -n "UNKNOWN $bus device ($DEVPATH)" else echo -n "UNKNOWN device ($DEVPATH)" fi local driver=$(sysreadlink device/driver) if [ "$driver" ]; then echo -n " (${driver##*/})"; fi } ############################################################################## 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, probably 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 line." fi echo "" [ "$comment" ] && echo "# $comment" echo "SUBSYSTEM==\"net\", $match, NAME=\"$name\"" } >> $RULES_FILE } write_all_rules() { cd /sys/class/net/ || return 0 for INTERFACE in *; do case $INTERFACE in eth*|ath*|wlan*|ra*|sta*) ;; *) continue ;; esac INTERFACE="$INTERFACE" DEVPATH="/class/net/$INTERFACE" \ /lib/udev/write_net_rules || true done } ############################################################################## # can be used only if $RULES_FILE is empty if [ "$1" = "all_interfaces" ]; then if [ -e $RULES_FILE ]; then printf "$RULES_FILE exists, persistent interface names\nnot saved.\n" >&2 exit 0 fi if [ ! -e /sys/class/net/ ]; then echo "/sys/class/net/ is not available, persistent interface names not saved." >&2 exit 0 fi write_all_rules exit 0 fi if [ -z "$INTERFACE" ]; then echo "Missing \$INTERFACE." >&2 exit 1 fi if [ "$1" ]; then MAC_ADDR="$1" else MAC_ADDR=$(sysread address) fi if [ -z "$MAC_ADDR" ]; then echo "No MAC address for $INTERFACE." >&2 exit 1 fi if [ "$MAC_ADDR" = "00:00:00:00:00:00" ]; then echo "NULL MAC address for $INTERFACE." >&2 exit 1 fi # Exit if the rules file should not be written yet. abort_if_run_early # Prevent concurrent processes from modifying the file at the same time. lock_rules_file # Check if the rules file is writeable. choose_rules_file # If a rule using the current name already exists then find a new name and # report it to udev which will rename the interface. basename=${INTERFACE%%[0-9]*} if interface_name_taken; then INTERFACE="$basename$(find_next_available "$basename[0-9]*")" if [ ! -t 1 ]; then echo "INTERFACE_NEW=$INTERFACE" fi fi comment=$(device_description) # the DRIVERS key is needed to not match bridges and VLAN sub-interfaces match="DRIVERS==\"?*\", ATTRS{address}==\"$MAC_ADDR\"" if [ $basename = "ath" -o $basename = "wlan" ]; then match="$match, ATTRS{type}==\"1\"" # do not match the wifi* interfaces fi write_rule "$match" "$INTERFACE" "$comment" unlock_rules_file exit 0