1#!/bin/sh 2# Copyright (c) 2007-2016 Roy Marples 3# All rights reserved 4 5# Redistribution and use in source and binary forms, with or without 6# modification, are permitted provided that the following conditions 7# are met: 8# * Redistributions of source code must retain the above copyright 9# notice, this list of conditions and the following disclaimer. 10# * Redistributions in binary form must reproduce the above 11# copyright notice, this list of conditions and the following 12# disclaimer in the documentation and/or other materials provided 13# with the distribution. 14# 15# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 27RESOLVCONF="$0" 28OPENRESOLV_VERSION="3.8.1" 29SYSCONFDIR=@SYSCONFDIR@ 30LIBEXECDIR=@LIBEXECDIR@ 31VARDIR=@VARDIR@ 32RCDIR=@RCDIR@ 33RESTARTCMD=@RESTARTCMD@ 34 35# Disregard dhcpcd setting 36unset interface_order state_dir 37 38# If you change this, change the test in VFLAG and libc.in as well 39local_nameservers="127.* 0.0.0.0 255.255.255.255 ::1" 40 41dynamic_order="tap[0-9]* tun[0-9]* vpn vpn[0-9]* ppp[0-9]* ippp[0-9]*" 42interface_order="lo lo[0-9]*" 43name_server_blacklist="0.0.0.0" 44 45# Support original resolvconf configuration layout 46# as well as the openresolv config file 47if [ -f "$SYSCONFDIR"/resolvconf.conf ]; then 48 . "$SYSCONFDIR"/resolvconf.conf 49 [ -n "$state_dir" ] && VARDIR="$state_dir" 50elif [ -d "$SYSCONFDIR/resolvconf" ]; then 51 SYSCONFDIR="$SYSCONFDIR/resolvconf" 52 if [ -f "$SYSCONFDIR"/interface-order ]; then 53 interface_order="$(cat "$SYSCONFDIR"/interface-order)" 54 fi 55fi 56IFACEDIR="$VARDIR/interfaces" 57METRICDIR="$VARDIR/metrics" 58PRIVATEDIR="$VARDIR/private" 59EXCLUSIVEDIR="$VARDIR/exclusive" 60LOCKDIR="$VARDIR/lock" 61_PWD="$PWD" 62 63warn() 64{ 65 echo "$*" >&2 66} 67 68error_exit() 69{ 70 echo "$*" >&2 71 exit 1 72} 73 74usage() 75{ 76 cat <<-EOF 77 Usage: ${RESOLVCONF##*/} [options] command [argument] 78 79 Inform the system about any DNS updates. 80 81 Commands: 82 -a \$INTERFACE Add DNS information to the specified interface 83 (DNS supplied via stdin in resolv.conf format) 84 -d \$INTERFACE Delete DNS information from the specified interface 85 -h Show this help cruft 86 -i [\$PATTERN] Show interfaces that have supplied DNS information 87 optionally from interfaces that match the specified 88 pattern 89 -l [\$PATTERN] Show DNS information, optionally from interfaces 90 that match the specified pattern 91 92 -u Run updates from our current DNS information 93 94 Options: 95 -f Ignore non existent interfaces 96 -m metric Give the added DNS information a metric 97 -p Mark the interface as private 98 -x Mark the interface as exclusive 99 100 Subscriber and System Init Commands: 101 -I Init the state dir 102 -r \$SERVICE Restart the system service 103 (restarting a non-existent or non-running service 104 should have no output and return 0) 105 -R Show the system service restart command 106 -v [\$PATTERN] echo NEWDOMAIN, NEWSEARCH and NEWNS variables to 107 the console 108 -V [\$PATTERN] Same as -v, but only uses configuration in 109 $SYSCONFDIR/resolvconf.conf 110 EOF 111 [ -z "$1" ] && exit 0 112 echo 113 error_exit "$*" 114} 115 116# Strip any trailing dot from each name as a FQDN does not belong 117# in resolv.conf(5) 118# If you think otherwise, capture a DNS trace and you'll see libc 119# will strip it regardless. 120# This also solves setting up duplicate zones in our subscribers. 121strip_trailing_dots() 122{ 123 local n= d= 124 125 for n; do 126 printf "$d%s" "${n%.}" 127 d=" " 128 done 129 printf "\n" 130} 131 132# Parse resolv.conf's and make variables 133# for domain name servers, search name servers and global nameservers 134parse_resolv() 135{ 136 local line= ns= ds= search= d= n= newns= 137 local new=true iface= private=false p= domain= l= islocal= 138 139 newns= 140 141 while read -r line; do 142 case "$line" in 143 "# resolv.conf from "*) 144 if ${new}; then 145 iface="${line#\# resolv.conf from *}" 146 new=false 147 if [ -e "$PRIVATEDIR/$iface" ]; then 148 private=true 149 else 150 # Allow expansion 151 cd "$IFACEDIR" 152 private=false 153 for p in $private_interfaces; do 154 case "$iface" in 155 "$p"|"$p":*) 156 private=true 157 break 158 ;; 159 esac 160 done 161 fi 162 fi 163 ;; 164 "nameserver "*) 165 islocal=false 166 for l in $local_nameservers; do 167 case "${line#* }" in 168 $l) 169 islocal=true 170 echo "LOCALNAMESERVERS=\"\$LOCALNAMESERVERS ${line#* }\"" 171 break 172 ;; 173 esac 174 done 175 $islocal || ns="$ns${line#* } " 176 ;; 177 "domain "*) 178 search="$(strip_trailing_dots ${line#* })" 179 if [ -z "$domain" ]; then 180 domain="$search" 181 echo "DOMAIN=\"$domain\"" 182 fi 183 ;; 184 "search "*) 185 search="$(strip_trailing_dots ${line#* })" 186 ;; 187 *) 188 [ -n "$line" ] && continue 189 if [ -n "$ns" -a -n "$search" ]; then 190 newns= 191 for n in $ns; do 192 newns="$newns${newns:+,}$n" 193 done 194 ds= 195 for d in $search; do 196 ds="$ds${ds:+ }$d:$newns" 197 done 198 echo "DOMAINS=\"\$DOMAINS $ds\"" 199 fi 200 echo "SEARCH=\"\$SEARCH $search\"" 201 if ! $private; then 202 echo "NAMESERVERS=\"\$NAMESERVERS $ns\"" 203 fi 204 ns= 205 search= 206 new=true 207 ;; 208 esac 209 done 210} 211 212uniqify() 213{ 214 local result= 215 while [ -n "$1" ]; do 216 case " $result " in 217 *" $1 "*);; 218 *) result="$result $1";; 219 esac 220 shift 221 done 222 echo "${result# *}" 223} 224 225dirname() 226{ 227 local dir= OIFS="$IFS" 228 local IFS=/ 229 set -- $@ 230 IFS="$OIFS" 231 if [ -n "$1" ]; then 232 printf %s . 233 else 234 shift 235 fi 236 while [ -n "$2" ]; do 237 printf "/%s" "$1" 238 shift 239 done 240 printf "\n" 241} 242 243config_mkdirs() 244{ 245 local e=0 f d 246 for f; do 247 [ -n "$f" ] || continue 248 d="$(dirname "$f")" 249 if [ ! -d "$d" ]; then 250 if type install >/dev/null 2>&1; then 251 install -d "$d" || e=$? 252 else 253 mkdir "$d" || e=$? 254 fi 255 fi 256 done 257 return $e 258} 259 260# With the advent of alternative init systems, it's possible to have 261# more than one installed. So we need to try and guess what one we're 262# using unless overriden by configure. 263# Note that restarting a service is a last resort - the subscribers 264# should make a reasonable attempt to reconfigre the service via some 265# method, normally SIGHUP. 266detect_init() 267{ 268 [ -n "$RESTARTCMD" ] && return 0 269 270 # Detect the running init system. 271 # As systemd and OpenRC can be installed on top of legacy init 272 # systems we try to detect them first. 273 local status="@STATUSARG@" 274 : ${status:=status} 275 if [ -x /bin/systemctl -a -S /run/systemd/private ]; then 276 RESTARTCMD="if /bin/systemctl --quiet is-active \$1.service; then 277 /bin/systemctl restart \$1.service; 278fi" 279 elif [ -x /usr/bin/systemctl -a -S /run/systemd/private ]; then 280 RESTARTCMD="if /usr/bin/systemctl --quiet is-active \$1.service; then 281 /usr/bin/systemctl restart \$1.service; 282fi" 283 elif [ -x /sbin/rc-service -a \ 284 -s /libexec/rc/init.d/softlevel -o -s /run/openrc/softlevel ] 285 then 286 RESTARTCMD="/sbin/rc-service -i \$1 -- -Ds restart" 287 elif [ -x /usr/sbin/invoke-rc.d ]; then 288 RCDIR=/etc/init.d 289 RESTARTCMD="if /usr/sbin/invoke-rc.d --quiet \$1 status 1>/dev/null 2>&1; then 290 /usr/sbin/invoke-rc.d \$1 restart; 291fi" 292 elif [ -x /sbin/service ]; then 293 # Old RedHat 294 RCDIR=/etc/init.d 295 RESTARTCMD="if /sbin/service \$1; then 296 /sbin/service \$1 restart; 297fi" 298 elif [ -x /usr/sbin/service ]; then 299 # Could be FreeBSD 300 RESTARTCMD="if /usr/sbin/service \$1 $status 1>/dev/null 2>&1; then 301 /usr/sbin/service \$1 restart; 302fi" 303 elif [ -x /bin/sv ]; then 304 RESTARTCMD="/bin/sv try-restart \$1" 305 elif [ -x /usr/bin/sv ]; then 306 RESTARTCMD="/usr/bin/sv try-restart \$1" 307 elif [ -e /etc/arch-release -a -d /etc/rc.d ]; then 308 RCDIR=/etc/rc.d 309 RESTARTCMD="if [ -e /var/run/daemons/\$1 ]; then 310 /etc/rc.d/\$1 restart; 311fi" 312 elif [ -e /etc/slackware-version -a -d /etc/rc.d ]; then 313 RESTARTCMD="if /etc/rc.d/rc.\$1 status 1>/dev/null 2>&1; then 314 /etc/rc.d/rc.\$1 restart; 315fi" 316 elif [ -e /etc/rc.d/rc.subr -a -d /etc/rc.d ]; then 317 # OpenBSD 318 RESTARTCMD="if /etc/rc.d/\$1 check 1>/dev/null 2>&1; then 319 /etc/rc.d/\$1 restart; 320fi" 321 else 322 for x in /etc/init.d/rc.d /etc/rc.d /etc/init.d; do 323 [ -d $x ] || continue 324 RESTARTCMD="if $x/\$1 $status 1>/dev/null 2>&1; then 325 $x/\$1 restart; 326fi" 327 break 328 done 329 fi 330 331 if [ -z "$RESTARTCMD" ]; then 332 if [ "$NOINIT_WARNED" != true ]; then 333 warn "could not detect a useable init system" 334 _NOINIT_WARNED=true 335 fi 336 return 1 337 fi 338 _NOINIT_WARNED= 339 return 0 340} 341 342echo_resolv() 343{ 344 local line= OIFS="$IFS" 345 346 [ -n "$1" -a -f "$IFACEDIR/$1" ] || return 1 347 echo "# resolv.conf from $1" 348 # Our variable maker works of the fact each resolv.conf per interface 349 # is separated by blank lines. 350 # So we remove them when echoing them. 351 while read -r line; do 352 IFS="$OIFS" 353 if [ -n "$line" ]; then 354 # We need to set IFS here to preserve any whitespace 355 IFS='' 356 printf "%s\n" "$line" 357 fi 358 done < "$IFACEDIR/$1" 359 IFS="$OIFS" 360} 361 362list_resolv() 363{ 364 [ -d "$IFACEDIR" ] || return 0 365 366 local report=false list= retval=0 cmd="$1" excl= 367 shift 368 369 case "$IF_EXCLUSIVE" in 370 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 371 if [ -d "$EXCLUSIVEDIR" ]; then 372 cd "$EXCLUSIVEDIR" 373 for i in *; do 374 if [ -f "$i" ]; then 375 list="${i#* }" 376 break 377 fi 378 done 379 fi 380 excl=true 381 ;; 382 *) 383 excl=false 384 ;; 385 esac 386 387 # If we have an interface ordering list, then use that. 388 # It works by just using pathname expansion in the interface directory. 389 if [ -n "$1" ]; then 390 list="$*" 391 $force || report=true 392 elif ! $excl; then 393 cd "$IFACEDIR" 394 for i in $interface_order; do 395 [ -f "$i" ] && list="$list $i" 396 for ii in "$i":* "$i".*; do 397 [ -f "$ii" ] && list="$list $ii" 398 done 399 done 400 for i in $dynamic_order; do 401 if [ -e "$i" -a ! -e "$METRICDIR/"*" $i" ]; then 402 list="$list $i" 403 fi 404 for ii in "$i":* "$i".*; do 405 if [ -f "$ii" -a ! -e "$METRICDIR/"*" $ii" ]; then 406 list="$list $ii" 407 fi 408 done 409 done 410 if [ -d "$METRICDIR" ]; then 411 cd "$METRICDIR" 412 for i in *; do 413 [ -f "$i" ] && list="$list ${i#* }" 414 done 415 fi 416 list="$list *" 417 fi 418 419 cd "$IFACEDIR" 420 retval=1 421 excl=true 422 for i in $(uniqify $list); do 423 # Only list interfaces which we really have 424 if ! [ -f "$i" ]; then 425 if $report; then 426 echo "No resolv.conf for interface $i" >&2 427 retval=2 428 fi 429 continue 430 fi 431 432 if [ "$cmd" = i -o "$cmd" = "-i" ]; then 433 printf %s "$i " 434 else 435 echo_resolv "$i" 436 echo 437 fi 438 [ $? = 0 -a "$retval" = 1 ] && retval=0 439 done 440 [ "$cmd" = i -o "$cmd" = "-i" ] && echo 441 return $retval 442} 443 444list_remove() { 445 local list= e= l= result= found= retval=0 446 447 [ -z "$2" ] && return 0 448 eval list=\"\$$1\" 449 shift 450 451 set -f 452 for e; do 453 found=false 454 for l in $list; do 455 case "$e" in 456 $l) found=true;; 457 esac 458 $found && break 459 done 460 if $found; then 461 retval=$(($retval + 1)) 462 else 463 result="$result $e" 464 fi 465 done 466 set +f 467 echo "${result# *}" 468 return $retval 469} 470 471echo_prepend() 472{ 473 echo "# Generated by resolvconf" 474 if [ -n "$search_domains" ]; then 475 echo "search $search_domains" 476 fi 477 for n in $name_servers; do 478 echo "nameserver $n" 479 done 480 echo 481} 482 483echo_append() 484{ 485 echo "# Generated by resolvconf" 486 if [ -n "$search_domains_append" ]; then 487 echo "search $search_domains_append" 488 fi 489 for n in $name_servers_append; do 490 echo "nameserver $n" 491 done 492 echo 493} 494 495replace() 496{ 497 local r= k= f= v= val= sub= 498 499 while read -r keyword value; do 500 for r in $replace; do 501 k="${r%%/*}" 502 r="${r#*/}" 503 f="${r%%/*}" 504 r="${r#*/}" 505 v="${r%%/*}" 506 case "$keyword" in 507 $k) 508 case "$value" in 509 $f) value="$v";; 510 esac 511 ;; 512 esac 513 done 514 val= 515 for sub in $value; do 516 for r in $replace_sub; do 517 k="${r%%/*}" 518 r="${r#*/}" 519 f="${r%%/*}" 520 r="${r#*/}" 521 v="${r%%/*}" 522 case "$keyword" in 523 $k) 524 case "$sub" in 525 $f) sub="$v";; 526 esac 527 ;; 528 esac 529 done 530 val="$val${val:+ }$sub" 531 done 532 printf "%s %s\n" "$keyword" "$val" 533 done 534} 535 536make_vars() 537{ 538 local newdomains= d= dn= newns= ns= 539 540 # Clear variables 541 DOMAIN= 542 DOMAINS= 543 SEARCH= 544 NAMESERVERS= 545 LOCALNAMESERVERS= 546 547 if [ -n "$name_servers" -o -n "$search_domains" ]; then 548 eval "$(echo_prepend | parse_resolv)" 549 fi 550 if [ -z "$VFLAG" ]; then 551 IF_EXCLUSIVE=1 552 list_resolv -i "$@" >/dev/null || IF_EXCLUSIVE=0 553 eval "$(list_resolv -l "$@" | replace | parse_resolv)" 554 fi 555 if [ -n "$name_servers_append" -o -n "$search_domains_append" ]; then 556 eval "$(echo_append | parse_resolv)" 557 fi 558 559 # Ensure that we only list each domain once 560 for d in $DOMAINS; do 561 dn="${d%%:*}" 562 list_remove domain_blacklist "$dn" >/dev/null || continue 563 case " $newdomains" in 564 *" ${dn}:"*) continue;; 565 esac 566 newns= 567 for nd in $DOMAINS; do 568 if [ "$dn" = "${nd%%:*}" ]; then 569 ns="${nd#*:}" 570 while [ -n "$ns" ]; do 571 case ",$newns," in 572 *,${ns%%,*},*) ;; 573 *) list_remove name_server_blacklist \ 574 "${ns%%,*}" >/dev/null \ 575 && newns="$newns${newns:+,}${ns%%,*}";; 576 esac 577 [ "$ns" = "${ns#*,}" ] && break 578 ns="${ns#*,}" 579 done 580 fi 581 done 582 if [ -n "$newns" ]; then 583 newdomains="$newdomains${newdomains:+ }$dn:$newns" 584 fi 585 done 586 DOMAIN="$(list_remove domain_blacklist $DOMAIN)" 587 SEARCH="$(uniqify $SEARCH)" 588 SEARCH="$(list_remove domain_blacklist $SEARCH)" 589 NAMESERVERS="$(uniqify $NAMESERVERS)" 590 NAMESERVERS="$(list_remove name_server_blacklist $NAMESERVERS)" 591 LOCALNAMESERVERS="$(uniqify $LOCALNAMESERVERS)" 592 LOCALNAMESERVERS="$(list_remove name_server_blacklist $LOCALNAMESERVERS)" 593 echo "DOMAIN='$DOMAIN'" 594 echo "SEARCH='$SEARCH'" 595 echo "NAMESERVERS='$NAMESERVERS'" 596 echo "LOCALNAMESERVERS='$LOCALNAMESERVERS'" 597 echo "DOMAINS='$newdomains'" 598} 599 600force=false 601VFLAG= 602while getopts a:Dd:fhIilm:pRruvVx OPT; do 603 case "$OPT" in 604 f) force=true;; 605 h) usage;; 606 m) IF_METRIC="$OPTARG";; 607 p) IF_PRIVATE=1;; 608 V) 609 VFLAG=1 610 if [ "$local_nameservers" = \ 611 "127.* 0.0.0.0 255.255.255.255 ::1" ] 612 then 613 local_nameservers= 614 fi 615 ;; 616 x) IF_EXCLUSIVE=1;; 617 '?') ;; 618 *) cmd="$OPT"; iface="$OPTARG";; 619 esac 620done 621shift $(($OPTIND - 1)) 622args="$iface${iface:+ }$*" 623 624# -I inits the state dir 625if [ "$cmd" = I ]; then 626 if [ -d "$VARDIR" ]; then 627 rm -rf "$VARDIR"/* 628 fi 629 exit $? 630fi 631 632# -D ensures that the listed config file base dirs exist 633if [ "$cmd" = D ]; then 634 config_mkdirs "$@" 635 exit $? 636fi 637 638# -l lists our resolv files, optionally for a specific interface 639if [ "$cmd" = l -o "$cmd" = i ]; then 640 list_resolv "$cmd" "$args" 641 exit $? 642fi 643 644# Restart a service or echo the command to restart a service 645if [ "$cmd" = r -o "$cmd" = R ]; then 646 detect_init || exit 1 647 if [ "$cmd" = r ]; then 648 set -- $args 649 eval $RESTARTCMD 650 else 651 echo "$RESTARTCMD" 652 fi 653 exit $? 654fi 655 656# Not normally needed, but subscribers should be able to run independently 657if [ "$cmd" = v -o -n "$VFLAG" ]; then 658 make_vars "$iface" 659 exit $? 660fi 661 662# Test that we have valid options 663if [ "$cmd" = a -o "$cmd" = d ]; then 664 if [ -z "$iface" ]; then 665 usage "Interface not specified" 666 fi 667elif [ "$cmd" != u ]; then 668 [ -n "$cmd" -a "$cmd" != h ] && usage "Unknown option $cmd" 669 usage 670fi 671 672if [ "$cmd" = a ]; then 673 for x in '/' \\ ' ' '*'; do 674 case "$iface" in 675 *[$x]*) error_exit "$x not allowed in interface name";; 676 esac 677 done 678 for x in '.' '-' '~'; do 679 case "$iface" in 680 [$x]*) error_exit \ 681 "$x not allowed at start of interface name";; 682 esac 683 done 684 [ "$cmd" = a -a -t 0 ] && error_exit "No file given via stdin" 685fi 686 687if [ ! -d "$VARDIR" ]; then 688 if [ -L "$VARDIR" ]; then 689 dir="$(readlink "$VARDIR")" 690 # link maybe relative 691 cd "${VARDIR%/*}" 692 if ! mkdir -m 0755 -p "$dir"; then 693 error_exit "Failed to create needed" \ 694 "directory $dir" 695 fi 696 else 697 if ! mkdir -m 0755 -p "$VARDIR"; then 698 error_exit "Failed to create needed" \ 699 "directory $VARDIR" 700 fi 701 fi 702fi 703 704if [ ! -d "$IFACEDIR" ]; then 705 mkdir -m 0755 -p "$IFACEDIR" || \ 706 error_exit "Failed to create needed directory $IFACEDIR" 707 if [ "$cmd" = d ]; then 708 # Provide the same error messages as below 709 if ! ${force}; then 710 cd "$IFACEDIR" 711 for i in $args; do 712 warn "No resolv.conf for interface $i" 713 done 714 fi 715 ${force} 716 exit $? 717 fi 718fi 719 720# An interface was added, changed, deleted or a general update was called. 721# Due to exclusivity we need to ensure that this is an atomic operation. 722# Our subscribers *may* need this as well if the init system is sub par. 723# As such we spinlock at this point as best we can. 724# We don't use flock(1) because it's not widely available and normally resides 725# in /usr which we do our very best to operate without. 726[ -w "$VARDIR" ] || error_exit "Cannot write to $LOCKDIR" 727: ${lock_timeout:=10} 728while true; do 729 if mkdir "$LOCKDIR" 2>/dev/null; then 730 trap 'rm -rf "$LOCKDIR";' EXIT 731 trap 'rm -rf "$LOCKDIR"; exit 1' INT QUIT ABRT SEGV ALRM TERM 732 echo $$ >"$LOCKDIR/pid" 733 break 734 fi 735 pid=$(cat "$LOCKDIR/pid") 736 if ! kill -0 "$pid"; then 737 warn "clearing stale lock pid $pid" 738 rm -rf "$LOCKDIR" 739 continue 740 fi 741 lock_timeout=$(($lock_timeout - 1)) 742 if [ "$lock_timeout" -le 0 ]; then 743 error_exit "timed out waiting for lock from pid $pid" 744 fi 745 sleep 1 746done 747 748case "$cmd" in 749a) 750 # Read resolv.conf from stdin 751 resolv="$(cat)" 752 changed=false 753 changedfile=false 754 # If what we are given matches what we have, then do nothing 755 if [ -e "$IFACEDIR/$iface" ]; then 756 if [ "$(echo "$resolv")" != \ 757 "$(cat "$IFACEDIR/$iface")" ] 758 then 759 changed=true 760 changedfile=true 761 fi 762 else 763 changed=true 764 changedfile=true 765 fi 766 767 # Set metric and private before creating the interface resolv.conf file 768 # to ensure that it will have the correct flags 769 [ ! -d "$METRICDIR" ] && mkdir "$METRICDIR" 770 oldmetric="$METRICDIR/"*" $iface" 771 newmetric= 772 if [ -n "$IF_METRIC" ]; then 773 # Pad metric to 6 characters, so 5 is less than 10 774 while [ ${#IF_METRIC} -le 6 ]; do 775 IF_METRIC="0$IF_METRIC" 776 done 777 newmetric="$METRICDIR/$IF_METRIC $iface" 778 fi 779 rm -f "$METRICDIR/"*" $iface" 780 [ "$oldmetric" != "$newmetric" -a \ 781 "$oldmetric" != "$METRICDIR/* $iface" ] && 782 changed=true 783 [ -n "$newmetric" ] && echo " " >"$newmetric" 784 785 case "$IF_PRIVATE" in 786 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 787 if [ ! -d "$PRIVATEDIR" ]; then 788 [ -e "$PRIVATEDIR" ] && rm "$PRIVATEDIR" 789 mkdir "$PRIVATEDIR" 790 fi 791 [ -e "$PRIVATEDIR/$iface" ] || changed=true 792 [ -d "$PRIVATEDIR" ] && echo " " >"$PRIVATEDIR/$iface" 793 ;; 794 *) 795 if [ -e "$PRIVATEDIR/$iface" ]; then 796 rm -f "$PRIVATEDIR/$iface" 797 changed=true 798 fi 799 ;; 800 esac 801 802 oldexcl= 803 for x in "$EXCLUSIVEDIR/"*" $iface"; do 804 if [ -f "$x" ]; then 805 oldexcl="$x" 806 break 807 fi 808 done 809 case "$IF_EXCLUSIVE" in 810 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) 811 if [ ! -d "$EXCLUSIVEDIR" ]; then 812 [ -e "$EXCLUSIVEDIR" ] && rm "$EXCLUSIVEDIR" 813 mkdir "$EXCLUSIVEDIR" 814 fi 815 cd "$EXCLUSIVEDIR" 816 for x in *; do 817 [ -f "$x" ] && break 818 done 819 if [ "${x#* }" != "$iface" ]; then 820 if [ "$x" = "${x% *}" ]; then 821 x=10000000 822 else 823 x="${x% *}" 824 fi 825 if [ "$x" = "0000000" ]; then 826 warn "exclusive underflow" 827 else 828 x=$(($x - 1)) 829 fi 830 if [ -d "$EXCLUSIVEDIR" ]; then 831 echo " " >"$EXCLUSIVEDIR/$x $iface" 832 fi 833 changed=true 834 fi 835 ;; 836 *) 837 if [ -f "$oldexcl" ]; then 838 rm -f "$oldexcl" 839 changed=true 840 fi 841 ;; 842 esac 843 844 if $changedfile; then 845 printf "%s\n" "$resolv" >"$IFACEDIR/$iface" || exit $? 846 elif ! $changed; then 847 exit 0 848 fi 849 unset changed changedfile oldmetric newmetric x oldexcl 850 ;; 851 852d) 853 # Delete any existing information about the interface 854 cd "$IFACEDIR" 855 changed=false 856 for i in $args; do 857 if [ -e "$i" ]; then 858 changed=true 859 elif ! ${force}; then 860 warn "No resolv.conf for interface $i" 861 fi 862 rm -f "$i" "$METRICDIR/"*" $i" \ 863 "$PRIVATEDIR/$i" \ 864 "$EXCLUSIVEDIR/"*" $i" || exit $? 865 done 866 if ! ${changed}; then 867 # Set the return code based on the forced flag 868 ${force} 869 exit $? 870 fi 871 unset changed i 872 ;; 873esac 874 875case "${resolvconf:-YES}" in 876[Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;; 877*) exit 0;; 878esac 879 880# Try and detect a suitable init system for our scripts 881detect_init 882export RESTARTCMD RCDIR _NOINIT_WARNED 883 884eval "$(make_vars)" 885export RESOLVCONF DOMAINS SEARCH NAMESERVERS LOCALNAMESERVERS 886: ${list_resolv:=list_resolv -l} 887retval=0 888 889# Run scripts in the same directory resolvconf is run from 890# in case any scripts accidentally dump files in the wrong place. 891cd "$_PWD" 892for script in "$LIBEXECDIR"/*; do 893 if [ -f "$script" ]; then 894 eval script_enabled="\$${script##*/}" 895 case "${script_enabled:-YES}" in 896 [Yy][Ee][Ss]|[Tt][Rr][Uu][Ee]|[Oo][Nn]|1) ;; 897 *) continue;; 898 esac 899 if [ -x "$script" ]; then 900 "$script" "$cmd" "$iface" 901 else 902 (set -- "$cmd" "$iface"; . "$script") 903 fi 904 retval=$(($retval + $?)) 905 fi 906done 907exit $retval 908