diff --git a/README.md b/README.md index 15cc5fbc..dec0a198 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,9 @@ Voidvault Last tested | ISO | Result ----------- | --------------------------------------------------------------- | ------ -2018-12-01 | [void-live-x86_64-20181111.iso][void-live-iso-x86_64-glibc] | PASS -2018-12-01 | [void-live-x86_64-musl-20181111.iso][void-live-iso-x86_64-musl] | PASS -2018-12-01 | [void-live-i686-20181111.iso][void-live-iso-i686-glibc] | PASS +2019-01-12 | [void-live-x86_64-20181111.iso][void-live-iso-x86_64-glibc] | PASS +2019-01-12 | [void-live-x86_64-musl-20181111.iso][void-live-iso-x86_64-musl] | FAIL +2019-01-12 | [void-live-i686-20181111.iso][void-live-iso-i686-glibc] | PASS Bootstrap Void with FDE @@ -16,7 +16,7 @@ Description ### Overview -Voidvault bootstraps Void with whole system Btrfs on LUKS. +Voidvault bootstraps Void with whole system NILFS+LVM on LUKS. Voidvault works on Void with Intel or AMD x86 CPU. It assumes you are comfortable working on the cmdline, and that you have no need for booting @@ -27,7 +27,7 @@ could cause catastrophic data loss and system instability. ### Features -- whole system Btrfs on LUKS, including encrypted `/boot` +- whole system [NILFS][NILFS]+LVM on LUKS, including encrypted `/boot` - [runit][runit] PID 1 - [GPT][GPT] partitioning - no swap partition, uses [zram][zram] via [zramen][zramen] @@ -68,6 +68,7 @@ could cause catastrophic data loss and system instability. - uses mq-deadline I/O scheduler for SSDs, BFQ for HDDs (see: [resources/etc/udev/rules.d/60-io-schedulers.rules](resources/etc/udev/rules.d/60-io-schedulers.rules)) - enables runit service for dnscrypt-proxy, nftables and socklog +- configures [nilfs_cleanerd][nilfs_cleanerd] to reduce overhead - configures [Xorg][Xorg], but does not install any Xorg packages (see: [resources/etc/X11](resources/etc/X11)) - optionally disables IPv6, and makes IPv4-only adjustments to dhcpcd, @@ -77,27 +78,23 @@ could cause catastrophic data loss and system instability. - `/dev/sdX1` is the BIOS boot sector (size: 2MB) - `/dev/sdX2` is the EFI system partition (size: [550MB][550MB]) -- `/dev/sdX3` is the root Btrfs filesystem on LUKS (size: remainder) - -Voidvault creates the following Btrfs subvolumes with a [flat layout][flat -layout]: - -Subvolume name | Mounting point ---- | --- -`@` | `/` -`@boot` | `/boot` -`@home` | `/home` -`@opt` | `/opt` -`@srv` | `/srv` -`@var` | `/var` -`@var-cache-xbps` | `/var/cache/xbps` -`@var-log` | `/var/log` -`@var-opt` | `/var/opt` -`@var-spool` | `/var/spool` -`@var-tmp` | `/var/tmp` - -Voidvault [disables Btrfs CoW][disables Btrfs CoW] on `/home`, `/srv`, -`/var/log`, `/var/spool` and `/var/tmp`. +- `/dev/sdX3` is the root NILFS+LVM filesystem on LUKS (size: remainder) + +Voidvault creates the following LVM logical volumes: + +Logical Volume name | Mounting point | Sizing +--- | --- | --- +`root` | `/` | `7G` +`boot` | `/boot` | `700M` +`opt` | `/opt` | `200M` +`srv` | `/srv` | `200M` +`var` | `/var` | `1G` +`var-cache-xbps` | `/var/cache/xbps` | `2G` +`var-log` | `/var/log` | `200M` +`var-opt` | `/var/opt` | `200M` +`var-spool` | `/var/spool` | `200M` +`var-tmp` | `/var/tmp` | `800M` +`home` | `/home` | `100%FREE` Voidvault mounts directories `/srv`, `/tmp`, `/var/log`, `/var/spool` and `/var/tmp` with options `nodev,noexec,nosuid`. @@ -143,6 +140,7 @@ VOIDVAULT_ROOT_PASS="your root password" VOIDVAULT_ROOT_PASS_HASH='$6$rounds=700000$xDn3UJKNvfOxJ1Ds$YEaaBAvQQgVdtV7jFfVnwmh57Do1awMh8vTBtI1higrZMAXUisX2XKuYbdTcxgQMleWZvK3zkSJQ4F3Jyd5Ln1' VOIDVAULT_VAULT_NAME="vault" VOIDVAULT_VAULT_PASS="your LUKS encrypted volume's password" +VOIDVAULT_POOL_NAME="vg0" VOIDVAULT_HOSTNAME="vault" VOIDVAULT_PARTITION="/dev/sdb" VOIDVAULT_PROCESSOR="other" @@ -171,6 +169,7 @@ voidvault --admin-name="live" \ --root-pass="your root password" \ --vault-name="vault" \ --vault-pass="your LUKS encrypted volume's password" \ + --pool-name="vg0" \ --hostname="vault" \ --partition="/dev/sdb" \ --processor="other" \ @@ -240,14 +239,6 @@ voidvault ls partitions voidvault ls timezones ``` -### `voidvault disable-cow` - -Disable the Copy-on-Write attribute for Btrfs directories. - -```sh -voidvault -r disable-cow dest/ -``` - Installation ------------ @@ -260,7 +251,6 @@ Dependencies Name | Provides | Included in Void ISO¹²? --- | --- | --- -btrfs-progs | Btrfs support | Y coreutils | `chmod`, `chown`, `cp`, `rm` | Y cryptsetup | FDE with LUKS | Y dosfstools | create VFAT filesystem for UEFI with `mkfs.vfat` | Y @@ -273,7 +263,9 @@ grub | FDE on `/boot`, `grub-mkpasswd-pbkdf2` | Y kbd | keymap data in `/usr/share/kbd/keymaps`, `setfont` | Y kmod | `modprobe` | Y libressl | user password salts | Y +lvm2 | LVM disk partitioning | N musl³ | libcrypt | Y +nilfs-utils | NILFS support | N procps-ng | `pkill` | Y rakudo | `voidvault` Perl 6 runtime | N tzdata | timezone data in `/usr/share/zoneinfo/zone.tab` | Y @@ -310,6 +302,7 @@ variable values for all configuration options aside from: - `--guest-pass` - `--hostname` - `--ignore-conf-repos` +- `--pool-name` - `--repository` - `--root-pass-hash` - `--root-pass` @@ -345,13 +338,13 @@ information, see http://unlicense.org/ or the accompanying UNLICENSE file. [550MB]: https://wiki.archlinux.org/index.php/EFI_system_partition#Create_the_partition [denies console login as root]: https://wiki.archlinux.org/index.php/Security#Denying_console_login_as_root -[disables Btrfs CoW]: https://wiki.archlinux.org/index.php/Btrfs#Disabling_CoW [dnscrypt-proxy]: https://wiki.archlinux.org/index.php/DNSCrypt -[flat layout]: https://btrfs.wiki.kernel.org/index.php/SysadminGuide#Layout [GPT]: https://wiki.archlinux.org/index.php/Partitioning#GUID_Partition_Table [GRUB]: https://wiki.archlinux.org/index.php/GRUB [hides process information]: https://wiki.archlinux.org/index.php/Security#hidepid [nftables]: https://wiki.archlinux.org/index.php/nftables +[NILFS]: https://nilfs.sourceforge.io/ +[nilfs_cleanerd]: https://news.ycombinator.com/item?id=18753858 [OpenSSH]: https://wiki.archlinux.org/index.php/Secure_Shell [runit]: https://wiki.voidlinux.org/runit [Sysctl]: https://wiki.archlinux.org/index.php/Sysctl diff --git a/bin/voidvault b/bin/voidvault index faa05d96..5daba236 100755 --- a/bin/voidvault +++ b/bin/voidvault @@ -10,33 +10,6 @@ use Voidvault::Utils; -# ----------------------------------------------------------------------------- -# disable-cow -# ----------------------------------------------------------------------------- - -multi sub MAIN( - 'disable-cow', - Bool :c(:$clean), - Str :g(:$group), - Str :p(:$permissions), - Bool :r(:$recursive), - Str :u(:$user), - *@directory - --> Nil -) -{ - my %opts; - %opts = $clean if $clean; - %opts = $group if $group; - %opts = $permissions if $permissions; - %opts = $recursive if $recursive; - %opts = $user if $user; - Voidvault::Utils.disable-cow(@directory, |%opts); -} - - - - # ----------------------------------------------------------------------------- # gen-pass-hash # ----------------------------------------------------------------------------- @@ -58,11 +31,6 @@ multi sub MAIN('gen-pass-hash', Bool :g(:$grub) --> Nil) # help # ----------------------------------------------------------------------------- -multi sub MAIN('help', 'disable-cow' --> Nil) -{ - USAGE('disable-cow'); -} - multi sub MAIN('help', 'gen-pass-hash' --> Nil) { USAGE('gen-pass-hash'); @@ -111,6 +79,7 @@ multi sub MAIN( Str :keymap($), Str :locale($), Str :partition($), + Str :pool-name($), Str :processor($), Str :repository($), Str :root-pass($), @@ -182,7 +151,6 @@ multi sub USAGE(--> Nil) voidvault Commands: - disable-cow Disable copy-on-write on directories gen-pass-hash Generate password hash help Show help for subcommands ls List keymaps, locales, partitions, timezones @@ -197,35 +165,6 @@ multi sub USAGE(--> Nil) say($HELP); } -multi sub USAGE('disable-cow' --> Nil) -{ - constant $HELP = qq:to/EOF/.trim; - Usage: - voidvault [--clean] - [--permissions=] - [--user=] - [--group=] - disable-cow [ ..] - voidvault [-r] disable-cow [ ..] - - Options: - -c, --clean - Remake directories with CoW disabled - -r, --recursive - Recursively disable CoW on directories - -p, --permissions= - Octal file mode bits (defaults to "755") - -u, --user= - Named user to own file (defaults to "$*USER") - -g, --group= - Named group to own file (defaults to "$*GROUP") - - Positionals: - Path to directory - EOF - say($HELP); -} - multi sub USAGE('gen-pass-hash' --> Nil) { constant $HELP = q:to/EOF/.trim; @@ -266,6 +205,7 @@ multi sub USAGE('new' --> Nil) [--grub-name=] [--grub-pass=] [--root-pass=] [--vault-name=] [--vault-pass=] + [--pool-name=] [--hostname=] [--partition=] [--processor=] [--graphics=] [--disk-type=] [--locale=] @@ -312,6 +252,8 @@ multi sub USAGE('new' --> Nil) Locale --partition= Partition target for install + --pool-name= + Name for LVM volume group --processor= Processor type --repository= diff --git a/doc/guides/btrfs-administration.md b/doc/guides/btrfs-administration.md deleted file mode 100644 index 18a15303..00000000 --- a/doc/guides/btrfs-administration.md +++ /dev/null @@ -1,181 +0,0 @@ -# Btrfs Administration - -## Setup - -```sh -# create base directories -mkdir -p /opt/{snapshots,subvolumes} -chmod 700 /opt/{snapshots,subvolumes} - -# create example-alpha subvolume -btrfs subvolume create /opt/subvolumes/example-alpha - -# mount example-alpha subvolume -_mount_opts+="compress=lzo," -_mount_opts+="noatime," -_mount_opts+="nodiratime," -_mount_opts+="rw," -_mount_opts+="space_cache," -_mount_opts+="ssd," -_mount_opts+="subvol=@opt/subvolumes/example-alpha" -mount -t btrfs -o "$_mount_opts" /dev/mapper/vault /home/admin/.example-alpha -chown -R admin:admin /home/admin/.example-alpha - -# add example-alpha subvolume mount to fstab -genfstab -U -p / | vipe -``` - -## Backup subvolumes - -```sh -# create read-only snapshot of example-alpha at time A -_snaptime_a="$(date '+%FT%H:%M')" -mkdir -p "/opt/snapshots/$_snaptime_a" -btrfs subvolume snapshot -r /opt/subvolumes/example-alpha "/opt/snapshots/$_snaptime_a" -sync - -# create read-only snapshot of example-alpha at time B -_snaptime_b="$(date '+%FT%H:%M')" -mkdir -p "/opt/snapshots/$_snaptime_b" -btrfs subvolume snapshot -r /opt/subvolumes/example-alpha "/opt/snapshots/$_snaptime_b" -sync - -# backup read-only incremental snapshot of example-alpha -btrfs send -p "/opt/snapshots/$_snaptime_a/example-alpha" "/opt/snapshots/$_snaptime_b/example-alpha" -``` - -```sh -MASTER_INTERFACE="enp4s0f2" -SLAVE_IPV6="fe80::6497:17de:fee3:1942" -SLAVE_USER_NAME="admin" - -# [master] snapshot example-alpha -_seconds_since_epoch="$(date --utc '+%s')" -_snapshot="example-alpha.snapshot.$_seconds_since_epoch" -btrfs subvolume snapshot -r /opt/subvolumes/example-alpha "/opt/snapshots/$_snapshot" -sync - -# [master] send/receive full example-alpha snapshot -btrfs send -v "/opt/snapshots/$_snapshot" \ - | ssh -T -i "/path/to/id_ed25519" \ - ${SLAVE_USER_NAME}@${SLAVE_IPV6}%${MASTER_INTERFACE} \ - "btrfs receive /opt/snapshots" - -# [master] save full example-alpha snapshot to file for sending -_snapshot_type="full" -_snapshot_file="$_snapshot.$_snapshot_type" -btrfs send -f "$_snapshot_file" "/opt/snapshots/$_snapshot" -sync -chown $USER:$USER "$_snapshot_file" - -# [master] rsync the full example-alpha snapshot file to slave -rsync \ - --dry-run \ - --recursive \ - --perms \ - --times \ - --partial \ - --inplace \ - --verbose \ - --human-readable \ - --progress \ - --itemize-changes \ - --itemize-changes \ - --rsh 'ssh -T -i /path/to/id_ed25519' \ - "$_snapshot_file" \ - ${SLAVE_USER_NAME}@[${SLAVE_IPV6}]:/home/staged/snapshots/$_snapshot_file - -# [slave] receive snapshot from file -btrfs receive -f "/home/staged/snapshots/$_snapshot_file" /opt/snapshots -rm "/home/staged/snapshots/$_snapshot_file" -sync - -# [slave] take rw snapshot of ro snapshot -btrfs subvolume snapshot "/opt/snapshots/$_snapshot" /opt/subvolumes/example-alpha -sync -``` - -```sh -#!/bin/bash - -MASTER_INTERFACE="enp4s0f2" -SLAVE_IPV6="fe80::6497:17de:fee3:1942" -SLAVE_USER_NAME="admin" - -# send / receive -ssh -T -i "$HOME/.ssh/box/id_ed25519" \ - ${SLAVE_USER_NAME}@${SLAVE_IPV6}%${MASTER_INTERFACE} \ - "btrfs send /opt/snapshots/$_snapshot" \ - | btrfs receive -v /opt/snapshots - -# incremental send / receive -ssh -T -i "$HOME/.ssh/box/id_ed25519" \ - ${SLAVE_USER_NAME}@${SLAVE_IPV6}%${MASTER_INTERFACE} \ - "btrfs send -p /opt/snapshots/$_snapshot_parent /opt/snapshots/$_snapshot" \ - | btrfs receive -v /opt/snapshots - -# syncing file -rsync \ - --dry-run \ - --recursive \ - --perms \ - --times \ - --partial \ - --inplace \ - --verbose \ - --human-readable \ - --progress \ - --itemize-changes \ - --itemize-changes \ - --rsh "ssh -T -i \"$HOME/.ssh/box/id_ed25519\"" \ - ${SLAVE_USER_NAME}@[${SLAVE_IPV6}%${MASTER_INTERFACE}]:/home/${SLAVE_USER_NAME}/${_snapshot_file} \ - "$HOME" -``` - -## Refresh snapshots - -```sh -#!/bin/bash - -# delete existing snapshots -# btrfs subvolume list / -# btrfs subvolume delete /opt/snapshots/... - -_seconds_since_epoch="$(date --utc '+%s')" -# refresh snapshots -for _name in example-alpha \ - example-bravo; do - _snapshot="$_name.snapshot.$_seconds_since_epoch" - sudo btrfs subvolume snapshot -r "/opt/subvolumes/$_name" "/opt/snapshots/$_snapshot" -done -sudo sync -``` - -## Restore from snapshot - -For when you have accidentally deleted `~/.example-alpha/important-file`. - -```sh -# unmount ~/.example-alpha -umount ~/.example-alpha - -# delete example-alpha subvolume -btrfs subvolume delete /opt/subvolumes/example-alpha - -# take rw snapshot of most recent example-alpha snapshot -btrfs subvolume snapshot "/opt/snapshots/example-alpha.snapshot.1476147345" /opt/subvolumes/example-alpha - -# retrieve subvolume ID of newly created example-alpha subvolume -btrfs subvolume list / -_NEW_ID=701 - -# the `mount` command, run as root, needs the absolute path to your `~` -_HOME="$HOME" - -# mount this new snapshot as example-alpha at ~/.example-alpha -# /dev/mapper/vault is root -mount -t btrfs -o rw,nodatacow,noatime,nodiratime,compress=lzo,ssd,space_cache,subvolid=$_NEW_ID,subvol=/@opt/subvolumes/example-alpha /dev/mapper/vault "$_HOME/.example-alpha" - -# update fstab (with `subvolid=$_NEW_ID`) -genfstab -U / -``` diff --git a/doc/guides/nilfs-lvm-administration.md b/doc/guides/nilfs-lvm-administration.md new file mode 100644 index 00000000..a33df717 --- /dev/null +++ b/doc/guides/nilfs-lvm-administration.md @@ -0,0 +1,126 @@ +# NILFS+LVM Administration + +## Create and mount new LVM logical volume + +```sh +# create lvm logical volume +lvcreate --name sandbox --extents 100%FREE vg0 + +# activate lvm logical volume +vgchange --activate y + +# format lvm logical volume +mkfs.nilfs2 -L sandbox /dev/vg0/sandbox + +# mount lvm logical volume +mkdir /path/to/sandbox +_mount_opts='rw,lazytime' +mount \ + --types nilfs2 \ + --options "$_mount_opts" \ + /dev/vg0/sandbox \ + /path/to/sandbox + +# add lvm logical volume mount to fstab (may require reboot to obtain UUID) +_uuid="$(blkid --match-tag UUID --output value /dev/vg0/sandbox)" +cat >> /etc/fstab <<"EOF" +# /dev/vg0/sandbox LABEL=sandbox +UUID=$_uuid /path/to/sandbox nilfs2 $_mount_opts 0 0 +EOF +``` + +## Resize LVM logical volume + +Shrink: + +```sh +# shrink NILFS to under target size +nilfs-resize /dev/vg0/srv 430M +# resize logical volume to target size +lvresize --size 500M vg0/srv +# grow NILFS without dimension to occupy all logical volume free space +nilfs-resize /dev/vg0/srv +``` + +Grow: + +```sh +# resize logical volume to target size +lvresize --size +2G vg0/srv +# grow NILFS without dimension to occupy all logical volume free space +nilfs-resize /dev/vg0/srv +``` + +Shrink and grow operations must be carried out on live, mounted NILFS +filesystems. They won't work otherwise. + +## Restore LVM logical volume from NILFS snapshot + +Take NILFS snapshot: + +```sh +mkcp --snapshot /dev/vg0/sandbox +``` + +Create and mount logical volume for holding data restored from NILFS +snapshot: + +```sh +lvcreate --name restore --extents 100%FREE vg0 +vgchange --activate y +mkfs.nilfs2 -L restore /dev/vg0/restore +mkdir /path/to/restore +mount \ + --types nilfs2 \ + --options 'rw,lazytime' \ + /dev/vg0/restore \ + /path/to/restore +``` + +Mount NILFS snapshot: + +```sh +mkdir /path/to/staging +# must mount snapshot read-only +mount \ + --types nilfs2 \ + --options 'cp=7,ro,lazytime' \ + /dev/vg0/sandbox \ + /path/to/staging +``` + +Conserve disk space by `rm -rf`ing the original contents after staging +contains read-only mount of snapshot. Do not destroy the original +filesystem (yet). + +Copy snapshotted contents: + +```sh +rsync \ + --recursive \ + --perms \ + --times \ + --partial \ + --inplace \ + --verbose \ + --human-readable \ + --progress \ + --itemize-changes \ + --itemize-changes \ + /path/to/staging/ \ + /path/to/restore +``` + +Unmount staging: + +``` +umount /path/to/staging +``` + +Securely delete original LVM logical volume: + +```sh +umount /path/to/sandbox +shred -fvz -n 7 /dev/vg0/sandbox +lvremove vg0/sandbox +``` diff --git a/examples/new-from-cli-passhash.sh b/examples/new-from-cli-passhash.sh index a1ad268a..147546bd 100755 --- a/examples/new-from-cli-passhash.sh +++ b/examples/new-from-cli-passhash.sh @@ -14,6 +14,7 @@ voidvault --admin-name='live' --root-pass-hash='$6$rounds=700000$xDn3UJKNvfOxJ1Ds$YEaaBAvQQgVdtV7jFfVnwmh57Do1awMh8vTBtI1higrZMAXUisX2XKuYbdTcxgQMleWZvK3zkSJQ4F3Jyd5Ln1' \ --vault-name='vault' \ --vault-pass='xyzzy' \ + --pool-name='vg0' \ --hostname='vault' \ --partition='/dev/sda' \ --processor='intel' \ diff --git a/examples/new-from-cli.sh b/examples/new-from-cli.sh index 4b5ff7f6..4778815a 100755 --- a/examples/new-from-cli.sh +++ b/examples/new-from-cli.sh @@ -13,6 +13,7 @@ voidvault --admin-name="live" \ --root-pass="your root password" \ --vault-name="vault" \ --vault-pass="your LUKS encrypted volume's password" \ + --pool-name="vg0" \ --hostname="vault" \ --partition="/dev/sdb" \ --processor="other" \ diff --git a/examples/new-from-env-vars-passhash.sh b/examples/new-from-env-vars-passhash.sh index 86299166..725a4845 100755 --- a/examples/new-from-env-vars-passhash.sh +++ b/examples/new-from-env-vars-passhash.sh @@ -14,6 +14,7 @@ export VOIDVAULT_GRUB_PASS_HASH='grub.pbkdf2.sha512.25000.4A7BC4FE022FA7E7D32B0B export VOIDVAULT_ROOT_PASS_HASH='$6$rounds=700000$xDn3UJKNvfOxJ1Ds$YEaaBAvQQgVdtV7jFfVnwmh57Do1awMh8vTBtI1higrZMAXUisX2XKuYbdTcxgQMleWZvK3zkSJQ4F3Jyd5Ln1' export VOIDVAULT_VAULT_NAME='vault' export VOIDVAULT_VAULT_PASS='xyzzy' +export VOIDVAULT_POOL_NAME='vg0' export VOIDVAULT_HOSTNAME='vault' export VOIDVAULT_PARTITION='/dev/sda' export VOIDVAULT_PROCESSOR='intel' diff --git a/examples/new-from-env-vars.sh b/examples/new-from-env-vars.sh index 95bc77d7..79cfeabd 100755 --- a/examples/new-from-env-vars.sh +++ b/examples/new-from-env-vars.sh @@ -13,6 +13,7 @@ export VOIDVAULT_GRUB_PASS="your grub user's password" export VOIDVAULT_ROOT_PASS="your root password" export VOIDVAULT_VAULT_NAME="vault" export VOIDVAULT_VAULT_PASS="your LUKS encrypted volume's password" +export VOIDVAULT_POOL_NAME="vg0" export VOIDVAULT_HOSTNAME="vault" export VOIDVAULT_PARTITION="/dev/sdb" export VOIDVAULT_PROCESSOR="other" diff --git a/lib/Voidvault.pm6 b/lib/Voidvault.pm6 index e2e6ee02..fcc8a3b4 100644 --- a/lib/Voidvault.pm6 +++ b/lib/Voidvault.pm6 @@ -25,6 +25,7 @@ method new( Str :keymap($), Str :locale($), Str :partition($), + Str :pool-name($), Str :processor($), Str :repository($), Str :root-pass($), diff --git a/lib/Voidvault/Bootstrap.pm6 b/lib/Voidvault/Bootstrap.pm6 index 52faa82e..af7ada0f 100644 --- a/lib/Voidvault/Bootstrap.pm6 +++ b/lib/Voidvault/Bootstrap.pm6 @@ -45,6 +45,7 @@ method bootstrap(::?CLASS:D: --> Nil) self!install-bootloader; self!configure-sysctl; self!configure-nftables; + self!configure-nilfs; self!configure-openssh; self!configure-udev; self!configure-hidepid; @@ -70,7 +71,6 @@ method !setup(--> Nil) # fetch dependencies needed prior to voidstrap my Str:D @dep = qw< - btrfs-progs coreutils cryptsetup dialog @@ -82,7 +82,10 @@ method !setup(--> Nil) grub kbd kmod + libnilfs libressl + lvm2 + nilfs-utils procps-ng tzdata util-linux @@ -163,8 +166,8 @@ multi sub build-xbps-install-dep-cmdline( # secure disk configuration method !mkdisk(--> Nil) { - my DiskType:D $disk-type = $.config.disk-type; my Str:D $partition = $.config.partition; + my PoolName:D $pool-name = $.config.pool-name; my VaultName:D $vault-name = $.config.vault-name; my VaultPass $vault-pass = $.config.vault-pass; @@ -181,14 +184,11 @@ method !mkdisk(--> Nil) Voidvault::Utils.gen-partition('vault', $partition); mkvault($partition-vault, $vault-name, :$vault-pass); - # create and mount btrfs volumes - mkbtrfs($disk-type, $vault-name); + # create and mount nilfs+lvm + mknilfslvm($pool-name, $vault-name); # mount efi boot mount-efi($partition-efi); - - # disable Btrfs CoW - disable-cow(); } # partition disk with gdisk @@ -441,38 +441,19 @@ multi sub build-cryptsetup-luks-open-cmdline( EOF } -# create and mount btrfs volumes on open vault -sub mkbtrfs(DiskType:D $disk-type, VaultName:D $vault-name --> Nil) +# create and mount nilfs+lvm structure on open vault +sub mknilfslvm(PoolName:D $pool-name, VaultName:D $vault-name --> Nil) { - # create btrfs filesystem on opened vault - run(qw); - run(qqw); - - # set mount options - my Str:D @mount-options = qw< - rw - lazytime - compress=lzo - space_cache - >; - push(@mount-options, 'ssd') if $disk-type eq 'SSD'; - my Str:D $mount-options = @mount-options.join(','); + # create lvm physical volume (pv) on open vault + run(qqw); - # mount main btrfs filesystem on open vault - mkdir('/mnt2'); - run(qqw< - mount - --types btrfs - --options $mount-options - /dev/mapper/$vault-name - /mnt2 - >); + # create lvm volume group (vg) hosting physical volume + run(qqw); - # btrfs subvolumes, starting with root / ('') - my Str:D @btrfs-dir = - '', + # logical volume (lv), deliberately custom ordered + my Str:D @lv = + 'root', 'boot', - 'home', 'opt', 'srv', 'var', @@ -480,148 +461,339 @@ sub mkbtrfs(DiskType:D $disk-type, VaultName:D $vault-name --> Nil) 'var-log', 'var-opt', 'var-spool', - 'var-tmp'; + 'var-tmp', + 'home'; + + # create lvm lvs + lvcreate(@lv, $pool-name); + + # activate lvm lvs + run(qw); + + # make nilfs on each lvm lv + mknilfs(@lv, $pool-name); - # create btrfs subvolumes - chdir('/mnt2'); - @btrfs-dir.map(-> Str:D $btrfs-dir { - run(qqw); + # mount nilfs lvm structure + mount-nilfslvm(@lv, $pool-name); +} + +multi sub lvcreate( + Str:D @lv, + PoolName:D $pool-name + --> Nil +) +{ + @lv.map(-> Str:D $lv { + lvcreate($lv, $pool-name); }); - chdir('/'); +} + +multi sub lvcreate( + Str:D $lv where 'root', + PoolName:D $pool-name + --> Nil +) +{ + # root (C) sized at 7G + my Str:D $size = '7G'; + lvcreate($lv, :$size, $pool-name); +} + +multi sub lvcreate( + Str:D $lv where 'boot', + PoolName:D $pool-name + --> Nil +) +{ + # boot (C) sized at 700M + my Str:D $size = '700M'; + lvcreate($lv, :$size, $pool-name); +} + +multi sub lvcreate( + Str:D $lv where 'opt', + PoolName:D $pool-name + --> Nil +) +{ + # opt (C) sized at 200M + my Str:D $size = '200M'; + lvcreate($lv, :$size, $pool-name); +} + +multi sub lvcreate( + Str:D $lv where 'srv', + PoolName:D $pool-name + --> Nil +) +{ + # srv (C) sized at 200M + my Str:D $size = '200M'; + lvcreate($lv, :$size, $pool-name); +} + +multi sub lvcreate( + Str:D $lv where 'var', + PoolName:D $pool-name + --> Nil +) +{ + # var (C) sized at 1G + my Str:D $size = '1G'; + lvcreate($lv, :$size, $pool-name); +} + +multi sub lvcreate( + Str:D $lv where 'var-cache-xbps', + PoolName:D $pool-name + --> Nil +) +{ + # var-cache-xbps (C) sized at 2G + my Str:D $size = '2G'; + lvcreate($lv, :$size, $pool-name); +} - # mount btrfs subvolumes - @btrfs-dir.map(-> Str:D $btrfs-dir { - mount-btrfs-subvolume($btrfs-dir, $mount-options, $vault-name); +multi sub lvcreate( + Str:D $lv where 'var-log', + PoolName:D $pool-name + --> Nil +) +{ + # var-log (C) sized at 200M + my Str:D $size = '200M'; + lvcreate($lv, :$size, $pool-name); +} + +multi sub lvcreate( + Str:D $lv where 'var-opt', + PoolName:D $pool-name + --> Nil +) +{ + # var-opt (C) sized at 200M + my Str:D $size = '200M'; + lvcreate($lv, :$size, $pool-name); +} + +multi sub lvcreate( + Str:D $lv where 'var-spool', + PoolName:D $pool-name + --> Nil +) +{ + # var-spool (C) sized at 200M + my Str:D $size = '200M'; + lvcreate($lv, :$size, $pool-name); +} + +multi sub lvcreate( + Str:D $lv where 'var-tmp', + PoolName:D $pool-name + --> Nil +) +{ + # var-tmp (C) sized at 800M + my Str:D $size = '800M'; + lvcreate($lv, :$size, $pool-name); +} + +multi sub lvcreate( + Str:D $lv where 'home', + PoolName:D $pool-name + --> Nil +) +{ + # home (C) sized at 100% of remaining free space in vg + my Str:D $extents = '100%FREE'; + lvcreate($lv, :$extents, $pool-name); +} + +multi sub lvcreate( + Str:D $name, + PoolName:D $pool-name, + Str:D :$extents! where .so + --> Nil +) +{ + run(qqw); +} + +multi sub lvcreate( + Str:D $name, + PoolName:D $pool-name, + Str:D :$size! where .so + --> Nil +) +{ + run(qqw); +} + +multi sub mknilfs(Str:D @lv, PoolName:D $pool-name --> Nil) +{ + run(qw); + @lv.map(-> Str:D $lv { + mknilfs($lv, $pool-name); }); +} + +multi sub mknilfs(Str:D $lv, PoolName:D $pool-name --> Nil) +{ + run(qqw); +} + +multi sub mount-nilfslvm( + Str:D @lv, + PoolName:D $pool-name + --> Nil +) +{ + @lv.map(-> Str:D $lv { + mount-nilfslvm($lv, $pool-name); + }); +} + +multi sub mount-nilfslvm( + Str:D $lv where 'root', + PoolName:D $pool-name + --> Nil +) +{ + # set mount options + my Str:D $mount-options = 'rw,lazytime'; - # unmount /mnt2 and remove - run(qw); - rmdir('/mnt2'); + # mount nilfs+lvm root on open vault + run(qqw< + mount + --types nilfs2 + --options $mount-options + /dev/$pool-name/$lv + /mnt + >); } -multi sub mount-btrfs-subvolume( - 'srv', - Str:D $mount-options, - VaultName:D $vault-name +multi sub mount-nilfslvm( + Str:D $lv where 'srv', + PoolName:D $pool-name --> Nil ) { - my Str:D $btrfs-dir = 'srv'; - mkdir("/mnt/$btrfs-dir"); + mkdir("/mnt/$lv"); + my Str:D $mount-options = 'rw,lazytime,nodev,noexec,nosuid'; run(qqw< mount - --types btrfs - --options $mount-options,nodev,noexec,nosuid,subvol=@$btrfs-dir - /dev/mapper/$vault-name - /mnt/$btrfs-dir + --types nilfs2 + --options $mount-options + /dev/$pool-name/$lv + /mnt/$lv >); } -multi sub mount-btrfs-subvolume( - 'var-cache-xbps', - Str:D $mount-options, - VaultName:D $vault-name +multi sub mount-nilfslvm( + Str:D $lv where 'var-cache-xbps', + PoolName:D $pool-name --> Nil ) { - my Str:D $btrfs-dir = 'var/cache/xbps'; - mkdir("/mnt/$btrfs-dir"); + my Str:D $dir = $lv.subst('-', '/', :g); + mkdir("/mnt/$dir"); + my Str:D $mount-options = 'rw,lazytime'; run(qqw< mount - --types btrfs - --options $mount-options,subvol=@var-cache-xbps - /dev/mapper/$vault-name - /mnt/$btrfs-dir + --types nilfs2 + --options $mount-options + /dev/$pool-name/$lv + /mnt/$dir >); } -multi sub mount-btrfs-subvolume( - 'var-log', - Str:D $mount-options, - VaultName:D $vault-name +multi sub mount-nilfslvm( + Str:D $lv where 'var-log', + PoolName:D $pool-name --> Nil ) { - my Str:D $btrfs-dir = 'var/log'; - mkdir("/mnt/$btrfs-dir"); + my Str:D $dir = $lv.subst('-', '/', :g); + mkdir("/mnt/$dir"); + my Str:D $mount-options = 'rw,lazytime,nodev,noexec,nosuid'; run(qqw< mount - --types btrfs - --options $mount-options,nodev,noexec,nosuid,subvol=@var-log - /dev/mapper/$vault-name - /mnt/$btrfs-dir + --types nilfs2 + --options $mount-options + /dev/$pool-name/$lv + /mnt/$dir >); } -multi sub mount-btrfs-subvolume( - 'var-opt', - Str:D $mount-options, - VaultName:D $vault-name +multi sub mount-nilfslvm( + Str:D $lv where 'var-opt', + PoolName:D $pool-name --> Nil ) { - my Str:D $btrfs-dir = 'var/opt'; - mkdir("/mnt/$btrfs-dir"); + my Str:D $dir = $lv.subst('-', '/', :g); + mkdir("/mnt/$dir"); + my Str:D $mount-options = 'rw,lazytime'; run(qqw< mount - --types btrfs - --options $mount-options,subvol=@var-opt - /dev/mapper/$vault-name - /mnt/$btrfs-dir + --types nilfs2 + --options $mount-options + /dev/$pool-name/$lv + /mnt/$dir >); } -multi sub mount-btrfs-subvolume( - 'var-spool', - Str:D $mount-options, - VaultName:D $vault-name +multi sub mount-nilfslvm( + Str:D $lv where 'var-spool', + PoolName:D $pool-name --> Nil ) { - my Str:D $btrfs-dir = 'var/spool'; - mkdir("/mnt/$btrfs-dir"); + my Str:D $dir = $lv.subst('-', '/', :g); + mkdir("/mnt/$dir"); + my Str:D $mount-options = 'rw,lazytime,nodev,noexec,nosuid'; run(qqw< mount - --types btrfs - --options $mount-options,nodev,noexec,nosuid,subvol=@var-spool - /dev/mapper/$vault-name - /mnt/$btrfs-dir + --types nilfs2 + --options $mount-options + /dev/$pool-name/$lv + /mnt/$dir >); } -multi sub mount-btrfs-subvolume( - 'var-tmp', - Str:D $mount-options, - VaultName:D $vault-name +multi sub mount-nilfslvm( + Str:D $lv where 'var-tmp', + PoolName:D $pool-name --> Nil ) { - my Str:D $btrfs-dir = 'var/tmp'; - mkdir("/mnt/$btrfs-dir"); + my Str:D $dir = $lv.subst('-', '/', :g); + mkdir("/mnt/$dir"); + my Str:D $mount-options = 'rw,lazytime,nodev,noexec,nosuid'; run(qqw< mount - --types btrfs - --options $mount-options,nodev,noexec,nosuid,subvol=@var-tmp - /dev/mapper/$vault-name - /mnt/$btrfs-dir + --types nilfs2 + --options $mount-options + /dev/$pool-name/$lv + /mnt/$dir >); - run(qqw); + run(qqw); } -multi sub mount-btrfs-subvolume( - Str:D $btrfs-dir, - Str:D $mount-options, - VaultName:D $vault-name +multi sub mount-nilfslvm( + Str:D $lv, + PoolName:D $pool-name --> Nil ) { - mkdir("/mnt/$btrfs-dir"); + my Str:D $mount-options = 'rw,lazytime'; + mkdir("/mnt/$lv"); run(qqw< mount - --types btrfs - --options $mount-options,subvol=@$btrfs-dir - /dev/mapper/$vault-name - /mnt/$btrfs-dir + --types nilfs2 + --options $mount-options + /dev/$pool-name/$lv + /mnt/$lv >); } @@ -632,18 +804,6 @@ sub mount-efi(Str:D $partition-efi --> Nil) run(qqw); } -sub disable-cow(--> Nil) -{ - my Str:D @directory = qw< - home - srv - var/log - var/spool - var/tmp - >.map(-> Str:D $directory { sprintf(Q{/mnt/%s}, $directory) }); - Voidvault::Utils.disable-cow(|@directory, :recursive); -} - # bootstrap initial chroot with voidstrap method !voidstrap-base(--> Nil) { @@ -671,7 +831,6 @@ method !voidstrap-base(--> Nil) bash bash-completion binutils - btrfs-progs bzip2 ca-certificates cdrtools @@ -717,6 +876,7 @@ method !voidstrap-base(--> Nil) linux-firmware linux-firmware-network logrotate + lvm2 lynx lz4 man-db @@ -725,6 +885,7 @@ method !voidstrap-base(--> Nil) ncurses-term net-tools nftables + nilfs-utils openresolv openssh pciutils @@ -1166,10 +1327,18 @@ method !install-bootloader(--> Nil) my Str:D $partition = $.config.partition; my Str:D $partition-vault = Voidvault::Utils.gen-partition('vault', $partition); + my PoolName:D $pool-name = $.config.pool-name; my UserName:D $user-name-grub = $.config.user-name-grub; my Str:D $user-pass-hash-grub = $.config.user-pass-hash-grub; my VaultName:D $vault-name = $.config.vault-name; - replace('grub', $disable-ipv6, $graphics, $partition-vault, $vault-name); + replace( + 'grub', + $disable-ipv6, + $graphics, + $partition-vault, + $pool-name, + $vault-name + ); replace('10_linux'); configure-bootloader('superusers', $user-name-grub, $user-pass-hash-grub); install-bootloader($partition); @@ -1301,6 +1470,11 @@ method !configure-nftables(--> Nil) }); } +method !configure-nilfs(--> Nil) +{ + replace('nilfs_cleanerd.conf'); +} + method !configure-openssh(--> Nil) { my Bool:D $disable-ipv6 = $.config.disable-ipv6; @@ -1461,12 +1635,14 @@ method !unmount(--> Nil) # C fails initially on void, resume after error CATCH { default { .resume } }; run(qw); + run(qw); run(qqw); # print instructions for manual cleanup my Str:D $msg = qq:to/EOF/.trim; Manual cleanup after `voidvault new` is recommended [1]: # umount -R /mnt + # vgchange --activate n # cryptsetup luksClose $vault-name [1]: https://github.com/atweiden/voidvault/blob/master/doc/TODO.md @@ -2036,10 +2212,10 @@ multi sub replace( # drivers are C<*.ko*> files in C my Str:D @driver = qw< ahci - btrfs libcrc32c lz4 lz4_compress + nilfs2 >; push(@driver, 'crc32c-intel') if $processor eq 'INTEL'; push(@driver, 'i915') if $graphics eq 'INTEL'; @@ -2058,9 +2234,9 @@ multi sub replace( my Str:D $file = sprintf(Q{/mnt/etc/dracut.conf.d/%s.conf}, $subject); # modules are found in C my Str:D @module = qw< - btrfs crypt kernel-modules + lvm >; my Str:D $replace = sprintf(Q{%s=" %s "}, $subject, @module.join(' ')); spurt($file, $replace ~ "\n"); @@ -2112,6 +2288,7 @@ multi sub replace( Bool:D $disable-ipv6, Graphics:D $graphics, Str:D $partition-vault, + PoolName:D $pool-name, VaultName:D $vault-name ) --> Nil @@ -2125,7 +2302,8 @@ multi sub replace( ==> replace('grub', 'GRUB_DISABLE_RECOVERY') ==> replace('grub', 'GRUB_ENABLE_CRYPTODISK') ==> replace('grub', 'GRUB_TERMINAL_INPUT') - ==> replace('grub', 'GRUB_TERMINAL_OUTPUT'); + ==> replace('grub', 'GRUB_TERMINAL_OUTPUT') + ==> replace('grub', 'GRUB_PRELOAD_MODULES'); my Str:D $replace = @replace.join("\n"); spurt($file, $replace ~ "\n"); } @@ -2136,6 +2314,7 @@ multi sub replace( Bool:D $disable-ipv6, Graphics:D $graphics, Str:D $partition-vault, + PoolName:D $pool-name, VaultName:D $vault-name, Str:D @line --> Array[Str:D] @@ -2145,11 +2324,12 @@ multi sub replace( my Str:D $vault-uuid = qqx.trim; my Str:D @grub-cmdline-linux = qqw< - rootflags=subvol=@ rd.auto=1 rd.luks=1 rd.luks.name=$vault-uuid=$vault-name rd.luks.uuid=$vault-uuid + dolvm + root=/dev/$pool-name/root loglevel=6 >; # enable slub/slab allocator free poisoning (needs CONFIG_SLUB_DEBUG=y) @@ -2241,6 +2421,21 @@ multi sub replace( @line; } +multi sub replace( + 'grub', + Str:D $subject where 'GRUB_PRELOAD_MODULES', + Str:D @line + --> Array[Str:D] +) +{ + # if C not found, append to bottom of file + my UInt:D $index = @line.first(/^'#'?$subject/, :k) // @line.elems; + # preload lvm module + my Str:D $replace = sprintf(Q{%s="lvm"}, $subject); + @line[$index] = $replace; + @line; +} + # --- end grub }}} # --- 10_linux {{{ @@ -2389,6 +2584,98 @@ multi sub replace( } # --- end 99-sysctl.conf }}} +# --- nilfs_cleanerd.conf {{{ + +multi sub replace( + 'nilfs_cleanerd.conf' + --> Nil +) +{ + my Str:D $file = '/mnt/etc/nilfs_cleanerd.conf'; + my Str:D @replace = + $file.IO.lines + # do continuous cleaning + ==> replace('nilfs_cleanerd.conf', 'min_clean_segments') + # increase maximum number of clean segments + ==> replace('nilfs_cleanerd.conf', 'max_clean_segments') + # decrease clean segment check interval + ==> replace('nilfs_cleanerd.conf', 'clean_check_interval') + # decrease cleaning interval + ==> replace('nilfs_cleanerd.conf', 'cleaning_interval') + # increase minimum number of reclaimable blocks in a segment + # before it can be cleaned + ==> replace('nilfs_cleanerd.conf', 'min_reclaimable_blocks'); + my Str:D $replace = @replace.join("\n"); + spurt($file, $replace ~ "\n"); +} + +multi sub replace( + 'nilfs_cleanerd.conf', + Str:D $subject where 'min_clean_segments', + Str:D @line + --> Array[Str:D] +) +{ + my UInt:D $index = @line.first(/^$subject/, :k); + my Str:D $replace = sprintf(Q{%s 0}, $subject); + @line[$index] = $replace; + @line; +} + +multi sub replace( + 'nilfs_cleanerd.conf', + Str:D $subject where 'max_clean_segments', + Str:D @line + --> Array[Str:D] +) +{ + my UInt:D $index = @line.first(/^$subject/, :k); + # double C<%> symbol is quirk of sprintf syntax for C<90%> + my Str:D $replace = sprintf(Q{%s 90%%}, $subject); + @line[$index] = $replace; + @line; +} + +multi sub replace( + 'nilfs_cleanerd.conf', + Str:D $subject where 'clean_check_interval', + Str:D @line + --> Array[Str:D] +) +{ + my UInt:D $index = @line.first(/^$subject/, :k); + my Str:D $replace = sprintf(Q{%s 2}, $subject); + @line[$index] = $replace; + @line; +} + +multi sub replace( + 'nilfs_cleanerd.conf', + Str:D $subject where 'cleaning_interval', + Str:D @line + --> Array[Str:D] +) +{ + my UInt:D $index = @line.first(/^$subject/, :k); + my Str:D $replace = sprintf(Q{%s 2}, $subject); + @line[$index] = $replace; + @line; +} + +multi sub replace( + 'nilfs_cleanerd.conf', + Str:D $subject where 'min_reclaimable_blocks', + Str:D @line + --> Array[Str:D] +) +{ + my UInt:D $index = @line.first(/^$subject/, :k); + my Str:D $replace = sprintf(Q{%s 60%%}, $subject); + @line[$index] = $replace; + @line; +} + +# --- end nilfs_cleanerd.conf }}} # --- sshd_config {{{ multi sub replace( diff --git a/lib/Voidvault/Config.pm6 b/lib/Voidvault/Config.pm6 index 1d230e03..36e33002 100644 --- a/lib/Voidvault/Config.pm6 +++ b/lib/Voidvault/Config.pm6 @@ -103,6 +103,12 @@ has VaultPass $.vault-pass = ?? Voidvault::Config.gen-vault-pass(%*ENV) !! Nil; +# name for LVM volume group (default: vg0) +has PoolName:D $.pool-name = + %*ENV + ?? Voidvault::Config.gen-pool-name(%*ENV) + !! prompt-name(:pool); + # name for host (default: vault) has HostName:D $.host-name = %*ENV @@ -182,6 +188,7 @@ submethod BUILD( Str :$keymap, Str :$locale, Str :$partition, + Str :$pool-name, Str :$processor, Str :$repository, Str :$root-pass, @@ -213,6 +220,8 @@ submethod BUILD( if $locale; $!partition = $partition if $partition; + $!pool-name = Voidvault::Config.gen-pool-name($pool-name) + if $pool-name; $!processor = Voidvault::Config.gen-processor($processor) if $processor; $!repository = $repository @@ -273,6 +282,7 @@ method new( Str :keymap($), Str :locale($), Str :partition($), + Str :pool-name($), Str :processor($), Str :repository($), Str :root-pass($), @@ -325,6 +335,12 @@ method gen-locale(Str:D $l --> Locale:D) my Locale:D $locale = $l or die("Sorry, invalid locale 「$l」"); } +# confirm pool name $p is valid PoolName and return PoolName +method gen-pool-name(Str:D $p --> PoolName:D) +{ + my PoolName:D $pool-name = $p or die("Sorry, invalid pool name 「$p」"); +} + # confirm processor $p is valid Processor and return Processor method gen-processor(Str:D $p --> Processor:D) { @@ -629,6 +645,30 @@ multi sub prompt-name( } } +multi sub prompt-name( + Bool:D :pool($)! where .so + --> PoolName:D +) +{ + my PoolName:D $pool-name = do { + my PoolName:D $response-default = 'vg0'; + my Str:D $prompt-text = "Enter pool name [$response-default]: "; + my Str:D $help-text = q:to/EOF/.trim; + Determining name of LVM volume group... + + Cannot be named the same as vault. Name should be unique in /dev/. + + Leave blank if you don't know what this is + EOF + tprompt( + PoolName, + $response-default, + :$prompt-text, + :$help-text + ); + } +} + multi sub prompt-name( Bool:D :user($)! where .so, Bool:D :admin($)! where .so diff --git a/lib/Voidvault/Grammar.pm6 b/lib/Voidvault/Grammar.pm6 index 9879cbe8..67120443 100644 --- a/lib/Voidvault/Grammar.pm6 +++ b/lib/Voidvault/Grammar.pm6 @@ -38,6 +38,21 @@ regex host-name $ } +# LVM volume group name validation +token pool-name +{ + # from `man 8 lvm` line 136: + # - VG name can only contain valid chars: A-Z a-z 0-9 + _ . - + # - VG name cannot begin with a hyphen + # - VG name cannot be anything that exists in /dev/ at the time of creation + # - VG name cannot be `.` or `..` + ( + <+alnum +[+] +[_] +[\.]> + <+alnum +[+] +[_] +[\.] +[-]>* + ) + { $0 !~~ /^^ '.' ** 1..2 $$/ or fail } +} + # linux username validation regex user-name { diff --git a/lib/Voidvault/Types.pm6 b/lib/Voidvault/Types.pm6 index 01e6fdc2..ebc117af 100644 --- a/lib/Voidvault/Types.pm6 +++ b/lib/Voidvault/Types.pm6 @@ -1095,6 +1095,12 @@ subset LibcFlavor of Str is export where { @libc.grep($_) }; # locale subset Locale of Str is export where { %locales.keys.grep($_) }; +# LVM volume group name +subset PoolName of Str is export where +{ + Voidvault::Grammar.parse($_, :rule); +} + # processor subset Processor of Str is export where { %processors.keys.grep($_) }; diff --git a/lib/Voidvault/Utils.pm6 b/lib/Voidvault/Utils.pm6 index 16bdc45e..e59e794f 100644 --- a/lib/Voidvault/Utils.pm6 +++ b/lib/Voidvault/Utils.pm6 @@ -25,91 +25,6 @@ constant $PBKDF2-LENGTH-HASH = 100; constant $PBKDF2-LENGTH-SALT = 100; -# ----------------------------------------------------------------------------- -# copy-on-write -# ----------------------------------------------------------------------------- - -method disable-cow( - *%opt ( - Bool :clean($), - Bool :recursive($), - Str :permissions($), - Str :user($), - Str :group($) - ), - *@directory - --> Nil -) -{ - # https://wiki.archlinux.org/index.php/Btrfs#Disabling_CoW - @directory.map(-> Str:D $directory { disable-cow($directory, |%opt) }); -} - -multi sub disable-cow( - Str:D $directory, - Bool:D :clean($)! where .so, - # ignored, recursive is implied with :clean - Bool :recursive($), - Str:D :$permissions = '755', - Str:D :$user = $*USER, - Str:D :$group = $*GROUP - --> Nil -) -{ - my Str:D $orig-dir = ~$directory.IO.resolve; - $orig-dir.IO.e && $orig-dir.IO.r && $orig-dir.IO.d - or die('directory failed exists readable directory test'); - my Str:D $backup-dir = sprintf(Q{%s-old}, $orig-dir); - rename($orig-dir, $backup-dir); - mkdir($orig-dir); - run(qqw); - run(qqw); - run(qqw); - dir($backup-dir).map(-> IO::Path:D $file { - run(qqw< - cp - --no-dereference - --preserve=links,mode,ownership,timestamps - $file - $orig-dir - >); - }); - run(qqw); -} - -multi sub disable-cow( - Str:D $directory, - Bool :clean($), - Bool:D :recursive($)! where .so, - Str :permissions($), - Str :user($), - Str :group($) - --> Nil -) -{ - my Str:D $orig-dir = ~$directory.IO.resolve; - $orig-dir.IO.e && $orig-dir.IO.r && $orig-dir.IO.d - or die('directory failed exists readable directory test'); - run(qqw); -} - -multi sub disable-cow( - Str:D $directory, - Bool :clean($), - Bool :recursive($), - Str :permissions($), - Str :user($), - Str :group($) - --> Nil -) -{ - my Str:D $orig-dir = ~$directory.IO.resolve; - $orig-dir.IO.e && $orig-dir.IO.r && $orig-dir.IO.d - or die('directory failed exists readable directory test'); - run(qqw); -} - - # ----------------------------------------------------------------------------- # password hashes # ----------------------------------------------------------------------------- diff --git a/scripts/mount-system.sh b/scripts/mount-system.sh index 90853ccc..b600199c 100755 --- a/scripts/mount-system.sh +++ b/scripts/mount-system.sh @@ -1,39 +1,49 @@ #!/bin/bash # ---------------------------------------------------------------------------- -# mount-system: mount voidvault btrfs subvolumes and efi partition +# mount-system: mount voidvault nilfs+lvm on luks and efi partition # ---------------------------------------------------------------------------- # instructions # - modify target partition (`_partition=/dev/sda`) as needed # - run `cryptsetup luksOpen /dev/sda3 vault` before running this script # setup -_btrfs_subvolumes=('' - 'boot' - 'home' - 'opt' - 'srv' - 'var' - 'var-cache-xbps' - 'var-log' - 'var-opt' - 'var-spool' - 'var-tmp') -# use lzo compression because grub does not yet support zstd -_compression='lzo' -_mount_options="rw,lazytime,compress=$_compression,space_cache" +_lvs=('boot' + 'opt' + 'srv' + 'var' + 'var-cache-xbps' + 'var-log' + 'var-opt' + 'var-spool' + 'var-tmp' + 'home') +_mount_options='rw,lazytime' _partition='/dev/sda' +_pool_name='vg0' _vault_name='vault' -# mount btrfs subvolumes starting with root ('') -for _btrfs_subvolume in "${_btrfs_subvolumes[@]}"; do - _btrfs_dir="${_btrfs_subvolume//-//}" - mkdir --parents "/mnt/$_btrfs_dir" +# activate lvm lvs +vgchange --activate y + +# mount root lv +mkdir --parents /mnt +mount \ + --types nilfs2 \ + --options "$_mount_options" \ + "/dev/$_pool_name/root" \ + /mnt + +# mount remaining lvs +for _lv in "${_lvs[@]}"; do + # replace hyphen in volume name with forward slash + _dir="${_lv//-//}" + mkdir --parents "/mnt/$_dir" mount \ - --types btrfs \ - --options "$_mount_options,subvol=@$_btrfs_subvolume" \ - "/dev/mapper/$_vault_name" \ - "/mnt/$_btrfs_dir" + --types nilfs2 \ + --options "$_mount_options" \ + "/dev/$_pool_name/$_lv" \ + "/mnt/$_dir" done # mount uefi boot partition diff --git a/scripts/umount-system.sh b/scripts/umount-system.sh index 2b0b6a82..018e9fa9 100755 --- a/scripts/umount-system.sh +++ b/scripts/umount-system.sh @@ -1,9 +1,19 @@ #!/bin/bash # ---------------------------------------------------------------------------- -# umount-system: unmount voidvault btrfs subvolumes and efi partition +# umount-system: unmount voidvault nilfs+lvm on luks and efi partition # ---------------------------------------------------------------------------- # instructions -# - run `cryptsetup luksClose vault` after running this script +# - modify vault name (`_vault_name='vault'`) as needed +# setup +_vault_name='vault' + +# unmount filesystems umount --recursive /mnt + +# deactivate lvm lvs +vgchange --activate n + +# close vault +cryptsetup luksClose "$_vault_name"