OSDN Git Service

merge in master-release history after reset to 8c008397141bf9a7d619eb2c53452bf3e397da39
[android-x86/system-vold.git] / VolumeManager.cpp
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <fts.h>
23 #include <unistd.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <sys/mount.h>
27 #include <dirent.h>
28
29 #include <linux/kdev_t.h>
30
31 #define LOG_TAG "Vold"
32
33 #include <openssl/md5.h>
34
35 #include <cutils/fs.h>
36 #include <cutils/log.h>
37
38 #include <selinux/android.h>
39
40 #include <sysutils/NetlinkEvent.h>
41
42 #include <private/android_filesystem_config.h>
43
44 #include "VolumeManager.h"
45 #include "DirectVolume.h"
46 #include "ResponseCode.h"
47 #include "Loop.h"
48 #include "Ext4.h"
49 #include "Fat.h"
50 #include "Devmapper.h"
51 #include "Process.h"
52 #include "Asec.h"
53 #include "cryptfs.h"
54
55 #define MASS_STORAGE_FILE_PATH  "/sys/class/android_usb/android0/f_mass_storage/lun/file"
56
57 VolumeManager *VolumeManager::sInstance = NULL;
58
59 VolumeManager *VolumeManager::Instance() {
60     if (!sInstance)
61         sInstance = new VolumeManager();
62     return sInstance;
63 }
64
65 VolumeManager::VolumeManager() {
66     mDebug = false;
67     mVolumes = new VolumeCollection();
68     mActiveContainers = new AsecIdCollection();
69     mBroadcaster = NULL;
70     mUmsSharingCount = 0;
71     mSavedDirtyRatio = -1;
72     // set dirty ratio to 0 when UMS is active
73     mUmsDirtyRatio = 0;
74     mVolManagerDisabled = 0;
75 }
76
77 VolumeManager::~VolumeManager() {
78     delete mVolumes;
79     delete mActiveContainers;
80 }
81
82 char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
83     static const char* digits = "0123456789abcdef";
84
85     unsigned char sig[MD5_DIGEST_LENGTH];
86
87     if (buffer == NULL) {
88         SLOGE("Destination buffer is NULL");
89         errno = ESPIPE;
90         return NULL;
91     } else if (id == NULL) {
92         SLOGE("Source buffer is NULL");
93         errno = ESPIPE;
94         return NULL;
95     } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
96         SLOGE("Target hash buffer size < %d bytes (%zu)",
97                 MD5_ASCII_LENGTH_PLUS_NULL, len);
98         errno = ESPIPE;
99         return NULL;
100     }
101
102     MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
103
104     char *p = buffer;
105     for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
106         *p++ = digits[sig[i] >> 4];
107         *p++ = digits[sig[i] & 0x0F];
108     }
109     *p = '\0';
110
111     return buffer;
112 }
113
114 void VolumeManager::setDebug(bool enable) {
115     mDebug = enable;
116     VolumeCollection::iterator it;
117     for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
118         (*it)->setDebug(enable);
119     }
120 }
121
122 int VolumeManager::start() {
123     return 0;
124 }
125
126 int VolumeManager::stop() {
127     return 0;
128 }
129
130 int VolumeManager::addVolume(Volume *v) {
131     mVolumes->push_back(v);
132     return 0;
133 }
134
135 void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
136     const char *devpath = evt->findParam("DEVPATH");
137
138     /* Lookup a volume to handle this device */
139     VolumeCollection::iterator it;
140     bool hit = false;
141     for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
142         if (!(*it)->handleBlockEvent(evt)) {
143 #ifdef NETLINK_DEBUG
144             SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
145 #endif
146             hit = true;
147             break;
148         }
149     }
150
151     if (!hit) {
152 #ifdef NETLINK_DEBUG
153         SLOGW("No volumes handled block event for '%s'", devpath);
154 #endif
155     }
156 }
157
158 int VolumeManager::listVolumes(SocketClient *cli) {
159     VolumeCollection::iterator i;
160
161     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
162         char *buffer;
163         asprintf(&buffer, "%s %s %d",
164                  (*i)->getLabel(), (*i)->getFuseMountpoint(),
165                  (*i)->getState());
166         cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
167         free(buffer);
168     }
169     cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
170     return 0;
171 }
172
173 int VolumeManager::formatVolume(const char *label, bool wipe) {
174     Volume *v = lookupVolume(label);
175
176     if (!v) {
177         errno = ENOENT;
178         return -1;
179     }
180
181     if (mVolManagerDisabled) {
182         errno = EBUSY;
183         return -1;
184     }
185
186     return v->formatVol(wipe);
187 }
188
189 int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
190     char idHash[33];
191     if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
192         SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
193         return -1;
194     }
195
196     memset(mountPath, 0, mountPathLen);
197     int written = snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
198     if ((written < 0) || (written >= mountPathLen)) {
199         errno = EINVAL;
200         return -1;
201     }
202
203     if (access(mountPath, F_OK)) {
204         errno = ENOENT;
205         return -1;
206     }
207
208     return 0;
209 }
210
211 int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
212     char asecFileName[255];
213
214     if (!isLegalAsecId(id)) {
215         SLOGE("getAsecMountPath: Invalid asec id \"%s\"", id);
216         errno = EINVAL;
217         return -1;
218     }
219
220     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
221         SLOGE("Couldn't find ASEC %s", id);
222         return -1;
223     }
224
225     memset(buffer, 0, maxlen);
226     if (access(asecFileName, F_OK)) {
227         errno = ENOENT;
228         return -1;
229     }
230
231     int written = snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
232     if ((written < 0) || (written >= maxlen)) {
233         SLOGE("getAsecMountPath failed for %s: couldn't construct path in buffer", id);
234         errno = EINVAL;
235         return -1;
236     }
237
238     return 0;
239 }
240
241 int VolumeManager::getAsecFilesystemPath(const char *id, char *buffer, int maxlen) {
242     char asecFileName[255];
243
244     if (!isLegalAsecId(id)) {
245         SLOGE("getAsecFilesystemPath: Invalid asec id \"%s\"", id);
246         errno = EINVAL;
247         return -1;
248     }
249
250     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
251         SLOGE("Couldn't find ASEC %s", id);
252         return -1;
253     }
254
255     memset(buffer, 0, maxlen);
256     if (access(asecFileName, F_OK)) {
257         errno = ENOENT;
258         return -1;
259     }
260
261     int written = snprintf(buffer, maxlen, "%s", asecFileName);
262     if ((written < 0) || (written >= maxlen)) {
263         errno = EINVAL;
264         return -1;
265     }
266
267     return 0;
268 }
269
270 int VolumeManager::createAsec(const char *id, unsigned int numSectors, const char *fstype,
271         const char *key, const int ownerUid, bool isExternal) {
272     struct asec_superblock sb;
273     memset(&sb, 0, sizeof(sb));
274
275     if (!isLegalAsecId(id)) {
276         SLOGE("createAsec: Invalid asec id \"%s\"", id);
277         errno = EINVAL;
278         return -1;
279     }
280
281     const bool wantFilesystem = strcmp(fstype, "none");
282     bool usingExt4 = false;
283     if (wantFilesystem) {
284         usingExt4 = !strcmp(fstype, "ext4");
285         if (usingExt4) {
286             sb.c_opts |= ASEC_SB_C_OPTS_EXT4;
287         } else if (strcmp(fstype, "fat")) {
288             SLOGE("Invalid filesystem type %s", fstype);
289             errno = EINVAL;
290             return -1;
291         }
292     }
293
294     sb.magic = ASEC_SB_MAGIC;
295     sb.ver = ASEC_SB_VER;
296
297     if (numSectors < ((1024*1024)/512)) {
298         SLOGE("Invalid container size specified (%d sectors)", numSectors);
299         errno = EINVAL;
300         return -1;
301     }
302
303     if (lookupVolume(id)) {
304         SLOGE("ASEC id '%s' currently exists", id);
305         errno = EADDRINUSE;
306         return -1;
307     }
308
309     char asecFileName[255];
310
311     if (!findAsec(id, asecFileName, sizeof(asecFileName))) {
312         SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
313                 asecFileName, strerror(errno));
314         errno = EADDRINUSE;
315         return -1;
316     }
317
318     const char *asecDir = isExternal ? Volume::SEC_ASECDIR_EXT : Volume::SEC_ASECDIR_INT;
319
320     int written = snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", asecDir, id);
321     if ((written < 0) || (size_t(written) >= sizeof(asecFileName))) {
322         errno = EINVAL;
323         return -1;
324     }
325
326     if (!access(asecFileName, F_OK)) {
327         SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
328                 asecFileName, strerror(errno));
329         errno = EADDRINUSE;
330         return -1;
331     }
332
333     /*
334      * Add some headroom
335      */
336     unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
337     unsigned numImgSectors = numSectors + fatSize + 2;
338
339     if (numImgSectors % 63) {
340         numImgSectors += (63 - (numImgSectors % 63));
341     }
342
343     // Add +1 for our superblock which is at the end
344     if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
345         SLOGE("ASEC image file creation failed (%s)", strerror(errno));
346         return -1;
347     }
348
349     char idHash[33];
350     if (!asecHash(id, idHash, sizeof(idHash))) {
351         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
352         unlink(asecFileName);
353         return -1;
354     }
355
356     char loopDevice[255];
357     if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
358         SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
359         unlink(asecFileName);
360         return -1;
361     }
362
363     char dmDevice[255];
364     bool cleanupDm = false;
365
366     if (strcmp(key, "none")) {
367         // XXX: This is all we support for now
368         sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
369         if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
370                              sizeof(dmDevice))) {
371             SLOGE("ASEC device mapping failed (%s)", strerror(errno));
372             Loop::destroyByDevice(loopDevice);
373             unlink(asecFileName);
374             return -1;
375         }
376         cleanupDm = true;
377     } else {
378         sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
379         strcpy(dmDevice, loopDevice);
380     }
381
382     /*
383      * Drop down the superblock at the end of the file
384      */
385
386     int sbfd = open(loopDevice, O_RDWR);
387     if (sbfd < 0) {
388         SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
389         if (cleanupDm) {
390             Devmapper::destroy(idHash);
391         }
392         Loop::destroyByDevice(loopDevice);
393         unlink(asecFileName);
394         return -1;
395     }
396
397     if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
398         close(sbfd);
399         SLOGE("Failed to lseek for superblock (%s)", strerror(errno));
400         if (cleanupDm) {
401             Devmapper::destroy(idHash);
402         }
403         Loop::destroyByDevice(loopDevice);
404         unlink(asecFileName);
405         return -1;
406     }
407
408     if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
409         close(sbfd);
410         SLOGE("Failed to write superblock (%s)", strerror(errno));
411         if (cleanupDm) {
412             Devmapper::destroy(idHash);
413         }
414         Loop::destroyByDevice(loopDevice);
415         unlink(asecFileName);
416         return -1;
417     }
418     close(sbfd);
419
420     if (wantFilesystem) {
421         int formatStatus;
422         char mountPoint[255];
423
424         int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
425         if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
426             SLOGE("ASEC fs format failed: couldn't construct mountPoint");
427             if (cleanupDm) {
428                 Devmapper::destroy(idHash);
429             }
430             Loop::destroyByDevice(loopDevice);
431             unlink(asecFileName);
432             return -1;
433         }
434
435         if (usingExt4) {
436             formatStatus = Ext4::format(dmDevice, mountPoint);
437         } else {
438             formatStatus = Fat::format(dmDevice, numImgSectors, 0);
439         }
440
441         if (formatStatus < 0) {
442             SLOGE("ASEC fs format failed (%s)", strerror(errno));
443             if (cleanupDm) {
444                 Devmapper::destroy(idHash);
445             }
446             Loop::destroyByDevice(loopDevice);
447             unlink(asecFileName);
448             return -1;
449         }
450
451         if (mkdir(mountPoint, 0000)) {
452             if (errno != EEXIST) {
453                 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
454                 if (cleanupDm) {
455                     Devmapper::destroy(idHash);
456                 }
457                 Loop::destroyByDevice(loopDevice);
458                 unlink(asecFileName);
459                 return -1;
460             }
461         }
462
463         int mountStatus;
464         if (usingExt4) {
465             mountStatus = Ext4::doMount(dmDevice, mountPoint, false, false, false);
466         } else {
467             mountStatus = Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid, 0, 0000,
468                     false);
469         }
470
471         if (mountStatus) {
472             SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
473             if (cleanupDm) {
474                 Devmapper::destroy(idHash);
475             }
476             Loop::destroyByDevice(loopDevice);
477             unlink(asecFileName);
478             return -1;
479         }
480
481         if (usingExt4) {
482             int dirfd = open(mountPoint, O_DIRECTORY);
483             if (dirfd >= 0) {
484                 if (fchown(dirfd, ownerUid, AID_SYSTEM)
485                         || fchmod(dirfd, S_IRUSR | S_IWUSR | S_IXUSR | S_ISGID | S_IRGRP | S_IXGRP)) {
486                     SLOGI("Cannot chown/chmod new ASEC mount point %s", mountPoint);
487                 }
488                 close(dirfd);
489             }
490         }
491     } else {
492         SLOGI("Created raw secure container %s (no filesystem)", id);
493     }
494
495     mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
496     return 0;
497 }
498
499 int VolumeManager::finalizeAsec(const char *id) {
500     char asecFileName[255];
501     char loopDevice[255];
502     char mountPoint[255];
503
504     if (!isLegalAsecId(id)) {
505         SLOGE("finalizeAsec: Invalid asec id \"%s\"", id);
506         errno = EINVAL;
507         return -1;
508     }
509
510     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
511         SLOGE("Couldn't find ASEC %s", id);
512         return -1;
513     }
514
515     char idHash[33];
516     if (!asecHash(id, idHash, sizeof(idHash))) {
517         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
518         return -1;
519     }
520
521     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
522         SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
523         return -1;
524     }
525
526     unsigned int nr_sec = 0;
527     struct asec_superblock sb;
528
529     if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
530         return -1;
531     }
532
533     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
534     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
535         SLOGE("ASEC finalize failed: couldn't construct mountPoint");
536         return -1;
537     }
538
539     int result = 0;
540     if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
541         result = Ext4::doMount(loopDevice, mountPoint, true, true, true);
542     } else {
543         result = Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false);
544     }
545
546     if (result) {
547         SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
548         return -1;
549     }
550
551     if (mDebug) {
552         SLOGD("ASEC %s finalized", id);
553     }
554     return 0;
555 }
556
557 int VolumeManager::fixupAsecPermissions(const char *id, gid_t gid, const char* filename) {
558     char asecFileName[255];
559     char loopDevice[255];
560     char mountPoint[255];
561
562     if (gid < AID_APP) {
563         SLOGE("Group ID is not in application range");
564         return -1;
565     }
566
567     if (!isLegalAsecId(id)) {
568         SLOGE("fixupAsecPermissions: Invalid asec id \"%s\"", id);
569         errno = EINVAL;
570         return -1;
571     }
572
573     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
574         SLOGE("Couldn't find ASEC %s", id);
575         return -1;
576     }
577
578     char idHash[33];
579     if (!asecHash(id, idHash, sizeof(idHash))) {
580         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
581         return -1;
582     }
583
584     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
585         SLOGE("Unable fix permissions during lookup on %s (%s)", id, strerror(errno));
586         return -1;
587     }
588
589     unsigned int nr_sec = 0;
590     struct asec_superblock sb;
591
592     if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
593         return -1;
594     }
595
596     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
597     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
598         SLOGE("Unable remount to fix permissions for %s: couldn't construct mountpoint", id);
599         return -1;
600     }
601
602     int result = 0;
603     if ((sb.c_opts & ASEC_SB_C_OPTS_EXT4) == 0) {
604         return 0;
605     }
606
607     int ret = Ext4::doMount(loopDevice, mountPoint,
608             false /* read-only */,
609             true  /* remount */,
610             false /* executable */);
611     if (ret) {
612         SLOGE("Unable remount to fix permissions for %s (%s)", id, strerror(errno));
613         return -1;
614     }
615
616     char *paths[] = { mountPoint, NULL };
617
618     FTS *fts = fts_open(paths, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL);
619     if (fts) {
620         // Traverse the entire hierarchy and chown to system UID.
621         for (FTSENT *ftsent = fts_read(fts); ftsent != NULL; ftsent = fts_read(fts)) {
622             // We don't care about the lost+found directory.
623             if (!strcmp(ftsent->fts_name, "lost+found")) {
624                 continue;
625             }
626
627             /*
628              * There can only be one file marked as private right now.
629              * This should be more robust, but it satisfies the requirements
630              * we have for right now.
631              */
632             const bool privateFile = !strcmp(ftsent->fts_name, filename);
633
634             int fd = open(ftsent->fts_accpath, O_NOFOLLOW);
635             if (fd < 0) {
636                 SLOGE("Couldn't open file %s: %s", ftsent->fts_accpath, strerror(errno));
637                 result = -1;
638                 continue;
639             }
640
641             result |= fchown(fd, AID_SYSTEM, privateFile? gid : AID_SYSTEM);
642
643             if (ftsent->fts_info & FTS_D) {
644                 result |= fchmod(fd, 0755);
645             } else if (ftsent->fts_info & FTS_F) {
646                 result |= fchmod(fd, privateFile ? 0640 : 0644);
647             }
648
649             if (selinux_android_restorecon(ftsent->fts_path, 0) < 0) {
650                 SLOGE("restorecon failed for %s: %s\n", ftsent->fts_path, strerror(errno));
651                 result |= -1;
652             }
653
654             close(fd);
655         }
656         fts_close(fts);
657
658         // Finally make the directory readable by everyone.
659         int dirfd = open(mountPoint, O_DIRECTORY);
660         if (dirfd < 0 || fchmod(dirfd, 0755)) {
661             SLOGE("Couldn't change owner of existing directory %s: %s", mountPoint, strerror(errno));
662             result |= -1;
663         }
664         close(dirfd);
665     } else {
666         result |= -1;
667     }
668
669     result |= Ext4::doMount(loopDevice, mountPoint,
670             true /* read-only */,
671             true /* remount */,
672             true /* execute */);
673
674     if (result) {
675         SLOGE("ASEC fix permissions failed (%s)", strerror(errno));
676         return -1;
677     }
678
679     if (mDebug) {
680         SLOGD("ASEC %s permissions fixed", id);
681     }
682     return 0;
683 }
684
685 int VolumeManager::renameAsec(const char *id1, const char *id2) {
686     char asecFilename1[255];
687     char *asecFilename2;
688     char mountPoint[255];
689
690     const char *dir;
691
692     if (!isLegalAsecId(id1)) {
693         SLOGE("renameAsec: Invalid asec id1 \"%s\"", id1);
694         errno = EINVAL;
695         return -1;
696     }
697
698     if (!isLegalAsecId(id2)) {
699         SLOGE("renameAsec: Invalid asec id2 \"%s\"", id2);
700         errno = EINVAL;
701         return -1;
702     }
703
704     if (findAsec(id1, asecFilename1, sizeof(asecFilename1), &dir)) {
705         SLOGE("Couldn't find ASEC %s", id1);
706         return -1;
707     }
708
709     asprintf(&asecFilename2, "%s/%s.asec", dir, id2);
710
711     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
712     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
713         SLOGE("Rename failed: couldn't construct mountpoint");
714         goto out_err;
715     }
716
717     if (isMountpointMounted(mountPoint)) {
718         SLOGW("Rename attempt when src mounted");
719         errno = EBUSY;
720         goto out_err;
721     }
722
723     written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
724     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
725         SLOGE("Rename failed: couldn't construct mountpoint2");
726         goto out_err;
727     }
728
729     if (isMountpointMounted(mountPoint)) {
730         SLOGW("Rename attempt when dst mounted");
731         errno = EBUSY;
732         goto out_err;
733     }
734
735     if (!access(asecFilename2, F_OK)) {
736         SLOGE("Rename attempt when dst exists");
737         errno = EADDRINUSE;
738         goto out_err;
739     }
740
741     if (rename(asecFilename1, asecFilename2)) {
742         SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
743         goto out_err;
744     }
745
746     free(asecFilename2);
747     return 0;
748
749 out_err:
750     free(asecFilename2);
751     return -1;
752 }
753
754 #define UNMOUNT_RETRIES 5
755 #define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
756 int VolumeManager::unmountAsec(const char *id, bool force) {
757     char asecFileName[255];
758     char mountPoint[255];
759
760     if (!isLegalAsecId(id)) {
761         SLOGE("unmountAsec: Invalid asec id \"%s\"", id);
762         errno = EINVAL;
763         return -1;
764     }
765
766     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
767         SLOGE("Couldn't find ASEC %s", id);
768         return -1;
769     }
770
771     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
772     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
773         SLOGE("ASEC unmount failed for %s: couldn't construct mountpoint", id);
774         return -1;
775     }
776
777     char idHash[33];
778     if (!asecHash(id, idHash, sizeof(idHash))) {
779         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
780         return -1;
781     }
782
783     return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
784 }
785
786 int VolumeManager::unmountObb(const char *fileName, bool force) {
787     char mountPoint[255];
788
789     char idHash[33];
790     if (!asecHash(fileName, idHash, sizeof(idHash))) {
791         SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
792         return -1;
793     }
794
795     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
796     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
797         SLOGE("OBB unmount failed for %s: couldn't construct mountpoint", fileName);
798         return -1;
799     }
800
801     return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
802 }
803
804 int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
805         const char *fileName, const char *mountPoint, bool force) {
806     if (!isMountpointMounted(mountPoint)) {
807         SLOGE("Unmount request for %s when not mounted", id);
808         errno = ENOENT;
809         return -1;
810     }
811
812     int i, rc;
813     for (i = 1; i <= UNMOUNT_RETRIES; i++) {
814         rc = umount(mountPoint);
815         if (!rc) {
816             break;
817         }
818         if (rc && (errno == EINVAL || errno == ENOENT)) {
819             SLOGI("Container %s unmounted OK", id);
820             rc = 0;
821             break;
822         }
823         SLOGW("%s unmount attempt %d failed (%s)",
824               id, i, strerror(errno));
825
826         int action = 0; // default is to just complain
827
828         if (force) {
829             if (i > (UNMOUNT_RETRIES - 2))
830                 action = 2; // SIGKILL
831             else if (i > (UNMOUNT_RETRIES - 3))
832                 action = 1; // SIGHUP
833         }
834
835         Process::killProcessesWithOpenFiles(mountPoint, action);
836         usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
837     }
838
839     if (rc) {
840         errno = EBUSY;
841         SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
842         return -1;
843     }
844
845     int retries = 10;
846
847     while(retries--) {
848         if (!rmdir(mountPoint)) {
849             break;
850         }
851
852         SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
853         usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
854     }
855
856     if (!retries) {
857         SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
858     }
859
860     if (Devmapper::destroy(idHash) && errno != ENXIO) {
861         SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
862     }
863
864     char loopDevice[255];
865     if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
866         Loop::destroyByDevice(loopDevice);
867     } else {
868         SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
869     }
870
871     AsecIdCollection::iterator it;
872     for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
873         ContainerData* cd = *it;
874         if (!strcmp(cd->id, id)) {
875             free(*it);
876             mActiveContainers->erase(it);
877             break;
878         }
879     }
880     if (it == mActiveContainers->end()) {
881         SLOGW("mActiveContainers is inconsistent!");
882     }
883     return 0;
884 }
885
886 int VolumeManager::destroyAsec(const char *id, bool force) {
887     char asecFileName[255];
888     char mountPoint[255];
889
890     if (!isLegalAsecId(id)) {
891         SLOGE("destroyAsec: Invalid asec id \"%s\"", id);
892         errno = EINVAL;
893         return -1;
894     }
895
896     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
897         SLOGE("Couldn't find ASEC %s", id);
898         return -1;
899     }
900
901     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
902     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
903         SLOGE("ASEC destroy failed for %s: couldn't construct mountpoint", id);
904         return -1;
905     }
906
907     if (isMountpointMounted(mountPoint)) {
908         if (mDebug) {
909             SLOGD("Unmounting container before destroy");
910         }
911         if (unmountAsec(id, force)) {
912             SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
913             return -1;
914         }
915     }
916
917     if (unlink(asecFileName)) {
918         SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
919         return -1;
920     }
921
922     if (mDebug) {
923         SLOGD("ASEC %s destroyed", id);
924     }
925     return 0;
926 }
927
928 /*
929  * Legal ASEC ids consist of alphanumeric characters, '-',
930  * '_', or '.'. ".." is not allowed. The first or last character
931  * of the ASEC id cannot be '.' (dot).
932  */
933 bool VolumeManager::isLegalAsecId(const char *id) const {
934     size_t i;
935     size_t len = strlen(id);
936
937     if (len == 0) {
938         return false;
939     }
940     if ((id[0] == '.') || (id[len - 1] == '.')) {
941         return false;
942     }
943
944     for (i = 0; i < len; i++) {
945         if (id[i] == '.') {
946             // i=0 is guaranteed never to have a dot. See above.
947             if (id[i-1] == '.') return false;
948             continue;
949         }
950         if (id[i] == '_' || id[i] == '-') continue;
951         if (id[i] >= 'a' && id[i] <= 'z') continue;
952         if (id[i] >= 'A' && id[i] <= 'Z') continue;
953         if (id[i] >= '0' && id[i] <= '9') continue;
954         return false;
955     }
956
957     return true;
958 }
959
960 bool VolumeManager::isAsecInDirectory(const char *dir, const char *asecName) const {
961     int dirfd = open(dir, O_DIRECTORY);
962     if (dirfd < 0) {
963         SLOGE("Couldn't open internal ASEC dir (%s)", strerror(errno));
964         return -1;
965     }
966
967     bool ret = false;
968
969     if (!faccessat(dirfd, asecName, F_OK, AT_SYMLINK_NOFOLLOW)) {
970         ret = true;
971     }
972
973     close(dirfd);
974
975     return ret;
976 }
977
978 int VolumeManager::findAsec(const char *id, char *asecPath, size_t asecPathLen,
979         const char **directory) const {
980     int dirfd, fd;
981     const int idLen = strlen(id);
982     char *asecName;
983
984     if (!isLegalAsecId(id)) {
985         SLOGE("findAsec: Invalid asec id \"%s\"", id);
986         errno = EINVAL;
987         return -1;
988     }
989
990     if (asprintf(&asecName, "%s.asec", id) < 0) {
991         SLOGE("Couldn't allocate string to write ASEC name");
992         return -1;
993     }
994
995     const char *dir;
996     if (isAsecInDirectory(Volume::SEC_ASECDIR_INT, asecName)) {
997         dir = Volume::SEC_ASECDIR_INT;
998     } else if (isAsecInDirectory(Volume::SEC_ASECDIR_EXT, asecName)) {
999         dir = Volume::SEC_ASECDIR_EXT;
1000     } else {
1001         free(asecName);
1002         return -1;
1003     }
1004
1005     if (directory != NULL) {
1006         *directory = dir;
1007     }
1008
1009     if (asecPath != NULL) {
1010         int written = snprintf(asecPath, asecPathLen, "%s/%s", dir, asecName);
1011         if ((written < 0) || (size_t(written) >= asecPathLen)) {
1012             SLOGE("findAsec failed for %s: couldn't construct ASEC path", id);
1013             free(asecName);
1014             return -1;
1015         }
1016     }
1017
1018     free(asecName);
1019     return 0;
1020 }
1021
1022 int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
1023     char asecFileName[255];
1024     char mountPoint[255];
1025
1026     if (!isLegalAsecId(id)) {
1027         SLOGE("mountAsec: Invalid asec id \"%s\"", id);
1028         errno = EINVAL;
1029         return -1;
1030     }
1031
1032     if (findAsec(id, asecFileName, sizeof(asecFileName))) {
1033         SLOGE("Couldn't find ASEC %s", id);
1034         return -1;
1035     }
1036
1037     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
1038     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1039         SLOGE("ASEC mount failed for %s: couldn't construct mountpoint", id);
1040         return -1;
1041     }
1042
1043     if (isMountpointMounted(mountPoint)) {
1044         SLOGE("ASEC %s already mounted", id);
1045         errno = EBUSY;
1046         return -1;
1047     }
1048
1049     char idHash[33];
1050     if (!asecHash(id, idHash, sizeof(idHash))) {
1051         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
1052         return -1;
1053     }
1054
1055     char loopDevice[255];
1056     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1057         if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
1058             SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
1059             return -1;
1060         }
1061         if (mDebug) {
1062             SLOGD("New loop device created at %s", loopDevice);
1063         }
1064     } else {
1065         if (mDebug) {
1066             SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
1067         }
1068     }
1069
1070     char dmDevice[255];
1071     bool cleanupDm = false;
1072     int fd;
1073     unsigned int nr_sec = 0;
1074     struct asec_superblock sb;
1075
1076     if (Loop::lookupInfo(loopDevice, &sb, &nr_sec)) {
1077         return -1;
1078     }
1079
1080     if (mDebug) {
1081         SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
1082     }
1083     if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
1084         SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
1085         Loop::destroyByDevice(loopDevice);
1086         errno = EMEDIUMTYPE;
1087         return -1;
1088     }
1089     nr_sec--; // We don't want the devmapping to extend onto our superblock
1090
1091     if (strcmp(key, "none")) {
1092         if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1093             if (Devmapper::create(idHash, loopDevice, key, nr_sec,
1094                                   dmDevice, sizeof(dmDevice))) {
1095                 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
1096                 Loop::destroyByDevice(loopDevice);
1097                 return -1;
1098             }
1099             if (mDebug) {
1100                 SLOGD("New devmapper instance created at %s", dmDevice);
1101             }
1102         } else {
1103             if (mDebug) {
1104                 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
1105             }
1106         }
1107         cleanupDm = true;
1108     } else {
1109         strcpy(dmDevice, loopDevice);
1110     }
1111
1112     if (mkdir(mountPoint, 0000)) {
1113         if (errno != EEXIST) {
1114             SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1115             if (cleanupDm) {
1116                 Devmapper::destroy(idHash);
1117             }
1118             Loop::destroyByDevice(loopDevice);
1119             return -1;
1120         }
1121     }
1122
1123     /*
1124      * The device mapper node needs to be created. Sometimes it takes a
1125      * while. Wait for up to 1 second. We could also inspect incoming uevents,
1126      * but that would take more effort.
1127      */
1128     int tries = 25;
1129     while (tries--) {
1130         if (!access(dmDevice, F_OK) || errno != ENOENT) {
1131             break;
1132         }
1133         usleep(40 * 1000);
1134     }
1135
1136     int result;
1137     if (sb.c_opts & ASEC_SB_C_OPTS_EXT4) {
1138         result = Ext4::doMount(dmDevice, mountPoint, true, false, true);
1139     } else {
1140         result = Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0, 0222, false);
1141     }
1142
1143     if (result) {
1144         SLOGE("ASEC mount failed (%s)", strerror(errno));
1145         if (cleanupDm) {
1146             Devmapper::destroy(idHash);
1147         }
1148         Loop::destroyByDevice(loopDevice);
1149         return -1;
1150     }
1151
1152     mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
1153     if (mDebug) {
1154         SLOGD("ASEC %s mounted", id);
1155     }
1156     return 0;
1157 }
1158
1159 Volume* VolumeManager::getVolumeForFile(const char *fileName) {
1160     VolumeCollection::iterator i;
1161
1162     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1163         const char* mountPoint = (*i)->getFuseMountpoint();
1164         if (!strncmp(fileName, mountPoint, strlen(mountPoint))) {
1165             return *i;
1166         }
1167     }
1168
1169     return NULL;
1170 }
1171
1172 /**
1173  * Mounts an image file <code>img</code>.
1174  */
1175 int VolumeManager::mountObb(const char *img, const char *key, int ownerGid) {
1176     char mountPoint[255];
1177
1178     char idHash[33];
1179     if (!asecHash(img, idHash, sizeof(idHash))) {
1180         SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
1181         return -1;
1182     }
1183
1184     int written = snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
1185     if ((written < 0) || (size_t(written) >= sizeof(mountPoint))) {
1186         SLOGE("OBB mount failed for %s: couldn't construct mountpoint", img);
1187         return -1;
1188     }
1189
1190     if (isMountpointMounted(mountPoint)) {
1191         SLOGE("Image %s already mounted", img);
1192         errno = EBUSY;
1193         return -1;
1194     }
1195
1196     char loopDevice[255];
1197     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
1198         if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
1199             SLOGE("Image loop device creation failed (%s)", strerror(errno));
1200             return -1;
1201         }
1202         if (mDebug) {
1203             SLOGD("New loop device created at %s", loopDevice);
1204         }
1205     } else {
1206         if (mDebug) {
1207             SLOGD("Found active loopback for %s at %s", img, loopDevice);
1208         }
1209     }
1210
1211     char dmDevice[255];
1212     bool cleanupDm = false;
1213     int fd;
1214     unsigned int nr_sec = 0;
1215
1216     if ((fd = open(loopDevice, O_RDWR)) < 0) {
1217         SLOGE("Failed to open loopdevice (%s)", strerror(errno));
1218         Loop::destroyByDevice(loopDevice);
1219         return -1;
1220     }
1221
1222     if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
1223         SLOGE("Failed to get loop size (%s)", strerror(errno));
1224         Loop::destroyByDevice(loopDevice);
1225         close(fd);
1226         return -1;
1227     }
1228
1229     close(fd);
1230
1231     if (strcmp(key, "none")) {
1232         if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
1233             if (Devmapper::create(idHash, loopDevice, key, nr_sec,
1234                                   dmDevice, sizeof(dmDevice))) {
1235                 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
1236                 Loop::destroyByDevice(loopDevice);
1237                 return -1;
1238             }
1239             if (mDebug) {
1240                 SLOGD("New devmapper instance created at %s", dmDevice);
1241             }
1242         } else {
1243             if (mDebug) {
1244                 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
1245             }
1246         }
1247         cleanupDm = true;
1248     } else {
1249         strcpy(dmDevice, loopDevice);
1250     }
1251
1252     if (mkdir(mountPoint, 0755)) {
1253         if (errno != EEXIST) {
1254             SLOGE("Mountpoint creation failed (%s)", strerror(errno));
1255             if (cleanupDm) {
1256                 Devmapper::destroy(idHash);
1257             }
1258             Loop::destroyByDevice(loopDevice);
1259             return -1;
1260         }
1261     }
1262
1263     if (Fat::doMount(dmDevice, mountPoint, true, false, true, 0, ownerGid,
1264                      0227, false)) {
1265         SLOGE("Image mount failed (%s)", strerror(errno));
1266         if (cleanupDm) {
1267             Devmapper::destroy(idHash);
1268         }
1269         Loop::destroyByDevice(loopDevice);
1270         return -1;
1271     }
1272
1273     mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
1274     if (mDebug) {
1275         SLOGD("Image %s mounted", img);
1276     }
1277     return 0;
1278 }
1279
1280 int VolumeManager::mountVolume(const char *label) {
1281     Volume *v = lookupVolume(label);
1282
1283     if (!v) {
1284         errno = ENOENT;
1285         return -1;
1286     }
1287
1288     return v->mountVol();
1289 }
1290
1291 int VolumeManager::listMountedObbs(SocketClient* cli) {
1292     char device[256];
1293     char mount_path[256];
1294     char rest[256];
1295     FILE *fp;
1296     char line[1024];
1297
1298     if (!(fp = fopen("/proc/mounts", "r"))) {
1299         SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1300         return -1;
1301     }
1302
1303     // Create a string to compare against that has a trailing slash
1304     int loopDirLen = strlen(Volume::LOOPDIR);
1305     char loopDir[loopDirLen + 2];
1306     strcpy(loopDir, Volume::LOOPDIR);
1307     loopDir[loopDirLen++] = '/';
1308     loopDir[loopDirLen] = '\0';
1309
1310     while(fgets(line, sizeof(line), fp)) {
1311         line[strlen(line)-1] = '\0';
1312
1313         /*
1314          * Should look like:
1315          * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
1316          */
1317         sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1318
1319         if (!strncmp(mount_path, loopDir, loopDirLen)) {
1320             int fd = open(device, O_RDONLY);
1321             if (fd >= 0) {
1322                 struct loop_info64 li;
1323                 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
1324                     cli->sendMsg(ResponseCode::AsecListResult,
1325                             (const char*) li.lo_file_name, false);
1326                 }
1327                 close(fd);
1328             }
1329         }
1330     }
1331
1332     fclose(fp);
1333     return 0;
1334 }
1335
1336 int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
1337     Volume *v = lookupVolume(label);
1338
1339     if (!v) {
1340         errno = ENOENT;
1341         return -1;
1342     }
1343
1344     if (strcmp(method, "ums")) {
1345         errno = ENOSYS;
1346         return -1;
1347     }
1348
1349     if (v->getState() != Volume::State_Shared) {
1350         *enabled = false;
1351     } else {
1352         *enabled = true;
1353     }
1354     return 0;
1355 }
1356
1357 int VolumeManager::shareVolume(const char *label, const char *method) {
1358     Volume *v = lookupVolume(label);
1359
1360     if (!v) {
1361         errno = ENOENT;
1362         return -1;
1363     }
1364
1365     /*
1366      * Eventually, we'll want to support additional share back-ends,
1367      * some of which may work while the media is mounted. For now,
1368      * we just support UMS
1369      */
1370     if (strcmp(method, "ums")) {
1371         errno = ENOSYS;
1372         return -1;
1373     }
1374
1375     if (v->getState() == Volume::State_NoMedia) {
1376         errno = ENODEV;
1377         return -1;
1378     }
1379
1380     if (v->getState() != Volume::State_Idle) {
1381         // You need to unmount manually befoe sharing
1382         errno = EBUSY;
1383         return -1;
1384     }
1385
1386     if (mVolManagerDisabled) {
1387         errno = EBUSY;
1388         return -1;
1389     }
1390
1391     dev_t d = v->getShareDevice();
1392     if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1393         // This volume does not support raw disk access
1394         errno = EINVAL;
1395         return -1;
1396     }
1397
1398     int fd;
1399     char nodepath[255];
1400     int written = snprintf(nodepath,
1401              sizeof(nodepath), "/dev/block/vold/%d:%d",
1402              major(d), minor(d));
1403
1404     if ((written < 0) || (size_t(written) >= sizeof(nodepath))) {
1405         SLOGE("shareVolume failed: couldn't construct nodepath");
1406         return -1;
1407     }
1408
1409     if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
1410         SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
1411         return -1;
1412     }
1413
1414     if (write(fd, nodepath, strlen(nodepath)) < 0) {
1415         SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
1416         close(fd);
1417         return -1;
1418     }
1419
1420     close(fd);
1421     v->handleVolumeShared();
1422     if (mUmsSharingCount++ == 0) {
1423         FILE* fp;
1424         mSavedDirtyRatio = -1; // in case we fail
1425         if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1426             char line[16];
1427             if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1428                 fprintf(fp, "%d\n", mUmsDirtyRatio);
1429             } else {
1430                 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1431             }
1432             fclose(fp);
1433         } else {
1434             SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1435         }
1436     }
1437     return 0;
1438 }
1439
1440 int VolumeManager::unshareVolume(const char *label, const char *method) {
1441     Volume *v = lookupVolume(label);
1442
1443     if (!v) {
1444         errno = ENOENT;
1445         return -1;
1446     }
1447
1448     if (strcmp(method, "ums")) {
1449         errno = ENOSYS;
1450         return -1;
1451     }
1452
1453     if (v->getState() != Volume::State_Shared) {
1454         errno = EINVAL;
1455         return -1;
1456     }
1457
1458     int fd;
1459     if ((fd = open(MASS_STORAGE_FILE_PATH, O_WRONLY)) < 0) {
1460         SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
1461         return -1;
1462     }
1463
1464     char ch = 0;
1465     if (write(fd, &ch, 1) < 0) {
1466         SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
1467         close(fd);
1468         return -1;
1469     }
1470
1471     close(fd);
1472     v->handleVolumeUnshared();
1473     if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1474         FILE* fp;
1475         if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1476             fprintf(fp, "%d\n", mSavedDirtyRatio);
1477             fclose(fp);
1478         } else {
1479             SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1480         }
1481         mSavedDirtyRatio = -1;
1482     }
1483     return 0;
1484 }
1485
1486 extern "C" int vold_disableVol(const char *label) {
1487     VolumeManager *vm = VolumeManager::Instance();
1488     vm->disableVolumeManager();
1489     vm->unshareVolume(label, "ums");
1490     return vm->unmountVolume(label, true, false);
1491 }
1492
1493 extern "C" int vold_getNumDirectVolumes(void) {
1494     VolumeManager *vm = VolumeManager::Instance();
1495     return vm->getNumDirectVolumes();
1496 }
1497
1498 int VolumeManager::getNumDirectVolumes(void) {
1499     VolumeCollection::iterator i;
1500     int n=0;
1501
1502     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1503         if ((*i)->getShareDevice() != (dev_t)0) {
1504             n++;
1505         }
1506     }
1507     return n;
1508 }
1509
1510 extern "C" int vold_getDirectVolumeList(struct volume_info *vol_list) {
1511     VolumeManager *vm = VolumeManager::Instance();
1512     return vm->getDirectVolumeList(vol_list);
1513 }
1514
1515 int VolumeManager::getDirectVolumeList(struct volume_info *vol_list) {
1516     VolumeCollection::iterator i;
1517     int n=0;
1518     dev_t d;
1519
1520     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1521         if ((d=(*i)->getShareDevice()) != (dev_t)0) {
1522             (*i)->getVolInfo(&vol_list[n]);
1523             snprintf(vol_list[n].blk_dev, sizeof(vol_list[n].blk_dev),
1524                      "/dev/block/vold/%d:%d", major(d), minor(d));
1525             n++;
1526         }
1527     }
1528
1529     return 0;
1530 }
1531
1532 int VolumeManager::unmountVolume(const char *label, bool force, bool revert) {
1533     Volume *v = lookupVolume(label);
1534
1535     if (!v) {
1536         errno = ENOENT;
1537         return -1;
1538     }
1539
1540     if (v->getState() == Volume::State_NoMedia) {
1541         errno = ENODEV;
1542         return -1;
1543     }
1544
1545     if (v->getState() != Volume::State_Mounted) {
1546         SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
1547              v->getState());
1548         errno = EBUSY;
1549         return UNMOUNT_NOT_MOUNTED_ERR;
1550     }
1551
1552     cleanupAsec(v, force);
1553
1554     return v->unmountVol(force, revert);
1555 }
1556
1557 extern "C" int vold_unmountAllAsecs(void) {
1558     int rc;
1559
1560     VolumeManager *vm = VolumeManager::Instance();
1561     rc = vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_EXT);
1562     if (vm->unmountAllAsecsInDir(Volume::SEC_ASECDIR_INT)) {
1563         rc = -1;
1564     }
1565     return rc;
1566 }
1567
1568 #define ID_BUF_LEN 256
1569 #define ASEC_SUFFIX ".asec"
1570 #define ASEC_SUFFIX_LEN (sizeof(ASEC_SUFFIX) - 1)
1571 int VolumeManager::unmountAllAsecsInDir(const char *directory) {
1572     DIR *d = opendir(directory);
1573     int rc = 0;
1574
1575     if (!d) {
1576         SLOGE("Could not open asec dir %s", directory);
1577         return -1;
1578     }
1579
1580     size_t dirent_len = offsetof(struct dirent, d_name) +
1581             fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
1582
1583     struct dirent *dent = (struct dirent *) malloc(dirent_len);
1584     if (dent == NULL) {
1585         SLOGE("Failed to allocate memory for asec dir");
1586         return -1;
1587     }
1588
1589     struct dirent *result;
1590     while (!readdir_r(d, dent, &result) && result != NULL) {
1591         if (dent->d_name[0] == '.')
1592             continue;
1593         if (dent->d_type != DT_REG)
1594             continue;
1595         size_t name_len = strlen(dent->d_name);
1596         if (name_len > 5 && name_len < (ID_BUF_LEN + ASEC_SUFFIX_LEN - 1) &&
1597                 !strcmp(&dent->d_name[name_len - 5], ASEC_SUFFIX)) {
1598             char id[ID_BUF_LEN];
1599             strlcpy(id, dent->d_name, name_len - 4);
1600             if (unmountAsec(id, true)) {
1601                 /* Register the error, but try to unmount more asecs */
1602                 rc = -1;
1603             }
1604         }
1605     }
1606     closedir(d);
1607
1608     free(dent);
1609
1610     return rc;
1611 }
1612
1613 /*
1614  * Looks up a volume by it's label or mount-point
1615  */
1616 Volume *VolumeManager::lookupVolume(const char *label) {
1617     VolumeCollection::iterator i;
1618
1619     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1620         if (label[0] == '/') {
1621             if (!strcmp(label, (*i)->getFuseMountpoint()))
1622                 return (*i);
1623         } else {
1624             if (!strcmp(label, (*i)->getLabel()))
1625                 return (*i);
1626         }
1627     }
1628     return NULL;
1629 }
1630
1631 bool VolumeManager::isMountpointMounted(const char *mp)
1632 {
1633     char device[256];
1634     char mount_path[256];
1635     char rest[256];
1636     FILE *fp;
1637     char line[1024];
1638
1639     if (!(fp = fopen("/proc/mounts", "r"))) {
1640         SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1641         return false;
1642     }
1643
1644     while(fgets(line, sizeof(line), fp)) {
1645         line[strlen(line)-1] = '\0';
1646         sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1647         if (!strcmp(mount_path, mp)) {
1648             fclose(fp);
1649             return true;
1650         }
1651     }
1652
1653     fclose(fp);
1654     return false;
1655 }
1656
1657 int VolumeManager::cleanupAsec(Volume *v, bool force) {
1658     int rc = 0;
1659
1660     char asecFileName[255];
1661
1662     AsecIdCollection removeAsec;
1663     AsecIdCollection removeObb;
1664
1665     for (AsecIdCollection::iterator it = mActiveContainers->begin(); it != mActiveContainers->end();
1666             ++it) {
1667         ContainerData* cd = *it;
1668
1669         if (cd->type == ASEC) {
1670             if (findAsec(cd->id, asecFileName, sizeof(asecFileName))) {
1671                 SLOGE("Couldn't find ASEC %s; cleaning up", cd->id);
1672                 removeAsec.push_back(cd);
1673             } else {
1674                 SLOGD("Found ASEC at path %s", asecFileName);
1675                 if (!strncmp(asecFileName, Volume::SEC_ASECDIR_EXT,
1676                         strlen(Volume::SEC_ASECDIR_EXT))) {
1677                     removeAsec.push_back(cd);
1678                 }
1679             }
1680         } else if (cd->type == OBB) {
1681             if (v == getVolumeForFile(cd->id)) {
1682                 removeObb.push_back(cd);
1683             }
1684         } else {
1685             SLOGE("Unknown container type %d!", cd->type);
1686         }
1687     }
1688
1689     for (AsecIdCollection::iterator it = removeAsec.begin(); it != removeAsec.end(); ++it) {
1690         ContainerData *cd = *it;
1691         SLOGI("Unmounting ASEC %s (dependent on %s)", cd->id, v->getLabel());
1692         if (unmountAsec(cd->id, force)) {
1693             SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1694             rc = -1;
1695         }
1696     }
1697
1698     for (AsecIdCollection::iterator it = removeObb.begin(); it != removeObb.end(); ++it) {
1699         ContainerData *cd = *it;
1700         SLOGI("Unmounting OBB %s (dependent on %s)", cd->id, v->getLabel());
1701         if (unmountObb(cd->id, force)) {
1702             SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1703             rc = -1;
1704         }
1705     }
1706
1707     return rc;
1708 }
1709
1710 int VolumeManager::mkdirs(char* path) {
1711     // Require that path lives under a volume we manage
1712     const char* emulated_source = getenv("EMULATED_STORAGE_SOURCE");
1713     const char* root = NULL;
1714     if (emulated_source && !strncmp(path, emulated_source, strlen(emulated_source))) {
1715         root = emulated_source;
1716     } else {
1717         Volume* vol = getVolumeForFile(path);
1718         if (vol) {
1719             root = vol->getMountpoint();
1720         }
1721     }
1722
1723     if (!root) {
1724         SLOGE("Failed to find volume for %s", path);
1725         return -EINVAL;
1726     }
1727
1728     /* fs_mkdirs() does symlink checking and relative path enforcement */
1729     return fs_mkdirs(path, 0700);
1730 }