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