Merge branch 'master' of git://openpandora.org/pandora-libraries
[pandora-libraries.git] / testdata / scripts / pnd_run.sh
1 #!/bin/bash
2  
3 #Usage: pnd_run.sh -p your.pnd -e executeable [-a "(arguments)"] [ -s "cd to folder inside pnd"] [-b UID (name of mountpoint/pandora/appdata)] [-x close x before launching(script needs to be started with nohup for this to work]
4 # -s startdir
5 # arguments can be inside -e, -a is optional
6  
7 #/etc/sudoers needs to be adjusted if you touch any of the sudo lines
8  
9 # look at the comments in the nox part, adjust 
10 #use "lsof /usr/lib/libX11.so.6 | awk '{print $1}'| sort | uniq > whitelist" with nothing running to generate the whitelist
11  
12 #todo - no proper order
13 #validate params better
14 #make uid/pnd_name mandatory (and rename var, its confusing!)
15 #find a clean way of shutting down x without a fixed dm, mabye avoid nohup usage somehow
16 #add options to just mount iso without union and to mount the union later
17 #cleanup
18 #Rewrite! - this sucks
19
20 showHelp() {
21         cat <<endHELP
22 Usage: pnd_run.sh -p your.pnd -e executeable [-a "(arguments)"] [ -s "cd to folder inside pnd"] [-b UID (name of mountpoint/pandora/appdata)] [-x close x before launching(script needs to be started with nohup for this to work]
23 Usage for mounting/umounting pnd_run.sh -p your.pnd -b uid -m or -u
24 endHELP
25 }
26
27 list_using_fs() {
28         for p in $(fuser -m $1 2>/dev/null);do ps hf $p;done
29 }
30 runApp() {
31         cd "/mnt/utmp/$PND_NAME"                # cd to union mount
32         if [ "$STARTDIR" ] && [ -d "$STARTDIR" ]; then
33                 cd "$STARTDIR";                 # cd to folder specified by the optional arg -s
34         fi
35         echo "[------------------------------]{ App start }[---------------------------------]"
36         LD_LIBRARY_PATH="/mnt/utmp/$PND_NAME" "./$EXENAME" $ARGUMENTS 
37                                                 # execute app with ld_lib_path set to the union mount, a bit evil but i think its a good solution
38
39         #the app could have exited now, OR it went into bg, we still need to wait in that case till it really quits!
40         PID=$(pidof -o %PPID -x \"$EXENAME\")   # get pid of app
41         while [ "$PID" ];do                     # wait till we get no pid back for tha app, again a bit ugly, but it works
42                 sleep 10s
43                 PID=`pidof -o %PPID -x \"$EXENAME\"`
44         done
45         echo "[-------------------------------]{ App end }[----------------------------------]"
46 }
47
48 mountPnd() {
49         #create mountpoints, check if they exist already first to avoid annoying error messages
50         if ! [ -d "/mnt/pnd/${PND_NAME}" ]; then 
51                 sudo mkdir -p "/mnt/pnd/${PND_NAME}"            #mountpoint for iso, ro
52         fi 
53         #writeable dir for union
54         if ! [ -d "${MOUNTPOINT}/pandora/appdata/${PND_NAME}" ]; then 
55                 sudo mkdir -p "${MOUNTPOINT}/pandora/appdata/${PND_NAME}"
56                 sudo chmod -R a+xrw "${MOUNTPOINT}/pandora/appdata/${PND_NAME}" 2>/dev/null
57         fi
58         if ! [ -d "/mnt/utmp/${PND_NAME}" ]; then
59                 sudo mkdir -p "/mnt/utmp/${PND_NAME}"           # union over the two
60         fi
61
62         if [ ${cpuspeed:-$(cat /proc/pandora/cpu_mhz_max)} -ne $(cat /proc/pandora/cpu_mhz_max) ]; then 
63                 gksudo --message "$PND_NAME wants to set the cpu speed to $cpuspeed, enter your password to allow" "echo $cpuspeed>/proc/pandora/cpu_mhz_max"
64         fi
65
66         #is the union already mounted? if not mount evrything, else launch the stuff
67         mount | grep "on /mnt/utmp/${PND_NAME} type"
68         if [ $? -ne 0 ];then
69                 echo not mounted on loop yet, doing so
70                 #check if pnd is already attached to loop 
71                 LOOP=$(sudo losetup -a | grep "$PND" | tail -n1 | awk -F: '{print $1}')
72                 #check if the loop device is already mounted
73                 if ! [ -z "$LOOP" ];then
74                         loopmountedon=$( mount | grep "$(mount | grep "$LOOP" | awk '{print $3}')" | grep utmp | awk '{print $3}' )
75                 else
76                         loopmountedon=""
77                 fi
78                 echo "LoopMountedon: $loopmountedon"
79                 if [ ! "$loopmountedon" ]; then #check if the pnd is already attached to some loop device but not used
80                         FREELOOP=$LOOP 
81                         #reuse existing loop
82                         if [ ! "$LOOP" ]; then
83                                 FREELOOP=$(sudo /sbin/losetup -f) #get first free loop device
84                                 echo $FREELOOP
85                                 if [ ! "$FREELOOP" ]; then  # no free loop device, create a new one
86                                             #find a free loop device and use it 
87                                             usedminor=$(sudo /sbin/losetup -a | tail -n1)
88                                             usedminor=${usedminor:9:1}
89                                             echo usedminor $usedminor
90                                             freeminor=$(($usedminor+1))
91                                             echo freeminor $freeminor
92                                             sudo mknod -m777 /dev/loop$freeminor b 7 $freeminor
93                                             FREELOOP=/dev/loop$freeminor
94                                 fi
95                         fi
96                         #detect fs
97
98                         case $PND_FSTYPE in
99                         ISO)
100                                 sudo /sbin/losetup $FREELOOP "$PND" #attach the pnd to the loop device
101                                 mntline="sudo mount ${FREELOOP}" #setup the mountline for later
102                                 #mntline="sudo mount -o loop,mode=777 $PND /mnt/pnd/$PND_NAME"
103                                 echo "Filetype is $PND_FSTYPE";;
104                         directory)
105                                 #we bind the folder, now it can be treated in a unified way 
106                                 #ATENTION: -o ro doesnt work for --bind at least on 25, on 26 its possible using remount, may have changed on 27
107                                 mntline="sudo mount --bind -o ro \"${PND}\" "
108                                 echo "Filetype is $PND_FSTYPE";;
109                         Squashfs)
110                                 sudo /sbin/losetup $FREELOOP "$PND" #attach the pnd to the loop device
111                                 mntline="sudo mount -t squashfs  ${FREELOOP}"
112                                 echo "Filetype is $PND_FSTYPE";;
113                         *)
114                                 echo "error determining fs, output was $PND_FSTYPE"
115                                 exit 1;;
116                         esac
117
118                         echo "$mntline"
119                         $mntline "/mnt/pnd/${PND_NAME}" #mount the pnd/folder
120                         echo "mounting union!"
121                         FILESYSTEM=$(mount | grep "on $MOUNTPOINT " | grep -v rootfs | awk '{print $5}' | tail -n1) #get filesystem appdata is on to determine aufs options
122                         echo "Filesystem is $FILESYSTEM"
123                         if [[ "$FILESYSTEM" = "vfat" ]]; then # use noplink on fat, dont on other fs's 
124                                 #append is fucking dirty, need to clean that up
125                                 sudo mount -t aufs -o exec,noplink,dirs="$MOUNTPOINT/pandora/appdata/$PND_NAME=rw+nolwh":"/mnt/pnd/$PND_NAME=rr$append" none "/mnt/utmp/$PND_NAME"
126                                 # put union on top
127                         else
128                                 sudo mount -t aufs -o exec,dirs="$MOUNTPOINT/pandora/appdata/$PND_NAME=rw+nolwh":"/mnt/pnd/$PND_NAME=rr$append" none "/mnt/utmp/$PND_NAME" 
129                                 # put union on top
130                         fi
131                 else #the pnd is already mounted but a mount was requested with a different basename/uid, just link it there
132                               echo $LOOP already mounted on $loopmountedon skipping losetup - putting link to old mount
133                               #this is bullshit
134                               sudo rmdir "/mnt/utmp/$PND_NAME"
135                               sudo ln -s $loopmountedon "/mnt/utmp/$PND_NAME" 
136                 fi
137         
138         else
139                 echo "Union already mounted"
140         fi
141 }
142
143 unmountPnd() {
144         sudo umount "/mnt/utmp/$PND_NAME" #umount union
145         if [ -z "$(mount |grep utmp/$PND_NAME|cut -f3 -d' ')" ]; then
146                 # check if the umount was successfull, if it wasnt it would mean that theres still something running so we skip this stuff, 
147                 # this WILL lead to clutter if it happens, so we should make damn sure it never happens
148                 # umount the actual pnd
149                 sudo umount "/mnt/pnd/$PND_NAME"
150                 if [ -z "$(mount |grep pnd/$PND_NAME|cut -f3 -d' ')" ]; then
151                         #delete folders created by aufs if empty
152                         sudo rmdir "$MOUNTPOINT/pandora/appdata/$PND_NAME/.wh..wh.plnk" 2>/dev/null
153                         sudo rmdir "$MOUNTPOINT/pandora/appdata/$PND_NAME/.wh..wh..tmp" 2>/dev/null
154                         #delete appdata folder and ancestors if empty
155                         sudo rmdir -p "$MOUNTPOINT/pandora/appdata/$PND_NAME/" 2>/dev/null
156                         #delete tmp mountpoint
157                         if [ -d "/mnt/utmp/$PND_NAME" ];then
158                                 sudo rmdir "/mnt/utmp/$PND_NAME"
159                         else
160                                 sudo rm "/mnt/utmp/$PND_NAME" >/dev/null 2>&1
161                         fi
162                         if [ $PND_FSTYPE = ISO ] || [ $PND_FSTYPE = Squashfs ]; then # check if we where running an iso, clean up loop device if we did
163                                 LOOP=$(sudo losetup -a | grep "$(basename $PND)" | tail -n1 | awk -F: '{print $1}')
164                                 sudo /sbin/losetup -d $LOOP
165                                 sudo rm $LOOP
166                         fi
167                         if [ -d /mnt/pnd/$PND_NAME ];then
168                                 sudo rmdir "/mnt/pnd/$PND_NAME" #delete pnd mountpoint
169                         fi
170
171                         echo cleanup done
172                 else
173                         echo umount failed, didnt clean up. Process still using this FS :
174                         list_using_fs "/mnt/pnd/$PND_NAME"
175                 fi
176         else
177                 echo umount failed, didnt clean up. Process still using this FS :
178                 list_using_fs "/mnt/utmp/$PND_NAME"
179         fi
180 }
181
182 main() {
183         if [ $nox ]; then #the app doesnt want x to run, so we kill it and restart it once the app quits
184                 if [ ! $(pidof X) ]; then 
185                         unset $nox
186                 else
187                         applist=$(lsof /usr/lib/libX11.so.6 | awk '{print $1}'| sort | uniq)
188                         whitelist=$(cat ~/pndtest/whitelist) #adjust this to a fixed whitelist, maybe in the config dir
189                         filteredlist=$(echo -e "$applist\n\n$whitelist\n\n$whitelist" | sort | uniq -u) #whitelist appended two times so those items are always removed
190                         if [ ${#filteredlist} -ge 1 ]; then
191                                 message=$(echo -e "The following applications are still running, are you sure you want to close x? \n$filteredlist")
192                                 echo -e "?ae[34me[30m?"
193                                 xmessage -center "$message", -buttons yes,no
194                                 if [ $? = 102 ]; then
195                                         exit 1
196                                 fi
197                                 sudo /etc/init.d/slim-init stop
198                                 sleep 5s
199                         else
200                                 echo -e "?ae[34me[30m?"
201                                 xmessage -center "killing x, nothing of value will be lost", -buttons ok,cancel
202                                 if [ $? = 102 ]; then
203                                         exit 1
204                                 fi
205                                 # close x now, do we want to use slim stop or just kill x?
206                                 sudo /etc/init.d/slim-init stop
207                                 sleep 5s
208                         fi
209                 fi
210         fi
211
212         case $ACTION in
213         mount)  mountPnd;;
214         umount) unmountPnd;;
215         run)
216                 mountPnd
217                 oPWD=$(pwd)
218                 runApp
219                 cd $oPWD
220                 unmountPnd;;
221         esac
222
223
224         if [ $nox ]; then #restart x if it was killed
225                 echo "starting x in 5s"
226                 sleep 5
227                 sudo /etc/init.d/slim-init start
228         fi
229 }
230
231 ######################################################################################
232 ####    Parse arguments
233 ##
234
235 TEMP=`getopt -o p:e:a:b:s:m::u::n::x::j:c: -- "$@"`
236  
237 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
238  
239 # Note the quotes around `$TEMP': they are essential!
240 eval set -- "$TEMP"
241  
242 ACTION=run
243 while true ; do
244         case "$1" in
245                 -p) PND=$2;shift 2;;
246                 -e) EXENAME=$2;shift 2 ;;
247                 -b) PND_NAME=$2;shift 2;;
248                 -s) STARTDIR=$2;shift 2;;
249                 -m) ACTION=mount;shift 2;;
250                 -u) ACTION=umount;shift 2;;
251                 -x) nox=1;shift 2;;
252                 -j) append=$2;shift 2;;
253                 -c) cpuspeed=$2;shift 2;;
254                 -a) 
255                         case "$2" in
256                                 "") echo "no arguments"; shift 2 ;;
257                                 *)  echo "args set to \`$2'" ;ARGUMENTS=$2;shift 2 ;;
258                         esac ;;
259                 --) shift ; break ;;
260                 *) echo "Error while parsing arguments!" ; exit 1 ;;
261         esac
262 done
263 if [ ! -e "$PND" ]; then #check if theres a pnd suplied, need to clean that up a bit more
264         echo "ERROR: selected PND file does not exist!"
265         showHelp
266         exit 1
267 fi
268 if [ ! "$EXENAME" ] && [[ "$ACTION" = "run" ]]; then
269         echo "ERROR: no executable name provided!"
270         showHelp
271         exit 1
272 fi
273
274
275 PND_FSTYPE=$(file -b "$PND" | awk '{ print $1 }')       # is -p a zip/iso or folder?
276 MOUNTPOINT=$(df "$PND" | tail -1|cut -f 1 -d ' ')       # find out on which mountpoint the pnd is
277 if [ ! -d "$MOUNTPOINT" ] || [ $MOUNTPOINT = "/" ]; then 
278         MOUNTPOINT="";
279 fi
280  
281 #PND_NAME really should be something sensible and somewhat unique
282 #if -b is set use that as pnd_name, else generate it from PND
283 #get basename (strip extension if file) for union mountpoints etc, maybe  this should be changed to something specified inside the xml
284 #this should probably be changed to .... something more sensible
285 #currently only everything up to the first '.' inside the filenames is used.
286 PND_NAME=${PND_NAME:-"$(basename $PND | cut -d'.' -f1)"}
287
288 if [ $nox ]; then
289         main > "/tmp/pndrun${PND_NAME}_$ACTION.out" 2>&1 & 
290         disown
291 else
292         main > "/tmp/pndrun${PND_NAME}_$ACTION.out" 2>&1
293 fi
294