5e2f62f00592927257006bcc0ab8fd021f4a2eb9
[packages/trusty/cirros-testvm.git] / cirros-testvm / src-cirros / buildroot-2015.05 / package / mke2img / mke2img
1 #!/usr/bin/env bash
2
3 # Buildroot wrapper to the collection of ext2/3/4 filesystem tools:
4 # - genext2fs, to generate ext2 filesystem images
5 # - tune2fs, to modify an ext2/3/4 filesystem (possibly in an image file)
6 # - e2fsck, to check and fix an ext2/3/4 filesystem (possibly in an image file)
7
8 set -e
9
10 main() {
11     local OPT OPTARG
12     local nb_blocks nb_inodes nb_res_blocks root_dir image gen rev label uuid
13     local -a genext2fs_opts
14     local -a tune2fs_opts
15     local tune2fs_O_opts
16
17     # Default values
18     gen=2
19     rev=1
20
21     while getopts :hb:i:r:d:o:G:R:l:u: OPT; do
22         case "${OPT}" in
23         h)  help; exit 0;;
24         b)  nb_blocks=${OPTARG};;
25         i)  nb_inodes=${OPTARG};;
26         r)  nb_res_blocks=${OPTARG};;
27         d)  root_dir="${OPTARG}";;
28         o)  image="${OPTARG}";;
29         G)  gen=${OPTARG};;
30         R)  rev=${OPTARG};;
31         l)  label="${OPTARG}";;
32         u)  uuid="${OPTARG}";;
33         :)  error "option '%s' expects a mandatory argument\n" "${OPTARG}";;
34         \?) error "unknown option '%s'\n" "${OPTARG}";;
35         esac
36     done
37
38     # Sanity checks
39     if [ -z "${root_dir}" ]; then
40         error "you must specify a root directory with '-d'\n"
41     fi
42     if [ -z "${image}" ]; then
43         error "you must specify an output image file with '-o'\n"
44     fi
45     case "${gen}:${rev}" in
46     2:0|2:1|3:1|4:1)
47         ;;
48     3:0|4:0)
49         error "revision 0 is invalid for ext3 and ext4\n"
50         ;;
51     *)  error "unknown ext generation '%s' and/or revision '%s'\n" \
52                "${gen}" "${rev}"
53         ;;
54     esac
55
56     # calculate needed inodes
57     if [ -z "${nb_inodes}" ]; then
58         nb_inodes=$(find "${root_dir}" | wc -l)
59         nb_inodes=$((nb_inodes+400))
60     fi
61
62     # calculate needed blocks
63     if [ -z "${nb_blocks}" ]; then
64         # size ~= superblock, block+inode bitmaps, inodes (8 per block),
65         # blocks; we scale inodes / blocks with 10% to compensate for
66         # bitmaps size + slack
67         nb_blocks=$(du -s -k "${root_dir}" |sed -r -e 's/[[:space:]]+.*$//')
68         nb_blocks=$((500+(nb_blocks+nb_inodes/8)*11/10))
69         if [ ${gen} -ge 3 ]; then
70             # we add 1300 blocks (a bit more than 1 MiB, assuming 1KiB blocks)
71             # for the journal
72             # Note: I came to 1300 blocks after trial-and-error checks. YMMV.
73             nb_blocks=$((nb_blocks+1300))
74         fi
75     fi
76
77     # Upgrade to rev1 if needed
78     if [ ${rev} -ge 1 ]; then
79         tune2fs_O_opts+=",filetype"
80     fi
81
82     # Add a journal for ext3 and above
83     if [ ${gen} -ge 3 ]; then
84         tune2fs_opts+=( -j -J size=1 )
85     fi
86
87     # Add ext4 specific features
88     if [ ${gen} -ge 4 ]; then
89         tune2fs_O_opts+=",extents,uninit_bg,dir_index"
90     fi
91
92     # Add our -O options (there will be at most one leading comma, remove it)
93     if [ -n "${tune2fs_O_opts}" ]; then
94         tune2fs_opts+=( -O "${tune2fs_O_opts#,}" )
95     fi
96
97     # Add the label if specified
98     if [ -n "${label}" ]; then
99         tune2fs_opts+=( -L "${label}" )
100     fi
101
102     # Generate the filesystem
103     genext2fs_opts=( -z -b ${nb_blocks} -N ${nb_inodes} -d "${root_dir}" )
104     if [ -n "${nb_res_blocks}" ]; then
105         genext2fs_opts+=( -m ${nb_res_blocks} )
106     fi
107     genext2fs "${genext2fs_opts[@]}" "${image}"
108
109     # genext2fs does not generate a UUID, but fsck will whine if one
110     # is missing, so we need to add a UUID.
111     # Of course, this has to happen _before_ we run fsck.
112     # Also, some ext4 metadata are based on the UUID, so we must
113     # set it before we can convert the filesystem to ext4.
114     # If the user did not specify a UUID, we generate a random one.
115     # Although a random UUID may seem bad for reproducibility, there
116     # already are so many things that are not reproducible in a
117     # filesystem: file dates, file ordering, content of the files...
118     tune2fs -U "${uuid:-random}" "${image}"
119
120     # Upgrade the filesystem
121     if [ ${#tune2fs_opts[@]} -ne 0 ]; then
122         tune2fs "${tune2fs_opts[@]}" "${image}"
123     fi
124
125     # After changing filesystem options, running fsck is required
126     # (see: man tune2fs). Running e2fsck in other cases will ensure
127     # coherency of the filesystem, although it is not required.
128     # 'e2fsck -pDf' means:
129     #  - automatically repair
130     #  - optimise and check for duplicate entries
131     #  - force checking
132     # Sending output to oblivion, as e2fsck can be *very* verbose,
133     # especially with filesystems generated by genext2fs.
134     # Exit codes 1 & 2 are OK, it means fs errors were successfully
135     # corrected, hence our little trick with $ret.
136     ret=0
137     e2fsck -pDf "${image}" >/dev/null || ret=$?
138     case ${ret} in
139        0|1|2) ;;
140        *)   errorN ${ret} "failed to run e2fsck on '%s' (ext%d)\n" \
141                    "${image}" ${gen}
142     esac
143     printf "\n"
144     trace "e2fsck was successfully run on '%s' (ext%d)\n" "${image}" ${gen}
145     printf "\n"
146
147     # Remove count- and time-based checks, they are not welcome
148     # on embedded devices, where they can cause serious boot-time
149     # issues by tremendously slowing down the boot.
150     tune2fs -c 0 -i 0 "${image}"
151 }
152
153 help() {
154     cat <<_EOF_
155 NAME
156     ${my_name} - Create an ext2/3/4 filesystem image
157
158 SYNOPSIS
159     ${my_name} [OPTION]...
160
161 DESCRIPTION
162     Create ext2/3/4 filesystem image from the content of a directory.
163
164     -b BLOCKS
165         Create a filesystem of BLOCKS 1024-byte blocs. The default is to
166         compute the required number of blocks.
167
168     -i INODES
169         Create a filesystem with INODES inodes. The default is to compute
170         the required number of inodes.
171
172     -r RES_BLOCKS
173         Create a filesystem with RES_BLOCKS reserved blocks. The default
174         is to reserve 0 block.
175
176     -d ROOT_DIR
177         Create a filesystem, using the content of ROOT_DIR as the content
178         of the root of the filesystem. Mandatory.
179
180     -o FILE
181         Create the filesystem in FILE. Madatory.
182
183     -G GEN -R REV
184         Create a filesystem of generation GEN (2, 3 or 4), and revision
185         REV (0 or 1). The default is to generate an ext2 revision 1
186         filesystem; revision 0 is invalid for ext3 and ext4.
187
188     -l LABEL
189         Create a filesystem with label LABEL. The default is to not set
190         a label.
191
192     -u UUID
193         Create filesystem with uuid UUID. The default is to set a random
194         UUID.
195
196   Exit status:
197     0   if OK
198     !0  in case of error
199 _EOF_
200 }
201
202 trace()  { local msg="${1}"; shift; printf "%s: ${msg}" "${my_name}" "${@}"; }
203 warn()   { trace "${@}" >&2; }
204 errorN() { local ret="${1}"; shift; warn "${@}"; exit ${ret}; }
205 error()  { errorN 1 "${@}"; }
206
207 my_name="${0##*/}"
208 main "$@"