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
1=== modified file 'debian/changelog'
2--- debian/changelog 2011-09-23 11:26:29 +0000
3+++ debian/changelog 2011-10-24 16:08:30 +0000
4@@ -1,3 +1,9 @@
5+isc-dhcp (4.1.1-P1-17ubuntu11) UNRELEASED; urgency=low
6+
7+ * debian/dhclient-script.linux: fix for read-only /etc (LP: #857524)
8+
9+ -- Scott Moser <smoser@ubuntu.com> Fri, 23 Sep 2011 12:07:24 -0400
10+
11 isc-dhcp (4.1.1-P1-17ubuntu10) oneiric; urgency=low
12
13 * make sure writing of /etc/resolv.conf actually waits until the file is
14
15=== modified file 'debian/dhclient-script.linux'
16--- debian/dhclient-script.linux 2011-09-23 11:26:29 +0000
17+++ debian/dhclient-script.linux 2011-10-24 16:08:30 +0000
18@@ -12,8 +12,9 @@
19
20 # The alias handling in here probably still sucks. -mdz
21
22-# wait for /etc/resolv.conf to become writable
23+# wait for given file to be writable
24 wait_for_rw() {
25+ local file=$1
26 # Find out whether we are going to mount / rw
27 exec 9>&0 </etc/fstab
28 rootmode=rw
29@@ -27,9 +28,9 @@
30 done
31 exec 0>&9 9>&-
32
33- # Wait for /etc/resolv.conf to become writable
34+ # Wait for $file to become writable
35 if [ "$rootmode" = "rw" ]; then
36- while ! { : >> /etc/resolv.conf; } 2>/dev/null; do
37+ while ! { : >> "$file"; } 2>/dev/null; do
38 sleep 0.1
39 done
40 fi
41@@ -37,17 +38,23 @@
42
43 # update /etc/resolv.conf based on received values
44 make_resolv_conf() {
45- local new_resolv_conf
46+ local old_ns="" resolv_conf="" new_resolv_conf=""
47+ [ -e /etc/resolv.conf ] && old_ns=$(grep -i '^nameserver' /etc/resolv.conf)
48+
49+ resolv_conf=$(readlink -f "/etc/resolv.conf" 2>/dev/null) ||
50+ resolv_conf="/etc/resolv.conf"
51+
52+ # write to temp file in same directory as target
53+ new_resolv_conf="${resolv_conf}.dhclient-new.$$"
54
55 # DHCPv4
56 if [ -n "$new_domain_search" ] || [ -n "$new_domain_name" ] ||
57 [ -n "$new_domain_name_servers" ]; then
58- wait_for_rw
59- new_resolv_conf=/etc/resolv.conf.dhclient-new
60- rm -f $new_resolv_conf
61+ wait_for_rw "$new_resolv_conf"
62
63+ {
64 if [ -n "$new_domain_name" ]; then
65- echo domain ${new_domain_name%% *} >>$new_resolv_conf
66+ echo domain ${new_domain_name%% *}
67 fi
68
69 if [ -n "$new_domain_search" ]; then
70@@ -63,44 +70,44 @@
71 new_domain_search="$new_domain_name $new_domain_search"
72 fi
73 fi
74- echo "search ${new_domain_search}" >> $new_resolv_conf
75+ echo "search ${new_domain_search}"
76 elif [ -n "$new_domain_name" ]; then
77- echo "search ${new_domain_name}" >> $new_resolv_conf
78+ echo "search ${new_domain_name}"
79 fi
80
81 if [ -n "$new_domain_name_servers" ]; then
82 for nameserver in $new_domain_name_servers; do
83- echo nameserver $nameserver >>$new_resolv_conf
84+ echo nameserver $nameserver
85 done
86- else # keep 'old' nameservers
87- sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p /etc/resolv.conf >>$new_resolv_conf
88+ elif [ -n "$old_ns" ]; then # keep 'old' nameservers
89+ echo "$old_ns"
90 fi
91-
92- chown --reference=/etc/resolv.conf $new_resolv_conf
93- chmod --reference=/etc/resolv.conf $new_resolv_conf
94- mv -f $new_resolv_conf /etc/resolv.conf
95+ } > "$new_resolv_conf"
96 # DHCPv6
97 elif [ -n "$new_dhcp6_domain_search" ] || [ -n "$new_dhcp6_name_servers" ]; then
98- wait_for_rw
99- new_resolv_conf=/etc/resolv.conf.dhclient-new
100- rm -f $new_resolv_conf
101+ wait_for_rw "$new_resolv_conf"
102
103+ {
104 if [ -n "$new_dhcp6_domain_search" ]; then
105- echo "search ${new_dhcp6_domain_search}" >> $new_resolv_conf
106+ echo "search ${new_dhcp6_domain_search}"
107 fi
108
109 if [ -n "$new_dhcp6_name_servers" ]; then
110 for nameserver in $new_dhcp6_name_servers; do
111- echo nameserver $nameserver >>$new_resolv_conf
112+ echo nameserver $nameserver
113 done
114- else # keep 'old' nameservers
115- sed -n /^\w*[Nn][Aa][Mm][Ee][Ss][Ee][Rr][Vv][Ee][Rr]/p /etc/resolv.conf >>$new_resolv_conf
116+ elif [ -n "$old_ns" ]; then # keep 'old' nameservers
117+ echo "$old_ns"
118 fi
119-
120- chown --reference=/etc/resolv.conf $new_resolv_conf
121- chmod --reference=/etc/resolv.conf $new_resolv_conf
122- mv -f $new_resolv_conf /etc/resolv.conf
123+ } > "$new_resolv_conf"
124 fi
125+
126+ [ -e "$resolv_conf" ] &&
127+ chmod --reference="$resolv_conf" "$new_resolv_conf" &&
128+ chown --reference="$resolv_conf" "$new_resolv_conf"
129+
130+ mv "$new_resolv_conf" "$resolv_conf" ||
131+ { rm -f "$new_resolv_conf"; return 1; }
132 }
133
134 # run given script

Subscribers

People subscribed via source and target branches

to all changes: