1#!/bin/bash 2 3# Builds mysteriously fail if stdout is non-blocking. 4fixup_ptys() { 5 python3 << 'EOF' 6import fcntl, os, sys 7fd = sys.stdout.fileno() 8flags = fcntl.fcntl(fd, fcntl.F_GETFL) 9flags &= ~(fcntl.FASYNC | os.O_NONBLOCK | os.O_APPEND) 10fcntl.fcntl(fd, fcntl.F_SETFL, flags) 11EOF 12} 13 14# Common kernel options 15OPTIONS=" ANDROID GKI_NET_XFRM_HACKS" 16OPTIONS="$OPTIONS DEBUG_SPINLOCK DEBUG_ATOMIC_SLEEP DEBUG_MUTEXES DEBUG_RT_MUTEXES" 17OPTIONS="$OPTIONS WARN_ALL_UNSEEDED_RANDOM IKCONFIG IKCONFIG_PROC" 18OPTIONS="$OPTIONS DEVTMPFS DEVTMPFS_MOUNT FHANDLE" 19OPTIONS="$OPTIONS IPV6 IPV6_ROUTER_PREF IPV6_MULTIPLE_TABLES IPV6_ROUTE_INFO" 20OPTIONS="$OPTIONS TUN SYN_COOKIES IP_ADVANCED_ROUTER IP_MULTIPLE_TABLES" 21OPTIONS="$OPTIONS NETFILTER NETFILTER_ADVANCED NETFILTER_XTABLES" 22OPTIONS="$OPTIONS NETFILTER_XT_MARK NETFILTER_XT_TARGET_MARK" 23OPTIONS="$OPTIONS IP_NF_IPTABLES IP_NF_MANGLE IP_NF_FILTER" 24OPTIONS="$OPTIONS IP6_NF_IPTABLES IP6_NF_MANGLE IP6_NF_FILTER INET6_IPCOMP" 25OPTIONS="$OPTIONS IPV6_OPTIMISTIC_DAD" 26OPTIONS="$OPTIONS IPV6_ROUTE_INFO IPV6_ROUTER_PREF" 27OPTIONS="$OPTIONS NETFILTER_XT_TARGET_IDLETIMER" 28OPTIONS="$OPTIONS NETFILTER_XT_TARGET_NFLOG" 29OPTIONS="$OPTIONS NETFILTER_XT_MATCH_POLICY" 30OPTIONS="$OPTIONS NETFILTER_XT_MATCH_QUOTA" 31OPTIONS="$OPTIONS NETFILTER_XT_MATCH_QUOTA2" 32OPTIONS="$OPTIONS NETFILTER_XT_MATCH_QUOTA2_LOG" 33OPTIONS="$OPTIONS NETFILTER_XT_MATCH_SOCKET" 34OPTIONS="$OPTIONS NETFILTER_XT_MATCH_QTAGUID" 35OPTIONS="$OPTIONS INET_DIAG INET_UDP_DIAG INET_DIAG_DESTROY" 36OPTIONS="$OPTIONS IP_SCTP" 37OPTIONS="$OPTIONS IP_NF_TARGET_REJECT IP_NF_TARGET_REJECT_SKERR" 38OPTIONS="$OPTIONS IP6_NF_TARGET_REJECT IP6_NF_TARGET_REJECT_SKERR" 39OPTIONS="$OPTIONS NET_KEY XFRM_USER XFRM_STATISTICS CRYPTO_CBC" 40OPTIONS="$OPTIONS CRYPTO_CTR CRYPTO_HMAC CRYPTO_AES CRYPTO_SHA1" 41OPTIONS="$OPTIONS CRYPTO_XCBC CRYPTO_CHACHA20POLY1305" 42OPTIONS="$OPTIONS CRYPTO_USER INET_ESP INET_XFRM_MODE_TRANSPORT" 43OPTIONS="$OPTIONS INET_XFRM_MODE_TUNNEL INET6_ESP" 44OPTIONS="$OPTIONS INET6_XFRM_MODE_TRANSPORT INET6_XFRM_MODE_TUNNEL" 45OPTIONS="$OPTIONS CRYPTO_SHA256 CRYPTO_SHA512 CRYPTO_AES_X86_64 CRYPTO_NULL" 46OPTIONS="$OPTIONS CRYPTO_GCM CRYPTO_ECHAINIV NET_IPVTI" 47OPTIONS="$OPTIONS DUMMY" 48 49# Kernel version specific options 50OPTIONS="$OPTIONS XFRM_INTERFACE" # Various device kernels 51OPTIONS="$OPTIONS XFRM_MIGRATE" # Added in 5.10 52OPTIONS="$OPTIONS CGROUP_BPF" # Added in android-4.9 53OPTIONS="$OPTIONS NF_SOCKET_IPV4 NF_SOCKET_IPV6" # Added in 4.9 54OPTIONS="$OPTIONS INET_SCTP_DIAG" # Added in 4.7 55OPTIONS="$OPTIONS SOCK_CGROUP_DATA" # Added in 4.5 56OPTIONS="$OPTIONS CRYPTO_ECHAINIV" # Added in 4.1 57OPTIONS="$OPTIONS BPF_SYSCALL" # Added in 3.18 58OPTIONS="$OPTIONS IPV6_VTI" # Added in 3.13 59OPTIONS="$OPTIONS IPV6_PRIVACY" # Removed in 3.12 60OPTIONS="$OPTIONS NETFILTER_TPROXY" # Removed in 3.11 61 62# UML specific options 63OPTIONS="$OPTIONS BLK_DEV_UBD HOSTFS" 64 65# QEMU specific options 66OPTIONS="$OPTIONS PCI VIRTIO VIRTIO_PCI VIRTIO_BLK NET_9P NET_9P_VIRTIO 9P_FS" 67OPTIONS="$OPTIONS CRYPTO_DEV_VIRTIO SERIAL_8250 SERIAL_8250_PCI" 68OPTIONS="$OPTIONS SERIAL_8250_CONSOLE PCI_HOST_GENERIC SERIAL_AMBA_PL011" 69OPTIONS="$OPTIONS SERIAL_AMBA_PL011_CONSOLE" 70 71# Obsolete options present at some time in Android kernels 72OPTIONS="$OPTIONS IP_NF_TARGET_REJECT_SKERR IP6_NF_TARGET_REJECT_SKERR" 73 74# b/262323440 - UML *sometimes* seems to have issues with: 75# UPSTREAM: hardening: Clarify Kconfig text for auto-var-init 76# which is in 4.14.~299/4.19.~266 LTS and which does: 77# prompt "Initialize kernel stack variables at function entry" 78# default GCC_PLUGIN_STRUCTLEAK_BYREF_ALL if COMPILE_TEST && GCC_PLUGINS 79# default INIT_STACK_ALL_PATTERN if COMPILE_TEST && CC_HAS_AUTO_VAR_INIT_PATTERN 80# + default INIT_STACK_ALL_ZERO if CC_HAS_AUTO_VAR_INIT_PATTERN 81# default INIT_STACK_NONE 82# and thus presumably switches from INIT_STACK_NONE to INIT_STACK_ALL_ZERO 83# 84# My guess it that this is triggering some sort of UML and/or compiler bug... 85# Let's just turn it off... we don't care that much. 86OPTIONS="$OPTIONS INIT_STACK_NONE" 87 88# These two break the flo kernel due to differences in -Werror on recent GCC. 89DISABLE_OPTIONS=" REISERFS_FS ANDROID_PMEM" 90 91# How many TAP interfaces to create to provide the VM with real network access 92# via the host. This requires privileges (e.g., root access) on the host. 93# 94# This is not needed to run the tests, but can be used, for example, to allow 95# the VM to update system packages, or to write tests that need access to a 96# real network. The VM does not set up networking by default, but it contains a 97# DHCP client and has the ability to use IPv6 autoconfiguration. This script 98# does not perform any host-level setup beyond configuring tap interfaces; 99# configuring IPv4 NAT and/or IPv6 router advertisements or ND proxying must 100# be done separately. 101NUMTAPINTERFACES=0 102 103# The root filesystem disk image we'll use. 104ROOTFS=${ROOTFS:-net_test.rootfs.20221014} 105COMPRESSED_ROOTFS=$ROOTFS.xz 106URL=https://dl.google.com/dl/android/$COMPRESSED_ROOTFS 107 108# Parse arguments and figure out which test to run. 109ARCH=${ARCH:-um} 110J=${J:-$(nproc)} 111MAKE="make" 112OUT_DIR=$(readlink -f ${OUT_DIR:-.}) 113KERNEL_DIR=$(readlink -f ${KERNEL_DIR:-.}) 114if [ "$OUT_DIR" != "$KERNEL_DIR" ]; then 115 MAKE="$MAKE O=$OUT_DIR" 116fi 117SCRIPT_DIR=$(dirname $(readlink -f $0)) 118CONFIG_SCRIPT=${KERNEL_DIR}/scripts/config 119CONFIG_FILE=${OUT_DIR}/.config 120consolemode= 121netconfig= 122testmode= 123cmdline= 124nowrite=1 125nobuild=0 126norun=0 127 128if [[ ! -f "${KERNEL_DIR}/Makefile" ]]; then 129 echo "No kernel Makefile found. Are you running this from a kernel directory?" 130 exit 1 131fi 132 133KVER_MAJOR="$(sed -rn 's@^ *VERSION *= *([0-9]+)$@\1@p' < "${KERNEL_DIR}/Makefile")" 134KVER_MINOR="$(sed -rn 's@^ *PATCHLEVEL *= *([0-9]+)$@\1@p' < "${KERNEL_DIR}/Makefile")" 135KVER_LEVEL="$(sed -rn 's@^ *SUBLEVEL *= *([0-9]+)$@\1@p' < "${KERNEL_DIR}/Makefile")" 136KVER="${KVER_MAJOR}.${KVER_MINOR}.${KVER_LEVEL}" 137echo "Detected kernel version ${KVER}" 138 139if [[ -z "${DEFCONFIG:-}" ]]; then 140 case "${ARCH}" in 141 um) 142 export DEFCONFIG=defconfig 143 ;; 144 arm64) 145 if [[ -e arch/arm64/configs/gki_defconfig ]]; then 146 export DEFCONFIG=gki_defconfig 147 elif [[ -e arch/arm64/configs/cuttlefish_defconfig ]]; then 148 export DEFCONFIG=cuttlefish_defconfig 149 fi 150 ;; 151 x86_64) 152 if [[ -e arch/x86/configs/gki_defconfig ]]; then 153 export DEFCONFIG=gki_defconfig 154 elif [[ -e arch/x86/configs/x86_64_cuttlefish_defconfig ]]; then 155 export DEFCONFIG=x86_64_cuttlefish_defconfig 156 fi 157 esac 158fi 159 160if tty >/dev/null; then 161 verbose= 162else 163 verbose=1 164fi 165 166test=all_tests.sh 167while [[ -n "$1" ]]; do 168 if [[ "$1" == "--builder" || "$1" == "-b" ]]; then 169 consolemode="con=null,fd:1" 170 testmode=builder 171 shift 172 elif [[ "$1" == "--readwrite" || "$1" == "--rw" ]]; then 173 nowrite=0 174 shift 175 elif [[ "$1" == "--readonly" || "$1" == "--ro" ]]; then 176 nowrite=1 177 shift 178 elif [[ "$1" == "--nobuild" ]]; then 179 nobuild=1 180 shift 181 elif [[ "$1" == "--build" ]]; then 182 nobuild=0 183 shift 184 elif [[ "$1" == "--norun" ]]; then 185 norun=1 186 shift 187 elif [[ "$1" == "--run" ]]; then 188 norun=0 189 shift 190 elif [[ "$1" == "--verbose" ]]; then 191 verbose=1 192 shift 193 elif [[ "$1" == "--noverbose" ]]; then 194 verbose= 195 shift 196 else 197 test=$1 198 break # Arguments after the test file are passed to the test itself. 199 fi 200done 201 202# Check that test file exists and is readable 203test_file=$SCRIPT_DIR/$test 204if [[ ! -e $test_file ]]; then 205 echo "test file '${test_file}' does not exist" 206 exit 1 207fi 208 209if [[ ! -x $test_file ]]; then 210 echo "test file '${test_file}' is not executable" 211 exit 1 212fi 213 214# Collect trailing arguments to pass to $test 215test_args=${@:2} 216 217function isRunningTest() { 218 ! (( norun )) 219} 220 221function isBuildOnly() { 222 (( norun )) && ! (( nobuild )) 223} 224 225if ! isRunningTest && ! isBuildOnly; then 226 echo "Usage:" >&2 227 echo " $0 [--builder] [--readonly|--ro|--readwrite|--rw] [--nobuild] [--verbose] [<test>]" >&2 228 echo " - if [<test>] is not specified, run all_tests.sh" >&2 229 echo " $0 --norun" >&2 230 exit 1 231fi 232 233cd $OUT_DIR 234echo Running tests from: `pwd` 235 236set -e 237 238# Check if we need to uncompress the disk image. 239# We use xz because it compresses better: to 42M vs 72M (gzip) / 62M (bzip2). 240cd $SCRIPT_DIR 241if [ ! -f $ROOTFS ]; then 242 echo "Deleting $COMPRESSED_ROOTFS" >&2 243 rm -f $COMPRESSED_ROOTFS 244 echo "Downloading $URL" >&2 245 wget -nv $URL 246 echo "Uncompressing $COMPRESSED_ROOTFS" >&2 247 unxz $COMPRESSED_ROOTFS 248fi 249if ! [[ "${ROOTFS}" =~ ^/ ]]; then 250 ROOTFS="${SCRIPT_DIR}/${ROOTFS}" 251fi 252echo "Using $ROOTFS" 253cd - 254 255# If network access was requested, create NUMTAPINTERFACES tap interfaces on 256# the host, and prepare UML command line params to use them. The interfaces are 257# called <user>TAP0, <user>TAP1, on the host, and eth0, eth1, ..., in the VM. 258if (( $NUMTAPINTERFACES > 0 )); then 259 user=${USER:0:10} 260 tapinterfaces= 261 for id in $(seq 0 $(( NUMTAPINTERFACES - 1 )) ); do 262 tap=${user}TAP$id 263 tapinterfaces="$tapinterfaces $tap" 264 mac=$(printf fe:fd:00:00:00:%02x $id) 265 if [ "$ARCH" == "um" ]; then 266 netconfig="$netconfig eth$id=tuntap,$tap,$mac" 267 else 268 netconfig="$netconfig -netdev tap,id=hostnet$id,ifname=$tap,script=no,downscript=no" 269 netconfig="$netconfig -device virtio-net-pci,netdev=hostnet$id,id=net$id,mac=$mac" 270 fi 271 done 272 273 for tap in $tapinterfaces; do 274 if ! ip link list $tap > /dev/null; then 275 echo "Creating tap interface $tap" >&2 276 sudo tunctl -u $USER -t $tap 277 sudo ip link set $tap up 278 fi 279 done 280fi 281 282if [[ -n "${KERNEL_BINARY:-}" ]]; then 283 nobuild=1 284else 285 # Set default KERNEL_BINARY location if it was not provided. 286 if [ "$ARCH" == "um" ]; then 287 KERNEL_BINARY=./linux 288 elif [ "$ARCH" == "i386" -o "$ARCH" == "x86_64" -o "$ARCH" == "x86" ]; then 289 KERNEL_BINARY=./arch/x86/boot/bzImage 290 elif [ "$ARCH" == "arm64" ]; then 291 KERNEL_BINARY=./arch/arm64/boot/Image.gz 292 fi 293fi 294 295if ((nobuild == 0)); then 296 make_flags= 297 if [ "$ARCH" == "um" ]; then 298 # Exporting ARCH=um SUBARCH=x86_64 doesn't seem to work, as it 299 # "sometimes" (?) results in a 32-bit kernel. 300 make_flags="$make_flags ARCH=$ARCH SUBARCH=${SUBARCH:-x86_64} CROSS_COMPILE= " 301 fi 302 if [[ -n "${CC:-}" ]]; then 303 # The CC flag is *not* inherited from the environment, so it must be 304 # passed in on the command line. 305 make_flags="$make_flags CC=$CC" 306 fi 307 308 # If there's no kernel config at all, create one or UML won't work. 309 [ -f $CONFIG_FILE ] || (cd $KERNEL_DIR && $MAKE $make_flags $DEFCONFIG) 310 311 # Enable the kernel config options listed in $OPTIONS. 312 $CONFIG_SCRIPT --file $CONFIG_FILE ${OPTIONS// / -e } 313 314 # Increase acceptable frame size. 315 $CONFIG_SCRIPT --file $CONFIG_FILE --set-val FRAME_WARN 3172 316 317 # Disable the kernel config options listed in $DISABLE_OPTIONS. 318 $CONFIG_SCRIPT --file $CONFIG_FILE ${DISABLE_OPTIONS// / -d } 319 320 echo "Running: $MAKE $make_flags olddefconfig" 321 $MAKE $make_flags olddefconfig 322 323 # Compile the kernel. 324 if [ "$ARCH" == "um" ]; then 325 echo "Running: $MAKE -j$J $make_flags linux" 326 $MAKE -j$J $make_flags linux 327 else 328 echo "Running: $MAKE -j$J $make_flags" 329 $MAKE -j$J $make_flags 330 fi 331fi 332 333if (( norun == 1 )); then 334 exit 0 335fi 336 337if (( nowrite == 1 )); then 338 cmdline="ro" 339fi 340 341if (( verbose == 1 )); then 342 cmdline="$cmdline verbose=1" 343fi 344 345cmdline="$cmdline panic=1 init=/sbin/net_test.sh" 346cmdline="$cmdline net_test_args=\"$test_args\" net_test_mode=$testmode" 347 348# Experience shows that we need at least 128 bits of entropy for the 349# kernel's crng init to complete (before it fully initializes stuff behaves 350# *weirdly* and there's plenty of kernel warnings and some tests even fail), 351# hence net_test.sh needs at least 32 hex chars (which is the amount of hex 352# in a single random UUID) provided to it on the kernel cmdline. 353# 354# Just to be safe, we'll pass in 384 bits, and we'll do this as a random 355# 64 character base64 seed (because this is shorter than base16). 356# We do this by getting *three* random UUIDs and concatenating their hex 357# digits into an *even* length hex encoded string, which we then convert 358# into base64. 359entropy="$(cat /proc/sys/kernel/random{/,/,/}uuid | tr -d '\n-')" 360entropy="$(xxd -r -p <<< "${entropy}" | base64 -w 0)" 361cmdline="${cmdline} random.trust_cpu=on entropy=${entropy}" 362 363if [ "$ARCH" == "um" ]; then 364 # Get the absolute path to the test file that's being run. 365 cmdline="$cmdline net_test=/host$SCRIPT_DIR/$test" 366 367 # We'd use UML's /proc/exitcode feature to communicate errors on test failure, 368 # if not for UML having a tendency to crash during shutdown, 369 # so instead use an extra serial line we'll redirect to an open fd... 370 cmdline="$cmdline exitcode=/dev/ttyS3" 371 372 # Map the --readonly flag to UML block device names 373 if ((nowrite == 0)); then 374 blockdevice=ubda 375 else 376 blockdevice=ubdar 377 fi 378 379 # Create a temp file for 'serial line 3' for return code. 380 SSL3="$(mktemp)" 381 382 exitcode=0 383 $KERNEL_BINARY >&2 3>"${SSL3}" umid=net_test mem=512M \ 384 $blockdevice=$ROOTFS $netconfig $consolemode ssl3=null,fd:3 $cmdline \ 385 || exitcode=$? 386 387 # Return to beginning of line (via carriage return) after the above newline moved us down. 388 echo -en '\r' 389 # re-enable: 'postprocess output' and 'translate newline to carriage return-newline' 390 stty opost onlcr || : 391 392 if [[ "${exitcode}" == 134 && -s "${SSL3}" && "$(tr -d '\r' < "${SSL3}")" == 0 ]]; then 393 # Sometimes the tests all pass, but UML crashes during the shutdown process itself. 394 # As such we can't actually rely on the /proc/exitcode returned value. 395 echo "Warning: UML appears to have crashed after successfully executing the tests." 1>&2 396 elif [[ "${exitcode}" != 0 ]]; then 397 echo "Warning: UML exited with ${exitcode} instead of zero." 1>&2 398 fi 399 400 if [[ -s "${SSL3}" ]]; then 401 exitcode="$(tr -d '\r' < "${SSL3}")" 402 echo "Info: retrieved exit code ${exitcode}." 1>&2 403 fi 404 405 rm -f "${SSL3}" 406 unset SSL3 407 408 # UML is kind of crazy in how guest syscalls work. It requires host kernel 409 # to not be in vsyscall=none mode. 410 if [[ "${exitcode}" != '0' ]]; then 411 { 412 # Hopefully one of these exists 413 cat /proc/config || : 414 zcat /proc/config.gz || : 415 cat "/boot/config-$(uname -r)" || : 416 zcat "/boot/config-$(uname -r).gz" || : 417 } 2>/dev/null \ 418 | egrep -q '^CONFIG_LEGACY_VSYSCALL_NONE=y' \ 419 && ! egrep -q '(^| )vsyscall=(native|emulate|xonly)( |$)' /proc/cmdline \ 420 && { 421 echo -e "\r" 422 echo -e "-----=====-----\r" 423 echo -e "If above you saw a 'net_test.sh[1]: segfault at ...' followed by\r" 424 echo -e "'Kernel panic - not syncing: Attempted to kill init!' then please\r" 425 echo -e "set 'vsyscall=emulate' on *host* kernel command line.\r" 426 echo -e "On Linux 5.2+ you can instead use the slightly safer 'vsyscall=xonly'.\r" 427 echo -e "(for example via GRUB_CMDLINE_LINUX in /etc/default/grub)\r" 428 echo -e "-----=====-----\r" 429 } 430 fi 431else 432 # We boot into the filesystem image directly in all cases 433 cmdline="$cmdline root=/dev/vda" 434 435 # The path is stripped by the 9p export; we don't need SCRIPT_DIR 436 cmdline="$cmdline net_test=/host/$test" 437 438 # Map the --readonly flag to a QEMU block device flag 439 if ((nowrite > 0)); then 440 blockdevice=",readonly=on" 441 else 442 blockdevice= 443 fi 444 blockdevice="-drive file=$ROOTFS,format=raw,if=none,id=drive-virtio-disk0$blockdevice" 445 blockdevice="$blockdevice -device virtio-blk-pci,drive=drive-virtio-disk0" 446 447 # Pass through our current console/screen size to inner shell session 448 read rows cols < <(stty size 2>/dev/null) 449 [[ -z "${rows}" ]] || cmdline="${cmdline} console_rows=${rows}" 450 [[ -z "${cols}" ]] || cmdline="${cmdline} console_cols=${cols}" 451 unset rows cols 452 453 # QEMU has no way to modify its exitcode; simulate it with a serial port. 454 # 455 # Choose to do it this way over writing a file to /host, because QEMU will 456 # initialize the 'exitcode' file for us, it avoids unnecessary writes to the 457 # host filesystem (which is normally not written to) and it allows us to 458 # communicate an exit code back in cases we do not have /host mounted. 459 # 460 if [ "$ARCH" == "i386" -o "$ARCH" == "x86_64" -o "$ARCH" == "x86" ]; then 461 # Assume we have hardware-accelerated virtualization support for amd64 462 qemu="qemu-system-x86_64 -machine pc,accel=kvm -cpu host" 463 464 # We know 'ttyS0' will be our serial port on x86 from the hard-coded 465 # '-serial mon:stdio' flag below 466 cmdline="$cmdline console=ttyS0" 467 468 # The assignment of 'ttyS1' here is magical; we know ttyS0 was used up 469 # by '-serial mon:stdio', and so this second serial port will be 'ttyS1' 470 cmdline="$cmdline exitcode=/dev/ttyS1" 471 elif [ "$ARCH" == "arm64" ]; then 472 # This uses a software model CPU, based on cortex-a57 473 qemu="qemu-system-aarch64 -machine virt -cpu cortex-a57" 474 475 # We know 'ttyAMA0' will be our serial port on arm64 from the hard-coded 476 # '-serial mon:stdio' flag below 477 cmdline="$cmdline console=ttyAMA0" 478 479 # The kernel will print messages via a virtual ARM serial port (ttyAMA0), 480 # but for command line consistency with x86, we put the exitcode serial 481 # port on the PCI bus, and it will be the only one. 482 cmdline="$cmdline exitcode=/dev/ttyS0" 483 fi 484 485 $qemu >&2 -name net_test -m 512 \ 486 -kernel $KERNEL_BINARY \ 487 -no-user-config -nodefaults -no-reboot \ 488 -display none -nographic -serial mon:stdio -parallel none \ 489 -smp 4,sockets=4,cores=1,threads=1 \ 490 -device virtio-rng-pci \ 491 -chardev file,id=exitcode,path=exitcode \ 492 -device pci-serial,chardev=exitcode \ 493 -fsdev local,security_model=mapped-xattr,id=fsdev0,fmode=0644,dmode=0755,path=$SCRIPT_DIR \ 494 -device virtio-9p-pci,id=fs0,fsdev=fsdev0,mount_tag=host \ 495 $blockdevice $netconfig -append "$cmdline" 496 [[ -s exitcode ]] && exitcode=`cat exitcode | tr -d '\r'` || exitcode=1 497 rm -f exitcode 498fi 499 500# UML reliably screws up the ptys, QEMU probably can as well... 501fixup_ptys 502stty sane || : 503tput smam || : 504 505echo "Returning exit code ${exitcode}." 1>&2 506exit "${exitcode}" 507