* Script now popups a message if mount fails.
[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         if [ -d /mnt/utmp/$PND_NAME/lib ];then
73                 export LD_LIBRARY_PATH="/mnt/utmp/$PND_NAME/lib:${LD_LIBRARY_PATH:-"/usr/lib:/lib"}"
74         else
75                 export LD_LIBRARY_PATH="/mnt/utmp/$PND_NAME:${LD_LIBRARY_PATH:-"/usr/lib:/lib"}"
76         fi
77         if [ -d /mnt/utmp/$PND_NAME/bin ];then
78                 export PATH="/mnt/utmp/$PND_NAME/bin:${PATH:-"/usr/bin:/bin:/usr/local/bin"}"
79         fi
80         if [ -d /mnt/utmp/$PND_NAME/share ];then
81                 export XDG_DATA_DIRS="/mnt/utmp/$PND_NAME/share:$XDG_DATA_DIRS:/usr/share"
82         fi
83         export XDG_CONFIG_HOME="/mnt/utmp/$PND_NAME"
84         "./$EXENAME" $ARGUMENTS 
85                                                 # execute app with ld_lib_path set to the union mount, a bit evil but i think its a good solution
86
87         #the app could have exited now, OR it went into bg, we still need to wait in that case till it really quits!
88         PID=$(pidof -o %PPID -x \"$EXENAME\")   # get pid of app
89         while [ "$PID" ];do                     # wait till we get no pid back for tha app, again a bit ugly, but it works
90                 sleep 10s
91                 PID=`pidof -o %PPID -x \"$EXENAME\"`
92         done
93         echo "[-------------------------------]{ App end }[----------------------------------]"
94
95         if [ ! -z "$CURRENTSPEED" ]; then
96                 sudo /usr/pandora/scripts/op_cpuspeed.sh $CURRENTSPEED
97         fi
98 }
99
100 mountPnd() {
101         if [ $(id -u) -ne 0 ];then
102                 echo "sudo /usr/pandora/scripts/pnd_run.sh -m $PNDARGS"
103                 sudo /usr/pandora/scripts/pnd_run.sh -m $PNDARGS
104                 mount | grep "on /mnt/utmp/${PND_NAME} type"
105                 if [ $? -ne 0 ];then
106                         echo "The Union File-system is not mounted !"
107                         return 1
108                 fi
109                 return $?
110         fi
111         #create mountpoints, check if they exist already first to avoid annoying error messages
112         if ! [ -d "/mnt/pnd/${PND_NAME}" ]; then 
113                 mkdir -p "/mnt/pnd/${PND_NAME}"         #mountpoint for iso, ro
114         fi 
115         #writeable dir for union
116         if ! [ -d "${APPDATADIR}" ]; then 
117                 mkdir -p "${APPDATADIR}"
118                 chmod -R a+xrw "${APPDATADIR}" 2>/dev/null
119         fi
120         # create the union mountpoint
121         if ! [ -d "/mnt/utmp/${PND_NAME}" ]; then
122                 mkdir -p "/mnt/utmp/${PND_NAME}"                # union over the two
123         fi
124         #is the union already mounted? if not mount evrything, else launch the stuff
125         mount | grep "on /mnt/utmp/${PND_NAME} type"
126         if [ $? -ne 0 ];then
127                 mount | grep "on /mnt/pnd/${PND_NAME} type"
128                 if [ $? -ne 0 ];then
129                         echo not mounted on loop yet, doing so
130                         #check if pnd is already attached to loop 
131                         LOOP=$(losetup -a | grep "$PND" | tail -n1 | awk -F: '{print $1}')
132                         #check if the loop device is already mounted
133                         if ! [ -z "$LOOP" ];then
134                                 echo "Found a loop ($LOOP), using it"
135                                 loopmountedon=$( mount | grep "$(mount | grep "$LOOP" | awk '{print $3}')" | grep utmp | awk '{print $3}' )
136                         else
137                                 loopmountedon=""
138                         fi
139                         echo "LoopMountedon: $loopmountedon"
140                         if [ ! "$loopmountedon" ]; then #check if the pnd is already attached to some loop device but not used
141                                 FREELOOP=$LOOP 
142                                 #reuse existing loop
143                                 if [ ! "$LOOP" ]; then
144                                         FREELOOP=$(/sbin/losetup -f) #get first free loop device
145                                         echo $FREELOOP
146                                         if [ ! "$FREELOOP" ]; then  # no free loop device, create a new one
147                                                     #find a free loop device and use it 
148                                                     usedminor=$(/sbin/losetup -a | tail -n1)
149                                                     usedminor=${usedminor:9:1}
150                                                     echo usedminor $usedminor
151                                                     freeminor=$(($usedminor+1))
152                                                     echo freeminor $freeminor
153                                                     mknod -m777 /dev/loop$freeminor b 7 $freeminor
154                                                     FREELOOP=/dev/loop$freeminor
155                                         fi
156                                 fi
157                                 #detect fs
158
159                                 case $PND_FSTYPE in
160                                 ISO)
161                                         /sbin/losetup $FREELOOP "$PND" #attach the pnd to the loop device
162                                         mntline="mount" #setup the mountline for later
163                                         mntdev="${FREELOOP}"
164                                         #mntline="mount -o loop,mode=777 $PND /mnt/pnd/$PND_NAME"
165                                         echo "Filetype is $PND_FSTYPE";;
166                                 directory)
167                                         #we bind the folder, now it can be treated in a unified way 
168                                         #ATENTION: -o ro doesnt work for --bind at least on 25, on 26 its possible using remount, may have changed on 27
169                                         mntline="mount --bind -o ro"
170                                         mntdev="${PND}"
171                                         echo "Filetype is $PND_FSTYPE";;
172                                 Squashfs)
173                                         /sbin/losetup $FREELOOP "$PND" #attach the pnd to the loop device
174                                         mntline="mount -t squashfs"
175                                         mntdev="${FREELOOP}"
176                                         echo "Filetype is $PND_FSTYPE";;
177                                 *)
178                                         echo "error determining fs, output was $PND_FSTYPE"
179                                         exit 1;;
180                                 esac
181                                 echo "Mounting PND ($mntline) :"
182                                 $mntline "$mntdev" "/mnt/pnd/${PND_NAME}" #mount the pnd/folder
183
184                         else #the pnd is already mounted but a mount was requested with a different basename/uid, just link it there
185                                       echo $LOOP already mounted on $loopmountedon skipping losetup - putting link to old mount
186                                       #this is bullshit
187                                       rmdir "/mnt/utmp/$PND_NAME"
188                                       ln -s $loopmountedon "/mnt/utmp/$PND_NAME" 
189                         fi
190
191                         mount | grep "on /mnt/pnd/${PND_NAME} type"
192                         if [ $? -ne 0 ];then
193                                 echo "The PND File-system is not mounted ! - Union wont work anyway"
194                                 return 2
195                         fi
196                 
197                 else
198                         echo "the PND is already mounted"
199                 fi
200                 FILESYSTEM=$(mount | grep "on $MOUNTPOINT " | grep -v rootfs | awk '{print $5}' | tail -n1) #get filesystem appdata is on to determine aufs options
201                 RO=0;for o in $(mount|grep "on $MOUNTPOINT "|sed 's/.*(//;s/)$//;s/,/ /g');do [[ $o = "ro" ]]&& RO=1;done
202                 if [ $RO -eq 1 ];then
203                         echo "SD-Card is mounted Read-only !! Trying to remount RW"
204                         mount -oremount,rw $MOUNTPOINT
205                 fi
206                 echo "Filesystem is $FILESYSTEM"
207                 echo "Mounting the Union FS using ${APPDATADIR} as Write directory:"
208                 if [[ "$FILESYSTEM" = "vfat" ]]; then # use noplink on fat, dont on other fs's 
209                         #append is fucking dirty, need to clean that up
210                         echo mount -t aufs -o exec,noplink,dirs="${APPDATADIR}=rw+nolwh":"/mnt/pnd/$PND_NAME=rr$append" none "/mnt/utmp/$PND_NAME"
211                         mount -t aufs -o exec,noplink,dirs="${APPDATADIR}=rw+nolwh":"/mnt/pnd/$PND_NAME=rr$append" none "/mnt/utmp/$PND_NAME"
212                         # put union on top
213                 else
214                         mount -t aufs -o exec,dirs="${APPDATADIR}=rw+nolwh":"/mnt/pnd/$PND_NAME=rr$append" none "/mnt/utmp/$PND_NAME" 
215                         # put union on top
216                 fi
217
218                 mount | grep "on /mnt/utmp/${PND_NAME} type"
219                 if [ $? -ne 0 ];then
220                         echo "The Union File-system is not mounted !"
221                         return 1
222                 fi
223                 
224         else
225                 echo "Union already mounted"
226         fi
227 }
228
229 cleanups() {
230         #delete folders created by aufs if empty
231         rmdir -rf "${APPDATADIR}/.wh..wh.plnk" 2>/dev/null
232         rmdir -rf "${APPDATADIR}/.wh..wh..tmp" 2>/dev/null
233
234         #delete appdata folder and ancestors if _empty_
235         rmdir -p "${APPDATADIR}" 2>/dev/null
236
237         # Clean the loopback device
238         if [ $PND_FSTYPE = ISO ] || [ $PND_FSTYPE = Squashfs ]; then # check if we where running an iso, clean up loop device if we did
239                 LOOP=$(losetup -a | grep "$(basename $PND)" | tail -n1 | awk -F: '{print $1}')
240                 /sbin/losetup -d $LOOP
241                 rm $LOOP
242         fi
243
244         echo cleanup done
245 }
246
247 umountPnd() {
248         if mount | grep -q "on /mnt/pnd/${PND_NAME} type";then
249                 umount "/mnt/pnd/$PND_NAME"
250         fi
251         if ! [ -z "$(mount |grep pnd/$PND_NAME|cut -f3 -d' ')" ]; then
252                 echo umount PND failed, didnt clean up. Process still using this FS :
253                 list_using_fs "/mnt/pnd/$PND_NAME"
254         else
255                 # removing the now useless mountpoint
256                 if [ -d /mnt/pnd/$PND_NAME ];then
257                         rmdir "/mnt/pnd/$PND_NAME"
258                 fi
259
260                 # All went well, cleaning
261                 cleanups
262         fi
263 }
264
265 umountUnion() {
266         # Are we root yet ?
267         if [ $(id -u) -ne 0 ];then
268                 sudo /usr/pandora/scripts/pnd_run.sh -u $PNDARGS
269                 return $?
270         fi
271
272         # Make sure the Union FS is unmounted
273         if mount | grep -q "on /mnt/utmp/${PND_NAME} type";then
274                 umount "/mnt/utmp/$PND_NAME" #umount union
275         fi
276         if ! [ -z "$(mount |grep utmp/$PND_NAME|cut -f3 -d' ')" ]; then
277                 echo umount UNION failed, didnt clean up. Process still using this FS :
278                 list_using_fs "/mnt/utmp/$PND_NAME"
279         else
280                 # the Union is umounted, removing the now empty mountpoint
281                 if [ -d "/mnt/utmp/$PND_NAME" ];then
282                         rmdir "/mnt/utmp/$PND_NAME"
283                 elif [ -e "/mnt/utmp/$PND_NAME" ];then
284                         rm "/mnt/utmp/$PND_NAME" >/dev/null 2>&1 # as it might be a symlink
285                 fi
286                 # Try umounting the PND
287                 umountPnd
288         fi
289 }
290
291 main() {
292         if [ $nox ]; then #the app doesnt want x to run, so we kill it and restart it once the app quits
293                 if [ ! $(pidof X) ]; then 
294                         unset $nox
295                 else
296                         applist=$(lsof /usr/lib/libX11.so.6 | awk '{print $1}'| sort | uniq)
297                         whitelist=$(cat ~/pndtest/whitelist) #adjust this to a fixed whitelist, maybe in the config dir
298                         filteredlist=$(echo -e "$applist\n\n$whitelist\n\n$whitelist" | sort | uniq -u) #whitelist appended two times so those items are always removed
299                         if [ ${#filteredlist} -ge 1 ]; then
300                                 message=$(echo -e "The following applications are still running, are you sure you want to close x? \n$filteredlist")
301                                 echo -e "?ae[34me[30m?"
302                                 xmessage -center "$message", -buttons yes,no
303                                 if [ $? = 102 ]; then
304                                         exit 1
305                                 fi
306                                 sudo /etc/init.d/slim-init stop
307                                 sleep 5s
308                         else
309                                 echo -e "?ae[34me[30m?"
310                                 xmessage -center "killing x, nothing of value will be lost", -buttons ok,cancel
311                                 if [ $? = 102 ]; then
312                                         exit 1
313                                 fi
314                                 # close x now, do we want to use slim stop or just kill x?
315                                 sudo /etc/init.d/slim-init stop
316                                 sleep 5s
317                         fi
318                 fi
319         fi
320
321         case $ACTION in
322         mount)  mountPnd;;
323         umount) umountUnion;;
324         run)
325                 mountPnd
326                 if [ $? -ne 0 ];then
327                         zenity --warning --title="Mounting the PND failed" --text="Mounting the PND failed. The application wont start. Please have a look at $LOGFILE"
328                         return 3
329                 fi
330                 oPWD=$(pwd)
331                 runApp
332                 cd $oPWD
333                 umountUnion;;
334         esac
335
336
337         if [ $nox ]; then #restart x if it was killed
338                 echo "starting x in 5s"
339                 sleep 5
340                 sudo /etc/init.d/slim-init start
341         fi
342 }
343
344 ######################################################################################
345 ####    Parse arguments
346 ##
347
348 PNDARGS="$@"
349
350 TEMP=`getopt -o d:p:e:a:b:s:m::u::n::x::j:c: -- $PNDARGS`
351 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
352 eval set -- "$TEMP"                             # Note the quotes around `$TEMP': they are essential!
353  
354 ACTION=run
355 while true ; do
356         case "$1" in
357                 -p) PND=$2;shift 2;;
358                 -e) EXENAME=$2;shift 2 ;;
359                 -b) PND_NAME=$2;shift 2;;
360                 -s) STARTDIR=$2;shift 2;;
361                 -m) ACTION=mount;shift 2;;
362                 -u) ACTION=umount;shift 2;;
363                 -x) nox=1;shift 2;;
364                 -j) append=$2;shift 2;;
365                 -c) cpuspeed=$2;shift 2;;
366                 -d) APPDATASET=1;APPDATADIR=$2;shift 2;;
367                 -a) 
368                         case "$2" in
369                                 "") echo "no arguments"; shift 2 ;;
370                                 *)  echo "args set to \`$2'" ;ARGUMENTS=$2;shift 2 ;;
371                         esac ;;
372                 --) shift ; break ;;
373                 *) echo "Error while parsing arguments!" ; exit 1 ;;
374         esac
375 done
376
377 if [ ! -e "$PND" ]; then #check if theres a pnd suplied, need to clean that up a bit more
378         echo "ERROR: selected PND($PND) file does not exist!"
379         showHelp
380         exit 1
381 fi
382
383 if [ ! "$EXENAME" ] && [[ "$ACTION" = "run" ]]; then
384         echo "ERROR: no executable name provided!"
385         showHelp
386         exit 1
387 fi
388
389 PND_FSTYPE=$(file -b "$PND" | awk '{ print $1 }')       # is -p a zip/iso or folder?
390 MOUNTPOINT=$(df "$PND" | tail -1|awk '{print $6}')      # find out on which mountpoint the pnd is
391 if [ ! -d "$MOUNTPOINT" ] || [ $MOUNTPOINT = "/" ]; then 
392         MOUNTPOINT="";
393 fi
394
395 [ ! -z $APPDATASET ] || [ -z ${MOUNTPOINT} ] && APPDATADIR=${APPDATADIR:-$(dirname $PND)/$PND_NAME}
396 APPDATADIR=${APPDATADIR:-${MOUNTPOINT}/pandora/appdata/${PND_NAME}}
397
398 LOGFILE="/tmp/pndrun_${PND_NAME}.out"
399
400 #PND_NAME really should be something sensible and somewhat unique
401 #if -b is set use that as pnd_name, else generate it from PND
402 #get basename (strip extension if file) for union mountpoints etc, maybe  this should be changed to something specified inside the xml
403 #this should probably be changed to .... something more sensible
404 #currently only everything up to the first '.' inside the filenames is used.
405 PND_NAME=${PND_NAME:-"$(basename $PND | cut -d'.' -f1)"}
406
407 if [[ $ACTION != "run" ]];then #not logging mount and umount as these are from command-line
408         main
409 elif [ $nox ]; then
410         main > $LOGFILE 2>&1 & 
411         disown
412 else
413         main > $LOGFILE 2>&1
414 fi
415