forked from dnschneid/crouton
-
Notifications
You must be signed in to change notification settings - Fork 0
/
prepare.sh
executable file
·338 lines (300 loc) · 12.3 KB
/
prepare.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
#!/bin/sh -e
# Copyright (c) 2016 The crouton Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
ARCH='#ARCH#'
MIRROR='#MIRROR#'
MIRROR2='#MIRROR2#'
DISTRO='#DISTRO#'
RELEASE='#RELEASE#'
PROXY='#PROXY#'
VERSION='#VERSION#'
USERNAME='#USERNAME#'
SETOPTIONS='#SETOPTIONS#'
# Additional set options: -x or -v can be added for debugging (-e is always on)
if [ -n "$SETOPTIONS" ]; then
set $SETOPTIONS
fi
# We need all paths to do administrative things
export PATH='/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin'
# Common functions
. "`dirname "$0"`/../installer/functions"
# Takes in a list of crouton-style package names, and outputs the list, filtered
# for the current distro.
# A crouton-style package name looks something like the following:
# distro_a+distro_b=pkg_for_a_b,distro_c=pkg_for_c,pkg_for_others
# That means distros A and B will use the first package name, distro C will use
# the second, and all others will use the third. You can also specify a specific
# release in a distro via: distro~release to filter to a specific release.
# If distros have DISTROAKA set (see the distro's prepare script), they can also
# use the pkg name for a distro they are derived from if one specific for them
# has not been specified. So if the distro is "ubuntu", it will use a "debian"
# entry if one is specified and an "ubuntu" one is not.
# The list is not ordered; instead there's a priority to the filtering:
# specific release > distro > parent distro > any distro
# It's safe for a package name to have an = in it as long as the distro is
# specified. This is good for specifying a specific version of a Debian package
# to install, for instance.
# Leaving a pkg name blank will result in that package being dropped for that
# distro. You can do so for all distros not listed by leaving a trailing comma.
# If no package for the distro is found, this will spit out an error and exit.
distropkgs() {
local descriptor desc pkgname rank option optionname optiondistro optionrel
# For each package
for descriptor in "$@"; do
pkgname='.'
rank=0
# For each filter/pkgname pair (add a comma to consider trailing commas)
desc="$descriptor,"
while [ -n "$desc" ]; do
option="${desc%%,*}"
optionname="${option#*=}"
desc="${desc#*,}"
if [ "$optionname" = "$option" ]; then
# No filter specified; minimum rank.
if [ "$rank" -lt 1 ]; then
rank=1
pkgname="$optionname"
fi
continue
fi
# For each distro option in the filter
option="${option%%=*}"
option="${option%+}+"
while [ -n "$option" ]; do
optiondistro="${option%%+*}"
option="${option#*+}"
if [ "${optiondistro%~*}" = "$DISTRO" ]; then
optionrel="${optiondistro#*~}"
if [ "$optionrel" = "$optiondistro" ]; then
# No specific release specified
if [ "$rank" -lt 3 ]; then
rank=3
pkgname="$optionname"
fi
elif [ "$optionrel" = "$RELEASE" ]; then
# Specific release matches
if [ "$rank" -lt 4 ]; then
rank=4
pkgname="$optionname"
fi
fi
elif [ "$optiondistro" = "$DISTROAKA" ]; then
# Option matches parent distro
if [ "$rank" -lt 2 ]; then
rank=2
pkgname="$optionname"
fi
fi
done
done
# Print out the result or error out if nothing found
if [ "$pkgname" != '.' ]; then
echo -n "$pkgname "
else
error 2 "Nothing specified for $DISTRO~$RELEASE in '$descriptor'"
fi
done
}
# install [--minimal] [--asdeps] <packages> -- <avoid packages>
# For the specified crouton-style package names (see distropkgs()), installs
# <packages>, while avoiding installing <avoid packages> if they are not
# already installed.
# If --minimal is specified, avoids installing unnecessary packages.
# Unlike --minimal, <avoid packages> is useful for allowing "recommended"
# dependencies to be brought in while avoiding installing specific ones.
# Distros without "recommended" dependencies can ignore <avoid packages>.
# --asdeps installs the packages, but marks them as dependencies if they are not
# already installed. Running the distro-equivalent of 'autoremove' at the end
# of his script will uninstall such packages, as they are considered as orphans.
install() {
install_dist `distropkgs "$@"`
}
# install_pkg: Installs the specified package file(s), ignoring dependency
# problems, and then attempts to resolve the dependencies. If called without
# parameters, simply fixes any dependency problems.
# If the first parameter is --minimal, avoids installing unnecessary packages.
# Distros that do not support external packages can implement this as an error.
install_pkg() {
install_pkg_dist "$@"
}
# install_dummy: Installs a dummy package that resolves dependencies. The
# parameters are a list of crouton-style package names to "install", optionally
# followed by -- and the packages it depends on.
install_dummy() {
install_dummy_dist `distropkgs "$@"`
}
# remove: Removes the specified packages. See distropkgs() for package syntax.
remove() {
remove_dist `distropkgs "$@"`
}
# list_uninstalled: For the specified crouton-style package names (see
# distropkgs()), prints out any package that is not already installed.
# Appends each package printed out with the contents of the first parameter.
list_uninstalled() {
suffix="$1"
shift
list_uninstalled_dist "$suffix" `distropkgs "$@"`
}
# Requests a re-launch of the preparation script with a fresh chroot setup.
# Generally called immediately after bootstrapping to fix the environment.
relaunch_setup() {
exit 0
}
# Fixes the tty keyboard mode. keyboard-configuration puts tty1~6 in UTF8 mode,
# assuming they are consoles. This isn't true for Chromium OS and crouton, and
# X11 sessions need to be in RAW mode. We do the smart thing and revert ttys
# with X sessions back to RAW. keyboard-configuration could be reconfigured
# after bootstrap, dpkg --configure -a, or dist-upgrade.
fixkeyboardmode() {
if hash kbd_mode 2>/dev/null; then
for tty in `ps -CX -CXorg -otname=`; do
# On some systems, the tty of Chromium OS returns ?
if [ "$tty" = "?" ]; then
tty='tty1'
fi
if [ -e "/dev/$tty" ]; then
kbd_mode -s -C "/dev/$tty" 2>/dev/null || true
fi
done
fi
}
# compile: Grabs the necessary dependencies and then compiles a C file from
# stdin to the specified output and strips it. Finally, removes whatever it
# installed. This allows targets to provide on-demand binaries without
# increasing the size of the chroot after install.
# $1: name; target is /usr/local/(bin|lib)/crouton$1[.so]
# $2: linker flags, quoted together
# [$3]: if 'so', compiles as a shared object and installs it into lib
# $3+: any package dependencies other than gcc and libc-dev, crouton-style.
compile() {
local out="/usr/local/bin/crouton$1"
local linker="$2"
local cflags='-xc -Os -I/usr/src/crouton'
if [ "$3" = 'so' ]; then
out="/usr/local/lib/crouton$1.so"
cflags="$cflags -shared -fPIC"
shift 1
fi
shift 2
echo "Installing dependencies for $out..." 1>&2
local pkgs="gcc libc6-dev $*"
install --minimal --asdeps $pkgs </dev/null
echo "Compiling $out..." 1>&2
local tmp="`mktemp crouton.XXXXXX --tmpdir=/tmp`"
addtrap "rm -f '$tmp'"
gcc $cflags - $linker -o "$tmp"
/usr/bin/install -sDT "$tmp" "$out"
}
# Convert an automake Makefile.am into a shell script, and provide useful
# functions to compile libraries and executables.
# Needs to be run in the same directory as the Makefile.am file.
# This outputs the converted Makefile.am to stdout, which is meant to be
# piped to sh -s (see audio and xiat for examples)
convert_automake() {
echo '
top_srcdir=".."
top_builddir=".."
'
sed -e '
# Concatenate lines ending in \
: start; /\\$/{N; b start}
s/ *\\\n[ \t]*/ /g
# Convert automake to shell
s/^[^ ]*:/#\0/
s/^\t/#\0/
s/\t/ /g
s/ *= */=/
s/\([^ ]*\) *+= */\1=${\1}\ /
s/ /\\ /g
y/()/{}/
s/if\\ !\(.*\)/if [ -z "${\1}" ]; then/
s/if\\ \([^!].*\)/if [ -n "${\1}" ]; then/
s/endif/fi/
' 'Makefile.am'
echo '
# buildsources: Build all source files for target
# $1: target
# $2: additional gcc flags
# Prints a list of .o files
buildsources() {
local target="$1"
local extragccflags="$2"
eval local sources=\"\$${target}_SOURCES\"
eval local cppflags=\"\$${target}_CPPFLAGS\"
local cflags="$cppflags ${CFLAGS} ${AM_CFLAGS}"
for dep in $sources; do
if [ "${dep%.c}" != "$dep" ]; then
ofile="${dep%.c}.o"
gcc -c "$dep" -o "$ofile" '"$archgccflags"' \
$cflags $extragccflags 1>&2 || return $?
echo -n "$ofile "
fi
done
}
# fixlibadd:
# Fix list of libraries ($1): replace lib<x>.la by -l<x>
fixlibadd() {
for libdep in $*; do
if [ "${libdep%.la}" != "$libdep" ]; then
libdep="${libdep%.la}"
libdep="-l${libdep#lib}"
fi
echo -n "$libdep "
done
}
# buildlib: Build a library
# $1: library name
# $2: additional linker flags
buildlib() {
local lib="$1"
local extraflags="$2"
local ofiles
# local eats the return status: separate the 2 statements
ofiles="`buildsources "${lib}_la" "-fPIC -DPIC"`"
eval local libadd=\"\$${lib}_la_LIBADD\"
eval local ldflags=\"\$${lib}_la_LDFLAGS\"
libadd="`fixlibadd $libadd`"
# Detect library version (e.g. 0.0.0)
local fullver="`echo -n "$ldflags" | \
sed -n '\''y/:/./; \
s/.*-version-info \([0-9.]*\)$/\\1/p'\''`"
local shortver=""
# Get "short" library version (e.g. 0)
if [ -n "$fullver" ]; then
shortver=".${fullver%%.*}"
fullver=".$fullver"
fi
local fullso="$lib.so$fullver"
local shortso="$lib.so$shortver"
gcc -shared -fPIC -DPIC $ofiles $libadd -o "$fullso" \
'"$archgccflags"' $extraflags -Wl,-soname,"$shortso"
if [ -n "$fullver" ]; then
ln -sf "$fullso" "$shortso"
# Needed at link-time only
ln -sf "$shortso" "$lib.so"
fi
}
# buildexe: Build an executable file
# $1: executable file name
# $2: additional linker flags
buildexe() {
local exe="$1"
local extraflags="$2"
local ofiles="`buildsources "$exe" ""`"
eval local ldadd=\"\$${exe}_LDADD\"
eval local ldflags=\"\$${exe}_LDFLAGS\"
ldadd="`fixlibadd $ldadd`"
gcc $ofiles $ldadd -o "$exe" '"$archgccflags"' $extraflags
}
'
}
# The rest is dictated first by the distro-specific prepare.sh, and then by the
# selected targets.
# All distro-specific prepare.sh scripts must define the install_dist,
# install_pkg_dist, remove_dist, and list_uninstalled_dist functions.
# They must also set PKGEXT and DISTROAKA.
# Finally, they must do whatever distro-specific bootstrapping is necessary.
# Note that we install targets before adding the user, since targets may affect
# /etc/skel or other default parts. The user is added in post-common, which is
# always added to targets.