• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright (C) 2008 The Android Open Source Project
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 <string.h>
19 #include <stdlib.h>
20 #include <errno.h>
21 
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 
25 #include "vold.h"
26 #include "uevent.h"
27 #include "mmc.h"
28 #include "blkdev.h"
29 #include "volmgr.h"
30 #include "media.h"
31 
32 #define DEBUG_UEVENT 0
33 
34 #define UEVENT_PARAMS_MAX 32
35 
36 enum uevent_action { action_add, action_remove, action_change };
37 
38 struct uevent {
39     char *path;
40     enum uevent_action action;
41     char *subsystem;
42     char *param[UEVENT_PARAMS_MAX];
43     unsigned int seqnum;
44 };
45 
46 struct uevent_dispatch {
47     char *subsystem;
48     int (* dispatch) (struct uevent *);
49 };
50 
51 static void dump_uevent(struct uevent *);
52 static int dispatch_uevent(struct uevent *event);
53 static void free_uevent(struct uevent *event);
54 static char *get_uevent_param(struct uevent *event, char *param_name);
55 
56 static int handle_powersupply_event(struct uevent *event);
57 static int handle_switch_event(struct uevent *);
58 static int handle_battery_event(struct uevent *);
59 static int handle_mmc_event(struct uevent *);
60 static int handle_block_event(struct uevent *);
61 static int handle_bdi_event(struct uevent *);
62 static void _cb_blkdev_ok_to_destroy(blkdev_t *dev);
63 
64 static struct uevent_dispatch dispatch_table[] = {
65     { "switch", handle_switch_event },
66     { "battery", handle_battery_event },
67     { "mmc", handle_mmc_event },
68     { "block", handle_block_event },
69     { "bdi", handle_bdi_event },
70     { "power_supply", handle_powersupply_event },
71     { NULL, NULL }
72 };
73 
74 static boolean low_batt = false;
75 static boolean door_open = true;
76 
process_uevent_message(int socket)77 int process_uevent_message(int socket)
78 {
79     char buffer[64 * 1024]; // Thank god we're not in the kernel :)
80     int count;
81     char *s = buffer;
82     char *end;
83     struct uevent *event;
84     int param_idx = 0;
85     int i;
86     int first = 1;
87     int rc = 0;
88 
89     if ((count = recv(socket, buffer, sizeof(buffer), 0)) < 0) {
90         LOGE("Error receiving uevent (%s)", strerror(errno));
91         return -errno;
92     }
93 
94     if (!(event = malloc(sizeof(struct uevent)))) {
95         LOGE("Error allocating memory (%s)", strerror(errno));
96         return -errno;
97     }
98 
99     memset(event, 0, sizeof(struct uevent));
100 
101     end = s + count;
102     while (s < end) {
103         if (first) {
104             char *p;
105             for (p = s; *p != '@'; p++);
106             p++;
107             event->path = strdup(p);
108             first = 0;
109         } else {
110             if (!strncmp(s, "ACTION=", strlen("ACTION="))) {
111                 char *a = s + strlen("ACTION=");
112 
113                 if (!strcmp(a, "add"))
114                     event->action = action_add;
115                 else if (!strcmp(a, "change"))
116                     event->action = action_change;
117                 else if (!strcmp(a, "remove"))
118                     event->action = action_remove;
119             } else if (!strncmp(s, "SEQNUM=", strlen("SEQNUM=")))
120                 event->seqnum = atoi(s + strlen("SEQNUM="));
121             else if (!strncmp(s, "SUBSYSTEM=", strlen("SUBSYSTEM=")))
122                 event->subsystem = strdup(s + strlen("SUBSYSTEM="));
123             else
124                 event->param[param_idx++] = strdup(s);
125         }
126         s+= strlen(s) + 1;
127     }
128 
129     rc = dispatch_uevent(event);
130 
131     free_uevent(event);
132     return rc;
133 }
134 
simulate_uevent(char * subsys,char * path,char * action,char ** params)135 int simulate_uevent(char *subsys, char *path, char *action, char **params)
136 {
137     struct uevent *event;
138     char tmp[255];
139     int i, rc;
140 
141     if (!(event = malloc(sizeof(struct uevent)))) {
142         LOGE("Error allocating memory (%s)", strerror(errno));
143         return -errno;
144     }
145 
146     memset(event, 0, sizeof(struct uevent));
147 
148     event->subsystem = strdup(subsys);
149 
150     if (!strcmp(action, "add"))
151         event->action = action_add;
152     else if (!strcmp(action, "change"))
153         event->action = action_change;
154     else if (!strcmp(action, "remove"))
155         event->action = action_remove;
156     else {
157         LOGE("Invalid action '%s'", action);
158         return -1;
159     }
160 
161     event->path = strdup(path);
162 
163     for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
164         if (!params[i])
165             break;
166         event->param[i] = strdup(params[i]);
167     }
168 
169     rc = dispatch_uevent(event);
170     free_uevent(event);
171     return rc;
172 }
173 
dispatch_uevent(struct uevent * event)174 static int dispatch_uevent(struct uevent *event)
175 {
176     int i;
177 
178 #if DEBUG_UEVENT
179     dump_uevent(event);
180 #endif
181     for (i = 0; dispatch_table[i].subsystem != NULL; i++) {
182         if (!strcmp(dispatch_table[i].subsystem, event->subsystem))
183             return dispatch_table[i].dispatch(event);
184     }
185 
186 #if DEBUG_UEVENT
187     LOG_VOL("No uevent handlers registered for '%s' subsystem", event->subsystem);
188 #endif
189     return 0;
190 }
191 
dump_uevent(struct uevent * event)192 static void dump_uevent(struct uevent *event)
193 {
194     int i;
195 
196     LOG_VOL("[UEVENT] Sq: %u S: %s A: %d P: %s",
197               event->seqnum, event->subsystem, event->action, event->path);
198     for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
199         if (!event->param[i])
200             break;
201         LOG_VOL("%s", event->param[i]);
202     }
203 }
204 
free_uevent(struct uevent * event)205 static void free_uevent(struct uevent *event)
206 {
207     int i;
208     free(event->path);
209     free(event->subsystem);
210     for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
211         if (!event->param[i])
212             break;
213         free(event->param[i]);
214     }
215     free(event);
216 }
217 
get_uevent_param(struct uevent * event,char * param_name)218 static char *get_uevent_param(struct uevent *event, char *param_name)
219 {
220     int i;
221 
222     for (i = 0; i < UEVENT_PARAMS_MAX; i++) {
223         if (!event->param[i])
224             break;
225         if (!strncmp(event->param[i], param_name, strlen(param_name)))
226             return &event->param[i][strlen(param_name) + 1];
227     }
228 
229     LOGE("get_uevent_param(): No parameter '%s' found", param_name);
230     return NULL;
231 }
232 
233 /*
234  * ---------------
235  * Uevent Handlers
236  * ---------------
237  */
238 
handle_powersupply_event(struct uevent * event)239 static int handle_powersupply_event(struct uevent *event)
240 {
241     char *ps_type = get_uevent_param(event, "POWER_SUPPLY_TYPE");
242 
243     if (!strcasecmp(ps_type, "battery")) {
244         char *ps_cap = get_uevent_param(event, "POWER_SUPPLY_CAPACITY");
245         int capacity = atoi(ps_cap);
246 
247         if (capacity < 5)
248             low_batt = true;
249         else
250             low_batt = false;
251         volmgr_safe_mode(low_batt || door_open);
252     }
253     return 0;
254 }
255 
handle_switch_event(struct uevent * event)256 static int handle_switch_event(struct uevent *event)
257 {
258     char *name = get_uevent_param(event, "SWITCH_NAME");
259     char *state = get_uevent_param(event, "SWITCH_STATE");
260 
261 
262     if (!strcmp(name, "usb_mass_storage")) {
263         if (!strcmp(state, "online")) {
264             ums_hostconnected_set(true);
265         } else {
266             ums_hostconnected_set(false);
267             volmgr_enable_ums(false);
268         }
269     } else if (!strcmp(name, "sd-door")) {
270         if (!strcmp(state, "open"))
271             door_open = true;
272         else
273             door_open = false;
274         volmgr_safe_mode(low_batt || door_open);
275     }
276 
277     return 0;
278 }
279 
handle_battery_event(struct uevent * event)280 static int handle_battery_event(struct uevent *event)
281 {
282     return 0;
283 }
284 
handle_block_event(struct uevent * event)285 static int handle_block_event(struct uevent *event)
286 {
287     char mediapath[255];
288     media_t *media;
289     int n;
290     int maj, min;
291     blkdev_t *blkdev;
292 
293     /*
294      * Look for backing media for this block device
295      */
296     if (!strncmp(get_uevent_param(event, "DEVPATH"),
297                  "/devices/virtual/",
298                  strlen("/devices/virtual/"))) {
299         n = 0;
300     } else if (!strcmp(get_uevent_param(event, "DEVTYPE"), "disk"))
301         n = 2;
302     else if (!strcmp(get_uevent_param(event, "DEVTYPE"), "partition"))
303         n = 3;
304     else {
305         LOGE("Bad blockdev type '%s'", get_uevent_param(event, "DEVTYPE"));
306         return -EINVAL;
307     }
308 
309     truncate_sysfs_path(event->path, n, mediapath, sizeof(mediapath));
310 
311     if (!(media = media_lookup_by_path(mediapath, false))) {
312 #if DEBUG_UEVENT
313         LOG_VOL("No backend media found @ device path '%s'", mediapath);
314 #endif
315         return 0;
316     }
317 
318     maj = atoi(get_uevent_param(event, "MAJOR"));
319     min = atoi(get_uevent_param(event, "MINOR"));
320 
321     if (event->action == action_add) {
322         blkdev_t *disk;
323 
324         /*
325          * If there isn't a disk already its because *we*
326          * are the disk
327          */
328         if (media->media_type == media_mmc)
329             disk = blkdev_lookup_by_devno(maj, ALIGN_MMC_MINOR(min));
330         else
331             disk = blkdev_lookup_by_devno(maj, 0);
332 
333         if (!(blkdev = blkdev_create(disk,
334                                      event->path,
335                                      maj,
336                                      min,
337                                      media,
338                                      get_uevent_param(event, "DEVTYPE")))) {
339             LOGE("Unable to allocate new blkdev (%s)", strerror(errno));
340             return -1;
341         }
342 
343         blkdev_refresh(blkdev);
344 
345         /*
346          * Add the blkdev to media
347          */
348         int rc;
349         if ((rc = media_add_blkdev(media, blkdev)) < 0) {
350             LOGE("Unable to add blkdev to card (%d)", rc);
351             return rc;
352         }
353 
354         LOGI("New blkdev %d.%d on media %s, media path %s, Dpp %d",
355                 blkdev->major, blkdev->minor, media->name, mediapath,
356                 blkdev_get_num_pending_partitions(blkdev->disk));
357 
358         if (blkdev_get_num_pending_partitions(blkdev->disk) == 0) {
359             if ((rc = volmgr_consider_disk(blkdev->disk)) < 0) {
360                 if (rc == -EBUSY) {
361                     LOGI("Volmgr not ready to handle device");
362                 } else {
363                     LOGE("Volmgr failed to handle device (%d)", rc);
364                     return rc;
365                 }
366             }
367         }
368     } else if (event->action == action_remove) {
369         if (!(blkdev = blkdev_lookup_by_devno(maj, min)))
370             return 0;
371 
372         LOGI("Destroying blkdev %d.%d @ %s on media %s", blkdev->major,
373                 blkdev->minor, blkdev->devpath, media->name);
374         volmgr_notify_eject(blkdev, _cb_blkdev_ok_to_destroy);
375 
376     } else if (event->action == action_change) {
377         if (!(blkdev = blkdev_lookup_by_devno(maj, min)))
378             return 0;
379 
380         LOGI("Modified blkdev %d.%d @ %s on media %s", blkdev->major,
381                 blkdev->minor, blkdev->devpath, media->name);
382 
383         blkdev_refresh(blkdev);
384     } else  {
385 #if DEBUG_UEVENT
386         LOG_VOL("No handler implemented for action %d", event->action);
387 #endif
388     }
389     return 0;
390 }
391 
_cb_blkdev_ok_to_destroy(blkdev_t * dev)392 static void _cb_blkdev_ok_to_destroy(blkdev_t *dev)
393 {
394     media_t *media = media_lookup_by_dev(dev);
395     if (media)
396         media_remove_blkdev(media, dev);
397     blkdev_destroy(dev);
398 }
399 
handle_bdi_event(struct uevent * event)400 static int handle_bdi_event(struct uevent *event)
401 {
402     return 0;
403 }
404 
handle_mmc_event(struct uevent * event)405 static int handle_mmc_event(struct uevent *event)
406 {
407     if (event->action == action_add) {
408         media_t *media;
409         char serial[80];
410         char *type;
411 
412         /*
413          * Pull card information from sysfs
414          */
415         type = get_uevent_param(event, "MMC_TYPE");
416         if (strcmp(type, "SD") && strcmp(type, "MMC"))
417             return 0;
418 
419         read_sysfs_var(serial, sizeof(serial), event->path, "serial");
420         if (!(media = media_create(event->path,
421                                    get_uevent_param(event, "MMC_NAME"),
422                                    serial,
423                                    media_mmc))) {
424             LOGE("Unable to allocate new media (%s)", strerror(errno));
425             return -1;
426         }
427         LOGI("New MMC card '%s' (serial %u) added @ %s", media->name,
428                   media->serial, media->devpath);
429     } else if (event->action == action_remove) {
430         media_t *media;
431 
432         if (!(media = media_lookup_by_path(event->path, false))) {
433             LOGE("Unable to lookup media '%s'", event->path);
434             return -1;
435         }
436 
437         LOGI("MMC card '%s' (serial %u) @ %s removed", media->name,
438                   media->serial, media->devpath);
439         media_destroy(media);
440     } else {
441 #if DEBUG_UEVENT
442         LOG_VOL("No handler implemented for action %d", event->action);
443 #endif
444     }
445 
446     return 0;
447 }
448