• 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 <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