Update to dhcpcd-9.4.0 with the following changes:
[dragonfly.git] / contrib / dhcpcd / hooks / dhcpcd-run-hooks.in
1 #!/bin/sh
2 # dhcpcd client configuration script 
3
4 # Handy variables and functions for our hooks to use
5 ifname="$interface${protocol+.}$protocol"
6 from=from
7 signature_base="# Generated by dhcpcd"
8 signature="$signature_base $from $ifname"
9 signature_base_end="# End of dhcpcd"
10 signature_end="$signature_base_end $from $ifname"
11 state_dir=@RUNDIR@/hook-state
12 _detected_init=false
13
14 : ${if_up:=false}
15 : ${if_down:=false}
16 : ${syslog_debug:=false}
17
18 # Ensure that all arguments are unique
19 uniqify()
20 {
21         result=
22         for i do
23                 case " $result " in
24                         *" $i "*);;
25                         *) result="$result${result:+ }$i";;
26                 esac
27         done
28         echo "$result"
29 }
30
31 # List interface config files in a directory.
32 # If dhcpcd is running as a single instance then it will have a list of
33 # interfaces in the preferred order.
34 # Otherwise we just use what we have.
35 list_interfaces()
36 {
37         ifaces=
38         for i in $interface_order; do
39                 for x in "$1"/$i.*; do
40                         [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
41                 done
42         done
43         for x in "$1"/*; do
44                 [ -f "$x" ] && ifaces="$ifaces${ifaces:+ }${x##*/}"
45         done
46         uniqify $ifaces
47 }
48
49 # Trim function
50 trim()
51 {
52         var="$*"
53         var=${var#"${var%%[![:space:]]*}"}
54         var=${var%"${var##*[![:space:]]}"}
55         if [ -z "$var" ]; then
56                 # So it seems our shell doesn't support wctype(3) patterns
57                 # Fall back to sed
58                 var=$(echo "$*" | sed -e 's/^[[:space:]]*//;s/[[:space:]]*$//')
59         fi
60         printf %s "$var"
61 }
62
63 # We normally use sed to extract values using a key from a list of files
64 # but sed may not always be available at the time.
65 key_get_value()
66 {
67         key="$1"
68         shift
69
70         if type sed >/dev/null 2>&1; then
71                 sed -n "s/^$key//p" $@
72         else
73                 for x do
74                         while read line; do
75                                 case "$line" in
76                                 "$key"*) echo "${line##$key}";;
77                                 esac
78                         done < "$x"
79                 done
80         fi
81 }
82
83 # We normally use sed to remove markers from a configuration file
84 # but sed may not always be available at the time.
85 remove_markers()
86 {
87         m1="$1"
88         m2="$2"
89         in_marker=0
90
91         shift; shift
92         if type sed >/dev/null 2>&1; then
93                 sed "/^$m1/,/^$m2/d" $@
94         else
95                 for x do
96                         while read line; do
97                                 case "$line" in
98                                 "$m1"*) in_marker=1;;
99                                 "$m2"*) in_marker=0;;
100                                 *) [ $in_marker = 0 ] && echo "$line";;
101                                 esac
102                         done < "$x"
103                 done
104         fi
105 }
106
107 # Compare two files.
108 comp_file()
109 {
110         [ -e "$1" ] && [ -e "$2" ] || return 1
111
112         if type cmp >/dev/null 2>&1; then
113                 cmp -s "$1" "$2"
114         elif type diff >/dev/null 2>&1; then
115                 diff -q "$1" "$2" >/dev/null
116         else
117                 # Hopefully we're only working on small text files ...
118                 [ "$(cat "$1")" = "$(cat "$2")" ]
119         fi
120 }
121
122 # Compare two files.
123 # If different, replace first with second otherwise remove second.
124 change_file()
125 {
126         if [ -e "$1" ]; then
127                 if comp_file "$1" "$2"; then
128                         rm -f "$2"
129                         return 1
130                 fi
131         fi
132         cat "$2" > "$1"
133         rm -f "$2"
134         return 0
135 }
136
137 # Compare two files.
138 # If different, copy or link depending on target type
139 copy_file()
140 {
141         if [ -h "$2" ]; then
142                 [ "$(readlink "$2")" = "$1" ] && return 1
143                 ln -sf "$1" "$2"
144         else
145                 comp_file "$1" "$2" && return 1
146                 cat "$1" >"$2"
147         fi
148 }
149
150 # Save a config file
151 save_conf()
152 {
153         if [ -f "$1" ]; then
154                 rm -f "$1-pre.$interface"
155                 cat "$1" > "$1-pre.$interface"
156         fi
157 }
158
159 # Restore a config file
160 restore_conf()
161 {
162         [ -f "$1-pre.$interface" ] || return 1
163         cat "$1-pre.$interface" > "$1"
164         rm -f "$1-pre.$interface"
165 }
166
167 # Write a syslog entry
168 syslog()
169 {
170         lvl="$1"
171
172         if [ "$lvl" = debug ]; then
173                 ${syslog_debug} || return 0
174         fi
175         [ -n "$lvl" ] && shift
176         [ -n "$*" ] || return 0
177         case "$lvl" in
178         err|error)      echo "$interface: $*" >&2;;
179         *)              echo "$interface: $*";;
180         esac
181         if type logger >/dev/null 2>&1; then
182                 logger -i -p daemon."$lvl" -t dhcpcd-run-hooks "$interface: $*"
183         fi
184 }
185
186 # Check for a valid name as per RFC952 and RFC1123 section 2.1
187 valid_domainname()
188 {
189         name="$1"
190         [ -z "$name" ] || [ ${#name} -gt 255 ] && return 1
191         
192         while [ -n "$name" ]; do
193                 label="${name%%.*}"
194                 [ -z "$label" ] || [ ${#label} -gt 63 ] && return 1
195                 case "$label" in
196                 -*|_*|*-|*_)            return 1;;
197                 *[![:alnum:]_-]*)       return 1;;
198                 "$name")                return 0;;
199                 esac
200                 name="${name#*.}"
201         done
202         return 0
203 }
204
205 valid_domainname_list()
206 {
207         for name do
208                 valid_domainname "$name" || return $?
209         done
210         return 0
211 }
212
213 # With the advent of alternative init systems, it's possible to have
214 # more than one installed. So we need to try to guess what one we're
215 # using unless overridden by configure.
216 detect_init()
217 {
218         _service_exists="@SERVICEEXISTS@"
219         _service_cmd="@SERVICECMD@"
220         _service_status="@SERVICESTATUS@"
221
222         [ -n "$_service_cmd" ] && return 0
223
224         if $_detected_init; then
225                 [ -n "$_service_cmd" ]
226                 return $?
227         fi
228
229         # Detect the running init system.
230         # As systemd and OpenRC can be installed on top of legacy init
231         # systems we try to detect them first.
232         status="@STATUSARG@"
233         : ${status:=status}
234         if [ -x /bin/systemctl ] && [ -S /run/systemd/private ]; then
235                 _service_exists="/bin/systemctl --quiet is-enabled \$1.service"
236                 _service_status="/bin/systemctl --quiet is-active \$1.service"
237                 _service_cmd="/bin/systemctl \$2 \$1.service"
238         elif [ -x /usr/bin/systemctl ] && [ -S /run/systemd/private ]; then
239                 _service_exists="/usr/bin/systemctl --quiet is-enabled \$1.service"
240                 _service_status="/usr/bin/systemctl --quiet is-active \$1.service"
241                 _service_cmd="/usr/bin/systemctl \$2 \$1.service"
242         elif [ -x /sbin/rc-service ] &&
243              { [ -s /libexec/rc/init.d/softlevel ] ||
244              [ -s /run/openrc/softlevel ]; }
245         then
246                 _service_exists="/sbin/rc-service -e \$1"
247                 _service_cmd="/sbin/rc-service \$1 -- -D \$2"
248         elif [ -x /usr/sbin/invoke-rc.d ]; then
249                 _service_exists="/usr/sbin/invoke-rc.d --query --quiet \$1 start >/dev/null 2>&1 || [ \$? = 104 ]"
250                 _service_cmd="/usr/sbin/invoke-rc.d \$1 \$2"
251         elif [ -x /sbin/service ]; then
252                 _service_exists="/sbin/service \$1 >/dev/null 2>&1"
253                 _service_cmd="/sbin/service \$1 \$2"
254         elif [ -x /usr/sbin/service ]; then
255                 _service_exists="/usr/sbin/service \$1 $status >/dev/null 2>&1"
256                 _service_cmd="/usr/sbin/service \$1 \$2"
257         elif [ -x /bin/sv ]; then
258                 _service_exists="/bin/sv status \$1 >/dev/null 2>&1"
259                 _service_cmd="/bin/sv \$2 \$1"
260         elif [ -x /usr/bin/sv ]; then
261                 _service_exists="/usr/bin/sv status \$1 >/dev/null 2>&1"
262                 _service_cmd="/usr/bin/sv \$2 \$1"
263         elif [ -e /etc/slackware-version ] && [ -d /etc/rc.d ]; then
264                 _service_exists="[ -x /etc/rc.d/rc.\$1 ]"
265                 _service_cmd="/etc/rc.d/rc.\$1 \$2"
266                 _service_status="/etc/rc.d/rc.\$1 status >/dev/null 2>&1"
267         else
268                 for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do
269                         if [ -d $x ]; then
270                                 _service_exists="[ -x $x/\$1 ]"
271                                 _service_cmd="$x/\$1 \$2"
272                                 _service_status="$x/\$1 $status >/dev/null 2>&1"
273                                 break
274                         fi
275                 done
276                 if [ -e /etc/arch-release ]; then
277                         _service_status="[ -e /var/run/daemons/\$1 ]"
278                 elif [ "$x" = "/etc/rc.d" ] && [ -e /etc/rc.d/rc.subr ]; then
279                         _service_status="$x/\$1 check >/dev/null 2>&1"
280                 fi
281         fi
282
283         _detected_init=true
284         if [ -z "$_service_cmd" ]; then
285                 syslog err "could not detect a useable init system"
286                 return 1
287         fi
288         return 0
289 }
290
291 # Check a system service exists 
292 service_exists()
293 {
294         if [ -z "$_service_exists" ]; then
295                 detect_init || return 1
296         fi
297         eval $_service_exists
298 }
299
300 # Send a command to a system service
301 service_cmd()
302 {
303         if [ -z "$_service_cmd" ]; then
304                 detect_init || return 1
305         fi
306         eval $_service_cmd
307 }
308
309 # Send a command to a system service if it is running
310 service_status()
311 {
312         if [ -z "$_service_cmd" ]; then
313                 detect_init || return 1
314         fi
315         if [ -n "$_service_status" ]; then
316                 eval $_service_status
317         else
318                 service_command $1 status >/dev/null 2>&1
319         fi
320 }
321
322 # Handy macros for our hooks
323 service_command()
324 {
325         service_exists $1 && service_cmd $1 $2
326 }
327 service_condcommand()
328 {
329         service_exists $1 && service_status $1 && service_cmd $1 $2
330 }
331
332 # We source each script into this one so that scripts run earlier can
333 # remove variables from the environment so later scripts don't see them.
334 # Thus, the user can create their dhcpcd.enter/exit-hook script to configure
335 # /etc/resolv.conf how they want and stop the system scripts ever updating it.
336 for hook in \
337         @SYSCONFDIR@/dhcpcd.enter-hook \
338         @HOOKDIR@/* \
339         @SYSCONFDIR@/dhcpcd.exit-hook
340 do
341         for skip in $skip_hooks; do
342                 case "$hook" in
343                         */*~)                           continue 2;;
344                         */"$skip")                      continue 2;;
345                         */[0-9][0-9]"-$skip")           continue 2;;
346                         */[0-9][0-9]"-$skip.sh")        continue 2;;
347                 esac
348         done
349         if [ -f "$hook" ]; then
350                 . "$hook"
351         fi
352 done