#!/bin/sh
#
# ramdisk rc functions for Arch Linux
# (by Jakub Neburka, neburka@volny.cz)
#
# This script is meant to be used for Arch linux installed on SSD drive. Script
# manages mounting frequently written directories as tmpfs. This should longer
# the life of SSD hard drives.
#
# USE AT YOUR OWN RISK !!!
#
# Prerequisites:
# --------------
# Arch linux installed. No swap partition active (It also kills SSDs).
#
# Installation:
# -------------
# 1) Check variables definitions in this script and modify them to fit your
# needs.
# 2) Copy this file to /etc/rc.d/functions.d/ directory.
# 3) Add rd_sysinit function call to /etc/rc.sysinit just after
# "Activating Swap" line.
# 4) Add rd_shutdown function call to /etc/rc.shutdown just before
# "Deactivating Swap" line.
# 5) Edit ramdisk "dirlist file" (defaults to /etc/ramdisk) to tell this
# script, which directories will be moved to ramdisk. The file should list
# directories one per line. Paths should be absolute and without trailing
# slash. Example of /etc/ramdisk file:
# /tmp
# /var/log
# /var/lock
# /var/run
# /home/jakub/.cache/chromium
# 6) Restart the system to se what will happend :)
#
# Warnings:
# - After the system update (pacman -Syu), there is sometimes necessery to
# repeat installation steps 3) and 4) (to reedit system rc scripts).
# - The script only moves directories in one way (/ -> /ramroot).
#
# Tip:
# use command inotifywatch from package inotify-tools to determine, which
# files are often modified and which directories should be moved to RAM.
#

#
# Variables to modify:
#
# Ramroot mount point (will be created)
RD_DIR=/ramdisk
# Ramroot maximum size (tmpfs grows up to this size)
RD_SIZE=512M
# File used for ramdisk backups
RD_BACKUP=/ramdisk.cpio
# Ramdisk "dilist file" file name
RD_DLIST=/etc/ramdisk

#
# Functions:
#

rd_mount()
{
	mkdir -p ${RD_DIR}

	if [ -d ${RD_DIR} ]
	then
		mount -t tmpfs -o size=${RD_SIZE} none ${RD_DIR}

		return $?
	fi

	return 1
}

rd_restore()
{
	if [ -f ${RD_BACKUP} ]
	then
		(cd ${RD_DIR}; cpio -idum < ${RD_BACKUP}) >/dev/null 2>&1

		return $?
	fi

	return 0
}

rd_populate()
{
	if [ ! -f ${RD_DLIST} ]
	then
		return 0
	fi

	ret=0

	while [ ${ret} -eq 0 ] && read dir
	do
		if [ ! -d ${RD_DIR}${dir} -a ! -L ${dir} ]
		then
			rd_move_dir ${dir} || ret=1
		fi

	done < ${RD_DLIST}

	return ${ret}
}

rd_move_dir()
{
	base=`basename ${1}`
	dir=`dirname ${1}`

	mkdir -p ${RD_DIR}${dir}

	(cd ${dir}; find ${base} -print | cpio -pdum ${RD_DIR}${dir}) >/dev/null 2>&1

	if [ $? -ne 0 ]
	then
		return 1
	fi

	tmpdir=/rd_$$
	mv ${1} ${tmpdir}

	ln -s ${RD_DIR}${1} ${1}

	ret=$?

	rm -rf ${tmpdir}
	
	return ${ret}
}

rd_save()
{
	if [ -d ${RD_DIR} ]
	then
		(cd ${RD_DIR}; find . -print | cpio -oO ${RD_BACKUP})\
		    >/dev/null 2>&1

		return $?
	fi

	return 1
}

rd_unmount()
{
	if [ -d ${RD_DIR} ]
	then

		umount ${RD_DIR}

		return $?
	fi

	return 1
}

rd_sysinit()
{
	stat_busy "Loading Ramdisk"

	if rd_mount && rd_restore && rd_populate
	then

		stat_done
		return 0
	fi

	stat_fail
	return 1
}

rd_shutdown()
{
	stat_busy "Saving Ramdisk"

	if rd_save && rd_unmount
	then
		stat_done
		return 0
	fi

	stat_fail
	return 1
}

# EOF
