pnd_run.sh: Added fixes and cleanups from sebt3
[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
31 runApp() {
32         unset CURRENTSPEED
33         if ! [ -f "${MOUNTPOINT}/pandora/appdata/${PND_NAME}/cpuspeed" ]; then
34                 if [ ${cpuspeed:-$(cat /proc/pandora/cpu_mhz_max)} -gt $(cat /proc/pandora/cpu_mhz_max) ]; then 
35                    cpuselection=$(zenity --title="set cpu speed" --height=350 --list --column "id" --column "Please select" --hide-column=1 --text="$PND_NAME suggests to set the cpu speed to $cpuspeed MHz to make it run properly.\n\n Do you want to change the cpu speed? (current speed: $(cat /proc/pandora/cpu_mhz_max) MHz)\n\nWarning: Setting the clock speed above 600MHz can be unstable and it NOT recommended!" "yes" "Yes, set it to $cpuspeed MHz" "custom" "Yes, select custom value" "yessave" "Yes, set it to $cpuspeed MHz and don't ask again" "customsave" "Yes, set it to custom speed and don't ask again" "no" "No, don't change the speed" "nosave" "No, don't chage the speed and don't ask again")
36                   if [ ${cpuselection} = "yes" ]; then  
37                         CURRENTSPEED=$(cat /proc/pandora/cpu_mhz_max)
38                         sudo /usr/pandora/scripts/op_cpuspeed.sh $cpuspeed
39                   elif [ ${cpuselection} = "custom" ]; then     
40                         CURRENTSPEED=$(cat /proc/pandora/cpu_mhz_max)
41                         sudo /usr/pandora/scripts/op_cpuspeed.sh
42                   elif [ ${cpuselection} = "customsave" ]; then 
43                         CURRENTSPEED=$(cat /proc/pandora/cpu_mhz_max)
44                         sudo /usr/pandora/scripts/op_cpuspeed.sh
45                         zenity --info --title="Note" --text="Speed saved.\n\nTo re-enable this dialogue, please delete the file\n${MOUNTPOINT}/pandora/appdata/${PND_NAME}/cpuspeed"
46                         cat /proc/pandora/cpu_mhz_max > ${MOUNTPOINT}/pandora/appdata/${PND_NAME}/cpuspeed
47                  elif [ ${cpuselection} = "yessave" ]; then     
48                         CURRENTSPEED=$(cat /proc/pandora/cpu_mhz_max)
49                         cat /proc/pandora/cpu_mhz_max > /tmp/cpuspeed           
50                         zenity --info --title="Note" --text="Speed saved.\n\nTo re-enable this dialogue, please delete the file\n${MOUNTPOINT}/pandora/appdata/${PND_NAME}/cpuspeed"
51                         sudo /usr/pandora/scripts/op_cpuspeed.sh $cpuspeed
52                         cat /proc/pandora/cpu_mhz_max > ${MOUNTPOINT}/pandora/appdata/${PND_NAME}/cpuspeed
53                  elif [ ${cpuselection} = "nosave" ]; then                      
54                         zenity --info --title="Note" --text="Speed will not be changed.\n\nTo re-enable this dialogue, please delete the file\n${MOUNTPOINT}/pandora/appdata/${PND_NAME}/cpuspeed"
55                         echo 9999 > ${MOUNTPOINT}/pandora/appdata/${PND_NAME}/cpuspeed
56                 fi
57                fi
58         else
59                 cpuspeed=$(cat "${MOUNTPOINT}/pandora/appdata/${PND_NAME}/cpuspeed")
60                 if [ "$cpuspeed" -lt "1500" ]; then
61                   CURRENTSPEED=$(cat /proc/pandora/cpu_mhz_max)
62                   echo Setting to CPU-Speed $cpuspeed MHz
63                   sudo /usr/pandora/scripts/op_cpuspeed.sh $cpuspeed
64                 fi
65         fi
66
67         cd "/mnt/utmp/$PND_NAME"                # cd to union mount
68         if [ "$STARTDIR" ] && [ -d "$STARTDIR" ]; then
69                 cd "$STARTDIR";                 # cd to folder specified by the optional arg -s
70         fi
71         echo "[------------------------------]{ App start }[---------------------------------]"
72         LD_LIBRARY_PATH="/mnt/utmp/$PND_NAME" "./$EXENAME" $ARGUMENTS 
73                                                 # execute app with ld_lib_path set to the union mount, a bit evil but i think its a good solution
74
75         #the app could have exited now, OR it went into bg, we still need to wait in that case till it really quits!
76         PID=$(pidof -o %PPID -x \"$EXENAME\")   # get pid of app
77         while [ "$PID" ];do                     # wait till we get no pid back for tha app, again a bit ugly, but it works
78                 sleep 10s
79                 PID=`pidof -o %PPID -x \"$EXENAME\"`
80         done
81         echo "[-------------------------------]{ App end }[----------------------------------]"
82
83         if [ ! -z "$CURRENTSPEED" ]; then
84                 sudo /usr/pandora/scripts/op_cpuspeed.sh $CURRENTSPEED
85         fi
86 }
87
88 mountPnd() {
89         #create mountpoints, check if they exist already first to avoid annoying error messages
90         if ! [ -d "/mnt/pnd/${PND_NAME}" ]; then 
91                 sudo mkdir -p "/mnt/pnd/${PND_NAME}"            #mountpoint for iso, ro
92         fi 
93         #writeable dir for union
94         if ! [ -d "${APPDATADIR}" ]; then 
95                 sudo mkdir -p "${APPDATADIR}"
96                 sudo chmod -R a+xrw "${APPDATADIR}" 2>/dev/null
97         fi
98         if ! [ -d "/mnt/utmp/${PND_NAME}" ]; then
99                 sudo mkdir -p "/mnt/utmp/${PND_NAME}"           # union over the two
100         fi
101         #is the union already mounted? if not mount evrything, else launch the stuff
102         mount | grep "on /mnt/utmp/${PND_NAME} type"
103         if [ $? -ne 0 ];then
104                 echo not mounted on loop yet, doing so
105                 #check if pnd is already attached to loop 
106                 LOOP=$(sudo losetup -a | grep "$PND" | tail -n1 | awk -F: '{print $1}')
107                 #check if the loop device is already mounted
108                 if ! [ -z "$LOOP" ];then
109                         loopmountedon=$( mount | grep "$(mount | grep "$LOOP" | awk '{print $3}')" | grep utmp | awk '{print $3}' )
110                 else
111                         loopmountedon=""
112                 fi
113                 echo "LoopMountedon: $loopmountedon"
114                 if [ ! "$loopmountedon" ]; then #check if the pnd is already attached to some loop device but not used
115                         FREELOOP=$LOOP 
116                         #reuse existing loop
117                         if [ ! "$LOOP" ]; then
118                                 FREELOOP=$(sudo /sbin/losetup -f) #get first free loop device
119                                 echo $FREELOOP
120                                 if [ ! "$FREELOOP" ]; then  # no free loop device, create a new one
121                                             #find a free loop device and use it 
122                                             usedminor=$(sudo /sbin/losetup -a | tail -n1)
123                                             usedminor=${usedminor:9:1}
124                                             echo usedminor $usedminor
125                                             freeminor=$(($usedminor+1))
126                                             echo freeminor $freeminor
127                                             sudo mknod -m777 /dev/loop$freeminor b 7 $freeminor
128                                             FREELOOP=/dev/loop$freeminor
129                                 fi
130                         fi
131                         #detect fs
132
133                         case $PND_FSTYPE in
134                         ISO)
135                                 sudo /sbin/losetup $FREELOOP "$PND" #attach the pnd to the loop device
136                                 mntline="sudo mount" #setup the mountline for later
137                                 mntdev="${FREELOOP}"
138                                 #mntline="sudo mount -o loop,mode=777 $PND /mnt/pnd/$PND_NAME"
139                                 echo "Filetype is $PND_FSTYPE";;
140                         directory)
141                                 #we bind the folder, now it can be treated in a unified way 
142                                 #ATENTION: -o ro doesnt work for --bind at least on 25, on 26 its possible using remount, may have changed on 27
143                                 mntline="sudo mount --bind -o ro"
144                                 mntdev="${PND}"
145                                 echo "Filetype is $PND_FSTYPE";;
146                         Squashfs)
147                                 sudo /sbin/losetup $FREELOOP "$PND" #attach the pnd to the loop device
148                                 mntline="sudo mount -t squashfs"
149                                 mntdev="${FREELOOP}"
150                                 echo "Filetype is $PND_FSTYPE";;
151                         *)
152                                 echo "error determining fs, output was $PND_FSTYPE"
153                                 exit 1;;
154                         esac
155
156                         echo "Mounting union ($mntline) :"
157                         $mntline "$mntdev" "/mnt/pnd/${PND_NAME}" #mount the pnd/folder
158                         echo done
159                         FILESYSTEM=$(mount | grep "on $MOUNTPOINT " | grep -v rootfs | awk '{print $5}' | tail -n1) #get filesystem appdata is on to determine aufs options
160                         echo "Filesystem is $FILESYSTEM"
161                         echo "Mounting the Union FS using ${APPDATADIR} as Write directory:"
162                         if [[ "$FILESYSTEM" = "vfat" ]]; then # use noplink on fat, dont on other fs's 
163                                 #append is fucking dirty, need to clean that up
164                                 sudo mount -t aufs -o exec,noplink,dirs="${APPDATADIR}=rw+nolwh":"/mnt/pnd/$PND_NAME=rr$append" none "/mnt/utmp/$PND_NAME"
165                                 # put union on top
166                         else
167                                 sudo mount -t aufs -o exec,dirs="${APPDATADIR}=rw+nolwh":"/mnt/pnd/$PND_NAME=rr$append" none "/mnt/utmp/$PND_NAME" 
168                                 # put union on top
169                         fi
170                         echo done
171                 else #the pnd is already mounted but a mount was requested with a different basename/uid, just link it there
172                               echo $LOOP already mounted on $loopmountedon skipping losetup - putting link to old mount
173                               #this is bullshit
174                               sudo rmdir "/mnt/utmp/$PND_NAME"
175                               sudo ln -s $loopmountedon "/mnt/utmp/$PND_NAME" 
176                 fi
177         
178         else
179                 echo "Union already mounted"
180         fi
181 }
182
183 unmountPnd() {
184         if mount | grep -q "on /mnt/utmp/${PND_NAME} type";then
185                 sudo umount "/mnt/utmp/$PND_NAME" #umount union
186                 if [ -z "$(mount |grep utmp/$PND_NAME|cut -f3 -d' ')" ]; then
187                         # check if the umount was successfull, if it wasnt it would mean that theres still something running so we skip this stuff, 
188                         # this WILL lead to clutter if it happens, so we should make damn sure it never happens
189                         # umount the actual pnd
190                         sudo umount "/mnt/pnd/$PND_NAME"
191                         if [ -z "$(mount |grep pnd/$PND_NAME|cut -f3 -d' ')" ]; then
192                                 #delete folders created by aufs if empty
193                                 sudo rmdir "${APPDATADIR}/.wh..wh.plnk" 2>/dev/null
194                                 sudo rmdir "${APPDATADIR}/.wh..wh..tmp" 2>/dev/null
195                                 #delete appdata folder and ancestors if empty
196                                 sudo rmdir -p "${APPDATADIR}" 2>/dev/null
197                                 #delete tmp mountpoint
198                                 if [ -d "/mnt/utmp/$PND_NAME" ];then
199                                         sudo rmdir "/mnt/utmp/$PND_NAME"
200                                 else
201                                         sudo rm "/mnt/utmp/$PND_NAME" >/dev/null 2>&1
202                                 fi
203                                 if [ $PND_FSTYPE = ISO ] || [ $PND_FSTYPE = Squashfs ]; then # check if we where running an iso, clean up loop device if we did
204                                         LOOP=$(sudo losetup -a | grep "$(basename $PND)" | tail -n1 | awk -F: '{print $1}')
205                                         sudo /sbin/losetup -d $LOOP
206                                         sudo rm $LOOP
207                                 fi
208                                 if [ -d /mnt/pnd/$PND_NAME ];then
209                                         sudo rmdir "/mnt/pnd/$PND_NAME" #delete pnd mountpoint
210                                 fi
211
212                                 echo cleanup done
213                         else
214                                 echo umount failed, didnt clean up. Process still using this FS :
215                                 list_using_fs "/mnt/pnd/$PND_NAME"
216                         fi
217                 else
218                         echo umount failed, didnt clean up. Process still using this FS :
219                         list_using_fs "/mnt/utmp/$PND_NAME"
220                 fi
221         fi
222 }
223
224 main() {
225         if [ $nox ]; then #the app doesnt want x to run, so we kill it and restart it once the app quits
226                 if [ ! $(pidof X) ]; then 
227                         unset $nox
228                 else
229                         applist=$(lsof /usr/lib/libX11.so.6 | awk '{print $1}'| sort | uniq)
230                         whitelist=$(cat ~/pndtest/whitelist) #adjust this to a fixed whitelist, maybe in the config dir
231                         filteredlist=$(echo -e "$applist\n\n$whitelist\n\n$whitelist" | sort | uniq -u) #whitelist appended two times so those items are always removed
232                         if [ ${#filteredlist} -ge 1 ]; then
233                                 message=$(echo -e "The following applications are still running, are you sure you want to close x? \n$filteredlist")
234                                 echo -e "?ae[34me[30m?"
235                                 xmessage -center "$message", -buttons yes,no
236                                 if [ $? = 102 ]; then
237                                         exit 1
238                                 fi
239                                 sudo /etc/init.d/slim-init stop
240                                 sleep 5s
241                         else
242                                 echo -e "?ae[34me[30m?"
243                                 xmessage -center "killing x, nothing of value will be lost", -buttons ok,cancel
244                                 if [ $? = 102 ]; then
245                                         exit 1
246                                 fi
247                                 # close x now, do we want to use slim stop or just kill x?
248                                 sudo /etc/init.d/slim-init stop
249                                 sleep 5s
250                         fi
251                 fi
252         fi
253
254         case $ACTION in
255         mount)  mountPnd;;
256         umount) unmountPnd;;
257         run)
258                 mountPnd
259                 oPWD=$(pwd)
260                 runApp
261                 cd $oPWD
262                 unmountPnd;;
263         esac
264
265
266         if [ $nox ]; then #restart x if it was killed
267                 echo "starting x in 5s"
268                 sleep 5
269                 sudo /etc/init.d/slim-init start
270         fi
271 }
272
273 ######################################################################################
274 ####    Parse arguments
275 ##
276
277 TEMP=`getopt -o d:p:e:a:b:s:m::u::n::x::j:c: -- "$@"`
278  
279 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
280  
281 # Note the quotes around `$TEMP': they are essential!
282 eval set -- "$TEMP"
283  
284 ACTION=run
285 while true ; do
286         case "$1" in
287                 -p) PND=$2;shift 2;;
288                 -e) EXENAME=$2;shift 2 ;;
289                 -b) PND_NAME=$2;shift 2;;
290                 -s) STARTDIR=$2;shift 2;;
291                 -m) ACTION=mount;shift 2;;
292                 -u) ACTION=umount;shift 2;;
293                 -x) nox=1;shift 2;;
294                 -j) append=$2;shift 2;;
295                 -c) cpuspeed=$2;shift 2;;
296                 -d) APPDATASET=1;APPDATADIR=$2;shift 2;;
297                 -a) 
298                         case "$2" in
299                                 "") echo "no arguments"; shift 2 ;;
300                                 *)  echo "args set to \`$2'" ;ARGUMENTS=$2;shift 2 ;;
301                         esac ;;
302                 --) shift ; break ;;
303                 *) echo "Error while parsing arguments!" ; exit 1 ;;
304         esac
305 done
306 if [ ! -e "$PND" ]; then #check if theres a pnd suplied, need to clean that up a bit more
307         echo "ERROR: selected PND file does not exist!"
308         showHelp
309         exit 1
310 fi
311 if [ ! "$EXENAME" ] && [[ "$ACTION" = "run" ]]; then
312         echo "ERROR: no executable name provided!"
313         showHelp
314         exit 1
315 fi
316 [ ! -z $APPDATASET ] && APPDATADIR=${APPDATADIR:-$(dirname $PND)/$PND_NAME}
317 APPDATADIR=${APPDATADIR:-${MOUNTPOINT}/pandora/appdata/${PND_NAME}}
318
319
320 PND_FSTYPE=$(file -b "$PND" | awk '{ print $1 }')       # is -p a zip/iso or folder?
321 MOUNTPOINT=$(df "$PND" | tail -1|awk '{print $6}')      # find out on which mountpoint the pnd is
322 if [ ! -d "$MOUNTPOINT" ] || [ $MOUNTPOINT = "/" ]; then 
323         MOUNTPOINT="";
324 fi
325  
326 #PND_NAME really should be something sensible and somewhat unique
327 #if -b is set use that as pnd_name, else generate it from PND
328 #get basename (strip extension if file) for union mountpoints etc, maybe  this should be changed to something specified inside the xml
329 #this should probably be changed to .... something more sensible
330 #currently only everything up to the first '.' inside the filenames is used.
331 PND_NAME=${PND_NAME:-"$(basename $PND | cut -d'.' -f1)"}
332
333 if [ $nox ]; then
334         main > "/tmp/pndrun${PND_NAME}_$ACTION.out" 2>&1 & 
335         disown
336 else
337         main > "/tmp/pndrun${PND_NAME}_$ACTION.out" 2>&1
338 fi
339
340