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:
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