mmenu will ignore 'old' lockfile (2 minutes or more), and for recent lockfile (<2mins) it will check every half second
for up to 20 times (10 seconds)
mmenu is configured in mmenu.conf so these settings can be fiddled with
// constants
#define PNDNOTIFYD_LOGLEVEL "pndnotifyd.loglevel"
+#define PNDLOCKNAME "pndnotifyd-disco.lock"
// decl's
void consume_configuration ( void );
pnd_log ( pndn_rem, "perform discovery - apps: %s, overrides: %s\n", appspath, overridespath );
pnd_log ( pndn_rem, " - emit desktop: %s, icons: %s\n", emitdesktoppath, emiticonpath );
+ // do some 'locking'
+ pnd_log ( pndn_rem, "creating lockfile %s", PNDLOCKNAME );
+
+ if ( ! pnd_lock ( PNDLOCKNAME ) ) {
+ // problem .. well, too bad, we need to do this .. proceed!
+ }
+
// attempt to auto-discover applications in the given path
applist = pnd_disco_search ( appspath, overridespath );
pnd_box_delete ( applist ); // does not free the disco_t contents!
}
+ // close the lock
+ pnd_log ( pndn_rem, "clearing lockfile %s", PNDLOCKNAME );
+ pnd_unlock ( PNDLOCKNAME );
+
return ( 1 );
}
menu_apps 1 # search the pnd standard menu searchpath for apps
aux_searchpath /media/*/pandora/mmenu:/usr/pandora/mmenu # if something here, also search this path; can be used for mmenu-only apps?
auto_rescan 1 # if >0, will automaticly rescan for applications, if SD inserts/ejects
+disco_lock_max 20 # number of tries to check lock (at 1/5th sec each, 20 == 4 seconds)
+disco_lock_usec_delta 500000 # number of usec between lockfile checks; 200000 is 1/5th second
+disco_lock_maxage_s 120 # number of seconds .. if lockfile is that old or older, just ignore it entirely
[utility]
terminal /usr/bin/Terminal # could also be /usr/bin/xterm, or a sh-script, or whatever
extern "C" {
#endif
+#include <time.h>
+
// expand_tilde() will only function correctly if a user is actually logged in; perhaps you
// want to spin until it looks like someone has in fact done so. (most devices will likely
// have auto-login, but its not instantaneous!)
// filecopy will return >0 on success
unsigned char pnd_filecopy ( char *sourcepath, char *targetpath );
+// some lame file locking utility (not using 'flock')
+// ** This is not race condition safe, so not for serious locking; this is just for casual locking, not high speed
+#define PND_LOCK_PATH "/tmp" /* default path to stick lockfiles */
+unsigned char pnd_lock ( char *lockname ); // return 0 on fail, >0 on success; lock file, not semaphore/etc
+time_t pnd_is_locked ( char *lockname ); // return 0 on unlocked, >0 is epoch time when locked
+void pnd_unlock ( char *lockname ); // assumes success
+// wait 'max' occurances of microseconds (usleep) for unlock
+// if max is 0, will not wait at all (will just check, same as pnd_is_locked())
+// return '1' for unlock (may be immediate), 0 for failed 'max' timse
+unsigned char pnd_wait_for_unlock ( char *lockname, unsigned short int max, unsigned int usec_delta );
+
#ifdef __cplusplus
} /* "C" */
#endif
#include <sys/types.h> /* ditto */
#include <pwd.h> /* ditto */
#include <sys/stat.h> /* for fstat */
+#include <errno.h> /* for stat->ENOENT */
#include <dirent.h> /* for opendir */
+#include <fcntl.h> /* for creat */
#include "pnd_pxml.h"
#include "pnd_container.h"
return ( 1 );
}
+
+unsigned char pnd_lock ( char *lockname ) {
+
+ if ( pnd_is_locked ( lockname ) ) {
+ return ( 0 ); // already locked
+ }
+
+ char fullpath [ PATH_MAX ];
+ int fd;
+
+ snprintf ( fullpath, PATH_MAX, "%s/%s", PND_LOCK_PATH, lockname );
+
+ if ( ( fd = creat ( fullpath, 0400 ) < 0 ) ) {
+ return ( 0 ); // error, yeah, I know, no way to know why it failed..
+ }
+
+ close ( fd );
+
+ return ( 1 );
+}
+
+time_t pnd_is_locked ( char *lockname ) {
+ char fullpath [ PATH_MAX ];
+ int rv;
+ snprintf ( fullpath, PATH_MAX, "%s/%s", PND_LOCK_PATH, lockname );
+
+ struct stat statbuf;
+ rv = stat ( fullpath, &statbuf );
+
+ if ( rv == ENOENT ) {
+ return ( 0 ); // file not existk, so no lock
+ } else if ( rv < 0 ) {
+ return ( 0 ); // assume unlocked for error, so app can continue?
+ }
+
+ return ( statbuf.st_mtime );
+}
+
+void pnd_unlock ( char *lockname ) {
+ char fullpath [ PATH_MAX ];
+ snprintf ( fullpath, PATH_MAX, "%s/%s", PND_LOCK_PATH, lockname );
+
+ unlink ( fullpath );
+
+ return;
+}
+
+unsigned char pnd_wait_for_unlock ( char *lockname, unsigned short int max, unsigned int usec_delta ) {
+
+ // check right off the top
+ if ( ! pnd_is_locked ( lockname ) ) {
+ return ( 1 ); // all clear!
+ }
+
+ unsigned short int count = 0;
+ while ( count < max ) {
+
+ if ( ! pnd_is_locked ( lockname ) ) {
+ return ( 1 ); // all clear!
+ }
+
+ usleep ( usec_delta );
+
+ count++;
+ }
+
+ return ( 0 );
+}
#include <sys/wait.h>
#include <dirent.h>
#include <signal.h> // for sigaction
+#include <time.h>
#include "pnd_logger.h"
#include "pnd_pxml.h"
#include "mmui.h"
#include "mmconf.h"
+#define PNDLOCKNAME "pndnotifyd-disco.lock" /* from pndnotifyd */
+
pnd_box_handle g_active_apps = NULL;
unsigned int g_active_appcount = 0;
char g_username [ 128 ]; // since we have to wait for login (!!), store username here
// perform app discovery on .desktop files?
//
if ( pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_dotdesktop", 0 ) ) {
+
+ // deal with locks
+ pnd_log ( pndn_debug, "Checking pndnotifyd disco lock %s\n", PNDLOCKNAME );
+
+ // first, check if lock is 'old' -- maybe locker crashed, or if its old enough.. its just good, right?
+ time_t age = pnd_is_locked ( PNDLOCKNAME );
+
+ if ( age == 0 ) {
+ pnd_log ( pndn_debug, "Lock is all clear %s so no need to wait\n", PNDLOCKNAME );
+
+ } else if ( time ( NULL ) - age > pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_lock_maxage_s", 120 ) ) {
+ // lock seems old, so who cares
+ pnd_log ( pndn_debug, "Lock is OLD so ignoring it: %s\n", PNDLOCKNAME );
+
+ } else {
+ // not too old, so lets wait.. we could be booting up!
+
+ int rv = pnd_wait_for_unlock ( PNDLOCKNAME,
+ pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_lock_max", 20 ),
+ pnd_conf_get_as_int_d ( g_conf, "minimenu.disco_lock_usec_delta", 500000 ) );
+ if ( rv ) {
+ pnd_log ( pndn_debug, "Waited for lock and is now clear %s\n", PNDLOCKNAME );
+ } else {
+ pnd_log ( pndn_debug, "Waited for lock and timed out %s .. proceeding anyway.\n", PNDLOCKNAME );
+ }
+
+ } // locking
+
+ // where to scan..
char *chunks[10] = {
pnd_conf_get_as_char ( g_desktopconf, "desktop.dotdesktoppath" ),
pnd_conf_get_as_char ( g_desktopconf, "menu.dotdesktoppath" ),
menu_apps 1 # search the pnd standard menu searchpath for apps
aux_searchpath /media/*/pandora/mmenu # if something here, also search this path; can be used for mmenu-only apps?
auto_rescan 1 # if >0, will automaticly rescan for applications, if SD inserts/ejects
+disco_lock_max 20 # number of tries to check lock (at 1/5th sec each, 20 == 4 seconds)
+disco_lock_usec_delta 500000 # number of usec between lockfile checks; 200000 is 1/5th second
+disco_lock_maxage_s 120 # number of seconds .. if lockfile is that old or older, just ignore it entirely
[utility]
terminal /usr/bin/Terminal # could also be /usr/bin/xterm, or a sh-script, or whatever