blob: c72482e14ee0b375c230b00289739fe4e8cf70d4 [file] [log] [blame]
San Mehatf1b736b2009-10-10 17:22:08 -07001/*
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>
San Mehatfd7f5872009-10-12 11:32:47 -070018#include <stdlib.h>
19#include <string.h>
San Mehatf1b736b2009-10-10 17:22:08 -070020#include <errno.h>
San Mehata2677e42009-12-13 10:40:18 -080021#include <fcntl.h>
San Mehata19b2502010-01-06 10:33:53 -080022#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/mount.h>
25
San Mehata2677e42009-12-13 10:40:18 -080026#include <linux/kdev_t.h>
San Mehatf1b736b2009-10-10 17:22:08 -070027
28#define LOG_TAG "Vold"
29
Kenny Root7b18a7b2010-03-15 13:13:41 -070030#include <openssl/md5.h>
31
San Mehatf1b736b2009-10-10 17:22:08 -070032#include <cutils/log.h>
33
San Mehatfd7f5872009-10-12 11:32:47 -070034#include <sysutils/NetlinkEvent.h>
35
San Mehatf1b736b2009-10-10 17:22:08 -070036#include "VolumeManager.h"
San Mehatae10b912009-10-12 14:57:05 -070037#include "DirectVolume.h"
San Mehata2677e42009-12-13 10:40:18 -080038#include "ResponseCode.h"
San Mehata19b2502010-01-06 10:33:53 -080039#include "Loop.h"
40#include "Fat.h"
San Mehatb78a32c2010-01-10 13:02:12 -080041#include "Devmapper.h"
San Mehat586536c2010-02-16 17:12:00 -080042#include "Process.h"
San Mehatfcf24fe2010-03-03 12:37:32 -080043#include "Asec.h"
San Mehat23969932010-01-09 07:08:06 -080044
San Mehatf1b736b2009-10-10 17:22:08 -070045VolumeManager *VolumeManager::sInstance = NULL;
46
47VolumeManager *VolumeManager::Instance() {
48 if (!sInstance)
49 sInstance = new VolumeManager();
50 return sInstance;
51}
52
53VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -080054 mDebug = false;
San Mehatf1b736b2009-10-10 17:22:08 -070055 mVolumes = new VolumeCollection();
San Mehat88705162010-01-15 09:26:28 -080056 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070057 mBroadcaster = NULL;
San Mehata2677e42009-12-13 10:40:18 -080058 mUsbMassStorageConnected = false;
San Mehatf1b736b2009-10-10 17:22:08 -070059}
60
61VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -080062 delete mVolumes;
63 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -070064}
65
Kenny Root7b18a7b2010-03-15 13:13:41 -070066#define MD5_ASCII_LENGTH ((MD5_DIGEST_LENGTH*2)+1)
San Mehatd9a4e352010-03-12 13:32:47 -080067
Kenny Root7b18a7b2010-03-15 13:13:41 -070068char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
69 unsigned char sig[MD5_DIGEST_LENGTH];
70
71 if (len < MD5_ASCII_LENGTH) {
72 LOGE("Target hash buffer size < %d bytes (%d)", MD5_ASCII_LENGTH, len);
San Mehatd9a4e352010-03-12 13:32:47 -080073 errno = ESPIPE;
74 return NULL;
75 }
Kenny Root7b18a7b2010-03-15 13:13:41 -070076
77 MD5(reinterpret_cast<const unsigned char*>(id), strlen(id), sig);
San Mehatd9a4e352010-03-12 13:32:47 -080078
79 memset(buffer, 0, len);
80
Kenny Root7b18a7b2010-03-15 13:13:41 -070081 for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
San Mehatd9a4e352010-03-12 13:32:47 -080082 char tmp[3];
83 snprintf(tmp, 3, "%.02x", sig[i]);
84 strcat(buffer, tmp);
85 }
86
87 return buffer;
88}
89
90void VolumeManager::setDebug(bool enable) {
91 mDebug = enable;
92 VolumeCollection::iterator it;
93 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
94 (*it)->setDebug(enable);
95 }
96}
97
San Mehatf1b736b2009-10-10 17:22:08 -070098int VolumeManager::start() {
99 return 0;
100}
101
102int VolumeManager::stop() {
103 return 0;
104}
105
106int VolumeManager::addVolume(Volume *v) {
107 mVolumes->push_back(v);
108 return 0;
109}
110
San Mehata2677e42009-12-13 10:40:18 -0800111void VolumeManager::notifyUmsConnected(bool connected) {
112 char msg[255];
113
114 if (connected) {
115 mUsbMassStorageConnected = true;
116 } else {
117 mUsbMassStorageConnected = false;
118 }
119 snprintf(msg, sizeof(msg), "Share method ums now %s",
120 (connected ? "available" : "unavailable"));
121
122 getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
123 msg, false);
124}
125
126void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
San Mehat0cde53c2009-12-22 08:32:33 -0800127 const char *devpath = evt->findParam("DEVPATH");
San Mehata2677e42009-12-13 10:40:18 -0800128 const char *name = evt->findParam("SWITCH_NAME");
129 const char *state = evt->findParam("SWITCH_STATE");
130
San Mehat0cde53c2009-12-22 08:32:33 -0800131 if (!name || !state) {
132 LOGW("Switch %s event missing name/state info", devpath);
133 return;
134 }
135
San Mehata2677e42009-12-13 10:40:18 -0800136 if (!strcmp(name, "usb_mass_storage")) {
137
138 if (!strcmp(state, "online")) {
139 notifyUmsConnected(true);
140 } else {
141 notifyUmsConnected(false);
142 }
143 } else {
144 LOGW("Ignoring unknown switch '%s'", name);
145 }
146}
147
San Mehatfd7f5872009-10-12 11:32:47 -0700148void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
149 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700150
San Mehatfd7f5872009-10-12 11:32:47 -0700151 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700152 VolumeCollection::iterator it;
153 bool hit = false;
154 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700155 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800156#ifdef NETLINK_DEBUG
157 LOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
158#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700159 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700160 break;
161 }
162 }
163
164 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800165#ifdef NETLINK_DEBUG
San Mehatfd7f5872009-10-12 11:32:47 -0700166 LOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800167#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700168 }
169}
170
San Mehatf1b736b2009-10-10 17:22:08 -0700171int VolumeManager::listVolumes(SocketClient *cli) {
172 VolumeCollection::iterator i;
173
174 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
175 char *buffer;
176 asprintf(&buffer, "%s %s %d",
177 (*i)->getLabel(), (*i)->getMountpoint(),
178 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800179 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700180 free(buffer);
181 }
San Mehata2677e42009-12-13 10:40:18 -0800182 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700183 return 0;
184}
San Mehat49e2bce2009-10-12 16:29:01 -0700185
San Mehata2677e42009-12-13 10:40:18 -0800186int VolumeManager::formatVolume(const char *label) {
187 Volume *v = lookupVolume(label);
188
189 if (!v) {
190 errno = ENOENT;
191 return -1;
192 }
193
194 return v->formatVol();
195}
196
San Mehata19b2502010-01-06 10:33:53 -0800197int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehat88ac2c02010-03-23 11:15:58 -0700198 char asecFileName[255];
199 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
200
201 memset(buffer, 0, maxlen);
202 if (access(asecFileName, F_OK)) {
203 errno = ENOENT;
204 return -1;
205 }
San Mehata19b2502010-01-06 10:33:53 -0800206
San Mehat3bb60202010-02-19 18:14:36 -0800207 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800208 return 0;
209}
210
San Mehat8b8f71b2010-01-11 09:17:25 -0800211int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800212 const char *fstype, const char *key, int ownerUid) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800213 struct asec_superblock sb;
214 memset(&sb, 0, sizeof(sb));
215
216 sb.magic = ASEC_SB_MAGIC;
217 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800218
San Mehatd31e3802010-02-18 08:37:45 -0800219 if (numSectors < ((1024*1024)/512)) {
220 LOGE("Invalid container size specified (%d sectors)", numSectors);
221 errno = EINVAL;
222 return -1;
223 }
224
San Mehata19b2502010-01-06 10:33:53 -0800225 if (lookupVolume(id)) {
San Mehat3bb60202010-02-19 18:14:36 -0800226 LOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800227 errno = EADDRINUSE;
228 return -1;
229 }
230
231 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800232 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800233
234 if (!access(asecFileName, F_OK)) {
235 LOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
236 asecFileName, strerror(errno));
237 errno = EADDRINUSE;
238 return -1;
239 }
240
San Mehatfcf24fe2010-03-03 12:37:32 -0800241 /*
242 * Add some headroom
243 */
244 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
245 unsigned numImgSectors = numSectors + fatSize + 2;
246
247 if (numImgSectors % 63) {
248 numImgSectors += (63 - (numImgSectors % 63));
249 }
250
251 // Add +1 for our superblock which is at the end
252 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehata19b2502010-01-06 10:33:53 -0800253 LOGE("ASEC image file creation failed (%s)", strerror(errno));
254 return -1;
255 }
256
San Mehatd9a4e352010-03-12 13:32:47 -0800257 char idHash[33];
258 if (!asecHash(id, idHash, sizeof(idHash))) {
259 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
260 unlink(asecFileName);
261 return -1;
262 }
263
San Mehata19b2502010-01-06 10:33:53 -0800264 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800265 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800266 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
267 unlink(asecFileName);
268 return -1;
269 }
270
San Mehatb78a32c2010-01-10 13:02:12 -0800271 char dmDevice[255];
272 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800273
San Mehatb78a32c2010-01-10 13:02:12 -0800274 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800275 // XXX: This is all we support for now
276 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800277 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800278 sizeof(dmDevice))) {
279 LOGE("ASEC device mapping failed (%s)", strerror(errno));
280 Loop::destroyByDevice(loopDevice);
281 unlink(asecFileName);
282 return -1;
283 }
284 cleanupDm = true;
285 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800286 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800287 strcpy(dmDevice, loopDevice);
288 }
289
San Mehatfcf24fe2010-03-03 12:37:32 -0800290 /*
291 * Drop down the superblock at the end of the file
292 */
293
294 int sbfd = open(loopDevice, O_RDWR);
295 if (sbfd < 0) {
296 LOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
297 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800298 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800299 }
300 Loop::destroyByDevice(loopDevice);
301 unlink(asecFileName);
302 return -1;
303 }
304
305 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
306 close(sbfd);
307 LOGE("Failed to lseek for superblock (%s)", strerror(errno));
308 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800309 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800310 }
311 Loop::destroyByDevice(loopDevice);
312 unlink(asecFileName);
313 return -1;
314 }
315
316 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
317 close(sbfd);
318 LOGE("Failed to write superblock (%s)", strerror(errno));
319 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800320 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800321 }
322 Loop::destroyByDevice(loopDevice);
323 unlink(asecFileName);
324 return -1;
325 }
326 close(sbfd);
327
San Mehata1091cb2010-02-28 20:17:20 -0800328 if (strcmp(fstype, "none")) {
329 if (strcmp(fstype, "fat")) {
330 LOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800331 }
San Mehata19b2502010-01-06 10:33:53 -0800332
San Mehatfcf24fe2010-03-03 12:37:32 -0800333 if (Fat::format(dmDevice, numImgSectors)) {
San Mehata1091cb2010-02-28 20:17:20 -0800334 LOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800335 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800336 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800337 }
San Mehateb13a902010-01-07 12:12:50 -0800338 Loop::destroyByDevice(loopDevice);
339 unlink(asecFileName);
340 return -1;
341 }
San Mehata1091cb2010-02-28 20:17:20 -0800342 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800343
San Mehata1091cb2010-02-28 20:17:20 -0800344 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
345 if (mkdir(mountPoint, 0777)) {
346 if (errno != EEXIST) {
347 LOGE("Mountpoint creation failed (%s)", strerror(errno));
348 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800349 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800350 }
351 Loop::destroyByDevice(loopDevice);
352 unlink(asecFileName);
353 return -1;
354 }
San Mehatb78a32c2010-01-10 13:02:12 -0800355 }
San Mehata1091cb2010-02-28 20:17:20 -0800356
357 if (Fat::doMount(dmDevice, mountPoint, false, false, ownerUid,
358 0, 0000, false)) {
359 LOGE("ASEC FAT mount failed (%s)", strerror(errno));
360 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800361 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800362 }
363 Loop::destroyByDevice(loopDevice);
364 unlink(asecFileName);
365 return -1;
366 }
367 } else {
368 LOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800369 }
San Mehat88705162010-01-15 09:26:28 -0800370
371 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800372 return 0;
373}
374
375int VolumeManager::finalizeAsec(const char *id) {
376 char asecFileName[255];
377 char loopDevice[255];
378 char mountPoint[255];
379
San Mehat3bb60202010-02-19 18:14:36 -0800380 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800381
San Mehatd9a4e352010-03-12 13:32:47 -0800382 char idHash[33];
383 if (!asecHash(id, idHash, sizeof(idHash))) {
384 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
385 return -1;
386 }
387
388 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800389 LOGE("Unable to finalize %s (%s)", id, strerror(errno));
390 return -1;
391 }
392
San Mehat3bb60202010-02-19 18:14:36 -0800393 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800394 // XXX:
395 if (Fat::doMount(loopDevice, mountPoint, true, true, 0, 0, 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800396 LOGE("ASEC finalize mount failed (%s)", strerror(errno));
397 return -1;
398 }
399
San Mehatd9a4e352010-03-12 13:32:47 -0800400 if (mDebug) {
401 LOGD("ASEC %s finalized", id);
402 }
San Mehata19b2502010-01-06 10:33:53 -0800403 return 0;
404}
405
San Mehat048b0802010-01-23 08:17:06 -0800406int VolumeManager::renameAsec(const char *id1, const char *id2) {
407 char *asecFilename1;
408 char *asecFilename2;
409 char mountPoint[255];
410
San Mehat3bb60202010-02-19 18:14:36 -0800411 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
412 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800413
San Mehat3bb60202010-02-19 18:14:36 -0800414 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800415 if (isMountpointMounted(mountPoint)) {
416 LOGW("Rename attempt when src mounted");
417 errno = EBUSY;
418 goto out_err;
419 }
420
San Mehat96956ed2010-02-24 08:42:51 -0800421 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
422 if (isMountpointMounted(mountPoint)) {
423 LOGW("Rename attempt when dst mounted");
424 errno = EBUSY;
425 goto out_err;
426 }
427
San Mehat048b0802010-01-23 08:17:06 -0800428 if (!access(asecFilename2, F_OK)) {
429 LOGE("Rename attempt when dst exists");
430 errno = EADDRINUSE;
431 goto out_err;
432 }
433
434 if (rename(asecFilename1, asecFilename2)) {
435 LOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
436 goto out_err;
437 }
438
439 free(asecFilename1);
440 free(asecFilename2);
441 return 0;
442
443out_err:
444 free(asecFilename1);
445 free(asecFilename2);
446 return -1;
447}
448
San Mehat4ba89482010-02-18 09:00:18 -0800449#define ASEC_UNMOUNT_RETRIES 5
450int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800451 char asecFileName[255];
452 char mountPoint[255];
453
San Mehat3bb60202010-02-19 18:14:36 -0800454 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
455 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800456
San Mehatd9a4e352010-03-12 13:32:47 -0800457 char idHash[33];
458 if (!asecHash(id, idHash, sizeof(idHash))) {
459 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
460 return -1;
461 }
462
San Mehat0586d542010-01-12 15:38:59 -0800463 if (!isMountpointMounted(mountPoint)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800464 LOGE("Unmount request for ASEC %s when not mounted", id);
465 errno = EINVAL;
466 return -1;
467 }
San Mehat23969932010-01-09 07:08:06 -0800468
San Mehatb78a32c2010-01-10 13:02:12 -0800469 int i, rc;
San Mehat8c940ef2010-02-13 14:19:53 -0800470 for (i = 1; i <= ASEC_UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800471 rc = umount(mountPoint);
472 if (!rc) {
473 break;
San Mehata19b2502010-01-06 10:33:53 -0800474 }
San Mehatb78a32c2010-01-10 13:02:12 -0800475 if (rc && (errno == EINVAL || errno == ENOENT)) {
San Mehat12f4b892010-02-24 11:43:22 -0800476 LOGI("Secure container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800477 rc = 0;
478 break;
San Mehata19b2502010-01-06 10:33:53 -0800479 }
San Mehatb78a32c2010-01-10 13:02:12 -0800480 LOGW("ASEC %s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800481 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800482
San Mehat4ba89482010-02-18 09:00:18 -0800483 int action = 0; // default is to just complain
484
485 if (force) {
486 if (i > (ASEC_UNMOUNT_RETRIES - 2))
487 action = 2; // SIGKILL
488 else if (i > (ASEC_UNMOUNT_RETRIES - 3))
489 action = 1; // SIGHUP
490 }
San Mehat8c940ef2010-02-13 14:19:53 -0800491
San Mehat586536c2010-02-16 17:12:00 -0800492 Process::killProcessesWithOpenFiles(mountPoint, action);
San Mehat8c940ef2010-02-13 14:19:53 -0800493 usleep(1000 * 1000);
San Mehatb78a32c2010-01-10 13:02:12 -0800494 }
495
496 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800497 errno = EBUSY;
498 LOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800499 return -1;
500 }
501
San Mehat12f4b892010-02-24 11:43:22 -0800502 int retries = 10;
503
504 while(retries--) {
505 if (!rmdir(mountPoint)) {
506 break;
507 }
508
509 LOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
510 usleep(1000 * 1000);
511 }
512
513 if (!retries) {
514 LOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800515 }
San Mehat88705162010-01-15 09:26:28 -0800516
San Mehatd9a4e352010-03-12 13:32:47 -0800517 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehatb78a32c2010-01-10 13:02:12 -0800518 LOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800519 }
520
521 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800522 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800523 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800524 } else {
525 LOGW("Failed to find loop device for {%s} (%s)", asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800526 }
San Mehat88705162010-01-15 09:26:28 -0800527
528 AsecIdCollection::iterator it;
529 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
530 if (!strcmp(*it, id)) {
531 free(*it);
532 mActiveContainers->erase(it);
533 break;
534 }
535 }
536 if (it == mActiveContainers->end()) {
537 LOGW("mActiveContainers is inconsistent!");
538 }
San Mehatb78a32c2010-01-10 13:02:12 -0800539 return 0;
540}
541
San Mehat4ba89482010-02-18 09:00:18 -0800542int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800543 char asecFileName[255];
544 char mountPoint[255];
545
San Mehat3bb60202010-02-19 18:14:36 -0800546 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800547 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800548
San Mehat0586d542010-01-12 15:38:59 -0800549 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800550 if (mDebug) {
551 LOGD("Unmounting container before destroy");
552 }
San Mehat4ba89482010-02-18 09:00:18 -0800553 if (unmountAsec(id, force)) {
San Mehat0586d542010-01-12 15:38:59 -0800554 LOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
555 return -1;
556 }
557 }
San Mehata19b2502010-01-06 10:33:53 -0800558
San Mehat0586d542010-01-12 15:38:59 -0800559 if (unlink(asecFileName)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800560 LOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800561 return -1;
562 }
San Mehata19b2502010-01-06 10:33:53 -0800563
San Mehatd9a4e352010-03-12 13:32:47 -0800564 if (mDebug) {
565 LOGD("ASEC %s destroyed", id);
566 }
San Mehata19b2502010-01-06 10:33:53 -0800567 return 0;
568}
569
570int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
571 char asecFileName[255];
572 char mountPoint[255];
573
San Mehat3bb60202010-02-19 18:14:36 -0800574 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
575 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800576
577 if (isMountpointMounted(mountPoint)) {
578 LOGE("ASEC %s already mounted", id);
579 errno = EBUSY;
580 return -1;
581 }
582
San Mehatd9a4e352010-03-12 13:32:47 -0800583 char idHash[33];
584 if (!asecHash(id, idHash, sizeof(idHash))) {
585 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
586 return -1;
587 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700588
San Mehata19b2502010-01-06 10:33:53 -0800589 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800590 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
591 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800592 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
593 return -1;
594 }
San Mehatd9a4e352010-03-12 13:32:47 -0800595 if (mDebug) {
596 LOGD("New loop device created at %s", loopDevice);
597 }
San Mehatb78a32c2010-01-10 13:02:12 -0800598 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800599 if (mDebug) {
600 LOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
601 }
San Mehatb78a32c2010-01-10 13:02:12 -0800602 }
603
604 char dmDevice[255];
605 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800606 int fd;
607 unsigned int nr_sec = 0;
608
609 if ((fd = open(loopDevice, O_RDWR)) < 0) {
610 LOGE("Failed to open loopdevice (%s)", strerror(errno));
611 Loop::destroyByDevice(loopDevice);
612 return -1;
613 }
614
615 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
616 LOGE("Failed to get loop size (%s)", strerror(errno));
617 Loop::destroyByDevice(loopDevice);
618 close(fd);
619 return -1;
620 }
621
622 /*
623 * Validate superblock
624 */
625 struct asec_superblock sb;
626 memset(&sb, 0, sizeof(sb));
627 if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
628 LOGE("lseek failed (%s)", strerror(errno));
629 close(fd);
630 Loop::destroyByDevice(loopDevice);
631 return -1;
632 }
633 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
634 LOGE("superblock read failed (%s)", strerror(errno));
635 close(fd);
636 Loop::destroyByDevice(loopDevice);
637 return -1;
638 }
639
640 close(fd);
641
San Mehatd9a4e352010-03-12 13:32:47 -0800642 if (mDebug) {
643 LOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
644 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800645 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
646 LOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
647 Loop::destroyByDevice(loopDevice);
648 errno = EMEDIUMTYPE;
649 return -1;
650 }
651 nr_sec--; // We don't want the devmapping to extend onto our superblock
652
San Mehatb78a32c2010-01-10 13:02:12 -0800653 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800654 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
655 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800656 dmDevice, sizeof(dmDevice))) {
657 LOGE("ASEC device mapping failed (%s)", strerror(errno));
658 Loop::destroyByDevice(loopDevice);
659 return -1;
660 }
San Mehatd9a4e352010-03-12 13:32:47 -0800661 if (mDebug) {
662 LOGD("New devmapper instance created at %s", dmDevice);
663 }
San Mehatb78a32c2010-01-10 13:02:12 -0800664 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800665 if (mDebug) {
666 LOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
667 }
San Mehatb78a32c2010-01-10 13:02:12 -0800668 }
669 cleanupDm = true;
670 } else {
671 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800672 }
673
674 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800675 if (errno != EEXIST) {
676 LOGE("Mountpoint creation failed (%s)", strerror(errno));
677 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800678 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800679 }
680 Loop::destroyByDevice(loopDevice);
681 return -1;
682 }
San Mehata19b2502010-01-06 10:33:53 -0800683 }
684
San Mehatb78a32c2010-01-10 13:02:12 -0800685 if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800686 0222, false)) {
687// 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800688 LOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800689 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800690 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800691 }
692 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800693 return -1;
694 }
695
San Mehat88705162010-01-15 09:26:28 -0800696 mActiveContainers->push_back(strdup(id));
San Mehatd9a4e352010-03-12 13:32:47 -0800697 if (mDebug) {
698 LOGD("ASEC %s mounted", id);
699 }
San Mehata19b2502010-01-06 10:33:53 -0800700 return 0;
701}
702
San Mehat49e2bce2009-10-12 16:29:01 -0700703int VolumeManager::mountVolume(const char *label) {
704 Volume *v = lookupVolume(label);
705
706 if (!v) {
707 errno = ENOENT;
708 return -1;
709 }
710
San Mehata2677e42009-12-13 10:40:18 -0800711 return v->mountVol();
712}
713
714int VolumeManager::shareAvailable(const char *method, bool *avail) {
715
716 if (strcmp(method, "ums")) {
717 errno = ENOSYS;
718 return -1;
719 }
720
721 if (mUsbMassStorageConnected)
722 *avail = true;
723 else
724 *avail = false;
725 return 0;
726}
727
San Mehateba65e92010-01-29 05:15:16 -0800728int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
729 Volume *v = lookupVolume(label);
730
731 if (!v) {
732 errno = ENOENT;
733 return -1;
734 }
735
736 if (strcmp(method, "ums")) {
737 errno = ENOSYS;
738 return -1;
739 }
740
741 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800742 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800743 } else {
744 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800745 }
746 return 0;
747}
748
San Mehata2677e42009-12-13 10:40:18 -0800749int VolumeManager::simulate(const char *cmd, const char *arg) {
750
751 if (!strcmp(cmd, "ums")) {
752 if (!strcmp(arg, "connect")) {
753 notifyUmsConnected(true);
754 } else if (!strcmp(arg, "disconnect")) {
755 notifyUmsConnected(false);
756 } else {
757 errno = EINVAL;
758 return -1;
759 }
760 } else {
761 errno = EINVAL;
762 return -1;
763 }
764 return 0;
765}
766
767int VolumeManager::shareVolume(const char *label, const char *method) {
768 Volume *v = lookupVolume(label);
769
770 if (!v) {
771 errno = ENOENT;
772 return -1;
773 }
774
775 /*
776 * Eventually, we'll want to support additional share back-ends,
777 * some of which may work while the media is mounted. For now,
778 * we just support UMS
779 */
780 if (strcmp(method, "ums")) {
781 errno = ENOSYS;
782 return -1;
783 }
784
785 if (v->getState() == Volume::State_NoMedia) {
786 errno = ENODEV;
787 return -1;
788 }
789
San Mehat49e2bce2009-10-12 16:29:01 -0700790 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800791 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700792 errno = EBUSY;
793 return -1;
794 }
795
San Mehata2677e42009-12-13 10:40:18 -0800796 dev_t d = v->getDiskDevice();
797 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
798 // This volume does not support raw disk access
799 errno = EINVAL;
800 return -1;
801 }
802
803 int fd;
804 char nodepath[255];
805 snprintf(nodepath,
806 sizeof(nodepath), "/dev/block/vold/%d:%d",
807 MAJOR(d), MINOR(d));
808
San Mehat0cde53c2009-12-22 08:32:33 -0800809 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
810 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800811 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
812 return -1;
813 }
814
815 if (write(fd, nodepath, strlen(nodepath)) < 0) {
816 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
817 close(fd);
818 return -1;
819 }
820
821 close(fd);
822 v->handleVolumeShared();
823 return 0;
824}
825
826int VolumeManager::unshareVolume(const char *label, const char *method) {
827 Volume *v = lookupVolume(label);
828
829 if (!v) {
830 errno = ENOENT;
831 return -1;
832 }
833
834 if (strcmp(method, "ums")) {
835 errno = ENOSYS;
836 return -1;
837 }
838
839 if (v->getState() != Volume::State_Shared) {
840 errno = EINVAL;
841 return -1;
842 }
843
844 dev_t d = v->getDiskDevice();
845
846 int fd;
847 char nodepath[255];
848 snprintf(nodepath,
849 sizeof(nodepath), "/dev/block/vold/%d:%d",
850 MAJOR(d), MINOR(d));
851
San Mehat0cde53c2009-12-22 08:32:33 -0800852 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800853 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
854 return -1;
855 }
856
857 char ch = 0;
858 if (write(fd, &ch, 1) < 0) {
859 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
860 close(fd);
861 return -1;
862 }
863
864 close(fd);
865 v->handleVolumeUnshared();
866 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700867}
868
San Mehat4ba89482010-02-18 09:00:18 -0800869int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -0700870 Volume *v = lookupVolume(label);
871
872 if (!v) {
873 errno = ENOENT;
874 return -1;
875 }
876
San Mehata2677e42009-12-13 10:40:18 -0800877 if (v->getState() == Volume::State_NoMedia) {
878 errno = ENODEV;
879 return -1;
880 }
881
San Mehat49e2bce2009-10-12 16:29:01 -0700882 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800883 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
884 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700885 errno = EBUSY;
886 return -1;
887 }
888
San Mehat88705162010-01-15 09:26:28 -0800889 while(mActiveContainers->size()) {
890 AsecIdCollection::iterator it = mActiveContainers->begin();
891 LOGI("Unmounting ASEC %s (dependant on %s)", *it, v->getMountpoint());
San Mehat4ba89482010-02-18 09:00:18 -0800892 if (unmountAsec(*it, force)) {
San Mehat12f4b892010-02-24 11:43:22 -0800893 LOGE("Failed to unmount ASEC %s (%s)", *it, strerror(errno));
San Mehat0e382532010-02-24 08:25:55 -0800894 return -1;
San Mehat88705162010-01-15 09:26:28 -0800895 }
896 }
897
San Mehat4ba89482010-02-18 09:00:18 -0800898 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -0700899}
900
San Mehata2677e42009-12-13 10:40:18 -0800901/*
902 * Looks up a volume by it's label or mount-point
903 */
San Mehat49e2bce2009-10-12 16:29:01 -0700904Volume *VolumeManager::lookupVolume(const char *label) {
905 VolumeCollection::iterator i;
906
907 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800908 if (label[0] == '/') {
909 if (!strcmp(label, (*i)->getMountpoint()))
910 return (*i);
911 } else {
912 if (!strcmp(label, (*i)->getLabel()))
913 return (*i);
914 }
San Mehat49e2bce2009-10-12 16:29:01 -0700915 }
916 return NULL;
917}
San Mehata19b2502010-01-06 10:33:53 -0800918
919bool VolumeManager::isMountpointMounted(const char *mp)
920{
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 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
929 return false;
930 }
931
932 while(fgets(line, sizeof(line), fp)) {
933 line[strlen(line)-1] = '\0';
934 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
935 if (!strcmp(mount_path, mp)) {
936 fclose(fp);
937 return true;
938 }
San Mehata19b2502010-01-06 10:33:53 -0800939 }
940
941 fclose(fp);
942 return false;
943}
944