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_BOOK:
65 noti->cb(CALENDAR_VIEW_BOOK, 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 /* LCOV_EXCL_START */
132 ERR("Invalid argument: fd is NULL");
133 return CALENDAR_ERROR_INVALID_PARAMETER;
137 channel = g_io_channel_unix_new(fd);
138 if (NULL == channel) {
139 /* LCOV_EXCL_START */
140 ERR("g_io_channel_unix_new() Fail");
141 return -1; /* CALENDAR_ERROR_FAILED_INOTIFY */
145 g_io_channel_set_flags(channel, G_IO_FLAG_NONBLOCK, NULL);
147 ret = g_io_add_watch(channel, G_IO_IN, _inotify_gio_cb, NULL);
148 g_io_channel_unref(channel);
153 int cal_inotify_init(void)
157 #ifdef CAL_IPC_CLIENT
158 cal_mutex_lock(CAL_MUTEX_INOTIFY);
159 calendar_inoti_count++;
161 if (1 < calendar_inoti_count) {
162 DBG("inotify count =%d", calendar_inoti_count);
163 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
164 return CALENDAR_ERROR_NONE;
166 DBG("inotify count =%d", calendar_inoti_count);
167 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
169 _inoti_fd = inotify_init();
170 if (_inoti_fd == -1) {
171 /* LCOV_EXCL_START */
172 ERR("inotify_init() Fail(%d)", errno);
173 #ifdef CAL_IPC_CLIENT
174 cal_mutex_lock(CAL_MUTEX_INOTIFY);
175 calendar_inoti_count = 0;
176 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
178 return -1; /* CALENDAR_ERROR_FAILED_INOTIFY */
182 ret = fcntl(_inoti_fd, F_SETFD, FD_CLOEXEC);
183 WARN_IF(ret < 0, "fcntl failed(%d)", ret);
184 ret = fcntl(_inoti_fd, F_SETFL, O_NONBLOCK);
185 WARN_IF(ret < 0, "fcntl failed(%d)", ret);
187 inoti_handler = _inotify_attach_handler(_inoti_fd);
188 if (inoti_handler <= 0) {
189 /* LCOV_EXCL_START */
190 ERR("_inotify_attach_handler() Fail");
194 #ifdef CAL_IPC_CLIENT
195 cal_mutex_lock(CAL_MUTEX_INOTIFY);
196 calendar_inoti_count = 0;
197 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
199 return -1; /* CALENDAR_ERROR_FAILED_INOTIFY */
203 return CALENDAR_ERROR_NONE;
206 static inline int _cal_inotify_get_wd(int fd, const char *notipath)
208 return inotify_add_watch(fd, notipath, IN_ACCESS);
211 static inline int _cal_inotify_add_watch(int fd, const char *notipath)
215 ret = inotify_add_watch(fd, notipath, IN_CLOSE_WRITE);
217 /* LCOV_EXCL_START */
218 ERR("Failed to add watch(ret:%d)", ret);
219 return -1; /* CALENDAR_ERROR_FAILED_INOTIFY */
223 return CALENDAR_ERROR_NONE;
226 static bool _has_noti(int wd, void *cb, void *cb_data)
228 bool has_noti = false;
229 GSList *cursor = NULL;
232 noti_info_s *info = (noti_info_s *)cursor->data;
235 cursor = g_slist_next(cursor);
239 if (info->wd == wd && info->cb == cb && info->cb_data == cb_data)
242 cursor = g_slist_next(cursor);
247 static int _append_noti(int wd, int type, void *cb, void *cb_data)
249 noti_info_s *info = NULL;
250 info = calloc(1, sizeof(noti_info_s));
252 /* LCOV_EXCL_START */
253 ERR("calloc() Fail");
254 return CALENDAR_ERROR_OUT_OF_MEMORY;
259 info->noti_type = type;
260 info->cb_data = cb_data;
262 info->blocked = false;
264 _noti_list = g_slist_append(_noti_list, info);
266 return CALENDAR_ERROR_NONE;
269 int cal_inotify_subscribe(cal_noti_type_e type, const char *path, void *cb, void *cb_data)
273 RETV_IF(NULL == path, CALENDAR_ERROR_INVALID_PARAMETER);
274 RETV_IF(NULL == cb, CALENDAR_ERROR_INVALID_PARAMETER);
275 RETVM_IF(_inoti_fd < 0, CALENDAR_ERROR_INVALID_PARAMETER, "_inoti_fd(%d) is invalid", _inoti_fd);
277 wd = _cal_inotify_get_wd(_inoti_fd, path);
279 /* LCOV_EXCL_START */
280 ERR("_cal_inotify_get_wd() Fail(%d)", errno);
282 return CALENDAR_ERROR_PERMISSION_DENIED;
283 return CALENDAR_ERROR_SYSTEM;
287 if (true == _has_noti(wd, cb, cb_data)) {
288 /* LCOV_EXCL_START */
289 ERR("noti is already registered: path[%s]", path);
290 _cal_inotify_add_watch(_inoti_fd, path);
291 return CALENDAR_ERROR_INVALID_PARAMETER;
295 ret = _cal_inotify_add_watch(_inoti_fd, path);
296 if (CALENDAR_ERROR_NONE != ret) {
297 /* LCOV_EXCL_START */
298 ERR("_cal_inotify_add_watch() Fail(%d)", ret);
302 _append_noti(wd, type, cb, cb_data);
304 return CALENDAR_ERROR_NONE;
307 static int _cal_del_noti(GSList **_noti_list, int wd, void *cb, void *cb_data)
309 int del_cnt, remain_cnt;
310 GSList *cursor, *result;
315 cursor = result = *_noti_list;
317 noti_info_s *noti = cursor->data;
318 if (noti && wd == noti->wd) {
319 if (cb == noti->cb && cb_data == noti->cb_data) {
320 cursor = g_slist_next(cursor);
321 result = g_slist_remove(result , noti);
329 cursor = g_slist_next(cursor);
333 /* LCOV_EXCL_START */
334 ERR("Nothing to delete");
335 return CALENDAR_ERROR_NO_DATA;
338 *_noti_list = result;
343 int cal_inotify_unsubscribe(const char *path, void *cb, void *cb_data)
347 RETV_IF(NULL == path, CALENDAR_ERROR_INVALID_PARAMETER);
348 RETV_IF(NULL == cb, CALENDAR_ERROR_INVALID_PARAMETER);
349 RETVM_IF(_inoti_fd < 0, CALENDAR_ERROR_SYSTEM, "System : _inoti_fd(%d) is invalid", _inoti_fd);
351 wd = _cal_inotify_get_wd(_inoti_fd, path);
353 /* LCOV_EXCL_START */
354 ERR("_cal_inotify_get_wd() Fail(%d)", errno);
356 return CALENDAR_ERROR_PERMISSION_DENIED;
357 return CALENDAR_ERROR_SYSTEM;
361 ret = _cal_del_noti(&_noti_list, wd, cb, cb_data);
362 WARN_IF(ret < CALENDAR_ERROR_NONE, "_cal_del_noti() Fail(%d)", ret);
364 if (CALENDAR_ERROR_NONE != ret) {
365 ret = _cal_inotify_add_watch(_inoti_fd, path);
369 return inotify_rm_watch(_inoti_fd, wd);
372 static inline gboolean _cal_inotify_detach_handler(guint id)
374 return g_source_remove(id);
377 static void __clear_nslot_list(gpointer data, gpointer user_data)
379 noti_info_s *noti = (noti_info_s *)data;
383 void cal_inotify_deinit(void)
385 #ifdef CAL_IPC_CLIENT
386 cal_mutex_lock(CAL_MUTEX_INOTIFY);
387 calendar_inoti_count--;
389 if (0 < calendar_inoti_count) {
390 DBG("inotify count =%d", calendar_inoti_count);
391 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
394 DBG("inotify count =%d", calendar_inoti_count);
395 cal_mutex_unlock(CAL_MUTEX_INOTIFY);
398 _cal_inotify_detach_handler(inoti_handler);
403 g_slist_foreach(_noti_list, __clear_nslot_list, NULL);
404 g_slist_free(_noti_list);
408 if (0 <= _inoti_fd) {