#!/bin/sh # Mount what a brintOS boot keeps in memory: /run and /var/volatile on every # boot, as /etc/fstab declares them, and a tmpfs over each login's home and # over /var/spool and /var/cache when that directory is read-only, seeded from # the image so what it ships stays visible. A snapshot launch on brintos.io # boots with a read-only root; a writable launch keeps its directories. # Run once per boot, before anything writes to these directories. mounted() { awk -v m="$1" '$2 == m { f = 1 } END { exit !f }' /proc/mounts } # A write probe, not test -w: on a snapshot the guest's superblock stays # read-write and only the backend refuses, with EROFS on the site and EIO under # Node. A mkdir that reports failure but leaves the directory (linux#73) means # the directory is writable. writable() { _p=$1/.brintos-volatile.$$ mkdir "$_p" 2>/dev/null || [ -d "$_p" ] || return 1 rmdir "$_p" 2>/dev/null return 0 } # Give $2 the mode and owner of $1. same_attr() { chown -h "$(stat -c %u:%g "$1")" "$2" && { [ -L "$2" ] || chmod "$(stat -c %a "$1")" "$2"; } } # Copy the tree under $1 into $2 with GNU tar, which reads with read(2). # busybox tar, cp and cat copy through sendfile(2), which on a file not yet # read this boot never returns or leaks a restart sentinel, so without GNU tar # the copy goes entry by entry, the file data through dd. # BRINTOS-WORKAROUND: glibc#14 remove -- when sendfile(2) no longer leaks the restart sentinel, any tar will do. seed() { if tar --version 2>/dev/null | grep -q 'GNU tar'; then tar -C "$1" -cf - . | tar -C "$2" -xpf - else (cd "$1" && find . ! -name .) | while IFS= read -r _e; do if [ -L "$1/$_e" ]; then ln -s "$(readlink "$1/$_e")" "$2/$_e" elif [ -d "$1/$_e" ]; then mkdir "$2/$_e" elif [ -f "$1/$_e" ]; then dd if="$1/$_e" of="$2/$_e" bs=64k 2>/dev/null else continue fi && same_attr "$1/$_e" "$2/$_e" done fi [ "$(cd "$1" && find . | sort)" = "$(cd "$2" && find . | sort)" ] || echo "brintos-volatile: $1: not every entry was copied" >&2 } # The directory's mode and owner, as tmpfs mount options. dir_opts() { set -- $(stat -c '%a %u %g' "$1" 2>/dev/null) [ $# = 3 ] && echo "mode=$1,uid=$2,gid=$3" } # A tmpfs of its own over a home: mounted at a staging point, seeded, then moved. cover_home() { [ -d "$1" ] && ! mounted "$1" && ! writable "$1" || return 0 _n=$((_n + 1)) _s=/run/brintos-volatile/home$_n mkdir "$_s" && mount -t tmpfs -o "$(dir_opts "$1")" tmpfs "$_s" && seed "$1" "$_s" && mount --move "$_s" "$1" && rmdir "$_s" } # /var/