18c2ecf20Sopenharmony_ci#!/bin/sh
28c2ecf20Sopenharmony_ci# Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
38c2ecf20Sopenharmony_ci# Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
48c2ecf20Sopenharmony_ci#
58c2ecf20Sopenharmony_ci# Released under the terms of the GNU GPL
68c2ecf20Sopenharmony_ci#
78c2ecf20Sopenharmony_ci# Generate a cpio packed initramfs. It uses gen_init_cpio to generate
88c2ecf20Sopenharmony_ci# the cpio archive.
98c2ecf20Sopenharmony_ci# This script assumes that gen_init_cpio is located in usr/ directory
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci# error out on errors
128c2ecf20Sopenharmony_ciset -e
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ciusage() {
158c2ecf20Sopenharmony_cicat << EOF
168c2ecf20Sopenharmony_ciUsage:
178c2ecf20Sopenharmony_ci$0 [-o <file>] [-l <dep_list>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
188c2ecf20Sopenharmony_ci	-o <file>      Create initramfs file named <file> by using gen_init_cpio
198c2ecf20Sopenharmony_ci	-l <dep_list>  Create dependency list named <dep_list>
208c2ecf20Sopenharmony_ci	-u <uid>       User ID to map to user ID 0 (root).
218c2ecf20Sopenharmony_ci		       <uid> is only meaningful if <cpio_source> is a
228c2ecf20Sopenharmony_ci		       directory.  "squash" forces all files to uid 0.
238c2ecf20Sopenharmony_ci	-g <gid>       Group ID to map to group ID 0 (root).
248c2ecf20Sopenharmony_ci		       <gid> is only meaningful if <cpio_source> is a
258c2ecf20Sopenharmony_ci		       directory.  "squash" forces all files to gid 0.
268c2ecf20Sopenharmony_ci	<cpio_source>  File list or directory for cpio archive.
278c2ecf20Sopenharmony_ci		       If <cpio_source> is a .cpio file it will be used
288c2ecf20Sopenharmony_ci		       as direct input to initramfs.
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ciAll options except -o and -l may be repeated and are interpreted
318c2ecf20Sopenharmony_cisequentially and immediately.  -u and -g states are preserved across
328c2ecf20Sopenharmony_ci<cpio_source> options so an explicit "-u 0 -g 0" is required
338c2ecf20Sopenharmony_cito reset the root/group mapping.
348c2ecf20Sopenharmony_ciEOF
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci# awk style field access
388c2ecf20Sopenharmony_ci# $1 - field number; rest is argument string
398c2ecf20Sopenharmony_cifield() {
408c2ecf20Sopenharmony_ci	shift $1 ; echo $1
418c2ecf20Sopenharmony_ci}
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cifiletype() {
448c2ecf20Sopenharmony_ci	local argv1="$1"
458c2ecf20Sopenharmony_ci
468c2ecf20Sopenharmony_ci	# symlink test must come before file test
478c2ecf20Sopenharmony_ci	if [ -L "${argv1}" ]; then
488c2ecf20Sopenharmony_ci		echo "slink"
498c2ecf20Sopenharmony_ci	elif [ -f "${argv1}" ]; then
508c2ecf20Sopenharmony_ci		echo "file"
518c2ecf20Sopenharmony_ci	elif [ -d "${argv1}" ]; then
528c2ecf20Sopenharmony_ci		echo "dir"
538c2ecf20Sopenharmony_ci	elif [ -b "${argv1}" -o -c "${argv1}" ]; then
548c2ecf20Sopenharmony_ci		echo "nod"
558c2ecf20Sopenharmony_ci	elif [ -p "${argv1}" ]; then
568c2ecf20Sopenharmony_ci		echo "pipe"
578c2ecf20Sopenharmony_ci	elif [ -S "${argv1}" ]; then
588c2ecf20Sopenharmony_ci		echo "sock"
598c2ecf20Sopenharmony_ci	else
608c2ecf20Sopenharmony_ci		echo "invalid"
618c2ecf20Sopenharmony_ci	fi
628c2ecf20Sopenharmony_ci	return 0
638c2ecf20Sopenharmony_ci}
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ciprint_mtime() {
668c2ecf20Sopenharmony_ci	local my_mtime="0"
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	if [ -e "$1" ]; then
698c2ecf20Sopenharmony_ci		my_mtime=$(find "$1" -printf "%T@\n" | sort -r | head -n 1)
708c2ecf20Sopenharmony_ci	fi
718c2ecf20Sopenharmony_ci
728c2ecf20Sopenharmony_ci	echo "# Last modified: ${my_mtime}" >> $cpio_list
738c2ecf20Sopenharmony_ci	echo "" >> $cpio_list
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cilist_parse() {
778c2ecf20Sopenharmony_ci	if [ -z "$dep_list" -o -L "$1" ]; then
788c2ecf20Sopenharmony_ci		return
798c2ecf20Sopenharmony_ci	fi
808c2ecf20Sopenharmony_ci	echo "$1" | sed 's/:/\\:/g; s/$/ \\/' >> $dep_list
818c2ecf20Sopenharmony_ci}
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci# for each file print a line in following format
848c2ecf20Sopenharmony_ci# <filetype> <name> <path to file> <octal mode> <uid> <gid>
858c2ecf20Sopenharmony_ci# for links, devices etc the format differs. See gen_init_cpio for details
868c2ecf20Sopenharmony_ciparse() {
878c2ecf20Sopenharmony_ci	local location="$1"
888c2ecf20Sopenharmony_ci	local name="/${location#${srcdir}}"
898c2ecf20Sopenharmony_ci	# change '//' into '/'
908c2ecf20Sopenharmony_ci	name=$(echo "$name" | sed -e 's://*:/:g')
918c2ecf20Sopenharmony_ci	local mode="$2"
928c2ecf20Sopenharmony_ci	local uid="$3"
938c2ecf20Sopenharmony_ci	local gid="$4"
948c2ecf20Sopenharmony_ci	local ftype=$(filetype "${location}")
958c2ecf20Sopenharmony_ci	# remap uid/gid to 0 if necessary
968c2ecf20Sopenharmony_ci	[ "$root_uid" = "squash" ] && uid=0 || [ "$uid" -eq "$root_uid" ] && uid=0
978c2ecf20Sopenharmony_ci	[ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
988c2ecf20Sopenharmony_ci	local str="${mode} ${uid} ${gid}"
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci	[ "${ftype}" = "invalid" ] && return 0
1018c2ecf20Sopenharmony_ci	[ "${location}" = "${srcdir}" ] && return 0
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ci	case "${ftype}" in
1048c2ecf20Sopenharmony_ci		"file")
1058c2ecf20Sopenharmony_ci			str="${ftype} ${name} ${location} ${str}"
1068c2ecf20Sopenharmony_ci			;;
1078c2ecf20Sopenharmony_ci		"nod")
1088c2ecf20Sopenharmony_ci			local dev="`LC_ALL=C ls -l "${location}"`"
1098c2ecf20Sopenharmony_ci			local maj=`field 5 ${dev}`
1108c2ecf20Sopenharmony_ci			local min=`field 6 ${dev}`
1118c2ecf20Sopenharmony_ci			maj=${maj%,}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci			[ -b "${location}" ] && dev="b" || dev="c"
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci			str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
1168c2ecf20Sopenharmony_ci			;;
1178c2ecf20Sopenharmony_ci		"slink")
1188c2ecf20Sopenharmony_ci			local target=`readlink "${location}"`
1198c2ecf20Sopenharmony_ci			str="${ftype} ${name} ${target} ${str}"
1208c2ecf20Sopenharmony_ci			;;
1218c2ecf20Sopenharmony_ci		*)
1228c2ecf20Sopenharmony_ci			str="${ftype} ${name} ${str}"
1238c2ecf20Sopenharmony_ci			;;
1248c2ecf20Sopenharmony_ci	esac
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_ci	echo "${str}" >> $cpio_list
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	return 0
1298c2ecf20Sopenharmony_ci}
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ciunknown_option() {
1328c2ecf20Sopenharmony_ci	printf "ERROR: unknown option \"$arg\"\n" >&2
1338c2ecf20Sopenharmony_ci	printf "If the filename validly begins with '-', " >&2
1348c2ecf20Sopenharmony_ci	printf "then it must be prefixed\n" >&2
1358c2ecf20Sopenharmony_ci	printf "by './' so that it won't be interpreted as an option." >&2
1368c2ecf20Sopenharmony_ci	printf "\n" >&2
1378c2ecf20Sopenharmony_ci	usage >&2
1388c2ecf20Sopenharmony_ci	exit 1
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ciheader() {
1428c2ecf20Sopenharmony_ci	printf "\n#####################\n# $1\n" >> $cpio_list
1438c2ecf20Sopenharmony_ci}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci# process one directory (incl sub-directories)
1468c2ecf20Sopenharmony_cidir_filelist() {
1478c2ecf20Sopenharmony_ci	header "$1"
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	srcdir=$(echo "$1" | sed -e 's://*:/:g')
1508c2ecf20Sopenharmony_ci	dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" | LANG=C sort)
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	# If $dirlist is only one line, then the directory is empty
1538c2ecf20Sopenharmony_ci	if [  "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
1548c2ecf20Sopenharmony_ci		print_mtime "$1"
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci		echo "${dirlist}" | \
1578c2ecf20Sopenharmony_ci		while read x; do
1588c2ecf20Sopenharmony_ci			list_parse $x
1598c2ecf20Sopenharmony_ci			parse $x
1608c2ecf20Sopenharmony_ci		done
1618c2ecf20Sopenharmony_ci	fi
1628c2ecf20Sopenharmony_ci}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ciinput_file() {
1658c2ecf20Sopenharmony_ci	source="$1"
1668c2ecf20Sopenharmony_ci	if [ -f "$1" ]; then
1678c2ecf20Sopenharmony_ci		# If a regular file is specified, assume it is in
1688c2ecf20Sopenharmony_ci		# gen_init_cpio format
1698c2ecf20Sopenharmony_ci		header "$1"
1708c2ecf20Sopenharmony_ci		print_mtime "$1" >> $cpio_list
1718c2ecf20Sopenharmony_ci		cat "$1"         >> $cpio_list
1728c2ecf20Sopenharmony_ci		if [ -n "$dep_list" ]; then
1738c2ecf20Sopenharmony_ci		        echo "$1 \\"  >> $dep_list
1748c2ecf20Sopenharmony_ci			cat "$1" | while read type dir file perm ; do
1758c2ecf20Sopenharmony_ci				if [ "$type" = "file" ]; then
1768c2ecf20Sopenharmony_ci					echo "$file \\" >> $dep_list
1778c2ecf20Sopenharmony_ci				fi
1788c2ecf20Sopenharmony_ci			done
1798c2ecf20Sopenharmony_ci		fi
1808c2ecf20Sopenharmony_ci	elif [ -d "$1" ]; then
1818c2ecf20Sopenharmony_ci		# If a directory is specified then add all files in it to fs
1828c2ecf20Sopenharmony_ci		dir_filelist "$1"
1838c2ecf20Sopenharmony_ci	else
1848c2ecf20Sopenharmony_ci		echo "  ${prog}: Cannot open '$1'" >&2
1858c2ecf20Sopenharmony_ci		exit 1
1868c2ecf20Sopenharmony_ci	fi
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ciprog=$0
1908c2ecf20Sopenharmony_ciroot_uid=0
1918c2ecf20Sopenharmony_ciroot_gid=0
1928c2ecf20Sopenharmony_cidep_list=
1938c2ecf20Sopenharmony_cicpio_list=$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)
1948c2ecf20Sopenharmony_cioutput="/dev/stdout"
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_citrap "rm -f $cpio_list" EXIT
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ciwhile [ $# -gt 0 ]; do
1998c2ecf20Sopenharmony_ci	arg="$1"
2008c2ecf20Sopenharmony_ci	shift
2018c2ecf20Sopenharmony_ci	case "$arg" in
2028c2ecf20Sopenharmony_ci		"-l")	# files included in initramfs - used by kbuild
2038c2ecf20Sopenharmony_ci			dep_list="$1"
2048c2ecf20Sopenharmony_ci			echo "deps_initramfs := \\" > $dep_list
2058c2ecf20Sopenharmony_ci			shift
2068c2ecf20Sopenharmony_ci			;;
2078c2ecf20Sopenharmony_ci		"-o")	# generate cpio image named $1
2088c2ecf20Sopenharmony_ci			output="$1"
2098c2ecf20Sopenharmony_ci			shift
2108c2ecf20Sopenharmony_ci			;;
2118c2ecf20Sopenharmony_ci		"-u")	# map $1 to uid=0 (root)
2128c2ecf20Sopenharmony_ci			root_uid="$1"
2138c2ecf20Sopenharmony_ci			[ "$root_uid" = "-1" ] && root_uid=$(id -u || echo 0)
2148c2ecf20Sopenharmony_ci			shift
2158c2ecf20Sopenharmony_ci			;;
2168c2ecf20Sopenharmony_ci		"-g")	# map $1 to gid=0 (root)
2178c2ecf20Sopenharmony_ci			root_gid="$1"
2188c2ecf20Sopenharmony_ci			[ "$root_gid" = "-1" ] && root_gid=$(id -g || echo 0)
2198c2ecf20Sopenharmony_ci			shift
2208c2ecf20Sopenharmony_ci			;;
2218c2ecf20Sopenharmony_ci		"-h")
2228c2ecf20Sopenharmony_ci			usage
2238c2ecf20Sopenharmony_ci			exit 0
2248c2ecf20Sopenharmony_ci			;;
2258c2ecf20Sopenharmony_ci		*)
2268c2ecf20Sopenharmony_ci			case "$arg" in
2278c2ecf20Sopenharmony_ci				"-"*)
2288c2ecf20Sopenharmony_ci					unknown_option
2298c2ecf20Sopenharmony_ci					;;
2308c2ecf20Sopenharmony_ci				*)	# input file/dir - process it
2318c2ecf20Sopenharmony_ci					input_file "$arg"
2328c2ecf20Sopenharmony_ci					;;
2338c2ecf20Sopenharmony_ci			esac
2348c2ecf20Sopenharmony_ci			;;
2358c2ecf20Sopenharmony_ci	esac
2368c2ecf20Sopenharmony_cidone
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci# If output_file is set we will generate cpio archive
2398c2ecf20Sopenharmony_ci# we are careful to delete tmp files
2408c2ecf20Sopenharmony_citimestamp=
2418c2ecf20Sopenharmony_ciif test -n "$KBUILD_BUILD_TIMESTAMP"; then
2428c2ecf20Sopenharmony_ci	timestamp="$(date -d"$KBUILD_BUILD_TIMESTAMP" +%s || :)"
2438c2ecf20Sopenharmony_ci	if test -n "$timestamp"; then
2448c2ecf20Sopenharmony_ci		timestamp="-t $timestamp"
2458c2ecf20Sopenharmony_ci	fi
2468c2ecf20Sopenharmony_cifi
2478c2ecf20Sopenharmony_ciusr/gen_init_cpio $timestamp $cpio_list > $output
248