From e86a4076b453f6c3410ae312821623bdb720e99f Mon Sep 17 00:00:00 2001 From: skeezix Date: Thu, 12 Jan 2012 16:53:22 -0500 Subject: [PATCH] Preliminary stab at app scan locking; pndnotifyd creates logfile /tmp/whatever and minimenu watches out for it 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 --- apps/pndnotifyd.c | 12 +++++ deployment/etc/pandora/conf/mmenu.conf | 3 ++ include/pnd_utility.h | 13 +++++ lib/pnd_utility.c | 70 ++++++++++++++++++++++++++ minimenu/mmenu.c | 32 ++++++++++++ minimenu/mmenu.conf | 3 ++ 6 files changed, 133 insertions(+) diff --git a/apps/pndnotifyd.c b/apps/pndnotifyd.c index fd1c1a1..b8ce530 100644 --- a/apps/pndnotifyd.c +++ b/apps/pndnotifyd.c @@ -73,6 +73,7 @@ unsigned char g_info_p = 0; // spit out info .desktops // constants #define PNDNOTIFYD_LOGLEVEL "pndnotifyd.loglevel" +#define PNDLOCKNAME "pndnotifyd-disco.lock" // decl's void consume_configuration ( void ); @@ -815,6 +816,13 @@ unsigned char perform_discoveries ( char *appspath, char *overridespath, 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 ); @@ -907,5 +915,9 @@ unsigned char perform_discoveries ( char *appspath, char *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 ); } diff --git a/deployment/etc/pandora/conf/mmenu.conf b/deployment/etc/pandora/conf/mmenu.conf index 496dac3..69e2e57 100644 --- a/deployment/etc/pandora/conf/mmenu.conf +++ b/deployment/etc/pandora/conf/mmenu.conf @@ -32,6 +32,9 @@ desktop_apps 1 # search the pnd standard desktop searchpath for apps 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 diff --git a/include/pnd_utility.h b/include/pnd_utility.h index e468258..09ea621 100644 --- a/include/pnd_utility.h +++ b/include/pnd_utility.h @@ -6,6 +6,8 @@ extern "C" { #endif +#include + // 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!) @@ -30,6 +32,17 @@ unsigned char pnd_determine_mountpoint ( char *fullpath, char *r_mountpoint, uns // 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 diff --git a/lib/pnd_utility.c b/lib/pnd_utility.c index 9647f20..de2a2b7 100644 --- a/lib/pnd_utility.c +++ b/lib/pnd_utility.c @@ -9,7 +9,9 @@ #include /* ditto */ #include /* ditto */ #include /* for fstat */ +#include /* for stat->ENOENT */ #include /* for opendir */ +#include /* for creat */ #include "pnd_pxml.h" #include "pnd_container.h" @@ -361,3 +363,71 @@ unsigned char pnd_filecopy ( char *sourcepath, char *targetpath ) { 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 ); +} diff --git a/minimenu/mmenu.c b/minimenu/mmenu.c index 78b3683..919b509 100644 --- a/minimenu/mmenu.c +++ b/minimenu/mmenu.c @@ -37,6 +37,7 @@ #include #include #include // for sigaction +#include #include "pnd_logger.h" #include "pnd_pxml.h" @@ -61,6 +62,8 @@ #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 @@ -597,6 +600,35 @@ void applications_scan ( void ) { // 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" ), diff --git a/minimenu/mmenu.conf b/minimenu/mmenu.conf index 70cb134..fb642e4 100644 --- a/minimenu/mmenu.conf +++ b/minimenu/mmenu.conf @@ -32,6 +32,9 @@ desktop_apps 1 # search the pnd standard desktop searchpath for apps 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 -- 2.39.2