README: add link for automatic readme display
[sudo-osx-update.git] / build
blobca43fd070ff6bd7ba37f4df4bbcc1c6656c5602d
1 #!/bin/bash
3 # build -- build version of sudo with Apple-specific patches applied
4 # Copyright (C) 2013 Kyle J. McKay. All rights reserved.
6 # Permission to use, copy, modify, and distribute this software for any
7 # purpose with or without fee is hereby granted, provided that the above
8 # copyright notice and this permission notice appear in all copies.
10 # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 # build version 1.0.1
20 myname="$0"
21 while [ -L "$myname" ]; do
22 oldname="$myname"
23 myname="$(readlink "$myname")"
24 case "$myname" in /*) :;; *)
25 myname="$(dirname "$oldname")/$myname"
26 esac
27 done
28 unset oldname
29 mydir="$(cd "$(dirname "$myname")" && pwd -P)"
30 myname="$(basename "$myname")"
32 case "$mydir" in
33 *' '*)
34 echo "error: build directory path contains a space: '$mydir'" >&2
35 exit 1
37 esac
39 : "${osmaj:=$(sysctl -n kern.osrelease | cut -d. -f1)}"
40 if [ $osmaj -lt 8 ]; then
41 echo "error: build os must be at least 10.4" >&2
42 exit 1
45 # exit on error
46 trap 'echo "FAILED COMMAND ($?): ${BASH_COMMAND:-Run $0 using bash -v for details}"' ERR
47 set -o errexit
49 cd "$mydir"
50 umask 022
52 SUDO174p10='http://www.sudo.ws/sudo/dist/sudo-1.7.10p7.tar.gz'
53 SUDO174p10_MD5=9faa5ceaf23cca0468d0f5d211bac6e4
54 SUDO174p10_SHA1=b5beb1a470d1f03b3940aff612f5089244dd773a
56 SUDO_TGZ="$SUDO174p10"
57 SUDO_MD5="$SUDO174p10_MD5"
58 SUDO_SHA1="$SUDO174p10_SHA1"
60 # Match Apple's sudo man pages use of the man macros for maximum compatibility (--with-man)
61 # Note that only 10.6.x embeds /etc/sudoers, all other OS X versions embed /private/etc/sudoers
62 SUDO_CONFIGURE='--prefix=/usr --sysconfdir=/private/etc --with-timedir=/var/db/sudo --with-man'
63 SUDO_CONFIGURE="$SUDO_CONFIGURE"' --with-noexec=no --with-bsm-audit --with-libraries=bsm --disable-static'
64 # While it appears that 10.7.x and 10.8.x sudo were been built without the disable-setreuid, env-editor,
65 # and password-timeout=0 options (which was apparently a mistake), 10.9.0 restores those options, so we
66 # always add them even if building for 10.7.x/10.8.x.
67 # The "--with-pam" option is redundant as it's automatically selected but we include it anyway to match
68 # what the opensource.apple.com sources have listed.
69 SUDO_CONFIGURE="$SUDO_CONFIGURE"' --with-pam --disable-setreuid --with-env-editor --with-password-timeout=0'
70 # Since the OS X sudo installation does not include sudoreplay there's little point in allowing io logging
71 SUDO_CONFIGURE="$SUDO_CONFIGURE"' --without-iologdir'
72 if [ $osmaj -lt 11 ]; then
73 # Prior to OS X 10.7 the version of sudo used logged by default to the local2 facility so emulate that
74 SUDO_CONFIGURE="$SUDO_CONFIGURE"' --with-logfac=local2' # otherwise current default is authpriv facility
76 if [ $osmaj -lt 9 ]; then
77 # The OS X 10.4 compiler does not support -fstack-protector in any form
78 # and neither does the 10.4 linker support -pie
79 SUDO_CONFIGURE="$SUDO_CONFIGURE"' --disable-hardening --disable-pie'
80 # Also add --disable-env-reset because although env reset by default
81 # is not actually effective until the version of sudo shipped with OS X 10.6
82 # it is activated by the OS X 10.5 /etc/sudoers file so env reset is
83 # effectively active starting with OS X 10.5 and need only be disabled for 10.4
84 SUDO_CONFIGURE="$SUDO_CONFIGURE"' --disable-env-reset'
87 # 10.4 ppc builds only ppc while 10.4 i386 builds i386/ppc
88 # 10.5 builds i386/ppc
89 # 10.6-10.7 builds x86_64/i386
90 # 10.8+ builds only x86_64
91 ARCHS=
92 if [ $osmaj -eq 8 ]; then
93 if [ "$(arch)" = "ppc" ]; then
94 ARCHS=ppc
95 else
96 ARCHS='i386 ppc'
98 elif [ $osmaj -eq 9 ]; then
99 ARCHS='i386 ppc'
100 elif [ $osmaj -eq 10 -o $osmaj -eq 11 ]; then
101 ARCHS='x86_64 i386'
102 elif [ $osmaj -ge 12 ]; then
103 ARCHS='x86_64'
106 DOWNLOADS="$mydir/sources"
107 BUILD="$mydir/sudo"
109 PATH="$(getconf PATH)"
110 export PATH
112 unset CPATH
113 unset LIBRARY_PATH
114 unset DYLD_LIBRARY_PATH
115 unset MANPATH
116 export LDFLAGS="$LDFLAGS -Wl,-S,-x,-dead_strip"
117 if [ $osmaj -ge 9 ]; then
118 LDFLAGS="$LDFLAGS -Wl,-dead_strip_dylibs,-exported_symbols_list,/dev/null"
119 else
120 # The OS X 10.4 linker needs at least one symbol in the file to strip
121 # and it also needs uninteresting warnings suppressed
122 LDFLAGS="$LDFLAGS -Wl,-w,-exported_symbols_list,.symbols_list"
124 for arch in $ARCHS; do
125 CFLAGS="$CFLAGS -arch $arch"
126 LDFLAGS="$LDFLAGS -arch $arch"
127 done
128 export CFLAGS
130 strip1=
131 if ! (tar --strip-path=1 || : ) 2>&1 | grep -Eqi 'unrecognized option|not supported'; then
132 strip1=--strip-path=1
133 elif ! (tar --strip-components=1 || : ) 2>&1 | grep -Eqi 'unrecognized option|not supported'; then
134 strip1=--strip-components=1
136 if [ -z "$strip1" ]; then
137 echo "error: Cannot figure out tar option to strip top level path" >&2
138 exit 1
141 AGENT1='Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)'
142 AGENT2='curl/7.25.0 (unknown-unknown-unknown) libcurl/7.25.0'
143 CURLOPT="--fail --location --connect-timeout 15 --speed-limit 10240"
144 CURLOPT0="$CURLOPT -H 'User-Agent:'"
145 CURLOPT1="$CURLOPT -H 'User-Agent: $AGENT1'"
146 CURLOPT2="$CURLOPT -H 'User-Agent: $AGENT2'"
148 die()
150 echo "Fatal: $*" >&2
151 exit 125;
154 getmd5()
156 openssl dgst -md5 < "$1" 2>/dev/null | sed -e 's/^[^ ][^ ]* //'
159 getsha1()
161 openssl dgst -sha1 < "$1" 2>/dev/null | sed -e 's/^[^ ][^ ]* //'
164 # Usage: downloadfile URL MD5 SHA1
165 # -> output is full path to downloaded file (will be in $DOWNLOADS)
166 downloadfile()
168 local url file md5 sha1 bad
169 url="$1"
170 file="$(basename "$url")"
171 md5="$2"
172 sha1="$3"
173 local checkmd5 checksha1
174 if [ ! -d "$DOWNLOADS" ]; then
175 mkdir "$DOWNLOADS"
177 if [ -e "$DOWNLOADS/$file" ]; then
178 checkmd5="$(getmd5 "$DOWNLOADS/$file")"
179 checksha1="$(getsha1 "$DOWNLOADS/$file")"
180 if [ "$md5" != "$checkmd5" -o "$sha1" != "$checksha1" ]; then
181 echo "Wrong md5/sha1 checksum for $DOWNLOADS/$file -- removing" >&2
182 chmod u+w "$DOWNLOADS/$file"
183 rm "$DOWNLOADS/$file"
186 if [ ! -e "$DOWNLOADS/$file" ]; then
187 eval "curl $CURLOPT0 -o '$DOWNLOADS/$file' '$url'"
189 if [ ! -e "$DOWNLOADS/$file" ]; then
190 echo "Failed to download $url" >&2
191 return 1
193 checkmd5="$(getmd5 "$DOWNLOADS/$file")"
194 checksha1="$(getsha1 "$DOWNLOADS/$file")"
195 bad=
196 if [ "$md5" != "$checkmd5" ]; then
197 bad=1
198 echo "Wrong md5 checksum $checkmd5 (expected $md5) for $DOWNLOADS/$file" >&2
200 if [ "$sha1" != "$checksha1" ]; then
201 bad=1
202 echo "Wrong sha1 checksum $checksha1 (expected $sha1) for $DOWNLOADS/$file" >&2
204 if [ -n "$bad" ]; then
205 echo "Checksum verifcation failed for $url" >&2
206 return 1
208 echo "$DOWNLOADS/$file"
209 return 0
212 # return a suitable directory name for a tarball
213 tgzdir()
215 local tb
216 tb="$(basename "$1")"
217 tb="${tb%.gz}"
218 tb="${tb%.bz2}"
219 tb="${tb%.tar}"
220 tb="${tb%.tgz}"
221 echo "$tb"
224 echo "Fetching/verifying sudo sources tarball" >&2
225 sudotgz="$(downloadfile "$SUDO_TGZ" "$SUDO_MD5" "$SUDO_SHA1")"
226 sudodir="$(tgzdir "$sudotgz")"
228 if [ ! -e "$DOWNLOADS/$sudodir/.extracted" ]; then
229 echo "Extracting sudo sources from tarball" >&2
230 rm -rf "$DOWNLOADS/$sudodir" "$BUILD"
231 mkdir "$DOWNLOADS/$sudodir"
232 tar -xzf "$sudotgz" -C "$DOWNLOADS/$sudodir" "$strip1"
233 touch "$DOWNLOADS/$sudodir/.extracted"
236 if [ ! -e "$DOWNLOADS/$sudodir/.patched" ]; then
237 [ -e "$DOWNLOADS/$sudodir/.extracted" ] || die "bad extraction"
238 echo "Patching sudo sources with Apple tweaks" >&2
239 rm -rf "$BUILD"
240 cd "$DOWNLOADS/$sudodir"
241 for pf in "$mydir/patches/"00*.patch.txt; do
242 echo "$(basename "$pf")" >&2
243 patch -p1 < "$pf"
244 done
245 touch "$DOWNLOADS/$sudodir/.patched"
247 cd "$mydir"
249 if [ ! -e "$BUILD/.configured" ]; then
250 [ -e "$DOWNLOADS/$sudodir/.patched" ] || die "bad patching operation"
251 echo "Configuring sudo build for OS X" >&2
252 rm -rf "$BUILD"
253 mkdir -p "$BUILD"
254 cd "$BUILD"
255 if [ $osmaj -lt 9 ]; then
256 echo __mh_execute_header > .symbols_list
258 "$DOWNLOADS/$sudodir/configure" $SUDO_CONFIGURE
259 echo "Stripping CONFIGURE_ARGS to match Apple sudo installation" >&2
260 perl -i -pe 's/"[^"]+"/""/ if /^#define CONFIGURE_ARGS/' sudo_usage.h
261 echo "Enabling HAVE_TCSETPGRP which is not set properly with --without-iologdir" >&2
262 perl -i -pe 's,^/[^/]+/,#define HAVE_TCSETPGRP 1, if /HAVE_TCSETPGRP/' config.h
263 touch "$BUILD/.configured"
265 cd "$mydir"
267 if [ ! -e "$BUILD/.built" ]; then
268 [ -e "$BUILD/.configured" ] || die "bad configure operation"
269 echo "Making sudo build for OS X" >&2
270 make -w -C "$BUILD"
271 [ -x "$BUILD/sudo" ] || die "build failed"
272 touch "$BUILD/.built"
275 echo ""
276 echo "The newly built sudo executable can be found in the directory:"
277 echo " $BUILD"
278 echo ""
279 echo "It can be installed with:"
280 echo " sudo make -C '$BUILD' install"
281 echo ""
282 echo "IMPORTANT: running the above install WILL REPLACE YOUR EXISTING sudo!!!"
283 echo ""
284 echo "Try the following to see what will be installed without installing:"
285 echo " make -C '$BUILD' -n install"
286 echo ""
287 echo "Note that the DESTDIR=/some/dir option can be used to perform a test"
288 echo "install to a different location first like so:"
289 echo " sudo make -C '$BUILD' DESTDIR=/tmp/testsudo install"
290 echo ""
291 echo "Using a test installation first can help decide whether or not to go"
292 echo "ahead with a normal installation."
293 echo ""