Fatdog Arm

Artifact Content
Login

Artifact 80c9e12fc3625ddf7f370c50a7c86053be67ee3b:


     1  #!/bin/bash
     2  # James Budiono 2011-2012, 2013
     3  # Licens: GNU GPL Version 3 or later
     4  # Load / unload SFS on the fly - this is also the system SFS loader for Fatdog64
     5  #
     6  # note: uses bash - we don't need speed here, we need features (uses array etc)
     7  # can probably be converted to ash but I can't be bothered
     8  # version 2 - supports start/stop as a service (to be run from /etc/init.d)
     9  #             When run in this way, supports persistence
    10  # version 3 - proper recovery if we fail to load for whatever reason
    11  # version 4 - canonicalise path if a parameter is passed in.
    12  # version 5 - adapted to be the system SFS loader for Fatdog64, now lives in /sbin
    13  # version 6 - more message, don't show base sfs
    14  
    15  # constants and start-up variables
    16  MAXLOOP=250					# highest loop device number we can use
    17  RESERVED=10					# reserve 10 loop devices for filemnt and others
    18  SFS_DIR=/mnt/home			# where to look for sfs
    19  BASE_SFS=fd64-620.sfs		# don't show base sfs
    20  UNLOAD_PERMANENTLY=false
    21  LOAD_PERMANENTLY=false
    22  LISTFILE=/etc/load_sfs
    23  export SFS_DIR BASE_SFS
    24  
    25  # boot-time configuration
    26  #BOOTSTATE_PATH=/etc/BOOTSTATE
    27  . $BOOTSTATE_PATH
    28  [ "$BASE_SFS_PATH" ] && BASE_SFS=${BASE_SFS_PATH##*/}
    29  
    30  
    31  # insertion point - below tmpfs, pup_save and pup_multi
    32  INSERT_POINT=1	# tmpfs / pup_save
    33  [ "$TMPFS_MOUNT" -a "$SAVEFILE_MOUNT" ] && INSERT_POINT=2   # both tmpfs & pup_save
    34  [ "$MULTI_MOUNT" ] && INSERT_POINT=$(( $INSERT_POINT + 1 )) # pup_multi is another layer
    35  
    36  ########## core load/unload functions ###########
    37  
    38  # $@ text to display
    39  function message() {
    40  	if [ "$DISPLAY" ]; then
    41  		Xdialog --infobox "$@" 0 0 10000
    42  	else
    43  		echo "$@"
    44  	fi
    45  }
    46  
    47  # output - FREELOOP = free loop device
    48  function find_free_loop() {
    49  	local loops_in_use
    50  	for i in $(losetup-FULL -a | sed 's/:.*$//;s_/dev/loop__'); do
    51  		loops_in_use[$i]=$i
    52  	done
    53  	#echo ${loops_in_use[@]}
    54  
    55  	for ((i=$RESERVED; i<$MAXLOOP; i++)); do
    56  		if [ -z "${loops_in_use[$i]}" ]; then
    57  			break
    58  		fi
    59  	done
    60  	#echo loop device $i is free	
    61  	FREELOOP=$i
    62  }
    63  
    64  # $1 = loop device number
    65  function check_and_make_loop_device() {
    66  	if [ ! -b /dev/loop$1 ]; then
    67  		mknod /dev/loop$1 b 7 $1
    68  #	else
    69  #		echo loop device $1 already exist
    70  	fi
    71  }
    72  
    73  # $1 = pup_ro number
    74  function check_and_make_pupro() {
    75  	if [ ! -d $AUFS_ROOT/pup_ro$1 ]; then
    76  		mkdir -p $AUFS_ROOT/pup_ro$1
    77  #	else
    78  #		echo pup_ro$1 already exist
    79  	fi	
    80  }
    81  
    82  # $1 = path to SFS to load
    83  function sfs_load() {
    84  	# make sure we're not loading the same sfs twice
    85  	if [ -z "$(losetup-FULL -a | fgrep "${1##*/}")" ]; then
    86  		# find free loop device, re-using what we can, if we can't, then make new loop/pup_ro mountpoint
    87  		# keep loop-N and pup_ro-N sync at all times
    88  		find_free_loop
    89  		check_and_make_loop_device $FREELOOP
    90  		check_and_make_pupro $FREELOOP
    91  		
    92  		# now ready to load
    93  		if losetup /dev/loop$FREELOOP "$1"; then
    94  			if mount -o ro /dev/loop$FREELOOP $AUFS_ROOT/pup_ro$FREELOOP; then
    95  				if busybox mount -t aufs -o remount,ins:$INSERT_POINT:$AUFS_ROOT/pup_ro$FREELOOP=rr aufs /; then
    96  					message "$1 loaded successfully."
    97  				else
    98  					message "Failed to remount aufs $1" 
    99  					umount -d $AUFS_ROOT/pup_ro$FREELOOP
   100  				fi
   101  			else
   102  				message "Failed to mount branch for $1" 
   103  				losetup -d /dev/loop$FREELOOP
   104  			fi
   105  		else
   106  			message "Failed to assign loop devices loop$FREELOOP for $1" 
   107  		fi
   108  	fi	
   109  }
   110  
   111  # $1 = sfs-name to unload - we have to figure out which branch this is
   112  function sfs_unload() {
   113  	# make sure the sfs we want to unload is loaded
   114  	local loopdev=$(losetup-FULL -a | grep "$1" | sed '/loop[0-9]:/ d;s_\(/dev/loop[0-9]*\):.*_\1_')
   115  	if [ -z $loopdev ]; then return; fi
   116  	local branch=$(grep -m 1 $loopdev /proc/mounts | awk '{print $2}')
   117  	
   118  	if [ "$branch" ]; then
   119  		# now ready to unload
   120  		busybox mount -t aufs -o remount,del:"$branch" unionfs / && 
   121  		umount -d "$branch" &&
   122  		message "$1 unloaded successfully." || message "Unable to unload $1"
   123  	else
   124  		losetup -d $loopdev # try to delete the loop anyway	
   125  		message "$1 is not listed in aufs branch - cannot unload." 
   126  	fi
   127  }
   128  
   129  ############ persistence management  #############
   130  # $1 = path to add
   131  function add_to_list() {
   132  	{ cat $LISTFILE; echo "$1"; } | sort | uniq > $LISTFILE.tmp
   133  	mv $LISTFILE.tmp $LISTFILE
   134  }
   135  
   136  # $1 = filename to remove
   137  function remove_from_list() {
   138  	if [ ! -f $LISTFILE ]; then return; fi
   139  	cat $LISTFILE | fgrep -v "$1" > $LISTFILE.tmp
   140  	mv $LISTFILE.tmp $LISTFILE
   141  }
   142  
   143  # get all sfs from the list
   144  function get_list() {
   145  	if [ ! -f $LISTFILE ]; then return; fi
   146  	cat $LISTFILE | sort -r
   147  }
   148  
   149  ############ GUI related stuff and helpers ############
   150  
   151  function list_loaded_sfs() {
   152  	losetup-FULL -a | sed '/loop[0-9]:/ d;s_^.*/__;s/)$//'
   153  }
   154  export -f list_loaded_sfs
   155  
   156  # don't display already loaded sfs
   157  function list_available_sfs() {
   158  	ls $SFS_DIR 2> /dev/null | grep -Fi ".sfs" | grep -Fiv "$BASE_SFS" |  awk '
   159  BEGIN {
   160  	while ("list_loaded_sfs" | getline) {
   161  		loaded[$0]=1
   162  	}
   163  }
   164  {
   165  	if (loaded[$0] == "") print $0
   166  }
   167  '
   168  }
   169  export -f list_available_sfs
   170  
   171  function build_gui() {
   172  export gui='
   173  <window title="System SFS Loader">
   174  	<vbox>
   175  		<hbox>
   176  			<frame Load SFS>
   177  				<vbox>
   178  					<tree>
   179  						<variable>LOADSFS</variable>
   180  						<label>Available SFS</label>
   181  						<input>list_available_sfs</input>
   182  						<height>200</height><width>300</width>
   183  					</tree>
   184  					<checkbox>
   185  						<variable>LOAD_PERMANENTLY</variable>
   186  						<label>Load at every boot</label>
   187  						<default>'$LOAD_PERMANENTLY'</default>
   188  					</checkbox>					
   189  					<button>
   190  						<label>Load</label>
   191  					</button>
   192  					<hbox>
   193  						<entry accept="directory">
   194  							<variable>SFS_DIR</variable>
   195  							<input>echo $SFS_DIR</input>
   196  						</entry>
   197  						<button>
   198  							<input file stock="gtk-open"></input>
   199  							<action type="fileselect">SFS_DIR</action>
   200  						</button>
   201  						<button>
   202  							<label>Refresh</label>
   203  							<action type="refresh">LOADSFS</action>
   204  						</button>					
   205  					</hbox>					
   206  				</vbox>
   207  			</frame>		
   208  			<frame Unload SFS>
   209  				<vbox>
   210  					<tree>
   211  						<variable>UNLOADSFS</variable>
   212  						<label>SFS currenty loaded</label>
   213  						<input>list_loaded_sfs</input>
   214  						<height>200</height><width>300</width>
   215  					</tree>
   216  					<checkbox>
   217  						<variable>UNLOAD_PERMANENTLY</variable>
   218  						<label>Do not load again at next boot</label>
   219  						<default>'$UNLOAD_PERMANENTLY'</default>
   220  					</checkbox>
   221  					<button>
   222  						<label>Unload</label>
   223  					</button>
   224  				</vbox>
   225  			</frame>
   226  		</hbox>
   227  		<button>
   228  			<label>Done</label>
   229  			<action>exit:Done</action>
   230  		</button>
   231  	</vbox>
   232  </window>
   233  '
   234  }
   235  
   236  # gui for load/unload
   237  function interactive() {
   238  	while true; do
   239  		build_gui
   240  		OUTPUT=$(gtkdialog -cp gui)
   241  		#echo $OUTPUT
   242  		eval "$OUTPUT"
   243  		case $EXIT in
   244  			Load) 
   245  				if [ "$LOADSFS" ]; then
   246  					sfs_load "$SFS_DIR/$LOADSFS"
   247  					if [ "$LOAD_PERMANENTLY" = "true" ]; then
   248  						add_to_list "$SFS_DIR/$LOADSFS"
   249  						message "$LOADSFS will be loaded at next boot".
   250  					fi
   251  				else
   252  					message "You didn't choose anything to load. Please try again." 
   253  				fi
   254  				;;
   255  				
   256  			Unload) 
   257  				if [ "$UNLOADSFS" ]; then
   258  					sfs_unload "$UNLOADSFS"
   259  					if [ "$UNLOAD_PERMANENTLY" = "true" ]; then
   260  						remove_from_list "$UNLOADSFS"
   261  						message "$UNLOADSFS will be no longer be loaded at next boot".
   262  					fi					
   263  				else
   264  					message "You didn't choose anything to unload. Please try again." 
   265  				fi
   266  				;;
   267  			Done|abort) 
   268  				break 
   269  				;;
   270  		esac
   271  	done
   272  	touch /usr/share/applications/abiword.desktop  #make menu refresh
   273  	return 0
   274  }
   275  
   276  ############## main ##############
   277  if [ -z "$1" ]; then
   278  	# no parameter passed - use interactive gui
   279  	[ $(id -u) -ne 0 -a "$DISPLAY" ] && exec gtksu "System SFS Loader" $0
   280  	[ "$DISPLAY" ] && interactive || echo "Try ${0##*/} --help"
   281  else
   282  	case "$1" in
   283  		start)
   284  			#echo start service - loadall
   285  			[ $(id -u) -ne 0 -a "$DISPLAY" ] && exec gtksu "System SFS Loader" $0 start
   286  			[ $(id -u) -ne 0 -a -z "$DISPLAY" ] && exec su -c "$0 start"
   287  			for a in $(get_list); do
   288  				sfs_load "$a"
   289  			done
   290  			;;
   291  		stop)
   292  			#echo stop service - unloadall
   293  			[ $(id -u) -ne 0 -a "$DISPLAY" ] && exec gtksu "System SFS Loader" $0 stop
   294  			[ $(id -u) -ne 0 -a -z "$DISPLAY" ] && exec su -c "$0 stop"
   295  			for a in $(get_list); do
   296  				sfs_unload "${a##*/}"
   297  			done
   298  			;;
   299  		--help|-h|help)
   300  			cat << EOF
   301  Usage: $0 [start|stop|help|--help|-h|/path/to/sfsfile]
   302  
   303  Without parameters, $0 will show the GUI.
   304  
   305  $0 has a config file, located in $LISTFILE.
   306  The config file stores the list of sfs to be automatically loaded or
   307  unloaded by "start" and "stop" parameters below.
   308  "Permanent" option in the GUI will update this config file.
   309  
   310  With "start", it will load all the sfs found in the config file.
   311  With "stop", it will unload all the sfs found in the config file.
   312  "start" and "stop" is meant for when $0 is symlink-ed to 
   313  /etc/init.d as system service.
   314  Any other parameter will be taken as an sfs filename to load.
   315  EOF
   316  			;;
   317  		*)
   318  			# anything else - assume it's path to sfs to load 
   319  			[ $(id -u) -ne 0 -a "$DISPLAY" ] && exec gtksu "System SFS Loader" $0 $(readlink -f "$1")
   320  			[ $(id -u) -ne 0 -a -z "$DISPLAY" ] && exec su -c "$0 \"$(readlink -f "$1")\""	
   321  			sfs_load $(readlink -f "$1")
   322  			;;
   323  	esac
   324  fi