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 #include "heynoti-internal.h"
42 #define AU_PREFIX_SYSNOTI "SYS"
45 # define NOTI_ROOT "/tmp/noti"
49 #define NODAC_PERMISSION
57 typedef struct noti_slot nslot;
59 static int __make_noti_root(const char *p);
60 static int __make_noti_file(const char *p);
61 static inline int __make_noti_path(char *path, int size, const char *name);
62 static int __read_proc(const char *path, char *buf, int size);
63 static int __get_kern_ver();
64 static void __clear_nslot_list(GList *g_ns);
65 static struct noti_cont *__get_noti_cont(int fd);
66 static int __handle_callback(struct noti_cont *nc, int wd, uint32_t mask);
67 static int __handle_event(int fd);
68 static inline int __get_wd(int fd, const char *notipath);
69 static int __add_wd(struct noti_cont *nc, int wd, uint32_t mask,
70 const char *notipath);
71 static int __add_noti(int fd, const char *notipath, void (*cb) (void *),
72 void *data, uint32_t mask);
73 static int _del_noti(struct noti_cont *nc, int wd, void (*cb) (void *),
74 const char *notipath);
75 static int del_noti(int fd, const char *notipath, void (*cb) (void *));
78 int slot_comp(struct noti_slot *a, struct noti_slot *b)
86 r = (int)(a->cb - b->cb);
104 struct sigaction oldact;
108 typedef struct noti_cont ncont;
110 static const char *noti_root = NOTI_ROOT;
113 static int __make_noti_root(const char *p)
117 if ((fd = open(p, O_RDONLY)) == -1) {
118 if (mkdir(p, 0777) == -1)
127 static int __make_noti_file(const char *p)
131 #ifdef NODAC_PERMISSION
132 if ((fd = open(p, O_RDONLY)) == -1) {
133 if ((fd = open(p, O_CREAT, 0666)) < 0) {
143 if ((fd = open(p, O_RDONLY)) == -1) {
144 if ((fd = open(p, O_CREAT, 0644)) < 0) {
156 static inline int __make_noti_path(char *path, int size, const char *name)
158 return snprintf(path, size, "%s/%s", noti_root, name);
161 static int __read_proc(const char *path, char *buf, int size)
166 if (buf == NULL || path == NULL) {
167 UTIL_DBG("%s: path or buf is NULL\n", __func__);
172 fd = open(path, O_RDONLY);
173 util_retvm_if(fd == -1, -1, "File open error: %s", strerror(errno));
175 memset(buf, 0x0, size);
176 ret = read(fd, buf, size);
182 static int kern_ver; /* Kernel version */
183 #define PROC_VERSION "/proc/version"
185 static int __get_kern_ver()
194 util_retv_if(kern_ver != 0, kern_ver);
198 strncpy(buf, nm.release, sizeof(buf));
200 ret = sscanf(buf, "%d.%d.%d", &v1, &v2, &v3);
202 __read_proc(PROC_VERSION, buf, sizeof(buf));
204 ret = sscanf(buf, "Linux version %d.%d.%d", &v1, &v2, &v3);
208 kern_ver = KERNEL_VERSION(v1, v2, v3);
215 static void __clear_nslot_list(GList *g_ns)
220 for (it = g_ns; it != NULL; it = g_list_next(it)) {
221 t = (struct noti_slot *)it->data;
227 static struct noti_cont *__get_noti_cont(int fd)
229 struct noti_cont *r = NULL;
232 for (it = g_nc; it != NULL; it = g_list_next(it)) {
234 r = (struct noti_cont *)it->data;
246 static int __handle_callback(struct noti_cont *nc, int wd, uint32_t mask)
254 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
255 t = (struct noti_slot *)it->data;
257 if ((mask & t->mask) && t->cb) {
266 static int __handle_event(int fd)
269 struct inotify_event ie;
270 char name[FILENAME_MAX];
272 struct noti_cont *nc;
274 nc = __get_noti_cont(fd);
275 util_warn_if(nc == NULL, "Non-registered file descriptor");
277 r = read(fd, &ie, sizeof(ie));
281 __handle_callback(nc, ie.wd, ie.mask);
284 read(fd, name, ie.len);
286 r = read(fd, &ie, sizeof(ie));
292 API int heynoti_poll_event(int fd)
295 struct noti_cont *nc;
296 struct pollfd fds[1];
298 nc = __get_noti_cont(fd);
300 UTIL_ERR("Non-registered file descriptor : %d", fd);
305 if (nc->ht != H_NONE) {
306 UTIL_ERR("Another handler already in progress");
312 fds[0].events = POLLIN;
314 r = poll(fds, 1, -1);
315 util_retvm_if(r == -1, -1, "Error: poll : %s", strerror(errno));
317 if (fds[0].revents & POLLIN)
323 static inline int __get_wd(int fd, const char *notipath)
325 return inotify_add_watch(fd, notipath, IN_ACCESS);
328 static int __add_wd(struct noti_cont *nc, int wd, uint32_t mask,
329 const char *notipath)
337 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
338 t = (struct noti_slot *)it->data;
346 r = inotify_add_watch(nc->fd, notipath, mask_all);
350 static int __add_noti(int fd, const char *notipath, void (*cb) (void *),
351 void *data, uint32_t mask)
355 struct noti_cont *nc;
356 struct noti_slot t, *n;
357 struct noti_slot *f = NULL;
360 nc = __get_noti_cont(fd);
362 UTIL_DBG("Bad file descriptor");
367 __make_noti_file(notipath);
369 wd = __get_wd(fd, notipath);
370 util_retvm_if(wd == -1, -1, "Error: add noti: %s", strerror(errno));
372 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
374 f = (struct noti_slot *)it->data;
375 if (f->wd == wd && f->cb == cb) {
384 __add_wd(nc, wd, 0, notipath);
389 r = __add_wd(nc, wd, mask, notipath);
390 util_retvm_if(r == -1, -1, "Error: add noti: %s", strerror(errno));
392 n = calloc(1, sizeof(nslot));
393 util_retvm_if(n == NULL, -1, "Error: add noti: %s", strerror(errno));
399 nc->g_ns = g_list_append(nc->g_ns, (gpointer) n);
404 API int heynoti_subscribe_file(int fd, const char *path, void (*cb) (void *),
405 void *data, uint32_t mask)
407 if (path == NULL || cb == NULL) {
408 UTIL_DBG("Error: add noti: Invalid input");
413 return __add_noti(fd, path, cb, data, mask);
416 API int heynoti_subscribe(int fd, const char *noti, void (*cb) (void *),
419 char notipath[FILENAME_MAX];
421 if (noti == NULL || cb == NULL) {
422 UTIL_DBG("Error: add noti: Invalid input");
427 __make_noti_path(notipath, sizeof(notipath), noti);
428 UTIL_DBG("add watch: [%s]", notipath);
430 return __add_noti(fd, notipath, cb, data, IN_CLOSE_WRITE | IN_DELETE);
433 static int _del_noti(struct noti_cont *nc, int wd, void (*cb) (void *),
434 const char *notipath)
451 t = (struct noti_slot *)it->data;
453 if (cb == NULL || cb == t->cb) {
454 nc->g_ns = g_list_remove(nc->g_ns, t);
467 return inotify_rm_watch(nc->fd, wd);
469 r = __add_wd(nc, wd, 0, notipath);
472 UTIL_DBG("Error: nothing deleted");
480 static int del_noti(int fd, const char *notipath, void (*cb) (void *))
483 struct noti_cont *nc;
485 nc = __get_noti_cont(fd);
487 UTIL_DBG("Bad file descriptor");
493 wd = __get_wd(fd, notipath);
494 util_retv_if(wd == -1, -1);
496 return _del_noti(nc, wd, cb, notipath);
499 API int heynoti_unsubscribe(int fd, const char *noti, void (*cb) (void *))
502 char notipath[FILENAME_MAX];
504 if (fd < 0 || noti == NULL) {
509 __make_noti_path(notipath, sizeof(notipath), noti);
510 UTIL_DBG("del watch: [%s]", notipath);
512 r = del_noti(fd, notipath, cb);
513 util_warn_if(r == -1, "Error: del [%s]: %s", noti, strerror(errno));
518 API int heynoti_unsubscribe_file(int fd, const char *path, void (*cb) (void *))
522 if (fd < 0 || path == NULL) {
527 r = del_noti(fd, path, cb);
528 util_warn_if(r == -1, "Error: del [%s]: %s", path, strerror(errno));
533 API int heynoti_publish(const char *noti)
537 char notipath[FILENAME_MAX];
541 UTIL_DBG("Error: send noti: Invalid input");
546 path = strstr(noti, "/");
548 snprintf(notipath, sizeof(notipath), "%s", noti);
550 __make_noti_path(notipath, sizeof(notipath), noti);
552 UTIL_DBG("send noti: [%s]", notipath);
554 #ifdef NODAC_PERMISSION
555 fd = open(notipath, O_CREAT | O_TRUNC | O_RDWR, 0666);
557 fd = open(notipath, O_CREAT | O_TRUNC | O_RDWR, 0644);
559 util_retvm_if(fd == -1, -1, "Error: send noti: %s", strerror(errno));
563 if(sb.st_uid != getuid())
564 fchown(fd, getuid(), getgid());
565 if(sb.st_mode & 0033)
568 #ifdef NODAC_PERMISSION
576 API int heynoti_init()
581 struct noti_cont *nc;
583 if (__get_kern_ver() < KERNEL_VERSION(2, 6, 13)) {
584 UTIL_ERR("inotify requires kernel version >= 2.6.13 ");
590 util_retvm_if(fd == -1, -1, "inotify init: %s", strerror(errno));
592 fcntl(fd, F_SETFD, FD_CLOEXEC);
593 fcntl(fd, F_SETFL, O_NONBLOCK);
595 r = __make_noti_root(noti_root);
597 UTIL_ERR("make noti root: %s : %s", noti_root, strerror(errno));
602 nc = calloc(1, sizeof(struct noti_cont));
609 /*sglib_ncont_add(&nc_h, nc); */
610 g_nc = g_list_append(g_nc, (gpointer) nc);
615 API int heynoti_get_pnoti_name(pid_t pid, const char *name, char *buf,
623 ret = snprintf(buf, buf_size, ".%d_%s", pid, name);
631 API int heynoti_get_snoti_name(const char *name, char *buf, int buf_size)
638 ret = snprintf(buf, buf_size, ".%s_%s", AU_PREFIX_SYSNOTI, name);
646 gboolean gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
650 /* need condition check?? */
652 fd = g_io_channel_unix_get_fd(src);
658 API int heynoti_attach_handler(int fd)
661 struct noti_cont *nc = NULL;
665 nc = __get_noti_cont(fd);
667 UTIL_ERR("Non-registered file descriptor : %d", fd);
677 UTIL_ERR("glib based handler now in progress");
681 UTIL_ERR("Another handler already in progress: %d", nc->ht);
685 util_retv_if(nc->ht != H_NONE, -1);
687 gio = g_io_channel_unix_new(fd);
688 util_retvm_if(gio == NULL, -1, "Error: create a new GIOChannel");
690 g_io_channel_set_flags(gio, G_IO_FLAG_NONBLOCK, NULL);
692 src = g_io_create_watch(gio, G_IO_IN);
693 g_source_set_callback(src, (GSourceFunc) gio_cb, NULL, NULL);
694 ret = g_source_attach(src, NULL);
695 g_io_channel_unref(gio);
706 API int heynoti_detach_handler(int fd)
708 struct noti_cont *nc = NULL;
710 nc = __get_noti_cont(fd);
712 UTIL_ERR("Non-registered file descriptor : %d", fd);
719 g_source_destroy(nc->handler);
731 API void heynoti_close(int fd)
733 struct noti_cont *r = NULL;
735 r = __get_noti_cont(fd);
736 util_warn_if(r == NULL, "Non-registered file descriptor");
740 heynoti_detach_handler(fd);
742 __clear_nslot_list(r->g_ns);
743 g_list_free(r->g_ns);
746 g_nc = g_list_remove(g_nc, (gconstpointer) r);