blob: c8e4480725181b58276ec91414ad92cd5e8dbe20 [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
30#include <cutils/log.h>
31
San Mehatfd7f5872009-10-12 11:32:47 -070032#include <sysutils/NetlinkEvent.h>
33
San Mehatf1b736b2009-10-10 17:22:08 -070034#include "VolumeManager.h"
San Mehatae10b912009-10-12 14:57:05 -070035#include "DirectVolume.h"
San Mehata2677e42009-12-13 10:40:18 -080036#include "ResponseCode.h"
San Mehata19b2502010-01-06 10:33:53 -080037#include "Loop.h"
38#include "Fat.h"
San Mehatb78a32c2010-01-10 13:02:12 -080039#include "Devmapper.h"
San Mehat586536c2010-02-16 17:12:00 -080040#include "Process.h"
San Mehatfcf24fe2010-03-03 12:37:32 -080041#include "Asec.h"
San Mehatd9a4e352010-03-12 13:32:47 -080042#include "md5.h"
San Mehat23969932010-01-09 07:08:06 -080043
San Mehatf1b736b2009-10-10 17:22:08 -070044VolumeManager *VolumeManager::sInstance = NULL;
45
46VolumeManager *VolumeManager::Instance() {
47 if (!sInstance)
48 sInstance = new VolumeManager();
49 return sInstance;
50}
51
52VolumeManager::VolumeManager() {
San Mehatd9a4e352010-03-12 13:32:47 -080053 mDebug = false;
San Mehatf1b736b2009-10-10 17:22:08 -070054 mVolumes = new VolumeCollection();
San Mehat88705162010-01-15 09:26:28 -080055 mActiveContainers = new AsecIdCollection();
San Mehatf1b736b2009-10-10 17:22:08 -070056 mBroadcaster = NULL;
San Mehata2677e42009-12-13 10:40:18 -080057 mUsbMassStorageConnected = false;
San Mehatf1b736b2009-10-10 17:22:08 -070058}
59
60VolumeManager::~VolumeManager() {
San Mehat88705162010-01-15 09:26:28 -080061 delete mVolumes;
62 delete mActiveContainers;
San Mehatf1b736b2009-10-10 17:22:08 -070063}
64
San Mehatd9a4e352010-03-12 13:32:47 -080065char *VolumeManager::asecHash(const char *id, char *buffer, size_t len) {
66 MD5_CTX ctx;
67 unsigned char sig[16];
68
69 if (len < 33) {
70 LOGE("Target hash buffer size < 33 bytes (%d)", len);
71 errno = ESPIPE;
72 return NULL;
73 }
74 MD5_Init(&ctx);
75 MD5_Update(&ctx, id, strlen(id));
76 MD5_Final(sig, &ctx);
77
78 memset(buffer, 0, len);
79
80 for (int i = 0; i < 16; i++) {
81 char tmp[3];
82 snprintf(tmp, 3, "%.02x", sig[i]);
83 strcat(buffer, tmp);
84 }
85
86 return buffer;
87}
88
89void VolumeManager::setDebug(bool enable) {
90 mDebug = enable;
91 VolumeCollection::iterator it;
92 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
93 (*it)->setDebug(enable);
94 }
95}
96
San Mehatf1b736b2009-10-10 17:22:08 -070097int VolumeManager::start() {
98 return 0;
99}
100
101int VolumeManager::stop() {
102 return 0;
103}
104
105int VolumeManager::addVolume(Volume *v) {
106 mVolumes->push_back(v);
107 return 0;
108}
109
San Mehata2677e42009-12-13 10:40:18 -0800110void VolumeManager::notifyUmsConnected(bool connected) {
111 char msg[255];
112
113 if (connected) {
114 mUsbMassStorageConnected = true;
115 } else {
116 mUsbMassStorageConnected = false;
117 }
118 snprintf(msg, sizeof(msg), "Share method ums now %s",
119 (connected ? "available" : "unavailable"));
120
121 getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
122 msg, false);
123}
124
125void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
San Mehat0cde53c2009-12-22 08:32:33 -0800126 const char *devpath = evt->findParam("DEVPATH");
San Mehata2677e42009-12-13 10:40:18 -0800127 const char *name = evt->findParam("SWITCH_NAME");
128 const char *state = evt->findParam("SWITCH_STATE");
129
San Mehat0cde53c2009-12-22 08:32:33 -0800130 if (!name || !state) {
131 LOGW("Switch %s event missing name/state info", devpath);
132 return;
133 }
134
San Mehata2677e42009-12-13 10:40:18 -0800135 if (!strcmp(name, "usb_mass_storage")) {
136
137 if (!strcmp(state, "online")) {
138 notifyUmsConnected(true);
139 } else {
140 notifyUmsConnected(false);
141 }
142 } else {
143 LOGW("Ignoring unknown switch '%s'", name);
144 }
145}
146
San Mehatfd7f5872009-10-12 11:32:47 -0700147void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
148 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700149
San Mehatfd7f5872009-10-12 11:32:47 -0700150 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700151 VolumeCollection::iterator it;
152 bool hit = false;
153 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700154 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800155#ifdef NETLINK_DEBUG
156 LOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
157#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700158 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700159 break;
160 }
161 }
162
163 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800164#ifdef NETLINK_DEBUG
San Mehatfd7f5872009-10-12 11:32:47 -0700165 LOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800166#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700167 }
168}
169
San Mehatf1b736b2009-10-10 17:22:08 -0700170int VolumeManager::listVolumes(SocketClient *cli) {
171 VolumeCollection::iterator i;
172
173 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
174 char *buffer;
175 asprintf(&buffer, "%s %s %d",
176 (*i)->getLabel(), (*i)->getMountpoint(),
177 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800178 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700179 free(buffer);
180 }
San Mehata2677e42009-12-13 10:40:18 -0800181 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700182 return 0;
183}
San Mehat49e2bce2009-10-12 16:29:01 -0700184
San Mehata2677e42009-12-13 10:40:18 -0800185int VolumeManager::formatVolume(const char *label) {
186 Volume *v = lookupVolume(label);
187
188 if (!v) {
189 errno = ENOENT;
190 return -1;
191 }
192
193 return v->formatVol();
194}
195
San Mehata19b2502010-01-06 10:33:53 -0800196int VolumeManager::getAsecMountPath(const char *id, char *buffer, int maxlen) {
San Mehata19b2502010-01-06 10:33:53 -0800197
San Mehat3bb60202010-02-19 18:14:36 -0800198 snprintf(buffer, maxlen, "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800199 return 0;
200}
201
San Mehat8b8f71b2010-01-11 09:17:25 -0800202int VolumeManager::createAsec(const char *id, unsigned int numSectors,
San Mehata19b2502010-01-06 10:33:53 -0800203 const char *fstype, const char *key, int ownerUid) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800204 struct asec_superblock sb;
205 memset(&sb, 0, sizeof(sb));
206
207 sb.magic = ASEC_SB_MAGIC;
208 sb.ver = ASEC_SB_VER;
San Mehata19b2502010-01-06 10:33:53 -0800209
San Mehatd31e3802010-02-18 08:37:45 -0800210 if (numSectors < ((1024*1024)/512)) {
211 LOGE("Invalid container size specified (%d sectors)", numSectors);
212 errno = EINVAL;
213 return -1;
214 }
215
San Mehata19b2502010-01-06 10:33:53 -0800216 if (lookupVolume(id)) {
San Mehat3bb60202010-02-19 18:14:36 -0800217 LOGE("ASEC id '%s' currently exists", id);
San Mehata19b2502010-01-06 10:33:53 -0800218 errno = EADDRINUSE;
219 return -1;
220 }
221
222 char asecFileName[255];
San Mehat3bb60202010-02-19 18:14:36 -0800223 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800224
225 if (!access(asecFileName, F_OK)) {
226 LOGE("ASEC file '%s' currently exists - destroy it first! (%s)",
227 asecFileName, strerror(errno));
228 errno = EADDRINUSE;
229 return -1;
230 }
231
San Mehatfcf24fe2010-03-03 12:37:32 -0800232 /*
233 * Add some headroom
234 */
235 unsigned fatSize = (((numSectors * 4) / 512) + 1) * 2;
236 unsigned numImgSectors = numSectors + fatSize + 2;
237
238 if (numImgSectors % 63) {
239 numImgSectors += (63 - (numImgSectors % 63));
240 }
241
242 // Add +1 for our superblock which is at the end
243 if (Loop::createImageFile(asecFileName, numImgSectors + 1)) {
San Mehata19b2502010-01-06 10:33:53 -0800244 LOGE("ASEC image file creation failed (%s)", strerror(errno));
245 return -1;
246 }
247
San Mehatd9a4e352010-03-12 13:32:47 -0800248 char idHash[33];
249 if (!asecHash(id, idHash, sizeof(idHash))) {
250 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
251 unlink(asecFileName);
252 return -1;
253 }
254
San Mehata19b2502010-01-06 10:33:53 -0800255 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800256 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800257 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
258 unlink(asecFileName);
259 return -1;
260 }
261
San Mehatb78a32c2010-01-10 13:02:12 -0800262 char dmDevice[255];
263 bool cleanupDm = false;
San Mehata19b2502010-01-06 10:33:53 -0800264
San Mehatb78a32c2010-01-10 13:02:12 -0800265 if (strcmp(key, "none")) {
San Mehatfcf24fe2010-03-03 12:37:32 -0800266 // XXX: This is all we support for now
267 sb.c_cipher = ASEC_SB_C_CIPHER_TWOFISH;
San Mehatd9a4e352010-03-12 13:32:47 -0800268 if (Devmapper::create(idHash, loopDevice, key, numImgSectors, dmDevice,
San Mehatb78a32c2010-01-10 13:02:12 -0800269 sizeof(dmDevice))) {
270 LOGE("ASEC device mapping failed (%s)", strerror(errno));
271 Loop::destroyByDevice(loopDevice);
272 unlink(asecFileName);
273 return -1;
274 }
275 cleanupDm = true;
276 } else {
San Mehatfcf24fe2010-03-03 12:37:32 -0800277 sb.c_cipher = ASEC_SB_C_CIPHER_NONE;
San Mehatb78a32c2010-01-10 13:02:12 -0800278 strcpy(dmDevice, loopDevice);
279 }
280
San Mehatfcf24fe2010-03-03 12:37:32 -0800281 /*
282 * Drop down the superblock at the end of the file
283 */
284
285 int sbfd = open(loopDevice, O_RDWR);
286 if (sbfd < 0) {
287 LOGE("Failed to open new DM device for superblock write (%s)", strerror(errno));
288 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800289 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800290 }
291 Loop::destroyByDevice(loopDevice);
292 unlink(asecFileName);
293 return -1;
294 }
295
296 if (lseek(sbfd, (numImgSectors * 512), SEEK_SET) < 0) {
297 close(sbfd);
298 LOGE("Failed to lseek for superblock (%s)", strerror(errno));
299 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800300 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800301 }
302 Loop::destroyByDevice(loopDevice);
303 unlink(asecFileName);
304 return -1;
305 }
306
307 if (write(sbfd, &sb, sizeof(sb)) != sizeof(sb)) {
308 close(sbfd);
309 LOGE("Failed to write superblock (%s)", strerror(errno));
310 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800311 Devmapper::destroy(idHash);
San Mehatfcf24fe2010-03-03 12:37:32 -0800312 }
313 Loop::destroyByDevice(loopDevice);
314 unlink(asecFileName);
315 return -1;
316 }
317 close(sbfd);
318
San Mehata1091cb2010-02-28 20:17:20 -0800319 if (strcmp(fstype, "none")) {
320 if (strcmp(fstype, "fat")) {
321 LOGW("Unknown fstype '%s' specified for container", fstype);
San Mehatb78a32c2010-01-10 13:02:12 -0800322 }
San Mehata19b2502010-01-06 10:33:53 -0800323
San Mehatfcf24fe2010-03-03 12:37:32 -0800324 if (Fat::format(dmDevice, numImgSectors)) {
San Mehata1091cb2010-02-28 20:17:20 -0800325 LOGE("ASEC FAT format failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800326 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800327 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800328 }
San Mehateb13a902010-01-07 12:12:50 -0800329 Loop::destroyByDevice(loopDevice);
330 unlink(asecFileName);
331 return -1;
332 }
San Mehata1091cb2010-02-28 20:17:20 -0800333 char mountPoint[255];
San Mehata19b2502010-01-06 10:33:53 -0800334
San Mehata1091cb2010-02-28 20:17:20 -0800335 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
336 if (mkdir(mountPoint, 0777)) {
337 if (errno != EEXIST) {
338 LOGE("Mountpoint creation failed (%s)", strerror(errno));
339 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800340 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800341 }
342 Loop::destroyByDevice(loopDevice);
343 unlink(asecFileName);
344 return -1;
345 }
San Mehatb78a32c2010-01-10 13:02:12 -0800346 }
San Mehata1091cb2010-02-28 20:17:20 -0800347
348 if (Fat::doMount(dmDevice, mountPoint, false, false, ownerUid,
349 0, 0000, false)) {
350 LOGE("ASEC FAT mount failed (%s)", strerror(errno));
351 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800352 Devmapper::destroy(idHash);
San Mehata1091cb2010-02-28 20:17:20 -0800353 }
354 Loop::destroyByDevice(loopDevice);
355 unlink(asecFileName);
356 return -1;
357 }
358 } else {
359 LOGI("Created raw secure container %s (no filesystem)", id);
San Mehata19b2502010-01-06 10:33:53 -0800360 }
San Mehat88705162010-01-15 09:26:28 -0800361
362 mActiveContainers->push_back(strdup(id));
San Mehata19b2502010-01-06 10:33:53 -0800363 return 0;
364}
365
366int VolumeManager::finalizeAsec(const char *id) {
367 char asecFileName[255];
368 char loopDevice[255];
369 char mountPoint[255];
370
San Mehat3bb60202010-02-19 18:14:36 -0800371 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800372
San Mehatd9a4e352010-03-12 13:32:47 -0800373 char idHash[33];
374 if (!asecHash(id, idHash, sizeof(idHash))) {
375 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
376 return -1;
377 }
378
379 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800380 LOGE("Unable to finalize %s (%s)", id, strerror(errno));
381 return -1;
382 }
383
San Mehat3bb60202010-02-19 18:14:36 -0800384 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatfff0b472010-01-06 19:19:46 -0800385 // XXX:
386 if (Fat::doMount(loopDevice, mountPoint, true, true, 0, 0, 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800387 LOGE("ASEC finalize mount failed (%s)", strerror(errno));
388 return -1;
389 }
390
San Mehatd9a4e352010-03-12 13:32:47 -0800391 if (mDebug) {
392 LOGD("ASEC %s finalized", id);
393 }
San Mehata19b2502010-01-06 10:33:53 -0800394 return 0;
395}
396
San Mehat048b0802010-01-23 08:17:06 -0800397int VolumeManager::renameAsec(const char *id1, const char *id2) {
398 char *asecFilename1;
399 char *asecFilename2;
400 char mountPoint[255];
401
San Mehat3bb60202010-02-19 18:14:36 -0800402 asprintf(&asecFilename1, "%s/%s.asec", Volume::SEC_ASECDIR, id1);
403 asprintf(&asecFilename2, "%s/%s.asec", Volume::SEC_ASECDIR, id2);
San Mehat048b0802010-01-23 08:17:06 -0800404
San Mehat3bb60202010-02-19 18:14:36 -0800405 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id1);
San Mehat048b0802010-01-23 08:17:06 -0800406 if (isMountpointMounted(mountPoint)) {
407 LOGW("Rename attempt when src mounted");
408 errno = EBUSY;
409 goto out_err;
410 }
411
San Mehat96956ed2010-02-24 08:42:51 -0800412 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id2);
413 if (isMountpointMounted(mountPoint)) {
414 LOGW("Rename attempt when dst mounted");
415 errno = EBUSY;
416 goto out_err;
417 }
418
San Mehat048b0802010-01-23 08:17:06 -0800419 if (!access(asecFilename2, F_OK)) {
420 LOGE("Rename attempt when dst exists");
421 errno = EADDRINUSE;
422 goto out_err;
423 }
424
425 if (rename(asecFilename1, asecFilename2)) {
426 LOGE("Rename of '%s' to '%s' failed (%s)", asecFilename1, asecFilename2, strerror(errno));
427 goto out_err;
428 }
429
430 free(asecFilename1);
431 free(asecFilename2);
432 return 0;
433
434out_err:
435 free(asecFilename1);
436 free(asecFilename2);
437 return -1;
438}
439
San Mehat4ba89482010-02-18 09:00:18 -0800440#define ASEC_UNMOUNT_RETRIES 5
441int VolumeManager::unmountAsec(const char *id, bool force) {
San Mehata19b2502010-01-06 10:33:53 -0800442 char asecFileName[255];
443 char mountPoint[255];
444
San Mehat3bb60202010-02-19 18:14:36 -0800445 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
446 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800447
San Mehatd9a4e352010-03-12 13:32:47 -0800448 char idHash[33];
449 if (!asecHash(id, idHash, sizeof(idHash))) {
450 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
451 return -1;
452 }
453
San Mehat0586d542010-01-12 15:38:59 -0800454 if (!isMountpointMounted(mountPoint)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800455 LOGE("Unmount request for ASEC %s when not mounted", id);
456 errno = EINVAL;
457 return -1;
458 }
San Mehat23969932010-01-09 07:08:06 -0800459
San Mehatb78a32c2010-01-10 13:02:12 -0800460 int i, rc;
San Mehat8c940ef2010-02-13 14:19:53 -0800461 for (i = 1; i <= ASEC_UNMOUNT_RETRIES; i++) {
San Mehatb78a32c2010-01-10 13:02:12 -0800462 rc = umount(mountPoint);
463 if (!rc) {
464 break;
San Mehata19b2502010-01-06 10:33:53 -0800465 }
San Mehatb78a32c2010-01-10 13:02:12 -0800466 if (rc && (errno == EINVAL || errno == ENOENT)) {
San Mehat12f4b892010-02-24 11:43:22 -0800467 LOGI("Secure container %s unmounted OK", id);
San Mehatb78a32c2010-01-10 13:02:12 -0800468 rc = 0;
469 break;
San Mehata19b2502010-01-06 10:33:53 -0800470 }
San Mehatb78a32c2010-01-10 13:02:12 -0800471 LOGW("ASEC %s unmount attempt %d failed (%s)",
San Mehat8c940ef2010-02-13 14:19:53 -0800472 id, i, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800473
San Mehat4ba89482010-02-18 09:00:18 -0800474 int action = 0; // default is to just complain
475
476 if (force) {
477 if (i > (ASEC_UNMOUNT_RETRIES - 2))
478 action = 2; // SIGKILL
479 else if (i > (ASEC_UNMOUNT_RETRIES - 3))
480 action = 1; // SIGHUP
481 }
San Mehat8c940ef2010-02-13 14:19:53 -0800482
San Mehat586536c2010-02-16 17:12:00 -0800483 Process::killProcessesWithOpenFiles(mountPoint, action);
San Mehat8c940ef2010-02-13 14:19:53 -0800484 usleep(1000 * 1000);
San Mehatb78a32c2010-01-10 13:02:12 -0800485 }
486
487 if (rc) {
San Mehat4ba89482010-02-18 09:00:18 -0800488 errno = EBUSY;
489 LOGE("Failed to unmount container %s (%s)", id, strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800490 return -1;
491 }
492
San Mehat12f4b892010-02-24 11:43:22 -0800493 int retries = 10;
494
495 while(retries--) {
496 if (!rmdir(mountPoint)) {
497 break;
498 }
499
500 LOGW("Failed to rmdir %s (%s)", mountPoint, strerror(errno));
501 usleep(1000 * 1000);
502 }
503
504 if (!retries) {
505 LOGE("Timed out trying to rmdir %s (%s)", mountPoint, strerror(errno));
San Mehatf5c61982010-02-03 11:04:46 -0800506 }
San Mehat88705162010-01-15 09:26:28 -0800507
San Mehatd9a4e352010-03-12 13:32:47 -0800508 if (Devmapper::destroy(idHash) && errno != ENXIO) {
San Mehatb78a32c2010-01-10 13:02:12 -0800509 LOGE("Failed to destroy devmapper instance (%s)", strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800510 }
511
512 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800513 if (!Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800514 Loop::destroyByDevice(loopDevice);
San Mehatd9a4e352010-03-12 13:32:47 -0800515 } else {
516 LOGW("Failed to find loop device for {%s} (%s)", asecFileName, strerror(errno));
San Mehata19b2502010-01-06 10:33:53 -0800517 }
San Mehat88705162010-01-15 09:26:28 -0800518
519 AsecIdCollection::iterator it;
520 for (it = mActiveContainers->begin(); it != mActiveContainers->end(); ++it) {
521 if (!strcmp(*it, id)) {
522 free(*it);
523 mActiveContainers->erase(it);
524 break;
525 }
526 }
527 if (it == mActiveContainers->end()) {
528 LOGW("mActiveContainers is inconsistent!");
529 }
San Mehatb78a32c2010-01-10 13:02:12 -0800530 return 0;
531}
532
San Mehat4ba89482010-02-18 09:00:18 -0800533int VolumeManager::destroyAsec(const char *id, bool force) {
San Mehatb78a32c2010-01-10 13:02:12 -0800534 char asecFileName[255];
535 char mountPoint[255];
536
San Mehat3bb60202010-02-19 18:14:36 -0800537 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
San Mehat55013f72010-02-24 12:12:34 -0800538 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehatb78a32c2010-01-10 13:02:12 -0800539
San Mehat0586d542010-01-12 15:38:59 -0800540 if (isMountpointMounted(mountPoint)) {
San Mehatd9a4e352010-03-12 13:32:47 -0800541 if (mDebug) {
542 LOGD("Unmounting container before destroy");
543 }
San Mehat4ba89482010-02-18 09:00:18 -0800544 if (unmountAsec(id, force)) {
San Mehat0586d542010-01-12 15:38:59 -0800545 LOGE("Failed to unmount asec %s for destroy (%s)", id, strerror(errno));
546 return -1;
547 }
548 }
San Mehata19b2502010-01-06 10:33:53 -0800549
San Mehat0586d542010-01-12 15:38:59 -0800550 if (unlink(asecFileName)) {
San Mehat68f8ebd2010-01-23 07:21:21 -0800551 LOGE("Failed to unlink asec '%s' (%s)", asecFileName, strerror(errno));
San Mehat0586d542010-01-12 15:38:59 -0800552 return -1;
553 }
San Mehata19b2502010-01-06 10:33:53 -0800554
San Mehatd9a4e352010-03-12 13:32:47 -0800555 if (mDebug) {
556 LOGD("ASEC %s destroyed", id);
557 }
San Mehata19b2502010-01-06 10:33:53 -0800558 return 0;
559}
560
561int VolumeManager::mountAsec(const char *id, const char *key, int ownerUid) {
562 char asecFileName[255];
563 char mountPoint[255];
564
San Mehat3bb60202010-02-19 18:14:36 -0800565 snprintf(asecFileName, sizeof(asecFileName), "%s/%s.asec", Volume::SEC_ASECDIR, id);
566 snprintf(mountPoint, sizeof(mountPoint), "%s/%s", Volume::ASECDIR, id);
San Mehata19b2502010-01-06 10:33:53 -0800567
568 if (isMountpointMounted(mountPoint)) {
569 LOGE("ASEC %s already mounted", id);
570 errno = EBUSY;
571 return -1;
572 }
573
San Mehatd9a4e352010-03-12 13:32:47 -0800574 char idHash[33];
575 if (!asecHash(id, idHash, sizeof(idHash))) {
576 LOGE("Hash of '%s' failed (%s)", id, strerror(errno));
577 return -1;
578 }
San Mehata19b2502010-01-06 10:33:53 -0800579 char loopDevice[255];
San Mehatd9a4e352010-03-12 13:32:47 -0800580 if (Loop::lookupActive(idHash, loopDevice, sizeof(loopDevice))) {
581 if (Loop::create(idHash, asecFileName, loopDevice, sizeof(loopDevice))) {
San Mehata19b2502010-01-06 10:33:53 -0800582 LOGE("ASEC loop device creation failed (%s)", strerror(errno));
583 return -1;
584 }
San Mehatd9a4e352010-03-12 13:32:47 -0800585 if (mDebug) {
586 LOGD("New loop device created at %s", loopDevice);
587 }
San Mehatb78a32c2010-01-10 13:02:12 -0800588 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800589 if (mDebug) {
590 LOGD("Found active loopback for %s at %s", asecFileName, loopDevice);
591 }
San Mehatb78a32c2010-01-10 13:02:12 -0800592 }
593
594 char dmDevice[255];
595 bool cleanupDm = false;
San Mehatfcf24fe2010-03-03 12:37:32 -0800596 int fd;
597 unsigned int nr_sec = 0;
598
599 if ((fd = open(loopDevice, O_RDWR)) < 0) {
600 LOGE("Failed to open loopdevice (%s)", strerror(errno));
601 Loop::destroyByDevice(loopDevice);
602 return -1;
603 }
604
605 if (ioctl(fd, BLKGETSIZE, &nr_sec)) {
606 LOGE("Failed to get loop size (%s)", strerror(errno));
607 Loop::destroyByDevice(loopDevice);
608 close(fd);
609 return -1;
610 }
611
612 /*
613 * Validate superblock
614 */
615 struct asec_superblock sb;
616 memset(&sb, 0, sizeof(sb));
617 if (lseek(fd, ((nr_sec-1) * 512), SEEK_SET) < 0) {
618 LOGE("lseek failed (%s)", strerror(errno));
619 close(fd);
620 Loop::destroyByDevice(loopDevice);
621 return -1;
622 }
623 if (read(fd, &sb, sizeof(sb)) != sizeof(sb)) {
624 LOGE("superblock read failed (%s)", strerror(errno));
625 close(fd);
626 Loop::destroyByDevice(loopDevice);
627 return -1;
628 }
629
630 close(fd);
631
San Mehatd9a4e352010-03-12 13:32:47 -0800632 if (mDebug) {
633 LOGD("Container sb magic/ver (%.8x/%.2x)", sb.magic, sb.ver);
634 }
San Mehatfcf24fe2010-03-03 12:37:32 -0800635 if (sb.magic != ASEC_SB_MAGIC || sb.ver != ASEC_SB_VER) {
636 LOGE("Bad container magic/version (%.8x/%.2x)", sb.magic, sb.ver);
637 Loop::destroyByDevice(loopDevice);
638 errno = EMEDIUMTYPE;
639 return -1;
640 }
641 nr_sec--; // We don't want the devmapping to extend onto our superblock
642
San Mehatb78a32c2010-01-10 13:02:12 -0800643 if (strcmp(key, "none")) {
San Mehatd9a4e352010-03-12 13:32:47 -0800644 if (Devmapper::lookupActive(idHash, dmDevice, sizeof(dmDevice))) {
645 if (Devmapper::create(idHash, loopDevice, key, nr_sec,
San Mehatb78a32c2010-01-10 13:02:12 -0800646 dmDevice, sizeof(dmDevice))) {
647 LOGE("ASEC device mapping failed (%s)", strerror(errno));
648 Loop::destroyByDevice(loopDevice);
649 return -1;
650 }
San Mehatd9a4e352010-03-12 13:32:47 -0800651 if (mDebug) {
652 LOGD("New devmapper instance created at %s", dmDevice);
653 }
San Mehatb78a32c2010-01-10 13:02:12 -0800654 } else {
San Mehatd9a4e352010-03-12 13:32:47 -0800655 if (mDebug) {
656 LOGD("Found active devmapper for %s at %s", asecFileName, dmDevice);
657 }
San Mehatb78a32c2010-01-10 13:02:12 -0800658 }
659 cleanupDm = true;
660 } else {
661 strcpy(dmDevice, loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800662 }
663
664 if (mkdir(mountPoint, 0777)) {
San Mehatb78a32c2010-01-10 13:02:12 -0800665 if (errno != EEXIST) {
666 LOGE("Mountpoint creation failed (%s)", strerror(errno));
667 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800668 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800669 }
670 Loop::destroyByDevice(loopDevice);
671 return -1;
672 }
San Mehata19b2502010-01-06 10:33:53 -0800673 }
674
San Mehatb78a32c2010-01-10 13:02:12 -0800675 if (Fat::doMount(dmDevice, mountPoint, true, false, ownerUid, 0,
San Mehatcff5ec32010-01-08 12:31:44 -0800676 0222, false)) {
677// 0227, false)) {
San Mehata19b2502010-01-06 10:33:53 -0800678 LOGE("ASEC mount failed (%s)", strerror(errno));
San Mehatb78a32c2010-01-10 13:02:12 -0800679 if (cleanupDm) {
San Mehatd9a4e352010-03-12 13:32:47 -0800680 Devmapper::destroy(idHash);
San Mehatb78a32c2010-01-10 13:02:12 -0800681 }
682 Loop::destroyByDevice(loopDevice);
San Mehata19b2502010-01-06 10:33:53 -0800683 return -1;
684 }
685
San Mehat88705162010-01-15 09:26:28 -0800686 mActiveContainers->push_back(strdup(id));
San Mehatd9a4e352010-03-12 13:32:47 -0800687 if (mDebug) {
688 LOGD("ASEC %s mounted", id);
689 }
San Mehata19b2502010-01-06 10:33:53 -0800690 return 0;
691}
692
San Mehat49e2bce2009-10-12 16:29:01 -0700693int VolumeManager::mountVolume(const char *label) {
694 Volume *v = lookupVolume(label);
695
696 if (!v) {
697 errno = ENOENT;
698 return -1;
699 }
700
San Mehata2677e42009-12-13 10:40:18 -0800701 return v->mountVol();
702}
703
704int VolumeManager::shareAvailable(const char *method, bool *avail) {
705
706 if (strcmp(method, "ums")) {
707 errno = ENOSYS;
708 return -1;
709 }
710
711 if (mUsbMassStorageConnected)
712 *avail = true;
713 else
714 *avail = false;
715 return 0;
716}
717
San Mehateba65e92010-01-29 05:15:16 -0800718int VolumeManager::shareEnabled(const char *label, const char *method, bool *enabled) {
719 Volume *v = lookupVolume(label);
720
721 if (!v) {
722 errno = ENOENT;
723 return -1;
724 }
725
726 if (strcmp(method, "ums")) {
727 errno = ENOSYS;
728 return -1;
729 }
730
731 if (v->getState() != Volume::State_Shared) {
San Mehateba65e92010-01-29 05:15:16 -0800732 *enabled = false;
San Mehatb9aed742010-02-04 15:07:01 -0800733 } else {
734 *enabled = true;
San Mehateba65e92010-01-29 05:15:16 -0800735 }
736 return 0;
737}
738
San Mehata2677e42009-12-13 10:40:18 -0800739int VolumeManager::simulate(const char *cmd, const char *arg) {
740
741 if (!strcmp(cmd, "ums")) {
742 if (!strcmp(arg, "connect")) {
743 notifyUmsConnected(true);
744 } else if (!strcmp(arg, "disconnect")) {
745 notifyUmsConnected(false);
746 } else {
747 errno = EINVAL;
748 return -1;
749 }
750 } else {
751 errno = EINVAL;
752 return -1;
753 }
754 return 0;
755}
756
757int VolumeManager::shareVolume(const char *label, const char *method) {
758 Volume *v = lookupVolume(label);
759
760 if (!v) {
761 errno = ENOENT;
762 return -1;
763 }
764
765 /*
766 * Eventually, we'll want to support additional share back-ends,
767 * some of which may work while the media is mounted. For now,
768 * we just support UMS
769 */
770 if (strcmp(method, "ums")) {
771 errno = ENOSYS;
772 return -1;
773 }
774
775 if (v->getState() == Volume::State_NoMedia) {
776 errno = ENODEV;
777 return -1;
778 }
779
San Mehat49e2bce2009-10-12 16:29:01 -0700780 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800781 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700782 errno = EBUSY;
783 return -1;
784 }
785
San Mehata2677e42009-12-13 10:40:18 -0800786 dev_t d = v->getDiskDevice();
787 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
788 // This volume does not support raw disk access
789 errno = EINVAL;
790 return -1;
791 }
792
793 int fd;
794 char nodepath[255];
795 snprintf(nodepath,
796 sizeof(nodepath), "/dev/block/vold/%d:%d",
797 MAJOR(d), MINOR(d));
798
San Mehat0cde53c2009-12-22 08:32:33 -0800799 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
800 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800801 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
802 return -1;
803 }
804
805 if (write(fd, nodepath, strlen(nodepath)) < 0) {
806 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
807 close(fd);
808 return -1;
809 }
810
811 close(fd);
812 v->handleVolumeShared();
813 return 0;
814}
815
816int VolumeManager::unshareVolume(const char *label, const char *method) {
817 Volume *v = lookupVolume(label);
818
819 if (!v) {
820 errno = ENOENT;
821 return -1;
822 }
823
824 if (strcmp(method, "ums")) {
825 errno = ENOSYS;
826 return -1;
827 }
828
829 if (v->getState() != Volume::State_Shared) {
830 errno = EINVAL;
831 return -1;
832 }
833
834 dev_t d = v->getDiskDevice();
835
836 int fd;
837 char nodepath[255];
838 snprintf(nodepath,
839 sizeof(nodepath), "/dev/block/vold/%d:%d",
840 MAJOR(d), MINOR(d));
841
San Mehat0cde53c2009-12-22 08:32:33 -0800842 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800843 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
844 return -1;
845 }
846
847 char ch = 0;
848 if (write(fd, &ch, 1) < 0) {
849 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
850 close(fd);
851 return -1;
852 }
853
854 close(fd);
855 v->handleVolumeUnshared();
856 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700857}
858
San Mehat4ba89482010-02-18 09:00:18 -0800859int VolumeManager::unmountVolume(const char *label, bool force) {
San Mehat49e2bce2009-10-12 16:29:01 -0700860 Volume *v = lookupVolume(label);
861
862 if (!v) {
863 errno = ENOENT;
864 return -1;
865 }
866
San Mehata2677e42009-12-13 10:40:18 -0800867 if (v->getState() == Volume::State_NoMedia) {
868 errno = ENODEV;
869 return -1;
870 }
871
San Mehat49e2bce2009-10-12 16:29:01 -0700872 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800873 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
874 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700875 errno = EBUSY;
876 return -1;
877 }
878
San Mehat88705162010-01-15 09:26:28 -0800879 while(mActiveContainers->size()) {
880 AsecIdCollection::iterator it = mActiveContainers->begin();
881 LOGI("Unmounting ASEC %s (dependant on %s)", *it, v->getMountpoint());
San Mehat4ba89482010-02-18 09:00:18 -0800882 if (unmountAsec(*it, force)) {
San Mehat12f4b892010-02-24 11:43:22 -0800883 LOGE("Failed to unmount ASEC %s (%s)", *it, strerror(errno));
San Mehat0e382532010-02-24 08:25:55 -0800884 return -1;
San Mehat88705162010-01-15 09:26:28 -0800885 }
886 }
887
San Mehat4ba89482010-02-18 09:00:18 -0800888 return v->unmountVol(force);
San Mehat49e2bce2009-10-12 16:29:01 -0700889}
890
San Mehata2677e42009-12-13 10:40:18 -0800891/*
892 * Looks up a volume by it's label or mount-point
893 */
San Mehat49e2bce2009-10-12 16:29:01 -0700894Volume *VolumeManager::lookupVolume(const char *label) {
895 VolumeCollection::iterator i;
896
897 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800898 if (label[0] == '/') {
899 if (!strcmp(label, (*i)->getMountpoint()))
900 return (*i);
901 } else {
902 if (!strcmp(label, (*i)->getLabel()))
903 return (*i);
904 }
San Mehat49e2bce2009-10-12 16:29:01 -0700905 }
906 return NULL;
907}
San Mehata19b2502010-01-06 10:33:53 -0800908
909bool VolumeManager::isMountpointMounted(const char *mp)
910{
911 char device[256];
912 char mount_path[256];
913 char rest[256];
914 FILE *fp;
915 char line[1024];
916
917 if (!(fp = fopen("/proc/mounts", "r"))) {
918 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
919 return false;
920 }
921
922 while(fgets(line, sizeof(line), fp)) {
923 line[strlen(line)-1] = '\0';
924 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
925 if (!strcmp(mount_path, mp)) {
926 fclose(fp);
927 return true;
928 }
929
930 }
931
932 fclose(fp);
933 return false;
934}
935