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