| #!/usr/bin/env bash |
| |
| # Copyright 2017 The Fuchsia Authors |
| # |
| # Use of this source code is governed by a MIT-style |
| # license that can be found in the LICENSE file or at |
| # https://opensource.org/licenses/MIT |
| |
| set -eo pipefail |
| |
| # Where the dash sources are expected to be. |
| DASH_SRC_DIR="/tmp/dash" |
| |
| usage() { |
| echo "usage: ${0} [options] {arm64, x64}" |
| echo |
| echo " -d Directory to clone toybox into." |
| echo " -o Disk image output path." |
| echo " -s Directory to clone dash into." |
| echo " -u Update before building." |
| echo |
| exit 1 |
| } |
| |
| # Ensures the toybox sources are downloaded. |
| # |
| # $1 - Directory to unpack the sources into. |
| get_toybox_source() { |
| local toybox_src=$1 |
| |
| if [ ! -d "$toybox_src" ]; then |
| git clone --depth 1 https://zircon-guest.googlesource.com/third_party/toybox "$toybox_src" |
| elif [[ "${UPDATE}" = "true" ]]; then |
| pushd "$toybox_src" |
| git pull --depth 1 |
| popd |
| fi |
| } |
| |
| # Build toybox and create a sysroot. |
| # |
| # $1 - Toybox source directory. |
| # $2 - Directory to build the toybox sysroot with the toybox binary and symlinks. |
| build_toybox() { |
| local toybox_src=$1 |
| local sysroot_dir="$2" |
| |
| make -C "$toybox_src" defconfig |
| CROSS_COMPILE="${AC_HOST}-" CC="gcc" LDFLAGS="--static" make -C "$toybox_src" -j100 |
| |
| mkdir -p "$sysroot_dir"/{bin,sbin,etc,proc,sys,usr/{bin,sbin},dev,tmp} |
| PREFIX=$sysroot_dir make -C "$toybox_src" install |
| } |
| |
| # Ensures the dash sources are downloaded. |
| # |
| # $1 - Directory to unpack the sources into. |
| get_dash_source() { |
| local dash_src=$1 |
| |
| if [ ! -d "$dash_src" ]; then |
| git clone --depth 1 https://zircon-guest.googlesource.com/third_party/dash "$dash_src" |
| elif [[ "${UPDATE}" = "true" ]]; then |
| pushd "$dash_src" |
| git pull --depth 1 |
| popd |
| fi |
| } |
| |
| # Build dash, copy it to sysroot and make it sh. |
| # |
| # $1 - Dash source directory. |
| # $2 - Directory of toybox sysroot. |
| build_dash() { |
| local dash_src=$1 |
| local sysroot_dir="$2" |
| |
| pushd $dash_src |
| ./autogen.sh |
| ./configure LDFLAGS="-static" --host="${AC_HOST}" --build=x86_64-linux-gnu |
| make -j100 |
| popd |
| |
| mkdir -p "$sysroot_dir/bin" |
| cp "$dash_src/src/dash" "$sysroot_dir/bin/sh" |
| } |
| |
| # Generate a simple init script at /init in the target sysroot. |
| # |
| # $1 - Toybox sysroot directory. |
| generate_init() { |
| local sysroot_dir="$1" |
| |
| mkdir -p "${sysroot_dir}/etc" |
| mkdir -p "${sysroot_dir}/test_utils" |
| |
| # Write an init script for toybox. |
| cat > "${sysroot_dir}/etc/init" <<'_EOF' |
| #!/bin/sh |
| mount -t proc proc /proc |
| mount -t sysfs sysfs /sys |
| mount -t ext2 /dev/vdb /test_utils |
| echo Launched init |
| exec /bin/sh |
| _EOF |
| |
| chmod +x "${sysroot_dir}/etc/init" |
| } |
| |
| # e2tools provides utilities for manipulating EXT2 filesystems. |
| check_e2tools() { |
| type -P e2cp &>/dev/null && return 0 |
| |
| echo "Required package e2tools is not installed. (sudo apt install e2tools)" |
| exit 1 |
| } |
| |
| # Generate an EXT2 filesystem image of the toybox sysroot. |
| # |
| # $1 - Toybox sysroot directory. |
| # $2 - Filepath of the created EXT2 image file. |
| package_rootfs() { |
| local sysroot="$1" |
| local rootfs="$2" |
| |
| dd if=/dev/zero of=$rootfs bs=1M count=20 |
| mkfs.ext2 -F $rootfs |
| |
| for dir in `find "${sysroot}" -type d -printf '%P\n'`; do |
| e2mkdir "${rootfs}:/${dir}" |
| done |
| |
| for file in `find "${sysroot}" -type f -printf '%P\n'`; do |
| e2cp -p -G 0 -O 0 "${sysroot}/${file}" "${rootfs}:/${file}" |
| done |
| |
| # e2cp follows symlinks which would create a copy of the toybox binary for |
| # every link. To work around this we enumerate all the symlinks in the |
| # sysroot and create a corresponding hardlink in the ext2 filesystem (e2ln |
| # does not currently support soft links). |
| for link in `find "${sysroot}" -type l -printf '%P\n'`; do |
| local dirname=`dirname ${link}` |
| local target=`readlink "${sysroot}/${link}"` |
| e2ln "${rootfs}:${dirname}/${target}" "/${link}" |
| done |
| } |
| |
| declare UPDATE="${UPDATE:-false}" |
| |
| while getopts "d:o:s:u" opt; do |
| case "${opt}" in |
| d) TOYBOX_SRC_DIR="${OPTARG}" ;; |
| o) DISK_OUT="${OPTARG}" ;; |
| s) DASH_SRC_DIR="${OPTARG}" ;; |
| u) UPDATE="true" ;; |
| *) usage ;; |
| esac |
| done |
| shift $((OPTIND - 1)) |
| |
| case "${1}" in |
| arm64) |
| ARCH=${1} |
| type aarch64-linux-gnu-gcc || |
| { echo "Required package gcc-aarch64-linux-gnu is not installed." |
| echo "(sudo apt install gcc-aarch64-linux-gnu)"; exit 1; }; |
| AC_HOST="aarch64-linux-gnu";; |
| x64) |
| ARCH=${1} |
| AC_HOST="x86_64-linux-gnu";; |
| *) |
| usage;; |
| esac |
| |
| # Where the toybox sources are expected to be. |
| TOYBOX_SRC_DIR="${TOYBOX_SRC_DIR:-/tmp/toybox-${ARCH}}" |
| |
| # Toybox root filesystem image. |
| TOYBOX_ROOTFS="${TOYBOX_SRC_DIR}/rootfs.ext2" |
| |
| # Where to prep the toybox directory structure. |
| TOYBOX_SYSROOT="${TOYBOX_SRC_DIR}/fs" |
| |
| check_e2tools |
| |
| get_toybox_source "${TOYBOX_SRC_DIR}" |
| |
| build_toybox "${TOYBOX_SRC_DIR}" "${TOYBOX_SYSROOT}" |
| |
| get_dash_source "${DASH_SRC_DIR}" |
| |
| build_dash "${DASH_SRC_DIR}" "${TOYBOX_SYSROOT}" |
| |
| generate_init "${TOYBOX_SYSROOT}" |
| |
| package_rootfs "${TOYBOX_SYSROOT}" "${TOYBOX_ROOTFS}" |
| |
| if [ -n "${DISK_OUT}" ]; then |
| mv "${TOYBOX_ROOTFS}" "${DISK_OUT}" |
| echo "filesystem image at ${DISK_OUT}" |
| else |
| echo "filesystem image at ${TOYBOX_ROOTFS}" |
| fi |