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