From 9327fe6000919072508ee8f35eb2f32539c3167b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Madis=20M=C3=A4gi?= Date: Tue, 23 Feb 2021 00:32:51 +0200 Subject: [PATCH] Explode overlay tar --- 00-deps.sh | 2 +- overlay.tar | Bin 40960 -> 0 bytes overlay/etc/motd | 13 + overlay/sbin/butterknife-advanced-options | 90 ++++ overlay/sbin/butterknife-discover | 12 + overlay/sbin/butterknife-partition-size | 12 + overlay/sbin/butterknife-provision | 440 ++++++++++++++++++ .../sbin/butterknife-select-btrfs-filesystem | 19 + overlay/sbin/butterknife-select-disk | 33 ++ overlay/sbin/init | 70 +++ 10 files changed, 690 insertions(+), 1 deletion(-) delete mode 100644 overlay.tar create mode 100644 overlay/etc/motd create mode 100755 overlay/sbin/butterknife-advanced-options create mode 100755 overlay/sbin/butterknife-discover create mode 100755 overlay/sbin/butterknife-partition-size create mode 100755 overlay/sbin/butterknife-provision create mode 100755 overlay/sbin/butterknife-select-btrfs-filesystem create mode 100755 overlay/sbin/butterknife-select-disk create mode 100755 overlay/sbin/init diff --git a/00-deps.sh b/00-deps.sh index dc6eab4..6ecd89d 100644 --- a/00-deps.sh +++ b/00-deps.sh @@ -10,6 +10,6 @@ fi curl -JLO https://github.com/buildroot/buildroot/archive/2020.02.10.tar.gz tar xf buildroot-2020.02.10.tar.gz mkdir buildroot-2020.02.10/butterknife/ -tar xf overlay.tar -C buildroot-2020.02.10/butterknife/ +cp -r overlay/ buildroot-2020.02.10/butterknife/ mkdir bin/ diff --git a/overlay.tar b/overlay.tar deleted file mode 100644 index 1d19d03c494523e95f10503032f390f99a7bcc67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 40960 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 >$(tty)) +clear + +case $action in + shell) + sh + ;; + instance) + export BUTTERKNIFE_PARTITION=$(butterknife-select-btrfs-filesystem 2>&1 >$(tty)) + + # Probe instances + pool_mountpoint=$(mktemp -d) + subvols=$(mktemp) + mount $BUTTERKNIFE_PARTITION $pool_mountpoint -o subvol=/ + for subvol in $(ls $pool_mountpoint | grep "^@root:" | sort -r); do + echo "$subvol \"\"" + done > $subvols + if [ -d $pool_mountpoint/deployments ]; then + for timestamp in $(ls $pool_mountpoint/deployments | sort -r); do + echo "deployments/$timestamp \"\"" + done >> $subvols + fi + umount $pool_mountpoint + rmdir $pool_mountpoint + + # Select instance + export BUTTERKNIFE_DEPLOY_SUBVOL=$(dialog \ + --menu "Select instance" 0 0 0 \ + --file $subvols 2>&1 >$(tty)) + + # TODO: Export BUTTERKNIFE_DISK for grub-install MBR + instance_mountpoint=$(mktemp -d) + mount $BUTTERKNIFE_PARTITION -o subvol=$BUTTERKNIFE_DEPLOY_SUBVOL $instance_mountpoint + mount --bind /dev $instance_mountpoint/dev + mount --bind /sys $instance_mountpoint/sys + mount --bind /proc $instance_mountpoint/proc + if [ -d $instance_mountpoint/var/lib/butterknife/persistent ]; then + mount --bind /proc $instance_mountpoint/var/lib/butterknife/persistent + fi + clear + echo "Mounted $BUTTERKNIFE_PARTITION$BUTTERKNIFE_DEPLOY_SUBVOL at $instance_mountpoint" + echo "Chrooting into $instance_mountpoint" + hostname $(cat $instance_mountpoint/etc/hostname) + cat /etc/resolv.conf > $instance_mountpoint/etc/resolv.conf + # Export sensible PATH + export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + chroot $instance_mountpoint butterknife-maintenance + umount -a + rmdir $instance_mountpoint + ;; + subvol) + BUTTERKNIFE_PARTITION=$(butterknife-select-btrfs-filesystem 2>&1 >$(tty)) + mountpoint=$(mktemp -d) + mount $BUTTERKNIFE_PARTITION -o subvol=/ $mountpoint + subvols=$(mktemp) + for subvol in $(btrfs subvol list $mountpoint | cut -d ' ' -f 9 | sort -r); do + echo "$subvol \"\"" + done > $subvols + selected_subvol=$(dialog --menu "Select subvolume to delete on $BUTTERKNIFE_PARTITION" 0 0 0 \ + --file $subvols 2>&1 >$(tty)) + rm -f $subvols + btrfs subvol delete -c $mountpoint/$selected_subvol + umount $mountpoint + rmdir $mountpoint + ;; + restore) + disk=$(butterknife-select-disk 2>&1 >$(tty)) + + # Select MBR type + action=$(dialog --menu "What kind of master boot record would you like to restore? You might have to mark partition bootable using fdisk." 0 0 0 \ + mbr7 "Windows 7/8/10" \ + mbrvista "Windows Vista" \ + mbr "Windows 2000/XP/2003" \ + 2>&1 >$(tty)) + + cmd="ms-sys --$action /dev/$disk" + $cmd | dialog --programbox "$cmd" 10 76 + + ;; +esac + diff --git a/overlay/sbin/butterknife-discover b/overlay/sbin/butterknife-discover new file mode 100755 index 0000000..8a0dfa6 --- /dev/null +++ b/overlay/sbin/butterknife-discover @@ -0,0 +1,12 @@ +dig -t ANY @224.0.0.251 -p5353 +noall +answer _butterknife._tcp.local | grep "IN SRV" | while read line; do + hostname=$(echo $line | cut -d " " -f 8) + address=$(dig +short +noall +answer @224.0.0.251 -p5353 $hostname | head -n1) + port=$(echo $line | cut -d " " -f 7) + title=$(echo $line | cut -d "." -f 1 | sed -e 's/\032/ /g') + if [ $port -eq 80 ]; then + echo "http://$address \"$title\"" + else + echo "http://$address:$port \"$title\"" + fi +done + diff --git a/overlay/sbin/butterknife-partition-size b/overlay/sbin/butterknife-partition-size new file mode 100755 index 0000000..df90dc3 --- /dev/null +++ b/overlay/sbin/butterknife-partition-size @@ -0,0 +1,12 @@ +#!/bin/sh + +partition_slug=$(echo $1 | cut -d "/" -f 3) +sys_part="/sys/block/*/$partition_slug" +sys_disk=$(dirname $sys_part) +sector_count=$(cat $sys_part/size) +sector_size=$(cat $sys_disk/queue/hw_sector_size) +size=$(expr $sector_count / 1000000 \* $sector_size / 1000)G +if [ $size == "G" ]; then + size=$(expr $sector_count / 1000 \* $sector_size / 1000)M +fi +echo $size diff --git a/overlay/sbin/butterknife-provision b/overlay/sbin/butterknife-provision new file mode 100755 index 0000000..3bfb25f --- /dev/null +++ b/overlay/sbin/butterknife-provision @@ -0,0 +1,440 @@ +#!/bin/sh + +# TODO: Make sure fdisk from busybox is NOT used, it's counting sectors incorrectly (?!) +# TODO: Check connectivity with API server + +BUTTERKNIFE_POOL_MOUNTPOINT=/var/lib/butterknife/pool +TARGET_MOUNTPOINT=/mnt/target + +AGENT="Butterknife-Provisioning-Image/0.2" +URL_LOCAL=http://butterknife + + +####################################### +### Check for presence of utilities ### +####################################### +for util in btrfs jq fdisk find ntfsresize udp-sender udp-receiver ntpdate curl ms-sys mktemp test true sort uniq dig; do + if [ -z "$(which $util)" ]; then + echo "Butterknife was unable to locate $util," \ + "are you sure the provisioning image was compiled properly?" + exit 253 + else + echo "Found $util..." + fi +done + +#for i in $(cat /proc/cmdline); do +# case i in +# bk_debug) + set -x # Echo +# ;; +# esac +#done + + +set -e # Bail on error + +####################################### +### Transfer method selection phase ### +####################################### + +if [ -z $BUTTERKNIFE_TRANSFER_METHOD ]; then + BUTTERKNIFE_TRANSFER_METHOD=$(dialog --menu "Select transfer method" 0 0 0 \ + http "HTTP-only" \ + multicast "Multicast receive" \ + tee "Multicast via HTTP and write" \ + proxy "Only proxy HTTP to multicast" 2>&1 >$(tty)) + clear +fi + + +################################## +### Harddisk preparation phase ### +################################## + +case $BUTTERKNIFE_TRANSFER_METHOD in + http|multicast|tee) + ############################# + ### Target disk selection ### + ############################# + + if [ -z $bk_disk_slug ]; then + bk_disk_slug=$(butterknife-select-disk 2>&1 >$(tty)) + fi + BUTTERKNIFE_DISK=/dev/$bk_disk_slug + + if [ -z $BUTTERKNIFE_PARTITIONING_METHOD ]; then + + BUTTERKNIFE_PARTITIONING_METHOD=$(dialog --menu "Partitioning $BUTTERKNIFE_DISK" 0 0 0 \ + receive "Receive into existing btrfs filesystem" \ + unpartitioned "Use unpartitioned area" \ + resize "Resize last partition" \ + reformat "Reformat partition" \ + mbr "Wipe <2TB disk" \ + gpt "Wipe 2TB+ disk" \ + efi "Wipe and do EFI install" \ + 2>&1 >$(tty)) + clear + fi + + # TODO: deploy "Deploy received template" \ + # TODO: postinstall "Run postinstall scripts (reinstall GRUB)" \ + case $BUTTERKNIFE_PARTITIONING_METHOD in + unpartitioned) + echo "Attempting to create new partition in unpartitioned space" + echo -e "n\np\n\n\n\nw" | fdisk $BUTTERKNIFE_DISK + ;; + resize) + NTFS_PARTITION=$(ls $BUTTERKNIFE_DISK? | tail -n 1) + # TODO: Assert last one is NTFS + # TODO: Suggested size heuristics + MINSIZE=$(ntfsresize $NTFS_PARTITION -m | grep Minsize | cut -d ':' -f 2) + SUGGESTED=${MINSIZE}M + SIZE=$(dialog --inputbox "Enter new filesystem size of at least ${MINSIZE}M" 0 0 $SUGGESTED 2>&1 >$(tty)) + clear + ntfsresize -s $SIZE $NTFS_PARTITION + echo -e "d\n\nw" | fdisk $BUTTERKNIFE_DISK # Remove last partition + echo -e "n\np\n\n\n+$SIZE\nt\n\n7\nw" | fdisk $BUTTERKNIFE_DISK # Re-create NTFS + echo -e "n\np\n\n\n\nw" | fdisk $BUTTERKNIFE_DISK # Create partition for btrfs + ;; + mbr) + echo "Purging whole disk" + echo -e "o\nn\np\n\n\n\na\n1\nw" | fdisk $BUTTERKNIFE_DISK + ;; + gpt) + sgdisk $BUTTERKNIFE_DISK -o -g \ + -n 1::+2MB -t 1:ef02 -c 1:"BIOS Boot Partition" \ + -n 2 -t 2:8300 -c 2:"Butterknife pool" -p + ;; + efi) + sgdisk $BUTTERKNIFE_DISK -o -g \ + -n 1::+100MB -t 1:ef00 -c 1:"EFI System Partition" \ + -n 2 -t 2:8300 -c 2:"Butterknife pool" -p + ;; + reformat|receive) + # NOOP + ;; + *) + echo "Invalid partitioning method $BUTTERKNIFE_PARTITIONING_METHOD" + exit 255 + ;; + esac + + + ############################################ + ### Target partition determination phase ### + ############################################ + case $BUTTERKNIFE_PARTITIONING_METHOD in + reformat|receive) + # Dialog to select partition for reformat or receive + for partition in $BUTTERKNIFE_DISK?; do + partition_slug=$(echo $BUTTERKNIFE_PARTITION | cut -d "/" -f 3) + sector_count=$(cat /sys/block/$bk_disk_slug/$BUTTERKNIFE_PARTITION_slug/size) + sector_size=$(cat /sys/block/$bk_disk_slug/queue/hw_sector_size) + size=$(expr $sector_count / 1000000 \* $sector_size / 1000 || true)G + if [ $size == "0G" ]; then + size=$(expr $sector_count / 1000 \* $sector_size / 1000 || true)M + fi + echo "$BUTTERKNIFE_PARTITION \"$size\""; + done > /tmp/partitions + + BUTTERKNIFE_PARTITION=$(dialog \ + --menu "Target partition" 0 0 0 \ + --file /tmp/partitions \ + 2>&1 >$(tty)) + clear + ;; + unpartitioned|resize|mbr|gpt|efi) + # Assume last partition + BUTTERKNIFE_PARTITION=$(ls $BUTTERKNIFE_DISK? | tail -n 1) + ;; + *) + echo "Invalid partitioning method $BUTTERKNIFE_PARTITIONING_METHOD" + exit 255 + ;; + esac + + PARTITION_SLUG=$(echo $BUTTERKNIFE_PARTITION | cut -d "/" -f 3) + + + ######################################## + ### Target filesystem creation phase ### + ######################################## + case $BUTTERKNIFE_PARTITIONING_METHOD in + efi) + mkfs.vfat ${BUTTERKNIFE_DISK}1 + ;; + esac + + case $BUTTERKNIFE_PARTITIONING_METHOD in + mbr|gpt|efi|reformat|unpartitioned|resize) + echo "Creating clean btrfs filesystem on $PARTITON" + mkfs.btrfs -f $BUTTERKNIFE_PARTITION + ;; + esac + + # Attempt to mount target directory + mkdir -p $BUTTERKNIFE_POOL_MOUNTPOINT + mount $BUTTERKNIFE_PARTITION $BUTTERKNIFE_POOL_MOUNTPOINT -o subvol=/ -t btrfs + if [ $? -ne 0 ]; then + dialog --msgbox "Mounting $BUTTERKNIFE_PARTITION at $BUTTERKNIFE_POOL_MOUNTPOINT failed, are you sure kernel has btrfs support built-in?" 0 0 + exit 255 + fi + + ################ + ### Clean up ### + ################ + + for subvol in $(ls $BUTTERKNIFE_POOL_MOUNTPOINT | (grep "^@template:" || true)); do + set +e + touch $BUTTERKNIFE_POOL_MOUNTPOINT/$subvol/.test + if [ $? -eq 0 ]; then + set -e + btrfs subvol delete $BUTTERKNIFE_POOL_MOUNTPOINT/$subvol + fi + set -e + done + ;; + *) + BUTTERKNIFE_PARTITIONING_METHOD="pass" + ;; +esac + +############################## +### Determine architecture ### +############################## + +bk_arch=$(uname -m | sed 's/^i.86$/x86/') + +case $BUTTERKNIFE_TRANSFER_METHOD in + http|tee|proxy) + ############################## + ### Server selection phase ### + ############################## + if [ -z $bk_url ]; then + + bk_url=$(dialog --menu "Select server" 0 0 0 \ + mdns:// "Autodiscover" \ + $URL_LOCAL "Manually enter" \ + https://butterknife.k-space.ee "K-SPACE MTÜ" 2>&1 >$(tty)) + + if [ "$bk_url" == "mdns://" ]; then + butterknife-discover > /tmp/discovered_servers + bk_url=$(dialog --menu "Select one of discovered servers" \ + 0 0 0 --file /tmp/discovered_servers 2>&1 >$(tty)) + elif [ "$bk_url" == $URL_LOCAL ]; then + bk_url=$(dialog --inputbox "Manually enter the URL of Butterknife server" \ + 0 0 $URL_LOCAL 2>&1 >$(tty)) + fi + clear + fi + + + ################################ + ### Template selection phase ### + ################################ + + if [ -z $bk_template ]; then + # Fetch template list + curl -A $AGENT -s $bk_url/api/template \ + | jq '.templates[] | .namespace + "." + .identifier + " \"" + .description + "\""' -r \ + > /tmp/available_templates + + bk_template=$(dialog \ + --menu "Select template to deploy" 0 0 0 \ + --file /tmp/available_templates \ + 2>&1 >$(tty)) + clear + + fi + + ############################### + ### Version selection phase ### + ############################### + if [ -z $bk_version ]; then + # Fetch version list + curl -A $AGENT -s $bk_url/api/template/$bk_template/arch/$bk_arch/version \ + > /tmp/available_versions.json + + cat /tmp/available_versions.json \ + | jq '.versions[] | .identifier + " \"" + .comment + "\""' -r \ + | head -n 100 \ + > /tmp/available_versions + + bk_version=$(dialog \ + --menu "Select version to deploy" 0 0 0 \ + --file /tmp/available_versions \ + 2>&1 >$(tty)) + clear + fi + + BUTTERKNIFE_TEMPLATE_SUBVOL="@template:$bk_template:$bk_arch:$bk_version" + + + + ##################################### + ### Stream URL construction phase ### + ##################################### + + # Build btrfs-stream URL + STREAM="$bk_url/$BUTTERKNIFE_TEMPLATE_SUBVOL" + ;; +esac + + +############################################## +### Allow differential versions using HTTP ### +############################################## + +case $BUTTERKNIFE_TRANSFER_METHOD in + http) + # Determine differential version parent + cat /tmp/available_versions.json | jq -r '.versions[] .identifier' > /tmp/available_version_names + ls $BUTTERKNIFE_POOL_MOUNTPOINT | (grep "^@template:$bk_template:$bk_arch:" || true) | cut -d ":" -f 4 > /tmp/local_version_names + PARENT=$(cat /tmp/local_version_names /tmp/available_version_names | sort | grep -v $bk_version | uniq -d | sort -t p -k 2n | tail -n 1) + if [ -z $PARENT ]; then + echo "Could not determine parent, falling back to full snapshot" + else + STREAM="$STREAM?parent=@template:$bk_template:$bk_arch:$PARENT" + fi + echo "Final URL is $STREAM" + ;; +esac + +#################################################### +### Enable compression if we're going over HTTPS ### +#################################################### + +case $STREAM in + https://*) + STREAM="--compressed $STREAM" + ;; +esac + + +###################### +### Transfer phase ### +###################### + +case $BUTTERKNIFE_TRANSFER_METHOD in + multicast) + ls $BUTTERKNIFE_POOL_MOUNTPOINT | (grep "^@template:" || true) > /tmp/local_templates + udp-receiver --nokbd | btrfs receive $BUTTERKNIFE_POOL_MOUNTPOINT + # Heuristics to determine name of received snapshot + ls $BUTTERKNIFE_POOL_MOUNTPOINT | (grep "^@template:" || true) > /tmp/new_templates + BUTTERKNIFE_TEMPLATE_SUBVOL=$(cat /tmp/local_templates /tmp/new_templates | sort | uniq -u) + # TODO: Break here if we got garbage + bk_template=$(echo $BUTTERKNIFE_TEMPLATE_SUBVOL | cut -d ":" -f 2) + bk_arch=$(echo $BUTTERKNIFE_TEMPLATE_SUBVOL | cut -d ":" -f 3) + bk_version=$(echo $BUTTERKNIFE_TEMPLATE_SUBVOL | cut -d ":" -f 4) + ;; + http) + curl -A $AGENT $STREAM | btrfs receive $BUTTERKNIFE_POOL_MOUNTPOINT + ;; + tee) + dialog --msgbox "Press enter once all the other machines are ready to receive" 0 0 + mkfifo /tmp/multicast_stream /tmp/local_stream + cat /tmp/local_stream | btrfs receive $BUTTERKNIFE_POOL_MOUNTPOINT & + sleep 1 + udp-sender --nokbd --no-progress --min-receivers 1 --min-wait 5 /tmp/multicast_stream & + sleep 1 + curl -A $AGENT -s $STREAM | tee /tmp/multicast_stream > /tmp/local_stream + sleep 2 + # TODO: Ensure btrfs receive has finished + ;; + proxy) + dialog --msgbox "Press enter once all the other machines are ready to receive" 0 0 + curl -A $AGENT -s $STREAM \ + | udp-sender --nokbd --min-receivers 1 --min-wait 5 + ;; +esac + +sync + +case $BUTTERKNIFE_PARTITIONING_METHOD in + pass) + echo "Skipping template deployment" + ;; + *) + ################################# + ### Template deployment phase ### + ################################# + + BUTTERKNIFE_DEPLOY_SUBVOL="@root:$bk_template:$bk_arch:$bk_version" + btrfs subvolume snapshot \ + $BUTTERKNIFE_POOL_MOUNTPOINT/$BUTTERKNIFE_TEMPLATE_SUBVOL \ + $BUTTERKNIFE_POOL_MOUNTPOINT/$BUTTERKNIFE_DEPLOY_SUBVOL + + # Symlink @root:active to current deployment subvol + rm -f $BUTTERKNIFE_POOL_MOUNTPOINT/@root:active + ln -s \ + $BUTTERKNIFE_DEPLOY_SUBVOL \ + $BUTTERKNIFE_POOL_MOUNTPOINT/@root:active + + + ############################### + ### Run post-deploy scripts ### + ############################### + + # Mount deployment subvolume at target directory + mkdir -p $TARGET_MOUNTPOINT + mount -o subvol=$BUTTERKNIFE_DEPLOY_SUBVOL \ + $BUTTERKNIFE_PARTITION \ + $TARGET_MOUNTPOINT + + # Mount pool also for chroot + mkdir -p $TARGET_MOUNTPOINT$BUTTERKNIFE_POOL_MOUNTPOINT + mount -o subvol=/ \ + $BUTTERKNIFE_PARTITION \ + $TARGET_MOUNTPOINT$BUTTERKNIFE_POOL_MOUNTPOINT + + # Mount stuff for chroot + mount --bind /dev/ $TARGET_MOUNTPOINT/dev/ + mount --bind /sys/ $TARGET_MOUNTPOINT/sys/ + mount --bind /proc/ $TARGET_MOUNTPOINT/proc/ + mount --bind /run/ $TARGET_MOUNTPOINT/run/ + mount none $TARGET_MOUNTPOINT/tmp/ -t tmpfs + + case $BUTTERKNIFE_PARTITIONING_METHOD in + efi) + mount ${BUTTERKNIFE_DISK}1 $TARGET_MOUNTPOINT/boot/efi + ;; + esac + + # Export variables for postinstall scripts + export BUTTERKNIFE_DOMAIN + export BUTTERKNIFE_TEMPLATE_SUBVOL + export BUTTERKNIFE_DEPLOY_SUBVOL + export BUTTERKNIFE_PARTITION + export BUTTERKNIFE_DISK + export BUTTERKNIFE_POOL_MOUNTPOINT + export BUTTERKNIFE_PARTITIONING_METHOD + export BUTTERKNIFE_TRANSFER_METHOD + export BUTTERKNIFE_POOL_UUID=$(blkid -s UUID -o value $BUTTERKNIFE_PARTITION) + + # Copy DNS config + mkdir -p /run/resolvconf + mkdir -p /run/systemd/resolve + cat /etc/resolv.conf > $TARGET_MOUNTPOINT/etc/resolv.conf + + # Export sensible PATH + export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + + # Run postinstall scripts, presumably in sorted order + chroot $TARGET_MOUNTPOINT butterknife-deploy + chroot $TARGET_MOUNTPOINT butterknife-maintenance + + # Be forgiving from now on + set +e + + # Unmount directories + echo "Unmounting filesystems" + umount -a + echo "Flushing buffers" + sync + sleep 1 + echo "Rebooting machine" + reboot -f + ;; +esac + diff --git a/overlay/sbin/butterknife-select-btrfs-filesystem b/overlay/sbin/butterknife-select-btrfs-filesystem new file mode 100755 index 0000000..48d7ff7 --- /dev/null +++ b/overlay/sbin/butterknife-select-btrfs-filesystem @@ -0,0 +1,19 @@ +#!/bin/sh + +volumes=$(mktemp) + +unset partition +for partition in $(blkid -t TYPE=btrfs | cut -d ":" -f 1); do + echo "$partition \"$(butterknife-partition-size $partition)\""; +done > $volumes + +if [ -z $partition ]; then + dialog --msgbox "Unable to detect any Butterknife filesystems" 0 0 + return 1 +else + dialog \ + --menu "Select btrfs filesystem" 0 0 0 \ + --file $volumes +fi + +rm -f $volumes diff --git a/overlay/sbin/butterknife-select-disk b/overlay/sbin/butterknife-select-disk new file mode 100755 index 0000000..547a6cb --- /dev/null +++ b/overlay/sbin/butterknife-select-disk @@ -0,0 +1,33 @@ +#!/bin/sh + +if [ -z "$(ls /sys/class/block/)" ]; then + dialog --msgbox "Butterknife was unable to detect any harddisks,\ + are you sure harddisk is connected and we have drivers for it?" 0 0 + exit 255 +fi + +for disk in /sys/class/block/*; do + if [ -d $disk/device ]; then + slug=$(basename $disk) + sector_count=$(cat $disk/size) + sector_size=$(cat $disk/queue/hw_sector_size) + # Hack around these dumbass cardreaders + + if [ "$sector_count" == "0" ]; then + continue + fi + size=$(expr $sector_count / 1000000 \* $sector_size / 1000 || true)G + + if [ -f $disk/device/model ]; then + echo "$slug \"$(cat $disk/device/model | xargs) ($size)\""; + else + echo "$slug \"$size\""; + fi + fi +done > /tmp/disks + +dialog \ + --menu "Target disk" 0 0 0 \ + --file /tmp/disks + + diff --git a/overlay/sbin/init b/overlay/sbin/init new file mode 100755 index 0000000..8a3bb12 --- /dev/null +++ b/overlay/sbin/init @@ -0,0 +1,70 @@ +#!/bin/sh + +clear + +if [ -f /etc/motd ]; then + cat /etc/motd +fi + +# Note that /dev should be handled by devtmpfs +# Make sure this file will be executable + +mount -t proc none /proc +mount -t sysfs sysfs /sys + +################################################################# +### There should be at least one network interface to proceed ### +################################################################# + +echo "Discovering network interfaces..." +sleep 5 + +if [ -z "$(ls /sys/class/net/ | grep -v '^lo$')" ]; then + dialog --msgbox "Butterknife was unable to detect any network interfaces,\ + are you sure network interface is attached properly and we have drivers for it?" 0 0 + exit 254 +fi + +echo "Asking for IP using DHCP ..." +udhcpc + +if [ -z "$bk_timeserver" ]; then + echo "No timeserver specified, skipping ntpdate" +else + echo "Adjusting time ..." + ntpdate $bk_timeserver +fi + +if [ $bk_action == "provision" ]; then + butterknife-provision + sync + sleep 10 + poweroff -f +fi + +while [ 1 ]; do + action=$(dialog --no-cancel --menu "What do you want to do" 0 0 0 \ + provision "Provision this machine" \ + advanced "Advanced options" \ + reboot "Reboot" \ + poweroff "Shutdown" 2>&1 >$(tty)) + + clear + + case $action in + reboot) + reboot -f + ;; + poweroff) + poweroff -f + ;; + provision) + butterknife-provision + read -p "Press Enter to continue..." + + ;; + advanced) + butterknife-advanced-options + ;; + esac +done