xref: /dragonfly/contrib/dhcpcd/hooks/dhcpcd-run-hooks (revision c80c9bba1b2fa2824af94c686145cb7eb7db2cd5)
1#!/bin/sh
2# dhcpcd client configuration script
3
4# Handy variables and functions for our hooks to use
5ifname="$interface${protocol+.}$protocol"
6from=from
7signature_base="# Generated by dhcpcd"
8signature="$signature_base $from $ifname"
9signature_base_end="# End of dhcpcd"
10signature_end="$signature_base_end $from $ifname"
11state_dir=/var/run/dhcpcd/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
19uniqify()
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.
35list_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
50trim()
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.
65key_get_value()
66{
67          key="$1"
68          shift
69
70          if command -v 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.
85remove_markers()
86{
87          m1="$1"
88          m2="$2"
89          in_marker=0
90
91          shift; shift
92          if command -v 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.
108comp_file()
109{
110          [ -e "$1" ] && [ -e "$2" ] || return 1
111
112          if command -v cmp >/dev/null 2>&1; then
113                    cmp -s "$1" "$2"
114          elif command -v 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.
124change_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
139copy_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
151save_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
160restore_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
168syslog()
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 command -v 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
187valid_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
205valid_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.
216detect_init()
217{
218          _service_exists=""
219          _service_cmd=""
220          _service_status=""
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="onestatus"
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 --no-block \$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 --no-block \$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
292service_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
301service_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
310service_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
323service_command()
324{
325          service_exists $1 && service_cmd $1 $2
326}
327service_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.
336for hook in \
337          /etc/dhcpcd.enter-hook \
338          /usr/libexec/dhcpcd-hooks/* \
339          /etc/dhcpcd.exit-hook
340do
341          case "$hook" in
342                    */*~)     continue;;
343          esac
344          for skip in $skip_hooks; do
345                    case "$hook" in
346                              */"$skip")                              continue 2;;
347                              */[0-9][0-9]"-$skip")                   continue 2;;
348                              */[0-9][0-9]"-$skip.sh")      continue 2;;
349                    esac
350          done
351          if [ -f "$hook" ]; then
352                    . "$hook"
353          fi
354done
355