cc7dcdd642
Changes: - clean up leftover swapfiles after unexpected reboots - also works if no swap is configured PR: ports/169467 Submitted by: freebsd@nagilum.org (maintainer) Approved by: crees (mentor)
234 lines
7.6 KiB
Bash
234 lines
7.6 KiB
Bash
#!/bin/sh
|
|
#
|
|
# swapmon - add / remove swap as needed
|
|
#
|
|
# Copyright (C) 2010 Alexander Kuehn. All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
# SUCH DAMAGE.
|
|
#
|
|
|
|
CONFIG=%%PREFIX%%/etc/swapmonrc
|
|
VERSION="1.5"
|
|
|
|
if [ -r "${CONFIG}" ]
|
|
then . "${CONFIG}"
|
|
fi
|
|
|
|
# where to create swapfiles
|
|
: ${SM_HOME=/usr/.swap}
|
|
# if the swap usage is higher than that (percentage) new swap will be added
|
|
: ${SWAP_HIGH=75}
|
|
# if the swap usage is lower than that then a previously added swapfile will be removed
|
|
: ${SWAP_LOW=45}
|
|
# if swap is running low we will increase the swapspace by this many percent
|
|
: ${SWAP_STEP=$(( 100 - ${SWAP_HIGH} ))}
|
|
# if running as daemon how long to wait between checks
|
|
: ${DELAY=30}
|
|
# if running as daemon where to log messages
|
|
: ${LOGGER=/usr/bin/logger}
|
|
# if running as daemon where to put pidfile
|
|
: ${PIDFILE=/var/run/swapmon.pid}
|
|
# if no swap is configured create a swapfile with this size
|
|
: ${SWAP_MIN=256}
|
|
|
|
LOCKF=$SM_HOME/lock
|
|
SWAPFILE=$SM_HOME/swap.XXXX
|
|
SWAPLIST=$SM_HOME/swapfiles
|
|
SWAPDEF=$SM_HOME/swap.def
|
|
MKTEMP=/usr/bin/mktemp
|
|
TRUNCATE=/usr/bin/truncate
|
|
TOUCH=/usr/bin/touch
|
|
CHMOD=/bin/chmod
|
|
MDCONFIG=/sbin/mdconfig
|
|
SWAPON=/sbin/swapon
|
|
SWAPOFF=/sbin/swapoff
|
|
SWAPCTL=/sbin/swapctl
|
|
RM=/bin/rm
|
|
SED=/usr/bin/sed
|
|
PERM=600
|
|
UID=$(/usr/bin/id -u)
|
|
GID=$(/usr/bin/id -g)
|
|
umask 0077
|
|
|
|
# a few sanity checks to see if we can do our work
|
|
if [ $UID -gt 0 ]
|
|
then echo "I'm not running as root (uid=0) this probably wont work."
|
|
# exit 1
|
|
fi
|
|
|
|
if [ \! -d ${SM_HOME} ]
|
|
then /bin/mkdir -p ${SM_HOME} || { echo "Error creating ${SM_HOME}!" ; exit 1; }
|
|
fi
|
|
$TOUCH ${SWAPLIST} || { echo "Can't write to ${SWAPLIST} aborting." ; exit 1; }
|
|
# add a 1MB swapfile to check if we have the permissions to do so
|
|
NSWAP=$($MKTEMP ${SWAPFILE})
|
|
$TRUNCATE -s 1M "${NSWAP}" || { echo "Error creating swapfile ${NSWAP}, aborting." ; exit 1; }
|
|
$CHMOD ${PERM} "${NSWAP}"
|
|
MDEV=$($MDCONFIG -a -t vnode -f "${NSWAP}")
|
|
if [ -n "$MDEV" ]
|
|
then
|
|
$SWAPON /dev/${MDEV} || { echo "error activating swapdevice /dev/${MDEV}."; exit 1; }
|
|
$SWAPOFF "/dev/${MDEV}"
|
|
$MDCONFIG -d -u ${MDEV} >/dev/null
|
|
$RM -f "${NSWAP}"
|
|
else
|
|
echo "error configuring memory disk ($MDCONFIG -a -t vnode -f \"${NSWAP}\")"
|
|
$RM -f "${NSWAP}"
|
|
exit
|
|
fi
|
|
# delete leftover swapfiles
|
|
find $SM_HOME -maxdepth 1 -name $(echo ${SWAPFILE##*/}|tr X \?) -type f \
|
|
-perm ${PERM} -user $UID -group $GID -exec $RM -fv "{}" \;
|
|
|
|
if [ ${SWAP_LOW} -ge $(( $(($SWAP_HIGH * 100)) / $((100 + $SWAP_STEP)) )) ]
|
|
then echo "SWAP_LOW(${SWAP_LOW}) schould be lower than $(( $(($SWAP_HIGH * 100)) / $((100 + $SWAP_STEP)) )) to be useful."
|
|
echo "Swapmon $VERSION."
|
|
exit 1
|
|
fi
|
|
|
|
# if there is no swap configured, add some
|
|
add_def_swap()
|
|
{
|
|
SWAPCTLSK=$($SWAPCTL -sk)
|
|
SWAPTOTAL=${SWAPCTLSK#* }
|
|
SWAPTOTAL=${SWAPTOTAL% *}
|
|
if [ "$SWAPTOTAL" -eq 0 ]
|
|
then
|
|
if [ "${SWAP_MIN}" -gt 0 ]
|
|
then
|
|
if [ -e "${SWAPDEF}" ] # if the file already exists
|
|
then if [ -f "${SWAPDEF}" -a \! -h "${SWAPDEF}"] # is it a regular file and no symlink?
|
|
then $RM -f "${SWAPDEF}"
|
|
else echo "Error: swapfile ${SWAPDEF} is not a regular file, aborting." ; exit 1;
|
|
fi
|
|
fi
|
|
$TRUNCATE -s ${SWAP_MIN}M "${SWAPDEF}" || { echo "Error creating swapfile ${SWAPDEF}, aborting." ; exit 1; }
|
|
$CHMOD $PERM "${SWAPDEF}"
|
|
MDEV=$($MDCONFIG -a -t vnode -f "${SWAPDEF}")
|
|
if [ -n "$MDEV" ]
|
|
then
|
|
$SWAPON /dev/${MDEV} || { echo "error activating swapdevice /dev/${MDEV}."; exit 1; }
|
|
echo "swapmon$VERSION[$$] Activated swapfile ${SWAPDEF} as there was no swap configured!"|$LOGGER
|
|
else
|
|
echo "error configuring memory disk ($MDCONFIG -a -t vnode -f \"${SWAPDEF}\")"
|
|
$RM -f "${SWAPDEF}"
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "No swap configured, SWAP_MIN set to $SWAP_MIN - aborting."
|
|
exit 1
|
|
fi
|
|
fi
|
|
}
|
|
|
|
check_swap()
|
|
{
|
|
SWAPCTLSK=$($SWAPCTL -sk)
|
|
SWAPTOTAL=${SWAPCTLSK#* }
|
|
SWAPTOTAL=${SWAPTOTAL% *}
|
|
SWAPUSAGE=$(( ${SWAPCTLSK##* } * 100 / $SWAPTOTAL ))
|
|
if [ ${SWAPUSAGE} -gt ${SWAP_HIGH} ]
|
|
then NSWAP=$($MKTEMP ${SWAPFILE})
|
|
BLOCKS=$(( $(( ${SWAPTOTAL} * ${SWAP_STEP} +1023)) / 102400 ))
|
|
# make sure we can write to the swaplist
|
|
$TOUCH "${SWAPLIST}" || { echo "swapmon$VERSION[$$] Error modifying ${SWAPLIST} exiting."|$LOGGER; exit 1; }
|
|
$TRUNCATE -s ${BLOCKS}M "${NSWAP}"
|
|
$CHMOD $PERM "${NSWAP}"
|
|
if [ -s "${NSWAP}" ]
|
|
then MDEV=$($MDCONFIG -a -t vnode -f "${NSWAP}")
|
|
printf "${MDEV} ${NSWAP}\n" >>"${SWAPLIST}"
|
|
echo "swapmon$VERSION[$$] Swapusage ${SWAPUSAGE}%($((${SWAPCTLSK##* }/1024))/$(($SWAPTOTAL/1024)) M), activated new swapdevice ${MDEV} backed by ${NSWAP}."|$LOGGER
|
|
$SWAPON /dev/${MDEV}
|
|
$SWAPCTL -lh|$SED -e "s/^/swapmon$VERSION[$$] /g"|$LOGGER
|
|
else echo "swapmon$VERSION[$$] Creating swapfile ${NSWAP} failed! :("|$LOGGER
|
|
fi
|
|
fi
|
|
while [ \( ${SWAPUSAGE} -lt ${SWAP_LOW} \) -a -s "${SWAPLIST}" ]
|
|
do MDEV=$(/usr/bin/tail -1 "${SWAPLIST}")
|
|
SWAPF=${MDEV#* }
|
|
MDEV=${MDEV%% *}
|
|
if [ -s "${SWAPF}" ]
|
|
then if [ "${SWAPF}" = "$($MDCONFIG -l -u ${MDEV}|/usr/bin/awk '{print $4}')" ]
|
|
then if [ -n "$($SWAPCTL -l|$SED -n '1!p'|/usr/bin/grep '/dev/'${MDEV})" ]
|
|
then echo "swapmon$VERSION[$$] Swapusage ${SWAPUSAGE}%($((${SWAPCTLSK##* }/1024))/$(($SWAPTOTAL/1024)) M), deactivating swapdevice ${MDEV}."|$LOGGER
|
|
$SWAPCTL -lh|$SED -e "s/^/swapmon$VERSION[$$] /g"|$LOGGER
|
|
$SWAPOFF "/dev/${MDEV}"
|
|
fi
|
|
echo "swapmon$VERSION[$$] Detaching vnode ${MDEV}."|$LOGGER
|
|
$MDCONFIG -d -u ${MDEV} >/dev/null
|
|
$RM -f "${SWAPF}"
|
|
else echo "swapmon$VERSION[$$] Swapfile ${SWAPF} is not attached to ${MDEV} as it should be!?"|$LOGGER
|
|
for MDEV in $($MDCONFIG -l)
|
|
do echo "swapmon$VERSION[$$] $($MDCONFIG -l -u ${MDEV})"|$LOGGER
|
|
done
|
|
fi
|
|
else echo "swapmon$VERSION[$$] ${SWAPF} is not a valid swapfile."|$LOGGER
|
|
fi
|
|
$SED -I '' -n '$!p' "${SWAPLIST}"
|
|
SWAPCTLSK=$($SWAPCTL -sk)
|
|
SWAPTOTAL=${SWAPCTLSK#* }
|
|
SWAPTOTAL=${SWAPTOTAL% *}
|
|
SWAPUSAGE=$(( ${SWAPCTLSK##* } * 100 / $SWAPTOTAL ))
|
|
done
|
|
}
|
|
|
|
add_def_swap # this will check if there is some swap configured
|
|
# we can't work without
|
|
case "$1" in
|
|
start)
|
|
$0 -F <&- 2>&1 >/dev/null &
|
|
;;
|
|
stop)
|
|
if [ -s "${PIDFILE}" ]
|
|
then
|
|
PID=$(/bin/cat ${PIDFILE})
|
|
if ( /bin/ps -p $PID|grep -q $0 )
|
|
then /bin/kill $PID
|
|
fi
|
|
$RM "${PIDFILE}"
|
|
fi
|
|
;;
|
|
-F)
|
|
echo $$ >"${PIDFILE}"
|
|
echo "swapmon$VERSION[$$] Writing pid $$ to pidfile ${PIDFILE}."|$LOGGER
|
|
cd / || exit 1
|
|
while [ -f "${PIDFILE}" ]
|
|
do check_swap
|
|
sleep ${DELAY}
|
|
done
|
|
;;
|
|
'')
|
|
if [ -r "${LOCKF}" ]
|
|
then
|
|
echo "${LOCKF} exists"
|
|
exit 1;
|
|
else
|
|
echo $$ >"${LOCKF}"
|
|
LOGGER="/bin/cat"
|
|
check_swap
|
|
fi
|
|
$RM -f "${LOCKF}"
|
|
;;
|
|
*)
|
|
echo "$* not supported"
|
|
;;
|
|
esac
|