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 <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <dirent.h>
22 #include <unistd.h>
23 #include <sched.h>
24
25 #include <sys/mount.h>
26
27 #include <cutils/config_utils.h>
28 #include <cutils/properties.h>
29
30 #include "vold.h"
31 #include "volmgr.h"
32 #include "blkdev.h"
33 #include "ums.h"
34 #include "format.h"
35 #include "devmapper.h"
36
37 #include "volmgr_ext3.h"
38 #include "volmgr_vfat.h"
39
40 #define DEBUG_VOLMGR 0
41
42 static volume_t *vol_root = NULL;
43 static boolean safe_mode = true;
44
45 static struct volmgr_fstable_entry fs_table[] = {
46 // { "ext3", ext_identify, ext_check, ext_mount , true },
47 { "vfat", vfat_identify, vfat_check, vfat_mount , false },
48 { NULL, NULL, NULL, NULL , false}
49 };
50
51 struct _volume_state_event_map {
52 volume_state_t state;
53 char *event;
54 char *property_val;
55 };
56
57 static struct _volume_state_event_map volume_state_strings[] = {
58 { volstate_unknown, "volstate_unknown:", "unknown" },
59 { volstate_nomedia, VOLD_EVT_NOMEDIA, VOLD_ES_PVAL_NOMEDIA },
60 { volstate_unmounted, VOLD_EVT_UNMOUNTED, VOLD_ES_PVAL_UNMOUNTED },
61 { volstate_checking, VOLD_EVT_CHECKING, VOLD_ES_PVAL_CHECKING },
62 { volstate_mounted, VOLD_EVT_MOUNTED, VOLD_ES_PVAL_MOUNTED },
63 { volstate_mounted_ro, VOLD_EVT_MOUNTED_RO, VOLD_ES_PVAL_MOUNTED_RO },
64 { volstate_badremoval, VOLD_EVT_BADREMOVAL, VOLD_ES_PVAL_BADREMOVAL },
65 { volstate_damaged, VOLD_EVT_DAMAGED, VOLD_ES_PVAL_DAMAGED },
66 { volstate_nofs, VOLD_EVT_NOFS, VOLD_ES_PVAL_NOFS },
67 { volstate_ums, VOLD_EVT_UMS, VOLD_ES_PVAL_UMS },
68 { 0, NULL, NULL }
69 };
70
71
72 static int volmgr_readconfig(char *cfg_path);
73 static int volmgr_config_volume(cnode *node);
74 static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy);
75 static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev);
76 static int _volmgr_start(volume_t *vol, blkdev_t *dev);
77 static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev);
78 static void *volmgr_start_fs_thread(void *arg);
79 static void volmgr_start_fs_thread_sighandler(int signo);
80 static void volume_setstate(volume_t *vol, volume_state_t state);
81 static char *conv_volstate_to_eventstr(volume_state_t state);
82 static char *conv_volstate_to_propstr(volume_state_t state);
83 static int volume_send_state(volume_t *vol);
84 static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg);
85 static int _volmgr_enable_ums(volume_t *);
86 static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *arg), boolean emit_statechange);
87 static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange);
88 static void _cb_volume_stopped_for_eject(volume_t *v, void *arg);
89 static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg);
90 static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev);
91 static void volmgr_uncage_reaper(volume_t *vol, void (* cb) (volume_t *, void *arg), void *arg);
92 static void volmgr_reaper_thread_sighandler(int signo);
93 static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path);
94 static int volmgr_send_eject_request(volume_t *v);
95 static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked);
96
_mountpoint_mounted(char * mp)97 static boolean _mountpoint_mounted(char *mp)
98 {
99 char device[256];
100 char mount_path[256];
101 char rest[256];
102 FILE *fp;
103 char line[1024];
104
105 if (!(fp = fopen("/proc/mounts", "r"))) {
106 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
107 return false;
108 }
109
110 while(fgets(line, sizeof(line), fp)) {
111 line[strlen(line)-1] = '\0';
112 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
113 if (!strcmp(mount_path, mp)) {
114 fclose(fp);
115 return true;
116 }
117
118 }
119
120 fclose(fp);
121 return false;
122 }
123
124 /*
125 * Public functions
126 */
127
volmgr_set_volume_key(char * mount_point,unsigned char * key)128 int volmgr_set_volume_key(char *mount_point, unsigned char *key)
129 {
130 volume_t *v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
131
132 if (!v)
133 return -ENOENT;
134
135 if (v->media_type != media_devmapper) {
136 LOGE("Cannot set key on a non devmapper volume");
137 pthread_mutex_unlock(&v->lock);
138 return -EINVAL;
139 }
140
141 memcpy(v->dm->key, key, sizeof(v->dm->key));
142 pthread_mutex_unlock(&v->lock);
143 return 0;
144 }
145
volmgr_format_volume(char * mount_point)146 int volmgr_format_volume(char *mount_point)
147 {
148 int rc;
149 volume_t *v;
150
151 LOG_VOL("volmgr_format_volume(%s):", mount_point);
152
153 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
154
155 if (!v)
156 return -ENOENT;
157
158 if (v->state == volstate_mounted ||
159 v->state == volstate_mounted_ro ||
160 v->state == volstate_ums ||
161 v->state == volstate_checking) {
162 LOGE("Can't format '%s', currently in state %d", mount_point, v->state);
163 pthread_mutex_unlock(&v->lock);
164 return -EBUSY;
165 } else if (v->state == volstate_nomedia &&
166 v->media_type != media_devmapper) {
167 LOGE("Can't format '%s', (no media)", mount_point);
168 pthread_mutex_unlock(&v->lock);
169 return -ENOMEDIUM;
170 }
171
172 // XXX:Reject if the underlying source media is not present
173
174 if (v->media_type == media_devmapper) {
175 if ((rc = devmapper_genesis(v->dm)) < 0) {
176 LOGE("devmapper genesis failed for %s (%d)", mount_point, rc);
177 pthread_mutex_unlock(&v->lock);
178 return rc;
179 }
180 } else {
181 if ((rc = initialize_mbr(v->dev->disk)) < 0) {
182 LOGE("MBR init failed for %s (%d)", mount_point, rc);
183 pthread_mutex_unlock(&v->lock);
184 return rc;
185 }
186 }
187
188 volume_setstate(v, volstate_formatting);
189 pthread_mutex_unlock(&v->lock);
190 return rc;
191 }
192
volmgr_bootstrap(void)193 int volmgr_bootstrap(void)
194 {
195 int rc;
196
197 if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) {
198 LOGE("Unable to process config");
199 return rc;
200 }
201
202 /*
203 * Check to see if any of our volumes is mounted
204 */
205 volume_t *v = vol_root;
206 while (v) {
207 if (_mountpoint_mounted(v->mount_point)) {
208 LOGW("Volume '%s' already mounted at startup", v->mount_point);
209 v->state = volstate_mounted;
210 }
211 v = v->next;
212 }
213
214 return 0;
215 }
216
volmgr_safe_mode(boolean enable)217 int volmgr_safe_mode(boolean enable)
218 {
219 if (enable == safe_mode)
220 return 0;
221
222 safe_mode = enable;
223
224 volume_t *v = vol_root;
225 int rc;
226
227 while (v) {
228 pthread_mutex_lock(&v->lock);
229 if (v->state == volstate_mounted && v->fs) {
230 rc = v->fs->mount_fn(v->dev, v, safe_mode);
231 if (!rc) {
232 LOGI("Safe mode %s on %s", (enable ? "enabled" : "disabled"), v->mount_point);
233 } else {
234 LOGE("Failed to %s safe-mode on %s (%s)",
235 (enable ? "enable" : "disable" ), v->mount_point, strerror(-rc));
236 }
237 }
238
239 pthread_mutex_unlock(&v->lock);
240 v = v->next;
241 }
242
243 return 0;
244 }
245
volmgr_send_states(void)246 int volmgr_send_states(void)
247 {
248 volume_t *vol_scan = vol_root;
249 int rc;
250
251 while (vol_scan) {
252 pthread_mutex_lock(&vol_scan->lock);
253 if ((rc = volume_send_state(vol_scan)) < 0) {
254 LOGE("Error sending state to framework (%d)", rc);
255 }
256 pthread_mutex_unlock(&vol_scan->lock);
257 vol_scan = vol_scan->next;
258 break; // XXX:
259 }
260
261 return 0;
262 }
263
264 /*
265 * Called when a block device is ready to be
266 * evaluated by the volume manager.
267 */
volmgr_consider_disk(blkdev_t * dev)268 int volmgr_consider_disk(blkdev_t *dev)
269 {
270 volume_t *vol;
271
272 if (!(vol = volmgr_lookup_volume_by_mediapath(dev->media->devpath, true)))
273 return 0;
274
275 pthread_mutex_lock(&vol->lock);
276
277 if (vol->state == volstate_mounted) {
278 LOGE("Volume %s already mounted (did we just crash?)", vol->mount_point);
279 pthread_mutex_unlock(&vol->lock);
280 return 0;
281 }
282
283 int rc = _volmgr_consider_disk_and_vol(vol, dev);
284 pthread_mutex_unlock(&vol->lock);
285 return rc;
286 }
287
volmgr_start_volume_by_mountpoint(char * mount_point)288 int volmgr_start_volume_by_mountpoint(char *mount_point)
289 {
290 volume_t *v;
291
292 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
293 if (!v)
294 return -ENOENT;
295
296 if (v->media_type == media_devmapper) {
297 if (devmapper_start(v->dm) < 0) {
298 LOGE("volmgr failed to start devmapper volume '%s'",
299 v->mount_point);
300 }
301 } else if (v->media_type == media_mmc) {
302 if (!v->dev) {
303 LOGE("Cannot start volume '%s' (volume is not bound)", mount_point);
304 pthread_mutex_unlock(&v->lock);
305 return -ENOENT;
306 }
307
308 if (_volmgr_consider_disk_and_vol(v, v->dev->disk) < 0) {
309 LOGE("volmgr failed to start volume '%s'", v->mount_point);
310 }
311 }
312
313 pthread_mutex_unlock(&v->lock);
314 return 0;
315 }
316
_cb_volstopped_for_devmapper_teardown(volume_t * v,void * arg)317 static void _cb_volstopped_for_devmapper_teardown(volume_t *v, void *arg)
318 {
319 devmapper_stop(v->dm);
320 volume_setstate(v, volstate_nomedia);
321 pthread_mutex_unlock(&v->lock);
322 }
323
volmgr_stop_volume_by_mountpoint(char * mount_point)324 int volmgr_stop_volume_by_mountpoint(char *mount_point)
325 {
326 int rc;
327 volume_t *v;
328
329 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
330 if (!v)
331 return -ENOENT;
332
333 if (v->state == volstate_mounted)
334 volmgr_send_eject_request(v);
335
336 if (v->media_type == media_devmapper)
337 rc = volmgr_shutdown_volume(v, _cb_volstopped_for_devmapper_teardown, false);
338 else
339 rc = volmgr_shutdown_volume(v, NULL, true);
340
341 /*
342 * If shutdown returns -EINPROGRESS,
343 * do *not* release the lock as
344 * it is now owned by the reaper thread
345 */
346 if (rc != -EINPROGRESS) {
347 if (rc)
348 LOGE("unable to shutdown volume '%s'", v->mount_point);
349 pthread_mutex_unlock(&v->lock);
350 }
351 return 0;
352 }
353
volmgr_notify_eject(blkdev_t * dev,void (* cb)(blkdev_t *))354 int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *))
355 {
356 LOG_VOL("Volmgr notified of %d:%d eject", dev->major, dev->minor);
357
358 volume_t *v;
359 int rc;
360
361 // XXX: Partitioning support is going to need us to stop *all*
362 // devices in this volume
363 if (!(v = volmgr_lookup_volume_by_dev(dev))) {
364 if (cb)
365 cb(dev);
366 return 0;
367 }
368
369 pthread_mutex_lock(&v->lock);
370
371 volume_state_t old_state = v->state;
372
373 if (v->state == volstate_mounted ||
374 v->state == volstate_ums ||
375 v->state == volstate_checking) {
376
377 volume_setstate(v, volstate_badremoval);
378
379 /*
380 * Stop any devmapper volumes which
381 * are using us as a source
382 * XXX: We may need to enforce stricter
383 * order here
384 */
385 volume_t *dmvol = vol_root;
386 while (dmvol) {
387 if ((dmvol->media_type == media_devmapper) &&
388 (dmvol->dm->src_type == dmsrc_loopback) &&
389 (!strncmp(dmvol->dm->type_data.loop.loop_src,
390 v->mount_point, strlen(v->mount_point)))) {
391
392 pthread_mutex_lock(&dmvol->lock);
393 if (dmvol->state != volstate_nomedia) {
394 rc = volmgr_shutdown_volume(dmvol, _cb_volstopped_for_devmapper_teardown, false);
395 if (rc != -EINPROGRESS) {
396 if (rc)
397 LOGE("unable to shutdown volume '%s'", v->mount_point);
398 pthread_mutex_unlock(&dmvol->lock);
399 }
400 } else
401 pthread_mutex_unlock(&dmvol->lock);
402 }
403 dmvol = dmvol->next;
404 }
405
406 } else if (v->state == volstate_formatting) {
407 /*
408 * The device is being ejected due to
409 * kernel disk revalidation.
410 */
411 LOG_VOL("Volmgr ignoring eject of %d:%d (volume formatting)",
412 dev->major, dev->minor);
413 if (cb)
414 cb(dev);
415 pthread_mutex_unlock(&v->lock);
416 return 0;
417 } else
418 volume_setstate(v, volstate_nomedia);
419
420 if (old_state == volstate_ums) {
421 ums_disable(v->ums_path);
422 pthread_mutex_unlock(&v->lock);
423 } else {
424 int rc = volmgr_stop_volume(v, _cb_volume_stopped_for_eject, cb, false);
425 if (rc != -EINPROGRESS) {
426 if (rc)
427 LOGE("unable to shutdown volume '%s'", v->mount_point);
428 pthread_mutex_unlock(&v->lock);
429 }
430 }
431 return 0;
432 }
433
_cb_volume_stopped_for_eject(volume_t * v,void * arg)434 static void _cb_volume_stopped_for_eject(volume_t *v, void *arg)
435 {
436 void (* eject_cb) (blkdev_t *) = arg;
437
438 #if DEBUG_VOLMGR
439 LOG_VOL("Volume %s has been stopped for eject", v->mount_point);
440 #endif
441
442 if (eject_cb)
443 eject_cb(v->dev);
444 v->dev = NULL; // Clear dev because its being ejected
445 }
446
447 /*
448 * Instructs the volume manager to enable or disable USB mass storage
449 * on any volumes configured to use it.
450 */
volmgr_enable_ums(boolean enable)451 int volmgr_enable_ums(boolean enable)
452 {
453 volume_t *v = vol_root;
454
455 while(v) {
456 if (v->ums_path) {
457 int rc;
458
459 if (enable) {
460 pthread_mutex_lock(&v->lock);
461 if (v->state == volstate_mounted)
462 volmgr_send_eject_request(v);
463 else if (v->state == volstate_ums || v->state == volstate_nomedia) {
464 pthread_mutex_unlock(&v->lock);
465 goto next_vol;
466 }
467
468 // Stop the volume, and enable UMS in the callback
469 rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable, false);
470 if (rc != -EINPROGRESS) {
471 if (rc)
472 LOGE("unable to shutdown volume '%s'", v->mount_point);
473 pthread_mutex_unlock(&v->lock);
474 }
475 } else {
476 // Disable UMS
477 pthread_mutex_lock(&v->lock);
478 if (v->state != volstate_ums) {
479 pthread_mutex_unlock(&v->lock);
480 goto next_vol;
481 }
482
483 if ((rc = ums_disable(v->ums_path)) < 0) {
484 LOGE("unable to disable ums on '%s'", v->mount_point);
485 pthread_mutex_unlock(&v->lock);
486 continue;
487 }
488
489 LOG_VOL("Kick-starting volume %d:%d after UMS disable",
490 v->dev->disk->major, v->dev->disk->minor);
491 // Start volume
492 if ((rc = _volmgr_consider_disk_and_vol(v, v->dev->disk)) < 0) {
493 LOGE("volmgr failed to consider disk %d:%d",
494 v->dev->disk->major, v->dev->disk->minor);
495 }
496 pthread_mutex_unlock(&v->lock);
497 }
498 }
499 next_vol:
500 v = v->next;
501 }
502 return 0;
503 }
504
505 /*
506 * Static functions
507 */
508
volmgr_send_eject_request(volume_t * v)509 static int volmgr_send_eject_request(volume_t *v)
510 {
511 return send_msg_with_data(VOLD_EVT_EJECTING, v->mount_point);
512 }
513
514 // vol->lock must be held!
_volmgr_consider_disk_and_vol(volume_t * vol,blkdev_t * dev)515 static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev)
516 {
517 int rc = 0;
518
519 #if DEBUG_VOLMGR
520 LOG_VOL("volmgr_consider_disk_and_vol(%s, %d:%d):", vol->mount_point,
521 dev->major, dev->minor);
522 #endif
523
524 if (vol->state == volstate_unknown ||
525 vol->state == volstate_mounted ||
526 vol->state == volstate_mounted_ro) {
527 LOGE("Cannot consider volume '%s' because it is in state '%d",
528 vol->mount_point, vol->state);
529 return -EADDRINUSE;
530 }
531
532 if (vol->state == volstate_formatting) {
533 LOG_VOL("Evaluating dev '%s' for formattable filesystems for '%s'",
534 dev->devpath, vol->mount_point);
535 /*
536 * Since we only support creating 1 partition (right now),
537 * we can just lookup the target by devno
538 */
539 blkdev_t *part;
540 if (vol->media_type == media_mmc)
541 part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor) + 1);
542 else
543 part = blkdev_lookup_by_devno(dev->major, 1);
544 if (!part) {
545 if (vol->media_type == media_mmc)
546 part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor));
547 else
548 part = blkdev_lookup_by_devno(dev->major, 0);
549 if (!part) {
550 LOGE("Unable to find device to format");
551 return -ENODEV;
552 }
553 }
554
555 if ((rc = format_partition(part,
556 vol->media_type == media_devmapper ?
557 FORMAT_TYPE_EXT2 : FORMAT_TYPE_FAT32)) < 0) {
558 LOGE("format failed (%d)", rc);
559 return rc;
560 }
561
562 }
563
564 LOGI("Evaluating dev '%s' for mountable filesystems for '%s'",
565 dev->devpath, vol->mount_point);
566
567 if (dev->nr_parts == 0) {
568 rc = _volmgr_start(vol, dev);
569 #if DEBUG_VOLMGR
570 LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d", vol->mount_point,
571 dev->major, dev->minor, rc);
572 #endif
573 } else {
574 /*
575 * Device has multiple partitions
576 * This is where interesting partition policies could be implemented.
577 * For now just try them in sequence until one succeeds
578 */
579
580 rc = -ENODEV;
581 int i;
582 for (i = 0; i < dev->nr_parts; i++) {
583 blkdev_t *part;
584 if (vol->media_type == media_mmc)
585 part = blkdev_lookup_by_devno(dev->major, ALIGN_MMC_MINOR(dev->minor) + (i+1));
586 else
587 part = blkdev_lookup_by_devno(dev->major, (i+1));
588 if (!part) {
589 LOGE("Error - unable to lookup partition for blkdev %d:%d",
590 dev->major, dev->minor);
591 continue;
592 }
593 rc = _volmgr_start(vol, part);
594 #if DEBUG_VOLMGR
595 LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d",
596 vol->mount_point, part->major, part->minor, rc);
597 #endif
598 if (!rc || rc == -EBUSY)
599 break;
600 }
601
602 if (rc == -ENODEV) {
603 // Assert to make sure each partition had a backing blkdev
604 LOGE("Internal consistency error");
605 return 0;
606 }
607 }
608
609 if (rc == -ENODATA) {
610 LOGE("Device %d:%d contains no usable filesystems",
611 dev->major, dev->minor);
612 rc = 0;
613 }
614
615 return rc;
616 }
617
volmgr_reaper_thread_sighandler(int signo)618 static void volmgr_reaper_thread_sighandler(int signo)
619 {
620 LOGE("Volume reaper thread got signal %d", signo);
621 }
622
__reaper_cleanup(void * arg)623 static void __reaper_cleanup(void *arg)
624 {
625 volume_t *vol = (volume_t *) arg;
626
627 if (vol->worker_args.reaper_args.cb)
628 vol->worker_args.reaper_args.cb(vol, vol->worker_args.reaper_args.cb_arg);
629
630 vol->worker_running = false;
631
632 // Wake up anyone that was waiting on this thread
633 pthread_mutex_unlock(&vol->worker_sem);
634
635 // Unlock the volume
636 pthread_mutex_unlock(&vol->lock);
637 }
638
volmgr_reaper_thread(void * arg)639 static void *volmgr_reaper_thread(void *arg)
640 {
641 volume_t *vol = (volume_t *) arg;
642
643 pthread_cleanup_push(__reaper_cleanup, arg);
644
645 vol->worker_running = true;
646 vol->worker_pid = getpid();
647
648 struct sigaction actions;
649
650 memset(&actions, 0, sizeof(actions));
651 sigemptyset(&actions.sa_mask);
652 actions.sa_flags = 0;
653 actions.sa_handler = volmgr_reaper_thread_sighandler;
654 sigaction(SIGUSR1, &actions, NULL);
655
656 LOGW("Reaper here - working on %s", vol->mount_point);
657
658 boolean send_sig_kill = false;
659 int i, rc;
660
661 for (i = 0; i < 10; i++) {
662 errno = 0;
663 rc = umount(vol->mount_point);
664 LOGW("volmngr reaper umount(%s) attempt %d (%s)",
665 vol->mount_point, i + 1, strerror(errno));
666 if (!rc)
667 break;
668 if (rc && (errno == EINVAL || errno == ENOENT)) {
669 rc = 0;
670 break;
671 }
672 sleep(1);
673 if (i >= 4) {
674 KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0);
675 if (!send_sig_kill)
676 send_sig_kill = true;
677 }
678 }
679
680 if (!rc) {
681 LOGI("Reaper sucessfully unmounted %s", vol->mount_point);
682 vol->fs = NULL;
683 volume_setstate(vol, volstate_unmounted);
684 } else {
685 LOGE("Unable to unmount!! (%d)", rc);
686 }
687
688 out:
689 pthread_cleanup_pop(1);
690 pthread_exit(NULL);
691 return NULL;
692 }
693
694 // vol->lock must be held!
volmgr_uncage_reaper(volume_t * vol,void (* cb)(volume_t *,void * arg),void * arg)695 static void volmgr_uncage_reaper(volume_t *vol, void (* cb) (volume_t *, void *arg), void *arg)
696 {
697
698 if (vol->worker_running) {
699 LOGE("Worker thread is currently running.. waiting..");
700 pthread_mutex_lock(&vol->worker_sem);
701 LOGI("Worker thread now available");
702 }
703
704 vol->worker_args.reaper_args.cb = cb;
705 vol->worker_args.reaper_args.cb_arg = arg;
706
707 pthread_attr_t attr;
708 pthread_attr_init(&attr);
709 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
710
711 pthread_create(&vol->worker_thread, &attr, volmgr_reaper_thread, vol);
712 }
713
volmgr_stop_volume(volume_t * v,void (* cb)(volume_t *,void *),void * arg,boolean emit_statechange)714 static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange)
715 {
716 int i, rc;
717
718 if (v->state == volstate_mounted || v->state == volstate_badremoval) {
719 // Try to unmount right away (5 retries)
720 for (i = 0; i < 5; i++) {
721 rc = umount(v->mount_point);
722 if (!rc)
723 break;
724
725 if (rc && (errno == EINVAL || errno == ENOENT)) {
726 rc = 0;
727 break;
728 }
729
730 LOGI("volmngr quick stop umount(%s) attempt %d (%s)",
731 v->mount_point, i + 1, strerror(errno));
732
733 if (i == 0)
734 usleep(1000 * 250); // First failure, sleep for 250 ms
735 else
736 sched_yield();
737 }
738
739 if (!rc) {
740 LOGI("volmgr_stop_volume(%s): Volume unmounted sucessfully",
741 v->mount_point);
742 if (emit_statechange)
743 volume_setstate(v, volstate_unmounted);
744 v->fs = NULL;
745 goto out_cb_immed;
746 }
747
748 /*
749 * Since the volume is still in use, dispatch the stopping to
750 * a thread
751 */
752 LOGW("Volume %s is busy (%d) - uncaging the reaper", v->mount_point, rc);
753 volmgr_uncage_reaper(v, cb, arg);
754 return -EINPROGRESS;
755 } else if (v->state == volstate_checking) {
756 volume_setstate(v, volstate_unmounted);
757 if (v->worker_running) {
758 LOG_VOL("Cancelling worker thread");
759 pthread_kill(v->worker_thread, SIGUSR1);
760 } else
761 LOGE("Strange... we were in checking state but worker thread wasn't running..");
762 goto out_cb_immed;
763 }
764
765 out_cb_immed:
766 if (cb)
767 cb(v, arg);
768 return 0;
769 }
770
771
772 /*
773 * Gracefully stop a volume
774 * v->lock must be held!
775 * if we return -EINPROGRESS, do NOT release the lock as the reaper
776 * is using the volume
777 */
volmgr_shutdown_volume(volume_t * v,void (* cb)(volume_t *,void *),boolean emit_statechange)778 static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *), boolean emit_statechange)
779 {
780 return volmgr_stop_volume(v, cb, NULL, emit_statechange);
781 }
782
_cb_volume_stopped_for_shutdown(volume_t * v,void * arg)783 static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg)
784 {
785 void (* shutdown_cb) (volume_t *) = arg;
786
787 #if DEBUG_VOLMGR
788 LOG_VOL("Volume %s has been stopped for shutdown", v->mount_point);
789 #endif
790 shutdown_cb(v);
791 }
792
793
794 /*
795 * Called when a volume is sucessfully unmounted for UMS enable
796 */
_cb_volstopped_for_ums_enable(volume_t * v,void * arg)797 static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg)
798 {
799 int rc;
800 char *devdir_path;
801
802 #if DEBUG_VOLMGR
803 LOG_VOL("_cb_volstopped_for_ums_enable(%s):", v->mount_point);
804 #endif
805 devdir_path = blkdev_get_devpath(v->dev->disk);
806
807 if ((rc = ums_enable(devdir_path, v->ums_path)) < 0) {
808 free(devdir_path);
809 LOGE("Error enabling ums (%d)", rc);
810 return;
811 }
812 free(devdir_path);
813 volume_setstate(v, volstate_ums);
814 pthread_mutex_unlock(&v->lock);
815 }
816
volmgr_readconfig(char * cfg_path)817 static int volmgr_readconfig(char *cfg_path)
818 {
819 cnode *root = config_node("", "");
820 cnode *node;
821
822 config_load_file(root, cfg_path);
823 node = root->first_child;
824
825 while (node) {
826 if (!strncmp(node->name, "volume_", 7))
827 volmgr_config_volume(node);
828 else
829 LOGE("Skipping unknown configuration node '%s'", node->name);
830 node = node->next;
831 }
832 return 0;
833 }
834
volmgr_add_mediapath_to_volume(volume_t * v,char * media_path)835 static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path)
836 {
837 int i;
838
839 #if DEBUG_VOLMGR
840 LOG_VOL("volmgr_add_mediapath_to_volume(%p, %s):", v, media_path);
841 #endif
842 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
843 if (!v->media_paths[i]) {
844 v->media_paths[i] = strdup(media_path);
845 return;
846 }
847 }
848 LOGE("Unable to add media path '%s' to volume (out of media slots)", media_path);
849 }
850
volmgr_config_volume(cnode * node)851 static int volmgr_config_volume(cnode *node)
852 {
853 volume_t *new;
854 int rc = 0, i;
855
856 char *dm_src, *dm_src_type, *dm_tgt, *dm_param, *dm_tgtfs;
857 uint32_t dm_size_mb = 0;
858
859 dm_src = dm_src_type = dm_tgt = dm_param = dm_tgtfs = NULL;
860 #if DEBUG_VOLMGR
861 LOG_VOL("volmgr_configure_volume(%s):", node->name);
862 #endif
863 if (!(new = malloc(sizeof(volume_t))))
864 return -ENOMEM;
865 memset(new, 0, sizeof(volume_t));
866
867 new->state = volstate_nomedia;
868 pthread_mutex_init(&new->lock, NULL);
869 pthread_mutex_init(&new->worker_sem, NULL);
870
871 cnode *child = node->first_child;
872
873 while (child) {
874 if (!strcmp(child->name, "media_path"))
875 volmgr_add_mediapath_to_volume(new, child->value);
876 else if (!strcmp(child->name, "emu_media_path"))
877 volmgr_add_mediapath_to_volume(new, child->value);
878 else if (!strcmp(child->name, "media_type")) {
879 if (!strcmp(child->value, "mmc"))
880 new->media_type = media_mmc;
881 else if (!strcmp(child->value, "devmapper"))
882 new->media_type = media_devmapper;
883 else {
884 LOGE("Invalid media type '%s'", child->value);
885 rc = -EINVAL;
886 goto out_free;
887 }
888 } else if (!strcmp(child->name, "mount_point"))
889 new->mount_point = strdup(child->value);
890 else if (!strcmp(child->name, "ums_path"))
891 new->ums_path = strdup(child->value);
892 else if (!strcmp(child->name, "dm_src"))
893 dm_src = strdup(child->value);
894 else if (!strcmp(child->name, "dm_src_type"))
895 dm_src_type = strdup(child->value);
896 else if (!strcmp(child->name, "dm_src_size_mb"))
897 dm_size_mb = atoi(child->value);
898 else if (!strcmp(child->name, "dm_target"))
899 dm_tgt = strdup(child->value);
900 else if (!strcmp(child->name, "dm_target_params"))
901 dm_param = strdup(child->value);
902 else if (!strcmp(child->name, "dm_target_fs"))
903 dm_tgtfs = strdup(child->value);
904 else
905 LOGE("Ignoring unknown config entry '%s'", child->name);
906 child = child->next;
907 }
908
909 if (new->media_type == media_mmc) {
910 if (!new->media_paths[0] || !new->mount_point || new->media_type == media_unknown) {
911 LOGE("Required configuration parameter missing for mmc volume");
912 rc = -EINVAL;
913 goto out_free;
914 }
915 } else if (new->media_type == media_devmapper) {
916 if (!dm_src || !dm_src_type || !dm_tgt ||
917 !dm_param || !dm_tgtfs || !dm_size_mb) {
918 LOGE("Required configuration parameter missing for devmapper volume");
919 rc = -EINVAL;
920 goto out_free;
921 }
922
923 char dm_mediapath[255];
924 if (!(new->dm = devmapper_init(dm_src, dm_src_type, dm_size_mb,
925 dm_tgt, dm_param, dm_tgtfs, dm_mediapath))) {
926 LOGE("Unable to initialize devmapping");
927 goto out_free;
928 }
929 LOG_VOL("media path for devmapper volume = '%s'", dm_mediapath);
930 volmgr_add_mediapath_to_volume(new, dm_mediapath);
931 }
932
933 if (!vol_root)
934 vol_root = new;
935 else {
936 volume_t *scan = vol_root;
937 while (scan->next)
938 scan = scan->next;
939 scan->next = new;
940 }
941
942 if (dm_src)
943 free(dm_src);
944 if (dm_src_type)
945 free(dm_src_type);
946 if (dm_tgt)
947 free(dm_tgt);
948 if (dm_param)
949 free(dm_param);
950 if (dm_tgtfs)
951 free(dm_tgtfs);
952
953 return rc;
954
955 out_free:
956
957 if (dm_src)
958 free(dm_src);
959 if (dm_src_type)
960 free(dm_src_type);
961 if (dm_tgt)
962 free(dm_tgt);
963 if (dm_param)
964 free(dm_param);
965 if (dm_tgtfs)
966 free(dm_tgtfs);
967
968
969 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
970 if (new->media_paths[i])
971 free(new->media_paths[i]);
972 }
973 if (new->mount_point)
974 free(new->mount_point);
975 if (new->ums_path)
976 free(new->ums_path);
977 return rc;
978 }
979
volmgr_lookup_volume_by_dev(blkdev_t * dev)980 static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev)
981 {
982 volume_t *scan = vol_root;
983 while(scan) {
984 if (scan->dev == dev)
985 return scan;
986 scan = scan->next;
987 }
988 return NULL;
989 }
990
volmgr_lookup_volume_by_mountpoint(char * mount_point,boolean leave_locked)991 static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked)
992 {
993 volume_t *v = vol_root;
994
995 while(v) {
996 pthread_mutex_lock(&v->lock);
997 if (!strcmp(v->mount_point, mount_point)) {
998 if (!leave_locked)
999 pthread_mutex_unlock(&v->lock);
1000 return v;
1001 }
1002 pthread_mutex_unlock(&v->lock);
1003 v = v->next;
1004 }
1005 return NULL;
1006 }
1007
volmgr_lookup_volume_by_mediapath(char * media_path,boolean fuzzy)1008 static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy)
1009 {
1010 volume_t *scan = vol_root;
1011 int i;
1012
1013 while (scan) {
1014
1015 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
1016 if (!scan->media_paths[i])
1017 continue;
1018
1019 if (fuzzy && !strncmp(media_path, scan->media_paths[i], strlen(scan->media_paths[i])))
1020 return scan;
1021 else if (!fuzzy && !strcmp(media_path, scan->media_paths[i]))
1022 return scan;
1023 }
1024
1025 scan = scan->next;
1026 }
1027 return NULL;
1028 }
1029
1030 /*
1031 * Attempt to bring a volume online
1032 * Returns: 0 on success, errno on failure, with the following exceptions:
1033 * - ENODATA - Unsupported filesystem type / blank
1034 * vol->lock MUST be held!
1035 */
_volmgr_start(volume_t * vol,blkdev_t * dev)1036 static int _volmgr_start(volume_t *vol, blkdev_t *dev)
1037 {
1038 struct volmgr_fstable_entry *fs;
1039 int rc = ENODATA;
1040
1041 #if DEBUG_VOLMGR
1042 LOG_VOL("_volmgr_start(%s, %d:%d):", vol->mount_point,
1043 dev->major, dev->minor);
1044 #endif
1045
1046 if (vol->state == volstate_mounted) {
1047 LOGE("Unable to start volume '%s' (already mounted)", vol->mount_point);
1048 return -EBUSY;
1049 }
1050
1051 for (fs = fs_table; fs->name; fs++) {
1052 if (!fs->identify_fn(dev))
1053 break;
1054 }
1055
1056 if (!fs) {
1057 LOGE("No supported filesystems on %d:%d", dev->major, dev->minor);
1058 volume_setstate(vol, volstate_nofs);
1059 return -ENODATA;
1060 }
1061
1062 return volmgr_start_fs(fs, vol, dev);
1063 }
1064
1065 // vol->lock MUST be held!
volmgr_start_fs(struct volmgr_fstable_entry * fs,volume_t * vol,blkdev_t * dev)1066 static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev)
1067 {
1068 /*
1069 * Spawn a thread to do the actual checking / mounting in
1070 */
1071
1072 if (vol->worker_running) {
1073 LOGE("Worker thread is currently running.. waiting..");
1074 pthread_mutex_lock(&vol->worker_sem);
1075 LOGI("Worker thread now available");
1076 }
1077
1078 vol->dev = dev;
1079
1080 if (bootstrap) {
1081 LOGI("Aborting start of %s (bootstrap = %d)\n", vol->mount_point,
1082 bootstrap);
1083 vol->state = volstate_unmounted;
1084 return -EBUSY;
1085 }
1086
1087 vol->worker_args.start_args.fs = fs;
1088 vol->worker_args.start_args.dev = dev;
1089
1090 pthread_attr_t attr;
1091 pthread_attr_init(&attr);
1092 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1093
1094 pthread_create(&vol->worker_thread, &attr, volmgr_start_fs_thread, vol);
1095
1096 return 0;
1097 }
1098
__start_fs_thread_lock_cleanup(void * arg)1099 static void __start_fs_thread_lock_cleanup(void *arg)
1100 {
1101 volume_t *vol = (volume_t *) arg;
1102
1103 #if DEBUG_VOLMGR
1104 LOG_VOL("__start_fs_thread_lock_cleanup(%s):", vol->mount_point);
1105 #endif
1106
1107 vol->worker_running = false;
1108
1109 // Wake up anyone that was waiting on this thread
1110 pthread_mutex_unlock(&vol->worker_sem);
1111
1112 // Unlock the volume
1113 pthread_mutex_unlock(&vol->lock);
1114 }
1115
volmgr_start_fs_thread(void * arg)1116 static void *volmgr_start_fs_thread(void *arg)
1117 {
1118 volume_t *vol = (volume_t *) arg;
1119
1120 pthread_cleanup_push(__start_fs_thread_lock_cleanup, arg);
1121 pthread_mutex_lock(&vol->lock);
1122
1123 vol->worker_running = true;
1124 vol->worker_pid = getpid();
1125
1126 struct sigaction actions;
1127
1128 memset(&actions, 0, sizeof(actions));
1129 sigemptyset(&actions.sa_mask);
1130 actions.sa_flags = 0;
1131 actions.sa_handler = volmgr_start_fs_thread_sighandler;
1132 sigaction(SIGUSR1, &actions, NULL);
1133
1134 struct volmgr_fstable_entry *fs = vol->worker_args.start_args.fs;
1135 blkdev_t *dev = vol->worker_args.start_args.dev;
1136 int rc;
1137
1138 #if DEBUG_VOLMGR
1139 LOG_VOL("Worker thread pid %d starting %s fs %d:%d on %s", getpid(),
1140 fs->name, dev->major, dev->minor, vol->mount_point);
1141 #endif
1142
1143 if (fs->check_fn) {
1144 #if DEBUG_VOLMGR
1145 LOG_VOL("Starting %s filesystem check on %d:%d", fs->name,
1146 dev->major, dev->minor);
1147 #endif
1148 volume_setstate(vol, volstate_checking);
1149 pthread_mutex_unlock(&vol->lock);
1150 rc = fs->check_fn(dev);
1151 pthread_mutex_lock(&vol->lock);
1152 if (vol->state != volstate_checking) {
1153 LOGE("filesystem check aborted");
1154 goto out;
1155 }
1156
1157 if (rc < 0) {
1158 LOGE("%s filesystem check failed on %d:%d (%s)", fs->name,
1159 dev->major, dev->minor, strerror(-rc));
1160 if (rc == -ENODATA) {
1161 volume_setstate(vol, volstate_nofs);
1162 goto out;
1163 }
1164 goto out_unmountable;
1165 }
1166 #if DEBUG_VOLMGR
1167 LOGI("%s filesystem check of %d:%d OK", fs->name,
1168 dev->major, dev->minor);
1169 #endif
1170 }
1171
1172 rc = fs->mount_fn(dev, vol, safe_mode);
1173 if (!rc) {
1174 LOGI("Sucessfully mounted %s filesystem %d:%d on %s (safe-mode %s)",
1175 fs->name, dev->major, dev->minor, vol->mount_point,
1176 (safe_mode ? "on" : "off"));
1177 vol->fs = fs;
1178 volume_setstate(vol, volstate_mounted);
1179 goto out;
1180 }
1181
1182 LOGE("%s filesystem mount of %d:%d failed (%d)", fs->name, dev->major,
1183 dev->minor, rc);
1184
1185 out_unmountable:
1186 volume_setstate(vol, volstate_damaged);
1187 out:
1188 pthread_cleanup_pop(1);
1189 pthread_exit(NULL);
1190 return NULL;
1191 }
1192
volmgr_start_fs_thread_sighandler(int signo)1193 static void volmgr_start_fs_thread_sighandler(int signo)
1194 {
1195 LOGE("Volume startup thread got signal %d", signo);
1196 }
1197
volume_setstate(volume_t * vol,volume_state_t state)1198 static void volume_setstate(volume_t *vol, volume_state_t state)
1199 {
1200 if (state == vol->state)
1201 return;
1202
1203 #if DEBUG_VOLMGR
1204 LOG_VOL("Volume %s state change from %d -> %d", vol->mount_point, vol->state, state);
1205 #endif
1206
1207 vol->state = state;
1208
1209 char *prop_val = conv_volstate_to_propstr(vol->state);
1210
1211 if (prop_val) {
1212 property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val);
1213 volume_send_state(vol);
1214 }
1215 }
1216
volume_send_state(volume_t * vol)1217 static int volume_send_state(volume_t *vol)
1218 {
1219 char *event = conv_volstate_to_eventstr(vol->state);
1220
1221 return send_msg_with_data(event, vol->mount_point);
1222 }
1223
conv_volstate_to_eventstr(volume_state_t state)1224 static char *conv_volstate_to_eventstr(volume_state_t state)
1225 {
1226 int i;
1227
1228 for (i = 0; volume_state_strings[i].event != NULL; i++) {
1229 if (volume_state_strings[i].state == state)
1230 break;
1231 }
1232
1233 return volume_state_strings[i].event;
1234 }
1235
conv_volstate_to_propstr(volume_state_t state)1236 static char *conv_volstate_to_propstr(volume_state_t state)
1237 {
1238 int i;
1239
1240 for (i = 0; volume_state_strings[i].event != NULL; i++) {
1241 if (volume_state_strings[i].state == state)
1242 break;
1243 }
1244
1245 return volume_state_strings[i].property_val;
1246 }
1247
1248