| #!/bin/sh |
| # genext2fs wrapper calculating needed blocks/inodes values if not specified |
| set -e |
| |
| export LC_ALL=C |
| |
| CALC_BLOCKS=1 |
| CALC_INODES=1 |
| EXT_OPTS= |
| EXT_OPTS_O= |
| |
| while getopts x:d:D:b:i:N:m:g:e:zfqUPhVv f |
| do |
| case $f in |
| b) CALC_BLOCKS=0 ;; |
| N) CALC_INODES=0; INODES=$OPTARG ;; |
| d) TARGET_DIR=$OPTARG ;; |
| esac |
| done |
| eval IMG="\"\${${OPTIND}}\"" |
| |
| # calculate needed inodes |
| if [ $CALC_INODES -eq 1 ]; |
| then |
| INODES=$(find $TARGET_DIR | wc -l) |
| INODES=$(expr $INODES + 400) |
| set -- $@ -N $INODES |
| fi |
| |
| # calculate needed blocks |
| if [ $CALC_BLOCKS -eq 1 ]; |
| then |
| # size ~= superblock, block+inode bitmaps, inodes (8 per block), blocks |
| # we scale inodes / blocks with 10% to compensate for bitmaps size + slack |
| BLOCKS=$(du -s -c -k $TARGET_DIR | grep total | sed -e "s/total//") |
| BLOCKS=$(expr 500 + \( $BLOCKS + $INODES / 8 \) \* 11 / 10) |
| # we add 1300 blocks (a bit more than 1 MiB, assuming 1KiB blocks) for |
| # the journal if ext3/4 |
| # Note: I came to 1300 blocks after trial-and-error checks. YMMV. |
| if [ ${GEN} -ge 3 ]; then |
| BLOCKS=$(expr 1300 + $BLOCKS ) |
| fi |
| set -- $@ -b $BLOCKS |
| fi |
| |
| e2tunefsck() { |
| # genext2fs does not generate a UUID, but fsck will whine if one is |
| # is missing, so we need to add a UUID. |
| # Of course, this has to happend _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. |
| # 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 random "${IMG}" |
| |
| # Upgrade the filesystem |
| if [ $# -ne 0 ]; then |
| tune2fs "$@" "${IMG}" |
| 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 "${IMG}" >/dev/null || ret=$? |
| case ${ret} in |
| 0|1|2) ;; |
| *) exit ${ret};; |
| esac |
| printf "\ne2fsck was successfully run on '%s' (ext%d)\n\n" \ |
| "${IMG##*/}" "${GEN}" |
| |
| # 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 "${IMG}" |
| } |
| |
| # Check we know what generation to generate |
| case "${GEN}:${REV}" in |
| 2:0|2:1|3:1|4:1) |
| ;; |
| *) |
| printf "%s: unknown ext generation '%s' and/or revision '%s'\n" \ |
| "${0##*/}" "${GEN}" "${REV}" >&2 |
| exit 1 |
| ;; |
| esac |
| |
| # Upgrade to rev1 if needed |
| if [ ${REV} -ge 1 ]; then |
| EXT_OPTS_O="${EXT_OPTS_O},filetype" |
| fi |
| |
| # Add a journal for ext3 and above |
| if [ ${GEN} -ge 3 ]; then |
| EXT_OPTS="${EXT_OPTS} -j -J size=1" |
| fi |
| |
| # Add ext4 specific features |
| if [ ${GEN} -ge 4 ]; then |
| EXT_OPTS_O="${EXT_OPTS_O},extents,uninit_bg,dir_index" |
| fi |
| |
| # Add our -O options (there will be at most one leading comma, remove it) |
| if [ -n "${EXT_OPTS_O}" ]; then |
| EXT_OPTS="${EXT_OPTS} -O ${EXT_OPTS_O#,}" |
| fi |
| |
| # Generate and upgrade the filesystem |
| genext2fs "$@" |
| e2tunefsck ${EXT_OPTS} |