4 * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
24 #include <sys/types.h>
25 #include <sys/inotify.h>
27 #include "cal_internal.h"
28 #include "cal_typedef.h"
30 #include "cal_inotify.h"
31 #include "cal_utils.h"
34 #include "cal_mutex.h"
39 calendar_db_changed_cb cb;
41 cal_noti_type_e noti_type;
45 static int _inoti_fd = -1;
46 static guint inoti_handler;
47 static GSList *_noti_list;
50 static int calendar_inoti_count = 0;
53 static inline void _handle_callback(GSList *_noti_list, int wd, uint32_t mask)
59 noti_info_s *noti = NULL;
60 noti = (noti_info_s *)cursor->data;
62 if ((mask & IN_CLOSE_WRITE) && noti->cb) {
63 switch (noti->noti_type) {
64 case CAL_NOTI_TYPE_CALENDAR:
65 noti->cb(CALENDAR_VIEW_CALENDAR, noti->cb_data);
67 case CAL_NOTI_TYPE_EVENT:
68 noti->cb(CALENDAR_VIEW_EVENT, noti->cb_data);
70 case CAL_NOTI_TYPE_TODO:
71 noti->cb(CALENDAR_VIEW_TODO, noti->cb_data);
78 cursor = cursor->next;
82 static gboolean _inotify_gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
85 struct inotify_event ie;
86 char name[FILENAME_MAX] = {0};
88 fd = g_io_channel_unix_get_fd(src);
90 while (0 < (ret = read(fd, &ie, sizeof(ie)))) {
91 if (sizeof(ie) == ret) {
93 _handle_callback(_noti_list, ie.wd, ie.mask);
96 ret = read(fd, name, (ie.len < sizeof(name)) ? ie.len : sizeof(name));
109 while (ret < sizeof(ie)) {
111 read_size = read(fd, name, sizeof(ie)-ret);
112 if (-1 == read_size) {
125 static inline int _inotify_attach_handler(int fd)
131 ERR("Invalid argument: fd is NULL");
132 return CALENDAR_ERROR_INVALID_PARAMETER;
135 channel = g_io_channel_unix_new(fd);
136 if (NULL == channel) {
137 ERR("g_io_channel_unix_new() Fail");
138 return -1; /* CALENDAR_ERROR_FAILED_INOTIFY */
141 g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL);
143 ret = g_io_add_watch(channel, G_IO_IN, _inotify_gio_cb, NULL);
144 g_io_channel_unref(channel);
149 int cal_inotify_init(void)
153 #ifdef CAL_IPC_CLIENT
154 cal_mutex_lock(CAL_MUTEX_INOTIFY);
155 calendar_inoti_count++;
157 if (1 < calendar_inoti_count) {
158 DBG("inotify count =%d", calendar_inoti_count);
159 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
160 return CALENDAR_ERROR_NONE;
162 DBG("inotify count =%d", calendar_inoti_count);
163 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
165 _inoti_fd = inotify_init();
166 if (_inoti_fd == -1) {
167 ERR("inotify_init() Fail(%d)", errno);
168 #ifdef CAL_IPC_CLIENT
169 cal_mutex_lock(CAL_MUTEX_INOTIFY);
170 calendar_inoti_count = 0;
171 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
173 return -1; /* CALENDAR_ERROR_FAILED_INOTIFY */
176 ret = fcntl(_inoti_fd, F_SETFD, FD_CLOEXEC);
177 WARN_IF(ret < 0, "fcntl failed(%d)", ret);
178 ret = fcntl(_inoti_fd, F_SETFL, O_NONBLOCK);
179 WARN_IF(ret < 0, "fcntl failed(%d)", ret);
181 inoti_handler = _inotify_attach_handler(_inoti_fd);
182 if (inoti_handler <= 0) {
183 ERR("_inotify_attach_handler() Fail");
187 #ifdef CAL_IPC_CLIENT
188 cal_mutex_lock(CAL_MUTEX_INOTIFY);
189 calendar_inoti_count = 0;
190 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
192 return -1; /* CALENDAR_ERROR_FAILED_INOTIFY */
195 return CALENDAR_ERROR_NONE;
198 static inline int _cal_inotify_get_wd(int fd, const char *notipath)
200 return inotify_add_watch(fd, notipath, IN_ACCESS);
203 static inline int _cal_inotify_add_watch(int fd, const char *notipath)
207 ret = inotify_add_watch(fd, notipath, IN_CLOSE_WRITE);
209 ERR("Failed to add watch(ret:%d)", ret);
210 return -1; /* CALENDAR_ERROR_FAILED_INOTIFY */
213 return CALENDAR_ERROR_NONE;
216 static bool _has_noti(int wd, void *cb, void *cb_data)
218 bool has_noti = false;
219 GSList *cursor = NULL;
222 noti_info_s *info = (noti_info_s *)cursor->data;
225 cursor = g_slist_next(cursor);
229 if (info->wd == wd && info->cb == cb && info->cb_data == cb_data)
232 cursor = g_slist_next(cursor);
237 static int _append_noti(int wd, int type, void *cb, void *cb_data)
239 noti_info_s *info = NULL;
240 info = calloc(1, sizeof(noti_info_s));
242 ERR("calloc() Fail");
243 return CALENDAR_ERROR_OUT_OF_MEMORY;
247 info->noti_type = type;
248 info->cb_data = cb_data;
250 info->blocked = false;
252 _noti_list = g_slist_append(_noti_list, info);
254 return CALENDAR_ERROR_NONE;
257 int cal_inotify_subscribe(cal_noti_type_e type, const char *path, void *cb, void *cb_data)
261 RETV_IF(NULL == path, CALENDAR_ERROR_INVALID_PARAMETER);
262 RETV_IF(NULL == cb, CALENDAR_ERROR_INVALID_PARAMETER);
263 RETVM_IF(_inoti_fd < 0, CALENDAR_ERROR_INVALID_PARAMETER, "_inoti_fd(%d) is invalid", _inoti_fd);
265 wd = _cal_inotify_get_wd(_inoti_fd, path);
267 ERR("_cal_inotify_get_wd() Fail(%d)", errno);
269 return CALENDAR_ERROR_PERMISSION_DENIED;
270 return CALENDAR_ERROR_SYSTEM;
273 if (true == _has_noti(wd, cb, cb_data)) {
274 ERR("noti is already registered: path[%s]", path);
275 _cal_inotify_add_watch(_inoti_fd, path);
276 return CALENDAR_ERROR_INVALID_PARAMETER;
279 ret = _cal_inotify_add_watch(_inoti_fd, path);
280 if (CALENDAR_ERROR_NONE != ret) {
281 ERR("_cal_inotify_add_watch() Fail(%d)", ret);
284 _append_noti(wd, type, cb, cb_data);
286 return CALENDAR_ERROR_NONE;
289 static int _cal_del_noti(GSList **_noti_list, int wd, void *cb, void *cb_data)
291 int del_cnt, remain_cnt;
292 GSList *cursor, *result;
297 cursor = result = *_noti_list;
299 noti_info_s *noti = cursor->data;
300 if (noti && wd == noti->wd) {
301 if (cb == noti->cb && cb_data == noti->cb_data) {
302 cursor = g_slist_next(cursor);
303 result = g_slist_remove(result , noti);
311 cursor = g_slist_next(cursor);
315 ERR("Nothing to delete");
316 return CALENDAR_ERROR_NO_DATA;
318 *_noti_list = result;
323 int cal_inotify_unsubscribe(const char *path, void *cb, void *cb_data)
327 RETV_IF(NULL == path, CALENDAR_ERROR_INVALID_PARAMETER);
328 RETV_IF(NULL == cb, CALENDAR_ERROR_INVALID_PARAMETER);
329 RETVM_IF(_inoti_fd < 0, CALENDAR_ERROR_SYSTEM, "System : _inoti_fd(%d) is invalid", _inoti_fd);
331 wd = _cal_inotify_get_wd(_inoti_fd, path);
333 ERR("_cal_inotify_get_wd() Fail(%d)", errno);
335 return CALENDAR_ERROR_PERMISSION_DENIED;
336 return CALENDAR_ERROR_SYSTEM;
339 ret = _cal_del_noti(&_noti_list, wd, cb, cb_data);
340 WARN_IF(ret < CALENDAR_ERROR_NONE, "_cal_del_noti() Fail(%d)", ret);
342 if (CALENDAR_ERROR_NONE != ret) {
343 ret = _cal_inotify_add_watch(_inoti_fd, path);
347 return inotify_rm_watch(_inoti_fd, wd);
350 static inline gboolean _cal_inotify_detach_handler(guint id)
352 return g_source_remove(id);
355 static void __clear_nslot_list(gpointer data, gpointer user_data)
357 noti_info_s *noti = (noti_info_s *)data;
361 void cal_inotify_deinit(void)
363 #ifdef CAL_IPC_CLIENT
364 cal_mutex_lock(CAL_MUTEX_INOTIFY);
365 calendar_inoti_count--;
367 if (0 < calendar_inoti_count) {
368 DBG("inotify count =%d", calendar_inoti_count);
369 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
372 DBG("inotify count =%d", calendar_inoti_count);
373 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
376 _cal_inotify_detach_handler(inoti_handler);
381 g_slist_foreach(_noti_list, __clear_nslot_list, NULL);
382 g_slist_free(_noti_list);
386 if (0 <= _inoti_fd) {