2c56b54b890241ce9d7d3174d72c07f221a8dcdd
[apps/core/preloaded/usb-manager.git] / src / um_usb_uevent_handler.c
1 /*
2  * usb-manager
3  * Copyright (c) 2012 Samsung Electronics Co., Ltd.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 #include "um_usb_uevent_handler.h"
19
20 #define UEVENT_BUF_MAX (128*1024*1024)
21 #define UDEV_MON_UDEV "udev"
22 #define UDEV_ENTRY_NAME_SUBSYSTEM "SUBSYSTEM"
23 #define UDEV_ENTRY_NAME_ACTION "ACTION"
24 #define UDEV_ENTRY_NAME_DEVTYPE "DEVTYPE"
25 #define UDEV_ENTRY_NAME_DEVNAME "DEVNAME"
26 #define UDEV_ENTRY_NAME_NPARTS "NPARTS"
27 #define UDEV_ENTRY_NAME_ACCESSORY "ACCESSORY"
28
29 #define UDEV_SUBSYSTEM_BLOCK "block"
30 #define UDEV_SUBSYSTEM_USB_DEVICE "usb_device"
31 #define UDEV_SUBSYSTEM_USB "usb"
32 #define UDEV_SUBSYSTEM_MISC "misc"
33 #define UDEV_ACTION_ADD "add"
34 #define UDEV_ACTION_REMOVE "remove"
35 #define UDEV_ACTION_CHANGE "change"
36 #define UDEV_DEVTYPE_DISK "disk"
37 #define UDEV_DEVTYPE_PARTITION "partition"
38 #define UDEV_ACCESSORY_START "START"
39
40 static int um_event_control_get_value_by_name(struct udev_list_entry *list_entry,
41                                                 char *name, char **value)
42 {
43         __USB_FUNC_ENTER__;
44         assert(list_entry);
45         assert(name);
46         assert(value);
47
48         const char *localValue = NULL;
49         struct udev_list_entry *entry_found = NULL;
50         entry_found = udev_list_entry_get_by_name(list_entry, name);
51         if (!entry_found) {
52                 USB_LOG("FAIL: udev_list_entry_get_by_name(%s)", name);
53                 return -1;
54         }
55         localValue = udev_list_entry_get_value(entry_found);
56         if (!localValue) {
57                 USB_LOG("FAIL: udev_list_entry_get_value(%s)", name);
58                 return -1;
59         }
60         USB_LOG("%s: %s", name, localValue);
61
62         *value = strdup(localValue);
63         if (*value == NULL) {
64                 USB_LOG("FAIL: strdup()");
65                 return -1;
66         }
67
68          __USB_FUNC_EXIT__;
69          return 0;
70 }
71
72 static int um_uevent_control_usb_storage_action(UmMainData *ad,
73                                                 char *action,
74                                                 char *devname,
75                                                 char *fstype)
76 {
77         __USB_FUNC_ENTER__;
78         assert(ad);
79         assert(action);
80         assert(devname);
81         assert(fstype);
82
83         if (!strcmp(action, UDEV_ACTION_ADD)) {
84                 USB_LOG("Mass storage is added");
85                 um_uevent_mass_storage_added(ad, (char *)devname, fstype);
86                 __USB_FUNC_EXIT__;
87                 return 0;
88
89         }
90
91         if (!strcmp(action, UDEV_ACTION_REMOVE)) {
92                 USB_LOG("Mass storage is removed");
93                 um_uevent_mass_storage_removed(ad, (char *)devname);
94                 __USB_FUNC_EXIT__;
95                 return 0;
96         }
97
98         USB_LOG("ERROR: Action (%s) is improper", action);
99         __USB_FUNC_EXIT__;
100         return -1;
101 }
102
103 static int um_uevent_control_subsystem_block(UmMainData *ad, struct udev_list_entry *list_entry)
104 {
105         __USB_FUNC_ENTER__;
106         assert(ad);
107         assert(list_entry);
108
109         int ret = -1;
110         char *action = NULL; /* add, remove, ... */
111         char *devname = NULL; /* /dev/sda, /dev/sda1, ... */
112         char *fstype = NULL; /* vfat, ... */
113         char *fsversion = NULL; /* fat, fat32, ntfs, ... */
114
115         ret = um_event_control_get_value_by_name(list_entry, "ID_FS_TYPE", &fstype);
116         if (ret != 0 || !fstype) {
117                 USB_LOG("ERROR: This block device cannot be mounted");
118                 return 0;
119         }
120
121         ret = um_event_control_get_value_by_name(list_entry, "ID_FS_VERSION", &fsversion);
122         if (ret != 0 || !fsversion) {
123                 USB_LOG("ERROR: This block device cannot be mounted");
124                 FREE(fstype);
125                 return 0;
126         }
127
128         /* Getting device name */
129         ret = um_event_control_get_value_by_name(list_entry, UDEV_ENTRY_NAME_DEVNAME, &devname);
130         if (ret != 0 || !devname) {
131                 USB_LOG("FAIL: um_event_control_get_value_by_name()");
132                 goto out_fsversion;
133         }
134         USB_LOG("The device name is %s", devname);
135         if (!strstr(devname, "sd")) {
136                 USB_LOG("ERROR: devname is improper");
137                 goto out_devname;
138         }
139
140         /* Getting device action */
141         ret = um_event_control_get_value_by_name(list_entry, UDEV_ENTRY_NAME_ACTION, &action);
142         if (ret != 0 || !action) {
143                 USB_LOG("FAIL: um_event_control_get_value_by_name()");
144                 goto out_action;
145         }
146         USB_LOG("The action is %s", action);
147
148         ret = um_uevent_control_usb_storage_action(ad, action, devname, fstype);
149         if (ret < 0) {
150                 USB_LOG("FAIL: um_uevent_control_usb_storage_action()");
151                 goto out_action;
152         }
153
154         FREE(fstype);
155         FREE(fsversion);
156         FREE(action);
157         FREE(devname);
158
159         __USB_FUNC_EXIT__;
160         return 0;
161
162 out_action:
163         FREE(action);
164 out_devname:
165         FREE(devname);
166 out_fsversion:
167         FREE(fsversion);
168         FREE(fstype);
169         return -1;
170 }
171
172 static int um_uevent_control_subsystem_usb_device(UmMainData *ad, struct udev_list_entry *list_entry)
173 {
174         __USB_FUNC_ENTER__;
175         assert(ad);
176         assert(list_entry);
177
178         int ret = -1;
179         char *action = NULL; /* add, remove, ... */
180
181         /* Getting device action */
182         ret = um_event_control_get_value_by_name(list_entry, UDEV_ENTRY_NAME_ACTION, &action);
183         if (ret < 0 || !action) {
184                 USB_LOG("FAIL: um_event_control_get_value_by_name()");
185                 FREE(action);
186                 return -1;
187         }
188         USB_LOG("The action is %s", action);
189
190         if (!strcmp(action, UDEV_ACTION_ADD)) {
191                 um_uevent_usb_host_added(ad);
192                 FREE(action);
193                 __USB_FUNC_EXIT__;
194                 return 0;
195         }
196
197         if (!strcmp(action, UDEV_ACTION_REMOVE)) {
198                 um_uevent_usb_host_removed(ad);
199                 FREE(action);
200                 __USB_FUNC_EXIT__;
201                 return 0;
202         }
203
204         USB_LOG("ERROR: action (%s) is improper", action);
205         FREE(action);
206         __USB_FUNC_EXIT__;
207         return -1;
208 }
209
210 static int um_uevent_control_subsystem_misc(UmMainData *ad, struct udev_list_entry *list_entry)
211 {
212         __USB_FUNC_ENTER__;
213         assert(ad);
214         assert(list_entry);
215
216         int ret = -1;
217         char *action = NULL; /* add, remove, change ... */
218         char *accessory = NULL; /* START, ... */
219
220         /* Getting device action */
221         ret = um_event_control_get_value_by_name(list_entry, UDEV_ENTRY_NAME_ACTION, &action);
222         if (ret < 0 || !action) {
223                 USB_LOG("FAIL: um_event_control_get_value_by_name()");
224                 FREE(action);
225                 return -1;
226         }
227         USB_LOG("The action is %s", action);
228
229         ret = um_event_control_get_value_by_name(list_entry, UDEV_ENTRY_NAME_ACCESSORY, &accessory);
230         if (ret < 0 || !accessory) {
231                 USB_LOG("FAIL: um_event_control_get_value_by_name()");
232                 FREE(action);
233                 FREE(accessory);
234                 return -1;
235         }
236         USB_LOG("The accessory is %s", accessory);
237
238         if (!strcmp(action, UDEV_ACTION_CHANGE) && !strcmp(accessory, UDEV_ACCESSORY_START)) {
239                 um_uevent_usb_accessory_added(ad);
240                 FREE(action);
241                 FREE(accessory);
242                 __USB_FUNC_EXIT__;
243                 return 0;
244         }
245
246         FREE(action);
247         FREE(accessory);
248         __USB_FUNC_EXIT__;
249         return -1;
250 }
251
252 static void um_uevent_control_subsystem(UmMainData *ad,
253                                         struct udev_list_entry *list_entry,
254                                         char *subsystem)
255 {
256         __USB_FUNC_ENTER__;
257         assert(ad);
258         assert(list_entry);
259         assert(subsystem);
260
261         if (!strcmp(subsystem, UDEV_SUBSYSTEM_BLOCK)) {
262                 if (um_uevent_control_subsystem_block(ad, list_entry) < 0)
263                         USB_LOG("FAIL: um_uevent_control_subsystem_block()");
264                 __USB_FUNC_EXIT__;
265                 return;
266         }
267
268         if (!strcmp(subsystem, UDEV_SUBSYSTEM_USB_DEVICE)) {
269                 if (um_uevent_control_subsystem_usb_device(ad, list_entry) < 0)
270                         USB_LOG("FAIL: um_uevent_control_subsystem_usb_device()");
271                 __USB_FUNC_EXIT__;
272                 return;
273         }
274
275         if (!strcmp(subsystem, UDEV_SUBSYSTEM_MISC)) {
276                 if (um_uevent_control_subsystem_misc(ad, list_entry) < 0)
277                         USB_LOG("FAIL: um_uevent_control_subsystem_usb_device()");
278                 __USB_FUNC_EXIT__;
279                 return;
280         }
281
282         USB_LOG("ERROR: subsystem (%s) is improper", subsystem);
283         __USB_FUNC_EXIT__;
284 }
285
286 static Eina_Bool uevent_control_cb(void *data, Ecore_Fd_Handler *fd_handler)
287 {
288         __USB_FUNC_ENTER__;
289         if (!data) return ECORE_CALLBACK_RENEW;
290         if (!fd_handler) return ECORE_CALLBACK_RENEW;
291         UmMainData *ad = (UmMainData *)data;
292         int ret = -1;
293         int i = 0;
294         struct udev_device *dev = NULL;
295         struct udev_list_entry *list_entry = NULL;
296         struct udev_list_entry *entry_found = NULL;
297         char *subsystem = NULL;
298
299         if (!ecore_main_fd_handler_active_get(ad->udevFdHandler, ECORE_FD_READ)) {
300                 USB_LOG("FAIL: ecore_main_fd_handler_active_get()");
301                 return ECORE_CALLBACK_RENEW;
302         }
303         dev = udev_monitor_receive_device(ad->udevMon);
304         if (!dev) {
305                 USB_LOG("FAIL: udev_monitor_receive_device()");
306                 return ECORE_CALLBACK_RENEW;
307         }
308
309         /* Getting the First element of the device entry list */
310         list_entry = udev_device_get_properties_list_entry(dev);
311         if (!list_entry) {
312                 USB_LOG("FAIL: udev_device_get_properties_list_entry()");
313                 udev_device_unref(dev);
314                 return ECORE_CALLBACK_RENEW;
315         }
316
317         ret = um_event_control_get_value_by_name(list_entry, UDEV_ENTRY_NAME_SUBSYSTEM, &subsystem);
318         if (ret < 0 || !subsystem) {
319                 USB_LOG("FAIL: um_event_control_get_value_by_name()");
320                 udev_device_unref(dev);
321                 return ECORE_CALLBACK_RENEW;
322         }
323
324         udev_list_entry_foreach(entry_found, list_entry) {
325                 USB_LOG("::::::::::::::::::::::::::::::::");
326                 USB_LOG("::: Number: %d", i);
327                 USB_LOG("::: Name  : %s", udev_list_entry_get_name(entry_found));
328                 USB_LOG("::: value : %s", udev_list_entry_get_value(entry_found));
329         }
330         USB_LOG(":::::::::::::::::::::::::::::");
331
332         um_uevent_control_subsystem(ad, list_entry, subsystem);
333
334         udev_device_unref(dev);
335         FREE(subsystem);
336         __USB_FUNC_EXIT__;
337         return ECORE_CALLBACK_RENEW;
338 }
339
340 void um_uevent_control_stop(UmMainData *ad)
341 {
342         __USB_FUNC_ENTER__;
343         if (!ad) return ;
344
345         if (ad->udevFdHandler) {
346                 ecore_main_fd_handler_del(ad->udevFdHandler);
347                 ad->udevFdHandler = NULL;
348         }
349
350         if (ad->udevFd >= 0) {
351                 close(ad->udevFd);
352                 ad->udevFd = -1;
353         }
354
355         if (ad->udevMon) {
356                 udev_monitor_unref(ad->udevMon);
357                 ad->udevMon = NULL;
358         }
359
360         if (ad->udev) {
361                 udev_unref(ad->udev);
362                 ad->udev = NULL;
363         }
364
365         __USB_FUNC_EXIT__;
366 }
367
368 int um_uevent_control_start(UmMainData *ad, int mode)
369 {
370         __USB_FUNC_ENTER__;
371         if (!ad) return -1;
372         int ret = -1;
373         ad->udevFd = -1;
374
375         ad->udev = udev_new();
376         if (!(ad->udev)) {
377                 USB_LOG("FAIL: udev_new()");
378                 return -1;
379         }
380
381         ad->udevMon = udev_monitor_new_from_netlink(ad->udev, UDEV_MON_UDEV);
382         if (ad->udevMon == NULL) {
383                 USB_LOG("FAIL: udev_monitor_new_from_netlink()");
384                 um_uevent_control_stop(ad);
385                 return -1;
386         }
387
388         /* The buffer size should be 128 * 1024 * 1024
389          * according to the buffer size of udev daemon */
390         ret = udev_monitor_set_receive_buffer_size(ad->udevMon, UEVENT_BUF_MAX);
391         if (ret < 0) {
392                 USB_LOG("FAIL: udev_monitor_set_receive_buffer_size()");
393                 um_uevent_control_stop(ad);
394                 return -1;
395         }
396
397         switch (mode) {
398         case USB_DEVICE_HOST:
399                 if (udev_monitor_filter_add_match_subsystem_devtype(ad->udevMon,
400                                         UDEV_SUBSYSTEM_BLOCK, NULL) < 0
401                         || udev_monitor_filter_add_match_subsystem_devtype(ad->udevMon,
402                                         UDEV_SUBSYSTEM_USB, NULL) < 0
403                         || udev_monitor_filter_add_match_subsystem_devtype(ad->udevMon,
404                                         UDEV_SUBSYSTEM_USB_DEVICE, NULL) < 0) {
405                         USB_LOG("FAIL: udev_monitor_filter_add_match_subsystem_devtype()");
406                         um_uevent_control_stop(ad);
407                         return -1;
408                 }
409                 break;
410
411         case USB_DEVICE_CLIENT:
412                 if (udev_monitor_filter_add_match_subsystem_devtype(ad->udevMon,
413                                         UDEV_SUBSYSTEM_MISC, NULL) < 0) {
414                         USB_LOG("FAIL: udev_monitor_filter_add_match_subsystem_devtype()");
415                         um_uevent_control_stop(ad);
416                         return -1;
417                 }
418
419                 break;
420
421         default:
422                 USB_LOG("ERROR: mode (%d) is improper", mode);
423                 um_uevent_control_stop(ad);
424                 return -1;
425         }
426
427         ad->udevFd = udev_monitor_get_fd(ad->udevMon);
428         if (ad->udevFd < 0) {
429                 USB_LOG("FAIL: udev_monitor_get_fd()");
430                 um_uevent_control_stop(ad);
431                 return -1;
432         }
433
434         ad->udevFdHandler = ecore_main_fd_handler_add(ad->udevFd, ECORE_FD_READ,
435                                                 uevent_control_cb, ad, NULL, NULL);
436         if (ad->udevFdHandler == NULL) {
437                 USB_LOG("FAIL: ecore_main_fd_handler_add()");
438                 um_uevent_control_stop(ad);
439                 return -1;
440         }
441
442         ret = udev_monitor_enable_receiving(ad->udevMon);
443         if (ret < 0) {
444                 USB_LOG("FAIL: udev_monitor_enable_receiving()");
445                 um_uevent_control_stop(ad);
446                 return -1;
447         }
448
449         __USB_FUNC_EXIT__;
450         return 0;
451 }
452