Merge lp:~smoser/ubuntu/oneiric/isc-dhcp/lp857524 into lp:ubuntu/oneiric/isc-dhcp

Proposed by Scott Moser
Status: Merged
Merge reported by: Scott Moser
Merged at revision: not available
Proposed branch: lp:~smoser/ubuntu/oneiric/isc-dhcp/lp857524
Merge into: lp:ubuntu/oneiric/isc-dhcp
Diff against target: 134 lines (+41/-28)
2 files modified
debian/changelog (+6/-0)
debian/dhclient-script.linux (+35/-28)
To merge this branch: bzr merge lp:~smoser/ubuntu/oneiric/isc-dhcp/lp857524
Reviewer Review Type Date Requested Status
Colin Watson Approve
Review via email: mp+76791@code.launchpad.net

Description of the change

fix updating of /etc/resolv.conf for read-only /etc/

This makes the following changes:
 * instead of writing to a temp file in /etc/, write to a temp file in
   same directory as resolv.conf (which might be different if
   /etc/resolv.conf is a link)
 * replace the multiple '>>' with a single '>' and braces. This means
   the temp file will be opened for write once rather than append many times.
 * use 'grep -i' rather than 'sed' to get the old nameserver entries from
   existing resolv.conf. This is how the linux.udeb does it, and I find it more
   clean.
 * changes 'wait_for_rw' to take a file argument rather than hard coding /etc
   and then actually tests that that file is writable by opening it for append

To post a comment you must log in.
Revision history for this message
Marc Deslauriers (mdeslaur) wrote :

Won't this result in potential problems while the /etc/resolv.conf file is in the process of being written to? Having the mv from the temp file results in it being atomic...

Revision history for this message
Scott Moser (smoser) wrote :

I suppose, yes. There is the potential for something to race on that file.
The old code path (and with a move) would still potentially have a race conditoin when it tries to read /etc/resolv.conf and get the old name servers, and then uses those for updating. Something could edit in between.

All that said, this should be *really* fast.
neither the DHCPv6 or DCHPv4 paths do any IO during the writing of that file.
Its all just shell builtins and variable operations.

You're correct, though, there is the potential for race. Should this be NAK'd because of that?

Revision history for this message
Colin Watson (cjwatson) wrote :

Nak - resolving the symlink is a much better approach.

Revision history for this message
Colin Watson (cjwatson) :
review: Disapprove
38. By Scott Moser

make the population of resolv.conf atomic with a move

This changes the previous commit by:
 * re-adding the use of chmod and chown --reference
 * using readlink -f to create a temp file to get the full path
   to /etc/resolv.conf (in the case it is a symlink)
 * creates a temp file in that directory and populates the final
   /etc/resolv.conf with a move.

39. By Scott Moser

remove unnecessary '{}' in chown/chmod call

Revision history for this message
Scott Moser (smoser) wrote :

I've re-written with 'mv' and a temp file so the population of /etc/resolv.conf is now atomic with respect to this process.

Revision history for this message
Colin Watson (cjwatson) wrote :

This looks OK to me now. Thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'debian/changelog'
--- debian/changelog 2011-09-23 11:26:29 +0000
+++ debian/changelog 2011-10-24 16:08:30 +0000
@@ -1,3 +1,9 @@
1isc-dhcp (4.1.1-P1-17ubuntu11) UNRELEASED; urgency=low
2
3 * debian/dhclient-script.linux: fix for read-only /etc (LP: #857524)
4
5 -- Scott Moser <smoser@ubuntu.com> Fri, 23 Sep 2011 12:07:24 -0400
6
1isc-dhcp (4.1.1-P1-17ubuntu10) oneiric; urgency=low7isc-dhcp (4.1.1-P1-17ubuntu10) oneiric; urgency=low
28
3 * make sure writing of /etc/resolv.conf actually waits until the file is 9 * make sure writing of /etc/resolv.conf actually waits until the file is
410
=== modified file 'debian/dhclient-script.linux'
--- debian/dhclient-script.linux 2011-09-23 11:26:29 +0000
+++ debian/dhclient-script.linux 2011-10-24 16:08:30 +0000
@@ -12,8 +12,9 @@
1212
13# The alias handling in here probably still sucks. -mdz13# The alias handling in here probably still sucks. -mdz
1414
15# wait for /etc/resolv.conf to become writable15# wait for given file to be writable
16wait_for_rw() {16wait_for_rw() {
17 local file=$1
17 # Find out whether we are going to mount / rw18 # Find out whether we are going to mount / rw
18 exec 9>&0 </etc/fstab19 exec 9>&0 </etc/fstab
19 rootmode=rw20 rootmode=rw
@@ -27,9 +28,9 @@
27 done28 done
28 exec 0>&9 9>&-29 exec 0>&9 9>&-
29 30
30 # Wait for /etc/resolv.conf to become writable31 # Wait for $file to become writable
31 if [ "$rootmode" = "rw" ]; then32 if [ "$rootmode" = "rw" ]; then
32 while ! { : >> /etc/resolv.conf; } 2>/dev/null; do33 while ! { : >> "$file"; } 2>/dev/null; do
33 sleep 0.134 sleep 0.1
34 done35 done
35 fi36 fi
@@ -37,17 +38,23 @@
3738
38# update /etc/resolv.conf based on received values39# update /etc/resolv.conf based on received values
39make_resolv_conf() {40make_resolv_conf() {
40 local new_resolv_conf41 local old_ns="" resolv_conf="" new_resolv_conf=""
42 [ -e /etc/resolv.conf ] && old_ns=$(grep -i '^nameserver' /etc/resolv.conf)
43
44 resolv_conf=$(readlink -f "/etc/resolv.conf" 2>/dev/null) ||
45 resolv_conf="/etc/resolv.conf"
46
47 # write to temp file in same directory as target
48 new_resolv_conf="${resolv_conf}.dhclient-new.$$"
4149
42 # DHCPv450 # DHCPv4
43 if [ -n "$new_domain_search" ] || [ -n "$new_domain_name" ] ||51 if [ -n "$new_domain_search" ] || [ -n "$new_domain_name" ] ||
44 [ -n "$new_domain_name_servers" ]; then52 [ -n "$new_domain_name_servers" ]; then
45 wait_for_rw53 wait_for_rw "$new_resolv_conf"
46 new_resolv_conf=/etc/resolv.conf.dhclient-new
47 rm -f $new_resolv_conf
4854
55 {
49 if [ -n "$new_domain_name" ]; then56 if [ -n "$new_domain_name" ]; then
50 echo domain ${new_domain_name%% *} >>$new_resolv_conf57 echo domain ${new_domain_name%% *}
51 fi58 fi
5259
53 if [ -n "$new_domain_search" ]; then60 if [ -n "$new_domain_search" ]; then
@@ -63,44 +70,44 @@
63 new_domain_search="$new_domain_name $new_domain_search"70 new_domain_search="$new_domain_name $new_domain_search"
64 fi71 fi
65 fi72 fi
66 echo "search ${new_domain_search}" >> $new_resolv_conf73 echo "search ${new_domain_search}"
67 elif [ -n "$new_domain_name" ]; then74 elif [ -n "$new_domain_name" ]; then
68 echo "search ${new_domain_name}" >> $new_resolv_conf75 echo "search ${new_domain_name}"
69 fi76 fi
7077
71 if [ -n "$new_domain_name_servers" ]; then78 if [ -n "$new_domain_name_servers" ]; then
72 for nameserver in $new_domain_name_servers; do79 for nameserver in $new_domain_name_servers; do
73 echo nameserver $nameserver >>$new_resolv_conf80 echo nameserver $nameserver
74 done81 done
75 else # keep 'old' nameservers82 elif [ -n "$old_ns" ]; then # keep 'old' nameservers
76 sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p /etc/resolv.conf >>$new_resolv_conf83 echo "$old_ns"
77 fi84 fi
7885 } > "$new_resolv_conf"
79 chown --reference=/etc/resolv.conf $new_resolv_conf
80 chmod --reference=/etc/resolv.conf $new_resolv_conf
81 mv -f $new_resolv_conf /etc/resolv.conf
82 # DHCPv686 # DHCPv6
83 elif [ -n "$new_dhcp6_domain_search" ] || [ -n "$new_dhcp6_name_servers" ]; then87 elif [ -n "$new_dhcp6_domain_search" ] || [ -n "$new_dhcp6_name_servers" ]; then
84 wait_for_rw88 wait_for_rw "$new_resolv_conf"
85 new_resolv_conf=/etc/resolv.conf.dhclient-new
86 rm -f $new_resolv_conf
8789
90 {
88 if [ -n "$new_dhcp6_domain_search" ]; then91 if [ -n "$new_dhcp6_domain_search" ]; then
89 echo "search ${new_dhcp6_domain_search}" >> $new_resolv_conf92 echo "search ${new_dhcp6_domain_search}"
90 fi93 fi
9194
92 if [ -n "$new_dhcp6_name_servers" ]; then95 if [ -n "$new_dhcp6_name_servers" ]; then
93 for nameserver in $new_dhcp6_name_servers; do96 for nameserver in $new_dhcp6_name_servers; do
94 echo nameserver $nameserver >>$new_resolv_conf97 echo nameserver $nameserver
95 done98 done
96 else # keep 'old' nameservers99 elif [ -n "$old_ns" ]; then # keep 'old' nameservers
97 sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p /etc/resolv.conf >>$new_resolv_conf100 echo "$old_ns"
98 fi101 fi
99102 } > "$new_resolv_conf"
100 chown --reference=/etc/resolv.conf $new_resolv_conf
101 chmod --reference=/etc/resolv.conf $new_resolv_conf
102 mv -f $new_resolv_conf /etc/resolv.conf
103 fi103 fi
104
105 [ -e "$resolv_conf" ] &&
106 chmod --reference="$resolv_conf" "$new_resolv_conf" &&
107 chown --reference="$resolv_conf" "$new_resolv_conf"
108
109 mv "$new_resolv_conf" "$resolv_conf" ||
110 { rm -f "$new_resolv_conf"; return 1; }
104}111}
105112
106# run given script113# run given script

Subscribers

People subscribed via source and target branches

to all changes: