#!/bin/sh ################################################################################ # Except for any bugs, it should be able to cope with the following scenarios: # # 1) One NIC, no kernel parameters: # It'll use DHCP. # 2) One NIC, static ip=::::::: # It'll use the static IP. # 3) One NIC, IPAPPEND 1 or 3 or ip=:::: # It'll use the static IP. # 4) One NIC, incomplete ip=::::::: # It'll use DHCP but override server-ip and hostname with the static ones. # 5) One NIC, IPAPPEND 1 or 3 and autoconf=dhcp: # It'll use DHCP (requesting the provided ip but accepting whatever the DHCP # server provides) but override server-ip and hostname with the static ones. # # 6) Two or more NICs, no kernel parameters: # It'll use DHCP on all NICs, and use the first one that got a lease. # 7) Two or more NICs, IPAPPEND 2 or BOOTIF=<01-mac-address> or : # It'll use DHCP on the specified NIC. # 8) Two or more NICs, IPAPPEND 3 or static ip along with BOOTIF or : # It'll use the static IP on the specified device. # 9) Two or more NICs, incomplete ip=::::::: # It'll use DHCP on the specified device but override server-ip and hostname with the static ones. #10) Two or more NICs, IPAPPEND 3 and autoconf=dhcp: # It'll use DHCP on the specified NIC and override server-ip and hostname with the static ones. ################################################################################ PREREQ="" prereqs() { echo "$PREREQ" } case "$1" in prereqs) prereqs exit 0 ;; esac # Exit if an LTSP boot was not requested grep -qs "init=/sbin/init-ltsp" /proc/cmdline || exit 0 . /scripts/functions bring_up_interfaces() { local i j # Wait for a network interface to become available i=0 while i=$(($i+1)); do if [ -n "$(ip -oneline link show | sed -n '/ether/s/[0-9 :]*\([^:]*\).*/\1/p')" ]; then break elif [ $i -ge 30 ]; then # After a while, give a shell to the user in case he can fix it panic "No network interfaces found" i=0 else sleep 1 fi done # Wait for a network interface to be up i=0 while i=$(($i+1)); do # Bring up the interfaces. Note that more interfaces may become # available progressively, so `ip link show` needs to be re-run. for j in $(ip -oneline link show | sed -n '/ether/s/[0-9 :]*\([^:]*\).*/\1/p'); do ip link set dev $j up done # Check if an interface is up if ip -oneline link show up | grep -vw lo | grep -q LOWER_UP; then break elif [ $i -ge 30 ]; then # After a while, give a shell to the user in case he can fix it panic "No network interfaces are up" i=0 else sleep 1 fi done } # Analyze whatever information was provided in the kernel command line process_kernel_parameters() { # "BOOTIF" can be passed manually or by IPAPPEND 2/3 # Form: BOOTIF=01-1a-2b-3c-4d-5e-6f, where 01=the ARP type code for ethernet # http://syslinux.zytor.com/wiki/index.php/SYSLINUX#IPAPPEND_flag_val_.5BPXELINUX_only.5D if [ -n "$BOOTIF" ]; then mac=$(echo $BOOTIF | sed -n 's/..-\(.*\)/\1/;y/ABCDEF-/abcdef:/p') interface=$(ip -oneline link show | sed -n "/ether $mac"'/{s/[0-9 :]*\([^:]*\).*/\1/p;q};') fi # "IP" can be passed manually or by IPAPPEND 1/3 # Form: ip=:::::: # http://www.kernel.org/doc/Documentation/filesystems/nfsroot.txt # Older initramfs-tools set "ip", newer set "IP". IP=${IP:-$ip} case "$IP" in "") ;; # If the user just specified e.g. ip=dhcp off|static|none|rarp|bootp|dhcp|both|all) autoconf="$IP" ;; *) local oldifs="${IFS-not set}" IFS=':' read ip tftp router subnet hostname new_interface new_autoconf< /tmp/dhcp-info.conf for var in bootfile bootsize broadcast dns domain hostname ipttl lease lprsrv \ message msstaticroutes mtu nisdomain nissrv ntpsrv rootpath router routes \ search serverid sipsrv staticroutes subnet swapsrv tftp timezone wins wpad \ boot_file interface ip mask siaddr; do eval value=\"\$$var\" if [ -n "$value" ]; then echo $var="\"$value\"" >> /tmp/dhcp-info.conf fi done' > /tmp/dhcp-script.sh chmod +x /tmp/dhcp-script.sh } do_dhcp() { hostname_param=${hostname:+"-h $hostname"} ip_param=${ip:+"-r $ip"} # If a specific interface wasn't provided, try all of the connected ones if [ -n "$interface" ]; then interfaces=$interface else interfaces=$(ip -oneline link show | grep LOWER_UP | sed -n '/ether/s/[0-9 :]*\([^:]*\).*/\1/p') fi # Clear screen when quiet to dampen some noise [ "$quiet" = "y" ] && clear while [ -z "$configured" ]; do for i in $interfaces; do # Make a DHCP request for each interface [ "$quiet" != "y" ] && echo "DHCP request for $i..." if udhcpc -n -C -O rootpath -s /tmp/dhcp-script.sh -i $i $hostname_param $ip_param >/dev/null 2>&1; then configured="true" break fi done done [ "$quiet" != "y" ] && echo "Done." # Source the generated dhcp-info.conf file which contains the dhcp variables. # But assume that the command-line-provided server and hostname take precedence. k_tftp="$tftp" k_hostname="$hostname" . /tmp/dhcp-info.conf tftp=${k_tftp:-$tftp} hostname=${k_hostname:-$hostname} } sanitize_configuration() { # $interface may not be defined if a static IP is desired; in this case, use the first one # TODO: it would be good if we could prefer the interface with a connected cable... # TODO: The $DEVICE that was set by initramfs.conf is not exported by init, is that by design? interface=${interface:-$(ip -oneline link show | sed -n '/ether/{s/[0-9 :]*\([^:]*\).*/\1/p;q};')} bootfile=${bootfile:-$boot_file} # There are 2 bootfile options in DHCP boot_file=$bootfile tftp=${tftp:-$siaddr} tftp=${tftp:-$sname} tftp=${tftp:-$serverid} # Ensure a default rootpath if it doesn't exist if [ -z "$rootpath" ]; then rootpath=$(echo "$BOOT_IMAGE" | awk -F / '{ if (NF>1) print $(NF-1) }') if [ -z "$rootpath" ] && [ -f /conf/arch.conf ]; then rootpath=$(. /conf/arch.conf; echo "$DPKG_ARCH") fi rootpath=/opt/ltsp/${rootpath:-i386} fi } # Converts a decimal subnet mask to the bit count needed for the CIDR notation subnet_to_cidr() { local bits=32 local oldifs="${IFS-not set}" IFS='.' for byte in $1; do byte=$((255-$byte)) while [ $byte -gt 0 ]; do bits=$(($bits-1)) byte=$(($byte/2)) done done test "$oldifs" = "not set" && unset IFS || IFS="$oldifs" echo $bits } apply_configuration() { [ -z "$ip" -o -z "$tftp" -o -z "$subnet" ] && exit ip address add $ip/$(subnet_to_cidr $subnet) broadcast ${broadcast:-+} dev $interface for i in $router do ip route add default via $i dev $interface done if [ -n "$hostname" ]; then echo "$hostname" > /proc/sys/kernel/hostname fi [ "$quiet" != "y" ] && echo "$interface configured at $ip:$tftp:$router:$subnet:$hostname" } export_configuration() { # Ensure that /run exists, otherwise older versions may fail. mkdir -p /run # dns and router may contain multiple values read dns0 dns1 rest_dns < /run/net-$interface.conf # Also make a /tmp symlink for backwards compatibility ln -sf /run/net-$interface.conf /tmp/net-$interface.conf # Write the file that'll be sourced by the callee function run_scripts mkdir -p /conf # Only export the lines that have something after the = sed -n "/[^=]*=[' ]*$/!s/.*/export &/p" "/run/net-$interface.conf" > /conf/param.conf } # Main [ "$xtrace" = "udhcp" ] && set -x # Provide a kernel parameter to enable tracing . /scripts/functions bring_up_interfaces process_kernel_parameters if dhcp_needed; then [ -x "/sbin/udhcpc" ] || exit # But do handle any static IP requests generate_dhcp_script do_dhcp fi sanitize_configuration apply_configuration export_configuration