summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.vim/lua/debugger.lua4
-rwxr-xr-xbin/os-conf136
-rw-r--r--os/.envrc1
-rw-r--r--os/README.md17
-rw-r--r--os/manifest48
5 files changed, 145 insertions, 61 deletions
diff --git a/.vim/lua/debugger.lua b/.vim/lua/debugger.lua
index e847076..32b75b5 100644
--- a/.vim/lua/debugger.lua
+++ b/.vim/lua/debugger.lua
@@ -64,8 +64,8 @@ dap.adapters.go_dlv_local = function(callback, config) -- {{{
 end -- }}}
 
 dap.adapters.go_dlv_remote = {
-  type = "server",
-  host = "127.0.0.1",
+  type = 'server',
+  host = '127.0.0.1',
   port = 38697,
 }
 
diff --git a/bin/os-conf b/bin/os-conf
index 94f60a4..8ee143d 100755
--- a/bin/os-conf
+++ b/bin/os-conf
@@ -1,56 +1,108 @@
 #!/bin/sh
 
+set -e
+[ -n "$DEBUG" ] && set -x
+
 OS_DIR=${OS_DIR:-$HOME/os}
 OS_MANIFEST=$OS_DIR/manifest
 
-noop="echo "
-total=0
+target=/tmp/os/
+restore=
+list=
+while getopts r:lh opt; do
+	case "$opt" in
+	r)
+		restore=1
+		target="$OPTARG"
+		;;
+	l) list=1 ;;
+	h | ?)
+		printf "usage: %s [options]\n" "$(basename "$0")"
+		printf "\n"
+		printf " -l list files that would be saved\n"
+		printf " -r TARGET restore to TARGET (default: %s)\n" "${target}"
+		printf "\n"
+		exit 2
+		;;
+	esac
+done
+shift $((OPTIND - 1))
 
-copy_file() {
-	path=$1
-	if [ -f "$path" ]; then
-		# check that the file in the manifest matches
-		# skip if it does
-		if cmp "$path" "$OS_DIR$path" >/dev/null; then
-			return
-		fi
-		# mkdir base path
-		mkdir -p "$(dirname "$OS_DIR$path")"
-		# copy
-		cp -v "$path" "$OS_DIR$path"
-		# tally
-		total=$((total + 1))
-	elif [ -d "$path" ]; then
-		# handle dir
-		for file in "$path"/*; do
-			copy_file "$file"
+tmp_prefix=os-secret-
+# cleanup
+trap '{ rm -f "/tmp/${tmp_prefix}"*; }' EXIT
+
+handle_secret() {
+	# NOTE: we can't print anything to stdout here, only the final encrypted file
+	# to be included in the os archive
+	case "$1" in
+	encrypt)
+		# read the first line from input and use it as path
+		IFS=$(printf '\r') read -r filepath
+		archive=/tmp/"$tmp_prefix"$(printf "%s" "$filepath" | md5sum | cut -d' ' -f1)
+		# create tar archive from input, descends into directory
+		(
+			printf "%s\n" "$filepath"
+			cat -
+		) |
+			doas sh -c "(
+			tar -cz -f $archive -T - 2>/dev/null;
+			chown 1000:1000 $archive;
+		)"
+		# encrypt the tarfile and amend some information that makes
+		# reconstructing easier
+		(
+			sops --config /dev/null --encrypt "$archive" 2>/dev/null |
+				jq -r '.sops.data_extension |= "tar.gz"'
+		) >"${archive}.enc"
+		printf "%s\n" "${archive}.enc"
+		;;
+	decrypt)
+		while IFS=$(printf '\r') read -r line; do
+			# if $(jq -r '.sops.data_extension' "$line") == "tar.gz"
+			sops --config /dev/null exec-file "$line" "tar xzf - -C $target < {}"
 		done
-	else
-		# noop
-		echo "noop: $path"
-		return
-	fi
+		;;
+	esac
 }
 
-main() {
-	while IFS="\r" read -r line
-	do
-		[ -z "$line" ] && continue
-		echo "$line" | awk '/#.*/{exit 1}' || continue
-
-		# check that the file in the manifest exists
-		if [ ! -e "$line" ]; then
-			echo "error: $line not found" >&2
-			continue
+handle_rules() {
+	while IFS=$(printf '\r') read -r line; do
+		if printf "%s" "$line" | grep -qe '#secret$'; then
+			printf "%s\n" "$line" | sed -e 's/\s#secret//' | handle_secret encrypt
+		else
+			# shellcheck disable=SC2086
+			find "$(printf "%s\n" $line)" -print 2>/dev/null || true
 		fi
-		copy_file "$line"
-
 	done
+
 }
 
-uniq "$OS_MANIFEST" \
-	| grep -v '^$' \
-	| grep -v '^#' \
-	| main
+_rsync() {
+	extra=
+	[ -n "$list" ] && extra="--dry-run"
+	rsync -v -hhh $extra \
+		--archive \
+		--links \
+		"$@"
+}
 
-echo "$total files."
+if [ -n "$restore" ]; then
+	printf "os-conf: restoring %s to %s\n" "${OS_DIR}" "${target}" >&2
+	mkdir -p "${target}" || true
+	_rsync \
+		--exclude '/manifest' \
+		--exclude '/README.md' \
+		--exclude 'colors.todo' \
+		--exclude 'os-secret*.enc' \
+		"${OS_DIR}/" "${target}"
+	find "${OS_DIR}" -type f -name 'os-secret*.enc' -print |
+		handle_secret decrypt
+else
+	printf "os-conf: saving to %s\n" "${OS_DIR}" >&2
+	uniq "$OS_MANIFEST" |
+		grep -v '^$' |
+		grep -v '^#' |
+		handle_rules |
+		_rsync --files-from=- "/" "${OS_DIR}/"
+fi
diff --git a/os/.envrc b/os/.envrc
new file mode 100644
index 0000000..4cfd171
--- /dev/null
+++ b/os/.envrc
@@ -0,0 +1 @@
+export SOPS_PGP_FP=17AE9645C9848DA159D6643B8E8F20D25FF33529
diff --git a/os/README.md b/os/README.md
index 8ca3356..80db948 100644
--- a/os/README.md
+++ b/os/README.md
@@ -1,8 +1,15 @@
-# os configuration
+# OS configuration
 
-TODO script that does:
+use `os-conf` to save and `os-conf -r /` to restore configuration
+the script reads a manifest file inside `$OS_DIR`, which defaults to `$HOME/os`
 
-* parse manifest
-* backup listed files from rootfs
-* patch/add files in rootfs
+## manifest syntax
 
+lines prefixed with `#` or `$` are ignored, the magic comment `#secret`, when
+appended to a line, marks the entry as containing data that shouldn't be checked
+into a public repository. Instead we use [sops](https://github.com/mozilla/sops) to encrypt and store it under
+`$OS_DIR/tmp/os-secret-*`. These encrypted archives are transparently handled
+by the restore code.
+
+Encryption requires the `SOPS_PGP_FP` environment variable (or whatever is required
+by any of the other supported encryption schemes).
diff --git a/os/manifest b/os/manifest
index debfc00..1e6047f 100644
--- a/os/manifest
+++ b/os/manifest
@@ -1,20 +1,44 @@
-# portage config
+# portage
 /var/lib/portage/world
-/etc/portage/*
+/etc/portage
+/etc/eixrc
+/etc/eix-sync.conf
+/etc/genup/updaters.d/10-tip.sh
+/etc/genup/updaters.d/23-eclean-packages.sh
 
-# openrc config
-/etc/conf.d/*
-/etc/runlevels/*
-
-/etc/buildkernel.conf
-/etc/doas.conf
+# core
 /etc/fstab
-/etc/bluetooth/audio.conf
-/etc/profile.d/toolbox.sh
 /etc/hosts
+/etc/resolvconf.conf
+/etc/resolv.conf
+/etc/doas*
+/etc/profile.d/toolbox.sh
+/etc/profile.d/xdg-cache-home.sh
+/etc/bluetooth
 
+# kernel stuff
+/etc/buildkernel.conf
+/etc/genkernel.conf
 /usr/src/linux/.config
-/usr/src/linux-5.10.76-gentoo-r1/.config
-/usr/src/linux-5.15.16-gentoo/.config
+/usr/src/linux-5.10*/.config
+/usr/src/linux-5.15*/.config
 
 /var/spool/cron/crontabs/robert
+
+# wifi
+/etc/iwd
+/var/lib/iwd #secret
+/etc/netplug.d
+
+# services
+/etc/conf.d
+/etc/runlevels
+
+/etc/buildkit
+/etc/cgroup
+/etc/default
+/etc/env.d/99bemenu.in
+/etc/env.d/99bemenu.out
+
+#/etc/greetd
+#/etc/plymouth