7d30234784cd816b613826b6cc32fca5e0b2bab2
[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(accessory);
233                 return -1;
234         }
235         USB_LOG("The accessory is %s", accessory);
236
237         if (!strcmp(action, UDEV_ACTION_CHANGE) && !strcmp(accessory, UDEV_ACCESSORY_START)) {
238                 um_uevent_usb_accessory_added(ad);
239                 FREE(action);
240                 FREE(accessory);
241                 __USB_FUNC_EXIT__;
242                 return 0;
243         }
244
245         FREE(action);
246         FREE(accessory);
247         __USB_FUNC_EXIT__;
248         return -1;
249 }
250
251 static void um_uevent_control_subsystem(UmMainData *ad,
252                                         struct udev_list_entry *list_entry,
253                                         char *subsystem)
254 {
255         __USB_FUNC_ENTER__;
256         assert(ad);
257         assert(list_entry);
258         assert(subsystem);
259
260         if (!strcmp(subsystem, UDEV_SUBSYSTEM_BLOCK)) {
261                 if (um_uevent_control_subsystem_block(ad, list_entry) < 0)
262                         USB_LOG("FAIL: um_uevent_control_subsystem_block()");
263                 __USB_FUNC_EXIT__;
264                 return;
265         }
266
267         if (!strcmp(subsystem, UDEV_SUBSYSTEM_USB_DEVICE)) {
268                 if (um_uevent_control_subsystem_usb_device(ad, list_entry) < 0)
269                         USB_LOG("FAIL: um_uevent_control_subsystem_usb_device()");
270                 __USB_FUNC_EXIT__;
271                 return;
272         }
273
274         if (!strcmp(subsystem, UDEV_SUBSYSTEM_MISC)) {
275                 if (um_uevent_control_subsystem_misc(ad, list_entry) < 0)
276                         USB_LOG("FAIL: um_uevent_control_subsystem_usb_device()");
277                 __USB_FUNC_EXIT__;
278                 return;
279         }
280
281         USB_LOG("ERROR: subsystem (%s) is improper", subsystem);
282         __USB_FUNC_EXIT__;
283 }
284
285 static Eina_Bool uevent_control_cb(void *data, Ecore_Fd_Handler *fd_handler)
286 {
287         __USB_FUNC_ENTER__;
288         if (!data) return ECORE_CALLBACK_RENEW;
289         if (!fd_handler) return ECORE_CALLBACK_RENEW;
290         UmMainData *ad = (UmMainData *)data;
291         int ret = -1;
292         int i = 0;
293         struct udev_device *dev = NULL;
294         struct udev_list_entry *list_entry = NULL;
295         struct udev_list_entry *entry_found = NULL;
296         char *subsystem = NULL;
297
298         if (!ecore_main_fd_handler_active_get(ad->udevFdHandler, ECORE_FD_READ)) {
299                 USB_LOG("FAIL: ecore_main_fd_handler_active_get()");
300                 return ECORE_CALLBACK_RENEW;
301         }
302         dev = udev_monitor_receive_device(ad->udevMon);
303         if (!dev) {
304                 USB_LOG("FAIL: udev_monitor_receive_device()");
305                 return ECORE_CALLBACK_RENEW;
306         }
307
308         /* Getting the First element of the device entry list */
309         list_entry = udev_device_get_properties_list_entry(dev);
310         if (!list_entry) {
311                 USB_LOG("FAIL: udev_device_get_properties_list_entry()");
312                 udev_device_unref(dev);
313                 return ECORE_CALLBACK_RENEW;
314         }
315
316         ret = um_event_control_get_value_by_name(list_entry, UDEV_ENTRY_NAME_SUBSYSTEM, &subsystem);
317         if (ret < 0 || !subsystem) {
318                 USB_LOG("FAIL: um_event_control_get_value_by_name()");
319                 udev_device_unref(dev);
320                 return ECORE_CALLBACK_RENEW;
321         }
322
323         udev_list_entry_foreach(entry_found, list_entry) {
324                 USB_LOG("::::::::::::::::::::::::::::::::");
325                 USB_LOG("::: Number: %d", i);
326                 USB_LOG("::: Name  : %s", udev_list_entry_get_name(entry_found));
327                 USB_LOG("::: value : %s", udev_list_entry_get_value(entry_found));
328         }
329         USB_LOG(":::::::::::::::::::::::::::::");
330
331         um_uevent_control_subsystem(ad, list_entry, subsystem);
332
333         udev_device_unref(dev);
334         FREE(subsystem);
335         __USB_FUNC_EXIT__;
336         return ECORE_CALLBACK_RENEW;
337 }
338
339 void um_uevent_control_stop(UmMainData *ad)
340 {
341         __USB_FUNC_ENTER__;
342         if (!ad) return ;
343
344         if (ad->udevFdHandler) {
345                 ecore_main_fd_handler_del(ad->udevFdHandler);
346                 ad->udevFdHandler = NULL;
347         }
348
349         if (ad->udevFd >= 0) {
350                 close(ad->udevFd);
351                 ad->udevFd = -1;
352         }
353
354         if (ad->udevMon) {
355                 udev_monitor_unref(ad->udevMon);
356                 ad->udevMon = NULL;
357         }
358
359         if (ad->udev) {
360                 udev_unref(ad->udev);
361                 ad->udev = NULL;
362         }
363
364         __USB_FUNC_EXIT__;
365 }
366
367 int um_uevent_control_start(UmMainData *ad, int mode)
368 {
369         __USB_FUNC_ENTER__;
370         if (!ad) return -1;
371         int ret = -1;
372         ad->udevFd = -1;
373
374         ad->udev = udev_new();
375         if (!(ad->udev)) {
376                 USB_LOG("FAIL: udev_new()");
377                 return -1;
378         }
379
380         ad->udevMon = udev_monitor_new_from_netlink(ad->udev, UDEV_MON_UDEV);
381         if (ad->udevMon == NULL) {
382                 USB_LOG("FAIL: udev_monitor_new_from_netlink()");
383                 um_uevent_control_stop(ad);
384                 return -1;
385         }
386
387         /* The buffer size should be 128 * 1024 * 1024
388          * according to the buffer size of udev daemon */
389         ret = udev_monitor_set_receive_buffer_size(ad->udevMon, UEVENT_BUF_MAX);
390         if (ret < 0) {
391                 USB_LOG("FAIL: udev_monitor_set_receive_buffer_size()");
392                 um_uevent_control_stop(ad);
393                 return -1;
394         }
395
396         switch (mode) {
397         case USB_DEVICE_HOST:
398                 if (udev_monitor_filter_add_match_subsystem_devtype(ad->udevMon,
399                                         UDEV_SUBSYSTEM_BLOCK, NULL) < 0
400                         || udev_monitor_filter_add_match_subsystem_devtype(ad->udevMon,
401                                         UDEV_SUBSYSTEM_USB, NULL) < 0
402                         || udev_monitor_filter_add_match_subsystem_devtype(ad->udevMon,
403                                         UDEV_SUBSYSTEM_USB_DEVICE, NULL) < 0) {
404                         USB_LOG("FAIL: udev_monitor_filter_add_match_subsystem_devtype()");
405                         um_uevent_control_stop(ad);
406                         return -1;
407                 }
408                 break;
409
410         case USB_DEVICE_CLIENT:
411                 if (udev_monitor_filter_add_match_subsystem_devtype(ad->udevMon,
412                                         UDEV_SUBSYSTEM_MISC, NULL) < 0) {
413                         USB_LOG("FAIL: udev_monitor_filter_add_match_subsystem_devtype()");
414                         um_uevent_control_stop(ad);
415                         return -1;
416                 }
417
418                 break;
419
420         default:
421                 USB_LOG("ERROR: mode (%d) is improper", mode);
422                 um_uevent_control_stop(ad);
423                 return -1;
424         }
425
426         ad->udevFd = udev_monitor_get_fd(ad->udevMon);
427         if (ad->udevFd < 0) {
428                 USB_LOG("FAIL: udev_monitor_get_fd()");
429                 um_uevent_control_stop(ad);
430                 return -1;
431         }
432
433         ad->udevFdHandler = ecore_main_fd_handler_add(ad->udevFd, ECORE_FD_READ,
434                                                 uevent_control_cb, ad, NULL, NULL);
435         if (ad->udevFdHandler == NULL) {
436                 USB_LOG("FAIL: ecore_main_fd_handler_add()");
437                 um_uevent_control_stop(ad);
438                 return -1;
439         }
440
441         ret = udev_monitor_enable_receiving(ad->udevMon);
442         if (ret < 0) {
443                 USB_LOG("FAIL: udev_monitor_enable_receiving()");
444                 um_uevent_control_stop(ad);
445                 return -1;
446         }
447
448         __USB_FUNC_EXIT__;
449         return 0;
450 }
451