[PATCH v4 03/18] inotify: Move inotify code into its own file

Daniel Wagner wagi at monom.org
Wed Nov 14 08:26:02 PST 2012


From: Daniel Wagner <daniel.wagner at bmw-carit.de>

The inotify code will be used by the core (config.c) and the session
policy plugin. We introduce a new API for file modifcation
notifcation.

We move the factored out code part from the last patch into a new file
and also change the inotify code so that it allows to monitor not only
STORAGEDIR. When registering a new observer, the callee has to tell
which directory should be watched. inotify.c will group the observers
together.
---
 Makefile.am       |   4 +-
 include/inotify.h |  37 +++++++++
 src/config.c      | 122 +---------------------------
 src/connman.h     |   5 ++
 src/inotify.c     | 236 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/main.c        |   2 +
 6 files changed, 284 insertions(+), 122 deletions(-)
 create mode 100644 include/inotify.h
 create mode 100644 src/inotify.c

diff --git a/Makefile.am b/Makefile.am
index b845d6e..4cb6ad2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -8,7 +8,7 @@ include_HEADERS = include/types.h include/log.h include/plugin.h \
 			include/resolver.h include/ipconfig.h \
 			include/device.h include/network.h include/inet.h \
 			include/storage.h include/provision.h \
-			include/session.h
+			include/session.h include/inotify.h
 
 nodist_include_HEADERS = include/version.h
 
@@ -85,7 +85,7 @@ src_connmand_SOURCES = $(gdbus_sources) $(gdhcp_sources) $(gweb_sources) \
 			src/technology.c src/counter.c src/ntp.c \
 			src/session.c src/tethering.c src/wpad.c src/wispr.c \
 			src/stats.c src/iptables.c src/dnsproxy.c src/6to4.c \
-			src/ippool.c src/bridge.c src/nat.c
+			src/ippool.c src/bridge.c src/nat.c src/inotify.c
 
 src_connmand_LDADD = $(builtin_libadd) @GLIB_LIBS@ @DBUS_LIBS@ \
 				@XTABLES_LIBS@ @GNUTLS_LIBS@ -lresolv -ldl -lrt
diff --git a/include/inotify.h b/include/inotify.h
new file mode 100644
index 0000000..1f642ab
--- /dev/null
+++ b/include/inotify.h
@@ -0,0 +1,37 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 2012  BMW Car IT GmbH. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __CONNMAN_INOTIFY_H
+#define __CONNMAN_INOTIFY_H
+
+struct inotify_event;
+
+typedef void (* inotify_event_cb) (struct inotify_event *event,
+					const char *ident);
+
+int connman_inotify_register(const char *path, inotify_event_cb callback);
+void connman_inotify_unregister(const char *path, inotify_event_cb callback);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CONNMAN_INOTIFY_H */
diff --git a/src/config.c b/src/config.c
index 16fed8d..6a5b12c 100644
--- a/src/config.c
+++ b/src/config.c
@@ -66,10 +66,6 @@ struct connman_config {
 static GHashTable *config_table = NULL;
 static GSList *protected_services = NULL;
 
-static int inotify_wd = -1;
-
-static GIOChannel *inotify_channel = NULL;
-static uint inotify_watch = 0;
 static connman_bool_t cleanup = FALSE;
 
 #define INTERNAL_CONFIG_PREFIX           "__internal"
@@ -613,120 +609,6 @@ static void config_notify_handler(struct inotify_event *event,
 		g_hash_table_remove(config_table, ident);
 }
 
-static gboolean inotify_data(GIOChannel *channel, GIOCondition cond,
-							gpointer user_data)
-{
-	char buffer[256];
-	char *next_event;
-	gsize bytes_read;
-	GIOStatus status;
-
-	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
-		inotify_watch = 0;
-		return FALSE;
-	}
-
-	status = g_io_channel_read_chars(channel, buffer,
-					sizeof(buffer) -1, &bytes_read, NULL);
-
-	switch (status) {
-	case G_IO_STATUS_NORMAL:
-		break;
-	case G_IO_STATUS_AGAIN:
-		return TRUE;
-	default:
-		connman_error("Reading from inotify channel failed");
-		inotify_watch = 0;
-		return FALSE;
-	}
-
-	next_event = buffer;
-
-	while (bytes_read > 0) {
-		struct inotify_event *event;
-		gchar *ident;
-		gsize len;
-
-		event = (struct inotify_event *) next_event;
-		if (event->len)
-			ident = next_event + sizeof(struct inotify_event);
-		else
-			ident = NULL;
-
-		len = sizeof(struct inotify_event) + event->len;
-
-		/* check if inotify_event block fit */
-		if (len > bytes_read)
-			break;
-
-		next_event += len;
-		bytes_read -= len;
-
-		config_notify_handler(event, ident);
-	}
-
-	return TRUE;
-}
-
-static int create_watch(void)
-{
-	int fd;
-
-	fd = inotify_init();
-	if (fd < 0)
-		return -EIO;
-
-	inotify_wd = inotify_add_watch(fd, STORAGEDIR,
-					IN_MODIFY | IN_CREATE | IN_DELETE);
-	if (inotify_wd < 0) {
-		connman_error("Creation of STORAGEDIR  watch failed");
-		close(fd);
-		return -EIO;
-	}
-
-	inotify_channel = g_io_channel_unix_new(fd);
-	if (inotify_channel == NULL) {
-		connman_error("Creation of inotify channel failed");
-		inotify_rm_watch(fd, inotify_wd);
-		inotify_wd = 0;
-
-		close(fd);
-		return -EIO;
-	}
-
-	g_io_channel_set_close_on_unref(inotify_channel, TRUE);
-	g_io_channel_set_encoding(inotify_channel, NULL, NULL);
-	g_io_channel_set_buffered(inotify_channel, FALSE);
-
-	inotify_watch = g_io_add_watch(inotify_channel,
-				G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
-				inotify_data, NULL);
-
-	return 0;
-}
-
-static void remove_watch(void)
-{
-	int fd;
-
-	if (inotify_channel == NULL)
-		return;
-
-	if (inotify_watch > 0) {
-		g_source_remove(inotify_watch);
-		inotify_watch = 0;
-	}
-
-	fd = g_io_channel_unix_get_fd(inotify_channel);
-
-	if (inotify_wd >= 0) {
-		inotify_rm_watch(fd, inotify_wd);
-		inotify_wd = 0;
-	}
-
-	g_io_channel_unref(inotify_channel);
-}
-
 int __connman_config_init(void)
 {
 	DBG("");
@@ -734,7 +616,7 @@ int __connman_config_init(void)
 	config_table = g_hash_table_new_full(g_str_hash, g_str_equal,
 						NULL, unregister_config);
 
-	create_watch();
+	connman_inotify_register(STORAGEDIR, config_notify_handler);
 
 	return read_configs();
 }
@@ -745,7 +627,7 @@ void __connman_config_cleanup(void)
 
 	cleanup = TRUE;
 
-	remove_watch();
+	connman_inotify_unregister(STORAGEDIR, config_notify_handler);
 
 	g_hash_table_destroy(config_table);
 	config_table = NULL;
diff --git a/src/connman.h b/src/connman.h
index 2472dab..3bdeb38 100644
--- a/src/connman.h
+++ b/src/connman.h
@@ -226,6 +226,11 @@ gboolean __connman_storage_remove_service(const char *service_id);
 int __connman_detect_init(void);
 void __connman_detect_cleanup(void);
 
+#include <connman/inotify.h>
+
+int __connman_inotify_init(void);
+void __connman_inotify_cleanup(void);
+
 #include <connman/proxy.h>
 
 int __connman_proxy_init(void);
diff --git a/src/inotify.c b/src/inotify.c
new file mode 100644
index 0000000..6646f5e
--- /dev/null
+++ b/src/inotify.c
@@ -0,0 +1,236 @@
+/*
+ *
+ *  Connection Manager
+ *
+ *  Copyright (C) 2007-2012  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2012  BMW Car IT GmbH. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <sys/inotify.h>
+
+#include <connman/storage.h>
+
+#include "connman.h"
+
+struct connman_inotify {
+	GIOChannel *channel;
+	uint watch;
+	int wd;
+
+	GSList *list;
+};
+
+static GHashTable *inotify_hash;
+
+static gboolean inotify_data(GIOChannel *channel, GIOCondition cond,
+							gpointer user_data)
+{
+	struct connman_inotify *inotify = user_data;
+	char buffer[256];
+	char *next_event;
+	gsize bytes_read;
+	GIOStatus status;
+	GSList *list;
+
+	if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+		inotify->watch = 0;
+		return FALSE;
+	}
+
+	status = g_io_channel_read_chars(channel, buffer,
+					sizeof(buffer) -1, &bytes_read, NULL);
+
+	switch (status) {
+	case G_IO_STATUS_NORMAL:
+		break;
+	case G_IO_STATUS_AGAIN:
+		return TRUE;
+	default:
+		connman_error("Reading from inotify channel failed");
+		inotify->watch = 0;
+		return FALSE;
+	}
+
+	next_event = buffer;
+
+	while (bytes_read > 0) {
+		struct inotify_event *event;
+		gchar *ident;
+		gsize len;
+
+		event = (struct inotify_event *) next_event;
+		if (event->len)
+			ident = next_event + sizeof(struct inotify_event);
+		else
+			ident = NULL;
+
+		len = sizeof(struct inotify_event) + event->len;
+
+		/* check if inotify_event block fit */
+		if (len > bytes_read)
+			break;
+
+		next_event += len;
+		bytes_read -= len;
+
+		for (list = inotify->list; list != NULL; list = list->next) {
+			inotify_event_cb callback = list->data;
+
+			(*callback)(event, ident);
+		}
+	}
+
+	return TRUE;
+}
+
+static int create_watch(const char *path, struct connman_inotify *inotify)
+{
+	int fd;
+
+	DBG("Add directory watch for %s", path);
+
+	fd = inotify_init();
+	if (fd < 0)
+		return -EIO;
+
+	inotify->wd = inotify_add_watch(fd, path,
+					IN_MODIFY | IN_CREATE | IN_DELETE);
+	if (inotify->wd < 0) {
+		connman_error("Creation of %s watch failed", path);
+		close(fd);
+		return -EIO;
+	}
+
+	inotify->channel = g_io_channel_unix_new(fd);
+	if (inotify->channel == NULL) {
+		connman_error("Creation of inotify channel failed");
+		inotify_rm_watch(fd, inotify->wd);
+		inotify->wd = 0;
+
+		close(fd);
+		return -EIO;
+	}
+
+	g_io_channel_set_close_on_unref(inotify->channel, TRUE);
+	g_io_channel_set_encoding(inotify->channel, NULL, NULL);
+	g_io_channel_set_buffered(inotify->channel, FALSE);
+
+	inotify->watch = g_io_add_watch(inotify->channel,
+				G_IO_IN | G_IO_HUP | G_IO_NVAL | G_IO_ERR,
+				inotify_data, inotify);
+
+	return 0;
+}
+
+static void remove_watch(struct connman_inotify *inotify)
+{
+	int fd;
+
+	if (inotify->channel == NULL)
+		return;
+
+	if (inotify->watch > 0)
+		g_source_remove(inotify->watch);
+
+	fd = g_io_channel_unix_get_fd(inotify->channel);
+
+	if (inotify->wd >= 0)
+		inotify_rm_watch(fd, inotify->wd);
+
+	g_io_channel_unref(inotify->channel);
+}
+
+int connman_inotify_register(const char *path, inotify_event_cb callback)
+{
+	struct connman_inotify *inotify;
+	int err;
+
+	if (callback == NULL)
+		return -EINVAL;
+
+	inotify = g_hash_table_lookup(inotify_hash, path);
+	if (inotify != NULL)
+		goto update;
+
+	inotify = g_try_new0(struct connman_inotify, 1);
+	if (inotify == NULL)
+		return -ENOMEM;
+
+	inotify->wd = -1;
+
+	err = create_watch(path, inotify);
+	if (err < 0) {
+		g_free(inotify);
+		return err;
+	}
+
+	g_hash_table_replace(inotify_hash, g_strdup(path), inotify);
+
+update:
+	inotify->list = g_slist_prepend(inotify->list, callback);
+
+	return 0;
+}
+
+static void cleanup_inotify(gpointer user_data)
+{
+	struct connman_inotify *inotify = user_data;
+
+	g_slist_free(inotify->list);
+
+	remove_watch(inotify);
+	g_free(inotify);
+}
+
+void connman_inotify_unregister(const char *path, inotify_event_cb callback)
+{
+	struct connman_inotify *inotify;
+
+	inotify = g_hash_table_lookup(inotify_hash, path);
+	if (inotify == NULL)
+		return;
+
+	inotify->list = g_slist_remove(inotify->list, callback);
+	if (inotify->list != NULL)
+		return;
+
+	g_hash_table_remove(inotify_hash, path);
+}
+
+int __connman_inotify_init(void)
+{
+	DBG("");
+
+	inotify_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+						g_free, cleanup_inotify);
+	return 0;
+}
+
+void __connman_inotify_cleanup(void)
+{
+	DBG("");
+
+	g_hash_table_destroy(inotify_hash);
+}
diff --git a/src/main.c b/src/main.c
index 187104b..ab50737 100644
--- a/src/main.c
+++ b/src/main.c
@@ -557,6 +557,7 @@ int main(int argc, char *argv[])
 		config_init(option_config);
 
 	__connman_storage_migrate();
+	__connman_inotify_init();
 	__connman_technology_init();
 	__connman_notifier_init();
 	__connman_service_init();
@@ -636,6 +637,7 @@ int main(int argc, char *argv[])
 	__connman_ipconfig_cleanup();
 	__connman_notifier_cleanup();
 	__connman_technology_cleanup();
+	__connman_inotify_cleanup();
 
 	__connman_dbus_cleanup();
 
-- 
1.8.0.rc0




More information about the connman mailing list