1#!/bin/bash 2 3# 4# Copyright (C) 2015 The Android Open Source Project 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18 19# This script generates some sample images used in unittests and packages them 20# in the sample_images.tar.bz2 file. The list of generated images and their 21# options are described in the main() function. You need to manually run this 22# script to update the generated images whenever you modify this script. 23 24set -e 25 26# cleanup <path> 27# Unmount and remove the mountpoint <path> 28cleanup() { 29 local path="$1" 30 if ! sudo umount "${path}" 2>/dev/null; then 31 if mountpoint -q "${path}"; then 32 sync && sudo umount "${path}" 33 fi 34 fi 35 if [ -n "${path}" ]; then 36 sudo rm -rf "${path}" 37 fi 38} 39 40# add_files_default <mntdir> <block_size> 41# Add several test files to the image mounted in <mntdir>. 42add_files_default() { 43 local mntdir="$1" 44 local block_size="$2" 45 46 ### Generate the files used in unittest with descriptive names. 47 sudo touch "${mntdir}"/empty-file 48 49 # regular: Regular files. 50 echo "small file" | sudo dd of="${mntdir}"/regular-small status=none 51 dd if=/dev/zero bs=1024 count=16 status=none | tr '\0' '\141' | 52 sudo dd of="${mntdir}"/regular-16k status=none 53 sudo dd if=/dev/zero of="${mntdir}"/regular-32k-zeros bs=1024 count=16 \ 54 status=none 55 56 echo "with net_cap" | sudo dd of="${mntdir}"/regular-with_net_cap status=none 57 sudo setcap cap_net_raw=ep "${mntdir}"/regular-with_net_cap 58 59 # sparse_empty: Files with no data blocks at all (only sparse holes). 60 sudo truncate --size=10240 "${mntdir}"/sparse_empty-10k 61 sudo truncate --size=$(( block_size * 2 )) "${mntdir}"/sparse_empty-2blocks 62 63 # sparse: Files with some data blocks but also sparse holes. 64 echo -n "foo" | 65 sudo dd of="${mntdir}"/sparse-16k-last_block bs=1 \ 66 seek=$(( 16 * 1024 - 3)) status=none 67 68 # ext2 inodes have 12 direct blocks, one indirect, one double indirect and 69 # one triple indirect. 10000 should be enough to have an indirect and double 70 # indirect block. 71 echo -n "foo" | 72 sudo dd of="${mntdir}"/sparse-10000blocks bs=1 \ 73 seek=$(( block_size * 10000 )) status=none 74 75 sudo truncate --size=16384 "${mntdir}"/sparse-16k-first_block 76 echo "first block" | sudo dd of="${mntdir}"/sparse-16k-first_block status=none 77 78 sudo truncate --size=16384 "${mntdir}"/sparse-16k-holes 79 echo "a" | sudo dd of="${mntdir}"/sparse-16k-holes bs=1 seek=100 status=none 80 echo "b" | sudo dd of="${mntdir}"/sparse-16k-holes bs=1 seek=10000 status=none 81 82 # link: symlinks and hardlinks. 83 sudo ln -s "broken-link" "${mntdir}"/link-short_symlink 84 sudo ln -s $(dd if=/dev/zero bs=256 count=1 status=none | tr '\0' '\141') \ 85 "${mntdir}"/link-long_symlink 86 sudo ln "${mntdir}"/regular-16k "${mntdir}"/link-hard-regular-16k 87 88 # Directories. 89 sudo mkdir -p "${mntdir}"/dir1/dir2/dir1 90 echo "foo" | sudo tee "${mntdir}"/dir1/dir2/file >/dev/null 91 echo "bar" | sudo tee "${mntdir}"/dir1/file >/dev/null 92 93 # FIFO 94 sudo mkfifo "${mntdir}"/fifo 95 96 # character special file 97 sudo mknod "${mntdir}"/cdev c 2 3 98 99 # removed: removed files that should not be listed. 100 echo "We will remove this file so it's contents will be somewhere in the " \ 101 "empty space data but it won't be all zeros." | 102 sudo dd of="${mntdir}"/removed conv=fsync status=none 103 sudo rm "${mntdir}"/removed 104} 105 106# add_files_ue_settings <mntdir> <block_size> 107# Add the update_engine.conf settings file. This file contains the 108add_files_ue_settings() { 109 local mntdir="$1" 110 111 sudo mkdir -p "${mntdir}"/etc >/dev/null 112 sudo tee "${mntdir}"/etc/update_engine.conf >/dev/null <<EOF 113PAYLOAD_MINOR_VERSION=1234 114EOF 115 # Example of a real lsb-release file released on link stable. 116 sudo tee "${mntdir}"/etc/lsb-release >/dev/null <<EOF 117CHROMEOS_AUSERVER=https://tools.google.com/service/update2 118CHROMEOS_BOARD_APPID={F26D159B-52A3-491A-AE25-B23670A66B32} 119CHROMEOS_CANARY_APPID={90F229CE-83E2-4FAF-8479-E368A34938B1} 120CHROMEOS_DEVSERVER= 121CHROMEOS_RELEASE_APPID={F26D159B-52A3-491A-AE25-B23670A66B32} 122CHROMEOS_RELEASE_BOARD=link-signed-mp-v4keys 123CHROMEOS_RELEASE_BRANCH_NUMBER=63 124CHROMEOS_RELEASE_BUILD_NUMBER=6946 125CHROMEOS_RELEASE_BUILD_TYPE=Official Build 126CHROMEOS_RELEASE_CHROME_MILESTONE=43 127CHROMEOS_RELEASE_DESCRIPTION=6946.63.0 (Official Build) stable-channel link 128CHROMEOS_RELEASE_NAME=Chrome OS 129CHROMEOS_RELEASE_PATCH_NUMBER=0 130CHROMEOS_RELEASE_TRACK=stable-channel 131CHROMEOS_RELEASE_VERSION=6946.63.0 132GOOGLE_RELEASE=6946.63.0 133EOF 134} 135 136add_files_postinstall() { 137 local mntdir="$1" 138 139 sudo mkdir -p "${mntdir}"/bin >/dev/null 140 141 # A postinstall bash program. 142 sudo tee "${mntdir}"/bin/postinst_example >/dev/null <<EOF 143#!/etc/../bin/sh 144echo "I'm a postinstall program and I know how to write to stdout" 145echo "My call was $@" 146exit 0 147EOF 148 149 # A symlink to another program. This should also work. 150 sudo ln -s "postinst_example" "${mntdir}"/bin/postinst_link 151 152 sudo tee "${mntdir}"/bin/postinst_fail3 >/dev/null <<EOF 153#!/etc/../bin/sh 154exit 3 155EOF 156 157 sudo tee "${mntdir}"/bin/postinst_fail1 >/dev/null <<EOF 158#!/etc/../bin/sh 159exit 1 160EOF 161 162 # A program that succeeds if it is suspended during the first 5 minutes. 163 sudo tee "${mntdir}"/bin/postinst_suspend >/dev/null <<EOF 164#!/etc/../bin/sh 165trap "{ echo Got a SIGCONT; exit 0; }" CONT 166# Signal that we are ready to receive the signal by redirecting our stdin to 167# /dev/zero, the test can detect that. 168exec </dev/zero 169# Allow the signal handler to run every 100 ms. 170i=3000 171while [ \$i -ge 0 ]; do 172 sleep 0.1 173 i=\$((i-1)) 174done 175exit 1 176EOF 177 178 # A program that reports back progress. 179 sudo tee "${mntdir}"/bin/postinst_progress >/dev/null <<EOF 180#!/etc/../bin/sh 181# These values have exact representation in IEEE 754 so we avoid rounding 182# errors. 183echo global_progress 0.25 >&3 184echo global_progress 0.5 >&3 185echo global_progress 1.0 >&3 186exit 0 187EOF 188 189 # A postinstall bash program. 190 sudo tee "${mntdir}"/bin/self_check_context >/dev/null <<EOF 191#!/etc/../bin/sh 192echo "This is my context:" 193ls -lZ "\$0" | grep -F ' u:object_r:postinstall_file:s0 ' || exit 5 194exit 0 195EOF 196 197 sudo tee "${mntdir}"/postinst >/dev/null <<EOF 198#!/etc/../bin/sh 199echo "postinst" 200exit 0 201EOF 202 203 sudo chmod +x "${mntdir}"/postinst "${mntdir}"/bin/* 204} 205 206# generate_fs <filename> <kind> <size> [block_size] [block_groups] 207generate_fs() { 208 local filename="$1" 209 local type="$2" 210 local kind="$3" 211 local size="$4" 212 local block_size="${5:-4096}" 213 local block_groups="${6:-}" 214 215 local mkfs_opts=( -q -F -b "${block_size}" -L "ROOT-TEST" -t ext2 ) 216 if [[ -n "${block_groups}" ]]; then 217 mkfs_opts+=( -G "${block_groups}" ) 218 fi 219 220 local mntdir=$(mktemp --tmpdir -d generate_ext2.XXXXXX) 221 trap 'cleanup "${mntdir}"; rm -f "${filename}"' INT TERM EXIT 222 # Cleanup old image. 223 if [[ -e "${filename}" ]]; then 224 rm -f "${filename}" 225 fi 226 227 if [[ "${type}" == "ext2" ]]; then 228 truncate --size="${size}" "${filename}" 229 230 mkfs.ext2 "${mkfs_opts[@]}" "${filename}" 231 sudo mount "${filename}" "${mntdir}" -o loop 232 fi 233 case "${kind}" in 234 unittest) 235 add_files_ue_settings "${mntdir}" "${block_size}" 236 add_files_postinstall "${mntdir}" "${block_size}" 237 ;; 238 default) 239 add_files_default "${mntdir}" "${block_size}" 240 ;; 241 empty) 242 ;; 243 esac 244 245 if [[ "${type}" == "sqfs" ]]; then 246 mksquashfs "${mntdir}" "${filename}" 247 fi 248 249 cleanup "${mntdir}" 250 trap - INT TERM EXIT 251} 252 253OUTPUT_DIR=$(dirname "$0") 254IMAGES=() 255 256# generate_image <image_name> [<image args> ...] 257generate_image() { 258 echo "Generating image $1.img" 259 IMAGES+=( "$1.img" ) 260 generate_fs "${OUTPUT_DIR}/$1.img" "${@:2}" 261} 262 263main() { 264 # Add more sample images here. 265 generate_image disk_ext2_1k ext2 default $((1024 * 1024)) 1024 266 generate_image disk_ext2_4k ext2 default $((1024 * 4096)) 4096 267 generate_image disk_ext2_4k_empty ext2 empty $((1024 * 4096)) 4096 268 generate_image disk_ext2_unittest ext2 unittest $((1024 * 4096)) 4096 269 270 # Add squashfs sample images. 271 generate_image disk_sqfs_empty sqfs empty $((1024 * 4096)) 4096 272 generate_image disk_sqfs_default sqfs default $((1024 * 4096)) 4096 273 274 # Generate the tarball and delete temporary images. 275 echo "Packing tar file sample_images.tar.bz2" 276 tar -jcf "${OUTPUT_DIR}/sample_images.tar.bz2" -C "${OUTPUT_DIR}" \ 277 --sparse "${IMAGES[@]}" 278 cd "${OUTPUT_DIR}" 279 rm "${IMAGES[@]}" 280} 281 282main 283