autoinst

scripts to make installation of custom debian easier and more automated
git clone git://deadbeef.fr/autoinst.git
Log | Files | Refs | README | LICENSE

commit 5443748ad27958801017efe104d8cc958ab5f251
parent 9e4bac30eb08ccc18302e701c2f3803a615b329c
Author: Morel BĂ©renger <berengermorel76@gmail.com>
Date:   Fri,  7 Aug 2020 12:22:46 +0200

new implementation

Rewrote the whole mess.
Now the script is template-based, which should hopefully make it a lot
more flexible.
Old files are deprecated and will be progressively removed as things go
on.
Several templates will be made, including some that enable disk
encryption.

Diffstat:
MREADME | 15++++++++++++++-
Minstall.sh | 234++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Atemplates/generic/boot | 3+++
Atemplates/generic/name | 1+
Atemplates/generic/packages/base.list | 1+
Atemplates/generic/partitions | 7+++++++
Atemplates/generic/root/etc/fstab | 5+++++
Atemplates/generic/syslinux/ldlinux.c32 | 0
Atemplates/generic/syslinux/libcom32.c32 | 0
Atemplates/generic/syslinux/libutil.c32 | 0
Atemplates/generic/syslinux/syslinux.cfg | 11+++++++++++
Atemplates/generic/syslinux/vesamenu.c32 | 0
Atemplates/generic/users | 2++
Dtemplates/vps_crypt/src/partitions | 6------
14 files changed, 221 insertions(+), 64 deletions(-)

diff --git a/README b/README @@ -80,7 +80,7 @@ Unfortunately, everything can not be guessed from those files, so there are additional ones: * partitions: a file read by sfdisk to partition $TARGET if - $TARGET is a file (block or normal); + $TARGET is a file (block or normal). * "syslinux/*": a folder containing syslinux's configuration to boot TARGET after installation; MULTIPLE BOOTS SUPPORT NOT IMPLEMENTED! @@ -125,3 +125,16 @@ Some of them are listed here: is voluntary: it is not needed for the system to boot. * UEFI secure boot is not supported (by this script, but you can do it manually. How to do so or patches welcome). +* if you want the script to install a bootloader (e.g. + syslinux), then you *MUST* use all of :"label: gpt", + named-fields format and partlabels ('name='). This + *does not* imply you must use UEFI booting mechanism. +* if you want the script to install a bootloader (e.g. + syslinux), then you *MUST* indicate on which partition the + bootloader will be installed with the "bootable" flag in + "partitions". The booting mechanism (UEFI/Legacy) will be + choosen by considering if the 'type=' field contains the + correct value for UEFI boots. + If 'attrs=LegacyBIOSBootable' is found, then _both_ + mechanisms will be installed. + The "bootable" flag *MUST* only be present *once*. diff --git a/install.sh b/install.sh @@ -1,4 +1,4 @@ -#!/bin/sh -e +#!/bin/sh -ex MUST_DIE=0 die() @@ -28,33 +28,121 @@ success() echo -e "\e[32m$@\e[0m" } +inst_efilinux() +{ + part_type="${1:?"part_type not provided"}" + shift + part="${1:?"partition not provided"}" + shift + fs="${1:?"fs not provided"}" + shift + disk="${1:?"disk not provided"}" + shift + src="${1:?"src folder not provided"}" + shift + rootfs="${1:?"rootfs folder not provided"}" + shift + + if test "$part_type" != "gpt" + then + error "EFIlinux only supports gpt partition type" + return + fi + mkfs.$fs $part + dd if=/usr/lib/SYSLINUX/gptmbr.bin of="$disk" + + mkdir /tmp/efiboot + mount $part /tmp/efiboot + mkdir -p /tmp/efiboot/EFI/BOOT + cp /usr/lib/SYSLINUX.EFI/efi64/syslinux.efi /tmp/efiboot/EFI/BOOT/bootx64.efi + cp -r --no-preserve=all "$src"/* /tmp/efiboot/EFI/BOOT + # this is probably a bad idea, since it prevent user's customisations + cp "$rootfs/vmlinuz" "$rootfs/initrd.img" /tmp/efiboot/EFI/BOOT + umount /tmp/efiboot +} + +inst_syslinux() +{ + part_type="${1:?"part_type not provided"}" + shift + part="${1:?"partition not provided"}" + shift + fs="${1:?"fs not provided"}" + shift + disk="${1:?"disk not provided"}" + shift + src="${1:?"src folder not provided"}" + shift + rootfs="${1:?"rootfs folder not provided"}" + shift + + #TODO support extlinux (should be trivial changes) + + mkfs.$fs $part + case "$part_type" in + mbr) + mbr="mbr.bin" + ;; + gpt) + mbr="gptmbr.bin" + ;; + *) + die "unknow partition type: $part_type" + esac + dd if=/usr/lib/SYSLINUX/$mbr of="$disk" + + syslinux -i $part + mkdir /tmp/syslinux + mount $part /tmp/syslinux + cp -r --no-preserve=all "$src"/* /tmp/syslinux/ + # this is probably a bad idea, since it prevent user's customisations + cp "$rootfs/vmlinuz" "$rootfs/initrd.img" /tmp/syslinux + umount /tmp/syslinux +} + TARGET="${1:?"TARGET must be provided as 1st arg"}" SOURCE="${2:?"SOURCE must be provided as 2nd arg"}" +MIRROR="${3}" -test -d "$TARGET" -a "$(find "$TARGET" -type f | wc -l)" -eq 0 && +test -z "$MIRROR" || + warn "No mirror is set, you are going to waste everyone's resources (including your time)" + +test -d "$TARGET" -n "$(find "$TARGET" -maxdepth 0 -empty)" && error "using a folder as TARGET ($TARGET) is only allowed if empty (for security reasons)" test -e "$TARGET" || mkdir -p "$TARGET" || - error "Unable to create $TARGET" + error "Unable to create folder $TARGET" test -b "$TARGET" -o -f "$TARGET" -o -d "$TARGET" || error "invalid TARGET ($TARGET) type" test -d "$SOURCE" || error "SOURCE ($SOURCE) should be a folder" +fstab="$SOURCE/root/etc/fstab" +test -f "$fstab" || + error "fstab ($fstab) must be a file" +test -e /mnt/target && + error "/mnt/target already exists" test $MUST_DIE -ne 0 && die "Errors where found, exiting." ### disk preparation -## target is a disk or a file: we need to prepare the disk +## target is a disk or a file: we need to prepare it +## folder targets are for building chroots. if test ! -d "$TARGET" then ## partitionning (and artificial delay for syncing) part_file="$SOURCE"/partitions - test -f "$part_file" || die "part_file ($part_file) must be a file" + test -f "$part_file" || + die "part_file ($part_file) must be a file" info "start partitioning" + #TODO: sfdisk is able to *not* destroy a disk's partitions. + # Thus, this script *should* be able to only add a new OS + # instead of only working in current "erase and write" way. + wipefs -a "$TARGET" sfdisk "$TARGET" < "$part_file" - info "partitioning done" - info "syncing disks... or udev, dunno... artificial sleep sorry." + success "partitioning done" + SYNCTIME=3 + info "syncing disks... or udev, dunno... artificial sleep sorry. (${SYNCTIME}s to wait)" sync - sleep 10 + sleep $SYNCTIME info "syncing done" ## encryption @@ -68,58 +156,40 @@ then if test "$keyfile" = "none" then keyfile="$mapped_dev.key" - test -f "$keyfile" || die "keyfile ($keyfile) is not a file" + test -f "$keyfile" || + die "keyfile ($keyfile) is not a file" fi OPTS="$(echo -n $params | sed -e 's/[a-z]*=/--&/g' -e 's/,/ /g')" cryptsetup -v $OPTS luksFormat "$dev" - < "$SOURCE/$keyfile" cryptsetup open "$dev" "$mapped_dev" --type luks --key-file - < "$SOURCE/$keyfile" done < "$crypttab" - info "encryption done" + success "encryption done" fi ## formatting partitions" info "formatting partitions" - fstab="$SOURCE/root/etc/fstab" - test -f "$fstab" || die "invalid fstab ($fstab)" - - $(awk < $fstab '$1 !~ /^[^ =\/]+ / { printf "mkfs.%s %s\n", $3, $1 }') - test -f "$fsboot" && $(awk < $fsboot '{ printf "mkfs.%s %s\n", $2, $1 }') - info "formatting done" - - ## syslinux installation - boot_dir="$SOURCE"/syslinux - syslinux="$(find "$boot_dir" -type f -name "syslinux.cfg")" - if test -n "$syslinux" -a "$(grep "$syslinux" -c -e "append.* root=")" -eq 1 - then - parttype="$(awk '/^label: / { print $2 }' < $part_file)" - syslinux_target="$(sed "$syslinux" -n -e '/root=/ s!^.* root=\([^ ]*\).*$!\1!g p')" - info "installing syslinux to $syslinux_target" - test "$parttype" = "gpt" && dd if=/usr/lib/syslinux/gptmbr.bin of="$TARGET" - syslinux -i "$syslinux_target" - info "syslinux installation done" - else - warn "$boot_dir not found, I will not install syslinux!" - fi + eval $(awk < "$fstab" '$1 ~ /[\/=]/ { if( sub( "PARTLABEL=", "$(readlink -f /dev/disk/by-partlabel/", $1 ) ) $1 = $1 ")"; printf "yes | mkfs.%s %s ;\n", $3, $1; }') + success "system partitions formated" fi ### system installation ## mounting partitions info "mounting partitions" -fstab="$SOURCE/root/etc/fstab" -test -f "$fstab" || die "invalid fstab ($fstab)" -$(awk < $fstab '$1 !~ /^[^ =\/]+ / { printf "mount -t %s %s %s\n", $3, $1, $2 }') -info "mounting done" +eval $(awk < $fstab '$1 !~ /^[^ =\/]+ / { printf "mkdir /mnt/target/%s; mount -t %s %s /mnt/target/%s;\n", $2, $3, $1, $2 }') +success "mounting done" ## template installation info "installing template" -cp -ar "$SOURCE/root/*" "$TARGET" -info "template installation done" +cp_target="$TARGET" +test -d "$TARGET" || cp_target="/mnt/target" +cp -ar "$SOURCE"/root/* "$cp_target" +success "template installation done" ## bootstrap -PKG_LIST="$(cat $SOURCE/packages/*.list),PKG_LIST" +PKG_LIST="$(find "$SOURCE" -path 'packages' -prune -o \( -type f -name '*.list' \) -exec cat {} \+),$PKG_LIST" info "preparing to install $PKG_LIST" -debootstrap --no-merged-usr --variant=minbase "--include=$PKG_LIST" $(cat $SOURCE/name) "$TARGET" -info "install done" +debootstrap --no-merged-usr --variant=minbase "--include=$PKG_LIST" $(cat $SOURCE/name) "$cp_target" "$MIRROR" +success "install done" info "users creation" for user in $(cut -d: -f1 "$SOURCE/users") @@ -129,39 +199,89 @@ do SKEL_DIR="-k $SOURCE/users.d/$user" fi - test "$user" = "root" || useradd -R "$TARGET" -m $SKEL_DIR + test "$user" = "root" || useradd -R "$cp_target" -m $SKEL_DIR $user done -chpassw -R "$TARGET" < "$SOURCE/users" -info "users creation done" +chpasswd -R "$cp_target" < "$SOURCE/users" +success "users creation done" -info "finishing syslinux installation" -if test -n "$parttype" +### boot-loaders configuration +## for now, only triggered if the script was asked to +## handle the partitions. +## for now, only syslinux is supported. +## Requirements for boot-loaders integration are: +## * they *MUST NOT* be managed by the installed system: +## this is because the user might be using this script +## for multi-boots, and automatic management of boot by +## a system is more than likely to cause havoc. +NOBOOT="won't install boot loader" +if test -n "$part_file" -a -f "$part_file" then -fi -info "finishing syslinux installation done" + # bootloaders require to know the partitionning type + part_type="$(awk < "$part_file" '/label:/ {print $2}')" + # the partiton where to install it is important, too + part_boot="$(sed -n -e '/bootable/ s/.*\<name="\([^"]*\)".*/\1/g p' -e 's/.*\<name=\([^"][^ ,]*\).*/\1/g p' "$part_file")" + part_boot="$(readlink -f /dev/disk/by-partlabel/$part_boot)" -## installing syslinux setup -if test -n "$syslinux_target" -then -info "unmounting partitions" - mount "$syslinux_target" "$TARGET" - cp -ar "$boot_dir" "$TARGET" + # for now, FS_BOOT and BOOTLOADER are sourced for + # simplicity + . "$SOURCE/boot" + # in future, I hope to guess as much as possible with + # various heuristics, like if fstab contains a /boot + # entry that can be linked to a $SOURCE/partitions's + # entry. + + INSTALL_BOOT="yes" + if test $(echo "$part_type" | wc -w ) -ne 1 + then + INSTALL_BOOT="no" + warn "only 1 label is supported for now, $NOBOOT" + fi + + if test $(echo "$part_boot" | wc -w ) -ne 1 + then + INSTALL_BOOT="no" + warn "only 1 bootable flag is supported for now, $NOBOOT" + fi + + if test -z "$BOOTLOADER" + then + INSTALL_BOOT="no" + warn "variable BOOTLOADER was not set, $NOBOOT" + fi + + if test "$INSTALL_BOOT" = "yes" + then + case "$BOOTLOADER" in + #TODO: pxe/iso/ext variants + efilinux) + inst_efilinux $part_type $part_boot $FS_BOOT $TARGET "$SOURCE/syslinux" "$cp_target" + ;; + syslinux) + inst_syslinux $part_type $part_boot $FS_BOOT $TARGET "$SOURCE/syslinux" "$cp_target" + ;; + *) + error "unsupported BOOTLOADER value ($BOOTLOADER)" + ;; + esac + fi fi ### cleaning up ## unmount info "unmounting partitions" -for mnt in $(findmnt -n -R -oTARGET -M $TARGET -l | tac) +for mnt in $(findmnt -n -R -oTARGET -M $cp_target -l | tac) do umount $mnt done -info "unmounting done" +success "unmounting done" ## closing luks if test -f "$crypttab" then info "closing luks" for name in $(cut -f1 "$SOURCE/root/etc/crypttab") - cryptsetup close $name - info "luks closed" + do + cryptsetup close $name + done + success "luks closed" fi diff --git a/templates/generic/boot b/templates/generic/boot @@ -0,0 +1,3 @@ +BOOTLOADER=syslinux +FS_BOOT=vfat +DIR=syslinux diff --git a/templates/generic/name b/templates/generic/name @@ -0,0 +1 @@ +buster diff --git a/templates/generic/packages/base.list b/templates/generic/packages/base.list @@ -0,0 +1 @@ +runit-init,linux-image-amd64 diff --git a/templates/generic/partitions b/templates/generic/partitions @@ -0,0 +1,7 @@ +label: gpt + name="BOOTLOADER",size=256M,bootable,attrs=LegacyBIOSBootable,type="C12A7328-F81F-11D2-BA4B-00A0C93EC93B" + name="tproot",size=2048M + name="tpusr",size=4096M + name="tpvar",size=1024M + name="tphome" +write diff --git a/templates/generic/root/etc/fstab b/templates/generic/root/etc/fstab @@ -0,0 +1,5 @@ +PARTLABEL=tproot / ext4 errors=remount-ro 0 1 +PARTLABEL=tpusr /usr ext4 nodev 0 2 +PARTLABEL=tpvar /var ext4 nodev 0 2 +PARTLABEL=tphome /home ext4 nodev,nosuid 0 2 +tmpfs /tmp tmpfs nosuid,nodev 0 0 diff --git a/templates/generic/syslinux/ldlinux.c32 b/templates/generic/syslinux/ldlinux.c32 Binary files differ. diff --git a/templates/generic/syslinux/libcom32.c32 b/templates/generic/syslinux/libcom32.c32 Binary files differ. diff --git a/templates/generic/syslinux/libutil.c32 b/templates/generic/syslinux/libutil.c32 Binary files differ. diff --git a/templates/generic/syslinux/syslinux.cfg b/templates/generic/syslinux/syslinux.cfg @@ -0,0 +1,11 @@ +prompt 0 +timeout 50 +default live + +ui vesamenu.c32 +menu title custom live boot + +label live + linux vmlinuz + initrd initrd.img + append ro root=PARTLABEL=tproot diff --git a/templates/generic/syslinux/vesamenu.c32 b/templates/generic/syslinux/vesamenu.c32 Binary files differ. diff --git a/templates/generic/users b/templates/generic/users @@ -0,0 +1,2 @@ +root:toor +user:resu diff --git a/templates/vps_crypt/src/partitions b/templates/vps_crypt/src/partitions @@ -1,6 +0,0 @@ -label: gpt - name="BOOTLOADER",size=256M,bootable,attrs=LegacyBIOSBootable,type="C12A7328-F81F-11D2-BA4B-00A0C93EC93B" - name="mainsys",size=2048M - name="mainvar",size=2048M - name="home" -write