blob: d560eb52c41d983066394cf499de7bff8d1fa16f [file] [log] [blame]
#
# Copyright 2023 Google LLC
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# version 2 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# Check for EAPI 5+
case "${EAPI:-0}" in
0|1|2|3|4) die "Unsupported EAPI=${EAPI:-0} (too old) for ${ECLASS}" ;;
5|6) inherit eapi7-ver ;;
7) ;;
esac
inherit systemd
function _mount_unit_name_from_path() {
[[ "$#" -eq 1 ]] || die "_mount_unit_fname_from_path expected 1 arg."
local ret="$1"; shift
ret="${ret//-/\\x2d}" # First, escape any dashes
ret="${ret//\//-}" # Next, take all slashes and make them a dash
ret="${ret/-/}" # Finally, strip the leading - off
echo "${ret}"
}
function _cat_to_file() {
local destpath="$1"; shift
local abspath="${D}/${destpath}"
mkdir -p "$(dirname "${abspath}")"
cat >"${abspath}"
}
# Creates a new overlay by creating a systemd mount unit, and a systemd oneshot
# to prepare backing dirs to support it.
#
# Usage:
#
# create_stateful_overlay mountpoint owner permissions backing-root
# - mountpoint is required: The location to mount an overlayfs on.
# - owner is optional: If set, the owner:group to chown mountpoint to once
# created.
# - permissions is optional: If set, the mode (as passed to `chown`) to set the
# mountpoint after the overlay is created.
# - backing-root is optional: If set, overrides the backing location where
# upper and data dirs are located. If not set, then
# defaults to /mnt/stateful_overlay/$mountpoint
# - For any optional arguments to this function, a single `-` means to use the
# default..
function create_stateful_overlay() {
[[ "$#" -eq 4 ]] || die "create_stateful_overlay expected 4 args but got $#"
local mountpoint="$1"; shift
local owner="$1"; shift
local chmod="$1"; shift
local backing_root="$1"; shift
if [[ "${backing_root}" = - ]]; then
backing_root="/mnt/stateful_partition${mountpoint}"
fi
local mount_name="$(_mount_unit_name_from_path "${mountpoint}")"
local mount_unit="/usr/lib/systemd/system/${mount_name}.mount"
local prep_unit="/usr/lib/systemd/system/prep_${mount_name}.service"
local datadir="${backing_root}/data"
local workdir="${backing_root}/.work"
keepdir "${mountpoint}"
_cat_to_file "${mount_unit}" <<EOF
[Unit]
Description=Statefully mount ${mountpoint} backed by ${backing_root}
After=mnt-stateful_partition-make-private.service
After=prep_${mount_name}.service
Requires=prep_${mount_name}.service
DefaultDependencies=no
[Install]
RequiredBy=local-fs.target
[Mount]
What=overlayfs
Where=${mountpoint}
Type=overlay
Options=lowerdir=${mountpoint},upperdir=${datadir},workdir=${workdir}
EOF
_cat_to_file "${prep_unit}" <<EOF
[Unit]
Description=Create backing directories for ${mountpoint}
Before=local-fs.target
After=mnt-stateful_partition-make-private.service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/bin/mkdir -p ${datadir} ${workdir}
EOF
if [[ "${owner}" != - ]]; then
echo "ExecStart=/bin/chown ${owner} ${datadir}" >>"${D}${prep_unit}"
fi
if [[ "${chmod}" != - ]]; then
echo "ExecStart=/bin/chmod ${chmod} ${datadir}" >>"${D}${prep_unit}"
fi
systemd_enable_service local-fs.target "${mount_unit}"
}
function create_tmpfs_overlay() {
[[ "$#" -eq 3 ]] || die "create_tmpfs_overlay expected 3 args but got $#"
local mountpoint="$1"; shift
local owner="$1"; shift
local chmod="$1"; shift
local backing_root="/tmp/_overlay${mountpoint//\//_}"
local mount_name="$(_mount_unit_name_from_path "${mountpoint}")"
local mount_unit="/usr/lib/systemd/system/${mount_name}.mount"
local prep_unit="/usr/lib/systemd/system/prep_${mount_name}.service"
local post_unit="/usr/lib/systemd/system/post_${mount_name}.service"
local datadir="${backing_root}/data"
local workdir="${backing_root}/.work"
keepdir "${mountpoint}"
_cat_to_file "${mount_unit}" <<EOF
[Unit]
Description=Statefully mount ${mountpoint} backed by ${backing_root}
After=mnt-stateful_partition-make-private.service prep_${mount_name}.service
Before=post_${mount_name}.service
Requires=prep_${mount_name}.service post_${mount_name}.service tmp.mount
DefaultDependencies=no
[Install]
RequiredBy=local-fs.target
[Mount]
What=overlayfs
Where=${mountpoint}
Type=overlay
Options=lowerdir=${mountpoint},upperdir=${datadir},workdir=${workdir}
EOF
_cat_to_file "${prep_unit}" <<EOF
[Unit]
Description=Create backing directories for ${mountpoint}
Before=local-fs.target
After=tmp.mount
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/bin/mkdir -p "${backing_root}"
ExecStart=/bin/mount -t tmpfs tmpfs "${backing_root}" -o mode=755,nosuid,nodev
ExecStart=/bin/mkdir -p "${datadir}" "${workdir}"
EOF
_cat_to_file "${post_unit}" <<EOF
[Unit]
Description=Create backing directories for ${mountpoint}
Before=local-fs.target
After=mnt-stateful_partition-make-private.service
DefaultDependencies=no
[Service]
Type=oneshot
ExecStart=/bin/umount "${backing_root}"
ExecStart=/bin/rmdir "${backing_root}"
EOF
if [[ "${owner}" != - ]]; then
echo "ExecStart=/bin/chown ${owner} ${datadir}" >>"${D}${prep_unit}"
fi
if [[ "${chmod}" != - ]]; then
echo "ExecStart=/bin/chmod ${chmod} ${datadir}" >>"${D}${prep_unit}"
fi
systemd_enable_service local-fs.target "${mount_unit}"
}