Shoudl be used sparingly, bt coudl be handy for guiding user to a needed path, or implying canonicle paths
pnd_log ( pndn_rem, "ERROR: Error creating .desktop file for app: %s\n", pnd_box_get_key ( d ) );
}
+ // does this object request any mkdir's?
+ if ( d -> mkdir_sp ) {
+
+ // it would appear it does! but we have to carefully validate these suckers
+ pnd_log ( pndn_rem, " App %s requests mkdir: %s\n", d -> object_path, d -> mkdir_sp );
+
+ // for each mkdir requested path, do it...
+ char *searchpath = d -> mkdir_sp;
+
+ SEARCHCHUNK_PRE
+ {
+ /* "buffer" now holds each chunk of the searchpath, expanded */
+
+ // WARN: This whole concept could be flawed; what if they represent '..' in some other obscure way (unicode?)
+ // and we end up allowing mkdir's all over the place? The risk really is limited -- once the pnd is here,
+ // if the user _runs it_, it can go nuts, so creating a few dirs isn't all that dangerous...
+ // HMRF :/
+ // Perhaps I should have a config setting for pndnotifyd to suppress this whole mkdir behaviour?
+
+ // if not containing ".." we allow it
+ if ( strstr ( buffer, ".." ) == NULL ) {
+
+ // determine mountpoint for the file
+ // - we could deduce this from the path (somewhat risky if we assume leading /media/mmcblk1p1 type notation .. could
+ // be other distributions entirely
+ // - better to scan through mount-list and figure it out.. *sucks*
+ char mountpoint [ PATH_MAX ];
+ if ( pnd_determine_mountpoint ( d -> object_path, mountpoint, PATH_MAX - strlen ( buffer ) - 1 ) == 1 ) {
+
+ strcat ( mountpoint, "/" );
+ strcat ( mountpoint, buffer );
+
+ struct stat t;
+ if ( stat ( mountpoint, &t ) == 0 ) {
+ pnd_log ( pndn_rem, " Skipping existing mkdir: %s\n", mountpoint );
+ } else {
+ pnd_log ( pndn_rem, " Attempting create of non-existant path: %s\n", mountpoint );
+ mkdir ( mountpoint, 0777 );
+ }
+
+ } // if figured out the mountpoint
+
+ } // if valid path
+
+ }
+ SEARCHCHUNK_POST
+
+ } // mkdir request
+
// next!
d = pnd_box_get_next ( d );
char *alt_category2;
char *preview_pic1;
char *preview_pic2;
+ char *mkdir_sp;
} pnd_disco_t;
void pnd_disco_destroy ( pnd_disco_t *p ); // a function name that simply could not be avoided
char *pnd_pxml_get_clockspeed ( pnd_pxml_handle h );
char *pnd_pxml_get_background ( pnd_pxml_handle h );
char *pnd_pxml_get_startdir ( pnd_pxml_handle h );
+char *pnd_pxml_get_mkdir ( pnd_pxml_handle h );
// for 'set' functions, pass NULL value to delete existing value without setting new one
void pnd_pxml_set_app_name ( pnd_pxml_handle h, char *v );
char *exec_no_x11;
char *package_name;
char *package_release_date;
+ char *mkdir_sp; // a colon separated list of paths to be mkdir'd (silently fail) when pnd is autodiscovered. path is always relative to the root of the hosting device.
} pnd_pxml_t;
#define PND_PXML_ATTRNAME_PACKAGE_NAME "name"
#define PND_PXML_ATTRNAME_PACKAGE_DATE "released"
+/* <mkdir>
+ * <dir path="..." />
+ * </mkdir>
+ */
+#define PND_PXML_NODENAME_MKDIR "mkdir"
+#define PND_PXML_ENAME_MKDIR "dir"
+#define PND_PXML_ATTRNAME_MKDIRPATH "path"
+
#ifdef __cplusplus
} // extern "C"
#endif
// NOTE: Does _NOT_ automatically pick up PXML-overrides; you can call that function if you want
pnd_pxml_handle pnd_pxml_get_by_path ( char *fullpath );
+// determine_mountpoint() will examine a path, and return the mountpoint that this path
+// is sitting on; returns 1 on success, meaning the target was populated.
+// consider for a similar effect: df /home -> look at "Mounted on"
+unsigned char pnd_determine_mountpoint ( char *fullpath, char *r_mountpoint, unsigned char mountpoint_len );
+
#ifdef __cplusplus
} /* "C" */
#endif
if ( p -> alt_category ) { free ( p -> alt_category ); }
if ( p -> alt_category1 ) { free ( p -> alt_category1 ); }
if ( p -> alt_category2 ) { free ( p -> alt_category2 ); }
+ if ( p -> mkdir_sp ) { free ( p -> mkdir_sp ); }
return;
}
if ( ( z = pnd_pxml_get_previewpic2 ( pxmlh ) ) ) {
p -> preview_pic2 = strdup ( z );
}
+ // mkdirs
+ if ( pnd_pxml_get_mkdir ( pxmlh ) ) {
+ p -> mkdir_sp = strdup ( pnd_pxml_get_mkdir ( pxmlh ) );
+ }
} else {
//printf ( "Invalid PXML; skipping.\n" );
#if 1 // globbing is performed
+// only iterates actual existing paths; if you want to return
+// non-matching paths, see below
+
#define SEARCHPATH_PRE \
char *end, *colon; \
char *head = searchpath; \
\
} // while
+
+// the following will return even non-matching chunks, but is not doing wordexp() expansion on it
+
+#define SEARCHCHUNK_PRE \
+ char *end, *colon; \
+ char *head = searchpath; \
+ char chunk [ FILENAME_MAX ]; \
+ \
+ /*fprintf ( stderr, "sp %s\n", searchpath );*/ \
+ \
+ while ( 1 ) { \
+ colon = strchr ( head, ':' ); \
+ end = strchr ( head, '\0' ); \
+ \
+ if ( colon && colon < end ) { \
+ memset ( chunk, '\0', FILENAME_MAX ); \
+ strncpy ( chunk, head, colon - head ); \
+ } else { \
+ strncpy ( chunk, head, FILENAME_MAX - 1 ); \
+ } \
+ \
+ /*fprintf ( stderr, "-> %s\n", chunk ); */ \
+ \
+ char buffer [ FILENAME_MAX ]; \
+ \
+ strcpy ( buffer, chunk ); \
+ /*fprintf ( stderr, "glob %s\n", buffer );*/ \
+ { /* user code */
+
+#define SEARCHCHUNK_POST \
+ } /* user code */ \
+ /* next search path */ \
+ if ( colon && colon < end ) { \
+ head = colon + 1; \
+ } else { \
+ break; /* done! */ \
+ } \
+ \
+ } // while
+
+
#endif // globbing is done
pnd_pxml_t *p = (pnd_pxml_t*) h;
return ( p -> startdir );
}
+
+char *pnd_pxml_get_mkdir ( pnd_pxml_handle h ) {
+ pnd_pxml_t *p = (pnd_pxml_t*) h;
+ return ( p -> mkdir_sp );
+}
app -> package_release_date = pnd_pxml_get_attribute ( pElem, PND_PXML_ATTRNAME_PACKAGE_DATE );
}
+ // mkdir request
+ if ( (pElem = hRoot.FirstChild(PND_PXML_NODENAME_MKDIR).Element()) ) {
+
+ // seek <dir>
+ if ( (pElem = pElem->FirstChildElement(PND_PXML_ENAME_MKDIR)) ) {
+ char *t;
+
+ if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) {
+ // first <dir>, so just replace it wholesale; we use strdup so we can free() easily later, consistently. Mmm, leak seems imminent.
+ app -> mkdir_sp = strdup ( t );
+ }
+
+ while ( ( pElem = pElem -> NextSiblingElement ( PND_PXML_ENAME_MKDIR ) ) ) {
+
+ if ( ( t = pnd_pxml_get_attribute(pElem, PND_PXML_ATTRNAME_MKDIRPATH) ) ) {
+ char *foo = (char*) malloc ( strlen ( app -> mkdir_sp ) + strlen ( t ) + 1 /*:*/ + 1 /*\0*/ );
+
+ if ( foo ) {
+ sprintf ( foo, "%s:%s", app -> mkdir_sp, t );
+ free ( app -> mkdir_sp );
+ app -> mkdir_sp = foo;
+ } // assuming we got ram, lets cat it all together
+
+ } // got another elem?
+
+ } // while
+
+ } // found a <dir>
+
+#if 0
+ if ( app -> mkdir_sp ) {
+ printf ( "mkdir: %s\n", app -> mkdir_sp );
+ }
+#endif
+
+ } // mkdir
+
return (1);
}
#include <utmp.h> /* for expand-tilde below; see commentary for this about-turn */
#include <sys/types.h> /* ditto */
#include <pwd.h> /* ditto */
+#include <sys/stat.h> /* for fstat */
+#include <dirent.h> /* for opendir */
#include "pnd_pxml.h"
#include "pnd_container.h"
return ( pxmlh );
}
+
+unsigned char pnd_determine_mountpoint ( char *fullpath, char *r_mountpoint, unsigned char mountpoint_len ) {
+
+ // just cheap it, and call df like an idiot.
+
+ // Filesystem 1K-blocks Used Available Use% Mounted on
+
+ char cmd [ PATH_MAX ];
+ FILE *p;
+ char inbuf [ PATH_MAX ];
+
+ sprintf ( cmd, "/bin/df %s 2>/dev/null", fullpath );
+
+ if ( ( p = popen ( cmd, "r" ) ) ) {
+
+ // ignore title line; we really shoudl analyze it to figure out which column, but we make assumptions..
+ fgets ( inbuf, PATH_MAX, p );
+
+ if ( ! fgets ( inbuf, PATH_MAX, p ) ) {
+ pclose ( p );
+ return ( 0 );
+ }
+
+ pclose ( p );
+
+ // by now, good
+ char crap [ PATH_MAX ];
+ char mount [ PATH_MAX ];
+ if ( sscanf ( inbuf, "%s %s %s %s %s %s", crap, crap, crap, crap, crap, mount ) != 6 ) {
+ return ( 0 );
+ }
+
+ if ( strlen ( mount ) < mountpoint_len ) {
+ strcpy ( r_mountpoint, mount );
+ return ( 1 );
+ }
+
+ } // if popen
+
+ return ( 0 );
+
+#if 0
+ struct stat fooby;
+
+ // can we even stat this file?
+ if ( stat ( fullpath, &fooby ) == 0 ) {
+ //dev_t st_dev; /* ID of device containing file */
+ //dev_t st_rdev; /* device ID (if special file) */
+
+ dev_t mount = fooby.st_dev;
+
+ DIR *d = opendir ( "/dev" );
+
+ if ( d ) {
+ struct dirent *de;
+ char path [ FILENAME_MAX ];
+
+ while ( de = readdir ( d ) ) {
+ sprintf ( path, "/dev/%s", de -> d_name );
+
+ if ( stat ( path, &fooby ) == 0 ) {
+
+ // finally, if we find the same major/minor pair in /dev, as we found for the target file, it means we found the right device
+ if ( fooby.st_rdev == mount ) {
+ printf ( "Device: %s\n", path );
+ }
+
+ } // if
+
+ } // while
+
+ } // opened /dev?
+
+ } // stat
+#endif
+
+ return ( 0 );
+}
if ( d -> preview_pic2 ) {
printf ( " Preview Pic 2: %s\n", d -> preview_pic2 );
}
+ if ( d -> mkdir_sp ) {
+ printf ( " mkdir requests: %s\n", d -> mkdir_sp );
+ }
if ( do_icon ) {
if ( pnd_emit_icon ( "./testdata/dotdesktop", d ) ) {
<author name="EvilDragon" website="http://www.openpandora.org"/><!--Optional email and website, name required-->
+ <mkdir>
+ <dir path="common/mydir1"/>
+ <dir path="common/mydir2"/>
+ </mkdir>
+
<version major="1" minor="1" release="1" build="2"/><!--This program's version-->
<osversion major="1" minor="0" release="0" build="0"/><!--The minimum OS version required-->