]> git.ipfire.org Git - thirdparty/dracut.git/blob - modules.d/35network-legacy/dhcp-multi.sh
788984b57b835099b2e44b1c4f63a26c26cba14f
[thirdparty/dracut.git] / modules.d / 35network-legacy / dhcp-multi.sh
1 #!/bin/sh
2 # -*- mode: shell-script; indent-tabs-mode: nil; sh-basic-offset: 4; -*-
3 # ex: ts=8 sw=4 sts=4 et filetype=sh
4 #
5 PATH=/usr/sbin:/usr/bin:/sbin:/bin
6
7 # File to start dhclient requests on different interfaces in parallel
8
9 . /lib/dracut-lib.sh
10 . /lib/net-lib.sh
11
12 netif=$1
13 do_vlan=$2
14 arg=$3
15
16 # Run dhclient in parallel
17 do_dhclient() {
18 local _COUNT=0
19 local _timeout
20 local _DHCPRETRY
21 _timeout=$(getarg rd.net.timeout.dhcp=)
22 _DHCPRETRY=$(getargnum 1 1 1000000000 rd.net.dhcp.retry=)
23
24 if [ -n "$_timeout" ]; then
25 if ! (dhclient --help 2>&1 | grep -q -F -- '--timeout' 2> /dev/null); then
26 warn "rd.net.timeout.dhcp has no effect because dhclient does not implement the --timeout option"
27 unset _timeout
28 fi
29 fi
30
31 while [ $_COUNT -lt "$_DHCPRETRY" ]; do
32 info "Starting dhcp for interface $netif"
33 dhclient "$arg" \
34 ${_timeout:+--timeout "$_timeout"} \
35 -q \
36 -1 \
37 -cf /etc/dhclient.conf \
38 -pf /tmp/dhclient."$netif".pid \
39 -lf /tmp/dhclient."$netif".lease \
40 "$netif" &
41 wait $! 2> /dev/null
42
43 # wait will return the return value of dhclient
44 retv=$?
45
46 # dhclient and hence wait returned success, 0.
47 if [ $retv -eq 0 ]; then
48 return 0
49 fi
50
51 # If dhclient exited before wait was called, or it was killed by
52 # another thread for interface whose DHCP succeeded, then it will not
53 # find the process with that pid and return error code 127. In that
54 # case we need to check if /tmp/dhclient.$netif.lease exists. If it
55 # does, it means dhclient finished executing before wait was called,
56 # and it was successful (return 0). If /tmp/dhclient.$netif.lease
57 # does not exist, then it means dhclient was killed by another thread
58 # or it finished execution but failed dhcp on that interface.
59
60 if [ $retv -eq 127 ]; then
61 read -r pid < /tmp/dhclient."$netif".pid
62 info "PID $pid was not found by wait for $netif"
63 if [ -e /tmp/dhclient."$netif".lease ]; then
64 info "PID $pid not found but DHCP successful on $netif"
65 return 0
66 fi
67 fi
68
69 _COUNT=$((_COUNT + 1))
70 [ $_COUNT -lt "$_DHCPRETRY" ] && sleep 1
71 done
72 warn "dhcp for interface $netif failed"
73 # nuke those files since we failed; we might retry dhcp again if it's e.g.
74 # `ip=dhcp,dhcp6` and we check for the PID file earlier
75 rm -f /tmp/dhclient."$netif".pid /tmp/dhclient."$netif".lease
76 return 1
77 }
78
79 do_dhclient
80 ret=$?
81
82 # setup nameserver
83 for s in "$dns1" "$dns2" $(getargs nameserver); do
84 [ -n "$s" ] || continue
85 echo nameserver "$s" >> /tmp/net."$netif".resolv.conf
86 done
87
88 if [ $ret -eq 0 ]; then
89 : > /tmp/net."${netif}".up
90
91 if [ -z "$do_vlan" ] && [ -e /sys/class/net/"${netif}"/address ]; then
92 : > "/tmp/net.$(cat /sys/class/net/"${netif}"/address).up"
93 fi
94
95 # Check if DHCP also suceeded on another interface before this one.
96 # We will always use the first one on which DHCP succeeded, by using
97 # a commom file $IFNETFILE, to synchronize between threads.
98 # Consider the race condition in which multiple threads
99 # corresponding to different interfaces may try to read $IFNETFILE
100 # and find it does not exist; they may all end up thinking they are the
101 # first to succeed (hence more than one thread may end up writing to
102 # $IFNETFILE). To take care of this, instead of checking if $IFNETFILE
103 # exists to determine if we are the first, we create a symbolic link
104 # in $IFNETFILE, pointing to the interface name ($netif), thus storing
105 # the interface name in the link pointer.
106 # Creating a link will fail, if the link already exists, hence kernel
107 # will take care of allowing only first thread to create link, which
108 # takes care of the race condition for us. Subsequent threads will fail.
109 # Also, the link points to the interface name, which will tell us which
110 # interface succeeded.
111
112 if ln -s "$netif" "$IFNETFILE" 2> /dev/null; then
113 intf=$(readlink "$IFNETFILE")
114 if [ -e /tmp/dhclient."$intf".lease ]; then
115 info "DHCP successful on interface $intf"
116 # Kill all existing dhclient calls for other interfaces, since we
117 # already got one successful interface
118
119 read -r npid < /tmp/dhclient."$netif".pid
120 pidlist=$(pgrep dhclient)
121 for pid in $pidlist; do
122 [ "$pid" -eq "$npid" ] && continue
123 kill -9 "$pid" > /dev/null 2>&1
124 done
125 else
126 echo "ERROR! $IFNETFILE exists but /tmp/dhclient.$intf.lease does not exist!!!"
127 fi
128 else
129 info "DHCP success on $netif, and also on $intf"
130 exit 0
131 fi
132 exit $ret
133 fi