• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <sys/stat.h>
23 #include <sys/types.h>
24 #include <sys/mount.h>
25 
26 #include <linux/kdev_t.h>
27 
28 #define LOG_TAG "Vold"
29 
30 #include <openssl/md5.h>
31 
32 #include <cutils/log.h>
33 
34 #include <sysutils/NetlinkEvent.h>
35 
36 #include "VolumeManager.h"
37 #include "DirectVolume.h"
38 #include "ResponseCode.h"
39 #include "Loop.h"
40 #include "Fat.h"
41 #include "Devmapper.h"
42 #include "Process.h"
43 #include "Asec.h"
44 
45 VolumeManager *VolumeManager::sInstance = NULL;
46 
Instance()47 VolumeManager *VolumeManager::Instance() {
48     if (!sInstance)
49         sInstance = new VolumeManager();
50     return sInstance;
51 }
52 
VolumeManager()53 VolumeManager::VolumeManager() {
54     mDebug = false;
55     mVolumes = new VolumeCollection();
56     mActiveContainers = new AsecIdCollection();
57     mBroadcaster = NULL;
58     mUsbMassStorageEnabled = false;
59     mUsbConnected = false;
60     mUmsSharingCount = 0;
61     mSavedDirtyRatio = -1;
62     // set dirty ratio to 0 when UMS is active
63     mUmsDirtyRatio = 0;
64 
65     readInitialState();
66 }
67 
readInitialState()68 void VolumeManager::readInitialState() {
69     FILE *fp;
70     char state[255];
71 
72     /*
73      * Read the initial mass storage enabled state
74      */
75     if ((fp = fopen("/sys/devices/virtual/usb_composite/usb_mass_storage/enable", "r"))) {
76         if (fgets(state, sizeof(state), fp)) {
77             mUsbMassStorageEnabled = !strncmp(state, "1", 1);
78         } else {
79             SLOGE("Failed to read usb_mass_storage enabled state (%s)", strerror(errno));
80         }
81         fclose(fp);
82     } else {
83         SLOGD("USB mass storage support is not enabled in the kernel");
84     }
85 
86     /*
87      * Read the initial USB connected state
88      */
89     if ((fp = fopen("/sys/devices/virtual/switch/usb_configuration/state", "r"))) {
90         if (fgets(state, sizeof(state), fp)) {
91             mUsbConnected = !strncmp(state, "1", 1);
92         } else {
93             SLOGE("Failed to read usb_configuration switch (%s)", strerror(errno));
94         }
95         fclose(fp);
96     } else {
97         SLOGD("usb_configuration switch is not enabled in the kernel");
98     }
99 }
100 
~VolumeManager()101 VolumeManager::~VolumeManager() {
102     delete mVolumes;
103     delete mActiveContainers;
104 }
105 
asecHash(const char * id,char * buffer,size_t len)106 char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
107     static const char* digits = "0123456789abcdef";
108 
109     unsigned char sig[MD5_DIGEST_LENGTH];
110 
111     if (buffer == NULL) {
112         SLOGE("Destination buffer is NULL");
113         errno = ESPIPE;
114         return NULL;
115     } else if (id == NULL) {
116         SLOGE("Source buffer is NULL");
117         errno = ESPIPE;
118         return NULL;
119     } else if (len < MD5_ASCII_LENGTH_PLUS_NULL) {
120         SLOGE("Target hash buffer size < %d bytes (%d)",
121                 MD5_ASCII_LENGTH_PLUS_NULL, len);
122         errno = ESPIPE;
123         return NULL;
124     }
125 
126     MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
127 
128     char *p = buffer;
129     for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
130         *p++ = digits[sig[i] >> 4];
131         *p++ = digits[sig[i] & 0x0F];
132     }
133     *p = '\0';
134 
135     return buffer;
136 }
137 
setDebug(bool enable)138 void VolumeManager::setDebug(bool enable) {
139     mDebug = enable;
140     VolumeCollection::iterator it;
141     for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
142         (*it)->setDebug(enable);
143     }
144 }
145 
start()146 int VolumeManager::start() {
147     return 0;
148 }
149 
stop()150 int VolumeManager::stop() {
151     return 0;
152 }
153 
addVolume(Volume * v)154 int VolumeManager::addVolume(Volume *v) {
155     mVolumes->push_back(v);
156     return 0;
157 }
158 
notifyUmsAvailable(bool available)159 void VolumeManager::notifyUmsAvailable(bool available) {
160     char msg[255];
161 
162     snprintf(msg, sizeof(msg), "Share method ums now %s",
163              (available ? "available" : "unavailable"));
164     SLOGD(msg);
165     getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
166                                     msg, false);
167 }
168 
handleSwitchEvent(NetlinkEvent * evt)169 void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
170     const char *devpath = evt->findParam("DEVPATH");
171     const char *name = evt->findParam("SWITCH_NAME");
172     const char *state = evt->findParam("SWITCH_STATE");
173 
174     if (!name || !state) {
175         SLOGW("Switch %s event missing name/state info", devpath);
176         return;
177     }
178 
179     bool oldAvailable = massStorageAvailable();
180     if (!strcmp(name, "usb_configuration")) {
181         mUsbConnected = !strcmp(state, "1");
182         SLOGD("USB %s", mUsbConnected ? "connected" : "disconnected");
183         bool newAvailable = massStorageAvailable();
184         if (newAvailable != oldAvailable) {
185             notifyUmsAvailable(newAvailable);
186         }
187     } else {
188         SLOGW("Ignoring unknown switch '%s'", name);
189     }
190 }
handleUsbCompositeEvent(NetlinkEvent * evt)191 void VolumeManager::handleUsbCompositeEvent(NetlinkEvent *evt) {
192     const char *function = evt->findParam("FUNCTION");
193     const char *enabled = evt->findParam("ENABLED");
194 
195     if (!function || !enabled) {
196         SLOGW("usb_composite event missing function/enabled info");
197         return;
198     }
199 
200     if (!strcmp(function, "usb_mass_storage")) {
201         bool oldAvailable = massStorageAvailable();
202         mUsbMassStorageEnabled = !strcmp(enabled, "1");
203         SLOGD("usb_mass_storage function %s", mUsbMassStorageEnabled ? "enabled" : "disabled");
204         bool newAvailable = massStorageAvailable();
205         if (newAvailable != oldAvailable) {
206             notifyUmsAvailable(newAvailable);
207         }
208     }
209 }
210 
handleBlockEvent(NetlinkEvent * evt)211 void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
212     const char *devpath = evt->findParam("DEVPATH");
213 
214     /* Lookup a volume to handle this device */
215     VolumeCollection::iterator it;
216     bool hit = false;
217     for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
218         if (!(*it)->handleBlockEvent(evt)) {
219 #ifdef NETLINK_DEBUG
220             SLOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
221 #endif
222             hit = true;
223             break;
224         }
225     }
226 
227     if (!hit) {
228 #ifdef NETLINK_DEBUG
229         SLOGW("No volumes handled block event for '%s'", devpath);
230 #endif
231     }
232 }
233 
listVolumes(SocketClient * cli)234 int VolumeManager::listVolumes(SocketClient *cli) {
235     VolumeCollection::iterator i;
236 
237     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
238         char *buffer;
239         asprintf(&buffer, "%s %s %d",
240                  (*i)->getLabel(), (*i)->getMountpoint(),
241                  (*i)->getState());
242         cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
243         free(buffer);
244     }
245     cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
246     return 0;
247 }
248 
formatVolume(const char * label)249 int VolumeManager::formatVolume(const char *label) {
250     Volume *v = lookupVolume(label);
251 
252     if (!v) {
253         errno = ENOENT;
254         return -1;
255     }
256 
257     return v->formatVol();
258 }
259 
getObbMountPath(const char * sourceFile,char * mountPath,int mountPathLen)260 int VolumeManager::getObbMountPath(const char *sourceFile, char *mountPath, int mountPathLen) {
261     char idHash[33];
262     if (!asecHash(sourceFile, idHash, sizeof(idHash))) {
263         SLOGE("Hash of '%s' failed (%s)", sourceFile, strerror(errno));
264         return -1;
265     }
266 
267     memset(mountPath, 0, mountPathLen);
268     snprintf(mountPath, mountPathLen, "%s/%s", Volume::LOOPDIR, idHash);
269 
270     if (access(mountPath, F_OK)) {
271         errno = ENOENT;
272         return -1;
273     }
274 
275     return 0;
276 }
277 
getAsecMountPath(const char * id,char * buffer,int maxlen)278 int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
279     char asecFileName[255];
280     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
281 
282     memset(buffer, 0, maxlen);
283     if (access(asecFileName, F_OK)) {
284         errno = ENOENT;
285         return -1;
286     }
287 
288     snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
289     return 0;
290 }
291 
createAsec(const char * id,unsigned int numSectors,const char * fstype,const char * key,int ownerUid)292 int VolumeManager::createAsec(const char *id, unsigned int numSectors,
293                               const char *fstype, const char *key, int ownerUid) {
294     struct asec_superblock sb;
295     memset(&sb, 0, sizeof(sb));
296 
297     sb.magic = ASEC_SB_MAGIC;
298     sb.ver = ASEC_SB_VER;
299 
300     if (numSectors < ((1024*1024)/512)) {
301         SLOGE("Invalid container size specified (%d sectors)", numSectors);
302         errno = EINVAL;
303         return -1;
304     }
305 
306     if (lookupVolume(id)) {
307         SLOGE("ASEC id '%s' currently exists", id);
308         errno = EADDRINUSE;
309         return -1;
310     }
311 
312     char asecFileName[255];
313     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
314 
315     if (!access(asecFileName, F_OK)) {
316         SLOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
317              asecFileName, strerror(errno));
318         errno = EADDRINUSE;
319         return -1;
320     }
321 
322     /*
323      * Add some headroom
324      */
325     unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
326     unsigned numImgSectors = numSectors + fatSize + 2;
327 
328     if (numImgSectors % 63) {
329         numImgSectors += (63 - (numImgSectors % 63));
330     }
331 
332     // Add +1 for our superblock which is at the end
333     if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
334         SLOGE("ASEC image file creation failed (%s)", strerror(errno));
335         return -1;
336     }
337 
338     char idHash[33];
339     if (!asecHash(id, idHash, sizeof(idHash))) {
340         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
341         unlink(asecFileName);
342         return -1;
343     }
344 
345     char loopDevice[255];
346     if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
347         SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
348         unlink(asecFileName);
349         return -1;
350     }
351 
352     char dmDevice[255];
353     bool cleanupDm = false;
354 
355     if (strcmp(key, "none")) {
356         // XXX: This is all we support for now
357         sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
358         if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
359                              sizeof(dmDevice))) {
360             SLOGE("ASEC device mapping failed (%s)", strerror(errno));
361             Loop::destroyByDevice(loopDevice);
362             unlink(asecFileName);
363             return -1;
364         }
365         cleanupDm = true;
366     } else {
367         sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
368         strcpy(dmDevice, loopDevice);
369     }
370 
371     /*
372      * Drop down the superblock at the end of the file
373      */
374 
375     int sbfd = open(loopDevice, O_RDWR);
376     if (sbfd < 0) {
377         SLOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
378         if (cleanupDm) {
379             Devmapper::destroy(idHash);
380         }
381         Loop::destroyByDevice(loopDevice);
382         unlink(asecFileName);
383         return -1;
384     }
385 
386     if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
387         close(sbfd);
388         SLOGE("Failed to lseek for superblock (%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 (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
398         close(sbfd);
399         SLOGE("Failed to write superblock (%s)", strerror(errno));
400         if (cleanupDm) {
401             Devmapper::destroy(idHash);
402         }
403         Loop::destroyByDevice(loopDevice);
404         unlink(asecFileName);
405         return -1;
406     }
407     close(sbfd);
408 
409     if (strcmp(fstype, "none")) {
410         if (strcmp(fstype, "fat")) {
411             SLOGW("Unknown fstype '%s' specified for container", fstype);
412         }
413 
414         if (Fat::format(dmDevice, numImgSectors)) {
415             SLOGE("ASEC FAT format failed (%s)", strerror(errno));
416             if (cleanupDm) {
417                 Devmapper::destroy(idHash);
418             }
419             Loop::destroyByDevice(loopDevice);
420             unlink(asecFileName);
421             return -1;
422         }
423         char mountPoint[255];
424 
425         snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
426         if (mkdir(mountPoint, 0777)) {
427             if (errno != EEXIST) {
428                 SLOGE("Mountpoint creation failed (%s)", strerror(errno));
429                 if (cleanupDm) {
430                     Devmapper::destroy(idHash);
431                 }
432                 Loop::destroyByDevice(loopDevice);
433                 unlink(asecFileName);
434                 return -1;
435             }
436         }
437 
438         if (Fat::doMount(dmDevice, mountPoint, false, false, false, ownerUid,
439                          0, 0000, false)) {
440             SLOGE("ASEC FAT mount failed (%s)", strerror(errno));
441             if (cleanupDm) {
442                 Devmapper::destroy(idHash);
443             }
444             Loop::destroyByDevice(loopDevice);
445             unlink(asecFileName);
446             return -1;
447         }
448     } else {
449         SLOGI("Created raw secure container %s (no filesystem)", id);
450     }
451 
452     mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
453     return 0;
454 }
455 
finalizeAsec(const char * id)456 int VolumeManager::finalizeAsec(const char *id) {
457     char asecFileName[255];
458     char loopDevice[255];
459     char mountPoint[255];
460 
461     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
462 
463     char idHash[33];
464     if (!asecHash(id, idHash, sizeof(idHash))) {
465         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
466         return -1;
467     }
468 
469     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
470         SLOGE("Unable to finalize %s (%s)", id, strerror(errno));
471         return -1;
472     }
473 
474     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
475     // XXX:
476     if (Fat::doMount(loopDevice, mountPoint, true, true, true, 0, 0, 0227, false)) {
477         SLOGE("ASEC finalize mount failed (%s)", strerror(errno));
478         return -1;
479     }
480 
481     if (mDebug) {
482         SLOGD("ASEC %s finalized", id);
483     }
484     return 0;
485 }
486 
renameAsec(const char * id1,const char * id2)487 int VolumeManager::renameAsec(const char *id1, const char *id2) {
488     char *asecFilename1;
489     char *asecFilename2;
490     char mountPoint[255];
491 
492     asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
493     asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
494 
495     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
496     if (isMountpointMounted(mountPoint)) {
497         SLOGW("Rename attempt when src mounted");
498         errno = EBUSY;
499         goto out_err;
500     }
501 
502     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
503     if (isMountpointMounted(mountPoint)) {
504         SLOGW("Rename attempt when dst mounted");
505         errno = EBUSY;
506         goto out_err;
507     }
508 
509     if (!access(asecFilename2, F_OK)) {
510         SLOGE("Rename attempt when dst exists");
511         errno = EADDRINUSE;
512         goto out_err;
513     }
514 
515     if (rename(asecFilename1, asecFilename2)) {
516         SLOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
517         goto out_err;
518     }
519 
520     free(asecFilename1);
521     free(asecFilename2);
522     return 0;
523 
524 out_err:
525     free(asecFilename1);
526     free(asecFilename2);
527     return -1;
528 }
529 
530 #define UNMOUNT_RETRIES 5
531 #define UNMOUNT_SLEEP_BETWEEN_RETRY_MS (1000 * 1000)
unmountAsec(const char * id,bool force)532 int VolumeManager::unmountAsec(const char *id, bool force) {
533     char asecFileName[255];
534     char mountPoint[255];
535 
536     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
537     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
538 
539     char idHash[33];
540     if (!asecHash(id, idHash, sizeof(idHash))) {
541         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
542         return -1;
543     }
544 
545     return unmountLoopImage(id, idHash, asecFileName, mountPoint, force);
546 }
547 
unmountObb(const char * fileName,bool force)548 int VolumeManager::unmountObb(const char *fileName, bool force) {
549     char mountPoint[255];
550 
551     char idHash[33];
552     if (!asecHash(fileName, idHash, sizeof(idHash))) {
553         SLOGE("Hash of '%s' failed (%s)", fileName, strerror(errno));
554         return -1;
555     }
556 
557     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
558 
559     return unmountLoopImage(fileName, idHash, fileName, mountPoint, force);
560 }
561 
unmountLoopImage(const char * id,const char * idHash,const char * fileName,const char * mountPoint,bool force)562 int VolumeManager::unmountLoopImage(const char *id, const char *idHash,
563         const char *fileName, const char *mountPoint, bool force) {
564     if (!isMountpointMounted(mountPoint)) {
565         SLOGE("Unmount request for %s when not mounted", id);
566         errno = ENOENT;
567         return -1;
568     }
569 
570     int i, rc;
571     for (i = 1; i <= UNMOUNT_RETRIES; i++) {
572         rc = umount(mountPoint);
573         if (!rc) {
574             break;
575         }
576         if (rc && (errno == EINVAL || errno == ENOENT)) {
577             SLOGI("Container %s unmounted OK", id);
578             rc = 0;
579             break;
580         }
581         SLOGW("%s unmount attempt %d failed (%s)",
582               id, i, strerror(errno));
583 
584         int action = 0; // default is to just complain
585 
586         if (force) {
587             if (i > (UNMOUNT_RETRIES - 2))
588                 action = 2; // SIGKILL
589             else if (i > (UNMOUNT_RETRIES - 3))
590                 action = 1; // SIGHUP
591         }
592 
593         Process::killProcessesWithOpenFiles(mountPoint, action);
594         usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
595     }
596 
597     if (rc) {
598         errno = EBUSY;
599         SLOGE("Failed to unmount container %s (%s)", id, strerror(errno));
600         return -1;
601     }
602 
603     int retries = 10;
604 
605     while(retries--) {
606         if (!rmdir(mountPoint)) {
607             break;
608         }
609 
610         SLOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
611         usleep(UNMOUNT_SLEEP_BETWEEN_RETRY_MS);
612     }
613 
614     if (!retries) {
615         SLOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
616     }
617 
618     if (Devmapper::destroy(idHash) && errno != ENXIO) {
619         SLOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
620     }
621 
622     char loopDevice[255];
623     if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
624         Loop::destroyByDevice(loopDevice);
625     } else {
626         SLOGW("Failed to find loop device for {%s} (%s)", fileName, strerror(errno));
627     }
628 
629     AsecIdCollection::iterator it;
630     for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
631         ContainerData* cd = *it;
632         if (!strcmp(cd->id, id)) {
633             free(*it);
634             mActiveContainers->erase(it);
635             break;
636         }
637     }
638     if (it == mActiveContainers->end()) {
639         SLOGW("mActiveContainers is inconsistent!");
640     }
641     return 0;
642 }
643 
destroyAsec(const char * id,bool force)644 int VolumeManager::destroyAsec(const char *id, bool force) {
645     char asecFileName[255];
646     char mountPoint[255];
647 
648     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
649     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
650 
651     if (isMountpointMounted(mountPoint)) {
652         if (mDebug) {
653             SLOGD("Unmounting container before destroy");
654         }
655         if (unmountAsec(id, force)) {
656             SLOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
657             return -1;
658         }
659     }
660 
661     if (unlink(asecFileName)) {
662         SLOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
663         return -1;
664     }
665 
666     if (mDebug) {
667         SLOGD("ASEC %s destroyed", id);
668     }
669     return 0;
670 }
671 
mountAsec(const char * id,const char * key,int ownerUid)672 int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
673     char asecFileName[255];
674     char mountPoint[255];
675 
676     snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
677     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
678 
679     if (isMountpointMounted(mountPoint)) {
680         SLOGE("ASEC %s already mounted", id);
681         errno = EBUSY;
682         return -1;
683     }
684 
685     char idHash[33];
686     if (!asecHash(id, idHash, sizeof(idHash))) {
687         SLOGE("Hash of '%s' failed (%s)", id, strerror(errno));
688         return -1;
689     }
690 
691     char loopDevice[255];
692     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
693         if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
694             SLOGE("ASEC loop device creation failed (%s)", strerror(errno));
695             return -1;
696         }
697         if (mDebug) {
698             SLOGD("New loop device created at %s", loopDevice);
699         }
700     } else {
701         if (mDebug) {
702             SLOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
703         }
704     }
705 
706     char dmDevice[255];
707     bool cleanupDm = false;
708     int fd;
709     unsigned int nr_sec = 0;
710 
711     if ((fd = open(loopDevice, O_RDWR)) < 0) {
712         SLOGE("Failed to open loopdevice (%s)", strerror(errno));
713         Loop::destroyByDevice(loopDevice);
714         return -1;
715     }
716 
717     if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
718         SLOGE("Failed to get loop size (%s)", strerror(errno));
719         Loop::destroyByDevice(loopDevice);
720         close(fd);
721         return -1;
722     }
723 
724     /*
725      * Validate superblock
726      */
727     struct asec_superblock sb;
728     memset(&sb, 0, sizeof(sb));
729     if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
730         SLOGE("lseek failed (%s)", strerror(errno));
731         close(fd);
732         Loop::destroyByDevice(loopDevice);
733         return -1;
734     }
735     if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
736         SLOGE("superblock read failed (%s)", strerror(errno));
737         close(fd);
738         Loop::destroyByDevice(loopDevice);
739         return -1;
740     }
741 
742     close(fd);
743 
744     if (mDebug) {
745         SLOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
746     }
747     if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
748         SLOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
749         Loop::destroyByDevice(loopDevice);
750         errno = EMEDIUMTYPE;
751         return -1;
752     }
753     nr_sec--; // We don't want the devmapping to extend onto our superblock
754 
755     if (strcmp(key, "none")) {
756         if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
757             if (Devmapper::create(idHash, loopDevice, key, nr_sec,
758                                   dmDevice, sizeof(dmDevice))) {
759                 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
760                 Loop::destroyByDevice(loopDevice);
761                 return -1;
762             }
763             if (mDebug) {
764                 SLOGD("New devmapper instance created at %s", dmDevice);
765             }
766         } else {
767             if (mDebug) {
768                 SLOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
769             }
770         }
771         cleanupDm = true;
772     } else {
773         strcpy(dmDevice, loopDevice);
774     }
775 
776     if (mkdir(mountPoint, 0777)) {
777         if (errno != EEXIST) {
778             SLOGE("Mountpoint creation failed (%s)", strerror(errno));
779             if (cleanupDm) {
780                 Devmapper::destroy(idHash);
781             }
782             Loop::destroyByDevice(loopDevice);
783             return -1;
784         }
785     }
786 
787     if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
788                      0222, false)) {
789 //                     0227, false)) {
790         SLOGE("ASEC mount failed (%s)", strerror(errno));
791         if (cleanupDm) {
792             Devmapper::destroy(idHash);
793         }
794         Loop::destroyByDevice(loopDevice);
795         return -1;
796     }
797 
798     mActiveContainers->push_back(new ContainerData(strdup(id), ASEC));
799     if (mDebug) {
800         SLOGD("ASEC %s mounted", id);
801     }
802     return 0;
803 }
804 
805 /**
806  * Mounts an image file <code>img</code>.
807  */
mountObb(const char * img,const char * key,int ownerUid)808 int VolumeManager::mountObb(const char *img, const char *key, int ownerUid) {
809     char mountPoint[255];
810 
811     char idHash[33];
812     if (!asecHash(img, idHash, sizeof(idHash))) {
813         SLOGE("Hash of '%s' failed (%s)", img, strerror(errno));
814         return -1;
815     }
816 
817     snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::LOOPDIR, idHash);
818 
819     if (isMountpointMounted(mountPoint)) {
820         SLOGE("Image %s already mounted", img);
821         errno = EBUSY;
822         return -1;
823     }
824 
825     char loopDevice[255];
826     if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
827         if (Loop::create(idHash, img, loopDevice, sizeof(loopDevice))) {
828             SLOGE("Image loop device creation failed (%s)", strerror(errno));
829             return -1;
830         }
831         if (mDebug) {
832             SLOGD("New loop device created at %s", loopDevice);
833         }
834     } else {
835         if (mDebug) {
836             SLOGD("Found active loopback for %s at %s", img, loopDevice);
837         }
838     }
839 
840     char dmDevice[255];
841     bool cleanupDm = false;
842     int fd;
843     unsigned int nr_sec = 0;
844 
845     if ((fd = open(loopDevice, O_RDWR)) < 0) {
846         SLOGE("Failed to open loopdevice (%s)", strerror(errno));
847         Loop::destroyByDevice(loopDevice);
848         return -1;
849     }
850 
851     if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
852         SLOGE("Failed to get loop size (%s)", strerror(errno));
853         Loop::destroyByDevice(loopDevice);
854         close(fd);
855         return -1;
856     }
857 
858     close(fd);
859 
860     if (strcmp(key, "none")) {
861         if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
862             if (Devmapper::create(idHash, loopDevice, key, nr_sec,
863                                   dmDevice, sizeof(dmDevice))) {
864                 SLOGE("ASEC device mapping failed (%s)", strerror(errno));
865                 Loop::destroyByDevice(loopDevice);
866                 return -1;
867             }
868             if (mDebug) {
869                 SLOGD("New devmapper instance created at %s", dmDevice);
870             }
871         } else {
872             if (mDebug) {
873                 SLOGD("Found active devmapper for %s at %s", img, dmDevice);
874             }
875         }
876         cleanupDm = true;
877     } else {
878         strcpy(dmDevice, loopDevice);
879     }
880 
881     if (mkdir(mountPoint, 0755)) {
882         if (errno != EEXIST) {
883             SLOGE("Mountpoint creation failed (%s)", strerror(errno));
884             if (cleanupDm) {
885                 Devmapper::destroy(idHash);
886             }
887             Loop::destroyByDevice(loopDevice);
888             return -1;
889         }
890     }
891 
892     if (Fat::doMount(dmDevice, mountPoint, true, false, true, ownerUid, 0,
893                      0227, false)) {
894         SLOGE("Image mount failed (%s)", strerror(errno));
895         if (cleanupDm) {
896             Devmapper::destroy(idHash);
897         }
898         Loop::destroyByDevice(loopDevice);
899         return -1;
900     }
901 
902     mActiveContainers->push_back(new ContainerData(strdup(img), OBB));
903     if (mDebug) {
904         SLOGD("Image %s mounted", img);
905     }
906     return 0;
907 }
908 
mountVolume(const char * label)909 int VolumeManager::mountVolume(const char *label) {
910     Volume *v = lookupVolume(label);
911 
912     if (!v) {
913         errno = ENOENT;
914         return -1;
915     }
916 
917     return v->mountVol();
918 }
919 
listMountedObbs(SocketClient * cli)920 int VolumeManager::listMountedObbs(SocketClient* cli) {
921     char device[256];
922     char mount_path[256];
923     char rest[256];
924     FILE *fp;
925     char line[1024];
926 
927     if (!(fp = fopen("/proc/mounts", "r"))) {
928         SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
929         return -1;
930     }
931 
932     // Create a string to compare against that has a trailing slash
933     int loopDirLen = sizeof(Volume::LOOPDIR);
934     char loopDir[loopDirLen + 2];
935     strcpy(loopDir, Volume::LOOPDIR);
936     loopDir[loopDirLen++] = '/';
937     loopDir[loopDirLen] = '\0';
938 
939     while(fgets(line, sizeof(line), fp)) {
940         line[strlen(line)-1] = '\0';
941 
942         /*
943          * Should look like:
944          * /dev/block/loop0 /mnt/obb/fc99df1323fd36424f864dcb76b76d65 ...
945          */
946         sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
947 
948         if (!strncmp(mount_path, loopDir, loopDirLen)) {
949             int fd = open(device, O_RDONLY);
950             if (fd >= 0) {
951                 struct loop_info64 li;
952                 if (ioctl(fd, LOOP_GET_STATUS64, &li) >= 0) {
953                     cli->sendMsg(ResponseCode::AsecListResult,
954                             (const char*) li.lo_file_name, false);
955                 }
956                 close(fd);
957             }
958         }
959     }
960 
961     fclose(fp);
962     return 0;
963 }
964 
shareAvailable(const char * method,bool * avail)965 int VolumeManager::shareAvailable(const char *method, bool *avail) {
966 
967     if (strcmp(method, "ums")) {
968         errno = ENOSYS;
969         return -1;
970     }
971 
972     *avail = massStorageAvailable();
973     return 0;
974 }
975 
shareEnabled(const char * label,const char * method,bool * enabled)976 int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
977     Volume *v = lookupVolume(label);
978 
979     if (!v) {
980         errno = ENOENT;
981         return -1;
982     }
983 
984     if (strcmp(method, "ums")) {
985         errno = ENOSYS;
986         return -1;
987     }
988 
989     if (v->getState() != Volume::State_Shared) {
990         *enabled = false;
991     } else {
992         *enabled = true;
993     }
994     return 0;
995 }
996 
simulate(const char * cmd,const char * arg)997 int VolumeManager::simulate(const char *cmd, const char *arg) {
998 
999     if (!strcmp(cmd, "ums")) {
1000         if (!strcmp(arg, "connect")) {
1001             notifyUmsAvailable(true);
1002         } else if (!strcmp(arg, "disconnect")) {
1003             notifyUmsAvailable(false);
1004         } else {
1005             errno = EINVAL;
1006             return -1;
1007         }
1008     } else {
1009         errno = EINVAL;
1010         return -1;
1011     }
1012     return 0;
1013 }
1014 
shareVolume(const char * label,const char * method)1015 int VolumeManager::shareVolume(const char *label, const char *method) {
1016     Volume *v = lookupVolume(label);
1017 
1018     if (!v) {
1019         errno = ENOENT;
1020         return -1;
1021     }
1022 
1023     /*
1024      * Eventually, we'll want to support additional share back-ends,
1025      * some of which may work while the media is mounted. For now,
1026      * we just support UMS
1027      */
1028     if (strcmp(method, "ums")) {
1029         errno = ENOSYS;
1030         return -1;
1031     }
1032 
1033     if (v->getState() == Volume::State_NoMedia) {
1034         errno = ENODEV;
1035         return -1;
1036     }
1037 
1038     if (v->getState() != Volume::State_Idle) {
1039         // You need to unmount manually befoe sharing
1040         errno = EBUSY;
1041         return -1;
1042     }
1043 
1044     dev_t d = v->getShareDevice();
1045     if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
1046         // This volume does not support raw disk access
1047         errno = EINVAL;
1048         return -1;
1049     }
1050 
1051     int fd;
1052     char nodepath[255];
1053     snprintf(nodepath,
1054              sizeof(nodepath), "/dev/block/vold/%d:%d",
1055              MAJOR(d), MINOR(d));
1056 
1057     if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
1058                    O_WRONLY)) < 0) {
1059         SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
1060         return -1;
1061     }
1062 
1063     if (write(fd, nodepath, strlen(nodepath)) < 0) {
1064         SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
1065         close(fd);
1066         return -1;
1067     }
1068 
1069     close(fd);
1070     v->handleVolumeShared();
1071     if (mUmsSharingCount++ == 0) {
1072         FILE* fp;
1073         mSavedDirtyRatio = -1; // in case we fail
1074         if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1075             char line[16];
1076             if (fgets(line, sizeof(line), fp) && sscanf(line, "%d", &mSavedDirtyRatio)) {
1077                 fprintf(fp, "%d\n", mUmsDirtyRatio);
1078             } else {
1079                 SLOGE("Failed to read dirty_ratio (%s)", strerror(errno));
1080             }
1081             fclose(fp);
1082         } else {
1083             SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1084         }
1085     }
1086     return 0;
1087 }
1088 
unshareVolume(const char * label,const char * method)1089 int VolumeManager::unshareVolume(const char *label, const char *method) {
1090     Volume *v = lookupVolume(label);
1091 
1092     if (!v) {
1093         errno = ENOENT;
1094         return -1;
1095     }
1096 
1097     if (strcmp(method, "ums")) {
1098         errno = ENOSYS;
1099         return -1;
1100     }
1101 
1102     if (v->getState() != Volume::State_Shared) {
1103         errno = EINVAL;
1104         return -1;
1105     }
1106 
1107     int fd;
1108     if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
1109         SLOGE("Unable to open ums lunfile (%s)", strerror(errno));
1110         return -1;
1111     }
1112 
1113     char ch = 0;
1114     if (write(fd, &ch, 1) < 0) {
1115         SLOGE("Unable to write to ums lunfile (%s)", strerror(errno));
1116         close(fd);
1117         return -1;
1118     }
1119 
1120     close(fd);
1121     v->handleVolumeUnshared();
1122     if (--mUmsSharingCount == 0 && mSavedDirtyRatio != -1) {
1123         FILE* fp;
1124         if ((fp = fopen("/proc/sys/vm/dirty_ratio", "r+"))) {
1125             fprintf(fp, "%d\n", mSavedDirtyRatio);
1126             fclose(fp);
1127         } else {
1128             SLOGE("Failed to open /proc/sys/vm/dirty_ratio (%s)", strerror(errno));
1129         }
1130         mSavedDirtyRatio = -1;
1131     }
1132     return 0;
1133 }
1134 
unmountVolume(const char * label,bool force)1135 int VolumeManager::unmountVolume(const char *label, bool force) {
1136     Volume *v = lookupVolume(label);
1137 
1138     if (!v) {
1139         errno = ENOENT;
1140         return -1;
1141     }
1142 
1143     if (v->getState() == Volume::State_NoMedia) {
1144         errno = ENODEV;
1145         return -1;
1146     }
1147 
1148     if (v->getState() != Volume::State_Mounted) {
1149         SLOGW("Attempt to unmount volume which isn't mounted (%d)\n",
1150              v->getState());
1151         errno = EBUSY;
1152         return -1;
1153     }
1154 
1155     cleanupAsec(v, force);
1156 
1157     return v->unmountVol(force);
1158 }
1159 
1160 /*
1161  * Looks up a volume by it's label or mount-point
1162  */
lookupVolume(const char * label)1163 Volume *VolumeManager::lookupVolume(const char *label) {
1164     VolumeCollection::iterator i;
1165 
1166     for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
1167         if (label[0] == '/') {
1168             if (!strcmp(label, (*i)->getMountpoint()))
1169                 return (*i);
1170         } else {
1171             if (!strcmp(label, (*i)->getLabel()))
1172                 return (*i);
1173         }
1174     }
1175     return NULL;
1176 }
1177 
isMountpointMounted(const char * mp)1178 bool VolumeManager::isMountpointMounted(const char *mp)
1179 {
1180     char device[256];
1181     char mount_path[256];
1182     char rest[256];
1183     FILE *fp;
1184     char line[1024];
1185 
1186     if (!(fp = fopen("/proc/mounts", "r"))) {
1187         SLOGE("Error opening /proc/mounts (%s)", strerror(errno));
1188         return false;
1189     }
1190 
1191     while(fgets(line, sizeof(line), fp)) {
1192         line[strlen(line)-1] = '\0';
1193         sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
1194         if (!strcmp(mount_path, mp)) {
1195             fclose(fp);
1196             return true;
1197         }
1198     }
1199 
1200     fclose(fp);
1201     return false;
1202 }
1203 
cleanupAsec(Volume * v,bool force)1204 int VolumeManager::cleanupAsec(Volume *v, bool force) {
1205     while(mActiveContainers->size()) {
1206         AsecIdCollection::iterator it = mActiveContainers->begin();
1207         ContainerData* cd = *it;
1208         SLOGI("Unmounting ASEC %s (dependant on %s)", cd->id, v->getMountpoint());
1209         if (cd->type == ASEC) {
1210             if (unmountAsec(cd->id, force)) {
1211                 SLOGE("Failed to unmount ASEC %s (%s)", cd->id, strerror(errno));
1212                 return -1;
1213             }
1214         } else if (cd->type == OBB) {
1215             if (unmountObb(cd->id, force)) {
1216                 SLOGE("Failed to unmount OBB %s (%s)", cd->id, strerror(errno));
1217                 return -1;
1218             }
1219         } else {
1220             SLOGE("Unknown container type %d!", cd->type);
1221             return -1;
1222         }
1223     }
1224     return 0;
1225 }
1226 
1227