#!/sbin/openrc-run
# SPDX-FileCopyrightText: 2026 zyxhere💭 <zyx@envs.net>
# SPDX-License-Identifier: 0BSD

: ${DEV:=/dev/zram0}
: ${MEM:=$(free --bytes | grep Mem | awk ' { print $2 } ')}
: ${SWAP:=$(free | grep Swap | awk ' { print $2 } ')}

description="Simple zram swap"

depend() {
    after modules

    # OpenRC bug where $RC_SERVICE isn't exported
    # in depend(), do a workaround
    local RC_SERVICE=
    RC_SERVICE=../$RC_SVCNAME

    # provide swap if the real one doesn't exist
    [ ! -f ${RC_SERVICE%/*}/swap ] && provide swap
}

loadzram() {

    case $size in
        # calculate the size from num%
        *%) size=$(( ${size//%} * ( MEM / 100 ) )) ;;
        *) [ -z $size ] && size=$(( MEM / 2 )) ;;
    esac

    ebegin "Loading zram module and device"
    modprobe -q zram num_devices=1 >/dev/null 2>&1
    zramctl --algorithm ${algorithm:=zstd} \
            --size $size $zramctl_args -- $DEV
    eend $? "Failed to load zram device"

    return $?
}

stopzram() {

    local retval=

    ebegin "Resetting zram module and device"
    zramctl --reset -- $DEV
    eend $? "Failed to reset zram device"; retval=$?
    # zram module might be built into the kernel
    modprobe -q --remove zram >/dev/null 2>&1

    return $retval
}

start_pre() {

    [ -b $DEV ] &&
	ewarn "$DEV already a block device, continuing anyway"

    case $RC_UNAME in
        Linux) ;;
        *)
	    eerror "$RC_SVCNAME should only be used on Linux"
	    return 1
	    ;;
    esac

    # check for any sort of swap and warn that
    # zram should not be used with regular swap
    # thats what zswap is for (zram should not
    # be used with zswap either but is possible)
    [ $SWAP -gt 0 ] && {
        ewarn "Some sort of swap is already active zram use is"
        ewarn "not recommended. Turn off swap with:"
        ewarn "\`swapoff -a\` and and restart the service."
    }

    loadzram || {
	einfo "Failure likely due to $DEV already being active"
	ebegin "Force retrying"
	stop && stop_post && loadzram
	eend $?

	return $?
    }
}

start() {
    ebegin "Turning ON $description"
    mkswap -- $DEV >/dev/null 2>&1 &&
	swapon -- $DEV
    eend $? "Failed to turn ON $description" || {
	stopzram; return 1
    }
}

stop() {

    [ $SWAP -eq 0 ] && {
        ewarn "Seems that $DEV swap is already turned off"
        ewarn "Service will be marked as stopped"
	mark_service_stopped
	return 0
    }

    ebegin "Turning off zram swap"
    # swapoff errors out if theres nothing to do
    swapoff -- $DEV >/dev/null 2>&1
    eend 0
}

stop_post() {
    # race condition with swapoff (sometimes)
    # zramctl: $DEV: failed to reset: Resource temporarily unavailable
    sleep 1
    stopzram
}
