blob: 4a24ff78103552581e2684fba4a0713c2c4fb5d5 [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>
22#include <linux/kdev_t.h>
San Mehatf1b736b2009-10-10 17:22:08 -070023
24#define LOG_TAG "Vold"
25
26#include <cutils/log.h>
27
San Mehatfd7f5872009-10-12 11:32:47 -070028#include <sysutils/NetlinkEvent.h>
29
San Mehatf1b736b2009-10-10 17:22:08 -070030#include "VolumeManager.h"
San Mehatae10b912009-10-12 14:57:05 -070031#include "DirectVolume.h"
San Mehata2677e42009-12-13 10:40:18 -080032#include "ResponseCode.h"
San Mehatf1b736b2009-10-10 17:22:08 -070033
34VolumeManager *VolumeManager::sInstance = NULL;
35
36VolumeManager *VolumeManager::Instance() {
37 if (!sInstance)
38 sInstance = new VolumeManager();
39 return sInstance;
40}
41
42VolumeManager::VolumeManager() {
43 mBlockDevices = new BlockDeviceCollection();
44 mVolumes = new VolumeCollection();
45 mBroadcaster = NULL;
San Mehata2677e42009-12-13 10:40:18 -080046 mUsbMassStorageConnected = false;
San Mehatf1b736b2009-10-10 17:22:08 -070047}
48
49VolumeManager::~VolumeManager() {
50 delete mBlockDevices;
51}
52
53int VolumeManager::start() {
54 return 0;
55}
56
57int VolumeManager::stop() {
58 return 0;
59}
60
61int VolumeManager::addVolume(Volume *v) {
62 mVolumes->push_back(v);
63 return 0;
64}
65
San Mehata2677e42009-12-13 10:40:18 -080066void VolumeManager::notifyUmsConnected(bool connected) {
67 char msg[255];
68
69 if (connected) {
70 mUsbMassStorageConnected = true;
71 } else {
72 mUsbMassStorageConnected = false;
73 }
74 snprintf(msg, sizeof(msg), "Share method ums now %s",
75 (connected ? "available" : "unavailable"));
76
77 getBroadcaster()->sendBroadcast(ResponseCode::ShareAvailabilityChange,
78 msg, false);
79}
80
81void VolumeManager::handleSwitchEvent(NetlinkEvent *evt) {
82 const char *name = evt->findParam("SWITCH_NAME");
83 const char *state = evt->findParam("SWITCH_STATE");
84
85 if (!strcmp(name, "usb_mass_storage")) {
86
87 if (!strcmp(state, "online")) {
88 notifyUmsConnected(true);
89 } else {
90 notifyUmsConnected(false);
91 }
92 } else {
93 LOGW("Ignoring unknown switch '%s'", name);
94 }
95}
96
San Mehatfd7f5872009-10-12 11:32:47 -070097void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
98 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -070099
San Mehatfd7f5872009-10-12 11:32:47 -0700100 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700101 VolumeCollection::iterator it;
102 bool hit = false;
103 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700104 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800105#ifdef NETLINK_DEBUG
106 LOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
107#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700108 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700109 break;
110 }
111 }
112
113 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800114#ifdef NETLINK_DEBUG
San Mehatfd7f5872009-10-12 11:32:47 -0700115 LOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800116#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700117 }
118}
119
San Mehatf1b736b2009-10-10 17:22:08 -0700120int VolumeManager::listVolumes(SocketClient *cli) {
121 VolumeCollection::iterator i;
122
123 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
124 char *buffer;
125 asprintf(&buffer, "%s %s %d",
126 (*i)->getLabel(), (*i)->getMountpoint(),
127 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800128 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700129 free(buffer);
130 }
San Mehata2677e42009-12-13 10:40:18 -0800131 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700132 return 0;
133}
San Mehat49e2bce2009-10-12 16:29:01 -0700134
San Mehata2677e42009-12-13 10:40:18 -0800135int VolumeManager::formatVolume(const char *label) {
136 Volume *v = lookupVolume(label);
137
138 if (!v) {
139 errno = ENOENT;
140 return -1;
141 }
142
143 return v->formatVol();
144}
145
San Mehat49e2bce2009-10-12 16:29:01 -0700146int VolumeManager::mountVolume(const char *label) {
147 Volume *v = lookupVolume(label);
148
149 if (!v) {
150 errno = ENOENT;
151 return -1;
152 }
153
San Mehata2677e42009-12-13 10:40:18 -0800154 return v->mountVol();
155}
156
157int VolumeManager::shareAvailable(const char *method, bool *avail) {
158
159 if (strcmp(method, "ums")) {
160 errno = ENOSYS;
161 return -1;
162 }
163
164 if (mUsbMassStorageConnected)
165 *avail = true;
166 else
167 *avail = false;
168 return 0;
169}
170
171int VolumeManager::simulate(const char *cmd, const char *arg) {
172
173 if (!strcmp(cmd, "ums")) {
174 if (!strcmp(arg, "connect")) {
175 notifyUmsConnected(true);
176 } else if (!strcmp(arg, "disconnect")) {
177 notifyUmsConnected(false);
178 } else {
179 errno = EINVAL;
180 return -1;
181 }
182 } else {
183 errno = EINVAL;
184 return -1;
185 }
186 return 0;
187}
188
189int VolumeManager::shareVolume(const char *label, const char *method) {
190 Volume *v = lookupVolume(label);
191
192 if (!v) {
193 errno = ENOENT;
194 return -1;
195 }
196
197 /*
198 * Eventually, we'll want to support additional share back-ends,
199 * some of which may work while the media is mounted. For now,
200 * we just support UMS
201 */
202 if (strcmp(method, "ums")) {
203 errno = ENOSYS;
204 return -1;
205 }
206
207 if (v->getState() == Volume::State_NoMedia) {
208 errno = ENODEV;
209 return -1;
210 }
211
San Mehat49e2bce2009-10-12 16:29:01 -0700212 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800213 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700214 errno = EBUSY;
215 return -1;
216 }
217
San Mehata2677e42009-12-13 10:40:18 -0800218 dev_t d = v->getDiskDevice();
219 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
220 // This volume does not support raw disk access
221 errno = EINVAL;
222 return -1;
223 }
224
225 int fd;
226 char nodepath[255];
227 snprintf(nodepath,
228 sizeof(nodepath), "/dev/block/vold/%d:%d",
229 MAJOR(d), MINOR(d));
230
231 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0", O_WRONLY)) < 0) {
232 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
233 return -1;
234 }
235
236 if (write(fd, nodepath, strlen(nodepath)) < 0) {
237 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
238 close(fd);
239 return -1;
240 }
241
242 close(fd);
243 v->handleVolumeShared();
244 return 0;
245}
246
247int VolumeManager::unshareVolume(const char *label, const char *method) {
248 Volume *v = lookupVolume(label);
249
250 if (!v) {
251 errno = ENOENT;
252 return -1;
253 }
254
255 if (strcmp(method, "ums")) {
256 errno = ENOSYS;
257 return -1;
258 }
259
260 if (v->getState() != Volume::State_Shared) {
261 errno = EINVAL;
262 return -1;
263 }
264
265 dev_t d = v->getDiskDevice();
266
267 int fd;
268 char nodepath[255];
269 snprintf(nodepath,
270 sizeof(nodepath), "/dev/block/vold/%d:%d",
271 MAJOR(d), MINOR(d));
272
273 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0", O_WRONLY)) < 0) {
274 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
275 return -1;
276 }
277
278 char ch = 0;
279 if (write(fd, &ch, 1) < 0) {
280 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
281 close(fd);
282 return -1;
283 }
284
285 close(fd);
286 v->handleVolumeUnshared();
287 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700288}
289
290int VolumeManager::unmountVolume(const char *label) {
291 Volume *v = lookupVolume(label);
292
293 if (!v) {
294 errno = ENOENT;
295 return -1;
296 }
297
San Mehata2677e42009-12-13 10:40:18 -0800298 if (v->getState() == Volume::State_NoMedia) {
299 errno = ENODEV;
300 return -1;
301 }
302
San Mehat49e2bce2009-10-12 16:29:01 -0700303 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800304 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
305 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700306 errno = EBUSY;
307 return -1;
308 }
309
San Mehata2677e42009-12-13 10:40:18 -0800310 return v->unmountVol();
San Mehat49e2bce2009-10-12 16:29:01 -0700311}
312
San Mehata2677e42009-12-13 10:40:18 -0800313/*
314 * Looks up a volume by it's label or mount-point
315 */
San Mehat49e2bce2009-10-12 16:29:01 -0700316Volume *VolumeManager::lookupVolume(const char *label) {
317 VolumeCollection::iterator i;
318
319 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800320 if (label[0] == '/') {
321 if (!strcmp(label, (*i)->getMountpoint()))
322 return (*i);
323 } else {
324 if (!strcmp(label, (*i)->getLabel()))
325 return (*i);
326 }
San Mehat49e2bce2009-10-12 16:29:01 -0700327 }
328 return NULL;
329}