blob: 64459bd88360641304027517bf64d42e5e6df252 [file] [log] [blame]
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -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/*
18** mountd server support
19*/
20
21#include "mountd.h"
The Android Open Source Project35237d12008-12-17 18:08:08 -080022#include "ASEC.h"
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070023
24#include <cutils/properties.h>
25#include <cutils/sockets.h>
26
27#include <pthread.h>
28#include <errno.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <unistd.h>
32#include <string.h>
33#include <sys/socket.h>
34
35#include <private/android_filesystem_config.h>
36
37
38// current client file descriptor
39static int sFD = -1;
40
41// to synchronize writing to client
42static pthread_mutex_t sWriteMutex = PTHREAD_MUTEX_INITIALIZER;
43
44// path for media that failed to mount before the runtime is connected
45static char* sDeferredUnmountableMediaPath = NULL;
46
The Android Open Source Project35237d12008-12-17 18:08:08 -080047// last asec msg before the runtime was connected
48static char* sAsecDeferredMessage = NULL;
49static char* sAsecDeferredArgument = NULL;
50
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -070051static int Write(const char* message)
52{
53 int result = -1;
54
55 pthread_mutex_lock(&sWriteMutex);
56
57 LOG_SERVER("Write: %s\n", message);
58 if (sFD >= 0)
59 result = write(sFD, message, strlen(message) + 1);
60
61 pthread_mutex_unlock(&sWriteMutex);
62
63 return result;
64}
65
66static int Write2(const char* message, const char* data)
67{
68 int result = -1;
69
70 char* buffer = (char *)alloca(strlen(message) + strlen(data) + 1);
71 if (!buffer)
72 {
73 LOG_ERROR("alloca failed in Write2\n");
74 return -1;
75 }
76
77 strcpy(buffer, message);
78 strcat(buffer, data);
79 return Write(buffer);
80}
81
82static void SendStatus()
83{
84 Write(IsMassStorageConnected() ? MOUNTD_UMS_CONNECTED : MOUNTD_UMS_DISCONNECTED);
85 Write(IsMassStorageEnabled() ? MOUNTD_UMS_ENABLED : MOUNTD_UMS_DISABLED);
86}
87
88static void DoCommand(const char* command)
89{
90 LOG_SERVER("DoCommand %s\n", command);
91
92 if (strcmp(command, MOUNTD_ENABLE_UMS) == 0)
93 {
94 EnableMassStorage(true);
95 Write(MOUNTD_UMS_ENABLED);
96 }
97 else if (strcmp(command, MOUNTD_DISABLE_UMS) == 0)
98 {
99 EnableMassStorage(false);
100 Write(MOUNTD_UMS_DISABLED);
101 }
102 else if (strcmp(command, MOUNTD_SEND_STATUS) == 0)
103 {
104 SendStatus();
105 }
106 else if (strncmp(command, MOUNTD_MOUNT_MEDIA, strlen(MOUNTD_MOUNT_MEDIA)) == 0)
107 {
108 const char* path = command + strlen(MOUNTD_MOUNT_MEDIA);
109 MountMedia(path);
110 }
111 else if (strncmp(command, MOUNTD_EJECT_MEDIA, strlen(MOUNTD_EJECT_MEDIA)) == 0)
112 {
113 const char* path = command + strlen(MOUNTD_EJECT_MEDIA);
114 UnmountMedia(path);
The Android Open Source Project35237d12008-12-17 18:08:08 -0800115 }
116 else if (strncmp(command, ASEC_CMD_ENABLE, strlen(ASEC_CMD_ENABLE)) == 0) {
117 LOG_ASEC("Got ASEC_CMD_ENABLE\n");
118 // XXX: SAN: Impliment
119 }
120 else if (strncmp(command, ASEC_CMD_DISABLE, strlen(ASEC_CMD_DISABLE)) == 0) {
121 LOG_ASEC("Got ASEC_CMD_DISABLE\n");
122 // XXX: SAN: Impliment
123 }
124 else if (strncmp(command, ASEC_CMD_SEND_STATUS, strlen(ASEC_CMD_SEND_STATUS)) == 0) {
125 LOG_ASEC("Got ASEC_CMD_SEND_STATUS\n");
126 // XXX: SAN: Impliment
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700127 }
128 else
129 LOGE("unknown command %s\n", command);
130}
131
132int RunServer()
133{
134 int socket = android_get_control_socket(MOUNTD_SOCKET);
135 if (socket < 0) {
136 LOGE("Obtaining file descriptor for socket '%s' failed: %s",
137 MOUNTD_SOCKET, strerror(errno));
138 return -1;
139 }
140
141 if (listen(socket, 4) < 0) {
142 LOGE("Unable to listen on file descriptor '%d' for socket '%s': %s",
143 socket, MOUNTD_SOCKET, strerror(errno));
144 return -1;
145 }
146
147 while (1)
148 {
149 struct sockaddr addr;
150 socklen_t alen;
151 struct ucred cred;
152 socklen_t size;
153
154 alen = sizeof(addr);
155 sFD = accept(socket, &addr, &alen);
156 if (sFD < 0)
157 continue;
158
159 if (sDeferredUnmountableMediaPath) {
160 NotifyMediaState(sDeferredUnmountableMediaPath, MEDIA_UNMOUNTABLE, false);
161 free(sDeferredUnmountableMediaPath);
162 sDeferredUnmountableMediaPath = NULL;
163 }
164
The Android Open Source Project35237d12008-12-17 18:08:08 -0800165 if (sAsecDeferredMessage) {
166
167 if (Write2(sAsecDeferredMessage, sAsecDeferredArgument) < 0)
168 LOG_ERROR("Failed to deliver deferred ASEC msg to framework\n");
169 free(sAsecDeferredMessage);
170 free(sAsecDeferredArgument);
171 sAsecDeferredMessage = sAsecDeferredArgument = NULL;
172 }
173
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700174 while (1)
175 {
176 char buffer[101];
177 int result = read(sFD, buffer, sizeof(buffer) - 1);
178 if (result > 0)
179 {
180 int start = 0;
181 int i;
182 // command should be zero terminated, but just in case
183 buffer[result] = 0;
184 for (i = 0; i < result; i++)
185 {
186 if (buffer[i] == 0)
187 {
188 DoCommand(buffer + start);
189 start = i + 1;
190 }
191 }
192 }
193 else
194 {
195 close(sFD);
196 sFD = -1;
197 break;
198 }
199 }
200 }
201
202 // should never get here
203 return 0;
204}
205
206void SendMassStorageConnected(boolean connected)
207{
208 Write(connected ? MOUNTD_UMS_CONNECTED : MOUNTD_UMS_DISCONNECTED);
209}
210
211void SendUnmountRequest(const char* path)
212{
213 Write2(MOUNTD_REQUEST_EJECT, path);
214}
215
The Android Open Source Project35237d12008-12-17 18:08:08 -0800216void NotifyAsecState(AsecState state, const char *argument)
217{
218 const char *event = NULL;
219 const char *status = NULL;
220 boolean deferr = true;;
221
222 switch (state) {
223 case ASEC_DISABLED:
224 event = ASEC_EVENT_DISABLED;
225 status = ASEC_STATUS_DISABLED;
226 break;
227 case ASEC_AVAILABLE:
228 event = ASEC_EVENT_AVAILABLE;
229 status = ASEC_STATUS_AVAILABLE;
230 break;
231 case ASEC_BUSY:
232 event = ASEC_EVENT_BUSY;
233 status = ASEC_STATUS_BUSY;
234 deferr = false;
235 break;
236 case ASEC_FAILED_INTERR:
237 event = ASEC_EVENT_FAILED_INTERR;
238 status = ASEC_STATUS_FAILED_INTERR;
239 break;
240 case ASEC_FAILED_NOMEDIA:
241 event = ASEC_EVENT_FAILED_NOMEDIA;
242 status = ASEC_STATUS_FAILED_NOMEDIA;
243 break;
244 case ASEC_FAILED_BADMEDIA:
245 event = ASEC_EVENT_FAILED_BADMEDIA;
246 status = ASEC_STATUS_FAILED_BADMEDIA;
247 break;
248 case ASEC_FAILED_BADKEY:
249 event = ASEC_EVENT_FAILED_BADKEY;
250 status = ASEC_STATUS_FAILED_BADKEY;
251 break;
252 default:
253 LOG_ERROR("unknown AsecState %d in NotifyAsecState\n", state);
254 return;
255 }
256
257 property_set(ASEC_STATUS, status);
258
259 int result = Write2(event, argument);
260 if ((result < 0) && deferr) {
261 if (sAsecDeferredMessage)
262 free(sAsecDeferredMessage);
263 sAsecDeferredMessage = strdup(event);
264 if (sAsecDeferredArgument)
265 free(sAsecDeferredArgument);
266 sAsecDeferredArgument = strdup(argument);
267 LOG_ASEC("Deferring event '%s' arg '%s' until framework connects\n", event, argument);
268 }
269}
270
The Android Open Source Project4f6e8d72008-10-21 07:00:00 -0700271void NotifyMediaState(const char* path, MediaState state, boolean readOnly)
272{
273 const char* event = NULL;
274 const char* propertyValue = NULL;
275
276 switch (state) {
277 case MEDIA_REMOVED:
278 event = MOUNTD_MEDIA_REMOVED;
279 propertyValue = EXTERNAL_STORAGE_REMOVED;
280 break;
281 case MEDIA_UNMOUNTED:
282 event = MOUNTD_MEDIA_UNMOUNTED;
283 propertyValue = EXTERNAL_STORAGE_UNMOUNTED;
284 break;
285 case MEDIA_MOUNTED:
286 event = (readOnly ? MOUNTD_MEDIA_MOUNTED_READ_ONLY : MOUNTD_MEDIA_MOUNTED);
287 propertyValue = (readOnly ? EXTERNAL_STORAGE_MOUNTED_READ_ONLY : EXTERNAL_STORAGE_MOUNTED);
288 break;
289 case MEDIA_SHARED:
290 event = MOUNTD_MEDIA_SHARED;
291 propertyValue = EXTERNAL_STORAGE_SHARED;
292 break;
293 case MEDIA_BAD_REMOVAL:
294 event = MOUNTD_MEDIA_BAD_REMOVAL;
295 propertyValue = EXTERNAL_STORAGE_BAD_REMOVAL;
296 break;
297 case MEDIA_UNMOUNTABLE:
298 event = MOUNTD_MEDIA_UNMOUNTABLE;
299 propertyValue = EXTERNAL_STORAGE_UNMOUNTABLE;
300 break;
301 default:
302 LOG_ERROR("unknown MediaState %d in NotifyMediaState\n", state);
303 return;
304 }
305
306 property_set(EXTERNAL_STORAGE_STATE, propertyValue);
307 int result = Write2(event, path);
308 if (result < 0 && state == MEDIA_UNMOUNTABLE) {
309
310 // if we cannot communicate with the runtime, defer this message until the runtime is available
311 sDeferredUnmountableMediaPath = strdup(path);
312 }
313}