#!/bin/sh
# This scripts is used to unify the disk space used by vservers
# It takes various RPM packages and hard link them together so all
# vservers are sharing the same exact copy of the files.
# After doing so, it set them immutable, so the vserver can't change them
#
# This has the following advantages:
#	-You save disk space. If you have 100 vservers, each using 500 megs
#	 (common linux server installation), you can unify 90% of that
#	-Memory usage. Since the exact same binary are loaded, including
#	 the same shared object, you save some memory and this can increase
#	 performance, especially the memory cache usage.
#
# On the down side, you are loosing some flexibility. The vserver
# administrators can't upgrade package as they see fit, since the
# files are immutable. On the other end, just unifying glibc is probably
# a win.
if [ $# = 0 ] ; then
	echo vunify [ --undo ] ref-vserver vservers -- packages
else
	undo=0
	if [ "$1" == "--undo" ] ; then
		undo=1
		shift
	fi
	ref=$1
	shift
	servers=
	while [ "$1" != "" -a "$1" != "--" ]
	do
		servers="$servers $1"
		shift
	done
	if [ "$servers" = "" ] ; then
		echo No vserver specified >&2
		exit 1
	elif [ "$1" != "--" ] ; then
		echo Missing -- marker >&2
		exit 1
	else
		shift
		if [ $# = 0 ] ; then
			echo No package specified >&2
			exit 1
		else
			if [ ! -d /vservers/$ref/. ] ; then
				echo No vserver $ref >&2
				exit 1
			else
				#echo ref=$ref
				#echo servers=$servers
				#echo packages=$*
				tmpfile=/var/run/vunifi.$$
				rm -f $tmpfile
				echo Extracting list of file to unify in $tmpfile
				for pkg in $*
				do
					/vservers/$ref/bin/rpm --root /vservers/$ref -ql --dump $pkg | \
					while read path size mtime md5 \
						mode owner group isconfig isdoc rdev symlink
					do
						if [ "$isconfig" = 0 ] ; then
							echo $path >>$tmpfile
						fi
					done
				done
				for serv in $servers
				do
					if [ "$undo" = 0 ] ; then
						echo Unifying server $serv
						cat $tmpfile | while read file
						do
							if [ ! -d /vservers/$ref/$file -a ! -L /vservers/$ref/$file ] ; then
								ln -f /vservers/$ref/$file /vservers/$serv/$file
							fi
						done
						cat $tmpfile | while read file
						do
							chattr +i /vservers/$ref/$file
						done
					else
						echo Differencing server $serv
						cat $tmpfile | while read file
						do
							chattr -i /vservers/$ref/$file
							if [ ! -d /vservers/$ref/$file ] ; then
								rm -f /vservers/$serv/$file
								cp -a /vservers/$ref/$file /vservers/$serv/$file
							fi
						done
					fi
				done
				rm -f $tmpfile 
			fi
		fi
	fi
fi

