gen_initramfs.sh 5.8 KB

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