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