gen_initramfs_list.sh 8.04 KB
Newer Older
1
#!/bin/sh
Linus Torvalds's avatar
Linus Torvalds committed
2
# Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
3
# Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
Linus Torvalds's avatar
Linus Torvalds committed
4
#
5
# Released under the terms of the GNU GPL
Linus Torvalds's avatar
Linus Torvalds committed
6
#
7
# Generate a cpio packed initramfs. It uses gen_init_cpio to generate
8
# the cpio archive, and then compresses it.
9 10 11 12 13 14 15 16 17 18
# The script may also be used to generate the inputfile used for gen_init_cpio
# This script assumes that gen_init_cpio is located in usr/ directory

# error out on errors
set -e

usage() {
cat << EOF
Usage:
$0 [-o <file>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
19 20
	-o <file>      Create compressed initramfs file named <file> using
		       gen_init_cpio and compressor depending on the extension
21
	-u <uid>       User ID to map to user ID 0 (root).
22 23
		       <uid> is only meaningful if <cpio_source> is a
		       directory.  "squash" forces all files to uid 0.
24
	-g <gid>       Group ID to map to group ID 0 (root).
25 26
		       <gid> is only meaningful if <cpio_source> is a
		       directory.  "squash" forces all files to gid 0.
27
	<cpio_source>  File list or directory for cpio archive.
28
		       If <cpio_source> is a .cpio file it will be used
29 30 31 32 33 34 35 36 37 38
		       as direct input to initramfs.
	-d             Output the default cpio list.

All options except -o and -l may be repeated and are interpreted
sequentially and immediately.  -u and -g states are preserved across
<cpio_source> options so an explicit "-u 0 -g 0" is required
to reset the root/group mapping.
EOF
}

39 40 41 42 43 44
# awk style field access
# $1 - field number; rest is argument string
field() {
	shift $1 ; echo $1
}

45 46 47 48
list_default_initramfs() {
	# echo usr/kinit/kinit
	:
}
Linus Torvalds's avatar
Linus Torvalds committed
49 50

default_initramfs() {
51
	cat <<-EOF >> ${output}
Linus Torvalds's avatar
Linus Torvalds committed
52 53 54 55 56
		# This is a very simple, default initramfs

		dir /dev 0755 0 0
		nod /dev/console 0600 0 0 c 5 1
		dir /root 0700 0 0
57 58
		# file /kinit usr/kinit/kinit 0755 0 0
		# slink /init kinit 0755 0 0
Linus Torvalds's avatar
Linus Torvalds committed
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
	EOF
}

filetype() {
	local argv1="$1"

	# symlink test must come before file test
	if [ -L "${argv1}" ]; then
		echo "slink"
	elif [ -f "${argv1}" ]; then
		echo "file"
	elif [ -d "${argv1}" ]; then
		echo "dir"
	elif [ -b "${argv1}" -o -c "${argv1}" ]; then
		echo "nod"
	elif [ -p "${argv1}" ]; then
		echo "pipe"
	elif [ -S "${argv1}" ]; then
		echo "sock"
	else
		echo "invalid"
	fi
	return 0
}

84 85 86 87
list_print_mtime() {
	:
}

Linus Torvalds's avatar
Linus Torvalds committed
88 89 90
print_mtime() {
	local my_mtime="0"

91 92
	if [ -e "$1" ]; then
		my_mtime=$(find "$1" -printf "%T@\n" | sort -r | head -n 1)
Linus Torvalds's avatar
Linus Torvalds committed
93
	fi
94 95 96 97 98 99

	echo "# Last modified: ${my_mtime}" >> ${output}
	echo "" >> ${output}
}

list_parse() {
100 101 102 103
	if [ -L "$1" ]; then
		return
	fi
	echo "$1" | sed 's/:/\\:/g; s/$/ \\/'
Linus Torvalds's avatar
Linus Torvalds committed
104 105
}

106 107 108
# for each file print a line in following format
# <filetype> <name> <path to file> <octal mode> <uid> <gid>
# for links, devices etc the format differs. See gen_init_cpio for details
Linus Torvalds's avatar
Linus Torvalds committed
109 110
parse() {
	local location="$1"
111
	local name="/${location#${srcdir}}"
Linus Torvalds's avatar
Linus Torvalds committed
112
	# change '//' into '/'
113
	name=$(echo "$name" | sed -e 's://*:/:g')
Linus Torvalds's avatar
Linus Torvalds committed
114 115 116 117 118
	local mode="$2"
	local uid="$3"
	local gid="$4"
	local ftype=$(filetype "${location}")
	# remap uid/gid to 0 if necessary
119 120
	[ "$root_uid" = "squash" ] && uid=0 || [ "$uid" -eq "$root_uid" ] && uid=0
	[ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
Linus Torvalds's avatar
Linus Torvalds committed
121 122
	local str="${mode} ${uid} ${gid}"

123 124
	[ "${ftype}" = "invalid" ] && return 0
	[ "${location}" = "${srcdir}" ] && return 0
Linus Torvalds's avatar
Linus Torvalds committed
125 126 127 128 129 130

	case "${ftype}" in
		"file")
			str="${ftype} ${name} ${location} ${str}"
			;;
		"nod")
131 132 133 134 135 136 137 138
			local dev=`LC_ALL=C ls -l "${location}"`
			local maj=`field 5 ${dev}`
			local min=`field 6 ${dev}`
			maj=${maj%,}

			[ -b "${location}" ] && dev="b" || dev="c"

			str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
Linus Torvalds's avatar
Linus Torvalds committed
139 140
			;;
		"slink")
141
			local target=`readlink "${location}"`
Linus Torvalds's avatar
Linus Torvalds committed
142 143 144 145 146 147 148
			str="${ftype} ${name} ${target} ${str}"
			;;
		*)
			str="${ftype} ${name} ${str}"
			;;
	esac

149
	echo "${str}" >> ${output}
Linus Torvalds's avatar
Linus Torvalds committed
150 151 152 153

	return 0
}

154 155 156 157 158 159 160 161 162 163 164
unknown_option() {
	printf "ERROR: unknown option \"$arg\"\n" >&2
	printf "If the filename validly begins with '-', " >&2
	printf "then it must be prefixed\n" >&2
	printf "by './' so that it won't be interpreted as an option." >&2
	printf "\n" >&2
	usage >&2
	exit 1
}

list_header() {
165
	:
166 167 168 169 170 171 172 173 174 175 176
}

header() {
	printf "\n#####################\n# $1\n" >> ${output}
}

# process one directory (incl sub-directories)
dir_filelist() {
	${dep_list}header "$1"

	srcdir=$(echo "$1" | sed -e 's://*:/:g')
177
	dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" | LANG=C sort)
178 179 180 181 182 183 184 185 186 187

	# If $dirlist is only one line, then the directory is empty
	if [  "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
		${dep_list}print_mtime "$1"

		echo "${dirlist}" | \
		while read x; do
			${dep_list}parse ${x}
		done
	fi
Linus Torvalds's avatar
Linus Torvalds committed
188 189
}

190 191 192 193 194 195 196
# if only one file is specified and it is .cpio file then use it direct as fs
# if a directory is specified then add all files in given direcotry to fs
# if a regular file is specified assume it is in gen_initramfs format
input_file() {
	source="$1"
	if [ -f "$1" ]; then
		${dep_list}header "$1"
197
		is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\{0,1\}/cpio/')"
198
		if [ $2 -eq 0 -a ${is_cpio} = "cpio" ]; then
199
			cpio_file=$1
200
			echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed"
201 202 203 204 205 206
			[ ! -z ${dep_list} ] && echo "$1"
			return 0
		fi
		if [ -z ${dep_list} ]; then
			print_mtime "$1" >> ${output}
			cat "$1"         >> ${output}
Linus Torvalds's avatar
Linus Torvalds committed
207
		else
208
		        echo "$1 \\"
209
			cat "$1" | while read type dir file perm ; do
210
				if [ "$type" = "file" ]; then
211 212 213
					echo "$file \\";
				fi
			done
Linus Torvalds's avatar
Linus Torvalds committed
214
		fi
215 216
	elif [ -d "$1" ]; then
		dir_filelist "$1"
Linus Torvalds's avatar
Linus Torvalds committed
217
	else
218
		echo "  ${prog}: Cannot open '$1'" >&2
Linus Torvalds's avatar
Linus Torvalds committed
219 220 221 222
		exit 1
	fi
}

223
prog=$0
Linus Torvalds's avatar
Linus Torvalds committed
224 225
root_uid=0
root_gid=0
226 227 228 229 230
dep_list=
cpio_file=
cpio_list=
output="/dev/stdout"
output_file=""
231
is_cpio_compressed=
Michal Marek's avatar
Michal Marek committed
232
compr="gzip -n -9 -f"
Linus Torvalds's avatar
Linus Torvalds committed
233

234 235 236 237
arg="$1"
case "$arg" in
	"-l")	# files included in initramfs - used by kbuild
		dep_list="list_"
238
		echo "deps_initramfs := $0 \\"
239 240
		shift
		;;
241
	"-o")	# generate compressed cpio image named $1
242 243 244 245
		shift
		output_file="$1"
		cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)"
		output=${cpio_list}
246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262
		echo "$output_file" | grep -q "\.gz$" \
                && [ -x "`which gzip 2> /dev/null`" ] \
                && compr="gzip -n -9 -f"
		echo "$output_file" | grep -q "\.bz2$" \
                && [ -x "`which bzip2 2> /dev/null`" ] \
                && compr="bzip2 -9 -f"
		echo "$output_file" | grep -q "\.lzma$" \
                && [ -x "`which lzma 2> /dev/null`" ] \
                && compr="lzma -9 -f"
		echo "$output_file" | grep -q "\.xz$" \
                && [ -x "`which xz 2> /dev/null`" ] \
                && compr="xz --check=crc32 --lzma2=dict=1MiB"
		echo "$output_file" | grep -q "\.lzo$" \
                && [ -x "`which lzop 2> /dev/null`" ] \
                && compr="lzop -9 -f"
		echo "$output_file" | grep -q "\.lz4$" \
                && [ -x "`which lz4 2> /dev/null`" ] \
263
                && compr="lz4 -l -9 -f"
264
		echo "$output_file" | grep -q "\.cpio$" && compr="cat"
265 266 267
		shift
		;;
esac
Linus Torvalds's avatar
Linus Torvalds committed
268 269 270 271
while [ $# -gt 0 ]; do
	arg="$1"
	shift
	case "$arg" in
272
		"-u")	# map $1 to uid=0 (root)
Linus Torvalds's avatar
Linus Torvalds committed
273
			root_uid="$1"
274
			[ "$root_uid" = "-1" ] && root_uid=$(id -u || echo 0)
Linus Torvalds's avatar
Linus Torvalds committed
275 276
			shift
			;;
277
		"-g")	# map $1 to gid=0 (root)
Linus Torvalds's avatar
Linus Torvalds committed
278
			root_gid="$1"
279
			[ "$root_gid" = "-1" ] && root_gid=$(id -g || echo 0)
Linus Torvalds's avatar
Linus Torvalds committed
280 281
			shift
			;;
282
		"-d")	# display default initramfs list
Linus Torvalds's avatar
Linus Torvalds committed
283
			default_list="$arg"
284
			${dep_list}default_initramfs
Linus Torvalds's avatar
Linus Torvalds committed
285 286 287 288 289 290 291 292
			;;
		"-h")
			usage
			exit 0
			;;
		*)
			case "$arg" in
				"-"*)
293
					unknown_option
Linus Torvalds's avatar
Linus Torvalds committed
294
					;;
295 296
				*)	# input file/dir - process it
					input_file "$arg" "$#"
Linus Torvalds's avatar
Linus Torvalds committed
297 298 299 300 301 302
					;;
			esac
			;;
	esac
done

303
# If output_file is set we will generate cpio archive and compress it
304
# we are careful to delete tmp files
305 306
if [ ! -z ${output_file} ]; then
	if [ -z ${cpio_file} ]; then
307 308 309 310 311 312 313
		timestamp=
		if test -n "$KBUILD_BUILD_TIMESTAMP"; then
			timestamp="$(date -d"$KBUILD_BUILD_TIMESTAMP" +%s || :)"
			if test -n "$timestamp"; then
				timestamp="-t $timestamp"
			fi
		fi
314
		cpio_tfile="$(mktemp ${TMPDIR:-/tmp}/cpiofile.XXXXXX)"
315
		usr/gen_init_cpio $timestamp ${cpio_list} > ${cpio_tfile}
316 317 318 319
	else
		cpio_tfile=${cpio_file}
	fi
	rm ${cpio_list}
320 321 322
	if [ "${is_cpio_compressed}" = "compressed" ]; then
		cat ${cpio_tfile} > ${output_file}
	else
323 324
		(cat ${cpio_tfile} | ${compr}  - > ${output_file}) \
		|| (rm -f ${output_file} ; false)
325
	fi
326 327
	[ -z ${cpio_file} ] && rm ${cpio_tfile}
fi
Linus Torvalds's avatar
Linus Torvalds committed
328
exit 0