replace strerr*() functions with %m format for thread-safety
[platform/core/uifw/pepper.git] / src / lib / inotify / pepper-inotify.c
1 /*
2 * Copyright © 2015-2017 Samsung Electronics co., Ltd. All Rights Reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #define _GNU_SOURCE
25
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <stdint.h>
33 #include <dirent.h>
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <linux/input.h>
37 #include <sys/inotify.h>
38
39 #include <pepper-inotify-internal.h>
40
41 static void
42 _inotify_event_post(pepper_inotify_watch_t *watch, pepper_inotify_event_type_t type, const char *name, pepper_bool_t is_dir)
43 {
44         pepper_inotify_event_t ev;
45
46         PEPPER_CHECK(watch->inotify->callback.cb, return, "Current inotify has no callback");
47
48         ev.inotify = watch->inotify;
49
50         ev.name = (char *)name;
51         ev.is_dir = is_dir;
52         ev.path = watch->path;
53
54         watch->inotify->callback.cb(type, &ev, watch->inotify->callback.data);
55 }
56
57 static void
58 _inotify_event_process(struct inotify_event *ev, pepper_inotify_watch_t *watch)
59 {
60         if (!ev->len) return;
61
62         if (ev->mask & IN_CREATE) {
63                 _inotify_event_post(watch, PEPPER_INOTIFY_EVENT_TYPE_CREATE,
64                                         ev->name, (ev->mask & IN_ISDIR) ? PEPPER_TRUE : PEPPER_FALSE);
65         }
66         else if (ev->mask & IN_DELETE) {
67                 _inotify_event_post(watch, PEPPER_INOTIFY_EVENT_TYPE_REMOVE,
68                                         ev->name, (ev->mask & IN_ISDIR) ? PEPPER_TRUE : PEPPER_FALSE);
69         }
70         else if (ev->mask & IN_MODIFY) {
71                 _inotify_event_post(watch, PEPPER_INOTIFY_EVENT_TYPE_MODIFY,
72                                         ev->name, (ev->mask & IN_ISDIR) ? PEPPER_TRUE : PEPPER_FALSE);
73         }
74 }
75
76 static int
77 _inotify_fd_read(int fd, uint32_t mask, void *data)
78 {
79         uint32_t i;
80         int nread;
81         struct inotify_event ev[32];
82         pepper_inotify_watch_t *watch_data = data;
83
84         PEPPER_CHECK(!(mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)),
85                         return 0,
86                         "[%s] With the given fd, there is an error or it's been hung-up.\n",
87                         __FUNCTION__);
88
89         if (!(mask & WL_EVENT_READABLE))
90                 return 0;
91
92         nread = read(fd, &ev, sizeof(ev));
93         PEPPER_CHECK(nread >= 0, return 0,
94                         "Failed on reading given fd. (error msg : %m, fd:%d)\n", fd);
95
96         for (i = 0 ; i < (nread / sizeof(ev[0])); i++) {
97                 if (ev[i].wd == watch_data->wd)
98                         _inotify_event_process(&ev[i], watch_data);
99         }
100
101         return 0;
102 }
103
104 PEPPER_API char *
105 pepper_inotify_event_name_get(pepper_inotify_event_t *ev)
106 {
107         PEPPER_CHECK(ev, return NULL,
108                         "Invalid inotify event\n");
109
110         return ev->name;
111 }
112
113 PEPPER_API char *
114 pepper_inotify_event_path_get(pepper_inotify_event_t *ev)
115 {
116         PEPPER_CHECK(ev, return NULL,
117                         "Invalid inotify event\n");
118
119         return ev->path;
120 }
121
122 PEPPER_API pepper_bool_t
123 pepper_inotify_event_is_directory(pepper_inotify_event_t *ev)
124 {
125         PEPPER_CHECK(ev, return PEPPER_FALSE,
126                         "Invalid inotify event\n");
127
128         return ev->is_dir;
129 }
130
131 PEPPER_API pepper_bool_t
132 pepper_inotify_add(pepper_inotify_t *inotify, const char *path)
133 {
134         pepper_inotify_watch_t *watch_data;
135
136         PEPPER_CHECK(inotify, return PEPPER_FALSE, "Invalid pepper_inotify_t object\n");
137         PEPPER_CHECK(path, return PEPPER_FALSE, "Invalid path\n");
138
139         watch_data = (pepper_inotify_watch_t *)calloc(1, sizeof(pepper_inotify_watch_t));
140         PEPPER_CHECK(watch_data, return PEPPER_FALSE,
141                 "Failed to allocate pepper_inotify_watch_t\n");
142
143         watch_data->inotify = inotify;
144
145         watch_data->wd = inotify_add_watch(inotify->fd, path,
146                         IN_MODIFY | IN_CREATE | IN_DELETE | IN_MOVED_FROM | IN_MOVED_TO | IN_MOVE_SELF);
147         PEPPER_CHECK(watch_data->wd >= 0, goto failed,
148                         "Failed to add watch for %s (error msg:%m)\n", path);
149
150         strncpy(watch_data->path, path, MAX_PATH_LEN - 1);
151
152         watch_data->event_source = wl_event_loop_add_fd(inotify->event_loop, inotify->fd,
153                         WL_EVENT_READABLE, _inotify_fd_read, watch_data);
154         PEPPER_CHECK(watch_data->event_source, goto failed,
155                         "Failed to add fd as an event source.\n");
156
157         pepper_list_insert(&inotify->watched_list, &watch_data->link);
158
159         return PEPPER_TRUE;
160
161 failed:
162         if (watch_data->event_source)
163                 wl_event_source_remove(watch_data->event_source);
164         if (watch_data->wd)
165                 inotify_rm_watch(inotify->fd, watch_data->wd);
166         free(watch_data);
167
168         return PEPPER_FALSE;
169 }
170
171 PEPPER_API void
172 pepper_inotify_del(pepper_inotify_t *inotify, const char *path)
173 {
174         pepper_inotify_watch_t *watch_data, *watch_data_tmp;
175
176         PEPPER_CHECK(inotify, return, "Invalid pepper_inotify_t object\n");
177         PEPPER_CHECK(path, return, "Invalid path\n");
178
179         if (!pepper_list_empty(&inotify->watched_list))
180         {
181                 pepper_list_for_each_safe(watch_data, watch_data_tmp, &inotify->watched_list, link)
182                 {
183                         if (!strncmp(watch_data->path, path, MAX_PATH_LEN - 1))
184                         {
185                                 if (watch_data->wd)
186                                         inotify_rm_watch(inotify->fd, watch_data->wd);
187                                 if (watch_data->event_source)
188                                         wl_event_source_remove(watch_data->event_source);
189                                 pepper_list_remove(&watch_data->link);
190                                 free(watch_data);
191                                 break;
192                         }
193                 }
194         }
195 }
196
197 PEPPER_API pepper_inotify_t *
198 pepper_inotify_create(pepper_compositor_t *compositor, pepper_inotify_event_cb_t cb, void *data)
199 {
200         pepper_inotify_t *inotify;
201
202         PEPPER_CHECK(compositor, return NULL, "Invalid compositor object\n");
203
204         inotify = (pepper_inotify_t *)calloc(1, sizeof(pepper_inotify_t));
205         PEPPER_CHECK(inotify, return NULL, "Failed to allocate pepper_inotify_t\n");
206
207         inotify->display = pepper_compositor_get_display(compositor);
208         PEPPER_CHECK(inotify->display, goto failed, "Invaild wl_display\n");
209
210         inotify->event_loop = wl_display_get_event_loop(inotify->display);
211         PEPPER_CHECK(inotify->event_loop, goto failed, "Invaild wl_event_loop\n");
212
213         inotify->fd = inotify_init();
214         PEPPER_CHECK(inotify->fd >= 0, goto failed, "Failed to init inotify. fd: %d\n", inotify->fd);
215
216         inotify->callback.cb = cb;
217         inotify->callback.data = data;
218
219         pepper_list_init(&inotify->watched_list);
220
221         return inotify;
222
223 failed:
224         if (inotify) {
225                 if (inotify->fd)
226                         close(inotify->fd);
227                 free(inotify);
228         }
229         return NULL;
230 }
231
232 PEPPER_API void
233 pepper_inotify_destroy(pepper_inotify_t *inotify)
234 {
235         pepper_inotify_watch_t *watch_data, *watch_data_tmp;
236
237         PEPPER_CHECK(inotify, return, "Invalid pepper_inotify_t object\n");
238
239         if (!pepper_list_empty(&inotify->watched_list))
240         {
241                 pepper_list_for_each_safe(watch_data, watch_data_tmp, &inotify->watched_list, link)
242                 {
243                         if (watch_data->wd)
244                                 inotify_rm_watch(inotify->fd, watch_data->wd);
245                         if (watch_data->event_source)
246                                 wl_event_source_remove(watch_data->event_source);
247
248                         pepper_list_remove(&watch_data->link);
249                         free(watch_data);
250                 }
251
252                 pepper_list_remove(&inotify->watched_list);
253         }
254
255         if (inotify->fd)
256                 close(inotify->fd);
257
258         free(inotify);
259         inotify = NULL;
260 }
261