297 lines
9.1 KiB
Bash
Executable File
297 lines
9.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
#
|
|
# Copyright (C) 2015 The Android Open Source Project
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
#
|
|
|
|
# This script generates some sample images used in unittests and packages them
|
|
# in the sample_images.tar.bz2 file. The list of generated images and their
|
|
# options are described in the main() function. You need to manually run this
|
|
# script to update the generated images whenever you modify this script.
|
|
|
|
set -e
|
|
|
|
# cleanup <path>
|
|
# Unmount and remove the mountpoint <path>
|
|
cleanup() {
|
|
local path="$1"
|
|
if ! sudo umount "${path}" 2>/dev/null; then
|
|
if mountpoint -q "${path}"; then
|
|
sync && sudo umount "${path}"
|
|
fi
|
|
fi
|
|
if [ -n "${path}" ]; then
|
|
sudo rm -rf "${path}"
|
|
fi
|
|
}
|
|
|
|
# add_files_default <mntdir> <block_size>
|
|
# Add several test files to the image mounted in <mntdir>.
|
|
add_files_default() {
|
|
local mntdir="$1"
|
|
local block_size="$2"
|
|
|
|
### Generate the files used in unittest with descriptive names.
|
|
sudo touch "${mntdir}"/empty-file
|
|
|
|
# regular: Regular files.
|
|
echo "small file" | sudo dd of="${mntdir}"/regular-small status=none
|
|
dd if=/dev/zero bs=1024 count=16 status=none | tr '\0' '\141' |
|
|
sudo dd of="${mntdir}"/regular-16k status=none
|
|
sudo dd if=/dev/zero of="${mntdir}"/regular-32k-zeros bs=1024 count=16 \
|
|
status=none
|
|
|
|
echo "with net_cap" | sudo dd of="${mntdir}"/regular-with_net_cap status=none
|
|
sudo setcap cap_net_raw=ep "${mntdir}"/regular-with_net_cap
|
|
|
|
# sparse_empty: Files with no data blocks at all (only sparse holes).
|
|
sudo truncate --size=10240 "${mntdir}"/sparse_empty-10k
|
|
sudo truncate --size=$(( block_size * 2 )) "${mntdir}"/sparse_empty-2blocks
|
|
|
|
# sparse: Files with some data blocks but also sparse holes.
|
|
echo -n "foo" |
|
|
sudo dd of="${mntdir}"/sparse-16k-last_block bs=1 \
|
|
seek=$(( 16 * 1024 - 3)) status=none
|
|
|
|
# ext2 inodes have 12 direct blocks, one indirect, one double indirect and
|
|
# one triple indirect. 10000 should be enough to have an indirect and double
|
|
# indirect block.
|
|
echo -n "foo" |
|
|
sudo dd of="${mntdir}"/sparse-10000blocks bs=1 \
|
|
seek=$(( block_size * 10000 )) status=none
|
|
|
|
sudo truncate --size=16384 "${mntdir}"/sparse-16k-first_block
|
|
echo "first block" | sudo dd of="${mntdir}"/sparse-16k-first_block status=none
|
|
|
|
sudo truncate --size=16384 "${mntdir}"/sparse-16k-holes
|
|
echo "a" | sudo dd of="${mntdir}"/sparse-16k-holes bs=1 seek=100 status=none
|
|
echo "b" | sudo dd of="${mntdir}"/sparse-16k-holes bs=1 seek=10000 status=none
|
|
|
|
# link: symlinks and hardlinks.
|
|
sudo ln -s "broken-link" "${mntdir}"/link-short_symlink
|
|
sudo ln -s $(dd if=/dev/zero bs=256 count=1 status=none | tr '\0' '\141') \
|
|
"${mntdir}"/link-long_symlink
|
|
sudo ln "${mntdir}"/regular-16k "${mntdir}"/link-hard-regular-16k
|
|
|
|
# Directories.
|
|
sudo mkdir -p "${mntdir}"/dir1/dir2/dir1
|
|
echo "foo" | sudo tee "${mntdir}"/dir1/dir2/file >/dev/null
|
|
echo "bar" | sudo tee "${mntdir}"/dir1/file >/dev/null
|
|
|
|
# FIFO
|
|
sudo mkfifo "${mntdir}"/fifo
|
|
|
|
# character special file
|
|
sudo mknod "${mntdir}"/cdev c 2 3
|
|
|
|
# removed: removed files that should not be listed.
|
|
echo "We will remove this file so it's contents will be somewhere in the " \
|
|
"empty space data but it won't be all zeros." |
|
|
sudo dd of="${mntdir}"/removed conv=fsync status=none
|
|
sudo rm "${mntdir}"/removed
|
|
}
|
|
|
|
# add_files_ue_settings <mntdir> <block_size>
|
|
# Add the update_engine.conf settings file. This file contains the
|
|
add_files_ue_settings() {
|
|
local mntdir="$1"
|
|
|
|
sudo mkdir -p "${mntdir}"/etc >/dev/null
|
|
sudo tee "${mntdir}"/etc/update_engine.conf >/dev/null <<EOF
|
|
PAYLOAD_MINOR_VERSION=1234
|
|
EOF
|
|
# Example of a real lsb-release file released on link stable.
|
|
sudo tee "${mntdir}"/etc/lsb-release >/dev/null <<EOF
|
|
CHROMEOS_AUSERVER=https://tools.google.com/service/update2
|
|
CHROMEOS_BOARD_APPID={F26D159B-52A3-491A-AE25-B23670A66B32}
|
|
CHROMEOS_CANARY_APPID={90F229CE-83E2-4FAF-8479-E368A34938B1}
|
|
CHROMEOS_DEVSERVER=
|
|
CHROMEOS_RELEASE_APPID={F26D159B-52A3-491A-AE25-B23670A66B32}
|
|
CHROMEOS_RELEASE_BOARD=link-signed-mp-v4keys
|
|
CHROMEOS_RELEASE_BRANCH_NUMBER=63
|
|
CHROMEOS_RELEASE_BUILD_NUMBER=6946
|
|
CHROMEOS_RELEASE_BUILD_TYPE=Official Build
|
|
CHROMEOS_RELEASE_CHROME_MILESTONE=43
|
|
CHROMEOS_RELEASE_DESCRIPTION=6946.63.0 (Official Build) stable-channel link
|
|
CHROMEOS_RELEASE_NAME=Chrome OS
|
|
CHROMEOS_RELEASE_PATCH_NUMBER=0
|
|
CHROMEOS_RELEASE_TRACK=stable-channel
|
|
CHROMEOS_RELEASE_VERSION=6946.63.0
|
|
GOOGLE_RELEASE=6946.63.0
|
|
EOF
|
|
}
|
|
|
|
add_files_postinstall() {
|
|
local mntdir="$1"
|
|
|
|
sudo mkdir -p "${mntdir}"/bin >/dev/null
|
|
|
|
# A postinstall bash program.
|
|
sudo tee "${mntdir}"/bin/postinst_example >/dev/null <<EOF
|
|
#!/etc/../bin/sh
|
|
echo "I'm a postinstall program and I know how to write to stdout"
|
|
echo "My call was $@"
|
|
exit 0
|
|
EOF
|
|
|
|
# A symlink to another program. This should also work.
|
|
sudo ln -s "postinst_example" "${mntdir}"/bin/postinst_link
|
|
|
|
sudo tee "${mntdir}"/bin/postinst_fail3 >/dev/null <<EOF
|
|
#!/etc/../bin/sh
|
|
exit 3
|
|
EOF
|
|
|
|
sudo tee "${mntdir}"/bin/postinst_fail1 >/dev/null <<EOF
|
|
#!/etc/../bin/sh
|
|
exit 1
|
|
EOF
|
|
|
|
# A program that succeeds if it is suspended during the first 5 minutes.
|
|
sudo tee "${mntdir}"/bin/postinst_suspend >/dev/null <<EOF
|
|
#!/etc/../bin/sh
|
|
trap "{ echo Got a SIGCONT; exit 0; }" CONT
|
|
# Signal that we are ready to receive the signal by redirecting our stdin to
|
|
# /dev/zero, the test can detect that.
|
|
exec </dev/zero
|
|
# Allow the signal handler to run every 100 ms.
|
|
i=3000
|
|
while [ \$i -ge 0 ]; do
|
|
sleep 0.1
|
|
i=\$((i-1))
|
|
done
|
|
exit 1
|
|
EOF
|
|
|
|
# A program that reports back progress.
|
|
sudo tee "${mntdir}"/bin/postinst_progress >/dev/null <<EOF
|
|
#!/etc/../bin/sh
|
|
# These values have exact representation in IEEE 754 so we avoid rounding
|
|
# errors.
|
|
echo global_progress 0.25 >&3
|
|
echo global_progress 0.5 >&3
|
|
echo global_progress 1.0 >&3
|
|
exit 0
|
|
EOF
|
|
|
|
# An unlabeled postinstall bash program.
|
|
sudo tee "${mntdir}"/bin/self_check_default_context >/dev/null <<EOF
|
|
#!/etc/../bin/sh
|
|
echo "This is my context:"
|
|
ls -lZ "\$0"
|
|
ls -lZ "\$0" | grep -F ' u:object_r:postinstall_file:s0 ' || exit 5
|
|
exit 0
|
|
EOF
|
|
|
|
# A postinstall bash program.
|
|
sudo tee "${mntdir}"/bin/self_check_context >/dev/null <<EOF
|
|
#!/etc/../bin/sh
|
|
echo "This is my context:"
|
|
ls -lZ "\$0"
|
|
ls -lZ "\$0" | grep -F ' u:object_r:postinstall_exec:s0 ' || exit 5
|
|
exit 0
|
|
EOF
|
|
|
|
# Give the test function the context we expect the postinstall-executable to have.
|
|
sudo setfattr -n security.selinux -v u:object_r:postinstall_exec:s0 "${mntdir}"/bin/self_check_context
|
|
|
|
sudo tee "${mntdir}"/postinst >/dev/null <<EOF
|
|
#!/etc/../bin/sh
|
|
echo "postinst"
|
|
exit 0
|
|
EOF
|
|
|
|
sudo chmod +x "${mntdir}"/postinst "${mntdir}"/bin/*
|
|
}
|
|
|
|
# generate_fs <filename> <kind> <size> [block_size] [block_groups]
|
|
generate_fs() {
|
|
local filename="$1"
|
|
local type="$2"
|
|
local kind="$3"
|
|
local size="$4"
|
|
local block_size="${5:-4096}"
|
|
local block_groups="${6:-}"
|
|
|
|
local mkfs_opts=( -q -F -b "${block_size}" -L "ROOT-TEST" -t ext2 )
|
|
if [[ -n "${block_groups}" ]]; then
|
|
mkfs_opts+=( -G "${block_groups}" )
|
|
fi
|
|
|
|
local mntdir=$(mktemp --tmpdir -d generate_ext2.XXXXXX)
|
|
trap 'cleanup "${mntdir}"; rm -f "${filename}"' INT TERM EXIT
|
|
# Cleanup old image.
|
|
if [[ -e "${filename}" ]]; then
|
|
rm -f "${filename}"
|
|
fi
|
|
|
|
if [[ "${type}" == "ext2" ]]; then
|
|
truncate --size="${size}" "${filename}"
|
|
|
|
mkfs.ext2 "${mkfs_opts[@]}" "${filename}"
|
|
sudo mount "${filename}" "${mntdir}" -o loop
|
|
fi
|
|
case "${kind}" in
|
|
unittest)
|
|
add_files_ue_settings "${mntdir}" "${block_size}"
|
|
add_files_postinstall "${mntdir}" "${block_size}"
|
|
;;
|
|
default)
|
|
add_files_default "${mntdir}" "${block_size}"
|
|
;;
|
|
empty)
|
|
;;
|
|
esac
|
|
|
|
if [[ "${type}" == "sqfs" ]]; then
|
|
mksquashfs "${mntdir}" "${filename}"
|
|
fi
|
|
|
|
cleanup "${mntdir}"
|
|
trap - INT TERM EXIT
|
|
}
|
|
|
|
OUTPUT_DIR=$(dirname "$0")
|
|
IMAGES=()
|
|
|
|
# generate_image <image_name> [<image args> ...]
|
|
generate_image() {
|
|
echo "Generating image $1.img"
|
|
IMAGES+=( "$1.img" )
|
|
generate_fs "${OUTPUT_DIR}/$1.img" "${@:2}"
|
|
}
|
|
|
|
main() {
|
|
# Add more sample images here.
|
|
generate_image disk_ext2_1k ext2 default $((1024 * 1024)) 1024
|
|
generate_image disk_ext2_4k ext2 default $((1024 * 4096)) 4096
|
|
generate_image disk_ext2_4k_empty ext2 empty $((1024 * 4096)) 4096
|
|
generate_image disk_ext2_unittest ext2 unittest $((1024 * 4096)) 4096
|
|
|
|
# Add squashfs sample images.
|
|
generate_image disk_sqfs_empty sqfs empty $((1024 * 4096)) 4096
|
|
generate_image disk_sqfs_default sqfs default $((1024 * 4096)) 4096
|
|
generate_image disk_sqfs_unittest sqfs unittest $((1024 * 4096)) 4096
|
|
|
|
# Generate the tarball and delete temporary images.
|
|
echo "Packing tar file sample_images.tar.bz2"
|
|
tar -jcf "${OUTPUT_DIR}/sample_images.tar.bz2" -C "${OUTPUT_DIR}" \
|
|
--sparse "${IMAGES[@]}"
|
|
cd "${OUTPUT_DIR}"
|
|
rm "${IMAGES[@]}"
|
|
}
|
|
|
|
main
|