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 24 set -e 25 26 # cleanup <path> 27 # Unmount and remove the mountpoint <path> 28 cleanup() { 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>. 39 add_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 # removed: removed files that should not be listed. 91 echo "We will remove this file so it's contents will be somewhere in the " \ 92 "empty space data but it won't be all zeros." | 93 sudo dd of="${mntdir}"/removed conv=fsync status=none 94 sudo rm "${mntdir}"/removed 95 } 96 97 # add_files_ue_settings <mntdir> <block_size> 98 # Add the update_engine.conf settings file. This file contains the 99 add_files_ue_settings() { 100 local mntdir="$1" 101 102 sudo mkdir -p "${mntdir}"/etc >/dev/null 103 sudo tee "${mntdir}"/etc/update_engine.conf >/dev/null <<EOF 104 PAYLOAD_MINOR_VERSION=1234 105 EOF 106 # Example of a real lsb-release file released on link stable. 107 sudo tee "${mntdir}"/etc/lsb-release >/dev/null <<EOF 108 CHROMEOS_AUSERVER=https://tools.google.com/service/update2 109 CHROMEOS_BOARD_APPID={F26D159B-52A3-491A-AE25-B23670A66B32} 110 CHROMEOS_CANARY_APPID={90F229CE-83E2-4FAF-8479-E368A34938B1} 111 CHROMEOS_DEVSERVER= 112 CHROMEOS_RELEASE_APPID={F26D159B-52A3-491A-AE25-B23670A66B32} 113 CHROMEOS_RELEASE_BOARD=link-signed-mp-v4keys 114 CHROMEOS_RELEASE_BRANCH_NUMBER=63 115 CHROMEOS_RELEASE_BUILD_NUMBER=6946 116 CHROMEOS_RELEASE_BUILD_TYPE=Official Build 117 CHROMEOS_RELEASE_CHROME_MILESTONE=43 118 CHROMEOS_RELEASE_DESCRIPTION=6946.63.0 (Official Build) stable-channel link 119 CHROMEOS_RELEASE_NAME=Chrome OS 120 CHROMEOS_RELEASE_PATCH_NUMBER=0 121 CHROMEOS_RELEASE_TRACK=stable-channel 122 CHROMEOS_RELEASE_VERSION=6946.63.0 123 GOOGLE_RELEASE=6946.63.0 124 EOF 125 } 126 127 add_files_postinstall() { 128 local mntdir="$1" 129 130 sudo mkdir -p "${mntdir}"/bin >/dev/null 131 132 # A postinstall bash program. 133 sudo tee "${mntdir}"/bin/postinst_example >/dev/null <<EOF 134 #!/etc/../bin/sh 135 echo "I'm a postinstall program and I know how to write to stdout" 136 echo "My call was $@" 137 exit 0 138 EOF 139 140 # A symlink to another program. This should also work. 141 sudo ln -s "postinst_example" "${mntdir}"/bin/postinst_link 142 143 sudo tee "${mntdir}"/bin/postinst_fail3 >/dev/null <<EOF 144 #!/etc/../bin/sh 145 exit 3 146 EOF 147 148 sudo tee "${mntdir}"/bin/postinst_fail1 >/dev/null <<EOF 149 #!/etc/../bin/sh 150 exit 1 151 EOF 152 153 # A program that succeeds if it is suspended during the first 5 minutes. 154 sudo tee "${mntdir}"/bin/postinst_suspend >/dev/null <<EOF 155 #!/etc/../bin/sh 156 trap "{ echo Got a SIGCONT; exit 0; }" CONT 157 # Signal that we are ready to receive the signal by redirecting our stdin to 158 # /dev/zero, the test can detect that. 159 exec </dev/zero 160 # Allow the signal handler to run every 100 ms. 161 i=3000 162 while [ \$i -ge 0 ]; do 163 sleep 0.1 164 i=\$((i-1)) 165 done 166 exit 1 167 EOF 168 169 # A program that reports back progress. 170 sudo tee "${mntdir}"/bin/postinst_progress >/dev/null <<EOF 171 #!/etc/../bin/sh 172 # These values have exact representation in IEEE 754 so we avoid rounding 173 # errors. 174 echo global_progress 0.25 >&3 175 echo global_progress 0.5 >&3 176 echo global_progress 1.0 >&3 177 exit 0 178 EOF 179 180 # A postinstall bash program. 181 sudo tee "${mntdir}"/bin/self_check_context >/dev/null <<EOF 182 #!/etc/../bin/sh 183 echo "This is my context:" 184 ls -lZ "\$0" | grep -F ' u:object_r:postinstall_file:s0 ' || exit 5 185 exit 0 186 EOF 187 188 sudo tee "${mntdir}"/postinst >/dev/null <<EOF 189 #!/etc/../bin/sh 190 echo "postinst" 191 exit 0 192 EOF 193 194 sudo chmod +x "${mntdir}"/postinst "${mntdir}"/bin/* 195 } 196 197 # generate_fs <filename> <kind> <size> [block_size] [block_groups] 198 generate_fs() { 199 local filename="$1" 200 local kind="$2" 201 local size="$3" 202 local block_size="${4:-4096}" 203 local block_groups="${5:-}" 204 205 local mkfs_opts=( -q -F -b "${block_size}" -L "ROOT-TEST" -t ext2 ) 206 if [[ -n "${block_groups}" ]]; then 207 mkfs_opts+=( -G "${block_groups}" ) 208 fi 209 210 local mntdir=$(mktemp --tmpdir -d generate_ext2.XXXXXX) 211 trap 'cleanup "${mntdir}"; rm -f "${filename}"' INT TERM EXIT 212 213 # Cleanup old image. 214 if [[ -e "${filename}" ]]; then 215 rm -f "${filename}" 216 fi 217 truncate --size="${size}" "${filename}" 218 219 mkfs.ext2 "${mkfs_opts[@]}" "${filename}" 220 sudo mount "${filename}" "${mntdir}" -o loop 221 222 case "${kind}" in 223 unittest) 224 add_files_ue_settings "${mntdir}" "${block_size}" 225 add_files_postinstall "${mntdir}" "${block_size}" 226 ;; 227 default) 228 add_files_default "${mntdir}" "${block_size}" 229 ;; 230 empty) 231 ;; 232 esac 233 234 cleanup "${mntdir}" 235 trap - INT TERM EXIT 236 } 237 238 OUTPUT_DIR=$(dirname "$0") 239 IMAGES=() 240 241 # generate_image <image_name> [<image args> ...] 242 generate_image() { 243 echo "Generating image $1.img" 244 IMAGES+=( "$1.img" ) 245 generate_fs "${OUTPUT_DIR}/$1.img" "${@:2}" 246 } 247 248 main() { 249 # Add more sample images here. 250 generate_image disk_ext2_1k default 16777216 1024 251 generate_image disk_ext2_4k default 16777216 4096 252 generate_image disk_ext2_4k_empty empty $((1024 * 4096)) 4096 253 generate_image disk_ext2_unittest unittest $((1024 * 4096)) 4096 254 255 # Generate the tarball and delete temporary images. 256 echo "Packing tar file sample_images.tar.bz2" 257 tar -jcf "${OUTPUT_DIR}/sample_images.tar.bz2" -C "${OUTPUT_DIR}" \ 258 --sparse "${IMAGES[@]}" 259 cd "${OUTPUT_DIR}" 260 rm "${IMAGES[@]}" 261 } 262 263 main 264