Path: blob/master/pkg/cidata/cidata.TEMPLATE.d/boot/04-persistent-data-volume.sh
2655 views
#!/bin/bash12# SPDX-FileCopyrightText: Copyright The Lima Authors3# SPDX-License-Identifier: Apache-2.045# bash is used for enabling `set -o pipefail`.6# NOTE: On Alpine, /bin/bash is ash with ASH_BASH_COMPAT, not GNU bash7set -eux -o pipefail89# Restrict the rest of this script to Alpine until it has been tested with other distros10test -f /etc/alpine-release || exit 01112# Nothing to do unless we are running from a ramdisk13[ "$(awk '$2 == "/" {print $3}' /proc/mounts)" != "tmpfs" ] && exit 01415# Data directories that should be persisted across reboots16DATADIRS="/etc /home /root /tmp /usr/local /var/lib"1718# Prepare mnt.sh (used for restoring mounts later)19echo "#!/bin/sh" >/mnt.sh20echo "set -eux" >>/mnt.sh21for DIR in ${DATADIRS}; do22while IFS= read -r LINE; do23[ -z "$LINE" ] && continue24MNTDEV="$(echo "${LINE}" | awk '{print $1}')"25# unmangle " \t\n\\#"26# https://github.com/torvalds/linux/blob/v6.6/fs/proc_namespace.c#L8927MNTPNT="$(echo "${LINE}" | awk '{print $2}' | sed -e 's/\\040/ /g; s/\\011/\t/g; s/\\012/\n/g; s/\\134/\\/g; s/\\043/#/g')"28# Ignore if MNTPNT is neither DIR nor a parent directory of DIR.29# It is not a parent if MNTPNT doesn't start with DIR, or the first30# character after DIR isn't a slash.31WITHOUT_DIR="${MNTPNT#"$DIR"}"32# shellcheck disable=SC216633[ "$MNTPNT" != "$DIR" ] && [ "$MNTPNT" == "$WITHOUT_DIR" -o "${WITHOUT_DIR::1}" != "/" ] && continue34MNTTYPE="$(echo "${LINE}" | awk '{print $3}')"35[ "${MNTTYPE}" = "ext4" ] && continue36[ "${MNTTYPE}" = "tmpfs" ] && continue37MNTOPTS="$(echo "${LINE}" | awk '{print $4}')"38if [ "${MNTTYPE}" = "9p" ]; then39# https://github.com/torvalds/linux/blob/v6.6/fs/9p/v9fs.h#L6140MNTOPTS="$(echo "${MNTOPTS}" | sed -e 's/cache=8f,/cache=fscache,/; s/cache=f,/cache=loose,/; s/cache=5,/cache=mmap,/; s/cache=1,/cache=readahead,/; s/cache=0,/cache=none,/')"41fi42# Before mv, unmount filesystems (virtiofs, 9p, etc.) below "${DIR}", otherwise host mounts will be wiped out43# https://github.com/rancher-sandbox/rancher-desktop/issues/658244umount "${MNTPNT}" || exit 145MNTPNT=${MNTPNT//\\/\\\\}46MNTPNT=${MNTPNT//\"/\\\"}47echo "mount -t \"${MNTTYPE}\" -o \"${MNTOPTS}\" \"${MNTDEV}\" \"${MNTPNT}\"" >>/mnt.sh48done </proc/mounts49done50chmod +x /mnt.sh5152mkdir -p /mnt/data53if [ -e /dev/disk/by-label/data-volume ]; then54# Find which disk is data volume on55DATA_DISK=$(blkid | grep "data-volume" | awk '{split($0,s,":"); sub(/\d$/, "", s[1]); print s[1]};')56# growpart command may be missing in older VMs57if command -v growpart >/dev/null 2>&1 && command -v resize2fs >/dev/null 2>&1; then58# Automatically expand the data volume filesystem59growpart "$DATA_DISK" 1 || true60# Only resize when filesystem is in a healthy state61if e2fsck -f -p /dev/disk/by-label/data-volume; then62resize2fs /dev/disk/by-label/data-volume || true63fi64fi65# Mount data volume66mount -t ext4 /dev/disk/by-label/data-volume /mnt/data67# Update /etc files that might have changed during this boot68cp /etc/network/interfaces /mnt/data/etc/network/69cp /etc/resolv.conf /mnt/data/etc/70if [ -f /etc/localtime ]; then71# Preserve symlink72cp -d /etc/localtime /mnt/data/etc/73# setup-timezone copies the single zoneinfo file into /etc/zoneinfo and targets the symlink there74if [ -d /etc/zoneinfo ]; then75rm -rf /mnt/data/etc/zoneinfo76cp -r /etc/zoneinfo /mnt/data/etc77fi78fi79if [ -f /etc/timezone ]; then80cp /etc/timezone /mnt/data/etc/81fi82# TODO there are probably others that should be updated as well83else84# Find an unpartitioned disk and create data-volume85DISKS=$(lsblk --list --noheadings --output name,type | awk '$2 == "disk" {print $1}')86for DISK in ${DISKS}; do87IN_USE=false88# Looking for a disk that is not mounted or partitioned89# shellcheck disable=SC201390for PART in $(awk '/^\/dev\// {gsub("/dev/", ""); print $1}' /proc/mounts); do91if [ "${DISK}" == "${PART}" ] || [ -e /sys/block/"${DISK}"/"${PART}" ]; then92IN_USE=true93break94fi95done96if [ "${IN_USE}" == "false" ]; then97echo 'type=83' | sfdisk --label dos /dev/"${DISK}"98PART=$(lsblk --list /dev/"${DISK}" --noheadings --output name,type | awk '$2 == "part" {print $1}')99mkfs.ext4 -L data-volume /dev/"${PART}"100mount -t ext4 /dev/disk/by-label/data-volume /mnt/data101# setup apk package cache102mkdir -p /mnt/data/apk/cache103mkdir -p /etc/apk104ln -s /mnt/data/apk/cache /etc/apk/cache105# Move all persisted directories to the data volume106for DIR in ${DATADIRS}; do107DEST="/mnt/data$(dirname "${DIR}")"108mkdir -p "${DIR}" "${DEST}"109mv "${DIR}" "${DEST}"110done111# Make sure all data moved to the persistent volume has been committed to disk112sync113break114fi115done116fi117for DIR in ${DATADIRS}; do118if [ -d /mnt/data"${DIR}" ]; then119mkdir -p "${DIR}"120mount --bind /mnt/data"${DIR}" "${DIR}"121fi122done123# Remount submounts on top of the new ${DIR}124/mnt.sh125# Reinstall packages from /mnt/data/apk/cache into the RAM disk126apk fix --no-network127128129