Commit d39a206bc35d46a3b2eb98cd4f34e340d5e56a50
1 parent
d9df92e22a
kbuild: rebuild initramfs if content of initramfs changes
initramfs.cpio.gz being build in usr/ and included in the kernel was not rebuild when the included files changed. To fix this the following was done: - let gen_initramfs.sh generate a list of files and directories included in the initramfs - gen_initramfs generate the gzipped cpio archive so we could simplify the kbuild file (Makefile) - utilising the kbuild infrastructure so when uid/gid root mapping changes the initramfs will be rebuild With this change we have a much more robust initramfs generation. Signed-off-by: Sam Ravnborg <sam@ravnborg.org>
Showing 2 changed files with 189 additions and 127 deletions Side-by-side Diff
scripts/gen_initramfs_list.sh
1 | 1 | #!/bin/bash |
2 | 2 | # Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org> |
3 | +# Copyright (c) 2006 Sam Ravnborg <sam@ravnborg.org> | |
4 | +# | |
3 | 5 | # Released under the terms of the GNU GPL |
4 | 6 | # |
5 | -# Generate a newline separated list of entries from the file/directory | |
6 | -# supplied as an argument. | |
7 | -# | |
8 | -# If a file/directory is not supplied then generate a small dummy file. | |
9 | -# | |
10 | -# The output is suitable for gen_init_cpio built from usr/gen_init_cpio.c. | |
11 | -# | |
7 | +# Generate a cpio packed initramfs. It uses gen_init_cpio to generate | |
8 | +# the cpio archive, and gzip to pack it. | |
9 | +# The script may also be used to generate the inputfile used for gen_init_cpio | |
10 | +# This script assumes that gen_init_cpio is located in usr/ directory | |
12 | 11 | |
12 | +# error out on errors | |
13 | +set -e | |
14 | + | |
15 | +usage() { | |
16 | +cat << EOF | |
17 | +Usage: | |
18 | +$0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ... | |
19 | + -o <file> Create gzipped initramfs file named <file> using | |
20 | + gen_init_cpio and gzip | |
21 | + -u <uid> User ID to map to user ID 0 (root). | |
22 | + <uid> is only meaningful if <cpio_source> | |
23 | + is a directory. | |
24 | + -g <gid> Group ID to map to group ID 0 (root). | |
25 | + <gid> is only meaningful if <cpio_source> | |
26 | + is a directory. | |
27 | + <cpio_source> File list or directory for cpio archive. | |
28 | + If <cpio_source> is a .cpio file it will be used | |
29 | + as direct input to initramfs. | |
30 | + -d Output the default cpio list. | |
31 | + | |
32 | +All options except -o and -l may be repeated and are interpreted | |
33 | +sequentially and immediately. -u and -g states are preserved across | |
34 | +<cpio_source> options so an explicit "-u 0 -g 0" is required | |
35 | +to reset the root/group mapping. | |
36 | +EOF | |
37 | +} | |
38 | + | |
39 | +list_default_initramfs() { | |
40 | + # echo usr/kinit/kinit | |
41 | + : | |
42 | +} | |
43 | + | |
13 | 44 | default_initramfs() { |
14 | - cat <<-EOF | |
45 | + cat <<-EOF >> ${output} | |
15 | 46 | # This is a very simple, default initramfs |
16 | 47 | |
17 | 48 | dir /dev 0755 0 0 |
18 | 49 | nod /dev/console 0600 0 0 c 5 1 |
19 | 50 | dir /root 0700 0 0 |
51 | + # file /kinit usr/kinit/kinit 0755 0 0 | |
52 | + # slink /init kinit 0755 0 0 | |
20 | 53 | EOF |
21 | 54 | } |
22 | 55 | |
23 | 56 | |
24 | 57 | |
25 | 58 | |
26 | 59 | |
... | ... | @@ -42,18 +75,28 @@ |
42 | 75 | return 0 |
43 | 76 | } |
44 | 77 | |
78 | +list_print_mtime() { | |
79 | + : | |
80 | +} | |
81 | + | |
45 | 82 | print_mtime() { |
46 | - local argv1="$1" | |
47 | 83 | local my_mtime="0" |
48 | 84 | |
49 | - if [ -e "${argv1}" ]; then | |
50 | - my_mtime=$(find "${argv1}" -printf "%T@\n" | sort -r | head -n 1) | |
85 | + if [ -e "$1" ]; then | |
86 | + my_mtime=$(find "$1" -printf "%T@\n" | sort -r | head -n 1) | |
51 | 87 | fi |
52 | - | |
53 | - echo "# Last modified: ${my_mtime}" | |
54 | - echo | |
88 | + | |
89 | + echo "# Last modified: ${my_mtime}" >> ${output} | |
90 | + echo "" >> ${output} | |
55 | 91 | } |
56 | 92 | |
93 | +list_parse() { | |
94 | + echo "$1 \\" | |
95 | +} | |
96 | + | |
97 | +# for each file print a line in following format | |
98 | +# <filetype> <name> <path to file> <octal mode> <uid> <gid> | |
99 | +# for links, devices etc the format differs. See gen_init_cpio for details | |
57 | 100 | parse() { |
58 | 101 | local location="$1" |
59 | 102 | local name="${location/${srcdir}//}" |
60 | 103 | |
61 | 104 | |
62 | 105 | |
63 | 106 | |
64 | 107 | |
65 | 108 | |
66 | 109 | |
67 | 110 | |
68 | 111 | |
69 | 112 | |
70 | 113 | |
71 | 114 | |
72 | 115 | |
73 | 116 | |
... | ... | @@ -99,80 +142,112 @@ |
99 | 142 | ;; |
100 | 143 | esac |
101 | 144 | |
102 | - echo "${str}" | |
145 | + echo "${str}" >> ${output} | |
103 | 146 | |
104 | 147 | return 0 |
105 | 148 | } |
106 | 149 | |
107 | -usage() { | |
108 | - printf "Usage:\n" | |
109 | - printf "$0 [ [-u <root_uid>] [-g <root_gid>] [-d | <cpio_source>] ] . . .\n" | |
110 | - printf "\n" | |
111 | - printf -- "-u <root_uid> User ID to map to user ID 0 (root).\n" | |
112 | - printf " <root_uid> is only meaningful if <cpio_source>\n" | |
113 | - printf " is a directory.\n" | |
114 | - printf -- "-g <root_gid> Group ID to map to group ID 0 (root).\n" | |
115 | - printf " <root_gid> is only meaningful if <cpio_source>\n" | |
116 | - printf " is a directory.\n" | |
117 | - printf "<cpio_source> File list or directory for cpio archive.\n" | |
118 | - printf " If <cpio_source> is not provided then a\n" | |
119 | - printf " a default list will be output.\n" | |
120 | - printf -- "-d Output the default cpio list. If no <cpio_source>\n" | |
121 | - printf " is given then the default cpio list will be output.\n" | |
122 | - printf "\n" | |
123 | - printf "All options may be repeated and are interpreted sequentially\n" | |
124 | - printf "and immediately. -u and -g states are preserved across\n" | |
125 | - printf "<cpio_source> options so an explicit \"-u 0 -g 0\" is required\n" | |
126 | - printf "to reset the root/group mapping.\n" | |
150 | +unknown_option() { | |
151 | + printf "ERROR: unknown option \"$arg\"\n" >&2 | |
152 | + printf "If the filename validly begins with '-', " >&2 | |
153 | + printf "then it must be prefixed\n" >&2 | |
154 | + printf "by './' so that it won't be interpreted as an option." >&2 | |
155 | + printf "\n" >&2 | |
156 | + usage >&2 | |
157 | + exit 1 | |
127 | 158 | } |
128 | 159 | |
129 | -build_list() { | |
130 | - printf "\n#####################\n# $cpio_source\n" | |
160 | +list_header() { | |
161 | + echo "deps_initramfs := \\" | |
162 | +} | |
131 | 163 | |
132 | - if [ -f "$cpio_source" ]; then | |
133 | - print_mtime "$cpio_source" | |
134 | - cat "$cpio_source" | |
135 | - elif [ -d "$cpio_source" ]; then | |
136 | - srcdir=$(echo "$cpio_source" | sed -e 's://*:/:g') | |
137 | - dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" 2>/dev/null) | |
164 | +header() { | |
165 | + printf "\n#####################\n# $1\n" >> ${output} | |
166 | +} | |
138 | 167 | |
139 | - # If $dirlist is only one line, then the directory is empty | |
140 | - if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then | |
141 | - print_mtime "$cpio_source" | |
142 | - | |
143 | - echo "${dirlist}" | \ | |
144 | - while read x; do | |
145 | - parse ${x} | |
146 | - done | |
168 | +# process one directory (incl sub-directories) | |
169 | +dir_filelist() { | |
170 | + ${dep_list}header "$1" | |
171 | + | |
172 | + srcdir=$(echo "$1" | sed -e 's://*:/:g') | |
173 | + dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" 2>/dev/null) | |
174 | + | |
175 | + # If $dirlist is only one line, then the directory is empty | |
176 | + if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then | |
177 | + ${dep_list}print_mtime "$1" | |
178 | + | |
179 | + echo "${dirlist}" | \ | |
180 | + while read x; do | |
181 | + ${dep_list}parse ${x} | |
182 | + done | |
183 | + fi | |
184 | +} | |
185 | + | |
186 | +# if only one file is specified and it is .cpio file then use it direct as fs | |
187 | +# if a directory is specified then add all files in given direcotry to fs | |
188 | +# if a regular file is specified assume it is in gen_initramfs format | |
189 | +input_file() { | |
190 | + source="$1" | |
191 | + if [ -f "$1" ]; then | |
192 | + ${dep_list}header "$1" | |
193 | + is_cpio="$(echo "$1" | sed 's/^.*\.cpio/cpio/')" | |
194 | + if [ $2 -eq 0 -a ${is_cpio} == "cpio" ]; then | |
195 | + cpio_file=$1 | |
196 | + [ ! -z ${dep_list} ] && echo "$1" | |
197 | + return 0 | |
198 | + fi | |
199 | + if [ -z ${dep_list} ]; then | |
200 | + print_mtime "$1" >> ${output} | |
201 | + cat "$1" >> ${output} | |
147 | 202 | else |
148 | - # Failsafe in case directory is empty | |
149 | - default_initramfs | |
203 | + grep ^file "$1" | cut -d ' ' -f 3 | |
150 | 204 | fi |
205 | + elif [ -d "$1" ]; then | |
206 | + dir_filelist "$1" | |
151 | 207 | else |
152 | - echo " $0: Cannot open '$cpio_source'" >&2 | |
208 | + echo " ${prog}: Cannot open '$1'" >&2 | |
153 | 209 | exit 1 |
154 | 210 | fi |
155 | 211 | } |
156 | 212 | |
157 | - | |
213 | +prog=$0 | |
158 | 214 | root_uid=0 |
159 | 215 | root_gid=0 |
216 | +dep_list= | |
217 | +cpio_file= | |
218 | +cpio_list= | |
219 | +output="/dev/stdout" | |
220 | +output_file="" | |
160 | 221 | |
222 | +arg="$1" | |
223 | +case "$arg" in | |
224 | + "-l") # files included in initramfs - used by kbuild | |
225 | + dep_list="list_" | |
226 | + shift | |
227 | + ;; | |
228 | + "-o") # generate gzipped cpio image named $1 | |
229 | + shift | |
230 | + output_file="$1" | |
231 | + cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)" | |
232 | + output=${cpio_list} | |
233 | + shift | |
234 | + ;; | |
235 | +esac | |
161 | 236 | while [ $# -gt 0 ]; do |
162 | 237 | arg="$1" |
163 | 238 | shift |
164 | 239 | case "$arg" in |
165 | - "-u") | |
240 | + "-u") # map $1 to uid=0 (root) | |
166 | 241 | root_uid="$1" |
167 | 242 | shift |
168 | 243 | ;; |
169 | - "-g") | |
244 | + "-g") # map $1 to gid=0 (root) | |
170 | 245 | root_gid="$1" |
171 | 246 | shift |
172 | 247 | ;; |
173 | - "-d") | |
248 | + "-d") # display default initramfs list | |
174 | 249 | default_list="$arg" |
175 | - default_initramfs | |
250 | + ${dep_list}default_initramfs | |
176 | 251 | ;; |
177 | 252 | "-h") |
178 | 253 | usage |
179 | 254 | |
180 | 255 | |
... | ... | @@ -181,24 +256,28 @@ |
181 | 256 | *) |
182 | 257 | case "$arg" in |
183 | 258 | "-"*) |
184 | - printf "ERROR: unknown option \"$arg\"\n" >&2 | |
185 | - printf "If the filename validly begins with '-', then it must be prefixed\n" >&2 | |
186 | - printf "by './' so that it won't be interpreted as an option." >&2 | |
187 | - printf "\n" >&2 | |
188 | - usage >&2 | |
189 | - exit 1 | |
259 | + unknown_option | |
190 | 260 | ;; |
191 | - *) | |
192 | - cpio_source="$arg" | |
193 | - build_list | |
261 | + *) # input file/dir - process it | |
262 | + input_file "$arg" "$#" | |
194 | 263 | ;; |
195 | 264 | esac |
196 | 265 | ;; |
197 | 266 | esac |
198 | 267 | done |
199 | 268 | |
200 | -# spit out the default cpio list if a source hasn't been specified | |
201 | -[ -z "$cpio_source" -a -z "$default_list" ] && default_initramfs | |
202 | - | |
269 | +# If output_file is set we will generate cpio archive and gzip it | |
270 | +# we are carefull to delete tmp files | |
271 | +if [ ! -z ${output_file} ]; then | |
272 | + if [ -z ${cpio_file} ]; then | |
273 | + cpio_tfile="$(mktemp ${TMPDIR:-/tmp}/cpiofile.XXXXXX)" | |
274 | + usr/gen_init_cpio ${cpio_list} > ${cpio_tfile} | |
275 | + else | |
276 | + cpio_tfile=${cpio_file} | |
277 | + fi | |
278 | + rm ${cpio_list} | |
279 | + cat ${cpio_tfile} | gzip -f -9 - > ${output_file} | |
280 | + [ -z ${cpio_file} ] && rm ${cpio_tfile} | |
281 | +fi | |
203 | 282 | exit 0 |
usr/Makefile
1 | +# | |
2 | +# kbuild file for usr/ - including initramfs image | |
3 | +# | |
1 | 4 | |
5 | +klibcdirs:; | |
6 | + | |
7 | +# Generate builtin.o based on initramfs_data.o | |
2 | 8 | obj-y := initramfs_data.o |
3 | 9 | |
4 | -hostprogs-y := gen_init_cpio | |
5 | - | |
6 | -clean-files := initramfs_data.cpio.gz initramfs_list | |
7 | - | |
8 | 10 | # initramfs_data.o contains the initramfs_data.cpio.gz image. |
9 | 11 | # The image is included using .incbin, a dependency which is not |
10 | 12 | # tracked automatically. |
11 | 13 | $(obj)/initramfs_data.o: $(obj)/initramfs_data.cpio.gz FORCE |
12 | 14 | |
13 | -ifdef CONFIG_INITRAMFS_ROOT_UID | |
14 | -gen_initramfs_args += -u $(CONFIG_INITRAMFS_ROOT_UID) | |
15 | -endif | |
15 | +##### | |
16 | +# Generate the initramfs cpio archive | |
16 | 17 | |
17 | -ifdef CONFIG_INITRAMFS_ROOT_GID | |
18 | -gen_initramfs_args += -g $(CONFIG_INITRAMFS_ROOT_GID) | |
19 | -endif | |
18 | +hostprogs-y := gen_init_cpio | |
19 | +initramfs := $(CONFIG_SHELL) $(srctree)/scripts/gen_initramfs_list.sh | |
20 | +ramfs-input := $(if $(filter-out "",$(CONFIG_INITRAMFS_SOURCE)), \ | |
21 | + $(CONFIG_INITRAMFS_SOURCE),-d) | |
22 | +ramfs-args := \ | |
23 | + $(if $(CONFIG_INITRAMFS_ROOT_UID), -u $(CONFIG_INITRAMFS_ROOT_UID)) \ | |
24 | + $(if $(CONFIG_INITRAMFS_ROOT_GID), -g $(CONFIG_INITRAMFS_ROOT_GID)) \ | |
25 | + $(ramfs-input) | |
20 | 26 | |
21 | -# The $(shell echo $(CONFIG_INITRAMFS_SOURCE)) is to remove the | |
22 | -# gratuitous begin and end quotes from the Kconfig string type. | |
23 | -# Internal, escaped quotes in the Kconfig string will loose the | |
24 | -# escape and become active quotes. | |
25 | -quotefixed_initramfs_source := $(shell echo $(CONFIG_INITRAMFS_SOURCE)) | |
26 | - | |
27 | -filechk_initramfs_list = $(CONFIG_SHELL) \ | |
28 | - $(srctree)/scripts/gen_initramfs_list.sh $(gen_initramfs_args) $(quotefixed_initramfs_source) | |
29 | - | |
30 | -$(obj)/initramfs_list: $(obj)/Makefile FORCE | |
31 | - $(call filechk,initramfs_list) | |
32 | - | |
33 | -quiet_cmd_cpio = CPIO $@ | |
34 | - cmd_cpio = ./$< $(obj)/initramfs_list > $@ | |
35 | - | |
36 | - | |
37 | -# Check if the INITRAMFS_SOURCE is a cpio archive | |
38 | -ifneq (,$(findstring .cpio,$(quotefixed_initramfs_source))) | |
39 | - | |
40 | -# INITRAMFS_SOURCE has a cpio archive - verify that it's a single file | |
41 | -ifneq (1,$(words $(quotefixed_initramfs_source))) | |
42 | -$(error Only a single file may be specified in CONFIG_INITRAMFS_SOURCE (="$(quotefixed_initramfs_source)") when a cpio archive is directly specified.) | |
27 | +# .initramfs_data.cpio.gz.d is used to identify all files included | |
28 | +# in initramfs and to detect if any files are added/removed. | |
29 | +# Removed files are identified by directory timestamp being updated | |
30 | +# The dependency list is generated by gen_initramfs.sh -l | |
31 | +ifneq ($(wildcard $(obj)/.initramfs_data.cpio.gz.d),) | |
32 | + include $(obj)/.initramfs_data.cpio.gz.d | |
43 | 33 | endif |
44 | -# Now use the cpio archive directly | |
45 | -initramfs_data_cpio = $(quotefixed_initramfs_source) | |
46 | -targets += $(quotefixed_initramfs_source) | |
47 | 34 | |
48 | -else | |
35 | +quiet_cmd_initfs = GEN $@ | |
36 | + cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input) | |
49 | 37 | |
50 | -# INITRAMFS_SOURCE is not a cpio archive - create one | |
51 | -$(obj)/initramfs_data.cpio: $(obj)/gen_init_cpio \ | |
52 | - $(initramfs-y) $(obj)/initramfs_list FORCE | |
53 | - $(call if_changed,cpio) | |
54 | - | |
55 | -targets += initramfs_data.cpio | |
56 | -initramfs_data_cpio = $(obj)/initramfs_data.cpio | |
57 | - | |
58 | -endif | |
59 | - | |
60 | - | |
61 | -$(obj)/initramfs_data.cpio.gz: $(initramfs_data_cpio) FORCE | |
62 | - $(call if_changed,gzip) | |
63 | - | |
64 | -targets += initramfs_data.cpio.gz | |
38 | +targets := initramfs_data.cpio.gz | |
39 | +$(deps_initramfs): klibcdirs | |
40 | +# We rebuild initramfs_data.cpio.gz if: | |
41 | +# 1) Any included file is newer then initramfs_data.cpio.gz | |
42 | +# 2) There are changes in which files are included (added or deleted) | |
43 | +# 3) If gen_init_cpio are newer than initramfs_data.cpio.gz | |
44 | +# 4) arguments to gen_initramfs.sh changes | |
45 | +$(obj)/initramfs_data.cpio.gz: $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs | |
46 | + $(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.gz.d | |
47 | + $(call if_changed,initfs) |