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 "/opt/share/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 void __clear_nslot_list(GList *g_ns);
64 static struct noti_cont *__get_noti_cont(int fd);
65 static int __handle_callback(struct noti_cont *nc, int wd, uint32_t mask);
66 static int __handle_event(int fd);
67 static inline int __get_wd(int fd, const char *notipath);
68 static int __add_wd(struct noti_cont *nc, int wd, uint32_t mask,
69 const char *notipath);
70 static int __add_noti(int fd, const char *notipath, void (*cb) (void *),
71 void *data, uint32_t mask);
72 static int _del_noti(struct noti_cont *nc, int wd, void (*cb) (void *),
73 const char *notipath);
74 static int del_noti(int fd, const char *notipath, void (*cb) (void *));
77 int slot_comp(struct noti_slot *a, struct noti_slot *b)
85 r = (int)(a->cb - b->cb);
103 struct sigaction oldact;
107 typedef struct noti_cont ncont;
109 static const char *noti_root = NOTI_ROOT;
112 static int __make_noti_root(const char *p)
116 if ((fd = open(p, O_RDONLY)) == -1 )
124 static int __make_noti_file(const char *p)
128 if ((fd = open(p, O_RDONLY)) == -1)
136 static inline int __make_noti_path(char *path, int size, const char *name)
138 return snprintf(path, size, "%s/%s", noti_root, name);
141 static int __read_proc(const char *path, char *buf, int size)
146 if (buf == NULL || path == NULL) {
147 UTIL_DBG("%s: path or buf is NULL\n", __func__);
152 fd = open(path, O_RDONLY);
153 util_retvm_if(fd == -1, -1, "File open error: %s", strerror(errno));
155 memset(buf, 0x0, size);
156 ret = read(fd, buf, size);
162 #define PROC_VERSION "/proc/version"
164 static int __check_kern_ver()
175 strncpy(buf, nm.release, sizeof(buf));
177 ret = sscanf(buf, "%d.%d.%d", &v1, &v2, &v3);
179 __read_proc(PROC_VERSION, buf, sizeof(buf));
181 ret = sscanf(buf, "Linux version %d.%d.%d", &v1, &v2, &v3);
185 if(KERNEL_VERSION(v1, v2, v3) < KERNEL_VERSION(2, 6, 13)) {
195 static void __clear_nslot_list(GList *g_ns)
200 for (it = g_ns; it != NULL; it = g_list_next(it)) {
201 t = (struct noti_slot *)it->data;
207 static struct noti_cont *__get_noti_cont(int fd)
209 struct noti_cont *r = NULL;
212 for (it = g_nc; it != NULL; it = g_list_next(it)) {
214 r = (struct noti_cont *)it->data;
226 static int __handle_callback(struct noti_cont *nc, int wd, uint32_t mask)
234 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
235 t = (struct noti_slot *)it->data;
237 if ((mask & t->mask) && t->cb) {
246 static int __handle_event(int fd)
249 struct inotify_event ie;
250 char name[FILENAME_MAX] = {0, };
252 struct noti_cont *nc;
254 nc = __get_noti_cont(fd);
255 util_warn_if(nc == NULL, "Non-registered file descriptor");
257 r = read(fd, &ie, sizeof(ie));
261 __handle_callback(nc, ie.wd, ie.mask);
263 if(ie.len > SSIZE_MAX)
267 read(fd, name, (ie.len > FILENAME_MAX) ? (size_t)FILENAME_MAX : (size_t) ie.len);
270 r = read(fd, &ie, sizeof(ie));
276 API int heynoti_poll_event(int fd)
279 struct noti_cont *nc;
280 struct pollfd fds[1];
282 nc = __get_noti_cont(fd);
284 UTIL_ERR("Non-registered file descriptor : %d", fd);
289 if (nc->ht != H_NONE) {
290 UTIL_ERR("Another handler already in progress");
296 fds[0].events = POLLIN;
298 r = poll(fds, 1, -1);
299 util_retvm_if(r == -1, -1, "Error: poll : %s", strerror(errno));
301 if (fds[0].revents & POLLIN)
307 static inline int __get_wd(int fd, const char *notipath)
309 return inotify_add_watch(fd, notipath, IN_ACCESS);
312 static int __add_wd(struct noti_cont *nc, int wd, uint32_t mask,
313 const char *notipath)
321 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
322 t = (struct noti_slot *)it->data;
330 r = inotify_add_watch(nc->fd, notipath, mask_all);
334 static int __add_noti(int fd, const char *notipath, void (*cb) (void *),
335 void *data, uint32_t mask)
339 struct noti_cont *nc;
340 struct noti_slot t, *n;
341 struct noti_slot *f = NULL;
344 nc = __get_noti_cont(fd);
346 UTIL_DBG("Bad file descriptor");
351 wd = __get_wd(fd, notipath);
352 util_retvm_if(wd == -1, -1, "Error: add noti: %s", strerror(errno));
354 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
356 f = (struct noti_slot *)it->data;
357 if (f->wd == wd && f->cb == cb) {
366 __add_wd(nc, wd, 0, notipath);
371 r = __add_wd(nc, wd, mask, notipath);
372 util_retvm_if(r == -1, -1, "Error: add noti: %s", strerror(errno));
374 n = calloc(1, sizeof(nslot));
375 util_retvm_if(n == NULL, -1, "Error: add noti: %s", strerror(errno));
381 nc->g_ns = g_list_append(nc->g_ns, (gpointer) n);
386 API int heynoti_subscribe(int fd, const char *noti, void (*cb) (void *),
389 char notipath[FILENAME_MAX];
391 if (noti == NULL || cb == NULL) {
392 UTIL_DBG("Error: add noti: Invalid input");
397 __make_noti_path(notipath, sizeof(notipath), noti);
398 UTIL_DBG("add watch: [%s]", notipath);
400 return __add_noti(fd, notipath, cb, data, IN_CLOSE_WRITE | IN_DELETE);
403 static int _del_noti(struct noti_cont *nc, int wd, void (*cb) (void *),
404 const char *notipath)
421 t = (struct noti_slot *)it->data;
423 if (cb == NULL || cb == t->cb) {
424 nc->g_ns = g_list_remove(nc->g_ns, t);
437 return inotify_rm_watch(nc->fd, wd);
439 r = __add_wd(nc, wd, 0, notipath);
442 UTIL_DBG("Error: nothing deleted");
450 static int del_noti(int fd, const char *notipath, void (*cb) (void *))
453 struct noti_cont *nc;
455 nc = __get_noti_cont(fd);
457 UTIL_DBG("Bad file descriptor");
463 wd = __get_wd(fd, notipath);
464 util_retv_if(wd == -1, -1);
466 return _del_noti(nc, wd, cb, notipath);
469 API int heynoti_unsubscribe(int fd, const char *noti, void (*cb) (void *))
472 char notipath[FILENAME_MAX];
474 if (fd < 0 || noti == NULL) {
479 __make_noti_path(notipath, sizeof(notipath), noti);
480 UTIL_DBG("del watch: [%s]", notipath);
482 r = del_noti(fd, notipath, cb);
483 util_warn_if(r == -1, "Error: del [%s]: %s", noti, strerror(errno));
488 API int heynoti_publish(const char *noti)
492 char notipath[FILENAME_MAX];
496 UTIL_DBG("Error: send noti: Invalid input");
501 path = strstr(noti, "/");
503 snprintf(notipath, sizeof(notipath), "%s", noti);
505 __make_noti_path(notipath, sizeof(notipath), noti);
507 UTIL_DBG("send noti: [%s]", notipath);
509 fd = open(notipath, O_TRUNC | O_WRONLY);
511 util_retvm_if(fd == -1, -1, "Error: send noti: %s", strerror(errno));
515 if(sb.st_uid != getuid())
516 fchown(fd, getuid(), getgid());
517 if(sb.st_mode & 0033)
525 API int heynoti_init()
530 struct noti_cont *nc;
532 if(__check_kern_ver() < 0) {
533 UTIL_ERR("inotify requires kernel version >= 2.6.13 ");
539 util_retvm_if(fd == -1, -1, "inotify init: %s", strerror(errno));
541 r = fcntl(fd, F_SETFD, FD_CLOEXEC);
542 util_retvm_if(r < 0, -1, "fcntl error : %s", strerror(errno));
543 r = fcntl(fd, F_SETFL, O_NONBLOCK);
544 util_retvm_if(r < 0, -1, "fcntl error : %s", strerror(errno));
546 r = __make_noti_root(noti_root);
548 UTIL_ERR("make noti root: %s : %s", noti_root, strerror(errno));
553 nc = calloc(1, sizeof(struct noti_cont));
560 /*sglib_ncont_add(&nc_h, nc); */
561 g_nc = g_list_append(g_nc, (gpointer) nc);
566 API int heynoti_get_pnoti_name(pid_t pid, const char *name, char *buf,
574 ret = snprintf(buf, buf_size, ".%d_%s", pid, name);
582 API int heynoti_get_snoti_name(const char *name, char *buf, int buf_size)
589 ret = snprintf(buf, buf_size, ".%s_%s", AU_PREFIX_SYSNOTI, name);
597 gboolean gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
601 /* need condition check?? */
603 fd = g_io_channel_unix_get_fd(src);
609 API int heynoti_attach_handler(int fd)
612 struct noti_cont *nc = NULL;
616 nc = __get_noti_cont(fd);
618 UTIL_ERR("Non-registered file descriptor : %d", fd);
628 UTIL_ERR("glib based handler now in progress");
632 UTIL_ERR("Another handler already in progress: %d", nc->ht);
636 util_retv_if(nc->ht != H_NONE, -1);
638 gio = g_io_channel_unix_new(fd);
639 util_retvm_if(gio == NULL, -1, "Error: create a new GIOChannel");
641 g_io_channel_set_flags(gio, G_IO_FLAG_NONBLOCK, NULL);
643 src = g_io_create_watch(gio, G_IO_IN);
644 g_source_set_callback(src, (GSourceFunc) gio_cb, NULL, NULL);
645 ret = g_source_attach(src, NULL);
646 g_io_channel_unref(gio);
657 API int heynoti_detach_handler(int fd)
659 struct noti_cont *nc = NULL;
661 nc = __get_noti_cont(fd);
663 UTIL_ERR("Non-registered file descriptor : %d", fd);
670 g_source_destroy(nc->handler);
682 API void heynoti_close(int fd)
684 struct noti_cont *r = NULL;
686 r = __get_noti_cont(fd);
687 util_warn_if(r == NULL, "Non-registered file descriptor");
691 heynoti_detach_handler(fd);
693 __clear_nslot_list(r->g_ns);
694 g_list_free(r->g_ns);
697 g_nc = g_list_remove(g_nc, (gconstpointer) r);