Artifact 80c9e12fc3625ddf7f370c50a7c86053be67ee3b:
#!/bin/bash
# James Budiono 2011-2012, 2013
# Licens: GNU GPL Version 3 or later
# Load / unload SFS on the fly - this is also the system SFS loader for Fatdog64
#
# note: uses bash - we don't need speed here, we need features (uses array etc)
# can probably be converted to ash but I can't be bothered
# version 2 - supports start/stop as a service (to be run from /etc/init.d)
# When run in this way, supports persistence
# version 3 - proper recovery if we fail to load for whatever reason
# version 4 - canonicalise path if a parameter is passed in.
# version 5 - adapted to be the system SFS loader for Fatdog64, now lives in /sbin
# version 6 - more message, don't show base sfs
# constants and start-up variables
MAXLOOP=250 # highest loop device number we can use
RESERVED=10 # reserve 10 loop devices for filemnt and others
SFS_DIR=/mnt/home # where to look for sfs
BASE_SFS=fd64-620.sfs # don't show base sfs
UNLOAD_PERMANENTLY=false
LOAD_PERMANENTLY=false
LISTFILE=/etc/load_sfs
export SFS_DIR BASE_SFS
# boot-time configuration
#BOOTSTATE_PATH=/etc/BOOTSTATE
. $BOOTSTATE_PATH
[ "$BASE_SFS_PATH" ] && BASE_SFS=${BASE_SFS_PATH##*/}
# insertion point - below tmpfs, pup_save and pup_multi
INSERT_POINT=1 # tmpfs / pup_save
[ "$TMPFS_MOUNT" -a "$SAVEFILE_MOUNT" ] && INSERT_POINT=2 # both tmpfs & pup_save
[ "$MULTI_MOUNT" ] && INSERT_POINT=$(( $INSERT_POINT + 1 )) # pup_multi is another layer
########## core load/unload functions ###########
# $@ text to display
function message() {
if [ "$DISPLAY" ]; then
Xdialog --infobox "$@" 0 0 10000
else
echo "$@"
fi
}
# output - FREELOOP = free loop device
function find_free_loop() {
local loops_in_use
for i in $(losetup-FULL -a | sed 's/:.*$//;s_/dev/loop__'); do
loops_in_use[$i]=$i
done
#echo ${loops_in_use[@]}
for ((i=$RESERVED; i<$MAXLOOP; i++)); do
if [ -z "${loops_in_use[$i]}" ]; then
break
fi
done
#echo loop device $i is free
FREELOOP=$i
}
# $1 = loop device number
function check_and_make_loop_device() {
if [ ! -b /dev/loop$1 ]; then
mknod /dev/loop$1 b 7 $1
# else
# echo loop device $1 already exist
fi
}
# $1 = pup_ro number
function check_and_make_pupro() {
if [ ! -d $AUFS_ROOT/pup_ro$1 ]; then
mkdir -p $AUFS_ROOT/pup_ro$1
# else
# echo pup_ro$1 already exist
fi
}
# $1 = path to SFS to load
function sfs_load() {
# make sure we're not loading the same sfs twice
if [ -z "$(losetup-FULL -a | fgrep "${1##*/}")" ]; then
# find free loop device, re-using what we can, if we can't, then make new loop/pup_ro mountpoint
# keep loop-N and pup_ro-N sync at all times
find_free_loop
check_and_make_loop_device $FREELOOP
check_and_make_pupro $FREELOOP
# now ready to load
if losetup /dev/loop$FREELOOP "$1"; then
if mount -o ro /dev/loop$FREELOOP $AUFS_ROOT/pup_ro$FREELOOP; then
if busybox mount -t aufs -o remount,ins:$INSERT_POINT:$AUFS_ROOT/pup_ro$FREELOOP=rr aufs /; then
message "$1 loaded successfully."
else
message "Failed to remount aufs $1"
umount -d $AUFS_ROOT/pup_ro$FREELOOP
fi
else
message "Failed to mount branch for $1"
losetup -d /dev/loop$FREELOOP
fi
else
message "Failed to assign loop devices loop$FREELOOP for $1"
fi
fi
}
# $1 = sfs-name to unload - we have to figure out which branch this is
function sfs_unload() {
# make sure the sfs we want to unload is loaded
local loopdev=$(losetup-FULL -a | grep "$1" | sed '/loop[0-9]:/ d;s_\(/dev/loop[0-9]*\):.*_\1_')
if [ -z $loopdev ]; then return; fi
local branch=$(grep -m 1 $loopdev /proc/mounts | awk '{print $2}')
if [ "$branch" ]; then
# now ready to unload
busybox mount -t aufs -o remount,del:"$branch" unionfs / &&
umount -d "$branch" &&
message "$1 unloaded successfully." || message "Unable to unload $1"
else
losetup -d $loopdev # try to delete the loop anyway
message "$1 is not listed in aufs branch - cannot unload."
fi
}
############ persistence management #############
# $1 = path to add
function add_to_list() {
{ cat $LISTFILE; echo "$1"; } | sort | uniq > $LISTFILE.tmp
mv $LISTFILE.tmp $LISTFILE
}
# $1 = filename to remove
function remove_from_list() {
if [ ! -f $LISTFILE ]; then return; fi
cat $LISTFILE | fgrep -v "$1" > $LISTFILE.tmp
mv $LISTFILE.tmp $LISTFILE
}
# get all sfs from the list
function get_list() {
if [ ! -f $LISTFILE ]; then return; fi
cat $LISTFILE | sort -r
}
############ GUI related stuff and helpers ############
function list_loaded_sfs() {
losetup-FULL -a | sed '/loop[0-9]:/ d;s_^.*/__;s/)$//'
}
export -f list_loaded_sfs
# don't display already loaded sfs
function list_available_sfs() {
ls $SFS_DIR 2> /dev/null | grep -Fi ".sfs" | grep -Fiv "$BASE_SFS" | awk '
BEGIN {
while ("list_loaded_sfs" | getline) {
loaded[$0]=1
}
}
{
if (loaded[$0] == "") print $0
}
'
}
export -f list_available_sfs
function build_gui() {
export gui='
<window title="System SFS Loader">
<vbox>
<hbox>
<frame Load SFS>
<vbox>
<tree>
<variable>LOADSFS</variable>
<label>Available SFS</label>
<input>list_available_sfs</input>
<height>200</height><width>300</width>
</tree>
<checkbox>
<variable>LOAD_PERMANENTLY</variable>
<label>Load at every boot</label>
<default>'$LOAD_PERMANENTLY'</default>
</checkbox>
<button>
<label>Load</label>
</button>
<hbox>
<entry accept="directory">
<variable>SFS_DIR</variable>
<input>echo $SFS_DIR</input>
</entry>
<button>
<input file stock="gtk-open"></input>
<action type="fileselect">SFS_DIR</action>
</button>
<button>
<label>Refresh</label>
<action type="refresh">LOADSFS</action>
</button>
</hbox>
</vbox>
</frame>
<frame Unload SFS>
<vbox>
<tree>
<variable>UNLOADSFS</variable>
<label>SFS currenty loaded</label>
<input>list_loaded_sfs</input>
<height>200</height><width>300</width>
</tree>
<checkbox>
<variable>UNLOAD_PERMANENTLY</variable>
<label>Do not load again at next boot</label>
<default>'$UNLOAD_PERMANENTLY'</default>
</checkbox>
<button>
<label>Unload</label>
</button>
</vbox>
</frame>
</hbox>
<button>
<label>Done</label>
<action>exit:Done</action>
</button>
</vbox>
</window>
'
}
# gui for load/unload
function interactive() {
while true; do
build_gui
OUTPUT=$(gtkdialog -cp gui)
#echo $OUTPUT
eval "$OUTPUT"
case $EXIT in
Load)
if [ "$LOADSFS" ]; then
sfs_load "$SFS_DIR/$LOADSFS"
if [ "$LOAD_PERMANENTLY" = "true" ]; then
add_to_list "$SFS_DIR/$LOADSFS"
message "$LOADSFS will be loaded at next boot".
fi
else
message "You didn't choose anything to load. Please try again."
fi
;;
Unload)
if [ "$UNLOADSFS" ]; then
sfs_unload "$UNLOADSFS"
if [ "$UNLOAD_PERMANENTLY" = "true" ]; then
remove_from_list "$UNLOADSFS"
message "$UNLOADSFS will be no longer be loaded at next boot".
fi
else
message "You didn't choose anything to unload. Please try again."
fi
;;
Done|abort)
break
;;
esac
done
touch /usr/share/applications/abiword.desktop #make menu refresh
return 0
}
############## main ##############
if [ -z "$1" ]; then
# no parameter passed - use interactive gui
[ $(id -u) -ne 0 -a "$DISPLAY" ] && exec gtksu "System SFS Loader" $0
[ "$DISPLAY" ] && interactive || echo "Try ${0##*/} --help"
else
case "$1" in
start)
#echo start service - loadall
[ $(id -u) -ne 0 -a "$DISPLAY" ] && exec gtksu "System SFS Loader" $0 start
[ $(id -u) -ne 0 -a -z "$DISPLAY" ] && exec su -c "$0 start"
for a in $(get_list); do
sfs_load "$a"
done
;;
stop)
#echo stop service - unloadall
[ $(id -u) -ne 0 -a "$DISPLAY" ] && exec gtksu "System SFS Loader" $0 stop
[ $(id -u) -ne 0 -a -z "$DISPLAY" ] && exec su -c "$0 stop"
for a in $(get_list); do
sfs_unload "${a##*/}"
done
;;
--help|-h|help)
cat << EOF
Usage: $0 [start|stop|help|--help|-h|/path/to/sfsfile]
Without parameters, $0 will show the GUI.
$0 has a config file, located in $LISTFILE.
The config file stores the list of sfs to be automatically loaded or
unloaded by "start" and "stop" parameters below.
"Permanent" option in the GUI will update this config file.
With "start", it will load all the sfs found in the config file.
With "stop", it will unload all the sfs found in the config file.
"start" and "stop" is meant for when $0 is symlink-ed to
/etc/init.d as system service.
Any other parameter will be taken as an sfs filename to load.
EOF
;;
*)
# anything else - assume it's path to sfs to load
[ $(id -u) -ne 0 -a "$DISPLAY" ] && exec gtksu "System SFS Loader" $0 $(readlink -f "$1")
[ $(id -u) -ne 0 -a -z "$DISPLAY" ] && exec su -c "$0 \"$(readlink -f "$1")\""
sfs_load $(readlink -f "$1")
;;
esac
fi