diff options
author | Aaron Ball <nullspoon@oper.io> | 2021-09-26 20:19:50 -0600 |
---|---|---|
committer | Aaron Ball <nullspoon@oper.io> | 2021-09-26 20:19:50 -0600 |
commit | 7fd96e4fffc25629653210a562e9077405e6fca0 (patch) | |
tree | 43d385fea2fd2ce9f494cc152a87f0e0354e01f6 | |
parent | fa5eaf860940060f61670a8e41eb58707c3e12c2 (diff) | |
download | zmount-emulate-util-linux-mount.tar.gz zmount-emulate-util-linux-mount.tar.xz |
Further refactoring to emulate util-linux mount commandsemulate-util-linux-mount
Previously this script (zmount) worked like an init script, with start,
stop, status commands. Now this behaves more like the util-linux mount
commands, mount and umount. This provides the commands zmount and
zumount. Currently it only supports the `-a` switch, which mounts all or
unmounts all zram filesystems.
This also provides a makefile for installing these scripts and the
corresponding script library to their relevant directories.
-rw-r--r-- | Makefile | 15 | ||||
-rw-r--r-- | lib/zmount.lib.sh | 127 | ||||
-rwxr-xr-x | zmount | 176 | ||||
-rwxr-xr-x | zmount.init | 11 | ||||
-rwxr-xr-x | zumount | 97 |
5 files changed, 288 insertions, 138 deletions
@@ -1,5 +1,14 @@ .DEFAULT: install +PREFIX := /usr +VERSION=1.0 -install: - install -D -v -m 755 zmount $(DESTDIR)/bin/zmount - install -D -v -m 755 ztab.example $(DESTDIR)/etc/ztab +interpolate: + if [ ! -d tmp ]; then mkdir -p tmp; fi + sed 's/{{ VERSION }}/$(VERSION)/' < zmount > tmp/zmount + sed 's/{{ VERSION }}/$(VERSION)/' < zumount > tmp/zumount + +install: interpolate + install -D -v -m 755 tmp/zmount $(DESTDIR)$(PREFIX)/bin/zmount + install -D -v -m 755 tmp/zumount $(DESTDIR)$(PREFIX)/bin/zumount + install -D -v -m 644 lib/zmount.lib.sh $(DESTDIR)$(PREFIX)/lib/zmount.lib.sh + install -D -v -m 755 ztab.example $(DESTDIR)/etc/ztab diff --git a/lib/zmount.lib.sh b/lib/zmount.lib.sh new file mode 100644 index 0000000..5743032 --- /dev/null +++ b/lib/zmount.lib.sh @@ -0,0 +1,127 @@ +#!/usr/bin/env bash +# Zmount automatically configures zram devices with the ztab config file +# Copyright (C) 2021 Aaron Ball <nullspoon@oper.io> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set -euo pipefail +export IFS=$'\n\t' + + +CONFIG='/etc/ztab' +RUN='/var/run/zmount' + +writelog() { printf '%s\n' "${1}"; } +error() { writelog "ERROR: ${1}" >&2; } + +require_root() { + if [ "${UID}" -ne 0 ]; then + printf 'Must be run as root\n' >&2 + return 1 + fi + return 0 +} + +zmount.ztab.parseline() { + local -a lineargs=() + lineargs=($(printf '%s\n' "${1:?}" | tr ' ' '\n')) + if [ "${#lineargs[@]}" -ne 5 ]; then + error "Line ${1} does not have correct columns" + return 1 + fi + printf '%s\n' ${lineargs[@]} + return 0 +} + +zmount.swap.setup() { + local size="${1}" + local dev="$(zramctl -f)" + + [ ! -d "${RUN}" ] && mkdir -p ${RUN} + + # Check for existing mounts to avoid duplicates + if [ -f "${RUN}/swap" ]; then + error 'Zswap device already detected. Skipping duplicate.' + return 1 + fi + + # Create the zram device + zramctl "${dev}" -s "${size}" -t "$(( $(nproc) / 2 ))" + + mkswap "${dev}" 2>&1 1>/dev/null + swapon "${dev}" + printf '%s\n' "${dev}" > "${RUN}/swap" +} + + +zmount.dir.setup() { + local fs="${1}" + local size="${2}" + local dir="${3}" + local opts="${4:-defaults}" + local perms="${5:-none}" # Default to 777 to emulate tmpfs + local dev="$(zramctl -f)" + + [ ! -d "${RUN}" ] && mkdir -p ${RUN} + + # Check for existing mounts to avoid duplicates + if [ -f "${RUN}/${dir//\//_}" ]; then + error "Skipping duplicate mount dir ${dir}" + return 1 + fi + + # Create the zram device + zramctl "${dev}" -s "${size}" -t "$(( $(nproc) / 2 ))" + + if [ "${fs}" = 'btrfs' ]; then + mkfs.btrfs -q "${dev}" + elif [ "${fs}" = 'ext2' ]; then + mkfs.ext2 -q "${dev}" + elif [ "${fs}" = 'ext3' ]; then + mkfs.ext3 -q "${dev}" + elif [ "${fs}" = 'ext4' ]; then + mkfs.ext4 -q "${dev}" + elif [ "${fs}" = 'exfat' ]; then + mkfs.exfat -q "${dev}" + elif [ "${fs}" = 'vfat' ]; then + mkfs.vfat -q "${dev}" + elif [ "${fs}" = 'xfs' ]; then + mkfs.xfs -q "${dev}" + else + printf 'Unknown filesystem type %s\n' "${fs}" + return 1 + fi + mount -o "${opts}" "${dev}" "${dir}" + printf '%s\n' "${dev}" > "${RUN}/${dir//\//_}" +} + +zmount.dir.setperms() { + local dir="${1}" + local permstr="${2}" + local perm + local -a keyval=() + + [ "${permstr}" = 'none' ] && return 0 + + for perm in $(printf '%s\n' ${permstr} | tr ',' '\n'); do + keyval=($(printf '%s\n' "${perm}" | tr '=' '\n')) + if [ "${keyval[0]}" = 'user' ]; then + chown "${keyval[1]}" "${dir}" + elif [ "${keyval[0]}" = 'group' ]; then + chgrp "${keyval[1]}" "${dir}" + elif [ "${keyval[0]}" = 'mode' ]; then + chmod "${keyval[1]}" "${dir}" + fi + done +} @@ -18,161 +18,67 @@ set -euo pipefail export IFS=$'\n\t' -CONFIG='/etc/ztab' -RUN='/var/run/zmount' - -_parseline() { - local -a lineargs=() - lineargs=($(printf '%s\n' "${1:?}" | tr ' ' '\n')) - if [ "${#lineargs[@]}" -ne 5 ]; then - printf 'ERROR: Line "%s" does not have correct columns\n' >&2 - return 1 - fi - printf '%s\n' ${lineargs[@]} - return 0 -} - -_setperms() { - local dir="${1}" - local permstr="${2}" - local perm - local -a keyval=() - - [ "${permstr}" = 'none' ] && return 0 - - for perm in $(printf '%s\n' ${permstr} | tr ',' '\n'); do - keyval=($(printf '%s\n' "${perm}" | tr '=' '\n')) - if [ "${keyval[0]}" = 'user' ]; then - chown "${keyval[1]}" "${dir}" - elif [ "${keyval[0]}" = 'group' ]; then - chgrp "${keyval[1]}" "${dir}" - elif [ "${keyval[0]}" = 'mode' ]; then - chmod "${keyval[1]}" "${dir}" - fi - done -} - -_setup_dev() { - local fs="${1}" - local size="${2}" - local dir="${3}" - local opts="${4:-defaults}" - local perms="${5:-none}" # Default to 777 to emulate tmpfs - - local dev="$(zramctl -f)" - local threads="$(( $(nproc) / 2 ))" - - [ ! -d "${RUN}" ] && mkdir -p ${RUN} - - # Check for existing mounts to avoid duplicates - if [ "${fs}" = 'swap' ] && [ -f "${RUN}/swap" ]; then - printf 'ERROR: Zswap device already detected. Skipping second.\n' >&2 - return 1 - elif [ -f "${RUN}/${dir//\//_}" ]; then - printf 'ERROR: Skipping duplicate mount dir %s\n' "${dir}" >&2 - return 1 - fi - - # Create the zram device - zramctl "${dev}" -s "${size}" -t "${threads}" - - if [ "${fs}" = 'swap' ]; then - mkswap "${dev}" 2>&1 1>/dev/null - swapon "${dev}" - printf '%s\n' "${dev}" > "${RUN}/swap" - else - if [ "${fs}" = 'btrfs' ]; then - mkfs.btrfs -q "${dev}" - elif [ "${fs}" = 'ext2' ]; then - mkfs.ext2 -q "${dev}" - elif [ "${fs}" = 'ext3' ]; then - mkfs.ext3 -q "${dev}" - elif [ "${fs}" = 'ext4' ]; then - mkfs.ext4 -q "${dev}" - elif [ "${fs}" = 'exfat' ]; then - mkfs.exfat -q "${dev}" - elif [ "${fs}" = 'vfat' ]; then - mkfs.vfat -q "${dev}" - elif [ "${fs}" = 'xfs' ]; then - mkfs.xfs -q "${dev}" - else - printf 'Unknown filesystem type %s\n' "${fs}" - return 1 - fi - mount -o "${opts}" "${dev}" "${dir}" - printf '%s\n' "${dev}" > "${RUN}/${dir//\//_}" - fi -} +LIBDIR="${LIBDIR:-/usr/lib}" +source "${LIBDIR}/zmount.lib.sh" status() { zramctl; } -start() { +mountall() { local -a lineargs=() - for line in $(grep -v '^#' /etc/ztab); do - lineargs=($(_parseline "${line}")) + for line in $(grep -v '^ *#\|^$' "${CONFIG}"); do + lineargs=($(zmount.ztab.parseline "${line}")) if [ "${lineargs[0]}" = 'swap' ]; then - printf 'Setting up %s zswap\n' "${lineargs[1]}" + writelog "Setting up ${lineargs[1]} zswap" + zmount.swap.setup ${lineargs[1]} || continue else - printf 'Setting up %s zram dev on %s\n' "${lineargs[1]}" "${lineargs[2]}" + writelog "Setting up ${lineargs[1]} zram dev on ${lineargs[2]}" + zmount.dir.setup ${lineargs[@]} || continue + zmount.dir.setperms "${lineargs[2]}" "${lineargs[4]}" fi - _setup_dev ${lineargs[@]} - _setperms "${lineargs[2]}" "${lineargs[4]}" done } +gethelp() { + cat - <<EOF -stop() { - local -a lineargs=() - local fs size dir - - for line in $(grep -v '^#' /etc/ztab); do - lineargs=($(_parseline "${line}")) - fs="${lineargs[0]}" - size="${lineargs[1]}" - dir="${lineargs[2]}" - # Ignore opts and perms column - - if [ "${fs}" = 'swap' ] && [ -f "${RUN}/swap" ]; then - dev="$(cat ${RUN}/swap)" - printf 'Stopping %s (mounted as swap)\n' "${dev}" - swapoff "${dev}" - rm -f "${RUN}/swap" - else - if [ ! -f "${RUN}/${dir//\//_}" ]; then - printf '%s is already unmounted from %s\n' "${fs}" "${dir}" - continue - fi - dev="$(cat ${RUN}/${dir//\//_})" - printf 'Stopping %s (mounted on %s)\n' "${dev}" "${dir}" - umount "${dir}" || : # Ignore unmount failures - rm -f "${RUN}/${dir//\//_}" - fi - zramctl "${dev}" -r - done -} +Usage: + zmount [-hV] + zmount -a + zmount <path> +Mount zram filesystems. + +Options: + -a, --all unmount all zram filesystems + + -h, --help display this help + -V, --version display version + +EOF +} main() { - if [ ${UID} -ne 0 ]; then - printf 'Must be run as root\n' >&2 - return 1 - fi + local -a args=(${@}) # Make sure the zram module is loaded modprobe zram - if [ "${1:-}" = 'start' ]; then - start - elif [ "${1:-}" = 'stop' ]; then - stop - elif [ "${1:-}" = 'status' ]; then - status - else - printf 'usage: %s [start|stop|status]\n' "${0}" - return 1 - fi + # Print status if no args specified + [ "${#args[@]}" -eq 0 ] && status && return 0 + + for arg in ${args[@]}; do + if [ "${arg}" = '-h' ] || [ "${arg}" = '--help' ]; then + gethelp + elif [ "${arg}" = '-V' ] || [ "${arg}" = '--version' ]; then + writelog 'zmount {{ VERSION }}' + else + if [ "${arg}" = '-a' ]; then + require_root && mountall + fi + fi + done } main ${@} diff --git a/zmount.init b/zmount.init new file mode 100755 index 0000000..99972f1 --- /dev/null +++ b/zmount.init @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +set -euo pipefail +export IFS=$'\n\t' + +if [ "${1}" = 'start' ]; then + zmount -a +elif [ "${1}" = 'stop' ]; then + zumount -a +elif [ "${1}" = 'status' ]; then + zmount +fi @@ -0,0 +1,97 @@ +#!/usr/bin/env bash +# Zmount automatically configures zram devices with the ztab config file +# Copyright (C) 2021 Aaron Ball <nullspoon@oper.io> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# 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. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +set -euo pipefail +export IFS=$'\n\t' + +LIBDIR="${LIBDIR:-/usr/lib}" +source "${LIBDIR}/zmount.lib.sh" + +umountall() { + local -a lineargs=() + local fs size dir + + for line in $(grep -v '^#' "${CONFIG}"); do + lineargs=($(zmount.ztab.parseline "${line}")) + fs="${lineargs[0]}" + size="${lineargs[1]}" + dir="${lineargs[2]}" + # Ignore opts and perms column + + if [ "${fs}" = 'swap' ] && [ -f "${RUN}/swap" ]; then + dev="$(cat ${RUN}/swap)" + writelog "Stopping ${dev} (mounted as swap)" + swapoff "${dev}" + rm -f "${RUN}/swap" + else + if [ ! -f "${RUN}/${dir//\//_}" ]; then + writelog "${fs} is already unmounted from ${dir}" + continue + fi + dev="$(cat ${RUN}/${dir//\//_})" + writelog "Stopping ${dev} (mounted on ${dir})" + umount "${dir}" || : # Ignore unmount failures + rm -f "${RUN}/${dir//\//_}" + fi + zramctl "${dev}" -r + done +} + +gethelp() { + cat - <<EOF + +Usage: + zumount [-hV] + zumount -a + zumount <path> + +Unmount zram filesystems. + +Options: + -a, --all unmount all zram filesystems + + -h, --help display this help + -V, --version display version + +EOF +} + + +main() { + local -a args=(${@}) + + # Print status if no args specified + if [ "${#args[@]}" -eq 0 ]; then + printf 'zumount: bad usage\n' >&2 + printf "Try 'zumount --help' for more information.\n" >&2 + return 1 + fi + + for arg in ${args[@]}; do + if [ "${arg}" = '-h' ] || [ "${arg}" = '--help' ]; then + gethelp + elif [ "${arg}" = '-V' ] || [ "${arg}" = '--version' ]; then + writelog 'zumount {{ VERSION }}' + else + if [ "${arg}" = '-a' ]; then + require_root && umountall + fi + fi + done +} + +main ${@} |