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