summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco d'Itri <md@Linux.IT>2006-09-05 15:20:28 +0200
committerKay Sievers <kay.sievers@suse.de>2006-09-05 15:20:28 +0200
commitfbcbf70bb21a618024ce8c1ea0b4f6718c2a8dd2 (patch)
tree215b15e195c046aae317a01db5edadde5a2e7ce1
parentd60fd52af868ec6043d9a6dc641a6a64feabd238 (diff)
add persistent rules generator for net devices and optical drives
-rw-r--r--extras/rule_generator/75-cd-aliases-generator.rules3
-rw-r--r--extras/rule_generator/75-persistent-net-generator.rules17
-rw-r--r--extras/rule_generator/Makefile68
-rw-r--r--extras/rule_generator/rule_generator.functions98
-rw-r--r--extras/rule_generator/write_cd_rules78
-rw-r--r--extras/rule_generator/write_net_rules130
-rwxr-xr-xtest/simple-build-check.sh4
7 files changed, 397 insertions, 1 deletions
diff --git a/extras/rule_generator/75-cd-aliases-generator.rules b/extras/rule_generator/75-cd-aliases-generator.rules
new file mode 100644
index 0000000000..c3eb887cb5
--- /dev/null
+++ b/extras/rule_generator/75-cd-aliases-generator.rules
@@ -0,0 +1,3 @@
+# these rules generate rules for the /dev/{cdrom,dvd,...} symlinks
+
+ACTION=="add", SUBSYSTEM=="block", ENV{ID_CDROM}=="?*", ENV{GENERATED}!="?*", PROGRAM="write_cd_rules", SYMLINK+="%c"
diff --git a/extras/rule_generator/75-persistent-net-generator.rules b/extras/rule_generator/75-persistent-net-generator.rules
new file mode 100644
index 0000000000..fdebb919bc
--- /dev/null
+++ b/extras/rule_generator/75-persistent-net-generator.rules
@@ -0,0 +1,17 @@
+# these rules generate rules for persistent network device naming
+
+ACTION=="add", SUBSYSTEM=="net", NAME!="?*", DRIVERS=="?*", GOTO="persistent_net_generator_do"
+GOTO="persistent_net_generator_end"
+
+LABEL="persistent_net_generator_do"
+# export device description to comment the generated rule
+SUBSYSTEMS=="pci", ENV{COMMENT}="PCI Device: $attr{vendor}:$attr{device} ($attr{driver})"
+SUBSYSTEMS=="usb", ENV{COMMENT}="USB Device: 0x$attr{idVendor}:0x$attr{idProduct} ($attr{driver})"
+SUBSYSTEMS=="ieee1394", ENV{COMMENT}="Firewire Device: $attr{host_id} ($attr{driver})"
+SUBSYSTEMS=="xen", ENV{COMMENT}="Xen virtual device"
+
+KERNEL=="eth*|ath*|wlan*|ra*|sta*", IMPORT{program}="write_net_rules $attr{address}"
+ENV{INTERFACE_NEW}=="?*", NAME="$env{INTERFACE_NEW}"
+
+LABEL="persistent_net_generator_end"
+
diff --git a/extras/rule_generator/Makefile b/extras/rule_generator/Makefile
new file mode 100644
index 0000000000..810be24d2b
--- /dev/null
+++ b/extras/rule_generator/Makefile
@@ -0,0 +1,68 @@
+# Makefile for udev extra invoked from the udev main Makefile
+#
+# Copyright (C) 2004-2006 Kay Sievers <kay.sievers@vrfy.org>
+#
+# Released under the GNU General Public License, version 2.
+#
+
+PROG =
+MAN_PAGES =
+
+prefix =
+etcdir = ${prefix}/etc
+sbindir = ${prefix}/sbin
+usrbindir = ${prefix}/usr/bin
+usrsbindir = ${prefix}/usr/sbin
+libudevdir = ${prefix}/lib/udev
+mandir = ${prefix}/usr/share/man
+configdir = ${etcdir}/udev
+
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+INSTALL_SCRIPT = ${INSTALL_PROGRAM}
+
+all: $(PROG) $(MAN_PAGES)
+.PHONY: all
+.DEFAULT: all
+
+# man pages
+%.8: %.xml
+ $(E) " XMLTO " $@
+ $(Q) xmlto man $?
+.PRECIOUS: %.8
+
+clean:
+ $(E) " CLEAN "
+.PHONY: clean
+
+install-bin: all
+ $(INSTALL_PROGRAM) -D rule_generator.functions $(DESTDIR)$(libudevdir)/rule_generator.functions
+ $(INSTALL_PROGRAM) -D write_cd_rules $(DESTDIR)$(libudevdir)/write_cd_rules
+ $(INSTALL_PROGRAM) -D write_net_rules $(DESTDIR)$(libudevdir)/write_net_rules
+ $(INSTALL_DATA) -D 75-cd-aliases-generator.rules \
+ $(DESTDIR)$(configdir)/rules.d/75-cd-aliases-generator.rules
+ $(INSTALL_DATA) -D 75-persistent-net-generator.rules \
+ $(DESTDIR)$(configdir)/rules.d/75-persistent-net-generator.rules
+.PHONY: install-bin
+
+uninstall-bin:
+ - rm $(DESTDIR)$(libudevdir)/rule_generator.functions
+ - rm $(DESTDIR)$(libudevdir)/write_cd_rules
+ - rm $(DESTDIR)$(libudevdir)/write_net_rules
+ - rm $(DESTDIR)$(configdir)/rules.d/75-cd-aliases-generator.rules
+ - rm $(DESTDIR)$(configdir)/rules.d/75-persistent-net-generator.rules
+.PHONY: uninstall-bin
+
+install-man:
+ @echo "Please create a man page for this tool."
+.PHONY: install-man
+
+uninstall-man:
+ @echo "Please create a man page for this tool."
+.PHONY: uninstall-man
+
+install-config:
+ @echo "no config file to install"
+.PHONY: install-config
+
diff --git a/extras/rule_generator/rule_generator.functions b/extras/rule_generator/rule_generator.functions
new file mode 100644
index 0000000000..14c585a86a
--- /dev/null
+++ b/extras/rule_generator/rule_generator.functions
@@ -0,0 +1,98 @@
+# functions used by the udev rule generator
+#
+# 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 version 2 of the License.
+
+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() {
+ [ -e /dev/.udev/ ] || return 0
+
+ RULES_LOCK="/dev/.udev/.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() {
+ local tmp_rules_file="/dev/.udev/tmp-rules--${RULES_FILE##*/}"
+ [ -e "$RULES_FILE" -o -e "$tmp_rules_file" ] || PRINT_HEADER=1
+
+ 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"
+
+ [ -e $RULES_FILE ] || return
+ local search='.*[[:space:],]'"$key"'"\('"$linkre"'\)"[[:space:]]*\(,.*\|\\\|\)$'
+ echo $(sed -n -e "${match}s/${search}/\1/p" $RO_RULES_FILE $RULES_FILE)
+}
diff --git a/extras/rule_generator/write_cd_rules b/extras/rule_generator/write_cd_rules
new file mode 100644
index 0000000000..232daeb86b
--- /dev/null
+++ b/extras/rule_generator/write_cd_rules
@@ -0,0 +1,78 @@
+#!/bin/sh -e
+
+# This script is run if an optical drive lacks a rule for persistent naming.
+#
+# It adds symlinks for optical drives based on the device class determined
+# by cdrom_id and used ID_PATH to identify the device.
+#
+# (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 version 2 of the License.
+
+RULES_FILE="/etc/udev/rules.d/70-persistent-cd.rules"
+
+. /lib/udev/rule_generator.functions
+
+find_next_available() {
+ raw_find_next_available "$(find_all_rules 'SYMLINK+=' $1)"
+}
+
+write_rule() {
+ local match="$1"
+ local link="$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 cd-aliases-generator.rules rules file."
+ echo "#"
+ echo "# You can modify it, as long as you keep each rule on a single line"
+ echo "# and set the \$GENERATED variable."
+ echo ""
+ fi
+
+ [ "$comment" ] && echo "# $comment"
+ echo "$match, SYMLINK+=\"$link\", ENV{GENERATED}=\"1\""
+ } >> $RULES_FILE
+ SYMLINKS="$SYMLINKS $link"
+}
+
+if [ -z "$DEVPATH" ]; then
+ echo "Missing \$DEVPATH." >&2
+ exit 1
+fi
+if [ -z "$ID_CDROM" ]; then
+ echo "$DEVPATH is not a CD reader." >&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
+
+link_num=$(find_next_available 'cdrom[0-9]*')
+
+match="ENV{ID_CDROM}==\"?*\", ENV{ID_PATH}==\"$ID_PATH\""
+
+comment="$ID_MODEL ($ID_PATH)"
+
+ write_rule "$match" "cdrom$link_num" "$comment"
+[ "$ID_CDROM_CD_R" -o "$ID_CDROM_CD_RW" ] && \
+ write_rule "$match" "cdrw$link_num"
+[ "$ID_CDROM_DVD" ] && \
+ write_rule "$match" "dvd$link_num"
+[ "$ID_CDROM_DVD_R" -o "$ID_CDROM_DVD_RW" -o "$ID_CDROM_DVD_RAM" ] && \
+ write_rule "$match" "dvdrw$link_num"
+
+unlock_rules_file
+
+echo $SYMLINKS
+
+exit 0
+
diff --git a/extras/rule_generator/write_net_rules b/extras/rule_generator/write_net_rules
new file mode 100644
index 0000000000..b709200a35
--- /dev/null
+++ b/extras/rule_generator/write_net_rules
@@ -0,0 +1,130 @@
+#!/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.
+#
+# (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 version 2 of the License.
+
+RULES_FILE='/etc/udev/rules.d/70-persistent-net.rules'
+
+. /lib/udev/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, 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
+}
+
+# used only if $RULES_FILE is empty, like on installation
+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
+
+ 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
+
+ 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
+
+# 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
+
+# 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
+
diff --git a/test/simple-build-check.sh b/test/simple-build-check.sh
index 6a03608477..385abbd09c 100755
--- a/test/simple-build-check.sh
+++ b/test/simple-build-check.sh
@@ -11,7 +11,9 @@ EXTRAS="\
extras/edd_id \
extras/floppy \
extras/run_directory \
- extras/firmware"
+ extras/firmware \
+ extras/path_id \
+ extras/rule_generator"
# with debug
make clean EXTRAS="$EXTRAS" >/dev/null