]> rtime.felk.cvut.cz Git - novaboot.git/blob - contrib/gen_cpio
gen_cpio fixes
[novaboot.git] / contrib / gen_cpio
1 #!/bin/sh
2 #
3 # Copyright (C) Michal Sojka <sojkam1@fel.cvut.cz>
4 #
5 # Includes pieces from gen_initramfs_list.sh:
6 #
7 # Copyright (C) Martin Schlemmer <azarah@nosferatu.za.org>
8 # Copyright (C) 2006 Sam Ravnborg <sam@ravnborg.org>
9 #
10 # Released under the terms of the GNU GPL
11
12 # Usage: gen_cpio rootfs.cpio "myapp->/bin/" "start.sh->/etc/init.d/S90startmyapp"
13 #        gen_cpio --mkimage="-T ramdisk -A powerpc -O linux" ...
14
15 set -e
16
17 root_uid=$(id -u)
18 root_gid=$(id -g)
19
20 usage() {
21 cat >&2 << EOF
22 Usage:
23 $0 [--mkimage="<mkimage params>"] [-u <uid>] [-g <gid>] {<cpio_source>}...
24         --mkimage=...  Pack the resulting image with U-Boot's "mkimage ..."
25         -u <uid>       User ID to map to user ID 0 (root).
26                        <uid> is only meaningful if <cpio_source> is a
27                        directory.  "squash" forces all files to uid 0.
28                        Default: $root_uid (you)
29         -g <gid>       Group ID to map to group ID 0 (root).
30                        <gid> is only meaningful if <cpio_source> is a
31                        directory.  "squash" forces all files to gid 0.
32                        Default: $root_gid (you)
33         <cpio_source>  One of:
34                        - *.cpio: Included directly into the output
35                        - directory: Content of the directory is included
36                          in the output
37                        - src/file->/dst/file: src/file appear in the output
38                          as dst/file
39                        - src/file->/dst/dir/: src/file appear in the output
40                          as dsr/dir/file
41
42 All options except --mkimage may be repeated and are interpreted
43 sequentially and immediately. -u and -g states are preserved across
44 <cpio_source> options so an explicit "-u 0 -g 0" is required to reset
45 the root/group mapping.
46 EOF
47 }
48
49
50 while [ $# -gt 0 ]; do
51     case "$1" in
52         --mkimage=*)
53             mkimage=${1#--mkimage=}
54             ;;
55         "-h"|"--help")
56             usage
57             exit 0
58             ;;
59         *) break;;
60     esac
61     shift
62 done
63
64 if [ -n "$mkimage" ]; then
65     tmp=$(mktemp)
66     exec 3<&1 1>$tmp
67 fi
68
69 gen_cpio_from_list() {
70     [ "$cpio_list" ] || return 0
71     echo "$cpio_list" | LANG=C sort -u | gen_init_cpio -
72     cpio_list=
73 }
74
75 # awk style field access
76 # $1 - field number; rest is argument string
77 field() {
78         shift $1 ; echo $1
79 }
80
81 filetype() {
82     local argv1="$1"
83
84     # symlink test must come before file test
85     if [ -L "${argv1}" ]; then
86         echo "slink"
87     elif [ -f "${argv1}" ]; then
88         echo "file"
89     elif [ -d "${argv1}" ]; then
90         echo "dir"
91     elif [ -b "${argv1}" -o -c "${argv1}" ]; then
92         echo "nod"
93     elif [ -p "${argv1}" ]; then
94         echo "pipe"
95     elif [ -S "${argv1}" ]; then
96         echo "sock"
97     else
98         echo "invalid"
99     fi
100     return 0
101 }
102
103 # for each file print a line in following format
104 # <filetype> <name> <path to file> <octal mode> <uid> <gid>
105 # for links, devices etc the format differs. See gen_init_cpio for details
106 parse() {
107         local location="$1"
108         local name="/${location#${srcdir}}"
109         # change '//' into '/'
110         name=$(echo "$name" | sed -e 's://*:/:g')
111         local mode="$2"
112         local uid="$3"
113         local gid="$4"
114         local ftype=$(filetype "${location}")
115         # remap uid/gid to 0 if necessary
116         [ "$root_uid" = "squash" ] && uid=0 || [ "$uid" -eq "$root_uid" ] && uid=0
117         [ "$root_gid" = "squash" ] && gid=0 || [ "$gid" -eq "$root_gid" ] && gid=0
118         local str="${mode} ${uid} ${gid}"
119
120         [ "${ftype}" = "invalid" ] && return 0
121         [ "${location}" = "${srcdir}" ] && return 0
122
123         case "${ftype}" in
124                 "file")
125                         str="${ftype} ${name} ${location} ${str}"
126                         ;;
127                 "nod")
128                         local dev=`LC_ALL=C ls -l "${location}"`
129                         local maj=`field 5 ${dev}`
130                         local min=`field 6 ${dev}`
131                         maj=${maj%,}
132
133                         [ -b "${location}" ] && dev="b" || dev="c"
134
135                         str="${ftype} ${name} ${str} ${dev} ${maj} ${min}"
136                         ;;
137                 "slink")
138                         local target=`readlink "${location}"`
139                         str="${ftype} ${name} ${target} ${str}"
140                         ;;
141                 *)
142                         str="${ftype} ${name} ${str}"
143                         ;;
144         esac
145
146         echo "${str}"
147
148         return 0
149 }
150
151 # process one directory (incl sub-directories)
152 gen_dirlist() {
153     srcdir=$(echo "$1" | sed -e 's://*:/:g')
154     dirlist=$(find "${srcdir}" -printf "%p %m %U %G\n")
155
156     # If $dirlist is only one line, then the directory is empty
157     if [  "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
158         echo "${dirlist}" | \
159             while read x; do
160             parse ${x}
161         done
162     fi
163 }
164
165
166 ends_with() { [ x"${1}" != x"${1%$2}" ]; }
167
168 gen_filelist() {
169     local src=$1
170     local dst=$2
171
172     if ends_with "$dst" "/"; then
173         dst="$dst$(basename $src)"
174     fi
175     local dir=$(dirname $dst)
176     while [ -n "$dir" -a "$dir" != "." -a "$dir" != "/" ]; do
177         echo "dir $dir 0755 0 0"
178         dir=$(dirname $dir)
179     done
180     echo "file $dst $src $(find $src -printf '%m') 0 0"
181 }
182
183 while [ $# -gt 0 ]; do
184     arg="$1"
185     shift
186     case "$arg" in
187         "-u")   # map $1 to uid=0 (root)
188             root_uid="$1"
189             shift
190             ;;
191         "-g")   # map $1 to gid=0 (root)
192             root_gid="$1"
193             shift
194             ;;
195         *"->"*)
196             src=${arg%%->*}
197             dst=${arg#*->}
198             cpio_list=$(echo "$cpio_list"; gen_filelist $src $dst)
199             ;;
200         *)
201             if [ -d "$arg" ]; then
202                 cpio_list="$cpio_list$(gen_dirlist $arg)"
203             elif [ -f "$arg" ]; then
204                 case "$(file -L $arg)" in
205                     *"cpio archive"*)
206                         gen_cpio_from_list
207                         cat $arg
208                         ;;
209                     *)
210                         echo >&2 "Unsuported file format: $arg"
211                         usage
212                         exit 1
213                         ;;
214                 esac
215             else
216                 echo >&2 "No file: $arg"
217                 exit 1
218             fi
219     esac
220 done
221
222 gen_cpio_from_list
223
224 if [ -n "$mkimage" ]; then
225     exec 1<&3
226     tmp2=$(mktemp)
227     mkimage $mkimage -d $tmp $tmp2 >&2
228     cat $tmp2
229     rm $tmp $tmp2
230 fi