4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Hakjoo Ko <hakjoo.ko@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
22 #include <sys/types.h>
23 #include <sys/inotify.h>
27 #include <linux/version.h>
31 #include "vconf-internals.h"
35 #define INOTY_EVENT_MASK (IN_CLOSE_WRITE | IN_DELETE_SELF)
43 struct noti_node *next;
45 typedef struct noti_node noti_node_s;
46 static GList *g_notilist;
48 static int _vconf_inoti_comp_with_wd(gconstpointer a, gconstpointer b)
52 noti_node_s *key1 = (noti_node_s *) a;
53 noti_node_s *key2 = (noti_node_s *) b;
55 r = key1->wd - key2->wd;
59 static int _vconf_inoti_comp_with_wd_cb(gconstpointer a, gconstpointer b)
63 noti_node_s *key1 = (noti_node_s *) a;
64 noti_node_s *key2 = (noti_node_s *) b;
66 r = key1->wd - key2->wd;
70 r = (int)(key1->cb - key2->cb);
74 static int _kdb_inoti_fd;
76 static pthread_mutex_t _kdb_inoti_fd_mutex = PTHREAD_MUTEX_INITIALIZER;
77 static pthread_mutex_t _kdb_g_ns_mutex = PTHREAD_MUTEX_INITIALIZER;
79 static GSource *_kdb_handler;
81 static GList* _vconf_copy_noti_list(GList *orig_notilist)
83 GList *copy_notilist = NULL;
84 struct noti_node *n = NULL;
85 struct noti_node *t = NULL;
90 orig_notilist = g_list_first(orig_notilist);
94 while(orig_notilist) {
95 t = orig_notilist->data;
97 n = calloc(1, sizeof(noti_node_s));
99 ERR("_vconf_copy_noti_list : calloc failed. memory full");
104 n->keyname = strndup(t->keyname, BUF_LEN);
105 n->cb_data = t->cb_data;
108 copy_notilist = g_list_append(copy_notilist, n);
109 orig_notilist = g_list_next(orig_notilist);
111 return copy_notilist;
115 static void _vconf_free_noti_node(gpointer data)
117 struct noti_node *n = (struct noti_node*)data;
122 static void _vconf_free_noti_list(GList *noti_list)
124 g_list_free_full(noti_list, _vconf_free_noti_node);
128 static gboolean _vconf_kdb_gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
131 struct inotify_event ie;
132 GList *l_notilist = NULL;
134 INFO("vconf noti function");
136 fd = g_io_channel_unix_get_fd(src);
137 r = read(fd, &ie, sizeof(ie));
140 INFO("read event from GIOChannel. pid : %d", getpid());
142 pthread_mutex_lock(&_kdb_g_ns_mutex);
143 l_notilist = _vconf_copy_noti_list(g_notilist);
144 pthread_mutex_unlock(&_kdb_g_ns_mutex);
149 struct noti_node *t = NULL;
150 GList *noti_list = NULL;
151 keynode_t* keynode = NULL;
153 retvm_if(!(ie.mask & INOTY_EVENT_MASK), TRUE,
154 "Invalid argument: ie.mask(%d), ie.len(%d)",
157 noti_list = g_list_first(l_notilist);
162 keynode_t* keynode = _vconf_keynode_new();
163 retvm_if(keynode == NULL, TRUE, "key malloc fail");
165 if( (t) && (t->wd == ie.wd) ) {
166 if ((ie.mask & IN_DELETE_SELF)) {
167 INFO("Notify that key(%s) is deleted", t->keyname);
168 _vconf_keynode_set_keyname(keynode, (const char *)t->keyname);
169 _vconf_keynode_set_null(keynode);
170 t->cb(keynode, t->cb_data);
171 _vconf_kdb_del_notify(t->keyname, t->cb);
173 _vconf_keynode_set_keyname(keynode, t->keyname);
174 _vconf_get_key(keynode);
175 t->cb(keynode, t->cb_data);
179 _vconf_keynode_free(keynode);
181 noti_list = g_list_next(noti_list);
184 _vconf_free_noti_list(l_notilist);
188 (void) lseek(fd, ie.len, SEEK_CUR);
190 r = read(fd, &ie, sizeof(ie));
195 static int _vconf_kdb_noti_init(void)
200 pthread_mutex_lock(&_kdb_inoti_fd_mutex);
202 if (0 < _kdb_inoti_fd) {
203 ERR("Error: invalid _kdb_inoti_fd");
204 pthread_mutex_unlock(&_kdb_inoti_fd_mutex);
207 _kdb_inoti_fd = inotify_init();
208 if (_kdb_inoti_fd == -1) {
209 char err_buf[100] = { 0, };
210 strerror_r(errno, err_buf, sizeof(err_buf));
211 ERR("inotify init: %s", err_buf);
212 pthread_mutex_unlock(&_kdb_inoti_fd_mutex);
216 ret = fcntl(_kdb_inoti_fd, F_SETFD, FD_CLOEXEC);
218 char err_buf[100] = { 0, };
219 strerror_r(errno, err_buf, sizeof(err_buf));
220 ERR("inotify init: %s", err_buf);
221 pthread_mutex_unlock(&_kdb_inoti_fd_mutex);
225 ret = fcntl(_kdb_inoti_fd, F_SETFL, O_NONBLOCK);
227 char err_buf[100] = { 0, };
228 strerror_r(errno, err_buf, sizeof(err_buf));
229 ERR("inotify init: %s", err_buf);
230 pthread_mutex_unlock(&_kdb_inoti_fd_mutex);
234 pthread_mutex_unlock(&_kdb_inoti_fd_mutex);
236 gio = g_io_channel_unix_new(_kdb_inoti_fd);
237 retvm_if(gio == NULL, -1, "Error: create a new GIOChannel");
239 g_io_channel_set_flags(gio, G_IO_FLAG_NONBLOCK, NULL);
241 _kdb_handler = g_io_create_watch(gio, G_IO_IN);
242 g_source_set_callback(_kdb_handler, (GSourceFunc) _vconf_kdb_gio_cb, NULL, NULL);
243 g_source_attach(_kdb_handler, NULL);
244 g_io_channel_unref(gio);
245 g_source_unref(_kdb_handler);
251 _vconf_kdb_add_notify(const char *keyname, vconf_callback_fn cb, void *data)
255 struct noti_node t, *n;
256 char err_buf[ERR_LEN] = { 0, };
259 int func_ret = VCONF_OK;
261 retvm_if((keyname == NULL || cb == NULL), VCONF_ERROR,
262 "_vconf_kdb_add_notify : Invalid argument - keyname(%s) cb(%p)",
265 if (_kdb_inoti_fd <= 0)
266 if (_vconf_kdb_noti_init())
269 ret = _vconf_get_key_path((char*)keyname, path);
270 retvm_if(ret != VCONF_OK, VCONF_ERROR, "Invalid argument: key is not valid");
272 if (0 != access(path, F_OK)) {
273 if (errno == ENOENT) {
274 ERR("_vconf_kdb_add_notify : Key(%s) does not exist", keyname);
279 wd = inotify_add_watch(_kdb_inoti_fd, path, INOTY_EVENT_MASK);
281 strerror_r(errno, err_buf, sizeof(err_buf));
282 ERR("_vconf_kdb_add_notify : add noti(%s)", err_buf);
289 pthread_mutex_lock(&_kdb_g_ns_mutex);
291 list = g_list_find_custom(g_notilist, &t, (GCompareFunc)_vconf_inoti_comp_with_wd_cb);
293 ERR("_vconf_kdb_add_notify : key(%s) has same callback(%p)", keyname, cb);
295 func_ret = VCONF_ERROR;
299 n = calloc(1, sizeof(noti_node_s));
301 strerror_r(errno, err_buf, sizeof(err_buf));
302 ERR("_vconf_kdb_add_notify : add noti(%s)", err_buf);
303 func_ret = VCONF_ERROR;
308 n->keyname = strndup(keyname, BUF_LEN);
312 g_notilist = g_list_append(g_notilist, n);
314 ERR("g_list_append fail");
317 INFO("cb(%p) is added for %s. tot cb cnt : %d\n", cb, n->keyname, g_list_length(g_notilist));
320 pthread_mutex_unlock(&_kdb_g_ns_mutex);
326 _vconf_kdb_del_notify(const char *keyname, vconf_callback_fn cb)
330 struct noti_node *n = NULL;
332 char path[KEY_PATH] = { 0, };
333 char err_buf[ERR_LEN] = { 0, };
337 int func_ret = VCONF_OK;
340 retvm_if(keyname == NULL, VCONF_ERROR, "Invalid argument: keyname(%s)", keyname);
341 retvm_if(_kdb_inoti_fd == 0, VCONF_ERROR, "Invalid operation: not exist anything for inotify");
343 ret = _vconf_get_key_path((char*)keyname, path);
344 retvm_if(ret != VCONF_OK, VCONF_ERROR, "Invalid argument: key is not valid");
347 wd = inotify_add_watch(_kdb_inoti_fd, path, INOTY_EVENT_MASK);
349 strerror_r(errno, err_buf, sizeof(err_buf));
350 ERR("Error: inotify_add_watch() [%s]: %s", path, err_buf);
354 pthread_mutex_lock(&_kdb_g_ns_mutex);
359 noti_list = g_list_find_custom(g_notilist, &t, (GCompareFunc)_vconf_inoti_comp_with_wd_cb);
364 g_notilist = g_list_remove(g_notilist, n);
368 INFO("key(%s) cb is removed. remained noti list total length(%d)",
369 keyname, g_list_length(g_notilist));
373 noti_list = g_list_find_custom(g_notilist, &t, (GCompareFunc)_vconf_inoti_comp_with_wd);
374 if(noti_list == NULL) {
375 INFO("all noti for keyname(%s)/wd(%d) is removed", keyname, wd);
377 r = inotify_rm_watch(_kdb_inoti_fd, wd);
379 strerror_r(errno, err_buf, sizeof(err_buf));
380 ERR("Error: inotify_rm_watch [%s]: %s", keyname, err_buf);
381 func_ret = VCONF_ERROR;
385 if(g_list_length(g_notilist) == 0) {
386 close(_kdb_inoti_fd);
389 g_source_destroy(_kdb_handler);
392 g_list_free(g_notilist);
395 INFO("all noti list is freed");
398 pthread_mutex_unlock(&_kdb_g_ns_mutex);
401 ERR("Error: nothing deleted");
403 func_ret = VCONF_ERROR;