| # |
| # 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 |
| After=mount-etc-overlay.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}" |
| } |