#!/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/z25_persistent-net.rules'

. /lib/udev/hotplug.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."
    echo "# MAC addresses must be written in lowercase."
  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

# 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

