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 r = read(fd, name, (ie.len > FILENAME_MAX) ? (size_t)FILENAME_MAX : (size_t) ie.len);
273 r = read(fd, &ie, sizeof(ie));
280 API int heynoti_poll_event(int fd)
283 struct noti_cont *nc;
284 struct pollfd fds[1];
286 nc = __get_noti_cont(fd);
288 UTIL_ERR("Non-registered file descriptor : %d", fd);
293 if (nc->ht != H_NONE) {
294 UTIL_ERR("Another handler already in progress");
300 fds[0].events = POLLIN;
302 r = poll(fds, 1, -1);
303 util_retvm_if(r == -1, -1, "Error: poll : %s", strerror(errno));
305 if (fds[0].revents & POLLIN)
311 static inline int __get_wd(int fd, const char *notipath)
313 return inotify_add_watch(fd, notipath, IN_ACCESS);
316 static int __add_wd(struct noti_cont *nc, int wd, uint32_t mask,
317 const char *notipath)
325 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
326 t = (struct noti_slot *)it->data;
334 r = inotify_add_watch(nc->fd, notipath, mask_all);
338 static int __add_noti(int fd, const char *notipath, void (*cb) (void *),
339 void *data, uint32_t mask)
343 struct noti_cont *nc;
344 struct noti_slot t, *n;
345 struct noti_slot *f = NULL;
348 nc = __get_noti_cont(fd);
350 UTIL_DBG("Bad file descriptor");
355 wd = __get_wd(fd, notipath);
356 util_retvm_if(wd == -1, -1, "Error: add noti: %s", strerror(errno));
358 for (it = nc->g_ns; it != NULL; it = g_list_next(it)) {
360 f = (struct noti_slot *)it->data;
361 if (f->wd == wd && f->cb == cb) {
370 __add_wd(nc, wd, 0, notipath);
375 r = __add_wd(nc, wd, mask, notipath);
376 util_retvm_if(r == -1, -1, "Error: add noti: %s", strerror(errno));
378 n = calloc(1, sizeof(nslot));
379 util_retvm_if(n == NULL, -1, "Error: add noti: %s", strerror(errno));
385 nc->g_ns = g_list_append(nc->g_ns, (gpointer) n);
390 API int heynoti_subscribe(int fd, const char *noti, void (*cb) (void *),
393 char notipath[FILENAME_MAX];
395 if (noti == NULL || cb == NULL) {
396 UTIL_DBG("Error: add noti: Invalid input");
401 __make_noti_path(notipath, sizeof(notipath), noti);
402 UTIL_DBG("add watch: [%s]", notipath);
404 return __add_noti(fd, notipath, cb, data, IN_CLOSE_WRITE | IN_DELETE);
407 static int _del_noti(struct noti_cont *nc, int wd, void (*cb) (void *),
408 const char *notipath)
425 t = (struct noti_slot *)it->data;
427 if (cb == NULL || cb == t->cb) {
428 nc->g_ns = g_list_remove(nc->g_ns, t);
441 return inotify_rm_watch(nc->fd, wd);
443 r = __add_wd(nc, wd, 0, notipath);
446 UTIL_DBG("Error: nothing deleted");
454 static int del_noti(int fd, const char *notipath, void (*cb) (void *))
457 struct noti_cont *nc;
459 nc = __get_noti_cont(fd);
461 UTIL_DBG("Bad file descriptor");
467 wd = __get_wd(fd, notipath);
468 util_retv_if(wd == -1, -1);
470 return _del_noti(nc, wd, cb, notipath);
473 API int heynoti_unsubscribe(int fd, const char *noti, void (*cb) (void *))
476 char notipath[FILENAME_MAX];
478 if (fd < 0 || noti == NULL) {
483 __make_noti_path(notipath, sizeof(notipath), noti);
484 UTIL_DBG("del watch: [%s]", notipath);
486 r = del_noti(fd, notipath, cb);
487 util_warn_if(r == -1, "Error: del [%s]: %s", noti, strerror(errno));
492 API int heynoti_publish(const char *noti)
496 char notipath[FILENAME_MAX];
500 UTIL_DBG("Error: send noti: Invalid input");
505 path = strstr(noti, "/");
507 snprintf(notipath, sizeof(notipath), "%s", noti);
509 __make_noti_path(notipath, sizeof(notipath), noti);
511 UTIL_DBG("send noti: [%s]", notipath);
513 fd = open(notipath, O_TRUNC | O_WRONLY);
515 util_retvm_if(fd == -1, -1, "Error: send noti: %s", strerror(errno));
519 if(sb.st_uid != getuid())
520 fchown(fd, getuid(), getgid());
521 if(sb.st_mode & 0033)
529 API int heynoti_init()
534 struct noti_cont *nc;
536 if(__check_kern_ver() < 0) {
537 UTIL_ERR("inotify requires kernel version >= 2.6.13 ");
543 util_retvm_if(fd == -1, -1, "inotify init: %s", strerror(errno));
545 r = fcntl(fd, F_SETFD, FD_CLOEXEC);
546 util_retvm_if(r < 0, -1, "fcntl error : %s", strerror(errno));
547 r = fcntl(fd, F_SETFL, O_NONBLOCK);
548 util_retvm_if(r < 0, -1, "fcntl error : %s", strerror(errno));
550 r = __make_noti_root(NOTI_ROOT);
552 UTIL_ERR("make noti root: %s : %s", NOTI_ROOT, strerror(errno));
557 nc = calloc(1, sizeof(struct noti_cont));
564 /*sglib_ncont_add(&nc_h, nc); */
565 g_nc = g_list_append(g_nc, (gpointer) nc);
570 API int heynoti_get_pnoti_name(pid_t pid, const char *name, char *buf,
578 ret = snprintf(buf, buf_size, ".%d_%s", pid, name);
586 API int heynoti_get_snoti_name(const char *name, char *buf, int buf_size)
593 ret = snprintf(buf, buf_size, ".%s_%s", AU_PREFIX_SYSNOTI, name);
601 gboolean gio_cb(GIOChannel *src, GIOCondition cond, gpointer data)
605 /* need condition check?? */
607 fd = g_io_channel_unix_get_fd(src);
613 API int heynoti_attach_handler(int fd)
616 struct noti_cont *nc = NULL;
620 nc = __get_noti_cont(fd);
622 UTIL_ERR("Non-registered file descriptor : %d", fd);
632 UTIL_ERR("glib based handler now in progress");
636 UTIL_ERR("Another handler already in progress: %d", nc->ht);
640 util_retv_if(nc->ht != H_NONE, -1);
642 gio = g_io_channel_unix_new(fd);
643 util_retvm_if(gio == NULL, -1, "Error: create a new GIOChannel");
645 g_io_channel_set_flags(gio, G_IO_FLAG_NONBLOCK, NULL);
647 src = g_io_create_watch(gio, G_IO_IN);
648 g_source_set_callback(src, (GSourceFunc) gio_cb, NULL, NULL);
649 ret = g_source_attach(src, NULL);
650 g_io_channel_unref(gio);
661 API int heynoti_detach_handler(int fd)
663 struct noti_cont *nc = NULL;
665 nc = __get_noti_cont(fd);
667 UTIL_ERR("Non-registered file descriptor : %d", fd);
674 g_source_destroy(nc->handler);
686 API void heynoti_close(int fd)
688 struct noti_cont *r = NULL;
690 r = __get_noti_cont(fd);
691 util_warn_if(r == NULL, "Non-registered file descriptor");
695 heynoti_detach_handler(fd);
697 __clear_nslot_list(r->g_ns);
698 g_list_free(r->g_ns);
701 g_nc = g_list_remove(g_nc, (gconstpointer) r);