buildrootschalter/package/mke2img/mke2img

207 lines
6.4 KiB
Bash
Executable File

#!/bin/bash
# Buildroot wrapper to the collection of ext2/3/4 filesystem tools:
# - genext2fs, to generate ext2 filesystem images
# - tune2fs, to modify an ext2/3/4 filesystem (possibly in an image file)
# - e2fsck, to check and fix an ext2/3/4 filesystem (possibly in an image file)
set -e
main() {
local OPT OPTARG
local nb_blocks nb_inodes nb_res_blocks root_dir image gen rev label uuid
local -a genext2fs_opts
local -a tune2fs_opts
local tune2fs_O_opts
# Default values
gen=2
rev=1
while getopts :hb:i:r:d:o:G:R:l:u: OPT; do
case "${OPT}" in
h) help; exit 0;;
b) nb_blocks=${OPTARG};;
i) nb_inodes=${OPTARG};;
r) nb_res_blocks=${OPTARG};;
d) root_dir="${OPTARG}";;
o) image="${OPTARG}";;
G) gen=${OPTARG};;
R) rev=${OPTARG};;
l) label="${OPTARG}";;
u) uuid="${OPTARG}";;
:) error "option '%s' expects a mandatory argument\n" "${OPTARG}";;
\?) error "unknown option '%s'\n" "${OPTARG}";;
esac
done
# Sanity checks
if [ -z "${root_dir}" ]; then
error "you must specify a root directory with '-d'\n"
fi
if [ -z "${image}" ]; then
error "you must specify an output image file with '-o'\n"
fi
case "${gen}:${rev}" in
2:0|2:1|3:1|4:1)
;;
3:0|4:0)
error "revision 0 is invalid for ext3 and ext4\n"
;;
*) error "unknown ext generation '%s' and/or revision '%s'\n" \
"${gen}" "${rev}"
;;
esac
# calculate needed inodes
if [ -z "${nb_inodes}" ]; then
nb_inodes=$(find "${root_dir}" | wc -l)
nb_inodes=$((nb_inodes+400))
fi
# calculate needed blocks
if [ -z "${nb_blocks}" ]; then
# size ~= superblock, block+inode bitmaps, inodes (8 per block),
# blocks; we scale inodes / blocks with 10% to compensate for
# bitmaps size + slack
nb_blocks=$(du -s -k "${root_dir}" |sed -r -e 's/[[:space:]]+.*$//')
nb_blocks=$((500+(nb_blocks+nb_inodes/8)*11/10))
fi
# Upgrade to rev1 if needed
if [ ${rev} -ge 1 ]; then
tune2fs_O_opts+=",filetype"
fi
# Add a journal for ext3 and above
if [ ${gen} -ge 3 ]; then
tune2fs_opts+=( -j -J size=1 )
# we add 1300 blocks (a bit more than 1 MiB, assuming 1KiB blocks)
# for the journal
# Note: I came to 1300 blocks after trial-and-error checks. YMMV.
nb_blocks=$((nb_blocks+1300))
fi
# Add ext4 specific features
if [ ${gen} -ge 4 ]; then
tune2fs_O_opts+=",extents,uninit_bg,dir_index"
fi
# Add our -O options (there will be at most one leading comma, remove it)
if [ -n "${tune2fs_O_opts}" ]; then
tune2fs_opts+=( -O "${tune2fs_O_opts#,}" )
fi
# Add the label if specified
if [ -n "${label}" ]; then
tune2fs_opts+=( -L "${label}" )
fi
# Generate the filesystem
genext2fs_opts=( -b ${nb_blocks} -N ${nb_inodes} -d "${root_dir}" )
if [ -n "${nb_res_blocks}" ]; then
genext2fs_opts+=( -m ${nb_res_blocks} )
fi
genext2fs "${genext2fs_opts[@]}" "${image}"
# genext2fs does not generate a UUID, but fsck will whine if one
# is missing, so we need to add a UUID.
# Of course, this has to happen _before_ we run fsck.
# Also, some ext4 metadata are based on the UUID, so we must
# set it before we can convert the filesystem to ext4.
# If the user did not specify a UUID, we generate a random one.
# Although a random UUID may seem bad for reproducibility, there
# already are so many things that are not reproducible in a
# filesystem: file dates, file ordering, content of the files...
tune2fs -U "${uuid:-random}" "${image}"
# Upgrade the filesystem
if [ ${#tune2fs_opts[@]} -ne 0 ]; then
tune2fs "${tune2fs_opts[@]}" "${image}"
fi
# After changing filesystem options, running fsck is required
# (see: man tune2fs). Running e2fsck in other cases will ensure
# coherency of the filesystem, although it is not required.
# 'e2fsck -pDf' means:
# - automatically repair
# - optimise and check for duplicate entries
# - force checking
# Sending output to oblivion, as e2fsck can be *very* verbose,
# especially with filesystems generated by genext2fs.
# Exit codes 1 & 2 are OK, it means fs errors were successfully
# corrected, hence our little trick with $ret.
ret=0
e2fsck -pDf "${image}" >/dev/null || ret=$?
case ${ret} in
0|1|2) ;;
*) errorN ${ret} "failed to run e2fsck on '%s' (ext%d)\n" \
"${image}" ${gen}
esac
printf "\n"
trace "e2fsck was successfully run on '%s' (ext%d)\n" "${image}" ${gen}
printf "\n"
# Remove count- and time-based checks, they are not welcome
# on embedded devices, where they can cause serious boot-time
# issues by tremendously slowing down the boot.
tune2fs -c 0 -i 0 "${image}"
}
help() {
cat <<_EOF_
NAME
${my_name} - Create an ext2/3/4 filesystem image
SYNOPSIS
${my_name} [OPTION]...
DESCRIPTION
Create ext2/3/4 filesystem image from the content of a directory.
-b BLOCKS
Create a filesystem of BLOCKS 1024-byte blocs. The default is to
compute the required number of blocks.
-i INODES
Create a filesystem with INODES inodes. The default is to compute
the required number of inodes.
-r RES_BLOCKS
Create a filesystem with RES_BLOCKS reserved blocks. The default
is to reserve 0 block.
-d ROOT_DIR
Create a filesystem, using the content of ROOT_DIR as the content
of the root of the filesystem. Mandatory.
-o FILE
Create the filesystem in FILE. Madatory.
-G GEN -R REV
Create a filesystem of generation GEN (2, 3 or 4), and revision
REV (0 or 1). The default is to generate an ext2 revision 1
filesystem; revision 0 is invalid for ext3 and ext4.
-l LABEL
Create a filesystem with label LABEL. The default is to not set
a label.
-u UUID
Create filesystem with uuid UUID. The default is to set a random
UUID.
Exit status:
0 if OK
!0 in case of error
_EOF_
}
trace() { local msg="${1}"; shift; printf "%s: ${msg}" "${my_name}" "${@}"; }
warn() { trace "${@}" >&2; }
errorN() { local ret="${1}"; shift; warn "${@}"; exit ${ret}; }
error() { errorN 1 "${@}"; }
my_name="${0##*/}"
main "$@"