Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

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