1#!/bin/sh -e
2#
3# This script is run if the interface (recognized by its MAC address) lacks
4# a rule for persistent naming.
5#
6# If there is already a persistent rule with that interface name then the
7# current interface needs to be renamed.
8#
9# If the interface needs to be renamed, a NAME=value pair will be printed
10# on stdout to allow udev to IMPORT it. Then a rule for the MAC address and
11# interface name is written.
12#
13# (C) 2006 Marco d'Itri <md@Linux.IT>
14#
15# This program is free software; you can redistribute it and/or modify it
16# under the terms of the GNU General Public License as published by the
17# Free Software Foundation version 2 of the License.
18
19RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules'
20
21. /lib/udev/rule_generator.functions
22
23interface_name_taken() {
24	local value="$(find_all_rules 'NAME=' $INTERFACE)"
25	if [ "$value" ]; then
26		return 0
27	else
28		return 1
29	fi
30}
31
32find_next_available() {
33	raw_find_next_available "$(find_all_rules 'NAME=' "$1")"
34}
35
36write_rule() {
37	local match="$1"
38	local name="$2"
39	local comment="$3"
40
41	{
42	if [ "$PRINT_HEADER" ]; then
43		PRINT_HEADER=
44		echo "# This file was automatically generated by the $0"
45		echo "# program, probably run by the persistent-net-generator.rules rules file."
46		echo "#"
47		echo "# You can modify it, as long as you keep each rule on a single line."
48	fi
49
50	echo ""
51	[ "$comment" ] && echo "# $comment"
52	echo "SUBSYSTEM==\"net\", $match, NAME=\"$name\""
53	} >> $RULES_FILE
54}
55
56# used only if $RULES_FILE is empty, like on installation
57if [ "$1" = "all_interfaces" ]; then
58	if [ -e $RULES_FILE ]; then
59		printf "$RULES_FILE exists, persistent interface names\nnot saved.\n" >&2
60		exit 0
61	fi
62
63	if [ ! -e /sys/class/net/ ]; then
64		echo "/sys/class/net/ is not available, persistent interface names not saved." >&2
65		exit 0
66	fi
67
68	cd /sys/class/net/ || return 0
69
70	for INTERFACE in *; do
71		case $INTERFACE in
72		eth*|ath*|wlan*|ra*|sta*) ;;
73		*) continue ;;
74		esac
75
76		INTERFACE="$INTERFACE" DEVPATH="/class/net/$INTERFACE" \
77			/lib/udev/write_net_rules || true
78	done
79
80	exit 0
81fi
82
83if [ -z "$INTERFACE" ]; then
84	echo "Missing \$INTERFACE." >&2
85	exit 1
86fi
87
88if [ "$1" ]; then
89	MAC_ADDR="$1"
90else
91	MAC_ADDR=$(sysread address)
92fi
93
94if [ -z "$MAC_ADDR" ]; then
95	echo "No MAC address for $INTERFACE." >&2
96	exit 1
97fi
98if [ "$MAC_ADDR" = "00:00:00:00:00:00" ]; then
99	echo "NULL MAC address for $INTERFACE." >&2
100	exit 1
101fi
102
103# Prevent concurrent processes from modifying the file at the same time.
104lock_rules_file
105
106# Check if the rules file is writeable.
107choose_rules_file
108
109# If a rule using the current name already exists then find a new name and
110# report it to udev which will rename the interface.
111basename=${INTERFACE%%[0-9]*}
112if interface_name_taken; then
113	INTERFACE="$basename$(find_next_available "$basename[0-9]*")"
114	if [ ! -t 1 ]; then
115		echo "INTERFACE_NEW=$INTERFACE"
116	fi
117fi
118
119# the DRIVERS key is needed to not match bridges and VLAN sub-interfaces
120match="DRIVERS==\"?*\", ATTRS{address}==\"$MAC_ADDR\""
121if [ $basename = "ath" -o $basename = "wlan" ]; then
122	match="$match, ATTRS{type}==\"1\"" # do not match the wifi* interfaces
123fi
124
125write_rule "$match" "$INTERFACE" "$COMMENT"
126
127unlock_rules_file
128
129exit 0
130
131