gen_initramfs_list.sh 6.64 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2
#!/bin/bash
# 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 8 9 10 11 12 13 14 15 16 17 18 19
# Generate a cpio packed initramfs. It uses gen_init_cpio to generate
# the cpio archive, and gzip to pack it.
# 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>} ...
	-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 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 100

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

list_parse() {
	echo "$1 \\"
Linus Torvalds's avatar
Linus Torvalds committed
101 102
}

103 104 105
# 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
106 107 108 109 110 111 112 113 114 115
parse() {
	local location="$1"
	local name="${location/${srcdir}//}"
	# change '//' into '/'
	name="${name//\/\///}"
	local mode="$2"
	local uid="$3"
	local gid="$4"
	local ftype=$(filetype "${location}")
	# remap uid/gid to 0 if necessary
116 117
	[ "$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
118 119 120 121 122 123 124 125 126 127
	local str="${mode} ${uid} ${gid}"

	[ "${ftype}" == "invalid" ] && return 0
	[ "${location}" == "${srcdir}" ] && return 0

	case "${ftype}" in
		"file")
			str="${ftype} ${name} ${location} ${str}"
			;;
		"nod")
128 129 130 131 132 133 134 135
			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
136 137
			;;
		"slink")
138
			local target=`field 11 $(LC_ALL=C ls -l "${location}")`
Linus Torvalds's avatar
Linus Torvalds committed
139 140 141 142 143 144 145
			str="${ftype} ${name} ${target} ${str}"
			;;
		*)
			str="${ftype} ${name} ${str}"
			;;
	esac

146
	echo "${str}" >> ${output}
Linus Torvalds's avatar
Linus Torvalds committed
147 148 149 150

	return 0
}

151 152 153 154 155 156 157 158 159 160 161
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() {
162
	:
163 164 165 166 167 168 169 170 171 172 173
}

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')
174
	dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n")
175 176 177 178 179 180 181 182 183 184

	# 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
185 186
}

187 188 189 190 191 192 193
# 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"
194
		is_cpio="$(echo "$1" | sed 's/^.*\.cpio\(\..*\)\?/cpio/')"
195 196
		if [ $2 -eq 0 -a ${is_cpio} == "cpio" ]; then
			cpio_file=$1
197
			echo "$1" | grep -q '^.*\.cpio\..*' && is_cpio_compressed="compressed"
198 199 200 201 202 203
			[ ! -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
204
		else
205 206 207 208 209
			cat "$1" | while read type dir file perm ; do
				if [ "$type" == "file" ]; then
					echo "$file \\";
				fi
			done
Linus Torvalds's avatar
Linus Torvalds committed
210
		fi
211 212
	elif [ -d "$1" ]; then
		dir_filelist "$1"
Linus Torvalds's avatar
Linus Torvalds committed
213
	else
214
		echo "  ${prog}: Cannot open '$1'" >&2
Linus Torvalds's avatar
Linus Torvalds committed
215 216 217 218
		exit 1
	fi
}

219
prog=$0
Linus Torvalds's avatar
Linus Torvalds committed
220 221
root_uid=0
root_gid=0
222 223 224 225 226
dep_list=
cpio_file=
cpio_list=
output="/dev/stdout"
output_file=""
227
is_cpio_compressed=
Linus Torvalds's avatar
Linus Torvalds committed
228

229 230 231 232
arg="$1"
case "$arg" in
	"-l")	# files included in initramfs - used by kbuild
		dep_list="list_"
233
		echo "deps_initramfs := \\"
234 235 236 237 238 239 240 241 242 243
		shift
		;;
	"-o")	# generate gzipped cpio image named $1
		shift
		output_file="$1"
		cpio_list="$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)"
		output=${cpio_list}
		shift
		;;
esac
Linus Torvalds's avatar
Linus Torvalds committed
244 245 246 247
while [ $# -gt 0 ]; do
	arg="$1"
	shift
	case "$arg" in
248
		"-u")	# map $1 to uid=0 (root)
Linus Torvalds's avatar
Linus Torvalds committed
249 250 251
			root_uid="$1"
			shift
			;;
252
		"-g")	# map $1 to gid=0 (root)
Linus Torvalds's avatar
Linus Torvalds committed
253 254 255
			root_gid="$1"
			shift
			;;
256
		"-d")	# display default initramfs list
Linus Torvalds's avatar
Linus Torvalds committed
257
			default_list="$arg"
258
			${dep_list}default_initramfs
Linus Torvalds's avatar
Linus Torvalds committed
259 260 261 262 263 264 265 266
			;;
		"-h")
			usage
			exit 0
			;;
		*)
			case "$arg" in
				"-"*)
267
					unknown_option
Linus Torvalds's avatar
Linus Torvalds committed
268
					;;
269 270
				*)	# input file/dir - process it
					input_file "$arg" "$#"
Linus Torvalds's avatar
Linus Torvalds committed
271 272 273 274 275 276
					;;
			esac
			;;
	esac
done

277 278 279 280 281 282 283 284 285 286
# If output_file is set we will generate cpio archive and gzip it
# we are carefull to delete tmp files
if [ ! -z ${output_file} ]; then
	if [ -z ${cpio_file} ]; then
		cpio_tfile="$(mktemp ${TMPDIR:-/tmp}/cpiofile.XXXXXX)"
		usr/gen_init_cpio ${cpio_list} > ${cpio_tfile}
	else
		cpio_tfile=${cpio_file}
	fi
	rm ${cpio_list}
287 288 289 290 291
	if [ "${is_cpio_compressed}" = "compressed" ]; then
		cat ${cpio_tfile} > ${output_file}
	else
		cat ${cpio_tfile} | gzip -f -9 - > ${output_file}
	fi
292 293
	[ -z ${cpio_file} ] && rm ${cpio_tfile}
fi
Linus Torvalds's avatar
Linus Torvalds committed
294
exit 0