udev: change the name of udev monitor buffer size
[platform/hal/backend/device-common.git] / src / udev / udev.c
1 /*
2  * Copyright (c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17
18 #include <stdio.h>
19 #include <stdbool.h>
20 #include <errno.h>
21 #include <libudev.h>
22 #include <glib.h>
23 #include <string.h>
24
25 #include "hal-backend-common-udev.h"
26 #include "hal-backend-common.h"
27
28 #define EVENT_KERNEL       "kernel"
29 #define EVENT_UDEV         "udev"
30
31 #define UDEV_MONITOR_BUFFER_SIZE   (128*1024)
32
33 struct uevent_info {
34         struct udev_monitor *mon;
35         GIOChannel *ch;
36         guint eventid;
37         GList *event_list;
38         int ref;
39         struct udev *udev;
40 };
41
42
43 /* Uevent */
44 static struct uevent_info kevent; /* kernel */
45 static struct uevent_info uevent; /* udev */
46
47 static gboolean uevent_control_cb(GIOChannel *channel,
48                 GIOCondition cond, void *data)
49 {
50         struct uevent_info *info = data;
51         struct udev_device *dev;
52         struct uevent_handler *l;
53         GList *elem;
54         const char *subsystem;
55         int len;
56
57         if (!info) {
58                 _E("data is invalid");
59                 return TRUE;
60         }
61
62         dev = udev_monitor_receive_device(info->mon);
63         if (!dev)
64                 return TRUE;
65
66         subsystem = udev_device_get_subsystem(dev);
67         if (!subsystem)
68                 goto out;
69
70         len = strlen(subsystem);
71
72         for (elem = info->event_list ; elem ; elem = g_list_next(elem)) {
73                 l = elem->data;
74                 if (!l)
75                         continue;
76                 if (!strncmp(l->subsystem, subsystem, len) &&
77                     l->uevent_func)
78                         l->uevent_func(dev);
79         }
80
81 out:
82         udev_device_unref(dev);
83         return TRUE;
84 }
85
86 static int uevent_control_stop(struct uevent_info *info)
87 {
88         struct udev_device *dev;
89
90         if (!info)
91                 return -EINVAL;
92
93         if (--info->ref > 0)
94                 return 0;
95
96         if (info->eventid) {
97                 g_source_remove(info->eventid);
98                 info->eventid = 0;
99         }
100         if (info->ch) {
101                 g_io_channel_unref(info->ch);
102                 info->ch = NULL;
103         }
104         if (info->mon) {
105                 dev = udev_monitor_receive_device(info->mon);
106                 if (dev)
107                         udev_device_unref(dev);
108                 udev_monitor_unref(info->mon);
109                 info->mon = NULL;
110         }
111         if (info->udev)
112                 info->udev = udev_unref(info->udev);
113
114         return 0;
115 }
116
117 static int uevent_control_start(const char *type,
118                 struct uevent_info *info)
119 {
120         int fd;
121         int ret;
122
123         if (!info)
124                 return -EINVAL;
125
126         if (!info->udev) {
127                 info->udev = udev_new();
128                 if (!info->udev) {
129                         _E("error create udev");
130                         return -EINVAL;
131                 }
132                 info->ref = 1;
133         } else {
134                 ++info->ref;
135                 return 0;
136         }
137
138         info->mon = udev_monitor_new_from_netlink(info->udev, type);
139         if (info->mon == NULL) {
140                 _E("error udev_monitor create");
141                 goto stop;
142         }
143
144         _I("Set udev monitor buffer size %d", UDEV_MONITOR_BUFFER_SIZE);
145         ret = udev_monitor_set_receive_buffer_size(info->mon,
146                         UDEV_MONITOR_BUFFER_SIZE);
147         if (ret != 0) {
148                 _E("fail to set receive buffer size");
149                 goto stop;
150         }
151
152         fd = udev_monitor_get_fd(info->mon);
153         if (fd == -1) {
154                 _E("error udev_monitor_get_fd");
155                 goto stop;
156         }
157
158         info->ch = g_io_channel_unix_new(fd);
159         info->eventid = g_io_add_watch(info->ch,
160                         G_IO_IN, uevent_control_cb, info);
161         if (info->eventid == 0) {
162                 _E("Failed to add channel watch");
163                 goto stop;
164         }
165
166         if (udev_monitor_enable_receiving(info->mon) < 0) {
167                 _E("error unable to subscribe to udev events");
168                 goto stop;
169         }
170
171         return 0;
172 stop:
173         uevent_control_stop(info);
174         return -EINVAL;
175 }
176
177 EXPORT int uevent_control_kernel_start(void)
178 {
179         return uevent_control_start(EVENT_KERNEL, &kevent);
180 }
181
182 EXPORT void uevent_control_kernel_stop(void)
183 {
184         uevent_control_stop(&kevent);
185 }
186
187 EXPORT int uevent_control_udev_start(void)
188 {
189         return uevent_control_start(EVENT_UDEV, &uevent);
190 }
191
192 EXPORT void uevent_control_udev_stop(void)
193 {
194         uevent_control_stop(&uevent);
195 }
196
197 static int register_uevent_control(struct uevent_info *info,
198                 struct uevent_handler *uh)
199 {
200         struct uevent_handler *l;
201         GList *elem;
202         int r;
203         int len;
204
205         if (!info || !uh || !uh->subsystem)
206                 return -EINVAL;
207
208         /* if udev is not initialized, it just will be added list */
209         if (!info->udev || !info->mon)
210                 goto add_list;
211
212         len = strlen(uh->subsystem);
213         /* check if the same subsystem is already added */
214         for (elem = info->event_list; elem ; elem = g_list_next(elem)) {
215                 l = elem->data;
216                 if (!strncmp(l->subsystem, uh->subsystem, len))
217                         goto add_list;
218         }
219
220         /* the first request to add subsystem */
221         r = udev_monitor_filter_add_match_subsystem_devtype(info->mon,
222                         uh->subsystem, NULL);
223         if (r < 0) {
224                 _E("fail to add %s subsystem : %d", uh->subsystem, r);
225                 return -EPERM;
226         }
227
228         r = udev_monitor_filter_update(info->mon);
229         if (r < 0)
230                 _E("fail to update udev monitor filter : %d", r);
231
232 add_list:
233         info->event_list = g_list_append(info->event_list, uh);
234         return 0;
235 }
236
237 static int unregister_uevent_control(struct uevent_info *info,
238                 const struct uevent_handler *uh)
239 {
240         struct uevent_handler *l;
241         GList *n, *next;
242         int len;
243
244         if (!info || !uh || !uh->subsystem)
245                 return -EINVAL;
246
247         len = strlen(uh->subsystem);
248         for (n = info->event_list, next = g_list_next(n) ;
249                         n ; n = next, next = g_list_next(n)) {
250                 l = n->data;
251                 if (!strncmp(l->subsystem, uh->subsystem, len) &&
252                     l->uevent_func == uh->uevent_func) {
253                         info->event_list = g_list_delete_link(info->event_list, n);
254                         return 0;
255                 }
256         }
257
258         return -ENOENT;
259 }
260
261 EXPORT int register_kernel_event_control(struct uevent_handler *uh)
262 {
263         return register_uevent_control(&kevent, uh);
264 }
265
266 EXPORT void unregister_kernel_event_control(struct uevent_handler *uh)
267 {
268         unregister_uevent_control(&kevent, uh);
269 }
270
271 EXPORT int register_udev_event_control(struct uevent_handler *uh)
272 {
273         return register_uevent_control(&uevent, uh);
274 }
275
276 EXPORT void unregister_udev_event_control(struct uevent_handler *uh)
277 {
278         unregister_uevent_control(&uevent, uh);
279 }