blob: dd25d861d62eedf15c81b1a8cbf1e776bf8d5827 [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 Mehata19b2502010-01-06 10:33:53 -0800198
San Mehat3bb60202010-02-19 18:14:36 -0800199 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800200 return 0;
201}
202
San Mehat8b8f71b2010-01-11 09:17:25 -0800203int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800204 const char *fstype, const char *key, int ownerUid) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800205 struct asec_superblock sb;
206 memset(&sb, 0, sizeof(sb));
207
208 sb.magic = ASEC_SB_MAGIC;
209 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800210
San Mehatd31e3802010-02-18 08:37:45 -0800211 if (numSectors < ((1024*1024)/512)) {
212 LOGE("Invalid container size specified (%d sectors)", numSectors);
213 errno = EINVAL;
214 return -1;
215 }
216
San Mehata19b2502010-01-06 10:33:53 -0800217 if (lookupVolume(id)) {
San Mehat3bb60202010-02-19 18:14:36 -0800218 LOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800219 errno = EADDRINUSE;
220 return -1;
221 }
222
223 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800224 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800225
226 if (!access(asecFileName, F_OK)) {
227 LOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
228 asecFileName, strerror(errno));
229 errno = EADDRINUSE;
230 return -1;
231 }
232
San Mehatfcf24fe2010-03-03 12:37:32 -0800233 /*
234 * Add some headroom
235 */
236 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
237 unsigned numImgSectors = numSectors + fatSize + 2;
238
239 if (numImgSectors % 63) {
240 numImgSectors += (63 - (numImgSectors % 63));
241 }
242
243 // Add +1 for our superblock which is at the end
244 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehata19b2502010-01-06 10:33:53 -0800245 LOGE("ASEC image file creation failed (%s)", strerror(errno));
246 return -1;
247 }
248
San Mehatd9a4e352010-03-12 13:32:47 -0800249 char idHash[33];
250 if (!asecHash(id, idHash, sizeof(idHash))) {
251 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
252 unlink(asecFileName);
253 return -1;
254 }
255
San Mehata19b2502010-01-06 10:33:53 -0800256 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800257 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800258 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
259 unlink(asecFileName);
260 return -1;
261 }
262
San Mehatb78a32c2010-01-10 13:02:12 -0800263 char dmDevice[255];
264 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800265
San Mehatb78a32c2010-01-10 13:02:12 -0800266 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800267 // XXX: This is all we support for now
268 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800269 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800270 sizeof(dmDevice))) {
271 LOGE("ASEC device mapping failed (%s)", strerror(errno));
272 Loop::destroyByDevice(loopDevice);
273 unlink(asecFileName);
274 return -1;
275 }
276 cleanupDm = true;
277 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800278 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800279 strcpy(dmDevice, loopDevice);
280 }
281
San Mehatfcf24fe2010-03-03 12:37:32 -0800282 /*
283 * Drop down the superblock at the end of the file
284 */
285
286 int sbfd = open(loopDevice, O_RDWR);
287 if (sbfd < 0) {
288 LOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
289 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800290 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800291 }
292 Loop::destroyByDevice(loopDevice);
293 unlink(asecFileName);
294 return -1;
295 }
296
297 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
298 close(sbfd);
299 LOGE("Failed to lseek for superblock (%s)", strerror(errno));
300 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800301 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800302 }
303 Loop::destroyByDevice(loopDevice);
304 unlink(asecFileName);
305 return -1;
306 }
307
308 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
309 close(sbfd);
310 LOGE("Failed to write superblock (%s)", strerror(errno));
311 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800312 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800313 }
314 Loop::destroyByDevice(loopDevice);
315 unlink(asecFileName);
316 return -1;
317 }
318 close(sbfd);
319
San Mehata1091cb2010-02-28 20:17:20 -0800320 if (strcmp(fstype, "none")) {
321 if (strcmp(fstype, "fat")) {
322 LOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800323 }
San Mehata19b2502010-01-06 10:33:53 -0800324
San Mehatfcf24fe2010-03-03 12:37:32 -0800325 if (Fat::format(dmDevice, numImgSectors)) {
San Mehata1091cb2010-02-28 20:17:20 -0800326 LOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800327 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800328 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800329 }
San Mehateb13a902010-01-07 12:12:50 -0800330 Loop::destroyByDevice(loopDevice);
331 unlink(asecFileName);
332 return -1;
333 }
San Mehata1091cb2010-02-28 20:17:20 -0800334 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800335
San Mehata1091cb2010-02-28 20:17:20 -0800336 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
337 if (mkdir(mountPoint, 0777)) {
338 if (errno != EEXIST) {
339 LOGE("Mountpoint creation failed (%s)", strerror(errno));
340 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800341 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800342 }
343 Loop::destroyByDevice(loopDevice);
344 unlink(asecFileName);
345 return -1;
346 }
San Mehatb78a32c2010-01-10 13:02:12 -0800347 }
San Mehata1091cb2010-02-28 20:17:20 -0800348
349 if (Fat::doMount(dmDevice, mountPoint, false, false, ownerUid,
350 0, 0000, false)) {
351 LOGE("ASEC FAT mount failed (%s)", strerror(errno));
352 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800353 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800354 }
355 Loop::destroyByDevice(loopDevice);
356 unlink(asecFileName);
357 return -1;
358 }
359 } else {
360 LOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800361 }
San Mehat88705162010-01-15 09:26:28 -0800362
363 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800364 return 0;
365}
366
367int VolumeManager::finalizeAsec(const char *id) {
368 char asecFileName[255];
369 char loopDevice[255];
370 char mountPoint[255];
371
San Mehat3bb60202010-02-19 18:14:36 -0800372 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800373
San Mehatd9a4e352010-03-12 13:32:47 -0800374 char idHash[33];
375 if (!asecHash(id, idHash, sizeof(idHash))) {
376 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
377 return -1;
378 }
379
380 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800381 LOGE("Unable to finalize %s (%s)", id, strerror(errno));
382 return -1;
383 }
384
San Mehat3bb60202010-02-19 18:14:36 -0800385 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800386 // XXX:
387 if (Fat::doMount(loopDevice, mountPoint, true, true, 0, 0, 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800388 LOGE("ASEC finalize mount failed (%s)", strerror(errno));
389 return -1;
390 }
391
San Mehatd9a4e352010-03-12 13:32:47 -0800392 if (mDebug) {
393 LOGD("ASEC %s finalized", id);
394 }
San Mehata19b2502010-01-06 10:33:53 -0800395 return 0;
396}
397
San Mehat048b0802010-01-23 08:17:06 -0800398int VolumeManager::renameAsec(const char *id1, const char *id2) {
399 char *asecFilename1;
400 char *asecFilename2;
401 char mountPoint[255];
402
San Mehat3bb60202010-02-19 18:14:36 -0800403 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
404 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800405
San Mehat3bb60202010-02-19 18:14:36 -0800406 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800407 if (isMountpointMounted(mountPoint)) {
408 LOGW("Rename attempt when src mounted");
409 errno = EBUSY;
410 goto out_err;
411 }
412
San Mehat96956ed2010-02-24 08:42:51 -0800413 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
414 if (isMountpointMounted(mountPoint)) {
415 LOGW("Rename attempt when dst mounted");
416 errno = EBUSY;
417 goto out_err;
418 }
419
San Mehat048b0802010-01-23 08:17:06 -0800420 if (!access(asecFilename2, F_OK)) {
421 LOGE("Rename attempt when dst exists");
422 errno = EADDRINUSE;
423 goto out_err;
424 }
425
426 if (rename(asecFilename1, asecFilename2)) {
427 LOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
428 goto out_err;
429 }
430
431 free(asecFilename1);
432 free(asecFilename2);
433 return 0;
434
435out_err:
436 free(asecFilename1);
437 free(asecFilename2);
438 return -1;
439}
440
San Mehat4ba89482010-02-18 09:00:18 -0800441#define ASEC_UNMOUNT_RETRIES 5
442int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800443 char asecFileName[255];
444 char mountPoint[255];
445
San Mehat3bb60202010-02-19 18:14:36 -0800446 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
447 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800448
San Mehatd9a4e352010-03-12 13:32:47 -0800449 char idHash[33];
450 if (!asecHash(id, idHash, sizeof(idHash))) {
451 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
452 return -1;
453 }
454
San Mehat0586d542010-01-12 15:38:59 -0800455 if (!isMountpointMounted(mountPoint)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800456 LOGE("Unmount request for ASEC %s when not mounted", id);
457 errno = EINVAL;
458 return -1;
459 }
San Mehat23969932010-01-09 07:08:06 -0800460
San Mehatb78a32c2010-01-10 13:02:12 -0800461 int i, rc;
San Mehat8c940ef2010-02-13 14:19:53 -0800462 for (i = 1; i <= ASEC_UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800463 rc = umount(mountPoint);
464 if (!rc) {
465 break;
San Mehata19b2502010-01-06 10:33:53 -0800466 }
San Mehatb78a32c2010-01-10 13:02:12 -0800467 if (rc && (errno == EINVAL || errno == ENOENT)) {
San Mehat12f4b892010-02-24 11:43:22 -0800468 LOGI("Secure container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800469 rc = 0;
470 break;
San Mehata19b2502010-01-06 10:33:53 -0800471 }
San Mehatb78a32c2010-01-10 13:02:12 -0800472 LOGW("ASEC %s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800473 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800474
San Mehat4ba89482010-02-18 09:00:18 -0800475 int action = 0; // default is to just complain
476
477 if (force) {
478 if (i > (ASEC_UNMOUNT_RETRIES - 2))
479 action = 2; // SIGKILL
480 else if (i > (ASEC_UNMOUNT_RETRIES - 3))
481 action = 1; // SIGHUP
482 }
San Mehat8c940ef2010-02-13 14:19:53 -0800483
San Mehat586536c2010-02-16 17:12:00 -0800484 Process::killProcessesWithOpenFiles(mountPoint, action);
San Mehat8c940ef2010-02-13 14:19:53 -0800485 usleep(1000 * 1000);
San Mehatb78a32c2010-01-10 13:02:12 -0800486 }
487
488 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800489 errno = EBUSY;
490 LOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800491 return -1;
492 }
493
San Mehat12f4b892010-02-24 11:43:22 -0800494 int retries = 10;
495
496 while(retries--) {
497 if (!rmdir(mountPoint)) {
498 break;
499 }
500
501 LOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
502 usleep(1000 * 1000);
503 }
504
505 if (!retries) {
506 LOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800507 }
San Mehat88705162010-01-15 09:26:28 -0800508
San Mehatd9a4e352010-03-12 13:32:47 -0800509 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehatb78a32c2010-01-10 13:02:12 -0800510 LOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800511 }
512
513 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800514 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800515 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800516 } else {
517 LOGW("Failed to find loop device for {%s} (%s)", asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800518 }
San Mehat88705162010-01-15 09:26:28 -0800519
520 AsecIdCollection::iterator it;
521 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
522 if (!strcmp(*it, id)) {
523 free(*it);
524 mActiveContainers->erase(it);
525 break;
526 }
527 }
528 if (it == mActiveContainers->end()) {
529 LOGW("mActiveContainers is inconsistent!");
530 }
San Mehatb78a32c2010-01-10 13:02:12 -0800531 return 0;
532}
533
San Mehat4ba89482010-02-18 09:00:18 -0800534int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800535 char asecFileName[255];
536 char mountPoint[255];
537
San Mehat3bb60202010-02-19 18:14:36 -0800538 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800539 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800540
San Mehat0586d542010-01-12 15:38:59 -0800541 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800542 if (mDebug) {
543 LOGD("Unmounting container before destroy");
544 }
San Mehat4ba89482010-02-18 09:00:18 -0800545 if (unmountAsec(id, force)) {
San Mehat0586d542010-01-12 15:38:59 -0800546 LOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
547 return -1;
548 }
549 }
San Mehata19b2502010-01-06 10:33:53 -0800550
San Mehat0586d542010-01-12 15:38:59 -0800551 if (unlink(asecFileName)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800552 LOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800553 return -1;
554 }
San Mehata19b2502010-01-06 10:33:53 -0800555
San Mehatd9a4e352010-03-12 13:32:47 -0800556 if (mDebug) {
557 LOGD("ASEC %s destroyed", id);
558 }
San Mehata19b2502010-01-06 10:33:53 -0800559 return 0;
560}
561
562int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
563 char asecFileName[255];
564 char mountPoint[255];
565
San Mehat3bb60202010-02-19 18:14:36 -0800566 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
567 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800568
569 if (isMountpointMounted(mountPoint)) {
570 LOGE("ASEC %s already mounted", id);
571 errno = EBUSY;
572 return -1;
573 }
574
San Mehatd9a4e352010-03-12 13:32:47 -0800575 char idHash[33];
576 if (!asecHash(id, idHash, sizeof(idHash))) {
577 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
578 return -1;
579 }
Kenny Root7b18a7b2010-03-15 13:13:41 -0700580
San Mehata19b2502010-01-06 10:33:53 -0800581 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800582 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
583 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800584 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
585 return -1;
586 }
San Mehatd9a4e352010-03-12 13:32:47 -0800587 if (mDebug) {
588 LOGD("New loop device created at %s", loopDevice);
589 }
San Mehatb78a32c2010-01-10 13:02:12 -0800590 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800591 if (mDebug) {
592 LOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
593 }
San Mehatb78a32c2010-01-10 13:02:12 -0800594 }
595
596 char dmDevice[255];
597 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800598 int fd;
599 unsigned int nr_sec = 0;
600
601 if ((fd = open(loopDevice, O_RDWR)) < 0) {
602 LOGE("Failed to open loopdevice (%s)", strerror(errno));
603 Loop::destroyByDevice(loopDevice);
604 return -1;
605 }
606
607 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
608 LOGE("Failed to get loop size (%s)", strerror(errno));
609 Loop::destroyByDevice(loopDevice);
610 close(fd);
611 return -1;
612 }
613
614 /*
615 * Validate superblock
616 */
617 struct asec_superblock sb;
618 memset(&sb, 0, sizeof(sb));
619 if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
620 LOGE("lseek failed (%s)", strerror(errno));
621 close(fd);
622 Loop::destroyByDevice(loopDevice);
623 return -1;
624 }
625 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
626 LOGE("superblock read failed (%s)", strerror(errno));
627 close(fd);
628 Loop::destroyByDevice(loopDevice);
629 return -1;
630 }
631
632 close(fd);
633
San Mehatd9a4e352010-03-12 13:32:47 -0800634 if (mDebug) {
635 LOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
636 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800637 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
638 LOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
639 Loop::destroyByDevice(loopDevice);
640 errno = EMEDIUMTYPE;
641 return -1;
642 }
643 nr_sec--; // We don't want the devmapping to extend onto our superblock
644
San Mehatb78a32c2010-01-10 13:02:12 -0800645 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800646 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
647 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800648 dmDevice, sizeof(dmDevice))) {
649 LOGE("ASEC device mapping failed (%s)", strerror(errno));
650 Loop::destroyByDevice(loopDevice);
651 return -1;
652 }
San Mehatd9a4e352010-03-12 13:32:47 -0800653 if (mDebug) {
654 LOGD("New devmapper instance created at %s", dmDevice);
655 }
San Mehatb78a32c2010-01-10 13:02:12 -0800656 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800657 if (mDebug) {
658 LOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
659 }
San Mehatb78a32c2010-01-10 13:02:12 -0800660 }
661 cleanupDm = true;
662 } else {
663 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800664 }
665
666 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800667 if (errno != EEXIST) {
668 LOGE("Mountpoint creation failed (%s)", strerror(errno));
669 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800670 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800671 }
672 Loop::destroyByDevice(loopDevice);
673 return -1;
674 }
San Mehata19b2502010-01-06 10:33:53 -0800675 }
676
San Mehatb78a32c2010-01-10 13:02:12 -0800677 if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800678 0222, false)) {
679// 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800680 LOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800681 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800682 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800683 }
684 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800685 return -1;
686 }
687
San Mehat88705162010-01-15 09:26:28 -0800688 mActiveContainers->push_back(strdup(id));
San Mehatd9a4e352010-03-12 13:32:47 -0800689 if (mDebug) {
690 LOGD("ASEC %s mounted", id);
691 }
San Mehata19b2502010-01-06 10:33:53 -0800692 return 0;
693}
694
San Mehat49e2bce2009-10-12 16:29:01 -0700695int VolumeManager::mountVolume(const char *label) {
696 Volume *v = lookupVolume(label);
697
698 if (!v) {
699 errno = ENOENT;
700 return -1;
701 }
702
San Mehata2677e42009-12-13 10:40:18 -0800703 return v->mountVol();
704}
705
706int VolumeManager::shareAvailable(const char *method, bool *avail) {
707
708 if (strcmp(method, "ums")) {
709 errno = ENOSYS;
710 return -1;
711 }
712
713 if (mUsbMassStorageConnected)
714 *avail = true;
715 else
716 *avail = false;
717 return 0;
718}
719
San Mehateba65e92010-01-29 05:15:16 -0800720int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
721 Volume *v = lookupVolume(label);
722
723 if (!v) {
724 errno = ENOENT;
725 return -1;
726 }
727
728 if (strcmp(method, "ums")) {
729 errno = ENOSYS;
730 return -1;
731 }
732
733 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800734 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800735 } else {
736 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800737 }
738 return 0;
739}
740
San Mehata2677e42009-12-13 10:40:18 -0800741int VolumeManager::simulate(const char *cmd, const char *arg) {
742
743 if (!strcmp(cmd, "ums")) {
744 if (!strcmp(arg, "connect")) {
745 notifyUmsConnected(true);
746 } else if (!strcmp(arg, "disconnect")) {
747 notifyUmsConnected(false);
748 } else {
749 errno = EINVAL;
750 return -1;
751 }
752 } else {
753 errno = EINVAL;
754 return -1;
755 }
756 return 0;
757}
758
759int VolumeManager::shareVolume(const char *label, const char *method) {
760 Volume *v = lookupVolume(label);
761
762 if (!v) {
763 errno = ENOENT;
764 return -1;
765 }
766
767 /*
768 * Eventually, we'll want to support additional share back-ends,
769 * some of which may work while the media is mounted. For now,
770 * we just support UMS
771 */
772 if (strcmp(method, "ums")) {
773 errno = ENOSYS;
774 return -1;
775 }
776
777 if (v->getState() == Volume::State_NoMedia) {
778 errno = ENODEV;
779 return -1;
780 }
781
San Mehat49e2bce2009-10-12 16:29:01 -0700782 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800783 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700784 errno = EBUSY;
785 return -1;
786 }
787
San Mehata2677e42009-12-13 10:40:18 -0800788 dev_t d = v->getDiskDevice();
789 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
790 // This volume does not support raw disk access
791 errno = EINVAL;
792 return -1;
793 }
794
795 int fd;
796 char nodepath[255];
797 snprintf(nodepath,
798 sizeof(nodepath), "/dev/block/vold/%d:%d",
799 MAJOR(d), MINOR(d));
800
San Mehat0cde53c2009-12-22 08:32:33 -0800801 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
802 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800803 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
804 return -1;
805 }
806
807 if (write(fd, nodepath, strlen(nodepath)) < 0) {
808 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
809 close(fd);
810 return -1;
811 }
812
813 close(fd);
814 v->handleVolumeShared();
815 return 0;
816}
817
818int VolumeManager::unshareVolume(const char *label, const char *method) {
819 Volume *v = lookupVolume(label);
820
821 if (!v) {
822 errno = ENOENT;
823 return -1;
824 }
825
826 if (strcmp(method, "ums")) {
827 errno = ENOSYS;
828 return -1;
829 }
830
831 if (v->getState() != Volume::State_Shared) {
832 errno = EINVAL;
833 return -1;
834 }
835
836 dev_t d = v->getDiskDevice();
837
838 int fd;
839 char nodepath[255];
840 snprintf(nodepath,
841 sizeof(nodepath), "/dev/block/vold/%d:%d",
842 MAJOR(d), MINOR(d));
843
San Mehat0cde53c2009-12-22 08:32:33 -0800844 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800845 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
846 return -1;
847 }
848
849 char ch = 0;
850 if (write(fd, &ch, 1) < 0) {
851 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
852 close(fd);
853 return -1;
854 }
855
856 close(fd);
857 v->handleVolumeUnshared();
858 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700859}
860
San Mehat4ba89482010-02-18 09:00:18 -0800861int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -0700862 Volume *v = lookupVolume(label);
863
864 if (!v) {
865 errno = ENOENT;
866 return -1;
867 }
868
San Mehata2677e42009-12-13 10:40:18 -0800869 if (v->getState() == Volume::State_NoMedia) {
870 errno = ENODEV;
871 return -1;
872 }
873
San Mehat49e2bce2009-10-12 16:29:01 -0700874 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800875 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
876 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700877 errno = EBUSY;
878 return -1;
879 }
880
San Mehat88705162010-01-15 09:26:28 -0800881 while(mActiveContainers->size()) {
882 AsecIdCollection::iterator it = mActiveContainers->begin();
883 LOGI("Unmounting ASEC %s (dependant on %s)", *it, v->getMountpoint());
San Mehat4ba89482010-02-18 09:00:18 -0800884 if (unmountAsec(*it, force)) {
San Mehat12f4b892010-02-24 11:43:22 -0800885 LOGE("Failed to unmount ASEC %s (%s)", *it, strerror(errno));
San Mehat0e382532010-02-24 08:25:55 -0800886 return -1;
San Mehat88705162010-01-15 09:26:28 -0800887 }
888 }
889
San Mehat4ba89482010-02-18 09:00:18 -0800890 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -0700891}
892
San Mehata2677e42009-12-13 10:40:18 -0800893/*
894 * Looks up a volume by it's label or mount-point
895 */
San Mehat49e2bce2009-10-12 16:29:01 -0700896Volume *VolumeManager::lookupVolume(const char *label) {
897 VolumeCollection::iterator i;
898
899 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800900 if (label[0] == '/') {
901 if (!strcmp(label, (*i)->getMountpoint()))
902 return (*i);
903 } else {
904 if (!strcmp(label, (*i)->getLabel()))
905 return (*i);
906 }
San Mehat49e2bce2009-10-12 16:29:01 -0700907 }
908 return NULL;
909}
San Mehata19b2502010-01-06 10:33:53 -0800910
911bool VolumeManager::isMountpointMounted(const char *mp)
912{
913 char device[256];
914 char mount_path[256];
915 char rest[256];
916 FILE *fp;
917 char line[1024];
918
919 if (!(fp = fopen("/proc/mounts", "r"))) {
920 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
921 return false;
922 }
923
924 while(fgets(line, sizeof(line), fp)) {
925 line[strlen(line)-1] = '\0';
926 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
927 if (!strcmp(mount_path, mp)) {
928 fclose(fp);
929 return true;
930 }
931
932 }
933
934 fclose(fp);
935 return false;
936}
937