From: skeezix Date: Mon, 23 Feb 2009 20:50:40 +0000 (-0500) Subject: discovery code now recognizes pnd files X-Git-Tag: Release-2010-05/1~215 X-Git-Url: http://git.openpandora.org/cgi-bin/gitweb.cgi?p=pandora-libraries.git;a=commitdiff_plain;h=2d27c18f8b065e7fa7a0824007a24987c3650c6c discovery code now recognizes pnd files 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* --- diff --git a/Makefile b/Makefile index f924fa2..90de4c4 100644 --- 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 diff --git a/TODO.txt b/TODO.txt index 77245c3..58ae80f 100644 --- 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 diff --git a/include/pnd_pndfiles.h b/include/pnd_pndfiles.h index e141482..2abefba 100644 --- a/include/pnd_pndfiles.h +++ b/include/pnd_pndfiles.h @@ -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 (case insensitively) +// Returns 1 on success ( found), leaving file pointer after the \n +// Returns 0 on failure (likely file pointer is at the end of the file, having sought out the +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 diff --git a/lib/pnd_discovery.c b/lib/pnd_discovery.c index 01f4c9a..9513087 100644 --- a/lib/pnd_discovery.c +++ b/lib/pnd_discovery.c @@ -1,6 +1,8 @@ #include /* for FILE etc */ #include /* for malloc */ + +#define __USE_GNU /* for strcasestr */ #include /* 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 .. , 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 } diff --git a/lib/pnd_pndfiles.c b/lib/pnd_pndfiles.c index 2b5a542..a8f564c 100644 --- a/lib/pnd_pndfiles.c +++ b/lib/pnd_pndfiles.c @@ -1,7 +1,10 @@ #include /* for FILE etc */ #include /* for malloc */ -#include /* for making ftw.h happy */ +#include /* for isprint */ + +#define __USE_GNU +#include /* for making strcasestr happy */ #include "pnd_container.h" #include "pnd_pxml.h" @@ -9,34 +12,122 @@ #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 ); } diff --git a/lib/pnd_pxml.c b/lib/pnd_pxml.c index 5471ff6..ab134ef 100644 --- a/lib/pnd_pxml.c +++ b/lib/pnd_pxml.c @@ -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 ); } diff --git a/lib/pnd_tinyxml.cpp b/lib/pnd_tinyxml.cpp index 68e8f94..83f5082 100644 --- a/lib/pnd_tinyxml.cpp +++ b/lib/pnd_tinyxml.cpp @@ -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(); diff --git a/testdata/apps/sampleapp3/PXML.xml b/testdata/apps/sampleapp3/PXML.xml index 72711e0..49a9106 100644 --- a/testdata/apps/sampleapp3/PXML.xml +++ b/testdata/apps/sampleapp3/PXML.xml @@ -1,13 +1,12 @@ - - <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> -127ulysis +256twinky Yes @@ -84,3 +83,4 @@ ../differentdir + diff --git a/testdata/pndsample/x86_ls.pnd b/testdata/pndsample/x86_ls.pnd new file mode 100644 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 index 0000000..87f9873 --- /dev/null +++ b/testdata/pndsample/x86_ls/PXML.xml @@ -0,0 +1,86 @@ + + + + <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> + + +123456x86ls + +Yes + +program.png + + + This is the [b]English Description[/b] of the file. + Can use [i]multiple lines[/i] and BBCode. + The German Description + The Italian Description + The French Description + + + + ./preview/pic1.jpg + ./preview/pic2.jpg + + + + EvilDragon + http://www.openpandora.org + + + + 1 + 1 + 1 + 2 + + +program.exe + + +
Main category
+ Subcategory 1 + Subcategory 2 +
+ + +
Alternate category
+ Alternate Subcategory 1 + Alternate Subcategory 2 +
+ + + 1 + 1 + 1 + 2 + + + + View this Picture + jpg,bmp,gif + ­view + + + + Convert this Picture + jpg,bmp,gif + ­convert + + + + Watch This Movie + mpg,avi,wmv + ­convert + + +600 + +Yes + +../differentdir + +
diff --git a/testdata/pndsample/x86_ls/ls b/testdata/pndsample/x86_ls/ls new file mode 100755 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 index 0000000..867f247 --- /dev/null +++ b/testdata/scripts/pnd_make.sh @@ -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 diff --git a/testdata/scripts/pnd_run.sh b/testdata/scripts/pnd_run.sh index d3f9083..eac2552 100644 --- a/testdata/scripts/pnd_run.sh +++ b/testdata/scripts/pnd_run.sh @@ -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 +"