Skip to content
Newer
Older
100755 417 lines (331 sloc) 10 KB
75052c2 @falconindy initial commit
authored Apr 26, 2011
1 #!/bin/bash
2
3 shopt -s extglob
4
5 declare -A modquirks
6
570ed43 @falconindy add -s option for saving the filelist. declare globals in an obvious …
authored Apr 29, 2011
7 # tender vittles
75052c2 @falconindy initial commit
authored Apr 27, 2011
8 _sysconfdir=/etc
9 _sharedir=.
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 27, 2011
10 builderdir=${_sharedir}/builders
11 baseconfig=${_sysconfdir}/geninit.conf
75052c2 @falconindy initial commit
authored Apr 27, 2011
12 carch=$(uname -m)
13 kernver=$(uname -r)
14
15 # declared as an array to force expansion. would be great if arch had
16 # symlink pointing to this from /lib/ld.so
1f2aff1 @falconindy add support for kernel presets
authored Apr 28, 2011
17 ld_so=(/lib/ld-linux-${carch//_/-}.so.?*)
18
19 # Alter PATH. We want to make sure that /bin and /sbin are favored, since
20 # we specifically rely on GNU coreutils
21 PATH=/sbin:/bin:$PATH
75052c2 @falconindy initial commit
authored Apr 27, 2011
22
570ed43 @falconindy add -s option for saving the filelist. declare globals in an obvious …
authored Apr 29, 2011
23 # error codes
24 ENOENT=2
25 EACCES=13
26 EEXIST=17
27 EINVAL=22
28
29 # globals
30 declare -i automods=0
31 declare -i savefilelist=0
32 declare basedir=
33 declare config=
34 declare imagename=
35 declare kernver=
36 declare preset=
37 declare skipbuilders=
38 declare ocompress=
39 declare dryrun=
40
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
41 # -------------------------- #
42 ## general util functions ##
43 # -------------------------- #
75052c2 @falconindy initial commit
authored Apr 27, 2011
44
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
45 err() { # {{{
75052c2 @falconindy initial commit
authored Apr 27, 2011
46 printf 'error: %s\n' "$*"
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
47 } >&2 # }}}
75052c2 @falconindy initial commit
authored Apr 27, 2011
48
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
49 info() { # {{{
75052c2 @falconindy initial commit
authored Apr 27, 2011
50 printf ':: %s\n' "$*"
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
51 } # }}}
75052c2 @falconindy initial commit
authored Apr 27, 2011
52
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
53 die() { # {{{
75052c2 @falconindy initial commit
authored Apr 27, 2011
54 err "$*"
55 cleanup 1
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
56 } # }}}
75052c2 @falconindy initial commit
authored Apr 27, 2011
57
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
58 in_array() { # {{{
75052c2 @falconindy initial commit
authored Apr 27, 2011
59 local item needle=$1; shift
60 [[ -z $1 ]] && return 1 # Not Found
61
62 for item; do
63 [[ $item = $needle ]] && return 0 # Found
64 done
65 return 1 # Not Found
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
66 } # }}}
75052c2 @falconindy initial commit
authored Apr 27, 2011
67
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
68 qgrep() { # {{{
75052c2 @falconindy initial commit
authored Apr 27, 2011
69 2>/dev/null grep -q "$@"
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
70 } # }}}
75052c2 @falconindy initial commit
authored Apr 27, 2011
71
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
72 kmodinfo() { # {{{
75052c2 @falconindy initial commit
authored Apr 27, 2011
73 modinfo -0k $kernver "$@"
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
74 } # }}}
75052c2 @falconindy initial commit
authored Apr 27, 2011
75
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
76 cleanup() { # {{{
75052c2 @falconindy initial commit
authored Apr 27, 2011
77 rm -rf "$tmpdir"
78 exit $1
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
79 } # }}}
75052c2 @falconindy initial commit
authored Apr 27, 2011
80
25a82f8 @falconindy add a usage function
authored Apr 28, 2011
81 usage() { # {{{
82 cat<<USAGE
83 geninit
84 Usage: geninit [options]
85
86 Options:
87 -b <path> Use base directory (default: /)
88 -c <file> Specify a different config file (default: $_sysconfdir/geninit.conf)
89 -g <path> Path and name of generated image (dry-run if unspecified)
90 -h Display this help message
91 -k <kver> Specify a different kernel version (default: $(uname -r))
92 -p <preset> Build using a preset file
93 -S <names> Skip the specified builders during the build process
94 -v Output more
95 -z <method> Override compression method
96
97 USAGE
98 exit
99 } # }}}
100
04d836e @falconindy relocate build_preset. rename it to __build_preset and declare a "pri…
authored Apr 28, 2011
101 # --------------- #
102 ## private API ##
103 # --------------- #
75052c2 @falconindy initial commit
authored Apr 27, 2011
104
105 __add_file() { # {{{
106 # add a file to cpio_filelist
107 # $1: pathname on initcpio
108 # $2: source on disk
109 # $3: mode
110
111 # file <dest> <src> <mode> <uid> <gid> [<hard links>]
112
113 (( $# == 3 )) || return $EINVAL
114
115 qgrep "^file $1 " "$cpio_filelist" && return $EEXIST
116 printf 'file %s %s %s 0 0\n' "$@" >>"$cpio_filelist"
117 } # }}}
118
119 __add_dir() { # {{{
120 # add a directory to cpio_filelist (no knowledge of parents, use add_path instead)
121 # $1: pathname on initcpio
122 # $2: mode
123
124 # dir <name> <mode> <uid> <gid>
125
126 (( $# == 2 )) || [[ $1 == /?* ]] || return $EINVAL
127
128 local name=$1 mode=$2
129
130 qgrep "^dir $name " "$cpio_filelist" && return $EEXIST
131 printf 'dir %s %s 0 0\n' "$@" >>"$cpio_filelist"
132 } # }}}
133
134 __add_slink() { # {{{
135 # add a symlink to cpio_filelist
136 # $1: name on initcpio
137 # $2: target of $1
138
139 # slink <name> <target> <mode> <uid> <gid>
140
141 (( $# == 2 )) || return $EINVAL
142
143 local name=$1 target=$2
144
145 qgrep "^slink $name " "$cpio_filelist" && return $EEXIST
146 printf 'slink %s %s 777 0 0\n' "$name" "$target" >> "$cpio_filelist"
147 } # }}}
148
149 __add_pipe() { # {{{
150 # add a pipe to cpio_filelist
151 # $1: pathname on initcpio
152 # $2: mode
153
154 # pipe <name> <mode> <uid> <gid>
155
156 (( $# == 2 )) || return $EINVAL
157
158 local name=$1 mode=$2
159
160 qgrep "^pipe $name " "$cpio_filelist" && return $EEXIST
161 printf 'pipe %s %s 0 0\n' "$name" "$mode" >> "$cpio_filelist"
162 } # }}}
163
164 __add_sock() { # {{{
165 # add a socket to cpio_filelist
166 # $1: pathname on initcpio
167 # $2: mode
168
169 # sock <name> <mode> <uid> <gid>
170 local name=$1 mode=$2
171
172 qgrep "^sock $name " "$cpio_filelist" && return $EEXIST
173 printf 'sock %s %s 0 0\n' "$name" "$mode" >> "$cpio_filelist"
174 } # }}}
175
2fa6276 @falconindy move main loop logic into its own function. localize variables
authored Apr 28, 2011
176 __build_image() { # {{{
177 declare -i modcount=0
178 declare -a zopts pipesave
179 declare builder= module= line= mod= file=
180
181 # parse builder array
182 for builder in "${builders[@]}"; do
183 in_array "$builder" "${skipbuilders[@]}" && continue
184
185 if [[ ! -f $builderdir/$builder ]]; then
186 err "cannot find builder '$builder': No such file"
187 continue
188 fi
189
f2136d7 @falconindy add quirks file for quirky modules
authored Apr 28, 2011
190 # subshell to prevent namespace pollution
191 . "$builderdir/$builder"
192 if ! type -t build >/dev/null; then
193 err "no build function found in builder '$builder'"
194 continue
195 fi
196
197 info "Processing buildstep: [$builder]"
198 build
2fa6276 @falconindy move main loop logic into its own function. localize variables
authored Apr 29, 2011
199 done
200
201 # add extra modules from config
202 for mod in ${modules[@]}; do
203 add_module "$mod"
204 done
205
206 # add extra files from config
207 for file in "${files[@]}"; do
208 add_file "$file"
209 done
210
211 # generate depmod files
212 info "Generating module dependencies"
213 while read line; do
214 if [[ $line =~ /lib/modules/[^[:space:]]+\.ko?(.gz) ]]; then
215 module=${BASH_REMATCH[0]}
216 install -Dm644 "$basedir$module" "$tmpdir$module"
217 (( ++modcount ))
218 fi
219 done < "$cpio_filelist"
220
221 if (( modcount )); then
222 depmod -b "$tmpdir" "$kernver"
223 for file in modules.{dep,alias,symbols}; do
224 add_file "${tmpdir}${moduledir}/$file" "/lib/modules/$kernver/$file"
225 done
226 fi
227
570ed43 @falconindy add -s option for saving the filelist. declare globals in an obvious …
authored Apr 29, 2011
228 if (( savefilelist )); then
229 imagename=${imagename:-image} # set during a dry-run
230 if cp "$cpio_filelist" "/tmp/${imagename##*/}.filelist"; then
231 info "image filelist saved to /tmp/${imagename##*/}.filelist"
232 else
233 err "failed to save filelist to /tmp" # should never happen
234 fi
235 fi
236
2fa6276 @falconindy move main loop logic into its own function. localize variables
authored Apr 29, 2011
237 if (( dryrun )); then
238 info "Dry run complete. Use -g <path> to create an initramfs."
239 cleanup 0
240 fi
241
242 if [[ $compress != cat ]]; then
243 zopts=('-9')
244 [[ $compress = xz ]] && zopts+=('--check=crc32')
245 fi
246
247 info "Creating$([[ $compress = cat ]] || printf " $compress") initramfs: $imagename"
248 gen_init_cpio $cpio_filelist | "$compress" "${zopts[@]}" > "$imagename"
249 pipesave=("${PIPESTATUS[@]}") # save immediately
250
251 (( pipesave[0] )) && die "failed to create initramfs image"
252 (( pipesave[1] )) && die "error compressing initramfs image"
253 info "Image creation completed successfully"
254
255 return $(( !!(pipesave[0] + pipesave[1]) ))
256 } # }}}
257
04d836e @falconindy relocate build_preset. rename it to __build_preset and declare a "pri…
authored Apr 29, 2011
258 __build_preset() { # {{{
259 local preset= presetfile=$_sysconfdir/geninit.d/$1.preset
260 local -a presets
261
262 if [[ ! -f $basedir$presetfile ]]; then
263 err "preset not found: $1"
264 return $ENOENT
265 fi
266
267 if ! . "$basedir$presetfile"; then
268 err "failed to read preset: $1"
269 return $EACCES
270 fi
271
272 local var= cfg= opts= imagename=
273
274 # preset pulls in a known array 'presets'
275 for preset in "${presets[@]}"; do
276 # resolve kernel version
277 if [[ -z $ALL_kver ]]; then
278 err "No kernel version defined for preset \`$1'"
279 return $EINVAL
280 fi
281
282 # resolve image name
283 var=${preset}_image
284 if [[ -z ${!var} ]]; then
285 err "No imagename defined for preset \`$1'"
286 return $EINVAL
287 fi
288 imagename=${!var}
289
290 # extra config
291 var=${preset}_config
292 if [[ -z ${!var} ]]; then
293 # fallback on $ALL_config if its available
294 cfg=${ALL_config:-$_sysconfigdir/geninit.conf}
295 else
296 cfg=${!var}
297 fi
298
299 # extra options are optional
300 var=${preset}_options
301 opts=${!var}
302
303 # this should always resolve to something (i hope)
304 if [[ ! -f $basedir$cfg ]]; then
305 err "preset config file not found: \`$basedir$cfg'"
306 return $ENOENT
307 fi
308
309 # we've got enough to relaunch geninit now
310 # TODO: don't relaunch. Do this the sane way.
311 info "Building image from preset: $1-$preset"
312 printf ' ==> %s\n' "-k $ALL_kver -c $cfg -g $basedir$imagename $opts"
313 "$0" -b "$basedir" -k "$ALL_kver" -c "$cfg" -g "$basedir$imagename" $opts || return 1
314 echo
315 done
316 } # }}}
317
75052c2 @falconindy initial commit
authored Apr 27, 2011
318 # its a trap!
319 trap 'cleanup 130' SIGINT
320 trap 'cleanup 143' SIGTERM
321
04d836e @falconindy relocate build_preset. rename it to __build_preset and declare a "pri…
authored Apr 29, 2011
322 # source public API
5aad559 @falconindy cleanup commenting in main file, do a little reorg
authored Apr 28, 2011
323 . "$_sharedir/geninit.api"
75052c2 @falconindy initial commit
authored Apr 27, 2011
324
f2136d7 @falconindy add quirks file for quirky modules
authored Apr 29, 2011
325 # source module quirks file
326 . "$_sharedir/geninit.quirks"
327
75052c2 @falconindy initial commit
authored Apr 27, 2011
328 # ------------------ #
329 ## option parsing ##
330 # ------------------ #
331
570ed43 @falconindy add -s option for saving the filelist. declare globals in an obvious …
authored Apr 29, 2011
332 while getopts ':b:c:g:hk:Mp:S:sz:' flag; do
75052c2 @falconindy initial commit
authored Apr 27, 2011
333 case $flag in
334 b) basedir=$OPTARG ;;
335 c) config=$OPTARG ;;
336 g) imagename=$OPTARG ;;
25a82f8 @falconindy add a usage function
authored Apr 29, 2011
337 h) usage ;;
75052c2 @falconindy initial commit
authored Apr 27, 2011
338 k) kernver=$OPTARG ;;
a7370a0 @falconindy add -M option for dumping autodetected modules
authored Apr 29, 2011
339 M) automods=1 ;;
1f2aff1 @falconindy add support for kernel presets
authored Apr 28, 2011
340 p) preset=$OPTARG ;;
341 S) skipbuilders=(${OPTARG//,/ }) ;;
570ed43 @falconindy add -s option for saving the filelist. declare globals in an obvious …
authored Apr 29, 2011
342 s) savefilelist=1 ;;
75052c2 @falconindy initial commit
authored Apr 27, 2011
343 z) ocompress=$OPTARG ;; # named differently to allow overriding
344 :) die "option requires an argument -- '$OPTARG'" ;;
345 \?) die "invalid option -- '$OPTARG'" ;;
346 esac
347 done
348
349 # ----------------- #
350 ## sanity checks ##
351 # ----------------- #
352
353 # how did our ld.so resolution go?
354 if (( ${#ld_so[*]} != 1 )); then # uh oh...
355 die "failed to resolve the location of /lib/ld.so. Please report this bug."
356 fi
357
358 # make sure our config exists, and source it
359 config=${config:-$baseconfig}
360 [[ ! -f $config ]] && die "failed to find config file: \`$config'" || . "$config"
361
e17a205 @falconindy fix inaccurate comment wrt basedir
authored Apr 29, 2011
362 # if specified, does the basedir exist? trim any trailing slash
75052c2 @falconindy initial commit
authored Apr 27, 2011
363 if [[ $basedir ]]; then
364 basedir=${basedir%/}
365 [[ -d $basedir ]] || die "basedir \`$basedir' not found"
366 fi
367
368 # does the kernel exist inside the basedir?
369 [[ -d $basedir/lib/modules/$kernver ]] || die "kernel \`$kernver' not found"
370
371 # is our supplied compression method (if supplied) valid?
372 compress=${ocompress:-$compress}
6048c99 @falconindy allow 'none' as a compression option
authored Apr 28, 2011
373 if [[ -z $compress || $compress = none ]]; then
374 compress=cat # NOOP compressor
375 else
75052c2 @falconindy initial commit
authored Apr 27, 2011
376 [[ $compress = @(gzip|bzip2|lzma|xz) ]] || die "unknown compression method: $compress"
377 type -P "$compress" >/dev/null || die "failed to find \`$compress' binary in PATH"
378 fi
379
340a7c4 @falconindy add support for dry runs
authored Apr 28, 2011
380 # if $imagename is provided, its path needs to be valid
381 if [[ $imagename ]]; then
aeea626 @falconindy fail when imagepath's dirname isn't writeable
authored Apr 28, 2011
382 imagepath=$(readlink -f "$imagename")
383 [[ $imagepath ]] || die "invalid path to imagename: $imagename"
384 [[ -w ${imagepath%/*} ]] || die "no permission to write to specified path: \`${imagepath%/*}'"
340a7c4 @falconindy add support for dry runs
authored Apr 28, 2011
385 else # no $imagename, so we're doing a dry run
386 dryrun=1
387 fi
75052c2 @falconindy initial commit
authored Apr 27, 2011
388
389 # ------------ #
390 ## int main ##
391 # ------------ #
392
393 # define a few paths for convenience
394 tmpdir=$(mktemp -d /tmp/${0##*/}.XXXXXX)
395 moduletmp=$tmpdir/modules
396 cpio_filelist=$tmpdir/cpiofilelist.$$
397 autodetect_cache=$tmpdir/autodetect.cache
398 moduledir=/lib/modules/$kernver
399
a7370a0 @falconindy add -M option for dumping autodetected modules
authored Apr 29, 2011
400 if (( automods )); then
401 . "$_sharedir/builders/autodetect" || die "unable to source autodetect builder"
402 build
403 info "Autodetected modules"
404 [[ -s $autodetect_cache ]] && cat "$autodetect_cache"
405 cleanup 0
406 fi
407
64aa373 @falconindy announce a dry run to avoid freaking out the user
authored Apr 29, 2011
408 (( dryrun )) && info "Starting dry run"
1f2aff1 @falconindy add support for kernel presets
authored Apr 28, 2011
409 if [[ $preset ]]; then
04d836e @falconindy relocate build_preset. rename it to __build_preset and declare a "pri…
authored Apr 29, 2011
410 __build_preset "$preset"
2fa6276 @falconindy move main loop logic into its own function. localize variables
authored Apr 29, 2011
411 else
412 __build_image
75052c2 @falconindy initial commit
authored Apr 27, 2011
413 fi
414
2fa6276 @falconindy move main loop logic into its own function. localize variables
authored Apr 29, 2011
415 cleanup $?
75052c2 @falconindy initial commit
authored Apr 27, 2011
416
Something went wrong with that request. Please try again.