--- /dev/null
+# monosys
+
+Monorepo for system configuration.
+
set -xeu
sudo arch-nspawn /var/cache/pacman/chroot/root pacman -Syu
-makechrootpkg -c -l "$(basename "$PWD")" -T -r /var/cache/pacman/chroot
+makechrootpkg -c -l "$(basename "$PWD")" -T -r /var/cache/pacman/chroot -U pacman-builder
cd /var/cache/pacman/abs
tosign=()
-for pkg in *.pkg.tar.xz; do
+for pkg in *.pkg.*; do
+ if [[ "$pkg" =~ .*\.sig ]]; then
+ continue
+ fi
if ! [ -f "${pkg}.sig" ]; then
tosign+=("$pkg")
fi
fi
if is_arch; then
- checkupdates
+ checkupdates || true
fi
America/New_York
Europe/London
UTC
+Asia/Kolkata
Asia/Ho_Chi_Minh
Australia/Perth
+Australia/Brisbane
Australia/Sydney
"
--- /dev/null
+#!/usr/bin/env node
+
+'use strict';
+
+const BLOCKSIZE = 3;
+const CHARS1 = [
+ ' ',
+ ...'0123456789'.split(''),
+ ...'abcdefghijklmnopqrstuvwxyz'.split(''),
+ '_',
+ '-',
+];
+const SHIFT = BigInt(Math.ceil(Math.log2(CHARS1.length ** BLOCKSIZE)));
+const MASK = 2n**SHIFT - 1n;
+
+const CHARSN = [...Array(BLOCKSIZE - 1)].reduce((acc) => acc.map((v1) => CHARS1.map((v2) => ''+v1+v2)).flat(), CHARS1);
+const FMAP = new Map(CHARSN.map((v, i) => [''+v, BigInt(i)]));
+const RMAP = new Map(CHARSN.map((v, i) => [BigInt(i), ''+v]));
+
+function main(arg1, arg2) {
+ if (!arg1) {
+ console.error('Usage: hexhost fdxx::4a59954e');
+ console.error('Usage: hexhost fdxx:: hostname');
+ process.exit(1);
+ }
+
+ if (arg2) {
+ const prefix = arg1;
+ const suffix = encode(arg2).replaceAll(/(.{4})/g, '$1:').replace(/:$/, '');
+ console.log(prefix + suffix);
+ } else {
+ const [, suffix] = arg1.split(/::|:0:/);
+ console.log(decode(suffix));
+ }
+}
+
+function decode(input) {
+ input = input && input.replaceAll(':', '');
+ if (!input) {
+ throw new Error('No suffix found');
+ }
+ input = BigInt('0x' + input);
+ let output = [];
+ while (input > 0) {
+ const encodedBlock = input & MASK;
+ input >>= SHIFT;
+ const block = RMAP.get(encodedBlock);
+ if (block !== undefined) {
+ output.push(block);
+ }
+ }
+ return output.reverse().join('').trim();
+}
+
+function encode(input) {
+ if (input.length / BLOCKSIZE > (64n / SHIFT)) {
+ throw new Error('Input is too long to fit in a /64!');
+ }
+
+ input = input.toLowerCase();
+
+ let out = BigInt(0);
+ for (let i = 0; i < input.length; i += BLOCKSIZE) {
+ const block = input.substring(i, i + BLOCKSIZE).padEnd(BLOCKSIZE);
+ const encodedBlock = FMAP.get(block);
+ if (encodedBlock !== undefined) {
+ out = (out << SHIFT) + encodedBlock;
+ }
+ }
+ return out.toString(16);
+}
+
+main(process.argv[2], process.argv[3]);
finishPartial();
partial = {};
partial.bssid = line.match(/[a-z0-9:]+/)[0];
+ partial.associated = line.indexOf('associated') >= 0 ? '**' : '';
}
line = line.trim()
}
}
+ finishPartial();
+
function finishPartial() {
if (!partial) {
return;
return results
.sort()
- .map(([, {bssid, ssid, signal, channel}]) => {
+ .map(([, {bssid, ssid, signal, channel, associated}]) => {
ssid = ssid.padStart(40, ' ').substr(0, 40);
channel = channel.padEnd(12, ' ');
- return `${signal} ${channel} ${ssid} ${bssid}`;
+ return `${signal} ${channel} ${ssid} ${bssid} ${associated}`;
})
.join('\n') + '\n';
}
--- /dev/null
+# bsnap
+
+Manage snapshots for backups using LVM or btrfs. This is intended for use with [borg](https://www.borgbackup.org) or [rsync](https://rsync.samba.org).
+
+## Usage
+
+Running `bsnap on` will do the following:
+- Create a new directory `/a` where the snapshots will be mounted.
+- Take snapshots as configured in your `/etc/fstab`.
+- Mount the snapshots into `/a`.
+
+At this point you can run something like [borg](https://www.borgbackup.org) or [rsync](https://rsync.samba.org) on `/a` to create your backup. Once that's completed you then run `bsnap off` to unmount, remove the snapshots and cleanup `/a`.
+
+You must configure your `/etc/fstab` by setting the second last column for each entry:
+- `0` -- no snapshot will be taken and the filesystem will not be mounted into `/a`
+- `1` -- no snapshot will be taken but the filesystem will be bind mounted into `/a`
+- `2` -- a snapshot will be taken and the snapshot will be mounted into `/a`
+
+```
+# Snapshot the LVM root filesystem
+/dev/mapper/vg-root / ext4 defaults 2 0
+
+# Mount it into /a so it's included in the backup without snapshotting it
+UUID="ABCD-1234" /boot vfat defaults 1 0
+```
--- /dev/null
+#!/bin/bash
+
+set -eu
+
+function snap {
+ unsnap
+
+ mkdir -p /a
+
+ dispatch snap < /etc/fstab
+}
+
+function unsnap {
+ tac /etc/fstab | dispatch unsnap
+
+ if [ -d "/a" ]; then
+ rmdir /a
+ fi
+}
+
+function dispatch {
+ local action="" snaptype=""
+ local dev="" mnt="" fstype="" opts="" dump=""
+
+ while read -r dev mnt fstype opts dump pass; do
+ snaptype="$(get_snaptype "$fstype" "$dump")"
+ if [ -z "$snaptype" ]; then
+ continue
+ fi
+ action="${1}_${snaptype}"
+ echo "$action $mnt"
+ "$action" "$dev" "$mnt" "$opts"
+ done
+}
+
+function get_snaptype {
+ local fstype="$1" dump="$2"
+ if [ "$dump" = "1" ]; then
+ echo bind
+ elif [ "$dump" = "2" ] && [ "$fstype" = "btrfs" ]; then
+ echo btrfs
+ elif [ "$dump" = "2" ]; then
+ echo lvm
+ fi
+}
+
+function snap_bind {
+ local mnt="$2"
+ mount --bind "${mnt}" "/a${mnt}"
+}
+
+function unsnap_bind {
+ local snapmnt="/a$2"
+ if mountpoint -q "$snapmnt"; then
+ umount "$snapmnt"
+ fi
+}
+
+function snap_lvm {
+ local mnt="$2"
+ local lvname="" vgname=""
+ read -r lvname vgname _ < <(get_lvm_vgname_lvname "${mnt}")
+
+ echo "snapshot ${vgname}/${lvname}"
+ lvcreate -L1G --snapshot --name "${lvname}-snap" "${vgname}/${lvname}"
+ mount -o ro "/dev/${vgname}/${lvname}-snap" "/a${mnt}"
+}
+
+function unsnap_lvm {
+ local mnt="$2"
+ local lvname="" vgname=""
+
+ if mountpoint -q "/a$mnt"; then
+ umount "/a$mnt"
+ fi
+
+ read -r lvname vgname _ < <(get_lvm_vgname_lvname "${mnt}")
+ if lvdisplay "${vgname}/${lvname}-snap" &> /dev/null; then
+ lvremove -f "${vgname}/${lvname}-snap"
+ fi
+}
+
+function get_lvm_vgname_lvname {
+ local mnt="$1" subvol=""
+ lvdisplay --noheadings -C "$(findmnt -n -o source "$mnt")"
+}
+
+function snap_btrfs {
+ local mnt="$2" opts="$3" snapdir=""
+
+ snapdir="$(get_btrfs_snapshot_dir "$opts" "$mnt")"
+ btrfs subvolume snapshot "$mnt" "$snapdir"
+
+ mount --bind "$snapdir" "/a${mnt}"
+}
+
+function unsnap_btrfs {
+ local mnt="$2" opts="$3" snapdir=""
+
+ local snapmnt="/a$2"
+ if mountpoint -q "$snapmnt"; then
+ umount "$snapmnt"
+ fi
+
+ snapdir="$(get_btrfs_snapshot_dir "$opts" "$mnt")"
+ if [ -d "$snapdir" ]; then
+ btrfs subvolume delete "$snapdir"
+ fi
+}
+
+function get_btrfs_snapshot_dir {
+ local opts="$1" mnt="$2" subvol=""
+ subvol="$(echo "$opts" | sed -nE 's/^.*\bsubvol=([^,]+)\b.*$/\1/p')"
+ if [ -z "$subvol" ]; then
+ echo "Unknown subvol for mountpoint: $mnt"
+ exit 1
+ fi
+ echo "/.snapshots/tmp-bsnap-${subvol}"
+}
+
+if [ "$(id -u)" -ne 0 ]; then
+ echo "Must be root"
+ exit 1
+fi
+
+if [ "${1:-}" = "off" ]; then
+ unsnap
+elif [ "${1:-}" = "on" ]; then
+ snap
+else
+ echo "Usage: $0 on|off"
+ exit 1
+fi
--- /dev/null
+[General]
+Name = %h
+#Class = 0x200420 # Bluetooth audio receiver
+
+[Policy]
+AutoEnable = true
--- /dev/null
+GRUB_DEFAULT=0
+GRUB_TIMEOUT=3
+GRUB_GFXMODE=1024x768x32,auto
+GRUB_GFXPAYLOAD_LINUX=keep
+GRUB_CMDLINE_LINUX="root=LABEL=btrfsroot cryptopts=target=crypt-btrfsroot,source=/dev/disk/by-partlabel/LUKSROOT,luks,discard"
+GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
--- /dev/null
+options hid_apple fnmode=2 swap_opt_cmd=1
--- /dev/null
+user http;
+worker_processes 1;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ include mime.types;
+ default_type application/octet-stream;
+
+ sendfile on;
+ tcp_nopush on;
+ tcp_nodelay on;
+ keepalive_timeout 65;
+
+ access_log syslog:server=unix:/dev/log,tag=nginx,nohostname,severity=info combined;
+ error_log syslog:server=unix:/dev/log,tag=nginx,nohostname,severity=error;
+
+ include sites-enabled/*;
+}
--- /dev/null
+server {
+ include snippets/listen-http.conf;
+ include snippets/listen-tls.conf;
+
+ return 404;
+}
--- /dev/null
+server {
+ include snippets/listen-tls.conf;
+ server_name example.com;
+
+ root /srv/http/example.com;
+
+ include snippets/standard-server.conf;
+}
+
+server {
+ include snippets/listen-http.conf;
+ server_name example.com;
+
+ return 301 https://example.com$request_uri;
+}
--- /dev/null
+../sites-available/default
\ No newline at end of file
--- /dev/null
+listen 80;
+listen [::]:80;
--- /dev/null
+listen 443 ssl;
+listen [::]:443 ssl;
+
+ssl_certificate /home/letsencrypt/output/latest.pem;
+ssl_certificate_key /home/letsencrypt/domain-key.pem;
+
+# https://wiki.mozilla.org/Security/Server_Side_TLS
+ssl_protocols TLSv1.2;
+ssl_prefer_server_ciphers on;
+ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
+
+add_header "Strict-Transport-Security" "max-age=7776000; includeSubdomains" always;
+add_header X-Frame-Options "DENY" always;
+add_header Content-Security-Policy "upgrade-insecure-requests" always;
--- /dev/null
+location ~ /\.git/ {
+ return 403;
+}
+
+
+location = /favicon.ico {
+ log_not_found off;
+ access_log off;
+}
+
+location ~ /apple-touch-icon[^/]*.png {
+ log_not_found off;
+ access_log off;
+}
+
+location = /robots.txt {
+ log_not_found off;
+ access_log off;
+}
+
+location /.well-known/acme-challenge {
+ alias /home/letsencrypt/web-acme-challenge;
+ auth_basic off;
+}
+
+location /healthcheck {
+ return 200;
+}
--- /dev/null
+DEVICESCAN -d removable -H -l error -l selftest -f -s (O/../.././(00|06|12|18)|S/../.././01|L/../../6/03) -m root
--- /dev/null
+LogLevel INFO
+Port 22
+
+
+AuthenticationMethods publickey
+HostKey /etc/ssh/ssh_host_ed25519_key
+HostKeyAlgorithms ssh-ed25519
+PubkeyAcceptedKeyTypes ssh-ed25519
+UsePAM yes
+
+AllowUsers root
+PermitRootLogin prohibit-password
+
+Subsystem sftp internal-sftp
+AcceptEnv LANG LC_* COLORFGBG
--- /dev/null
+Defaults umask=0022
+Defaults umask_override
+
+Defaults env_keep += "LANG LANGUAGE LINGUAS LC_* _XKB_CHARSET"
+Defaults env_keep += "COLORFGBG"
+Defaults env_keep += "EDITOR"
+
+Defaults>root env_keep += "HOME"
+Defaults>root env_keep += "SSH_AUTH_SOCK SSH_AGENT_PID"
--- /dev/null
+%sudo ALL=(ALL) ALL
--- /dev/null
+%sudo ALL = NOPASSWD: /usr/bin/aptitude update, /usr/bin/aptitude full-upgrade
--- /dev/null
+%sudo ALL = NOPASSWD: /usr/bin/pacman -Syu
--- /dev/null
+%sudo ALL = NOPASSWD: /usr/bin/podman *
--- /dev/null
+[Match]
+Name=en* eth*
+
+[Network]
+DHCP=yes
+IPv6PrivacyExtensions=yes
+
+#Address=fdXX:YYYY:YYYY::XXXX/64
--- /dev/null
+# See resolved.conf(5) for details
+
+[Resolve]
+DNSSEC=no
+LLMNR=no
+MulticastDNS=no
--- /dev/null
+[Service]
+# Never accessible to any services
+InaccessiblePaths=/mnt
+
+# By default inaccessible, may be overriden with BindPaths/BindReadOnlyPaths
+TemporaryFileSystem=/home:ro
+
+NoNewPrivileges=yes
+
+MountFlags=private
+ProtectSystem=strict
+ProtectKernelTunables=yes
+ProtectKernelModules=yes
+ProtectControlGroups=yes
+PrivateTmp=yes
+PrivateDevices=yes
+
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+RestrictRealtime=yes
+RestrictNamespaces=yes
+MemoryDenyWriteExecute=yes
+RestrictSUIDSGID=yes
+
+CapabilityBoundingSet=~CAP_SYS_ADMIN
+SystemCallFilter=@system-service
+SystemCallErrorNumber=EPERM
+SystemCallArchitectures=native
--- /dev/null
+SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="00:00:00:00:00:00", NAME="ethernet"
+SUBSYSTEM=="net", ACTION=="add", ATTR{address}=="00:00:00:00:00:00", NAME="wifi"
--- /dev/null
+#!/bin/bash
+
+BACKUP_HOSTS="$(awk '/^Host.*openwrt/ {print $2}' < ~/.ssh/config)"
+
+cd ~/backup-openwrt/
+
+for host in $BACKUP_HOSTS; do
+ file="${host}.backup.tar.gz"
+ ssh "$host" sysupgrade -b - > "${file}.new" && mv "${file}.new" "${file}"
+done
+
--- /dev/null
+#!/bin/bash
+
+DEVNAME="ST3000DM001-Z1F4RTWN_then_WD15EADS-WMAVU0714940"
+echo -e '0 5858433934 linear /dev/disk/by-id/ata-ST3000DM001-1CH166_Z1F4RTWN-part3 0\n5858433934 2928175821 linear /dev/nbd0 0' > "/tmp/$DEVNAME"
+dmsetup create "$DEVNAME" --verbose --table "/tmp/$DEVNAME"
+
--- /dev/null
+#!/bin/bash
+
+# /etc/crontabs/root
+# m h dom mon dow command
+# * * * * * /root/fix-openwrt-hairpin
+
+for f in /sys/devices/virtual/net/*/*wlan*/brport/hairpin_mode; do
+ if [ -f $f ]; then
+ echo 1 > "$f"
+ fi
+done
--- /dev/null
+#!/bin/bash
+
+if [ "$1" = "config" ] && [ -z "${GIT_CONFIG_ENABLE}" ] && ! [[ "$2" =~ --get ]]; then
+ echo "Ignoring git $*"
+ exit 0
+fi
+
+/usr/bin/git "$@"
fi
DISKNAME="$(basename "$DEVICE")"
CRYPTNAME="crypt-$DISKNAME"
+ if [ -L "/run/ext-backup-crypt/$CRYPTNAME" ]; then
+ continue
+ fi
echo "> cryptsetup luksOpen $DEVICE $CRYPTNAME"
cryptsetup luksOpen "$DEVICE" "$CRYPTNAME" --key-file "/etc/lukskeys/${DISKNAME}"
mkdir -p /run/ext-backup-crypt/
}
function pool_setup {
- zpool set failmode=continue "$ZPOOLNAME"
+ zpool set failmode=wait "$ZPOOLNAME"
zfs set mountpoint="/mnt/$ZPOOLNAME" "$ZPOOLNAME"
chmod 0700 "/mnt/$ZPOOLNAME"
zfs set compression=lz4 "$ZPOOLNAME"
echo "> zpool scrub $ZPOOLNAME"
zpool scrub "$ZPOOLNAME"
- while zpool status "$ZPOOLNAME" | grep -q "scrub in progress"; do
+ while zpool status "$ZPOOLNAME" | awk '/state: ONLINE|scan: scrub in progress/ {x++} END {exit x-2}'; do
echo -n .
sleep 60
done
echo " done"
+
+ if zpool list -H -o health "$ZPOOLNAME" | grep -qv ONLINE; then
+ zpool status -v "$ZPOOLNAME"
+ return 1
+ fi
}
function syncoidw {
| xargs -rn1 zfs destroy -v
}
+function snapshot_convert_to_bookmarks {
+ local fs
+ local snap
+
+ for fs in "$@"; do
+ for snap in $(zfs list -H -o name -t snapshot -r "$fs"); do
+ echo "> zfs bookmark $snap"
+ zfs bookmark "$snap" "${snap/@/#}"
+ zfs destroy "$snap"
+ done
+ done
+}
+
function main {
zfs get all -s local -H > /root/zfs-props.txt
cryptsetup_open
set -eu
-PARTITION_LABEL="multiboot"
-MULTIBOOT_MNT="/mnt/multiboot"
+PARTITION_LABEL_ESP="multibt-esp"
+PARTITION_LABEL_DATA="multiboot"
+MULTIBOOT_MNT="${MULTIBOOT_MNT:-/mnt/multiboot}"
function cmd_format {
if [ ! -b "${1:-}" ]; then
sudo -k
DISK_DEVICE="$1"
- PARTITION_DEVICE="${DISK_DEVICE}1"
- echo -ne 'label: dos\ntype=c, bootable\n' | sudo sfdisk "$DISK_DEVICE"
- sudo mkfs.vfat -n "$PARTITION_LABEL" "$PARTITION_DEVICE"
+ print_sfdisk_command | sudo sfdisk --wipe always --wipe-partitions always "$DISK_DEVICE"
+ udevadm settle
+ sudo mkfs.vfat -n "${PARTITION_LABEL_ESP}" "/dev/disk/by-partlabel/${PARTITION_LABEL_ESP}"
+ sudo mkfs.ext4 -L "${PARTITION_LABEL_DATA}" -E "root_owner=$(id -u):$(id -g)" "/dev/disk/by-partlabel/${PARTITION_LABEL_DATA}"
+}
+
+function print_sfdisk_command {
+ cat <<EOT
+label: gpt
+unit: sectors
+
+size=10M, type=uefi, name="$PARTITION_LABEL_ESP"
+size=1M, type=21686148-6449-6E6F-744E-656564454649
+type=linux, name="$PARTITION_LABEL_DATA"
+EOT
}
function cmd_grub {
--target="$arch" \
--no-nvram \
--removable \
- --efi-directory="$MULTIBOOT_MNT" \
+ --efi-directory="${MULTIBOOT_MNT}/EFI" \
--boot-directory="$MULTIBOOT_MNT" \
"$DISK_DEVICE"
done
}
function install_grub_cfg {
- print_grub_cfg | sudo tee "${MULTIBOOT_MNT}/grub/grub.cfg" > /dev/null
+ if [[ -w "${MULTIBOOT_MNT}/grub/" ]]; then
+ # We already have write access, no need to use sudo
+ print_grub_cfg > "${MULTIBOOT_MNT}/grub/grub.cfg"
+ else
+ print_grub_cfg | sudo tee "${MULTIBOOT_MNT}/grub/grub.cfg" > /dev/null
+ fi
}
function cmd_mount {
set -x
- PARTITION_DEVICE="$(readlink -f "/dev/disk/by-label/${PARTITION_LABEL}")"
+ while sudo umount "/dev/disk/by-partlabel/${PARTITION_LABEL_ESP}" &> /dev/null; do true; done
+ while sudo umount "/dev/disk/by-partlabel/${PARTITION_LABEL_DATA}" &> /dev/null; do true; done
sudo mkdir -p "$MULTIBOOT_MNT"
- while sudo umount "$PARTITION_DEVICE" &> /dev/null; do true; done
- sudo mount "$PARTITION_DEVICE" "$MULTIBOOT_MNT" -o "uid=$(whoami)"
+ sudo mount "/dev/disk/by-partlabel/${PARTITION_LABEL_DATA}" "$MULTIBOOT_MNT"
+ mkdir -p "${MULTIBOOT_MNT}/EFI"
+ sudo mount "/dev/disk/by-partlabel/${PARTITION_LABEL_ESP}" "${MULTIBOOT_MNT}/EFI"
}
function cmd_umount {
set -x
- sudo umount "$MULTIBOOT_MNT"
+ sudo umount "${MULTIBOOT_MNT}/EFI" || true
+ sudo umount "$MULTIBOOT_MNT" || true
sudo rmdir "$MULTIBOOT_MNT"
}
local SYSLINUX_VERSION="6.03"
local SYSLINUX_URL="https://www.kernel.org/pub/linux/utils/boot/syslinux/syslinux-${SYSLINUX_VERSION}.tar.gz"
- local FREEDOS_URL="http://www.freedos.org/download/download/FD12LITE.zip"
+ local FREEDOS_URL="https://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/distributions/1.2/official/FD12LITE.zip"
curl -fL "$SYSLINUX_URL" | \
tar xz --no-same-owner --strip-components=3 -C "$MULTIBOOT_MNT" \
}
function cmd_memtest {
- curl -fL "https://www.memtest.org/download/5.01/memtest86+-5.01.bin.gz" | \
- zcat - > "${MULTIBOOT_MNT}/memtest.bin"
+ curl -fL -o "${MULTIBOOT_MNT}/memtest.tmp.zip" "https://memtest.org/download/v6.20/mt86plus_6.20_64.grub.iso.zip"
+ unzip -d "$MULTIBOOT_MNT" "${MULTIBOOT_MNT}/memtest.tmp.zip"
+ rm "${MULTIBOOT_MNT}/memtest.tmp.zip"
}
function print_grub_cfg {
cat <<EOT
+search --set=root --label $PARTITION_LABEL_DATA
+
insmod all_video
+insmod gfxterm
+loadfont unicode
+set gfxmode=1024x768
+terminal_output gfxterm
+
insmod part_msdos
insmod progress
insmod regexp
-search --set=root --label $PARTITION_LABEL
+
+set maybe_quiet='quiet splash'
+set maybe_to_ram=''
+
+menuentry "! Copy ISO image to ram before booting" {
+ # copytoram is used by arch
+ # toram is used by casper based images (tails, Ubuntu, etc)
+ set maybe_to_ram="copytoram toram"
+}
+
+menuentry "! Verbose" {
+ set maybe_quiet=''
+}
function setup_arch {
menuentry "\$1" {
loopback loop \$1
- linux (loop)/arch/boot/x86_64/vmlinuz img_label=${PARTITION_LABEL} img_loop=\$1 archisobasedir=arch earlymodules=loop
- initrd (loop)/arch/boot/x86_64/archiso.img
+ echo "Loading kernel..."
+ linux (loop)/arch/boot/x86_64/vmlinuz-* img_label=${PARTITION_LABEL_DATA} img_loop=\$1 archisobasedir=arch earlymodules=loop \$maybe_to_ram \$maybe_quiet
+ echo "Loading initrd (and microcode if they exist)..."
+ initrd (loop)/arch/boot/*.img (loop)/arch/boot/x86_64/initramfs-*.img
}
}
-for iso in /archlinux-*.iso; do
+for iso in /archlinux-*.iso /isos/archlinux-*.iso; do
if [ -f "\$iso" ]; then
setup_arch \$iso
fi
function setup_debian {
menuentry "\$1" {
- linux \$1/vmlinuz
- initrd \$1/initrd.gz
+ loopback loop \$1
+ echo "Loading kernel..."
+ linux (loop)/live/vmlinuz* boot=live components findiso=\$1 \$maybe_to_ram \$maybe_quiet
+ echo "Loading initrd..."
+ initrd (loop)/live/initrd*
}
}
-for d in /debian-*-hd-media; do
- if [ -d "\$d" ]; then
- setup_debian \$d
+for iso in /debian-live-*.iso /isos/debian-live-*.iso; do
+ if [ -f "\$iso" ]; then
+ setup_debian \$iso
fi
done
}
fi
-if [ -f /memtest.bin ]; then
- menuentry "/memtest" {
- linux16 /memtest.bin
+
+function setup_memtest {
+ menuentry "\$1" {
+ loopback loop \$1
+ if [ \${grub_platform} = pc ]; then
+ linux (loop)/boot/memtest
+ else
+ linux (loop)/EFI/BOOT/memtest
+ fi
}
-fi
+}
+for iso in /mt86plus*.grub.iso /isos/mt86plus*.grub.iso; do
+ if [ -f "\$iso" ]; then
+ setup_memtest \$iso
+ fi
+done
+
function setup_fedora {
menuentry "\$1" {
loopback loop \$1
probe -s iso_label -l (loop)
- linux (loop)/isolinux/vmlinuz root=live:CDLABEL=\$iso_label rd.live.image quiet iso-scan/filename=\$1
- initrd (loop)/isolinux/initrd.img
+ echo "Loading kernel..."
+ linux (loop)/images/pxeboot/vmlinuz root=live:CDLABEL=\$iso_label rd.live.image iso-scan/filename=\$1 \$maybe_quiet
+ echo "Loading initrd..."
+ initrd (loop)/images/pxeboot/initrd.img
}
}
-for iso in /Fedora-Workstation-Live-*.iso; do
+for iso in /Fedora-Workstation-Live-*.iso /isos/Fedora-Workstation-Live-*.iso; do
if [ -f "\$iso" ]; then
setup_fedora \$iso
fi
function setup_ubuntu {
menuentry "\$1" {
loopback loop \$1
- linux (loop)/casper/vmlinuz* boot=casper quiet iso-scan/filename=\$1
+ set maybe_layerfs_path=''
+ for f in minimal.standard.live.squashfs; do
+ if [ -f "(loop)/casper/\$f" ]; then
+ echo " \$f"
+ set maybe_layerfs_path="layerfs-path=\$f"
+ echo "Setting \$maybe_layerfs_path"
+ fi
+ done
+ echo "Loading kernel..."
+ linux (loop)/casper/vmlinuz* \$maybe_layerfs_path boot=casper iso-scan/filename=\$1 \$maybe_to_ram \$maybe_quiet
+ echo "Loading initrd..."
initrd (loop)/casper/initrd*
}
}
-for iso in /ubuntu-*-desktop-*.iso; do
+for iso in /ubuntu-*-desktop-*.iso /isos/ubuntu-*-desktop-*.iso; do
if [ -f "\$iso" ]; then
setup_ubuntu \$iso
fi
done
+function setup_tails {
+ menuentry "\$1" {
+ loopback loop \$1
+ echo "Loading kernel..."
+ linux (loop)/live/vmlinuz* initrd=/live/initrd.img boot=live config iso-scan/filename=\$1 findiso=\$1 nopersistence noprompt timezone=Etc/UTC noautologin module=Tails slab_nomerge slub_debug=FZP mce=0 vsyscall=none page_poison=1 init_on_free=1 mds=full,nosmt \$maybe_to_ram \$maybe_quiet
+ echo "Loading initrd..."
+ initrd (loop)/live/initrd*
+ }
+}
+for iso in /tails-*.iso /isos/tails-*.iso; do
+ if [ -f "\$iso" ]; then
+ setup_tails \$iso
+ fi
+done
+
EOT
}
set -eu
hostname="$(basename "$0")"
-local_hostname="${hostname}.localnet"
-public_hostname="p${hostname}"
-
-if grep -Eq "^Host ${hostname}\b" ~/.ssh/config; then
- true
-elif ping -c1 -t1 "$local_hostname" &> /dev/null; then
- hostname="$local_hostname"
-else
- hostname="$public_hostname"
-fi
while true; do
clear
--- /dev/null
+#!/usr/bin/env node
+
+/* eslint-env es2020 */
+
+const API_URL = process.env.API_URL;
+const API_KEY = process.env.API_KEY;
+const VERBOSE = !!process.env.VERBOSE;
+
+async function main() {
+ const config = await fetchConfig();
+ const devicesStatus = await fetchDevicesStatus();
+ const connectionsStatus = await fetchConnections();
+
+ for (const {deviceID, name} of config.devices) {
+ const {connected} = connectionsStatus.connections[deviceID];
+ const {lastSeen: lastSeenString} = devicesStatus[deviceID];
+ const lastSeenDate = new Date(lastSeenString);
+ const {completion, needItems} = await fetchCompletion(deviceID);
+ //console.log(name, await fetchCompletion(deviceID));
+
+ checkDevice({name, connected, lastSeenDate, completion, needItems});
+ }
+}
+
+async function checkDevice({name, connected, lastSeenDate, completion, needItems}) {
+ if (VERBOSE) {
+ console.error('checkDevice', {name, connected, lastSeenDate, completion, needItems});
+ }
+
+ if (lastSeenDate.getTime() === 0 || connected) {
+ return;
+ }
+
+ if (lastSeenDate < newDateDays(-10)) {
+ console.log(`Alert! '${name}' has been missing since ` +
+ lastSeenDate.toISOString().replace(/T.*/, ''));
+ }
+ if (needItems > 0 || completion < 100) {
+ console.log(`Alert! '${name}' is out of sync! ` +
+ `${Math.round(completion)}%, missing ${needItems} files.`);
+ }
+}
+
+function newDateDays(days) {
+ return new Date(Date.now() + days * 24 * 3600 * 1000);
+}
+
+async function fetchConfig() {
+ const response = await fetchSyncthing('/rest/config');
+ await assertResponseOk(response);
+ return response.json();
+}
+
+async function fetchDevicesStatus() {
+ const response = await fetchSyncthing('/rest/stats/device');
+ await assertResponseOk(response);
+ return response.json();
+}
+
+async function fetchConnections() {
+ const response = await fetchSyncthing('/rest/system/connections');
+ await assertResponseOk(response);
+ return response.json();
+}
+
+async function fetchCompletion(deviceID) {
+ const response = await fetchSyncthing(`/rest/db/completion?device=${deviceID}`);
+ await assertResponseOk(response);
+ return response.json();
+}
+
+async function fetchSyncthing(path) {
+ return fetch(`${API_URL}${path}`, {
+ headers: {
+ 'X-API-Key': API_KEY,
+ }
+ });
+}
+
+async function assertResponseOk(response) {
+ if (response.ok) {
+ return;
+ }
+ throw new Error(
+ 'Response error! ' +
+ response.status + ' ' + response.statusText +
+ ' -- ' + (await response.text())
+ );
+}
+
+main().catch((err) => {
+ console.error('Exiting due to error!', err);
+ process.exit(1);
+});
for i in ./*; do
if [ "$(basename "$i")" != "$(basename "$0")" ]; then
if ! "$i"; then
- echo -e "\n^^ FAILED! $(hostname) $PRETTY_NAME -- $i ^^\n"
+ echo -e "\n^^ FAILED! $(cat /etc/hostname) $PRETTY_NAME -- $i ^^\n"
exit 1
fi
fi
+++ /dev/null
-#!/bin/bash
-
-cd ~/.config/systemd/user/ &> /dev/null || exit 0
-
-error=0
-for timer in *.timer; do
- if ! systemctl --user is-enabled "$timer" > /dev/null; then
- echo "disabled timer $timer"
- error=1
- fi
- if ! systemctl --user is-active "$timer" > /dev/null; then
- echo "inactive timer $timer"
- error=1
- fi
-done
-
-exit "$error"
#!/bin/bash
-if systemctl --user is-system-running > /dev/null; then
- exit 0
-fi
+users="$(systemctl list-units | \
+ sed -nE 's/.*user@([0-9]+)\.service .*loaded active running.*/\1/p' | \
+ xargs -n1 id -un)"
-echo -e "# systemctl --user --failed"
-systemctl --user --failed
-exit 1
+error=0
+for user in $users; do
+ homedir="$(getent passwd "$user"|cut -d: -f6)"
+ for timer in "$homedir"/.config/systemd/user/*.timer; do
+ if ! [ -f "$timer" ]; then
+ continue
+ fi
+ timerunit="$(basename "$timer")"
+ if ! systemctl --user -M"$user@" is-enabled "$timerunit" > /dev/null; then
+ echo "disabled timer $timer"
+ error=1
+ fi
+ if ! systemctl --user -M"$user@" is-active "$timerunit" > /dev/null; then
+ echo "inactive timer $timer"
+ error=1
+ fi
+ done
+
+ if systemctl --user -M "$user@" is-system-running > /dev/null; then
+ continue
+ fi
+
+ echo -e "# systemctl --user -M "$user@" --failed"
+ systemctl --user -M "$user@" --failed
+ error=1
+done
+
+exit "$error"
--- /dev/null
+#!/bin/bash
+
+# https://www.kernel.org/doc/html/latest/hwmon/it87.html
+# https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=2cbb9c370fe32b5de5243f7338dc6ce8747d495b
+
+set -eux
+
+modprobe it87
+
+CT="$(grep -l coretemp /sys/class/hwmon/hwmon*/name | head -n1 | xargs dirname)/temp1_input"
+cd "$(grep -l it8792 /sys/class/hwmon/hwmon*/name | head -n1 | xargs dirname)"
+
+grep . pwm1* temp1*
+
+# automatic fan control - the chip seems to ignore these settings
+#echo 2 > pwm1_enable # automatic mode
+#echo 1 > pwm1_auto_channels_temp # temperature channel
+#echo 127000 > pwm1_auto_point1_temp_hyst # ??
+#echo 127000 > pwm1_auto_point1_temp # fan off temp
+#echo 127000 > pwm1_auto_point2_temp # fan start temp
+#echo 127000 > pwm1_auto_point3_temp # fan max temperature
+#echo 100 > pwm1_auto_start # start pwm value
+#echo 0 > pwm1_auto_slope # pwm slope, 1/8th pwm
+
+# manual fan control - magic incantation
+echo 1 > pwm1_enable # manual mode
+echo 200000 > pwm1_freq # quieter fan
+echo 0 > temp3_type # disabled unused sensor
+echo 4 > temp1_type # switch sensor to thermistor
+sleep 1 # wait for driver to write to chip
+echo 0 > temp1_type # disable the sensor
+echo 42 > pwm1 # set the fan speed
+
+grep . *pwm1* temp1*
+
+set +x
+OLDPWM="$(cat pwm1)"
+while sleep 1; do
+ TEMPC="$(cat "$CT")"
+ if [ "$TEMPC" -ge 85000 ]; then
+ NEWPWM=255
+ elif [ "$TEMPC" -ge 80000 ]; then
+ NEWPWM=180
+ elif [ "$TEMPC" -ge 60000 ]; then
+ NEWPWM=130
+ else
+ NEWPWM=100
+ fi
+ if [ "$OLDPWM" -ne "$NEWPWM" ]; then
+ echo "Fan speed change: OLDPWM=$OLDPWM TEMPC=$TEMPC NEWPWM=$NEWPWM"
+ echo "$NEWPWM" > pwm1
+ OLDPWM="$NEWPWM"
+ sleep 30
+ fi
+done
--- /dev/null
+options it87 ignore_resource_conflict=1
--- /dev/null
+[Service]
+ExecStart=/etc/fancontrol
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+THE_DEV=/dev/sda
+THE_HOSTNAME=somehost
+THE_USERNAME=someuser
+
+
+gdisk $THE_DEV
+ESP 200M ef00
+XBOOTLDR 824M
+LUKSROOT
+
+
+vgcreate $THE_HOSTNAME /dev/disk/by-partlabel/LUKSROOT
+lvcreate -L16G -nswap $THE_HOSTNAME
+lvcreate -l100%FREE -nroot $THE_HOSTNAME
+
+mount /dev/mapper/$THE_HOSTNAME-root /mnt/
+cd /mnt/
+btrfs fi label /mnt/ btrfsroot
+btrfs subv create @root
+btrfs subv set-default /mnt/@root
+btrfs subv create @home
+btrfs subv create @apt
+btrfs subv create @vartmp
+chmod 1777 @vartmp
+umount /mnt/
+mount /dev/mapper/$THE_HOSTNAME-root /mnt/
+
+mkdir -p /mnt/etc/
+cat <<EOT > /mnt/etc/fstab
+LABEL=btrfsroot / btrfs subvol=@root,discard,compress,nodev 0 0
+LABEL=btrfsroot /btrfs btrfs subvol=/,discard,compress,nodev,nosuid 0 0
+LABEL=btrfsroot /home btrfs subvol=@home,discard,compress,nodev,nosuid 0 0
+LABEL=btrfsroot /var/cache/apt btrfs subvol=@apt,discard,compress,nodev,nosuid 0 0
+LABEL=btrfsroot /var/tmp btrfs subvol=@vartmp,discard,compress,nodev,nosuid 0 0
+PARTLABEL=XBOOTLDR /boot ext4 discard,nodev,nosuid,noexec 0 0
+PARTLABEL=ESP /boot/efi vfat discard,nodev,nosuid,noexec 0 0
+LABEL=swap swap swap discard 0 0
+tmpfs /tmp tmpfs nosuid,nodev 0 0
+EOT
+
+
+debootstrap bookworm /mnt/ https://deb.debian.org/debian
+
+cat <<EOT > /mnt/etc/apt/sources.list
+deb https://deb.debian.org/debian bookworm main contrib non-free non-free-firmware
+deb https://deb.debian.org/debian bookworm-updates main contrib non-free non-free-firmware
+deb https://deb.debian.org/debian-security bookworm-security main contrib non-free non-free-firmware
+EOT
+
+
+for i in /dev /proc /sys /run /tmp; do mount --rbind $i /mnt$i; done
+chroot /mnt/
+mkdir -p /btrfs/ /boot/efi/ /home/ /var/cache/apt/ /var/tmp/
+
+
+mkdir /run/systemd/resolve/
+[ -f /run/systemd/resolve/stub-resolv.conf ] || echo 'nameserver 1.1.1.1' > /run/systemd/resolve/stub-resolv.conf
+
+
+echo $THE_HOSTNAME > /etc/hostname
+ln -sf /usr/share/zoneinfo/Australia/Sydney /etc/localtime
+echo do_symlinks=no > /etc/kernel-img.conf
+
+
+dpkg-reconfigure locales
+apt-get install aptitude curl git python3 vim
+
+
+cd /root/
+curl -sSfL https://code.delx.au/p/dotfiles | bash
+exit
+
+
+chroot /mnt/
+cd /root
+
+mkdir /root/bin/
+git clone https://code.delx.au/monosys
+ln -s /root/monosys/bin /root/bin/monosys-bin
+
+mkdir /root/monosys/package-lists/local
+ln -s /root/monosys/package-lists/local /root/.aptorphan
+cd /root/monosys/package-lists/local
+for i in base base-hw desktop-base desktop-gnome desktop-gnome-software desktop-plymouth desktop-printing filesystems multimedia-players wifi; do ln -s ../debian/$i; done
+cp ../debian/system-efi-amd64 .
+
+apt-get update
+aptorphan
+
+systemctl disable ssh
+find /etc/systemd/system -xtype l -delete
+
+mv /etc/default/grub{,.bak}
+cp /root/monosys/etc/default/grub /etc/default/grub
+grub-install
+update-grub
+
+passwd root
+adduser $THE_USER
+gpasswd -a $THE_USER sudo
+
+plymouth-set-default-theme spinner
+
+
+
+# reboot
+
+flatpak remote-add flathub https://dl.flathub.org/repo/flathub.flatpakrepo
--- /dev/null
+flatpak install
+- firefox
+- flatseal
+- libreoffice
+- keepassxc
--- /dev/null
+THE_DEV=/dev/mmcblk0
+THE_HOSTNAME=somehost
+
+
+raspi.debian.net
+xzcat image.xz | pv > $THE_DEV
+
+
+gdisk $THE_DEV
+# resize partition 2
+
+
+btrfs-convert ${THE_DEV}p2
+mount ${THE_DEV}p2 /mnt
+btrfs fi resize max /mnt
+cd /mnt
+rmdir lost+found
+
+btrfs subv create @root
+mv ./* @root/
+mv @root/ext2_saved/ @ext2_saved
+mkdir @root/btrfs
+btrfs subv create @apt; mv @root/var/cache/apt/archives/* @apt/
+btrfs subv create @vartmp; chmod 1777 @vartmp ; chmod 0755 @root/var/tmp
+btrfs subv set-default @root
+
+cat <<EOT >| @root/etc/fstab
+# <file system> <dir> <type> <options> <dump><pass>
+LABEL=RASPIROOT / btrfs subvol=@root,discard,compress,nodev 2 0
+LABEL=RASPIROOT /btrfs btrfs subvol=/,discard,compress,nodev,nosuid 0 0
+LABEL=RASPIROOT /var/cache/apt/archives btrfs subvol=@apt,discard,compress,nodev,nosuid 0 0
+LABEL=RASPIROOT /var/tmp btrfs subvol=@vartmp,discard,compress,nodev,nosuid 0 0
+LABEL=RASPIFIRM /boot/firmware vfat discard,nodev,nosuid,noexec 1 0
+EOT
+
+
+rm @root/initrd.img @root/initrd.img.old @root/vmlinuz @root/vmlinuz.old
+echo 'do_symlinks=no' > @root/etc/kernel-img.conf
+
+rmdir @root/var/log/journal
+find @root/usr/local -type f -print #-delete
+find @root/etc/systemd/system -name 'rpi*' -print #-delete
+find @root/etc/systemd/system -type d -empty -print -delete
+
+
+echo $THE_HOSTNAME > @root/etc/hostname
+ln -sf /usr/share/zoneinfo/Australia/Sydney @root/etc/localtime
+echo > @root/etc/motd
+
+
+cp ~/monosys/etc/ssh/sshd_config @root/etc/ssh/sshd_config
+ssh-keygen -f @root/etc/ssh/ssh_host_ed25519_key -t ed25519 -N '' -C ''
+cp ~/.ssh/id_ed25519.pub @root/root/.ssh/authorized_keys
+
+
+# boot
+
+ssh root@192.168.1.XXX
+
+passwd -l root
+dpkg-reconfigure raspi-firmware
+apt-get update
+apt-get install locales
+dpkg-reconfigure locales
+apt-get install aptitude curl git python3 vim
+
+curl -sSfL https://code.delx.au/p/dotfiles | bash
+exit
+ssh root@192.168.1.XXX
+
+mkdir /root/bin/
+git clone https://code.delx.au/monosys
+ln -s /root/monosys/bin /root/bin/monosys-bin
+
+
+cp monosys/etc/systemd/network/ethernet.network /etc/systemd/network/
+systemctl stop networking ; systemctl restart systemd-networkd
+systemctl disable networking ; systemctl enable systemd-networkd
+
+
+mkdir /root/monosys/package-lists/local
+ln -s /root/monosys/package-lists/local /root/.aptorphan
+cd /root/monosys/package-lists/local
+ln -s ../debian/base
+cp ../debian/system-raspi system
+aptorphan
--- /dev/null
+# https://www.raspberrypi.com/documentation/computers/configuration.html#set-up-a-headless-raspberry-pi
+# https://www.raspberrypi.com/software/operating-systems/
+
+xzcat image.xz | pv > /dev/mmcblk0
+
+mount /dev/mmcblk0p1 /mnt
+touch /mnt/ssh
+echo "pitmp:$(echo 'password1A!' | openssl passwd -6 -stdin)" > /mnt/userconf.txt
+
+# boot
+THE_IP=192.168.1.XXX
+
+ssh-copy-id pitmp@$THE_IP
+ssh pitmp@$THE_IP sudo cp -R ~pitmp/.ssh /root/.ssh
+
+ssh root@$THE_IP
+
+deluser pitmp
+rm -rf /home/pitmp
+
+hostnamectl set-hostname XYZ
+timedatectl set-timezone Australia/Sydney
+localectl set-locale en_AU.UTF-8
+
+rm -rf /var/log/journal
+systemctl restart systemd-journald
+
+rm /initrd.img /initrd.img.old /vmlinuz /vmlinuz.old
+echo 'do_symlinks=no' > /etc/kernel-img.conf
+
+apt-get install git python3 screen vim
+curl -sSfL https://code.delx.au/p/dotfiles | bash
+
+git clone https://code.delx.au/monosys
+
+cp monosys/etc/ssh/sshd_config sshd_config
+(cd /etc/ssh/; rm ssh_host_ecdsa_key ssh_host_ecdsa_key.pub ssh_host_rsa_key ssh_host_rsa_key.pub)
+
+cp monosys/etc/systemd/network/ethernet.network /etc/systemd/network/ethernet.network
+systemctl stop networking
+systemctl start systemd-networkd
+systemctl enable systemd-networkd
+for i in ModemManager NetworkManager avahi-daemon{,.socket} triggerhappy{,.socket} wpa_supplicant udisks2; do systemctl disable --now $i; done
+
+find /etc/systemd/system -xtype l -delete
--- /dev/null
+snapper -c root create-config /
+snapper -c home create-config /home
+
+vim /etc/snapper/configs/*
+```
+SUBVOLUME="/"
+FSTYPE="btrfs"
+
+SPACE_LIMIT="0.5"
+FREE_LIMIT="0.2"
+
+TIMELINE_CREATE="yes"
+TIMELINE_CLEANUP="yes"
+TIMELINE_MIN_AGE="1800"
+TIMELINE_LIMIT_HOURLY="10"
+TIMELINE_LIMIT_DAILY="60"
+TIMELINE_LIMIT_WEEKLY="0"
+TIMELINE_LIMIT_MONTHLY="0"
+TIMELINE_LIMIT_YEARLY="0"
+```
--- /dev/null
+# My base
+base
+bash
+bash-completion
+busybox
+coreutils
+cronie
+diffutils
+fdupes
+file
+findutils
+gawk
+git
+grep
+hexedit
+jq
+less
+logrotate
+lsof
+m4
+make
+man-db
+man-pages
+moreutils
+nodejs
+openssh
+pacman
+pacman-contrib
+patch
+perl
+procps-ng
+psmisc
+pv
+python
+python-virtualenv
+renameutils
+ripgrep
+rsync
+screen
+sed
+sqlite
+strace
+sudo
+vim
+which
+yq
+
+# Compression
+bzip2
+cpio
+gzip
+p7zip
+tar
+unrar
+unzip
+xz
+zip
+
+# Network
+curl
+dog
+fping
+iftop
+iperf3
+iproute2
+iputils
+mtr
+nmap
+openbsd-netcat
+speedtest-cli
+tcpdump
+wget
+whois
--- /dev/null
+autoconf
+automake
+bison
+cmake
+fakeroot
+flex
+gcc
+gcc-libs
+gdb
+intltool
+libtool
+pkgconf
--- /dev/null
+atop
+ddrescue
+dmidecode
+ethtool
+fwupd
+gptfdisk
+hdparm
+iotop
+lm_sensors
+lshw
+pciutils
+smartmontools
+sysfsutils
+sysstat
+usbutils
--- /dev/null
+bluez
+bluez-hid2hci
+bluez-libs
+bluez-utils
--- /dev/null
+# Desktop base
+d-feet
+dconf-editor
+flatpak
+wev
+xorg-xeyes
+zenity
+
+# Audio
+alsa-firmware
+alsa-lib
+alsa-plugins
+alsa-utils
+pavucontrol
+pipewire-alsa
+pipewire-pulse
+wireplumber
+
+# Fonts
+ttf-dejavu
+ttf-liberation
+ttf-ubuntu-font-family
+
+# Wallpapers
+deepin-wallpapers
+gnome-backgrounds
+mate-backgrounds
--- /dev/null
+baobab
+cheese
+eog
+evince
+file-roller
+gdm
+gedit
+gnome-calculator
+gnome-characters
+gnome-color-manager
+gnome-control-center
+gnome-font-viewer
+gnome-keyring
+gnome-menus
+gnome-power-manager
+gnome-screenshot
+gnome-session
+gnome-settings-daemon
+gnome-shell
+gnome-shell-extension-appindicator
+gnome-shell-extensions
+gnome-sound-recorder
+gnome-system-monitor
+gnome-terminal
+gnome-tweaks
+gvfs
+gvfs-afc
+gvfs-gphoto2
+gvfs-mtp
+gvfs-smb
+libappindicator-gtk3
+mutter
+nautilus
+seahorse
+sushi
+tracker3
+tracker3-miners
+qt5-wayland
+wl-clipboard
+xdg-desktop-portal-gnome
--- /dev/null
+cups
+ghostscript
+gsfonts
+avahi
+nss-mdns
+
+# drivers
+foomatic-db
+foomatic-db-engine
+foomatic-db-nonfree
+gutenprint
+splix
--- /dev/null
+~pipewire-alsa
+~pipewire-pulse
+~wireplumber
+pulseaudio
+pulseaudio-alsa
+pulseaudio-bluetooth
--- /dev/null
+eog
+evince
+file-roller
+gedit
+gnome-system-monitor
+gtk-xfce-engine
+gvfs
+gvfs-mtp
+gvfs-smb
+lightdm
+lightdm-gtk-greeter
+thunar
+thunar-volman
+tumbler
+xfce4-appfinder
+xfce4-datetime-plugin
+xfce4-notifyd
+xfce4-panel
+xfce4-pulseaudio-plugin
+xfce4-session
+xfce4-settings
+xfce4-terminal
+xfdesktop
+xfwm4
+xfwm4-themes
--- /dev/null
+xdotool
+xf86-input-libinput
+xf86-input-void
+xorg-bdftopcf
+xorg-docs
+xorg-font-util
+xorg-fonts-100dpi
+xorg-fonts-encodings
+xorg-fonts-misc
+xorg-iceauth
+xorg-luit
+xorg-mkfontscale
+xorg-server
+xorg-sessreg
+xorg-setxkbmap
+xorg-smproxy
+xorg-x11perf
+xorg-xauth
+xorg-xbacklight
+xorg-xcmsdb
+xorg-xcursorgen
+xorg-xdpyinfo
+xorg-xdriinfo
+xorg-xev
+xorg-xfontsel
+xorg-xgamma
+xorg-xhost
+xorg-xinput
+xorg-xkbcomp
+xorg-xkbevd
+xorg-xkbutils
+xorg-xkill
+xorg-xlsatoms
+xorg-xlsclients
+xorg-xmodmap
+xorg-xpr
+xorg-xprop
+xorg-xrandr
+xorg-xrdb
+xorg-xrefresh
+xorg-xset
+xorg-xsetroot
+xorg-xvinfo
+xorg-xwd
+xorg-xwininfo
+xorg-xwud
+xsel
+xterm
--- /dev/null
+emacs-wayland
+aspell-en
+python-markdown
+shellcheck-bin
+
+python-lsp-server
+python-lsp-black
+python-pyflakes
+
+typescript-language-server
--- /dev/null
+btrfs-progs
+cryptsetup
+dosfstools
+e2fsprogs
+exfat-utils
+lvm2
+ntfs-3g
+xfsprogs
--- /dev/null
+abcde
+cdparanoia
+glyr
--- /dev/null
+dvdbackup
+libdvdcss
--- /dev/null
+gst-libav
+gst-plugins-good
+gst-plugins-ugly
+mplayer
+mpv
+vlc
--- /dev/null
+atomicparsley
+exiv2
+fdkaac
+ffmpeg
+handbrake-cli
+imagemagick
+mkvtoolnix-cli
+sox
--- /dev/null
+podman
+buildah
+netavark
+aardvark-dns
+catatonit
--- /dev/null
+lzop
+mbuffer
+sanoid
--- /dev/null
+# bootloader
+efibootmgr
+grub
+
+# kernel/drivers
+intel-ucode
+linux-lts
+linux-firmware
+terminus-font # Linux VT
+tlp
+
+# filesystems
+cryptsetup
+zfs-linux-lts
+
+# networking
+crda
+iw
+networkmanager
--- /dev/null
+iw
+networkmanager
+wireguard-tools
+wireless-regdb
--- /dev/null
+# My base
+acl
+apt-config-auto-update
+apt-utils
+aptitude
+bash-completion
+busybox-static
+ca-certificates
+dbus
+dbus-user-session
+debian-keyring
+debian-security-support
+diffutils
+doc-debian
+eject
+fdupes
+file
+gawk
+git
+hexedit
+info
+initramfs-tools
+jq
+less
+libpam-systemd
+locales
+logrotate
+lsof
+man-db
+manpages
+moreutils
+nano
+netbase
+nodejs
+openssh-client
+openssh-server
+patch
+popularity-contest
+psmisc
+pv
+python3
+renameutils
+ripgrep
+rsync
+screen
+sed
+sqlite3
+strace
+sudo
+systemd-container
+systemd-timesyncd
+time
+tzdata
+uuid-runtime
+vim
+virtualenv
+whiptail
+xxd
+
+# Compression
+bzip2
+cpio
+gzip
+p7zip
+tar
+unzip
+xz-utils
+zip
+
+# Network
+bind9-dnsutils
+curl
+fping
+iftop
+iperf3
+iproute2
+iputils-ping
+mtr-tiny
+netcat-openbsd
+nftables
+nmap
+speedtest-cli
+systemd-resolved
+tcpdump
+telnet
+wget
+whois
--- /dev/null
+build-essential
+fakeroot
+libbsd-dev
+libssl-dev
--- /dev/null
+atop
+dmidecode
+ethtool
+fwupd
+gddrescue
+gdisk
+hdparm
+iotop
+lm-sensors
+lshw
+pciutils
+smartmontools
+sysstat
+usbutils
--- /dev/null
+bluez
+bluez-tools
+pulseaudio-module-bluetooth
--- /dev/null
+# Desktop base
+d-feet
+dconf-editor
+flatpak
+wev
+xdg-utils
+zenity
+
+# Audio
+alsa-utils
+paprefs
+pavucontrol
+pulseaudio
+pulseaudio-utils
+
+# Fonts
+fonts-dejavu
+fonts-liberation
+fonts-ubuntu
+ttf-mscorefonts-installer
+
+# Wallpapers
+gnome-backgrounds
+mate-backgrounds
--- /dev/null
+adwaita-icon-theme
+baobab
+cheese
+eog
+evince
+file-roller
+gdm3
+gedit
+gnome-calculator
+gnome-characters
+gnome-color-manager
+gnome-control-center
+gnome-font-viewer
+gnome-keyring
+gnome-menus
+gnome-power-manager
+gnome-screenshot
+gnome-session
+gnome-settings-daemon
+gnome-shell
+gnome-sound-recorder
+gnome-sushi
+gnome-system-monitor
+gnome-terminal
+gnome-tweaks
+gvfs
+gvfs-backends
+gvfs-fuse
+mutter
+nautilus
+nautilus-extension-gnome-terminal
+seahorse
--- /dev/null
+gnome-software
+gnome-software-plugin-flatpak
--- /dev/null
+plymouth
+plymouth-label
+plymouth-themes
--- /dev/null
+avahi-daemon
+libnss-mdns
+cups
--- /dev/null
+accountsservice
+desktop-base
+eog
+evince
+file-roller
+gedit
+gnome-icon-theme
+gnome-system-monitor
+gnome-themes-extra
+gtk2-engines-pixbuf
+gtk2-engines-xfce
+gtk3-engines-xfce
+gvfs
+gvfs-backends
+gvfs-bin
+gvfs-fuse
+lightdm
+lightdm-gtk-greeter
+policykit-1
+policykit-1-gnome
+thunar
+thunar-volman
+tumbler
+xfce4-appfinder
+xfce4-datetime-plugin
+xfce4-notifyd
+xfce4-panel
+xfce4-pulseaudio-plugin
+xfce4-session
+xfce4-settings
+xfce4-terminal
+xfdesktop4
+xfwm4
--- /dev/null
+x11-session-utils
+x11-xserver-utils
+xauth
+xdotool
+xfonts-base
+xsel
+xserver-xorg
+xserver-xorg-video-all
+xterm
--- /dev/null
+btrfs-progs
+cryptsetup
+dosfstools
+e2fsprogs
+exfatprogs
+lvm2
+ntfs-3g
+xfsprogs
--- /dev/null
+dvdbackup
+libdvdcss
--- /dev/null
+gstreamer1.0-libav
+gstreamer1.0-plugins-good
+gstreamer1.0-plugins-ugly
+mpv
+vlc
--- /dev/null
+atomicparsley
+exiv2
+fdkaac
+ffmpeg
+handbrake-cli
+imagemagick
+mkvtoolnix
+sox
--- /dev/null
+# bootloader
+efibootmgr
+grub-efi-amd64
+
+# kernel/drivers
+linux-image-amd64
+intel-microcode
+firmware-linux
+
+# filesystems
+cryptsetup-initramfs
--- /dev/null
+# kernel/boot
+linux-image-arm64
+raspi-firmware
+
+# filesystems
+btrfs-progs
--- /dev/null
+iw
+network-manager
+network-manager-gnome
+wireless-regdb
+wpasupplicant
--- /dev/null
+language-pack-en
+software-properties-common
+update-notifier-common
+~apt-config-auto-update
--- /dev/null
+# Ubuntu desktop base
+language-pack-gnome-en
+
+# Ubuntu wallpapers
+ubuntu-wallpapers-karmic
+ubuntu-wallpapers-lucid
+ubuntu-wallpapers-maverick
+ubuntu-wallpapers-natty
+ubuntu-wallpapers-oneiric
+ubuntu-wallpapers-precise
+ubuntu-wallpapers-quantal
+ubuntu-wallpapers-raring
+ubuntu-wallpapers-saucy
+ubuntu-wallpapers-trusty
+ubuntu-wallpapers-utopic
+ubuntu-wallpapers-vivid
+ubuntu-wallpapers-wily
+ubuntu-wallpapers-xenial