| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 1 | #!/bin/bash | 
|  | 2 |  | 
| Alex Deymo | aea4c1c | 2015-08-19 20:24:43 -0700 | [diff] [blame] | 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 | # | 
| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 18 |  | 
| Alex Deymo | 04ef207 | 2015-08-13 08:19:16 -0700 | [diff] [blame] | 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 |  | 
| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 24 | set -e | 
|  | 25 |  | 
|  | 26 | # cleanup <path> | 
|  | 27 | # Unmount and remove the mountpoint <path> | 
|  | 28 | cleanup() { | 
| Amin Hassani | d7da8f4 | 2017-08-23 14:29:40 -0700 | [diff] [blame] | 29 | local path="$1" | 
|  | 30 | if ! sudo umount "${path}" 2>/dev/null; then | 
|  | 31 | if mountpoint -q "${path}"; then | 
|  | 32 | sync && sudo umount "${path}" | 
| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 33 | fi | 
|  | 34 | fi | 
| Amin Hassani | d7da8f4 | 2017-08-23 14:29:40 -0700 | [diff] [blame] | 35 | if [ -n "${path}" ]; then | 
|  | 36 | sudo rm -rf "${path}" | 
|  | 37 | fi | 
| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 38 | } | 
|  | 39 |  | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 40 | # add_files_default <mntdir> <block_size> | 
|  | 41 | # Add several test files to the image mounted in <mntdir>. | 
|  | 42 | add_files_default() { | 
|  | 43 | local mntdir="$1" | 
|  | 44 | local block_size="$2" | 
| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 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 |  | 
| Sen Jiang | 990c27b | 2016-03-15 17:09:21 -0700 | [diff] [blame] | 93 | # FIFO | 
|  | 94 | sudo mkfifo "${mntdir}"/fifo | 
|  | 95 |  | 
|  | 96 | # character special file | 
|  | 97 | sudo mknod "${mntdir}"/cdev c 2 3 | 
|  | 98 |  | 
| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 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 | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 104 | } | 
|  | 105 |  | 
|  | 106 | # add_files_ue_settings <mntdir> <block_size> | 
|  | 107 | # Add the update_engine.conf settings file. This file contains the | 
|  | 108 | add_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 | 
|  | 113 | PAYLOAD_MINOR_VERSION=1234 | 
|  | 114 | EOF | 
|  | 115 | # Example of a real lsb-release file released on link stable. | 
|  | 116 | sudo tee "${mntdir}"/etc/lsb-release >/dev/null <<EOF | 
|  | 117 | CHROMEOS_AUSERVER=https://tools.google.com/service/update2 | 
|  | 118 | CHROMEOS_BOARD_APPID={F26D159B-52A3-491A-AE25-B23670A66B32} | 
|  | 119 | CHROMEOS_CANARY_APPID={90F229CE-83E2-4FAF-8479-E368A34938B1} | 
|  | 120 | CHROMEOS_DEVSERVER= | 
|  | 121 | CHROMEOS_RELEASE_APPID={F26D159B-52A3-491A-AE25-B23670A66B32} | 
|  | 122 | CHROMEOS_RELEASE_BOARD=link-signed-mp-v4keys | 
|  | 123 | CHROMEOS_RELEASE_BRANCH_NUMBER=63 | 
|  | 124 | CHROMEOS_RELEASE_BUILD_NUMBER=6946 | 
|  | 125 | CHROMEOS_RELEASE_BUILD_TYPE=Official Build | 
|  | 126 | CHROMEOS_RELEASE_CHROME_MILESTONE=43 | 
|  | 127 | CHROMEOS_RELEASE_DESCRIPTION=6946.63.0 (Official Build) stable-channel link | 
|  | 128 | CHROMEOS_RELEASE_NAME=Chrome OS | 
|  | 129 | CHROMEOS_RELEASE_PATCH_NUMBER=0 | 
|  | 130 | CHROMEOS_RELEASE_TRACK=stable-channel | 
|  | 131 | CHROMEOS_RELEASE_VERSION=6946.63.0 | 
|  | 132 | GOOGLE_RELEASE=6946.63.0 | 
|  | 133 | EOF | 
|  | 134 | } | 
|  | 135 |  | 
| Alex Deymo | cbc2274 | 2016-03-04 17:53:02 -0800 | [diff] [blame] | 136 | add_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 | 
|  | 144 | echo "I'm a postinstall program and I know how to write to stdout" | 
|  | 145 | echo "My call was $@" | 
|  | 146 | exit 0 | 
|  | 147 | EOF | 
|  | 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 | 
|  | 154 | exit 3 | 
|  | 155 | EOF | 
|  | 156 |  | 
|  | 157 | sudo tee "${mntdir}"/bin/postinst_fail1 >/dev/null <<EOF | 
|  | 158 | #!/etc/../bin/sh | 
|  | 159 | exit 1 | 
|  | 160 | EOF | 
|  | 161 |  | 
| Alex Deymo | d15c546 | 2016-03-09 18:11:12 -0800 | [diff] [blame] | 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 | 
|  | 165 | trap "{ 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. | 
|  | 168 | exec </dev/zero | 
|  | 169 | # Allow the signal handler to run every 100 ms. | 
|  | 170 | i=3000 | 
|  | 171 | while [ \$i -ge 0 ]; do | 
|  | 172 | sleep 0.1 | 
|  | 173 | i=\$((i-1)) | 
|  | 174 | done | 
|  | 175 | exit 1 | 
|  | 176 | EOF | 
|  | 177 |  | 
| Alex Deymo | 0d29854 | 2016-03-30 18:31:49 -0700 | [diff] [blame] | 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. | 
|  | 183 | echo global_progress 0.25 >&3 | 
|  | 184 | echo global_progress 0.5 >&3 | 
|  | 185 | echo global_progress 1.0 >&3 | 
|  | 186 | exit 0 | 
|  | 187 | EOF | 
|  | 188 |  | 
| Alex Light | 7361d27 | 2021-03-12 09:05:55 -0800 | [diff] [blame] | 189 | # An unlabeled postinstall bash program. | 
|  | 190 | sudo tee "${mntdir}"/bin/self_check_default_context >/dev/null <<EOF | 
|  | 191 | #!/etc/../bin/sh | 
|  | 192 | echo "This is my context:" | 
|  | 193 | ls -lZ "\$0" | 
|  | 194 | ls -lZ "\$0" | grep -F ' u:object_r:postinstall_file:s0 ' || exit 5 | 
|  | 195 | exit 0 | 
|  | 196 | EOF | 
|  | 197 |  | 
| Alex Deymo | cbc2274 | 2016-03-04 17:53:02 -0800 | [diff] [blame] | 198 | # A postinstall bash program. | 
|  | 199 | sudo tee "${mntdir}"/bin/self_check_context >/dev/null <<EOF | 
|  | 200 | #!/etc/../bin/sh | 
|  | 201 | echo "This is my context:" | 
| Alex Light | 7361d27 | 2021-03-12 09:05:55 -0800 | [diff] [blame] | 202 | ls -lZ "\$0" | 
|  | 203 | ls -lZ "\$0" | grep -F ' u:object_r:postinstall_exec:s0 ' || exit 5 | 
| Alex Deymo | cbc2274 | 2016-03-04 17:53:02 -0800 | [diff] [blame] | 204 | exit 0 | 
|  | 205 | EOF | 
|  | 206 |  | 
| Alex Light | 7361d27 | 2021-03-12 09:05:55 -0800 | [diff] [blame] | 207 | # Give the test function the context we expect the postinstall-executable to have. | 
|  | 208 | sudo setfattr -n security.selinux -v u:object_r:postinstall_exec:s0 "${mntdir}"/bin/self_check_context | 
|  | 209 |  | 
| Alex Deymo | cbc2274 | 2016-03-04 17:53:02 -0800 | [diff] [blame] | 210 | sudo tee "${mntdir}"/postinst >/dev/null <<EOF | 
|  | 211 | #!/etc/../bin/sh | 
|  | 212 | echo "postinst" | 
|  | 213 | exit 0 | 
|  | 214 | EOF | 
|  | 215 |  | 
|  | 216 | sudo chmod +x "${mntdir}"/postinst "${mntdir}"/bin/* | 
|  | 217 | } | 
|  | 218 |  | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 219 | # generate_fs <filename> <kind> <size> [block_size] [block_groups] | 
|  | 220 | generate_fs() { | 
|  | 221 | local filename="$1" | 
| Amin Hassani | d7da8f4 | 2017-08-23 14:29:40 -0700 | [diff] [blame] | 222 | local type="$2" | 
|  | 223 | local kind="$3" | 
|  | 224 | local size="$4" | 
|  | 225 | local block_size="${5:-4096}" | 
|  | 226 | local block_groups="${6:-}" | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 227 |  | 
|  | 228 | local mkfs_opts=( -q -F -b "${block_size}" -L "ROOT-TEST" -t ext2 ) | 
|  | 229 | if [[ -n "${block_groups}" ]]; then | 
|  | 230 | mkfs_opts+=( -G "${block_groups}" ) | 
|  | 231 | fi | 
|  | 232 |  | 
|  | 233 | local mntdir=$(mktemp --tmpdir -d generate_ext2.XXXXXX) | 
|  | 234 | trap 'cleanup "${mntdir}"; rm -f "${filename}"' INT TERM EXIT | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 235 | # Cleanup old image. | 
|  | 236 | if [[ -e "${filename}" ]]; then | 
|  | 237 | rm -f "${filename}" | 
|  | 238 | fi | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 239 |  | 
| Amin Hassani | d7da8f4 | 2017-08-23 14:29:40 -0700 | [diff] [blame] | 240 | if [[ "${type}" == "ext2" ]]; then | 
|  | 241 | truncate --size="${size}" "${filename}" | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 242 |  | 
| Amin Hassani | d7da8f4 | 2017-08-23 14:29:40 -0700 | [diff] [blame] | 243 | mkfs.ext2 "${mkfs_opts[@]}" "${filename}" | 
|  | 244 | sudo mount "${filename}" "${mntdir}" -o loop | 
|  | 245 | fi | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 246 | case "${kind}" in | 
| Alex Deymo | d15c546 | 2016-03-09 18:11:12 -0800 | [diff] [blame] | 247 | unittest) | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 248 | add_files_ue_settings "${mntdir}" "${block_size}" | 
| Alex Deymo | cbc2274 | 2016-03-04 17:53:02 -0800 | [diff] [blame] | 249 | add_files_postinstall "${mntdir}" "${block_size}" | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 250 | ;; | 
|  | 251 | default) | 
|  | 252 | add_files_default "${mntdir}" "${block_size}" | 
|  | 253 | ;; | 
| Alex Deymo | c90be63 | 2016-02-17 19:25:20 -0800 | [diff] [blame] | 254 | empty) | 
|  | 255 | ;; | 
| Alex Deymo | 2e9533b | 2015-06-26 20:57:06 -0700 | [diff] [blame] | 256 | esac | 
| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 257 |  | 
| Amin Hassani | d7da8f4 | 2017-08-23 14:29:40 -0700 | [diff] [blame] | 258 | if [[ "${type}" == "sqfs" ]]; then | 
|  | 259 | mksquashfs "${mntdir}" "${filename}" | 
|  | 260 | fi | 
|  | 261 |  | 
| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 262 | cleanup "${mntdir}" | 
|  | 263 | trap - INT TERM EXIT | 
|  | 264 | } | 
|  | 265 |  | 
| Alex Deymo | 04ef207 | 2015-08-13 08:19:16 -0700 | [diff] [blame] | 266 | OUTPUT_DIR=$(dirname "$0") | 
|  | 267 | IMAGES=() | 
| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 268 |  | 
| Alex Deymo | 04ef207 | 2015-08-13 08:19:16 -0700 | [diff] [blame] | 269 | # generate_image <image_name> [<image args> ...] | 
|  | 270 | generate_image() { | 
|  | 271 | echo "Generating image $1.img" | 
|  | 272 | IMAGES+=( "$1.img" ) | 
|  | 273 | generate_fs "${OUTPUT_DIR}/$1.img" "${@:2}" | 
|  | 274 | } | 
| Alex Deymo | 2b19cfb | 2015-03-26 00:35:07 -0700 | [diff] [blame] | 275 |  | 
| Alex Deymo | 04ef207 | 2015-08-13 08:19:16 -0700 | [diff] [blame] | 276 | main() { | 
|  | 277 | # Add more sample images here. | 
| Amin Hassani | d7da8f4 | 2017-08-23 14:29:40 -0700 | [diff] [blame] | 278 | generate_image disk_ext2_1k ext2 default $((1024 * 1024)) 1024 | 
|  | 279 | generate_image disk_ext2_4k ext2 default $((1024 * 4096)) 4096 | 
|  | 280 | generate_image disk_ext2_4k_empty ext2 empty $((1024 * 4096)) 4096 | 
|  | 281 | generate_image disk_ext2_unittest ext2 unittest $((1024 * 4096)) 4096 | 
|  | 282 |  | 
|  | 283 | # Add squashfs sample images. | 
|  | 284 | generate_image disk_sqfs_empty sqfs empty $((1024 * 4096)) 4096 | 
|  | 285 | generate_image disk_sqfs_default sqfs default $((1024 * 4096)) 4096 | 
| Amin Hassani | 77c25fc | 2019-01-29 10:24:19 -0800 | [diff] [blame] | 286 | generate_image disk_sqfs_unittest sqfs unittest $((1024 * 4096)) 4096 | 
| Alex Deymo | 04ef207 | 2015-08-13 08:19:16 -0700 | [diff] [blame] | 287 |  | 
|  | 288 | # Generate the tarball and delete temporary images. | 
|  | 289 | echo "Packing tar file sample_images.tar.bz2" | 
|  | 290 | tar -jcf "${OUTPUT_DIR}/sample_images.tar.bz2" -C "${OUTPUT_DIR}" \ | 
| Alex Deymo | a3553e4 | 2016-03-04 18:55:05 -0800 | [diff] [blame] | 291 | --sparse "${IMAGES[@]}" | 
| Alex Deymo | 04ef207 | 2015-08-13 08:19:16 -0700 | [diff] [blame] | 292 | cd "${OUTPUT_DIR}" | 
|  | 293 | rm "${IMAGES[@]}" | 
|  | 294 | } | 
|  | 295 |  | 
|  | 296 | main |