discovery code now recognizes pnd files
authorskeezix <skeezix@flotsam-vm.(none)>
Mon, 23 Feb 2009 20:50:40 +0000 (15:50 -0500)
committerskeezix <skeezix@flotsam-vm.(none)>
Mon, 23 Feb 2009 20:50:40 +0000 (15:50 -0500)
Fixed a bunch of little bugs lieing around

Almost there.. just need to fix up the exec-paths in the .desktop files, and add icon support.. and see TODO.. *cry*

13 files changed:
Makefile
TODO.txt
include/pnd_pndfiles.h
lib/pnd_discovery.c
lib/pnd_pndfiles.c
lib/pnd_pxml.c
lib/pnd_tinyxml.cpp
testdata/apps/sampleapp3/PXML.xml
testdata/pndsample/x86_ls.pnd [new file with mode: 0644]
testdata/pndsample/x86_ls/PXML.xml [new file with mode: 0644]
testdata/pndsample/x86_ls/ls [new file with mode: 0755]
testdata/scripts/pnd_make.sh [new file with mode: 0755]
testdata/scripts/pnd_run.sh

index f924fa2..90de4c4 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -20,7 +20,7 @@ LIB = libpnd.a
 SOLIB = libpnd.so.1         # canonicle name
 SOLIB1 = libpnd.so.1.0.1    # versioned name
 XMLOBJ = lib/tinyxml/tinystr.o lib/tinyxml/tinyxml.o lib/tinyxml/tinyxmlerror.o lib/tinyxml/tinyxmlparser.o
-ALLOBJ = pnd_conf.o pnd_container.o pnd_discovery.o pnd_pxml.o pnd_notify.o pnd_locate.o pnd_tinyxml.o
+ALLOBJ = pnd_conf.o pnd_container.o pnd_discovery.o pnd_pxml.o pnd_notify.o pnd_locate.o pnd_tinyxml.o pnd_pndfiles.o
 
 all: ${SOLIB} ${LIB} conftest discotest notifytest locatetest pndnotifyd
 
index 77245c3..58ae80f 100644 (file)
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,10 +1,18 @@
 
 Some things to be done..
 
+- replace brute force memcmp() in pnd pnd with a fancy pants CS alg
+
 - review pnd_tinyxml to ensure the PXML_FILENAME is csae insensitive as needed
+- fix pnd_tinyxml.. why does it need 'if ( s )' protection. it assumes some filename weird stuff
+    - why does it need filenames at all for icons/etc?!
+
+- fix is_pxml_valid_app() .. right now it always returns 1!
 
 - make pnd_pndfiles seek of PXML more efficient; fread ( 1, nmemb ) gotta be slow :)
 
+- make accrused PXML from pnd-buffer growable, not locked at 32k/X size
+
 apps/pndnotifyd.c:// TODO: Catch HUP and reparse config
 apps/pndnotifyd.c:// TODO: Should perhaps direct all printf's through a vsprintf handler to avoid redundant "if ! g_daemon_mode"
 apps/pndnotifyd.c:// TODO: During daemon mode, should perhaps syslog or log errors
index e141482..2abefba 100644 (file)
@@ -18,12 +18,22 @@ extern "C" {
 // either if the goods are near the end. How big is an average .png for an average icon
 // size?
 #define PND_PXML_WINDOW_SIZE 4096
+#define PND_PXML_WINDOW_FRACTIONAL ( PND_PXML_WINDOW_SIZE - 10 )
 
 // pnd_seek_pxml should vaguely work like fseek, trying to position at begin of the appended/found PXML
 // On return of 0, assuming nothing.
 // On 1, assume that the FILE pointer is positioned for next read to pull in the PXML line by line
 unsigned char pnd_pnd_seek_pxml ( FILE *f );
 
+// accrue_pxml will read through the given FILE * until it finds </PXML> (case insensitively)
+// Returns 1 on success (</PXML> found), leaving file pointer after the </PXML>\n
+// Returns 0 on failure (likely file pointer is at the end of the file, having sought out the </PXML>
+unsigned char pnd_pnd_accrue_pxml ( FILE *f, char *target, unsigned int maxlen );
+
+// pnd_match_binbuf will find a case insensitve string within a binary buffer (ie: strcasestr will
+// only work in a non-binary buffer.) Brute force zombies ahead!
+char *pnd_match_binbuf ( char *haystack, unsigned int maxlen, char *needle );
+
 #ifdef __cplusplus
 } /* "C" */
 #endif
index 01f4c9a..9513087 100644 (file)
@@ -1,6 +1,8 @@
 
 #include <stdio.h> /* for FILE etc */
 #include <stdlib.h> /* for malloc */
+
+#define __USE_GNU /* for strcasestr */
 #include <string.h> /* for making ftw.h happy */
 
 #define _XOPEN_SOURCE 500
@@ -51,68 +53,112 @@ static int pnd_disco_callback ( const char *fpath, const struct stat *sb,
                                int typeflag, struct FTW *ftwbuf )
 {
   unsigned char valid = 0; // 1 for plaintext PXML, 2 for PND...
+  pnd_pxml_handle pxmlh = 0;
+
+  //printf ( "disco root callback encountered '%s'\n", fpath );
 
   // PXML.xml is a possible application candidate (and not a dir named PXML.xml :)
   if ( typeflag & FTW_D ) {
+    //printf ( " .. is dir, skipping\n" );
     return ( 0 ); // skip directories and other non-regular files
   }
 
   // PND/PNZ file and others may be valid as well .. but lets leave that for now
+  //   printf ( "%s %s\n", fpath + ftwbuf -> base, PND_PACKAGE_FILEEXT );
   if ( strcasecmp ( fpath + ftwbuf -> base, PXML_FILENAME ) == 0 ) {
     valid = 1;
-  } else if ( strcasecmp ( fpath + ftwbuf -> base, PND_PACKAGE_FILEEXT "\0" ) == 0 ) {
+  } else if ( strcasestr ( fpath + ftwbuf -> base, PND_PACKAGE_FILEEXT "\0" ) ) {
     valid = 2;
   }
 
   // if not a file of interest, just keep looking until we run out
   if ( ! valid ) {
+    //printf ( " .. bad filename, skipping\n" );
     return ( 0 );
   }
 
   // potentially a valid application
   if ( valid == 1 ) {
     // Plaintext PXML file
-    //printf ( "disco callback encountered '%s'\n", fpath );
-
-    pnd_pxml_handle pxmlh;
+    //printf ( "PXML: disco callback encountered '%s'\n", fpath );
 
     // pick up the PXML if we can
-
     pxmlh = pnd_pxml_fetch ( (char*) fpath );
 
-    if ( ! pxmlh ) {
-      return ( 0 ); // continue the scan
+  } else if ( valid == 2 ) {
+    // PND ... ??
+    FILE *f;
+    char pxmlbuf [ 32 * 1024 ]; // TBD: assuming 32k pxml accrual buffer is a little lame
+
+    //printf ( "PND: disco callback encountered '%s'\n", fpath );
+
+    // is this a valid .pnd file? The filename is a candidate already, but verify..
+    // .. presence of PXML appended, or at least contained within?
+    // .. presence of an icon appended after PXML?
+
+    // open it up..
+    f = fopen ( fpath, "r" );
+
+    // try to locate the PXML portion
+    if ( ! pnd_pnd_seek_pxml ( f ) ) {
+      fclose ( f );
+      return ( 0 ); // pnd or not, but not to spec. Pwn'd the pnd?
+    }
+
+    // accrue it into a buffer
+    if ( ! pnd_pnd_accrue_pxml ( f, pxmlbuf, 32 * 1024 ) ) {
+      fclose ( f );
+      return ( 0 );
     }
 
+    //printf ( "buffer is %s\n", pxmlbuf );
+    //fflush ( stdout );
+
+    // by now, we have <PXML> .. </PXML>, try to parse..
+    pxmlh = pnd_pxml_fetch_buffer ( (char*) fpath, pxmlbuf );
+
+  }
+
+  // pxmlh is useful?
+  if ( pxmlh ) {
+
     // look for any overrides, if requested
     pnd_pxml_merge_override ( pxmlh, disco_overrides );
 
     // check for validity and add to resultset if it looks executable
     if ( pnd_is_pxml_valid_app ( pxmlh ) ) {
+      char b [ 1024 ]; // TBD: also lame
       pnd_disco_t *p;
 
       p = pnd_box_allocinsert ( disco_box, (char*) fpath, sizeof(pnd_disco_t) );
-      p -> title_en = strdup ( pnd_pxml_get_app_name ( pxmlh ) );
-      p -> icon = strdup ( pnd_pxml_get_icon_path ( pxmlh ) );
-      p -> exec = strdup ( pnd_pxml_get_exec_path ( pxmlh ) );
-      p -> unique_id = strdup ( pnd_pxml_get_unique_id ( pxmlh ) );
-      p -> main_category = strdup ( pnd_pxml_get_primary_category ( pxmlh ) );
-      p -> clockspeed = strdup ( pnd_pxml_get_clockspeed ( pxmlh ) ); 
-
+      if ( pnd_pxml_get_app_name ( pxmlh ) ) {
+       p -> title_en = strdup ( pnd_pxml_get_app_name ( pxmlh ) );
+      }
+      if ( pnd_pxml_get_icon_path ( pxmlh ) ) {
+       p -> icon = strdup ( pnd_pxml_get_icon_path ( pxmlh ) );
+      }
+      if ( pnd_pxml_get_exec_path ( pxmlh ) ) {
+       snprintf ( b, 1024, "pnd_run_magic %s", pnd_pxml_get_exec_path ( pxmlh ) );
+       p -> exec = strdup ( b );
+      }
+      if ( pnd_pxml_get_unique_id ( pxmlh ) ) {
+       p -> unique_id = strdup ( pnd_pxml_get_unique_id ( pxmlh ) );
+      }
+      if ( pnd_pxml_get_primary_category ( pxmlh ) ) {
+       p -> main_category = strdup ( pnd_pxml_get_primary_category ( pxmlh ) );
+      }
+      if ( pnd_pxml_get_clockspeed ( pxmlh ) ) {
+       p -> clockspeed = strdup ( pnd_pxml_get_clockspeed ( pxmlh ) ); 
+      }
+
+    } else {
+      //printf ( "Invalid PXML; skipping.\n" );
     }
 
     // ditch pxml
     pnd_pxml_delete ( pxmlh );
 
-  } else if ( valid == 2 ) {
-    // PND ... ??
-    printf ( "PND: disco callback encountered '%s'\n", fpath );
-
-    // is this a valid .pnd file? The filename is a candidate already, but verify..
-    // .. presence of PXML appeneded, or at least contained within?
-    // .. presence of an icon appended after PXML?
-
-  }
+  } // got a pxmlh
 
   return ( 0 ); // continue the tree walk
 }
index 2b5a542..a8f564c 100644 (file)
@@ -1,7 +1,10 @@
 
 #include <stdio.h> /* for FILE etc */
 #include <stdlib.h> /* for malloc */
-#include <string.h> /* for making ftw.h happy */
+#include <ctype.h> /* for isprint */
+
+#define __USE_GNU
+#include <string.h> /* for making strcasestr happy */
 
 #include "pnd_container.h"
 #include "pnd_pxml.h"
 #include "pnd_pndfiles.h"
 
 unsigned char pnd_pnd_seek_pxml ( FILE *f ) {
-  char *b;
-  unsigned int len;
+  char *b;                // buffer
+  char *match;            // match within buffer
+  unsigned int len;       // length of file (not suporting 'big files' 2GB..)
+  unsigned int pos;       // current tape head
+  unsigned int readable;  // amount to read (for small files/chunks)
 
-  b = malloc ( PND_PXML_WINDOW_SIZE );
+  b = malloc ( PND_PXML_WINDOW_SIZE + 1 );
 
   if ( ! b ) {
     return ( 0 );
   }
 
-  memset ( b, '\0', PND_PXML_WINDOW_SIZE );
+  memset ( b, '\0', PND_PXML_WINDOW_SIZE + 1 );
 
   // determine length of file
   fseek ( f, 0, SEEK_END );
-
   len = ftell ( f );
-
   fseek ( f, 0, SEEK_SET );
 
   /* ready to scan through the file, backwards
    */
 
-  //strcasestr ( b, PXML_TAGHEAD );
-
+  // easy case or no?
+  if ( len <= PND_PXML_WINDOW_SIZE ) {
+    pos = 0;
+    readable = len;
+  } else {
+    pos = len - PND_PXML_WINDOW_SIZE;
+    readable = PND_PXML_WINDOW_SIZE;
+  }
 
+  while ( 1 ) {
+
+    printf ( "find pxml; pos %u readable %u\n", pos, readable );
+
+    // seek into this blocks position
+    fseek ( f, pos, SEEK_SET );
+
+    // read
+    fread ( b, 1, readable, f );
+
+    // find the head tag here? now, there are serious heavy duty algorithyms for locating
+    // strings within an arbitrary buffer. Thats needs to be done. This is the worst
+    // performing brute force strategy here.
+    if ( ( match = pnd_match_binbuf ( b, readable, PXML_TAGHEAD ) ) ) {
+      fseek ( f, pos + ( match - b ), SEEK_SET );
+      printf ( "  match found at %u\n", pos + ( match - b ) );
+      free ( b );
+      return ( 1 );
+    }
+
+    // no match, so we need to back up another chunk; if we can't
+    // back up that much, we're on our last check. if we can't back
+    // up at all, we've already been here and time to fail
+    if ( pos == 0 ) {
+      break; // done, FAIL
+    } else if ( pos > PND_PXML_WINDOW_FRACTIONAL ) {
+      pos -= PND_PXML_WINDOW_FRACTIONAL;
+      readable = PND_PXML_WINDOW_SIZE;
+    } else {
+      readable = PND_PXML_WINDOW_SIZE - pos;
+      memset ( b + pos, '\0', PND_PXML_WINDOW_SIZE - pos );
+      pos = 0;
+    }
+
+  } // while
 
   // exeunt, with alarums
-
   free ( b );
+  return ( 0 );
+}
+
+unsigned char pnd_pnd_accrue_pxml ( FILE *f, char *target, unsigned int maxlen ) {
+  char inbuf [ 1024 ]; // TBD: love all these assumptions? noob!
+  char *insert = target;
+  unsigned int l;
+
+  while ( fgets ( inbuf, 1023, f ) ) {
+
+    // copy inbuf onto end of target
+#if 1
+    strncpy ( insert, inbuf, maxlen );
+    // reduce counter for max size so we can avoid buffer overruns
+    l = strlen ( inbuf );
+    maxlen -= l; // reduce
+    insert += l; // increment
+#else
+    strncat ( target, inbuf, maxlen );
+#endif
+
+    if ( strcasestr ( inbuf, PXML_TAGFOOT ) ) {
+      return ( 1 );
+    }
+
+  } // while
+
+  return ( 0 );
+}
+
+char *pnd_match_binbuf ( char *haystack, unsigned int maxlen, char *needle ) {
+  char *end = haystack + maxlen - strlen ( needle );
+  unsigned int needlelen = strlen ( needle );
+
+  while ( haystack < end ) {
+
+    if ( isprint(*haystack) ) {
+
+      if ( strncasecmp ( haystack, needle, needlelen ) == 0 ) {
+       //printf ( "haystack %s\n", haystack );
+       return ( haystack );
+      }
+
+    }
+
+    haystack += 1;
+  }
 
-  return ( 1 );
+  return ( NULL );
 }
index 5471ff6..ab134ef 100644 (file)
@@ -112,12 +112,19 @@ unsigned char pnd_is_pxml_valid_app ( pnd_pxml_handle h ) {
   pnd_pxml_t *p = (pnd_pxml_t*) h;
 
   // for now, lets just verify the exec-path is valid
+
   //printf ( "exec is '%s'\n", p -> exec );
 
+  return ( 1 );
+
+  // even this is complicated by pnd_run.sh semantics .. can't check if it exists
+  // during discovery, since it is not mounted yet..
+#if 0
   struct stat buf;
   if ( stat ( p -> exec, &buf ) == 0 ) {
     return ( 1 ); // path is present
   }
+#endif
 
   return ( 0 );
 }
index 68e8f94..83f5082 100644 (file)
@@ -93,8 +93,10 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
                char anotherbuffer [ FILENAME_MAX ];
                strcpy ( anotherbuffer, pFilename );
                char *s = strstr ( anotherbuffer, PXML_FILENAME );
-               strcpy ( s, strdup(pElem->GetText()));
-               app->icon = strdup(anotherbuffer);
+               if ( s ) {
+                 strcpy ( s, strdup(pElem->GetText()));
+                 app->icon = strdup(anotherbuffer);
+               }
        }
 
        pElem = hRoot.FirstChild( "description" ).FirstChildElement("en").Element();
@@ -175,8 +177,14 @@ unsigned char pnd_pxml_parse ( const char *pFilename, char *buffer, unsigned int
                char anotherbuffer [ FILENAME_MAX ];
                strcpy ( anotherbuffer, pFilename );
                char *s = strstr ( anotherbuffer, PXML_FILENAME );
-               strcpy ( s, strdup(pElem->GetText()));
-               app->exec = strdup(anotherbuffer);
+               if ( s ) {
+                 strcpy ( s, strdup(pElem->GetText()));
+                 app->exec = strdup(anotherbuffer);
+               } else if ( ( s = strrchr ( anotherbuffer, '/' ) ) ) {
+                 s += 1;
+                 strcpy ( s, strdup(pElem->GetText()));
+                 app->exec = strdup(anotherbuffer);
+               }
        }       
 
        pElem = hRoot.FirstChild( "category" ).FirstChildElement("main").Element();
index 72711e0..49a9106 100644 (file)
@@ -1,13 +1,12 @@
-<?xml version="1.0"?>
 <PXML>
 <title>
-       <en>Program Title</en>
+       <en>sample 3</en>
        <de>Program Title in German Language</de>
        <fr>Program Title in French Language</fr>
        <it>Program Title in Italian Language</it>
 </title>
 
-<unique_id>127ulysis</unique_id>
+<unique_id>256twinky</unique_id>
 
 <standalone>Yes</standalone>
 
@@ -84,3 +83,4 @@
 <startdir>../differentdir</startdir>
 
 </PXML>
+
diff --git a/testdata/pndsample/x86_ls.pnd b/testdata/pndsample/x86_ls.pnd
new file mode 100644 (file)
index 0000000..a3f11b4
Binary files /dev/null and b/testdata/pndsample/x86_ls.pnd differ
diff --git a/testdata/pndsample/x86_ls/PXML.xml b/testdata/pndsample/x86_ls/PXML.xml
new file mode 100644 (file)
index 0000000..87f9873
--- /dev/null
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<PXML>
+<title>
+       <en>x86 ls</en>
+       <de>Program Title in German Language</de>
+       <fr>Program Title in French Language</fr>
+       <it>Program Title in Italian Language</it>
+</title>
+
+<unique_id>123456x86ls</unique_id>
+
+<standalone>Yes</standalone>
+
+<icon>program.png</icon>
+
+<description>
+       <en>This is the [b]English Description[/b] of the file.
+            Can use [i]multiple lines[/i] and BBCode.</en>
+       <de>The German Description</de>
+       <it>The Italian Description</it>
+       <fr>The French Description</fr>
+</description>
+
+<previewpic>
+       <pic1>./preview/pic1.jpg</pic1>
+       <pic2>./preview/pic2.jpg</pic2>
+</previewpic>
+
+<author>
+       <name>EvilDragon</name>
+       <website>http://www.openpandora.org</website>
+</author>
+
+<version>
+       <major>1</major>
+       <minor>1</minor>
+       <release>1</release>
+       <build>2</build>
+</version>
+
+<exec>program.exe</exec>
+
+<category>
+       <main>Main category</main>
+       <subcategory1>Subcategory 1</subcategory1>
+       <subcategory2>Subcategory 2</subcategory2>
+</category>
+
+<altcategory>
+       <main>Alternate category</main>
+       <subcategory1>Alternate Subcategory 1</subcategory1>
+       <subcategory2>Alternate Subcategory 2</subcategory2>
+</altcategory>
+
+<osversion> 
+       <major>1</major>
+       <minor>1</minor>
+       <release>1</release>
+       <build>2</build>
+</osversion>
+
+<associationitem1>
+       <name>View this Picture</name>
+       <filetype>jpg,bmp,gif</filetype>
+       <parameter>­view</parameter>
+</associationitem1>
+
+<associationitem2>
+       <name>Convert this Picture</name>
+       <filetype>jpg,bmp,gif</filetype>
+       <parameter>­convert</parameter>
+</associationitem2>
+
+<associationitem3>
+       <name>Watch This Movie</name>
+       <filetype>mpg,avi,wmv</filetype>
+       <parameter>­convert</parameter>
+</associationitem3>
+
+<clockspeed>600</clockspeed>
+
+<background>Yes</background>
+
+<startdir>../differentdir</startdir>
+
+</PXML>
diff --git a/testdata/pndsample/x86_ls/ls b/testdata/pndsample/x86_ls/ls
new file mode 100755 (executable)
index 0000000..c250cd7
Binary files /dev/null and b/testdata/pndsample/x86_ls/ls differ
diff --git a/testdata/scripts/pnd_make.sh b/testdata/scripts/pnd_make.sh
new file mode 100755 (executable)
index 0000000..867f247
--- /dev/null
@@ -0,0 +1,7 @@
+#!/bin/bash
+pkgname=$1
+folder=$3
+xml=$2
+mkisofs -o $pkgname.iso -R $folder
+cat $pkgname.iso $xml >  $pkgname
+rm $pkgname.iso
index d3f9083..eac2552 100644 (file)
@@ -1,6 +1,8 @@
 #!/bin/bash
  
 #input pnd_run.sh -p "/path/to/foobar.pnd" -e "exe" --a "arguments for exe"
+# -u to skip union mount
+# -b to override basename
 #output none
  
 ########################### FS NAMES NEED ADJUSTMENT #################
@@ -8,7 +10,7 @@
 # check if all vars are set to sensible values
  
 # parse arguments
-TEMP=`getopt -o p:e:a:: --long p-long,e-long:,a-long: -- "$@"`
+TEMP=`getopt -o p:e:a:b:u:: --long p-long,e-long:,a-long: -- "$@"`
  
 if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
  
@@ -19,10 +21,9 @@ while true ; do
         case "$1" in
                 -p|--p-long) echo "pnd set to \`$2'" ;PND=$2;shift 2;;
                 -e|--e-long) echo "exec set to \`$2'" ;EXENAME=$2;shift 2 ;;
+                -u) echo "u set, no union pls!";UNION=1;shift 2 ;;
+                -b) echo "BASENAME set to $2";BASENAME=$2;shift 2;;
                 -a|--a-long) 
-                        # a has an optional argument. As we are in quoted mode,
-                        # an empty parameter will be generated if its optional
-                        # argument is not found.
                         case "$2" in
                                 "") echo "no arguments"; shift 2 ;;
                                 *)  echo "args set to \`$2'" ;ARGUMENTS=$2;shift 2 ;;
@@ -37,7 +38,11 @@ done
 #vars
 DFS=$(file -b $PND | awk '{ print $1 }') # is -p a zip iso or folder?
 MOUNTPOINT=$(df $PND | grep -vE '^Filesystem' | awk '{ print $6  }') #find out which mountpoint the pnd/folder is on
-BASENAME=$(basename "$PND" | cut -d'.' -f1) #get basename (strip extension if file) for union mountpoints etc, maybe  this should be changed to something specified inside the xml
+#if -b is set use that as basename, else generate it from PND
+#get basename (strip extension if file) for union mountpoints etc, maybe  this should be changed to something specified inside the xml
+if [ ! $BASENAME ]; then BASENAME=$(basename "$PND" | cut -d'.' -f1) ; fi
 oCWD=$(pwd)
 # add sanity check
  
@@ -58,26 +63,54 @@ else
 fi
  
 #create mountpoints
-#echo "
+echo "
 #will run:
 # create mountpoints
-mkdir -p /mnt/pnd/$BASENAME
-mkdir -p $MOUNTPOINT/appdata/$BASENAME
-mkdir -p /mnt/utmp/$BASENAME
+" 
+if [ ! -d /mnt/pnd/$BASENAME ]; then
+echo "mkdir -p /mnt/pnd/$BASENAME "
+fi
+if [ ! -d $MOUNTPOINT/appdata/$BASENAME ]; then
+echo "mkdir -p $MOUNTPOINT/appdata/$BASENAME "
+fi
+if [ ! -d /mnt/utmp/$BASENAME ]; then
+echo "mkdir -p /mnt/utmp/$BASENAME "
+fi 
  
 #mount
-$mntline #mount the pnd/folder
-mount -t unionfs -o exec,dirs\=$MOUNTPOINT/appdata/$BASENAME=rw:/mnt/pnd/$BASENAME=ro unionfs /mnt/utmp/$BASENAME #union mount
-#start app
-cd /mnt/utmp/$BASENAME
-$EXENAME $ARGUMENTS 
-cd $oCWD
-#app exited
+if [ ! $UNION ] ; then
+        mount | grep "on /mnt/utmp/$BASENAME type" > /dev/null
+        if [ ! $? -eq 0 ]; then 
+                echo "
+                $mntline #mount the pnd/folder
+                #mount -t unionfs -o exec,dirs\=$MOUNTPOINT/appdata/$BASENAME=rw:/mnt/pnd/$BASENAME=ro unionfs /mnt/utmp/$BASENAME #union mount
+                #aufs, one of those should work, bit unsure.
+                mount -t aufs -o exec,dirs\=$MOUNTPOINT/appdata/$BASENAME=rw:/mnt/pnd/$BASENAME=ro none /mnt/utmp/$BASENAME #aufs?
+                #mount -t aufs -o exec,dirs\=$MOUNTPOINT/appdata/$BASENAME=rw:/mnt/pnd/$BASENAME=ro aufs /mnt/utmp/$BASENAME #aufs?
+                "
+        else
+                echo "doh!"
+        fi
  
+        echo "
+        #start app
+        cd /mnt/utmp/$BASENAME
+        $EXENAME $ARGUMENTS 
+        cd $oCWD
+        #app exited
+        "
+else
+echo "
+        $mntline
+        cd /mnt/pnd/$BASENAME
+        $EXENAME $ARGUMENTS 
+        cd $oCWD
+"
+fi
+echo "
 #clean up
 umount /mnt/utmp/$BASENAME
 umount /mnt/pnd/$BASENAME
 rmdir /mnt/pnd/$BASENAME
 rmdir /mnt/utmp/$BASENAME
-#
\ No newline at end of file
+"