diff options
-rwxr-xr-x | scripts/genapkovl-dhcp.sh | 66 | ||||
-rwxr-xr-x | scripts/genapkovl-xen.sh | 75 | ||||
-rw-r--r-- | scripts/mkimage.sh | 226 | ||||
-rw-r--r-- | scripts/mkimg.arm.sh | 86 | ||||
-rw-r--r-- | scripts/mkimg.base.sh | 151 | ||||
-rw-r--r-- | scripts/mkimg.standard.sh | 53 | ||||
-rw-r--r-- | scripts/mkimg.xen.sh | 17 |
7 files changed, 674 insertions, 0 deletions
diff --git a/scripts/genapkovl-dhcp.sh b/scripts/genapkovl-dhcp.sh new file mode 100755 index 0000000000..83ed3dd9aa --- /dev/null +++ b/scripts/genapkovl-dhcp.sh @@ -0,0 +1,66 @@ +#!/bin/sh -e + +HOSTNAME="$1" +if [ -z "$HOSTNAME" ]; then + echo "usage: $0 hostname" + exit 1 +fi + +cleanup() { + rm -rf "$tmp" +} + +makefile() { + OWNER="$1" + PERMS="$2" + FILENAME="$3" + cat > "$FILENAME" + chown "$OWNER" "$FILENAME" + chmod "$PERMS" "$FILENAME" +} + +rc_add() { + mkdir -p "$tmp"/etc/runlevels/"$2" + ln -sf /etc/init.d/"$1" "$tmp"/etc/runlevels/"$2"/"$1" +} + +tmp="$(mktemp -d)" +trap cleanup EXIT + +mkdir -p "$tmp"/etc +makefile root:root 0644 "$tmp"/etc/hostname <<EOF +$HOSTNAME +EOF + +mkdir -p "$tmp"/etc/network +makefile root:root 0644 "$tmp"/etc/network/interfaces <<EOF +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet dhcp +EOF + +mkdir -p "$tmp"/etc/apk +makefile root:root 0644 "$tmp"/etc/apk/world <<EOF +alpine-base +EOF + +rc_add devfs sysinit +rc_add dmesg sysinit +rc_add mdev sysinit +rc_add hwdrivers sysinit +rc_add modloop sysinit + +rc_add hwclock boot +rc_add modules boot +rc_add sysctl boot +rc_add hostname boot +rc_add bootmisc boot +rc_add syslog boot + +rc_add mount-ro shutdown +rc_add killprocs shutdown +rc_add savecache shutdown + +tar -c -C "$tmp" etc | gzip -9n > $HOSTNAME.apkovl.tar.gz diff --git a/scripts/genapkovl-xen.sh b/scripts/genapkovl-xen.sh new file mode 100755 index 0000000000..3b65e41ca8 --- /dev/null +++ b/scripts/genapkovl-xen.sh @@ -0,0 +1,75 @@ +#!/bin/sh -e + +HOSTNAME="$1" +if [ -z "$HOSTNAME" ]; then + echo "usage: $0 hostname" + exit 1 +fi + +cleanup() { + rm -rf "$tmp" +} + +makefile() { + OWNER="$1" + PERMS="$2" + FILENAME="$3" + cat > "$FILENAME" + chown "$OWNER" "$FILENAME" + chmod "$PERMS" "$FILENAME" +} + +rc_add() { + mkdir -p "$tmp"/etc/runlevels/"$2" + ln -sf /etc/init.d/"$1" "$tmp"/etc/runlevels/"$2"/"$1" +} + +tmp="$(mktemp -d)" +trap cleanup EXIT + +mkdir -p "$tmp"/etc +makefile root:root 0644 "$tmp"/etc/hostname <<EOF +$HOSTNAME +EOF + +makefile root:root 0644 "$tmp"/etc/modules <<EOF +xen_netback +xen_blkback +xenfs +xen-platform-pci +xen_wdt +tun +EOF + +mkdir -p "$tmp"/etc/network +makefile root:root 0644 "$tmp"/etc/network/interfaces <<EOF +auto lo +iface lo inet loopback +EOF + +mkdir -p "$tmp"/etc/apk + +makefile root:root 0644 "$tmp"/etc/apk/world <<EOF +xen +EOF + +rc_add devfs sysinit +rc_add dmesg sysinit +rc_add udev sysinit + +rc_add hwclock boot +rc_add modules boot +rc_add sysctl boot +rc_add hostname boot +rc_add bootmisc boot +rc_add syslog boot + +rc_add udev-postmount default +rc_add xenstored default +rc_add xenconsoled default + +rc_add mount-ro shutdown +rc_add killprocs shutdown +rc_add savecache shutdown + +tar -c -C "$tmp" etc | gzip -9n > $HOSTNAME.apkovl.tar.gz diff --git a/scripts/mkimage.sh b/scripts/mkimage.sh new file mode 100644 index 0000000000..c94e415fe9 --- /dev/null +++ b/scripts/mkimage.sh @@ -0,0 +1,226 @@ +#!/bin/sh + +# apk add abuild apk-tools alpine-conf busybox fakeroot xorriso + +# FIXME: clean workdir out of unneeded sections +# FIXME: --release: cp/mv images to REPODIR/$ARCH/releases/ +# FIXME: --update-latest: rewrite latest-releases.yaml with this build + +set -e + +# get abuild configurables +[ -e /usr/share/abuild/functions.sh ] || (echo "abuild not found" ; exit 1) +. /usr/share/abuild/functions.sh + +# deduce aports directory +[ -n "$APORTS" ] || APORTS=$(realpath $(dirname $0)/../) +[ -e "$APORTS/main/build-base" ] || die "Unable to deduce aports base checkout" + +# +all_sections="" +all_profiles="" +all_checksums="sha256 sha512" +all_arches="armhf x86 x86_64" +all_dirs="" +build_date="$(date +%y%m%d)" +default_arch="$(apk --print-arch)" +_hostkeys="" +_simulate="" +_checksum="" + +OUTDIR="$PWD" +RELEASE="${build_date}" + +msg() { + if [ -n "$quiet" ]; then return 0; fi + local prompt="$GREEN>>>${NORMAL}" + local name="${BLUE}mkimage${ARCH+-$ARCH}${NORMAL}" + printf "${prompt} ${name}: %s\n" "$1" >&2 +} + +list_has() { + local needle="$1" + local i + shift + for i in $@; do + [ "$needle" != "$i" ] || return 0 + done + return 1 +} + +usage() { + cat <<EOF + +$0 [--tag RELEASE] [--outdir OUTDIR] [--workdir WORKDIR] + [--arch ARCH] [--profile PROFILE] [--hostkeys] [--simulate] +$0 --help + +options: +--arch Specify which architecture images to build + (default: $default_arch) +--hostkeys Copy system apk signing keys to created images +--outdir Specify directory for the created images +--profile Specify which profiles to build +--simulate Don't execute commands +--tag Build images for tag RELEASE +--workdir Specify temporary working directory (cache) + +known profiles: $(echo $all_profiles | sort -u) + +EOF +} + +# helpers +load_plugins() { + local f + [ -e "$1" ] || return 0 + for f in "$1"/mkimg.*.sh; do + [ -e "$f" ] || return 0 + break + done + all_profiles="$all_profiles $(sed -n -e 's/^profile_\(.*\)() {$/\1/p' $1/mkimg.*.sh)" + all_sections="$all_sections $(sed -n -e 's/^section_\(.*\)() {$/\1/p' $1/mkimg.*.sh)" + for f in "$1"/mkimg.*.sh; do + . $f + done +} + +checksum() { + sha1sum | cut -f 1 -d ' ' +} + +build_section() { + local section="$1" + local args="$@" + local _dir="${args//[^a-zA-Z0-9]/_}" + shift + local args="$@" + + if [ -z "$_dir" ]; then + _fail="yes" + return 1 + fi + + if [ ! -e "$WORKDIR/${_dir}" ]; then + DESTDIR="$WORKDIR/${_dir}.work" + msg "--> $section $args" + if [ -z "$_simulate" ]; then + rm -rf "$DESTDIR" + mkdir -p "$DESTDIR" + if build_${section} "$@"; then + mv "$DESTDIR" "$WORKDIR/${_dir}" + _dirty="yes" + else + rm -rf "$DESTDIR" + _fail="yes" + fi + fi + fi + unset DESTDIR + all_dirs="$all_dirs $_dir" + _my_sections="$_my_sections $_dir" +} + +build_profile() { + local _id _dir _spec + _my_sections="" + _dirty="no" + _fail="no" + + profile_$PROFILE + list_has $ARCH $arch || return 0 + + msg "Building $PROFILE" + + # Collect list of needed sections, and make sure they are built + for SECTION in $all_sections; do + section_$SECTION + done + [ "$_fail" = "no" ] || return 1 + + # Defaults + [ -n "$image_name" ] || image_name="alpine-${PROFILE}" + [ -n "$output_filename" ] || output_filename="${image_name}-${RELEASE}-${ARCH}.${image_ext}" + + # Construct final image + local _imgid=$(echo -n $_my_sections | sort | checksum) + DESTDIR=$WORKDIR/image-$_imgid-$ARCH-$PROFILE + if [ "_$dirty" = "yes" -o ! -e "$DESTDIR" ]; then + msg "Creating $output_filename" + if [ -z "$_simulate" ]; then + # Merge sections + rm -rf "$DESTDIR" + mkdir -p "$DESTDIR" + for _dir in $_my_sections; do + for _fn in $WORKDIR/$_dir/*; do + [ ! -e "$_fn" ] || cp -Lrs $_fn $DESTDIR/ + done + done + echo "${image_name}-${RELEASE} ${build_date}" > "$DESTDIR"/.alpine-release + fi + fi + + if [ "_$dirty" = "yes" -o ! -e "$output_filename" ]; then + # Create image + output_format="${image_ext//[:\.]/}" + create_image_${output_format} || _fail="yes" + + if [ "$_checksum" = "yes" ]; then + for _c in $all_checksums; do + ${_c}sum "$output_filename" > "${output_filename}.${_c}" + done + fi + fi +} + +# load plugins +load_plugins "$(dirname $0)" +[ -z "$HOME" ] || load_plugins "$HOME/.mkimage" + +# parse parameters +while [ $# -gt 0 ]; do + opt="$1" + shift + case "$opt" in + --repository) REPODIR="$1"; shift ;; + --workdir) WORKDIR="$1"; shift ;; + --outdir) OUTDIR="$1"; shift ;; + --tag) RELEASE="$1"; shift ;; + --arch) req_arch="$1"; shift ;; + --profile) req_profiles="$1"; shift ;; + --hostkeys) _hostkeys="--hostkeys";; + --simulate) _simulate="yes";; + --checksum) _checksum="yes";; + --) break ;; + -*) usage; exit 1;; + esac +done + +# setup defaults +if [ -z "$WORKDIR" ]; then + WORKDIR="$(mktemp -d -t mkimage.XXXXXX)" + trap 'rm -rf $WORKDIR' INT + mkdir -p "$WORKDIR" +fi +req_profiles=${req_profiles:-${all_profiles}} +req_arch=${req_arch:-${default_arch}} +[ "$req_arch" != "all" ] || req_arch="${all_arch}" +[ "$req_profiles" != "all" ] || req_profiles="${all_profiles}" + +# create images +for ARCH in $req_arch; do + APKROOT="$WORKDIR/apkroot-$ARCH" + if [ ! -e "$APKROOT" ]; then + # create root for caching packages + mkdir -p "$APKROOT/etc/apk/cache" + cp -Pr /etc/apk/keys "$APKROOT/etc/apk/" + abuild-apk --arch "$ARCH" --root "$APKROOT" add --initdb + + echo "$REPODIR" > "$APKROOT/etc/apk/repositories" + fi + abuild-apk update --root "$APKROOT" + + for PROFILE in $req_profiles; do + (build_profile) + done +done diff --git a/scripts/mkimg.arm.sh b/scripts/mkimg.arm.sh new file mode 100644 index 0000000000..7b1f9cc343 --- /dev/null +++ b/scripts/mkimg.arm.sh @@ -0,0 +1,86 @@ +build_rpi_blobs() { + local fw + for fw in bootcode.bin fixup.dat start.elf ; do + curl --remote-time https://raw.githubusercontent.com/raspberrypi/firmware/${rpi_firmware_commit}/boot/${fw} \ + --output "${DESTDIR}"/${fw} || return 1 + done +} + +rpi_gen_cmdline() { + echo "modules=loop,squashfs,sd-mod,usb-storage quiet ${kernel_cmdline}" +} + +rpi_gen_config() { + cat <<EOF +disable_splash=1 +boot_delay=0 +gpu_mem=256 +gpu_mem_256=64 +[pi0] +kernel=boot/vmlinuz-rpi +initramfs boot/initramfs-rpi 0x08000000 +[pi1] +kernel=boot/vmlinuz-rpi +initramfs boot/initramfs-rpi 0x08000000 +[pi2] +kernel=boot/vmlinuz-rpi2 +initramfs boot/initramfs-rpi2 0x08000000 +[pi3] +kernel=boot/vmlinuz-rpi2 +initramfs boot/initramfs-rpi2 0x08000000 +[all] +include usercfg.txt +EOF +} + +build_rpi_config() { + rpi_gen_cmdline > "${DESTDIR}"/cmdline.txt + rpi_gen_config > "${DESTDIR}"/config.txt +} + +section_rpi_config() { + [ -n "$rpi_firmware_commit" ] || return 0 + build_section rpi_config $( (rpi_gen_cmdline ; rpi_gen_config) | checksum ) + build_section rpi_blobs "$rpi_firmware_commit" +} + +profile_rpi() { + profile_base + image_ext="tar.gz" + arch="armhf" + rpi_firmware_commit="4bf906cdd221c4f6815d0da7dda0cd59d25d945b" + kernel_flavors="rpi rpi2" + kernel_cmdline="dwc_otg.lpm_enable=0 console=ttyAMA0,115200 console=tty1" + initrd_features="base bootchart squashfs ext2 ext3 ext4 f2fs kms mmc raid scsi usb" + apkovl="genapkovl-dhcp.sh" + hostname="rpi" + image_ext="tar.gz" +} + +build_uboot() { + # FIXME: Fix apk-tools to extract packages directly + local pkg pkgs="$(apk fetch --simulate --root /tmp/timo/apkroot-armhf/ --recursive u-boot-all | sed -ne "s/^Downloading \([^0-9.]*\)\-.*$/\1/p")" + for pkg in $pkgs; do + [ "$pkg" == "u-boot-all" ] || apk fetch --root "$APKROOT" --stdout $pkg | tar -C "$DESTDIR" -xz usr + done + mkdir -p "$DESTDIR"/u-boot + mv "$DESTDIR"/usr/sbin/update-u-boot "$DESTDIR"/usr/share/u-boot/* "$DESTDIR"/u-boot + rm -rf "$DESTDIR"/usr +} + +section_uboot() { + [ -n "$uboot_install" ] || return 0 + build_section uboot $ARCH $(apk fetch --root "$APKROOT" --simulate --recursive u-boot-all | sort | checksum) +} + +profile_uboot() { + profile_base + image_ext="tar.gz" + arch="armhf armv7" + kernel_flavors="grsec" + kernel_addons="xtables-addons" + initfs_features="base bootchart squashfs ext2 ext3 ext4 kms mmc raid scsi usb" + apkovl="genapkovl-dhcp.sh" + hostname="alpine" + uboot_install="yes" +} diff --git a/scripts/mkimg.base.sh b/scripts/mkimg.base.sh new file mode 100644 index 0000000000..db2a3b2818 --- /dev/null +++ b/scripts/mkimg.base.sh @@ -0,0 +1,151 @@ +build_kernel() { + local _flavor="$2" + shift 3 + local _pkgs="$@" + update-kernel \ + $_hostkeys \ + --media \ + --flavor "$_flavor" \ + --arch "$ARCH" \ + --package "$_pkgs" \ + --feature "$initfs_features" \ + --repositories-file "$APKROOT/etc/apk/repositories" \ + "$DESTDIR" +} + +section_kernels() { + local _f _a _pkgs + for _f in $kernel_flavors; do + _pkgs="linux-$_f linux-firmware" + for _a in $kernel_addons; do + _pkgs="$_pkgs $_a-$_f" + done + local id=$( (echo "$initfs_features::$_hostkeys" ; apk fetch --root "$APKROOT" --simulate alpine-base $_pkgs | sort) | checksum) + build_section kernel $ARCH $_f $id $_pkgs + done +} + +build_apks() { + local _apksdir="$DESTDIR/apks" + local _archdir="$_apksdir/$ARCH" + mkdir -p "$_archdir" + + apk fetch --root "$APKROOT" --link --recursive --output "$_archdir" $apks + if ! ls "$_archdir"/*.apk >& /dev/null; then + return 1 + fi + + apk index \ + --description "$RELEASE" \ + --rewrite-arch "$ARCH" \ + --index "$_archdir"/APKINDEX.tar.gz \ + --output "$_archdir"/APKINDEX.tar.gz \ + "$_archdir"/*.apk + abuild-sign "$_archdir"/APKINDEX.tar.gz + touch "$_apksdir/.boot_repository" +} + +section_apks() { + [ -n "$apks" ] || return 0 + build_section apks $ARCH $(apk fetch --root "$APKROOT" --simulate --recursive $apks | sort | checksum) +} + +build_apkovl() { + local _host="$1" + msg "Generating $_host.apkovl.tar.gz" + (local _pwd=$PWD; cd "$DESTDIR"; fakeroot "$_pwd"/"$apkovl" "$_host") +} + +section_apkovl() { + [ -n "$apkovl" -a -n "$hostname" ] || return 0 + build_section apkovl $hostname $(checksum < "$apkovl") +} + +build_syslinux() { + local _fn + mkdir -p "$DESTDIR"/boot/syslinux + apk fetch --root "$APKROOT" --stdout syslinux | tar -C "$DESTDIR" -xz usr/share/syslinux + for _fn in isolinux.bin ldlinux.c32 libutil.c32 libcom32.c32 mboot.c32; do + mv "$DESTDIR"/usr/share/syslinux/$_fn "$DESTDIR"/boot/syslinux/$_fn || return 1 + done + rm -rf "$DESTDIR"/usr +} + +section_syslinux() { + [ "$output_format" = "iso" ] || return 0 + build_section syslinux $(apk fetch --root "$APKROOT" --simulate syslinux | sort | checksum) +} + +syslinux_gen_config() { + [ -z "$syslinux_serial" ] || echo "SERIAL $syslinux_serial" + echo "TIMEOUT ${syslinux_timeout:-20}" + echo "PROMPT ${syslinux_prompt:-1}" + echo "DEFAULT ${kernel_flavors%% *}" + + local _f + for _f in $kernel_flavors; do + if [ -z "${xen_params+set}" ]; then + cat <<EOF + +LABEL $_f + MENU LABEL Linux $_f + KERNEL /boot/vmlinuz-$_f + INITRD /boot/initramfs-$_f + DEVICETREEDIR /boot/dtbs + APPEND $initfs_cmdline $kernel_cmdline +EOF + else + cat <<EOF + +LABEL $_f + MENU LABEL Xen/Linux $_f + KERNEL /boot/syslinux/mboot.c32 + APPEND /boot/xen.gz ${xen_params} --- /boot/vmlinuz-$_f $initfs_cmdline $kernel_cmdline --- /boot/initramfs-$_f +EOF + fi + done +} + +build_syslinux_cfg() { + local syslinux_cfg="$1" + mkdir -p "${DESTDIR}/$(dirname $syslinux_cfg)" + syslinux_gen_config > "${DESTDIR}"/$syslinux_cfg +} + +section_syslinux_cfg() { + syslinux_cfg="" + [ ! "$output_format" = "iso" ] || syslinux_cfg="boot/syslinux/syslinux.cfg" + [ ! -n "$uboot_install" ] || syslinux_cfg="extlinux/extlinux.conf" + [ -n "$syslinux_cfg" ] || return 0 + build_section syslinux_cfg $syslinux_cfg $(syslinux_gen_config | checksum) +} + +create_image_iso() { + local ISO="${OUTDIR}/${output_filename}" + xorrisofs \ + -o ${ISO} -l -J -R \ + -b boot/syslinux/isolinux.bin \ + -c boot/syslinux/boot.cat \ + -V "alpine-$PROFILE $RELEASE $ARCH" \ + -no-emul-boot \ + -boot-load-size 4 \ + -boot-info-table \ + -quiet \ + -follow-links \ + ${iso_opts} \ + ${DESTDIR} + isohybrid ${ISO} +} + +create_image_targz() { + tar -C "${DESTDIR}" -chzf ${OUTDIR}/${output_filename} . +} + +profile_base() { + kernel_flavors="grsec" + initfs_cmdline="modules=loop,squashfs,sd-mod,usb-storage quiet" + initfs_features="ata base bootchart cdrom squashfs ext2 ext3 ext4 mmc raid scsi usb virtio" + apks="alpine-base alpine-mirrors bkeymaps chrony e2fsprogs network-extras openssl openssh tzdata" + apkovl="genapkovl-dhcp.sh" + hostname="alpine" +} diff --git a/scripts/mkimg.standard.sh b/scripts/mkimg.standard.sh new file mode 100644 index 0000000000..7348ebe35b --- /dev/null +++ b/scripts/mkimg.standard.sh @@ -0,0 +1,53 @@ +profile_standard() { + profile_base + image_ext="iso" + arch="x86 x86_64" + output_format="iso" +} + +profile_vanilla() { + profile_standard + kernel_flavors="vanilla" +} + +profile_extended() { + profile_standard + kernel_addons="dahdi-linux xtables-addons" + apks="$apks + dahdi-linux dahdi-tools ethtool hwdata lftp links + logrotate lua5.3 lsof lm_sensors lxc lxc-templates nano + pax-utils paxctl pciutils screen strace sudo tmux + usbutils v86d vim xtables-addons + + acct arpon arpwatch awall bridge-utils bwm-ng + ca-certificates conntrack-tools cutter cyrus-sasl dhcp + dhcpcd dhcrelay dnsmasq email fping fprobe haserl htop + igmpproxy ip6tables iproute2 iproute2-qos ipsec-tools + iptables iputils irssi ldns-tools links + ncurses-terminfo net-snmp net-snmp-tools nrpe nsd + opennhrp openvpn openvswitch pingu ppp quagga + quagga-nhrp rpcbind sntpc socat ssmtp strongswan + sysklogd tcpdump tcpproxy tinyproxy unbound + wireless-tools wpa_supplicant zonenotify + + btrfs-progs cksfv dosfstools cryptsetup + cciss_vol_status lvm2 mdadm mkinitfs mtools nfs-utils + parted rsync sfdisk syslinux unrar util-linux xfsprogs + " + + local _k _a + for _k in $kernel_flavors; do + apks="$apks linux-$_k" + for _a in $kernel_addons; do + apks="$apks $_a-$_k" + done + done + apks="$apks linux-firmware" +} + +profile_virt() { + profile_standard + kernel_flavors="virtgrsec" + kernel_cmdline="console=tty0 console=ttyS0,115200" + syslinux_serial="0 115200" +} diff --git a/scripts/mkimg.xen.sh b/scripts/mkimg.xen.sh new file mode 100644 index 0000000000..95ec182833 --- /dev/null +++ b/scripts/mkimg.xen.sh @@ -0,0 +1,17 @@ +build_xen() { + apk fetch --root "$APKROOT" --stdout xen-hypervisor | tar -C "$DESTDIR" -xz boot +} + +section_xen() { + [ -n "${xen_params+set}" ] || return 0 + build_section xen $ARCH $(apk fetch --root "$APKROOT" --simulate xen-hypervisor | checksum) +} + +profile_xen() { + profile_standard + arch="x86_64" + kernel_cmdline="nomodeset" + xen_params="" + apks="$apks ethtool lvm2 mdadm multipath-tools openvswitch sfdisk xen" + apkovl="genapkovl-xen.sh" +} |