#!/bin/sh # Copyright (C) Martin Schlemmer # Copyright (C) 2006 Sam Ravnborg # # Released under the terms of the GNU GPL # # Generate a cpio packed initramfs. It uses gen_init_cpio to generate # the cpio archive, and then compresses 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 proc usage { cat << """ Usage: $0 [-o ] [-u ] [-g ] {-d | } ... -o Create compressed initramfs file named using gen_init_cpio and compressor depending on the extension -u User ID to map to user ID 0 (root). is only meaningful if is a directory. "squash" forces all files to uid 0. -g Group ID to map to group ID 0 (root). is only meaningful if is a directory. "squash" forces all files to gid 0. File list or directory for cpio archive. If is a .cpio file it will be used 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 options so an explicit "-u 0 -g 0" is required to reset the root/group mapping. """ } # awk style field access # $1 - field number; rest is argument string proc field { shift $1 ; echo $1 } proc list_default_initramfs { # echo usr/kinit/kinit : } proc default_initramfs { cat << """ >> ${output} # 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 # file /kinit usr/kinit/kinit 0755 0 0 # slink /init kinit 0755 0 0 """ >> $(output) # 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 # file /kinit usr/kinit/kinit 0755 0 0 # slink /init kinit 0755 0 0 EOF } proc filetype { var argv1 = $1 # symlink test must come before file test if test -L $(argv1) { echo "slink" } elif test -f $(argv1) { echo "file" } elif test -d $(argv1) { echo "dir" } elif test -b $(argv1) -o -c $(argv1) { echo "nod" } elif test -p $(argv1) { echo "pipe" } elif test -S $(argv1) { echo "sock" } else { echo "invalid" } return 0 } proc list_print_mtime { : } proc print_mtime { var my_mtime = '"0'" if test -e $1 { set my_mtime = $[find $1 -printf "%T@\n" | sort -r | head -n 1] } echo "# Last modified: $(my_mtime)" >> $(output) echo "" >> $(output) } proc list_parse { test ! -L $1 && echo "$1 \\" || : } # for each file print a line in following format # # for links, devices etc the format differs. See gen_init_cpio for details proc parse { var location = $1 var name = ""/$(location#${srcdir})"" # change '//' into '/' set name = $[echo $name | sed -e 's://*:/:g] var mode = $2 var uid = $3 var gid = $4 var ftype = $[filetype $(location)] # remap uid/gid to 0 if necessary test $root_uid = "squash" && set uid = '0' || test $uid -eq $root_uid && set uid = '0' test $root_gid = "squash" && set gid = '0' || test $gid -eq $root_gid && set gid = '0' var str = ""$(mode) $(uid) $(gid)"" test $(ftype) = "invalid" && return 0 test $(location) = $(srcdir) && return 0 match $(ftype) { with "file" set str = ""$(ftype) $(name) $(location) $(str)"" with "nod" var dev = $[env LC_ALL=C ls -l $(location)] var maj = $[field 5 $(dev)] var min = $[field 6 $(dev)] set maj = $(maj%,) test -b $(location) && set dev = '"b'" || set dev = '"c'" set str = ""$(ftype) $(name) $(str) $(dev) $(maj) $(min)"" with "slink" var target = $[readlink $(location)] set str = ""$(ftype) $(name) $(target) $(str)"" with * set str = ""$(ftype) $(name) $(str)"" } echo $(str) >> $(output) return 0 } proc 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 } proc list_header { : } proc header { printf "\n#####################\n# $1\n" >> $(output) } # process one directory (incl sub-directories) proc dir_filelist { $(dep_list)header $1 setglobal srcdir = $[echo $1 | sed -e 's://*:/:g] setglobal dirlist = $[find $(srcdir) -printf "%p %m %U %G\n] # If $dirlist is only one line, then the directory is empty if test $[echo $(dirlist) | wc -l] -gt 1 { $(dep_list)print_mtime $1 echo $(dirlist) | \ while read x { $(dep_list)parse $(x) } } } # 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 proc input_file { setglobal source = $1 if test -f $1 { $(dep_list)header $1 setglobal is_cpio = $[echo $1 | sed 's/^.*\.cpio\(\..*\)\?/cpio/] if test $2 -eq 0 -a $(is_cpio) = "cpio" { setglobal cpio_file = $1 echo $1 | grep -q '^.*\.cpio\..*' && setglobal is_cpio_compressed = '"compressed'" test ! -z $(dep_list) && echo $1 return 0 } if test -z $(dep_list) { print_mtime $1 >> $(output) cat $1 >> $(output) } else { echo "$1 \\" cat $1 | while read type dir file perm { if test $type = "file" { echo "$file \\"; } } } } elif test -d $1 { dir_filelist $1 } else { echo " $(prog): Cannot open '$1'" > !2 exit 1 } } setglobal prog = $0 setglobal root_uid = '0' setglobal root_gid = '0' setglobal dep_list = '' setglobal cpio_file = '' setglobal cpio_list = '' setglobal output = '"/dev/stdout'" setglobal output_file = ''"" setglobal is_cpio_compressed = '' setglobal compr = '"gzip -n -9 -f'" setglobal arg = $1 match $arg { with "-l" # files included in initramfs - used by kbuild setglobal dep_list = '"list_'" echo "deps_initramfs := $0 \\" shift with "-o" # generate compressed cpio image named $1 shift setglobal output_file = $1 setglobal cpio_list = $[mktemp $(TMPDIR:-/tmp)/cpiolist.XXXXXX] setglobal output = $(cpio_list) echo $output_file | grep -q "\.gz$" \ && test -x $[which gzip !2 > /dev/null] \ && setglobal compr = '"gzip -n -9 -f'" echo $output_file | grep -q "\.bz2$" \ && test -x $[which bzip2 !2 > /dev/null] \ && setglobal compr = '"bzip2 -9 -f'" echo $output_file | grep -q "\.lzma$" \ && test -x $[which lzma !2 > /dev/null] \ && setglobal compr = '"lzma -9 -f'" echo $output_file | grep -q "\.xz$" \ && test -x $[which xz !2 > /dev/null] \ && setglobal compr = '"xz --check=crc32 --lzma2=dict=1MiB'" echo $output_file | grep -q "\.lzo$" \ && test -x $[which lzop !2 > /dev/null] \ && setglobal compr = '"lzop -9 -f'" echo $output_file | grep -q "\.lz4$" \ && test -x $[which lz4 !2 > /dev/null] \ && setglobal compr = '"lz4 -l -9 -f'" echo $output_file | grep -q "\.cpio$" && setglobal compr = '"cat'" shift } while test $Argc -gt 0 { setglobal arg = $1 shift match $arg { with "-u" # map $1 to uid=0 (root) setglobal root_uid = $1 shift with "-g" # map $1 to gid=0 (root) setglobal root_gid = $1 shift with "-d" # display default initramfs list setglobal default_list = $arg $(dep_list)default_initramfs with "-h" usage exit 0 with * match $arg { with "-"* unknown_option with * # input file/dir - process it input_file $arg "$Argc" } } } # If output_file is set we will generate cpio archive and compress it # we are careful to delete tmp files if test ! -z $(output_file) { if test -z $(cpio_file) { setglobal timestamp = '' if test -n $KBUILD_BUILD_TIMESTAMP { setglobal timestamp = $[date -d"$KBUILD_BUILD_TIMESTAMP" +%s || :] if test -n $timestamp { setglobal timestamp = ""-t $timestamp"" } } setglobal cpio_tfile = $[mktemp $(TMPDIR:-/tmp)/cpiofile.XXXXXX] usr/gen_init_cpio $timestamp $(cpio_list) > $(cpio_tfile) } else { setglobal cpio_tfile = $(cpio_file) } rm $(cpio_list) if test $(is_cpio_compressed) = "compressed" { cat $(cpio_tfile) > $(output_file) } else { shell {cat $(cpio_tfile) | $(compr) - > $(output_file)} \ || shell {rm -f $(output_file) ; false} } test -z $(cpio_file) && rm $(cpio_tfile) } exit 0