Hello community, here is the log from the commit of package menu-cache for openSUSE:Factory checked in at 2017-09-13 22:38:11 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/menu-cache (Old) and /work/SRC/openSUSE:Factory/.menu-cache.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "menu-cache" Wed Sep 13 22:38:11 2017 rev:29 rq:525865 version:1.0.2 Changes: -------- --- /work/SRC/openSUSE:Factory/menu-cache/menu-cache.changes 2017-01-12 15:55:56.498600930 +0100 +++ /work/SRC/openSUSE:Factory/.menu-cache.new/menu-cache.changes 2017-09-13 22:38:30.722535795 +0200 @@ -1,0 +2,8 @@ +Wed Sep 13 12:57:27 UTC 2017 - [email protected] + +- boo#boo#1044483: + - Add menu-cache-1.0.2-until-fd52af6.patch + We need a6763eb which tests for multiple daemons. + Other fixes are also important/related/good-to-have + +------------------------------------------------------------------- New: ---- menu-cache-1.0.2-until-fd52af6.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ menu-cache.spec ++++++ --- /var/tmp/diff_new_pack.keepb7/_old 2017-09-13 22:38:31.246462028 +0200 +++ /var/tmp/diff_new_pack.keepb7/_new 2017-09-13 22:38:31.250461465 +0200 @@ -24,6 +24,7 @@ Group: System/GUI/LXDE Url: http://www.lxde.org Source0: %{name}-%{version}.tar.xz +Patch0: menu-cache-1.0.2-until-fd52af6.patch BuildRequires: fdupes BuildRequires: gtk-doc BuildRequires: gtk2-devel @@ -57,6 +58,7 @@ %prep %setup -q +%patch0 -p1 %build export CFLAGS="%{optflags}" ++++++ menu-cache-1.0.2-until-fd52af6.patch ++++++ diff --git a/NEWS b/NEWS index dcc572a..0de60f8 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,26 @@ +* Fixed crash with invalid <Name> tag in a menu. + +* Added new API menu_cache_app_get_generic_name() to get generic + name for application. + +* Fixed potential access violation, use runtime user dir instead of tmp dir. + It limits libmenu-cache compatibility to menu-cached >= 0.7.0. + +* Directory $XDG_DATA_HOME/applications will be created if it does not + exist so it will be monitored in any case. + +* Fixed issue when subdirectories added would be skipped in monitoring. + +* Fixed potential file descriptors leak. + +* Reduced inactivity timer to 6 seconds (from 600 seconds). + +* Fixed an issue with multiple daemons started: test if daemon is already + running on socket before killing old socket file. + +* Fixed 100% CPU load by menu-cached due to invalid dup2() call. + + Changes in 1.0.2 since 1.0.1: * Fixed crash in menu-cached if cache regeneration fails. diff --git a/libmenu-cache/menu-cache.c b/libmenu-cache/menu-cache.c index 3bc9cfc..5025d72 100644 --- a/libmenu-cache/menu-cache.c +++ b/libmenu-cache/menu-cache.c @@ -3,7 +3,7 @@ * * Copyright 2008 PCMan <[email protected]> * Copyright 2009 Jürgen Hötzel <[email protected]> - * Copyright 2012-2015 Andriy Grytsenko (LStranger) <[email protected]> + * Copyright 2012-2017 Andriy Grytsenko (LStranger) <[email protected]> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -1233,6 +1233,22 @@ gboolean menu_cache_dir_is_visible(MenuCacheDir *dir) return ((dir->flags & FLAG_IS_NODISPLAY) == 0); } +/** + * menu_cache_app_get_generic_name + * @app: a menu cache item + * + * Retrieves generic name for @app. Returned data are owned by menu + * cache and should not be freed by caller. + * + * Returns: (transfer none): app's generic name or %NULL. + * + * Since: 1.0.3 + */ +const char* menu_cache_app_get_generic_name( MenuCacheApp* app ) +{ + return app->generic_name; +} + /** * menu_cache_app_get_exec * @app: a menu cache item @@ -1522,8 +1538,13 @@ static void get_socket_name( char* buf, int len ) if(*p) *p = '\0'; } +#if GLIB_CHECK_VERSION(2, 28, 0) + g_snprintf( buf, len, "%s/menu-cached-%s", g_get_user_runtime_dir(), + dpy ? dpy : ":0" ); +#else g_snprintf( buf, len, "%s/.menu-cached-%s-%s", g_get_tmp_dir(), dpy ? dpy : ":0", g_get_user_name() ); +#endif g_free(dpy); } @@ -1698,6 +1719,9 @@ retry: G_UNLOCK(connect); return FALSE; } + + fcntl (fd, F_SETFD, FD_CLOEXEC); + memset(&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; diff --git a/libmenu-cache/menu-cache.h.in b/libmenu-cache/menu-cache.h.in index 76ea7b4..cded59d 100644 --- a/libmenu-cache/menu-cache.h.in +++ b/libmenu-cache/menu-cache.h.in @@ -151,6 +151,7 @@ MenuCacheItem *menu_cache_find_child_by_name(MenuCacheDir *dir, const char *name char* menu_cache_dir_make_path( MenuCacheDir* dir ); +const char* menu_cache_app_get_generic_name( MenuCacheApp* app ); const char* menu_cache_app_get_exec( MenuCacheApp* app ); const char* menu_cache_app_get_working_dir( MenuCacheApp* app ); const char* const *menu_cache_app_get_categories(MenuCacheApp* app); diff --git a/menu-cache-daemon/menu-cached.c b/menu-cache-daemon/menu-cached.c index a6895ee..bda766a 100644 --- a/menu-cache-daemon/menu-cached.c +++ b/menu-cache-daemon/menu-cached.c @@ -3,7 +3,7 @@ * * Copyright 2008 - 2010 PCMan <[email protected]> * Copyright 2009 Jürgen Hötzel <[email protected]> - * Copyright 2012-2015 Andriy Grytsenko (LStranger) <[email protected]> + * Copyright 2012-2017 Andriy Grytsenko (LStranger) <[email protected]> * Copyright 2016 Mamoru TASAKA <[email protected]> * * This file is a part of libmenu-cache package and created program @@ -34,6 +34,7 @@ #include <stdio.h> #include <stdlib.h> #include <glib.h> +#include <glib/gstdio.h> #include <gio/gio.h> #include <sys/types.h> #include <sys/socket.h> @@ -131,12 +132,12 @@ static gboolean delayed_cache_free(gpointer data) static void cache_free(Cache* cache) { - /* shutdown cache in 10 minutes of inactivity */ + /* shutdown cache in 6 seconds of inactivity */ if(!cache->delayed_free_handler) - cache->delayed_free_handler = g_timeout_add_seconds(600, + cache->delayed_free_handler = g_timeout_add_seconds(6, delayed_cache_free, cache); - DEBUG("menu %p cache unused, removing in 600s", cache); + DEBUG("menu %p cache unused, removing in 6s", cache); } static gboolean read_all_used_files( FILE* f, int* n_files, char*** used_files ) @@ -221,6 +222,7 @@ static gboolean regenerate_cache( const char* menu_name, FILE* f; int n_files, status = 0; char** files; + const char *user_data_dir = env[5]; const char* argv[] = { MENUCACHE_LIBEXECDIR "/menu-cache-gen", "-l", NULL, @@ -233,6 +235,18 @@ static gboolean regenerate_cache( const char* menu_name, /* DEBUG("cmd: %s", g_strjoinv(" ", argv)); */ + /* create $XDG_DATA_HOME/applications if it does not exist yet */ + if (!user_data_dir || !user_data_dir[0]) + user_data_dir = g_get_user_data_dir(); + if (g_file_test(user_data_dir, G_FILE_TEST_IS_DIR) || + g_mkdir(user_data_dir, 0700) == 0) + { + char *local_app_path = g_build_filename(user_data_dir, "applications", NULL); + if (!g_file_test(local_app_path, G_FILE_TEST_IS_DIR)) + g_mkdir(local_app_path, 0700); + g_free(local_app_path); + } + /* run menu-cache-gen */ /* FIXME: is cast to (char**) valid here? */ if( !g_spawn_sync(NULL, (char **)argv, NULL, 0, @@ -376,25 +390,39 @@ void on_file_changed( GFileMonitor* mon, GFile* gf, GFile* other, if( G_LIKELY(idx < cache->n_files) && cache->files[idx][0] == 'D' ) { char* changed_file = g_file_get_path(gf); - char* dir_path = cache->files[idx]+1; - int len = strlen(dir_path); - /* if the changed file is a file in the monitored dir */ - if( strncmp(changed_file, dir_path, len) == 0 && changed_file[len] == '/' ) + /* Regenerate the cache if the changed file is a directory. + * + * The file monitor isn't recursive, so imagine we add a + * subdirectory to /usr/share/applications, and subsequently + * add a desktop entry to that. If we ignore the new + * subdirectory, we won't notice when the desktop entry is + * added. By regenerating the cache, the subdirectory will + * be mentioned there, picked up by read_all_used_files(), + * and monitored for subsequent changes. + */ + if (!g_file_test(changed_file, G_FILE_TEST_IS_DIR)) { - char* base_name = changed_file + len + 1; - gboolean skip = TRUE; - /* only *.desktop and *.directory files can affect the content of the menu. */ - if( g_str_has_suffix(base_name, ".desktop") ) + char* dir_path = cache->files[idx]+1; + int len = strlen(dir_path); + /* if the changed file is a file in the monitored dir */ + if( strncmp(changed_file, dir_path, len) == 0 && changed_file[len] == '/' ) { + char* base_name = changed_file + len + 1; + gboolean skip = TRUE; + /* only *.desktop and *.directory files can affect the content of the menu. */ + if( g_str_has_suffix(base_name, ".desktop") ) + { + skip = FALSE; + } + else if( g_str_has_suffix(base_name, ".directory") ) skip = FALSE; - } - else if( g_str_has_suffix(base_name, ".directory") ) - skip = FALSE; - if( skip ) - { - DEBUG("files are changed, but no re-generation is needed."); - return; + if( skip ) + { + DEBUG("files are changed, but no re-generation is needed."); + g_free(changed_file); + return; + } } } g_free(changed_file); @@ -473,21 +501,33 @@ static void get_socket_name( char* buf, int len ) if(*p) *p = '\0'; } + /* NOTE: this socket name is incompatible with versions > 1.0.2, + although this function is never used since 0.7.0 but + libmenu-cache always requests exact socket name instead */ g_snprintf( buf, len, "%s/.menu-cached-%s-%s", g_get_tmp_dir(), dpy ? dpy : ":0", g_get_user_name() ); g_free(dpy); } -static int create_socket(struct sockaddr_un *addr) +static gboolean socket_is_alive(struct sockaddr_un *addr) { - int fd = -1; + int fd = socket(PF_UNIX, SOCK_STREAM, 0); + socklen_t len = sizeof(sa_family_t) + strlen(addr->sun_path) + 1; - fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { DEBUG("Failed to create socket"); - return -1; + /* still return TRUE to drop attempt */ + return TRUE; + } + if (connect(fd, (struct sockaddr*)addr, len) >= 0) + { + /* there is a listener on the socket */ + close(fd); + DEBUG("Another menu-cached seems to reside on the socket"); + return TRUE; } + close(fd); /* remove previous socket file */ if (unlink(addr->sun_path) < 0) { @@ -497,19 +537,57 @@ static int create_socket(struct sockaddr_un *addr) /* remove of previous socket file successful */ else g_warning("removed previous socket file %s", addr->sun_path); + return FALSE; +} + +static int create_socket(struct sockaddr_un *addr) +{ + int fd = -1; + char *lockfile; - if(bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) + lockfile = g_strconcat(addr->sun_path, ".lock", NULL); + fd = open(lockfile, O_CREAT | O_EXCL | O_WRONLY, 0700); + if (fd < 0) + { + DEBUG("Cannot create lock file %s: %s", lockfile, strerror(errno)); + g_free(lockfile); + return -1; + } + close(fd); + + fd = socket(PF_UNIX, SOCK_STREAM, 0); + if (fd < 0) + { + DEBUG("Failed to create socket"); + } + + /* remove previous socket file */ + else if (g_file_test(addr->sun_path, G_FILE_TEST_EXISTS) && + socket_is_alive(addr)) + { + close(fd); + fd = -1; + } + + else if(bind(fd, (struct sockaddr *)addr, sizeof(*addr)) < 0) { DEBUG("Failed to bind to socket"); close(fd); - return -1; + fd = -1; } - if(listen(fd, 30) < 0) + + else if(listen(fd, 30) < 0) { DEBUG( "Failed to listen to socket" ); close(fd); - return -1; + fd = -1; } + + else + fcntl(fd, F_SETFD, FD_CLOEXEC); + + unlink(lockfile); + g_free(lockfile); return fd; } @@ -717,6 +795,14 @@ retry: return ret; } +static void terminate(int sig) +{ +/* #ifndef HAVE_ABSTRACT_SOCKETS */ + unlink(socket_file); + exit(0); +/* #endif */ +} + static gboolean on_new_conn_incoming(GIOChannel* ch, GIOCondition cond, gpointer user_data) { int server, client; @@ -732,9 +818,16 @@ static gboolean on_new_conn_incoming(GIOChannel* ch, GIOCondition cond, gpointer if( client == -1 ) { DEBUG("accept error"); - return TRUE; + if (errno == ECONNABORTED) + /* client failed, just continue */ + return TRUE; + /* else it's socket error, terminate server */ + terminate(SIGTERM); + return FALSE; } + fcntl (client, F_SETFD, FD_CLOEXEC); + child = g_io_channel_unix_new(client); g_io_channel_set_close_on_unref( child, TRUE ); @@ -749,14 +842,6 @@ static gboolean on_new_conn_incoming(GIOChannel* ch, GIOCondition cond, gpointer return TRUE; } -static void terminate(int sig) -{ -/* #ifndef HAVE_ABSTRACT_SOCKETS */ - unlink(socket_file); - exit(0); -/* #endif */ -} - static gboolean on_server_conn_close(GIOChannel* ch, GIOCondition cond, gpointer user_data) { /* FIXME: is this possible? */ @@ -771,7 +856,7 @@ int main(int argc, char** argv) int server_fd; struct sockaddr_un addr; #ifndef DISABLE_DAEMONIZE - int fd, pid; + pid_t pid; long open_max; long i; @@ -815,28 +900,18 @@ int main(int argc, char** argv) g_error("can't change directory to /"); } + /* don't hold open fd opened besides server socket and std{in,out,err} */ open_max = sysconf (_SC_OPEN_MAX); - for (i = 0; i < open_max; i++) + for (i = 3; i < open_max; i++) { - /* don't hold open fd opened besides server socket */ if (i != server_fd) - fcntl (i, F_SETFD, FD_CLOEXEC); + close (i); } /* /dev/null for stdin, stdout, stderr */ - fd = open ("/dev/null", O_RDONLY); - if (fd != -1) - { - dup2 (fd, 0); - close (fd); - } - fd = open ("/dev/null", O_WRONLY); - if (fd != -1) - { - dup2 (fd, 1); - dup2 (fd, 2); - close (fd); - } + if (freopen("/dev/null", "r", stdin)) i = i; + if (freopen("/dev/null", "w", stdout)) i = i; + if (freopen("/dev/null", "w", stderr)) i = i; #endif signal(SIGHUP, terminate); diff --git a/menu-cache-gen/menu-merge.c b/menu-cache-gen/menu-merge.c index 816cf96..31f05b0 100644 --- a/menu-cache-gen/menu-merge.c +++ b/menu-cache-gen/menu-merge.c @@ -1,7 +1,7 @@ /* * menu-file.c : parses <name>.menu file and merges all XML tags. * - * Copyright 2013-2016 Andriy Grytsenko (LStranger) <[email protected]> + * Copyright 2013-2017 Andriy Grytsenko (LStranger) <[email protected]> * * This file is a part of libmenu-cache package and created program * should be not used without the library. @@ -138,11 +138,13 @@ static gboolean _menu_xml_handler_Name(FmXmlFileItem *item, GList *children, guint n_attributes, gint line, gint pos, GError **error, gpointer user_data) { + FmXmlFileItem *name_item; const char *name; RETURN_IF_IN_LAYOUT(item, error); - item = fm_xml_file_item_find_child(item, FM_XML_FILE_TEXT); - if (item == NULL || (name = fm_xml_file_item_get_data(item, NULL)) == NULL || + name_item = fm_xml_file_item_find_child(item, FM_XML_FILE_TEXT); + if (name_item == NULL || + (name = fm_xml_file_item_get_data(name_item, NULL)) == NULL || strchr(name, '/') != NULL) /* empty or invalid tag */ { RETURN_TRUE_AND_DESTROY_IF_QUIET(item);
