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 9e4bac30eb08ccc18302e701c2f3803a615b329c
parent 56f563500c56798972ec79491d1c09fc7a4368c6
Author: Morel BĂ©renger <berengermorel76@gmail.com>
Date:   Thu,  6 Aug 2020 15:00:47 +0200

reworked readme

Diffstat:
MREADME | 173+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Ainstall.sh | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 262 insertions(+), 78 deletions(-)

diff --git a/README b/README @@ -1,110 +1,127 @@ -This repo aims to build a small personnal distro based on Debian. +This repo aims to build a small personnal distro based on +Debian. -It targets powerusers. If you don't know how to script, don't use this. +It targets powerusers. If you don't know how to script, +don't use this, it's safer and easier to just use the debian +installer. + += DISCLAIMER + +THIS SCRIPT IS VERY, VERY LIKELY TO DAMAGE YOUR COMPUTER IF +NOT USED CORRECTLY. DO *NOT* USE IT ON A SYSTEM WHERE THERE +ARE ACTUAL DATA. +YOU ARE THE ONLY RESPONSIBLE OF ANY DAMAGE CAUSED BY THE +USE OF THIS CODE! + +This being said, let's talk about serious things. + += Generalities == Main goals * based on runit-init + busybox; * code maintainable by a small group of persons; -* release-based, stable core with the possibility of having a more volatile user - environment (for desktops); -* POSIX portable binaries as much as possible; +* release-based, stable core with the possibility of having + a more volatile user environment (for desktops); +* use of POSIX portable binaries as much as possible; * read-only root; == Non goals * package everything; * being generic; -* being lightweight (but it might be the result of real goals); +* being lightweight (but simplicity might result in that); -== Dependencies +== Installer dependencies * busybox * debootstrap * xorriso (if willing to build an iso) -* fakechroot (for non-root usage, fakeroot-ng might be supporter too, some day) + +TODO: +* fakechroot, to allow installing without being root == Usage ./install.sh [TARGET] [SOURCE] -TARGET: file where the installation will be done. Must either be an -existing file (block file or normal file with fixed allocated size) or -non-existing folder. -If TARGET does not exists, a folder will be created, and installation -will proceed in it. +TARGET: file where the installation will be done. Must +either be an existing file (block file or normal file with +fixed allocated size) or non-existing folder. +If TARGET does not exists, a folder will be created, and +installation will proceed in it. + +SOURCE: folder where instructions to build the system will +be found. -SOURCE: folder where instructions to build the system will be found. += A more in-depth view == Resulting system -The script enforces some particularities that can currently not be -changed (whithout hacking it): +This script is mostly tested to generate systems which have +those caracteristics, but should work with other setups too: * syslinux is used for boot management; -* a GPT partition system *must* be used; -* the boot partition *must* have the partition label "BOOTLOADER"; +* a GPT partition system is used; +* the boot partition have the partition label "BOOTLOADER"; * "BOOTLOADER" will be a vfat partition; +* the resulting system is encrypted; == Modifying defaults -The script should be built to facilitate configuration changes. -Thus, it fetches it configuration from a subfolder named 'src'. In -practice, most of this folder is simply copied to target, except for -the following: - -* src/partitions -* src/users -* src/users.d/* -* src/pkglist.d/* -* src/encryption.d/* - -=== src/partitions - -This file describes the partitions to build, it is fed into sfdisk. -etc/fstab is used to determine where the system will be installed, so -be certain to have a way to have a way to link those informations. - -If absent, the script will attempt to create a chroot (this, for now, -imply it needs root rights) in a new folder named (for now) 'distro'. -If the script cannot create the folder or does not run as root, it will -fail. - -=== src/users and src/users.d - -This file describes the users to create, their passwords and their -groups. Passwords are clear-text, so you might want to pre-configure -something to force or encourage the final user to fix that. -Except for the user "root" (which is always created, without password -if none was speficied): - -* a $HOME directory will be created; -* if src/users.d/$USER/ exists, it will be used as the --skel parameter - of useradd; -* a group will be created and the user will be added to it; - -Currently, the groups *must* exist before the users are created. They -can be created by the package selection you provided. - -Syntax is: -USER:PASSWORD:GROUP_1:GROUP_2:...:GROUP_N - -TODO: create groups before creating users if those does not exists yet - -=== src/pkglist.d/* - -The concatenation of the files here is used as a package list. - -=== src/encryption.d/* - -This folder contains files named after an existing partition. Those -files must define following variables: - -* CIPHER -* KEY_SIZE -* KEY_PASS -* HASH_TYPE -* FILE_SYSTEM - -Those variables are provided to cryptsetup like this: -`echo $KEY_PASS | cryptsetup -v -c $CIPHER -s $KEY_SIZE -h $HASH_TYPE luksFormat $PARTITION -` +The script is built to make changes easy while being able +to perform a full installation. +It works mostly by the use of a template $TARGET/root/etc +folder containing the traditional UNIX folder and files +hierarchy, which are parsed to guess the what the resulting +installation should looks like. + +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); +* "syslinux/*": a folder containing syslinux's configuration + to boot TARGET after installation; + MULTIPLE BOOTS SUPPORT NOT IMPLEMENTED! +* fsboot: a file describing the partition where and how + syslinux will be installed (formated after fstab done). + Format: "PARTITION FSTYPE SUBFOLDER"; +* "*.key": when encryption is required (presence of + TARGET/etc/crypttab, all encrypted partitions with the + "none" keyfile must have a file named MAPPED_DEVICE.key + to initialize the encryption; +* "packages/*.list": a folder with files containing the + list of packages to install on target system; +* proxy: an optional file containing proxy parameters (to + speed up installations); +* name: a file containing the of the distribution to install; +* users/users: a file containing informations for user + creation. Format: "USER:PASSWORD" + +=== Limitations + +The script have several limitations, for various reasons. +Some of them are listed here: + +* in /etc/fstab, lines will be considered listing a special + filesystem if it *does not* match this regex: "^[#^ =/]+". + If the 1st field does not match, the script *will* try to + format the partition to correct filesystem type. + This means comments are not supported (for now). + This also means that those names *must exist* before + formating. +* in /etc/cryptab, the format supported is the one supported + by Debian 10 "Buster", for initramfs and SysVinit (*not* + the specific crap systemd *again* reimplement). + Also, the last field is modified by adding '--' before + option names and replacing ',' with ' '. + Finally, only LUKS is supported. +* the name of the distribution to install must be known by + the debootstrap program. +* syslinux is not automatically adjusted with luks + parameters. +* syslinux will not automatically install on TARGET, this + 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). diff --git a/install.sh b/install.sh @@ -0,0 +1,167 @@ +#!/bin/sh -e + +MUST_DIE=0 +die() +{ + echo -e "\e[31m$@\e[0m" + exit 1 +} + +error() +{ + echo -e "\e[31m$@\e[0m" + MUST_DIE=1 +} + +warn() +{ + echo -e "\e[33m$@\e[0m" +} + +info() +{ + echo -e "\e[36m$@\e[0m" +} + +success() +{ + echo -e "\e[32m$@\e[0m" +} + +TARGET="${1:?"TARGET must be provided as 1st arg"}" +SOURCE="${2:?"SOURCE must be provided as 2nd arg"}" + +test -d "$TARGET" -a "$(find "$TARGET" -type f | wc -l)" -eq 0 && + 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" +test -b "$TARGET" -o -f "$TARGET" -o -d "$TARGET" || + error "invalid TARGET ($TARGET) type" +test -d "$SOURCE" || + error "SOURCE ($SOURCE) should be a folder" +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 +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" + info "start partitioning" + sfdisk "$TARGET" < "$part_file" + info "partitioning done" + info "syncing disks... or udev, dunno... artificial sleep sorry." + sync + sleep 10 + info "syncing done" + + ## encryption + crypttab="$SOURCE/root/etc/crypttab" + if test -f "$crypttab" + then + info "encrypting partitions" + PKG_LIST="cryptsetup-initramfs,cryptsetup-bin,cryptsetup-run,$PKG_LIST" + while read mapped_dev dev keyfile params + do + if test "$keyfile" = "none" + then + keyfile="$mapped_dev.key" + 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" + 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 +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" + +## template installation +info "installing template" +cp -ar "$SOURCE/root/*" "$TARGET" +info "template installation done" + +## bootstrap +PKG_LIST="$(cat $SOURCE/packages/*.list),PKG_LIST" +info "preparing to install $PKG_LIST" +debootstrap --no-merged-usr --variant=minbase "--include=$PKG_LIST" $(cat $SOURCE/name) "$TARGET" +info "install done" + +info "users creation" +for user in $(cut -d: -f1 "$SOURCE/users") +do + if test -d "$SOURCE/users.d/$user" + then + SKEL_DIR="-k $SOURCE/users.d/$user" + fi + + test "$user" = "root" || useradd -R "$TARGET" -m $SKEL_DIR +done +chpassw -R "$TARGET" < "$SOURCE/users" +info "users creation done" + +info "finishing syslinux installation" +if test -n "$parttype" +then +fi +info "finishing syslinux installation done" + +## installing syslinux setup +if test -n "$syslinux_target" +then +info "unmounting partitions" + mount "$syslinux_target" "$TARGET" + cp -ar "$boot_dir" "$TARGET" +fi + +### cleaning up +## unmount +info "unmounting partitions" +for mnt in $(findmnt -n -R -oTARGET -M $TARGET -l | tac) +do + umount $mnt +done +info "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" +fi