gen_initramfs.sh 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. #!/bin/sh
  2. # Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
  3. # Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
  4. #
  5. # Released under the terms of the GNU GPL
  6. #
  7. # Generate a cpio packed initramfs. It uses gen_init_cpio to generate
  8. # the cpio archive.
  9. # This script assumes that gen_init_cpio is located in usr/ directory
  10. # error out on errors
  11. set -e
  12. usage() {
  13. cat << EOF
  14. Usage:
  15. $0 [-o <file>] [-l <dep_list>] [-u <uid>] [-g <gid>] {-d | <cpio_source>} ...
  16. -o <file> Create initramfs file named <file> by using gen_init_cpio
  17. -l <dep_list> Create dependency list named <dep_list>
  18. -u <uid> User ID to map to user ID 0 (root).
  19. <uid> is only meaningful if <cpio_source> is a
  20. directory. "squash" forces all files to uid 0.
  21. -g <gid> Group ID to map to group ID 0 (root).
  22. <gid> is only meaningful if <cpio_source> is a
  23. directory. "squash" forces all files to gid 0.
  24. <cpio_source> File list or directory for cpio archive.
  25. If <cpio_source> is a .cpio file it will be used
  26. as direct input to initramfs.
  27. All options except -o and -l may be repeated and are interpreted
  28. sequentially and immediately. -u and -g states are preserved across
  29. <cpio_source> options so an explicit "-u 0 -g 0" is required
  30. to reset the root/group mapping.
  31. EOF
  32. }
  33. # awk style field access
  34. # $1 - field number; rest is argument string
  35. field() {
  36. shift $1 ; echo $1
  37. }
  38. filetype() {
  39. local argv1="$1"
  40. # symlink test must come before file test
  41. if [ -L "${argv1}" ]; then
  42. echo "slink"
  43. elif [ -f "${argv1}" ]; then
  44. echo "file"
  45. elif [ -d "${argv1}" ]; then
  46. echo "dir"
  47. elif [ -b "${argv1}" -o -c "${argv1}" ]; then
  48. echo "nod"
  49. elif [ -p "${argv1}" ]; then
  50. echo "pipe"
  51. elif [ -S "${argv1}" ]; then
  52. echo "sock"
  53. else
  54. echo "invalid"
  55. fi
  56. return 0
  57. }
  58. print_mtime() {
  59. local my_mtime="0"
  60. if [ -e "$1" ]; then
  61. my_mtime=$(find "$1" -printf "%T@\n" | sort -r | head -n 1)
  62. fi
  63. echo "# Last modified: ${my_mtime}" >> $cpio_list
  64. echo "" >> $cpio_list
  65. }
  66. list_parse() {
  67. if [ -z "$dep_list" -o -L "$1" ]; then
  68. return
  69. fi
  70. echo "$1" | sed 's/:/\\:/g; s/$/ \\/' >> $dep_list
  71. }
  72. # for each file print a line in following format
  73. # <filetype> <name> <path to file> <octal mode> <uid> <gid>
  74. # for links, devices etc the format differs. See gen_init_cpio for details
  75. parse() {
  76. local location="$1"
  77. local name="/${location#${srcdir}}"
  78. # change '//' into '/'
  79. name=$(echo "$name" | sed -e 's://*:/:g')
  80. local mode="$2"
  81. local uid="$3"
  82. local gid="$4"
  83. local ftype=$(filetype "${location}")
  84. # remap uid/gid to 0 if necessary
  85. [ "$root_uid" = "squash" ] && uid=0 || [ "$uid" -eq "$root_uid" ] && uid=0
  86. [ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
  87. local str="${mode} ${uid} ${gid}"
  88. [ "${ftype}" = "invalid" ] && return 0
  89. [ "${location}" = "${srcdir}" ] && return 0
  90. case "${ftype}" in
  91. "file")
  92. str="${ftype} ${name} ${location} ${str}"
  93. ;;
  94. "nod")
  95. local dev="`LC_ALL=C ls -l "${location}"`"
  96. local maj=`field 5 ${dev}`
  97. local min=`field 6 ${dev}`
  98. maj=${maj%,}
  99. [ -b "${location}" ] && dev="b" || dev="c"
  100. str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
  101. ;;
  102. "slink")
  103. local target=`readlink "${location}"`
  104. str="${ftype} ${name} ${target} ${str}"
  105. ;;
  106. *)
  107. str="${ftype} ${name} ${str}"
  108. ;;
  109. esac
  110. echo "${str}" >> $cpio_list
  111. return 0
  112. }
  113. unknown_option() {
  114. printf "ERROR: unknown option \"$arg\"\n" >&2
  115. printf "If the filename validly begins with '-', " >&2
  116. printf "then it must be prefixed\n" >&2
  117. printf "by './' so that it won't be interpreted as an option." >&2
  118. printf "\n" >&2
  119. usage >&2
  120. exit 1
  121. }
  122. header() {
  123. printf "\n#####################\n# $1\n" >> $cpio_list
  124. }
  125. # process one directory (incl sub-directories)
  126. dir_filelist() {
  127. header "$1"
  128. srcdir=$(echo "$1" | sed -e 's://*:/:g')
  129. dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n" | LANG=C sort)
  130. # If $dirlist is only one line, then the directory is empty
  131. if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
  132. print_mtime "$1"
  133. echo "${dirlist}" | \
  134. while read x; do
  135. list_parse $x
  136. parse $x
  137. done
  138. fi
  139. }
  140. input_file() {
  141. source="$1"
  142. if [ -f "$1" ]; then
  143. # If a regular file is specified, assume it is in
  144. # gen_init_cpio format
  145. header "$1"
  146. print_mtime "$1" >> $cpio_list
  147. cat "$1" >> $cpio_list
  148. if [ -n "$dep_list" ]; then
  149. echo "$1 \\" >> $dep_list
  150. cat "$1" | while read type dir file perm ; do
  151. if [ "$type" = "file" ]; then
  152. echo "$file \\" >> $dep_list
  153. fi
  154. done
  155. fi
  156. elif [ -d "$1" ]; then
  157. # If a directory is specified then add all files in it to fs
  158. dir_filelist "$1"
  159. else
  160. echo " ${prog}: Cannot open '$1'" >&2
  161. exit 1
  162. fi
  163. }
  164. prog=$0
  165. root_uid=0
  166. root_gid=0
  167. dep_list=
  168. cpio_list=$(mktemp ${TMPDIR:-/tmp}/cpiolist.XXXXXX)
  169. output="/dev/stdout"
  170. trap "rm -f $cpio_list" EXIT
  171. while [ $# -gt 0 ]; do
  172. arg="$1"
  173. shift
  174. case "$arg" in
  175. "-l") # files included in initramfs - used by kbuild
  176. dep_list="$1"
  177. echo "deps_initramfs := \\" > $dep_list
  178. shift
  179. ;;
  180. "-o") # generate cpio image named $1
  181. output="$1"
  182. shift
  183. ;;
  184. "-u") # map $1 to uid=0 (root)
  185. root_uid="$1"
  186. [ "$root_uid" = "-1" ] && root_uid=$(id -u || echo 0)
  187. shift
  188. ;;
  189. "-g") # map $1 to gid=0 (root)
  190. root_gid="$1"
  191. [ "$root_gid" = "-1" ] && root_gid=$(id -g || echo 0)
  192. shift
  193. ;;
  194. "-h")
  195. usage
  196. exit 0
  197. ;;
  198. *)
  199. case "$arg" in
  200. "-"*)
  201. unknown_option
  202. ;;
  203. *) # input file/dir - process it
  204. input_file "$arg"
  205. ;;
  206. esac
  207. ;;
  208. esac
  209. done
  210. # If output_file is set we will generate cpio archive
  211. # we are careful to delete tmp files
  212. timestamp=
  213. if test -n "$KBUILD_BUILD_TIMESTAMP"; then
  214. timestamp="$(date -d"$KBUILD_BUILD_TIMESTAMP" +%s || :)"
  215. if test -n "$timestamp"; then
  216. timestamp="-t $timestamp"
  217. fi
  218. fi
  219. usr/gen_init_cpio $timestamp $cpio_list > $output