blob: 462029c4f01d01211dcf33d49438828701572c14 [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) {
San Mehat0cde53c2009-12-22 08:32:33 -080082 const char *devpath = evt->findParam("DEVPATH");
San Mehata2677e42009-12-13 10:40:18 -080083 const char *name = evt->findParam("SWITCH_NAME");
84 const char *state = evt->findParam("SWITCH_STATE");
85
San Mehat0cde53c2009-12-22 08:32:33 -080086 if (!name || !state) {
87 LOGW("Switch %s event missing name/state info", devpath);
88 return;
89 }
90
San Mehata2677e42009-12-13 10:40:18 -080091 if (!strcmp(name, "usb_mass_storage")) {
92
93 if (!strcmp(state, "online")) {
94 notifyUmsConnected(true);
95 } else {
96 notifyUmsConnected(false);
97 }
98 } else {
99 LOGW("Ignoring unknown switch '%s'", name);
100 }
101}
102
San Mehatfd7f5872009-10-12 11:32:47 -0700103void VolumeManager::handleBlockEvent(NetlinkEvent *evt) {
104 const char *devpath = evt->findParam("DEVPATH");
San Mehatf1b736b2009-10-10 17:22:08 -0700105
San Mehatfd7f5872009-10-12 11:32:47 -0700106 /* Lookup a volume to handle this device */
San Mehatf1b736b2009-10-10 17:22:08 -0700107 VolumeCollection::iterator it;
108 bool hit = false;
109 for (it = mVolumes->begin(); it != mVolumes->end(); ++it) {
San Mehatfd7f5872009-10-12 11:32:47 -0700110 if (!(*it)->handleBlockEvent(evt)) {
San Mehata2677e42009-12-13 10:40:18 -0800111#ifdef NETLINK_DEBUG
112 LOGD("Device '%s' event handled by volume %s\n", devpath, (*it)->getLabel());
113#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700114 hit = true;
San Mehatf1b736b2009-10-10 17:22:08 -0700115 break;
116 }
117 }
118
119 if (!hit) {
San Mehata2677e42009-12-13 10:40:18 -0800120#ifdef NETLINK_DEBUG
San Mehatfd7f5872009-10-12 11:32:47 -0700121 LOGW("No volumes handled block event for '%s'", devpath);
San Mehata2677e42009-12-13 10:40:18 -0800122#endif
San Mehatf1b736b2009-10-10 17:22:08 -0700123 }
124}
125
San Mehatf1b736b2009-10-10 17:22:08 -0700126int VolumeManager::listVolumes(SocketClient *cli) {
127 VolumeCollection::iterator i;
128
129 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
130 char *buffer;
131 asprintf(&buffer, "%s %s %d",
132 (*i)->getLabel(), (*i)->getMountpoint(),
133 (*i)->getState());
San Mehata2677e42009-12-13 10:40:18 -0800134 cli->sendMsg(ResponseCode::VolumeListResult, buffer, false);
San Mehatf1b736b2009-10-10 17:22:08 -0700135 free(buffer);
136 }
San Mehata2677e42009-12-13 10:40:18 -0800137 cli->sendMsg(ResponseCode::CommandOkay, "Volumes listed.", false);
San Mehatf1b736b2009-10-10 17:22:08 -0700138 return 0;
139}
San Mehat49e2bce2009-10-12 16:29:01 -0700140
San Mehata2677e42009-12-13 10:40:18 -0800141int VolumeManager::formatVolume(const char *label) {
142 Volume *v = lookupVolume(label);
143
144 if (!v) {
145 errno = ENOENT;
146 return -1;
147 }
148
149 return v->formatVol();
150}
151
San Mehat49e2bce2009-10-12 16:29:01 -0700152int VolumeManager::mountVolume(const char *label) {
153 Volume *v = lookupVolume(label);
154
155 if (!v) {
156 errno = ENOENT;
157 return -1;
158 }
159
San Mehata2677e42009-12-13 10:40:18 -0800160 return v->mountVol();
161}
162
163int VolumeManager::shareAvailable(const char *method, bool *avail) {
164
165 if (strcmp(method, "ums")) {
166 errno = ENOSYS;
167 return -1;
168 }
169
170 if (mUsbMassStorageConnected)
171 *avail = true;
172 else
173 *avail = false;
174 return 0;
175}
176
177int VolumeManager::simulate(const char *cmd, const char *arg) {
178
179 if (!strcmp(cmd, "ums")) {
180 if (!strcmp(arg, "connect")) {
181 notifyUmsConnected(true);
182 } else if (!strcmp(arg, "disconnect")) {
183 notifyUmsConnected(false);
184 } else {
185 errno = EINVAL;
186 return -1;
187 }
188 } else {
189 errno = EINVAL;
190 return -1;
191 }
192 return 0;
193}
194
195int VolumeManager::shareVolume(const char *label, const char *method) {
196 Volume *v = lookupVolume(label);
197
198 if (!v) {
199 errno = ENOENT;
200 return -1;
201 }
202
203 /*
204 * Eventually, we'll want to support additional share back-ends,
205 * some of which may work while the media is mounted. For now,
206 * we just support UMS
207 */
208 if (strcmp(method, "ums")) {
209 errno = ENOSYS;
210 return -1;
211 }
212
213 if (v->getState() == Volume::State_NoMedia) {
214 errno = ENODEV;
215 return -1;
216 }
217
San Mehat49e2bce2009-10-12 16:29:01 -0700218 if (v->getState() != Volume::State_Idle) {
San Mehata2677e42009-12-13 10:40:18 -0800219 // You need to unmount manually befoe sharing
San Mehat49e2bce2009-10-12 16:29:01 -0700220 errno = EBUSY;
221 return -1;
222 }
223
San Mehata2677e42009-12-13 10:40:18 -0800224 dev_t d = v->getDiskDevice();
225 if ((MAJOR(d) == 0) && (MINOR(d) == 0)) {
226 // This volume does not support raw disk access
227 errno = EINVAL;
228 return -1;
229 }
230
231 int fd;
232 char nodepath[255];
233 snprintf(nodepath,
234 sizeof(nodepath), "/dev/block/vold/%d:%d",
235 MAJOR(d), MINOR(d));
236
San Mehat0cde53c2009-12-22 08:32:33 -0800237 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file",
238 O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800239 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
240 return -1;
241 }
242
243 if (write(fd, nodepath, strlen(nodepath)) < 0) {
244 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
245 close(fd);
246 return -1;
247 }
248
249 close(fd);
250 v->handleVolumeShared();
251 return 0;
252}
253
254int VolumeManager::unshareVolume(const char *label, const char *method) {
255 Volume *v = lookupVolume(label);
256
257 if (!v) {
258 errno = ENOENT;
259 return -1;
260 }
261
262 if (strcmp(method, "ums")) {
263 errno = ENOSYS;
264 return -1;
265 }
266
267 if (v->getState() != Volume::State_Shared) {
268 errno = EINVAL;
269 return -1;
270 }
271
272 dev_t d = v->getDiskDevice();
273
274 int fd;
275 char nodepath[255];
276 snprintf(nodepath,
277 sizeof(nodepath), "/dev/block/vold/%d:%d",
278 MAJOR(d), MINOR(d));
279
San Mehat0cde53c2009-12-22 08:32:33 -0800280 if ((fd = open("/sys/devices/platform/usb_mass_storage/lun0/file", O_WRONLY)) < 0) {
San Mehata2677e42009-12-13 10:40:18 -0800281 LOGE("Unable to open ums lunfile (%s)", strerror(errno));
282 return -1;
283 }
284
285 char ch = 0;
286 if (write(fd, &ch, 1) < 0) {
287 LOGE("Unable to write to ums lunfile (%s)", strerror(errno));
288 close(fd);
289 return -1;
290 }
291
292 close(fd);
293 v->handleVolumeUnshared();
294 return 0;
San Mehat49e2bce2009-10-12 16:29:01 -0700295}
296
297int VolumeManager::unmountVolume(const char *label) {
298 Volume *v = lookupVolume(label);
299
300 if (!v) {
301 errno = ENOENT;
302 return -1;
303 }
304
San Mehata2677e42009-12-13 10:40:18 -0800305 if (v->getState() == Volume::State_NoMedia) {
306 errno = ENODEV;
307 return -1;
308 }
309
San Mehat49e2bce2009-10-12 16:29:01 -0700310 if (v->getState() != Volume::State_Mounted) {
San Mehata2677e42009-12-13 10:40:18 -0800311 LOGW("Attempt to unmount volume which isn't mounted (%d)\n",
312 v->getState());
San Mehat49e2bce2009-10-12 16:29:01 -0700313 errno = EBUSY;
314 return -1;
315 }
316
San Mehata2677e42009-12-13 10:40:18 -0800317 return v->unmountVol();
San Mehat49e2bce2009-10-12 16:29:01 -0700318}
319
San Mehata2677e42009-12-13 10:40:18 -0800320/*
321 * Looks up a volume by it's label or mount-point
322 */
San Mehat49e2bce2009-10-12 16:29:01 -0700323Volume *VolumeManager::lookupVolume(const char *label) {
324 VolumeCollection::iterator i;
325
326 for (i = mVolumes->begin(); i != mVolumes->end(); ++i) {
San Mehata2677e42009-12-13 10:40:18 -0800327 if (label[0] == '/') {
328 if (!strcmp(label, (*i)->getMountpoint()))
329 return (*i);
330 } else {
331 if (!strcmp(label, (*i)->getLabel()))
332 return (*i);
333 }
San Mehat49e2bce2009-10-12 16:29:01 -0700334 }
335 return NULL;
336}