4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jayoun Lee <airjany@samsung.com>, Sewook Park <sewook7.park@samsung.com>,
7 * Jaeho Lee <jaeho81.lee@samsung.com>
9 * Licensed under the Apache License, Version 2.0 (the "License");
10 * you may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
27 #include <sys/types.h>
28 #include <sys/inotify.h>
31 #include <linux/version.h>
38 #include <sys/utsname.h>
40 /* For multi-user support */
41 #include <tzplatform_config.h>
43 #include "heynoti-internal.h"
45 #define AU_PREFIX_SYSNOTI "SYS"
48 #define NOTI_ROOT tzplatform_mkpath(TZ_SYS_SHARE, "noti")
52 #define NODAC_PERMISSION
60 typedef struct noti_slot nslot;
62 static int __make_noti_root(const char *p);
63 static int __make_noti_file(const char *p);
64 static inline int __make_noti_path(char *path, int size, const char *name);
65 static int __read_proc(const char *path, char *buf, int size);
66 static void __clear_nslot_list(GList *g_ns);
67 static struct noti_cont *__get_noti_cont(int fd);
68 static int __handle_callback(struct noti_cont *nc, int wd, uint32_t mask);
69 static int __handle_event(int fd);
70 static inline int __get_wd(int fd, const char *notipath);
71 static int __add_wd(struct noti_cont *nc, int wd, uint32_t mask,
72 const char *notipath);
73 static int __add_noti(int fd, const char *notipath, void (*cb) (void *),
74 void *data, uint32_t mask);
75 static int _del_noti(struct noti_cont *nc, int wd, void (*cb) (void *),
76 const char *notipath);
77 static int del_noti(int fd, const char *notipath, void (*cb) (void *));
80 int slot_comp(struct noti_slot *a, struct noti_slot *b)
88 r = (int)(a->cb - b->cb);
106 struct sigaction oldact;
110 typedef struct noti_cont ncont;
114 static int __make_noti_root(const char *p)
118 if ((fd = open(p, O_RDONLY)) == -1 )
126 static int __make_noti_file(const char *p)
130 if ((fd = open(p, O_RDONLY)) == -1)
138 static inline int __make_noti_path(char *path, int size, const char *name)
140 return snprintf(path, size, "%s/%s", NOTI_ROOT, name);
143 static int __read_proc(const char *path, char *buf, int size)
148 if (buf == NULL || path == NULL) {
149 UTIL_DBG("%s: path or buf is NULL\n", __func__);
154 fd = open(path, O_RDONLY);
155 util_retvm_if(fd == -1, -1, "File open error: %s", strerror(errno));
157 memset(buf, 0x0, size);
158 ret = read(fd, buf, size);
164 #define PROC_VERSION "/proc/version"
166 static int __check_kern_ver()
177 strncpy(buf, nm.release, sizeof(buf));
179 ret = sscanf(buf, "%d.%d.%d", &v1, &v2, &v3);
181 __read_proc(PROC_VERSION, buf, sizeof(buf));
183 ret = sscanf(buf, "Linux version %d.%d.%d", &v1, &v2, &v3);
187 if(KERNEL_VERSION(v1, v2, v3) < KERNEL_VERSION(2, 6, 13)) {
197 static void __clear_nslot_list(GList *g_ns)
202 for (it = g_ns; it != NULL; it = g_list_next(it)) {
203 t = (struct noti_slot *)it->data;
209 static struct noti_cont *__get_noti_cont(int fd)
211 struct noti_cont *r = NULL;
214 for (it = g_nc; it != NULL; it = g_list_next(it)) {
216 r = (struct noti_cont *)it->data;
228 static int __handle_callback(struct noti_cont *nc, int wd, uint32_t mask)
236 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
237 t = (struct noti_slot *)it->data;
239 if ((mask & t->mask) && t->cb) {
248 static int __handle_event(int fd)
251 struct inotify_event ie;
252 char name[FILENAME_MAX] = {0, };
254 struct noti_cont *nc;
256 nc = __get_noti_cont(fd);
257 util_warn_if(nc == NULL, "Non-registered file descriptor");
259 r = read(fd, &ie, sizeof(ie));
263 __handle_callback(nc, ie.wd, ie.mask);
265 if(ie.len > SSIZE_MAX)
269 read(fd, name, (ie.len > FILENAME_MAX) ? (size_t)FILENAME_MAX : (size_t) ie.len);
272 r = read(fd, &ie, sizeof(ie));
278 API int heynoti_poll_event(int fd)
281 struct noti_cont *nc;
282 struct pollfd fds[1];
284 nc = __get_noti_cont(fd);
286 UTIL_ERR("Non-registered file descriptor : %d", fd);
291 if (nc->ht != H_NONE) {
292 UTIL_ERR("Another handler already in progress");
298 fds[0].events = POLLIN;
300 r = poll(fds, 1, -1);
301 util_retvm_if(r == -1, -1, "Error: poll : %s", strerror(errno));
303 if (fds[0].revents & POLLIN)
309 static inline int __get_wd(int fd, const char *notipath)
311 return inotify_add_watch(fd, notipath, IN_ACCESS);
314 static int __add_wd(struct noti_cont *nc, int wd, uint32_t mask,
315 const char *notipath)
323 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
324 t = (struct noti_slot *)it->data;
332 r = inotify_add_watch(nc->fd, notipath, mask_all);
336 static int __add_noti(int fd, const char *notipath, void (*cb) (void *),
337 void *data, uint32_t mask)
341 struct noti_cont *nc;
342 struct noti_slot t, *n;
343 struct noti_slot *f = NULL;
346 nc = __get_noti_cont(fd);
348 UTIL_DBG("Bad file descriptor");
353 wd = __get_wd(fd, notipath);
354 util_retvm_if(wd == -1, -1, "Error: add noti: %s", strerror(errno));
356 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
358 f = (struct noti_slot *)it->data;
359 if (f->wd == wd && f->cb == cb) {
368 __add_wd(nc, wd, 0, notipath);
373 r = __add_wd(nc, wd, mask, notipath);
374 util_retvm_if(r == -1, -1, "Error: add noti: %s", strerror(errno));
376 n = calloc(1, sizeof(nslot));
377 util_retvm_if(n == NULL, -1, "Error: add noti: %s", strerror(errno));
383 nc->g_ns = g_list_append(nc->g_ns, (gpointer) n);
388 API int heynoti_subscribe(int fd, const char *noti, void (*cb) (void *),
391 char notipath[FILENAME_MAX];
393 if (noti == NULL || cb == NULL) {
394 UTIL_DBG("Error: add noti: Invalid input");
399 __make_noti_path(notipath, sizeof(notipath), noti);
400 UTIL_DBG("add watch: [%s]", notipath);
402 return __add_noti(fd, notipath, cb, data, IN_CLOSE_WRITE | IN_DELETE);
405 static int _del_noti(struct noti_cont *nc, int wd, void (*cb) (void *),
406 const char *notipath)
423 t = (struct noti_slot *)it->data;
425 if (cb == NULL || cb == t->cb) {
426 nc->g_ns = g_list_remove(nc->g_ns, t);
439 return inotify_rm_watch(nc->fd, wd);
441 r = __add_wd(nc, wd, 0, notipath);
444 UTIL_DBG("Error: nothing deleted");
452 static int del_noti(int fd, const char *notipath, void (*cb) (void *))
455 struct noti_cont *nc;
457 nc = __get_noti_cont(fd);
459 UTIL_DBG("Bad file descriptor");
465 wd = __get_wd(fd, notipath);
466 util_retv_if(wd == -1, -1);
468 return _del_noti(nc, wd, cb, notipath);
471 API int heynoti_unsubscribe(int fd, const char *noti, void (*cb) (void *))
474 char notipath[FILENAME_MAX];
476 if (fd < 0 || noti == NULL) {
481 __make_noti_path(notipath, sizeof(notipath), noti);
482 UTIL_DBG("del watch: [%s]", notipath);
484 r = del_noti(fd, notipath, cb);
485 util_warn_if(r == -1, "Error: del [%s]: %s", noti, strerror(errno));
490 API int heynoti_publish(const char *noti)
494 char notipath[FILENAME_MAX];
498 UTIL_DBG("Error: send noti: Invalid input");
503 path = strstr(noti, "/");
505 snprintf(notipath, sizeof(notipath), "%s", noti);
507 __make_noti_path(notipath, sizeof(notipath), noti);
509 UTIL_DBG("send noti: [%s]", notipath);
511 fd = open(notipath, O_TRUNC | O_WRONLY);
513 util_retvm_if(fd == -1, -1, "Error: send noti: %s", strerror(errno));
517 if(sb.st_uid != getuid())
518 fchown(fd, getuid(), getgid());
519 if(sb.st_mode & 0033)
527 API int heynoti_init()
532 struct noti_cont *nc;
534 if(__check_kern_ver() < 0) {
535 UTIL_ERR("inotify requires kernel version >= 2.6.13 ");
541 util_retvm_if(fd == -1, -1, "inotify init: %s", strerror(errno));
543 r = fcntl(fd, F_SETFD, FD_CLOEXEC);
544 util_retvm_if(r < 0, -1, "fcntl error : %s", strerror(errno));
545 r = fcntl(fd, F_SETFL, O_NONBLOCK);
546 util_retvm_if(r < 0, -1, "fcntl error : %s", strerror(errno));
548 r = __make_noti_root(NOTI_ROOT);
550 UTIL_ERR("make noti root: %s : %s", NOTI_ROOT, strerror(errno));
555 nc = calloc(1, sizeof(struct noti_cont));
562 /*sglib_ncont_add(&nc_h, nc); */
563 g_nc = g_list_append(g_nc, (gpointer) nc);
568 API int heynoti_get_pnoti_name(pid_t pid, const char *name, char *buf,
576 ret = snprintf(buf, buf_size, ".%d_%s", pid, name);
584 API int heynoti_get_snoti_name(const char *name, char *buf, int buf_size)
591 ret = snprintf(buf, buf_size, ".%s_%s", AU_PREFIX_SYSNOTI, name);
599 gboolean gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
603 /* need condition check?? */
605 fd = g_io_channel_unix_get_fd(src);
611 API int heynoti_attach_handler(int fd)
614 struct noti_cont *nc = NULL;
618 nc = __get_noti_cont(fd);
620 UTIL_ERR("Non-registered file descriptor : %d", fd);
630 UTIL_ERR("glib based handler now in progress");
634 UTIL_ERR("Another handler already in progress: %d", nc->ht);
638 util_retv_if(nc->ht != H_NONE, -1);
640 gio = g_io_channel_unix_new(fd);
641 util_retvm_if(gio == NULL, -1, "Error: create a new GIOChannel");
643 g_io_channel_set_flags(gio, G_IO_FLAG_NONBLOCK, NULL);
645 src = g_io_create_watch(gio, G_IO_IN);
646 g_source_set_callback(src, (GSourceFunc) gio_cb, NULL, NULL);
647 ret = g_source_attach(src, NULL);
648 g_io_channel_unref(gio);
659 API int heynoti_detach_handler(int fd)
661 struct noti_cont *nc = NULL;
663 nc = __get_noti_cont(fd);
665 UTIL_ERR("Non-registered file descriptor : %d", fd);
672 g_source_destroy(nc->handler);
684 API void heynoti_close(int fd)
686 struct noti_cont *r = NULL;
688 r = __get_noti_cont(fd);
689 util_warn_if(r == NULL, "Non-registered file descriptor");
693 heynoti_detach_handler(fd);
695 __clear_nslot_list(r->g_ns);
696 g_list_free(r->g_ns);
699 g_nc = g_list_remove(g_nc, (gconstpointer) r);