CommandListener.cpp revision b9aed74b146beb7499ebc5775e8ae179d16900ef
1/*
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 <stdlib.h>
18#include <sys/socket.h>
19#include <sys/types.h>
20#include <netinet/in.h>
21#include <arpa/inet.h>
22#include <dirent.h>
23#include <errno.h>
24
25#define LOG_TAG "CommandListener"
26#include <cutils/log.h>
27
28#include <sysutils/SocketClient.h>
29
30#include "CommandListener.h"
31#include "VolumeManager.h"
32#include "ResponseCode.h"
33
34CommandListener::CommandListener() :
35                 FrameworkListener("vold") {
36    registerCmd(new VolumeCmd());
37    registerCmd(new AsecCmd());
38    registerCmd(new ShareCmd());
39}
40
41CommandListener::VolumeCmd::VolumeCmd() :
42                 VoldCommand("volume") {
43}
44
45int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
46                                                      int argc, char **argv) {
47    if (argc < 2) {
48        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
49        return 0;
50    }
51
52    VolumeManager *vm = VolumeManager::Instance();
53    int rc = 0;
54
55    if (!strcmp(argv[1], "list")) {
56        return vm->listVolumes(cli);
57    } else if (!strcmp(argv[1], "mount")) {
58        rc = vm->mountVolume(argv[2]);
59    } else if (!strcmp(argv[1], "unmount")) {
60        rc = vm->unmountVolume(argv[2]);
61    } else if (!strcmp(argv[1], "format")) {
62        rc = vm->formatVolume(argv[2]);
63    } else if (!strcmp(argv[1], "share")) {
64        rc = vm->shareVolume(argv[2], argv[3]);
65    } else if (!strcmp(argv[1], "unshare")) {
66        rc = vm->unshareVolume(argv[2], argv[3]);
67    } else if (!strcmp(argv[1], "shared")) {
68        bool enabled = false;
69
70        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
71            cli->sendMsg(
72                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);
73        } else {
74            cli->sendMsg(ResponseCode::ShareEnabledResult,
75                    (enabled ? "Share enabled" : "Share disabled"), false);
76        }
77        return 0;
78    } else {
79        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
80    }
81
82    if (!rc) {
83        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
84    } else {
85        /*
86         * Failed
87         */
88        if (errno == ENODEV) {
89            rc = ResponseCode::OpFailedNoMedia;
90        } else if (errno == ENODATA) {
91            rc = ResponseCode::OpFailedMediaBlank;
92        } else if (errno == EIO) {
93            rc = ResponseCode::OpFailedMediaCorrupt;
94        } else if (errno == EBUSY) {
95            rc = ResponseCode::OpFailedVolBusy;
96        } else {
97            LOGW("Returning OperationFailed - no handler for errno %d", errno);
98            rc = ResponseCode::OperationFailed;
99        }
100        cli->sendMsg(rc, "volume operation failed", true);
101    }
102
103    return 0;
104}
105
106CommandListener::ShareCmd::ShareCmd() :
107                 VoldCommand("share") {
108}
109
110int CommandListener::ShareCmd::runCommand(SocketClient *cli,
111                                                      int argc, char **argv) {
112    if (argc < 2) {
113        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
114        return 0;
115    }
116
117    VolumeManager *vm = VolumeManager::Instance();
118    int rc = 0;
119
120    if (!strcmp(argv[1], "status")) {
121        bool avail = false;
122
123        if (vm->shareAvailable(argv[2], &avail)) {
124            cli->sendMsg(
125                    ResponseCode::OperationFailed, "Failed to determine share availability", true);
126        } else {
127            cli->sendMsg(ResponseCode::ShareStatusResult,
128                    (avail ? "Share available" : "Share unavailable"), false);
129        }
130    } else {
131        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown share cmd", false);
132    }
133
134    return 0;
135}
136
137CommandListener::AsecCmd::AsecCmd() :
138                 VoldCommand("asec") {
139}
140
141int CommandListener::AsecCmd::runCommand(SocketClient *cli,
142                                                      int argc, char **argv) {
143    if (argc < 2) {
144        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
145        return 0;
146    }
147
148    VolumeManager *vm = VolumeManager::Instance();
149    int rc = 0;
150
151    if (!strcmp(argv[1], "list")) {
152        DIR *d = opendir("/sdcard/android_secure");
153
154        if (!d) {
155            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
156            return 0;
157        }
158
159        struct dirent *dent;
160        while ((dent = readdir(d))) {
161            if (dent->d_name[0] == '.')
162                continue;
163            if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) {
164                char id[255];
165                memset(id, 0, sizeof(id));
166                strncpy(id, dent->d_name, strlen(dent->d_name) -5);
167                cli->sendMsg(ResponseCode::AsecListResult, id, false);
168            }
169        }
170        closedir(d);
171        cli->sendMsg(ResponseCode::CommandOkay, "ASEC listing complete", false);
172    } else if (!strcmp(argv[1], "create")) {
173        if (argc != 7) {
174            cli->sendMsg(ResponseCode::CommandSyntaxError,
175                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false);
176            return 0;
177        }
178
179        unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
180        if (vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]))) {
181            cli->sendMsg(ResponseCode::OperationFailed, "Container creation failed", true);
182        } else {
183            cli->sendMsg(ResponseCode::CommandOkay, "Container created", false);
184        }
185    } else if (!strcmp(argv[1], "finalize")) {
186        if (argc != 3) {
187            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
188            return 0;
189        }
190        if (vm->finalizeAsec(argv[2])) {
191            cli->sendMsg(ResponseCode::OperationFailed, "Container finalize failed", true);
192        } else {
193            cli->sendMsg(ResponseCode::CommandOkay, "Container finalized", false);
194        }
195    } else if (!strcmp(argv[1], "destroy")) {
196        if (argc != 3) {
197            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id>", false);
198            return 0;
199        }
200        if (vm->destroyAsec(argv[2])) {
201            cli->sendMsg(ResponseCode::OperationFailed, "Container destroy failed", true);
202        } else {
203            cli->sendMsg(ResponseCode::CommandOkay, "Container destroyed", false);
204        }
205    } else if (!strcmp(argv[1], "mount")) {
206        if (argc != 5) {
207            cli->sendMsg(ResponseCode::CommandSyntaxError,
208                    "Usage: asec mount <namespace-id> <key> <ownerUid>", false);
209            return 0;
210        }
211
212        int rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]));
213
214        if (rc < 0) {
215            cli->sendMsg(ResponseCode::OperationFailed, "Mount failed", true);
216        } else {
217            cli->sendMsg(ResponseCode::CommandOkay, "Mount succeeded", false);
218        }
219
220    } else if (!strcmp(argv[1], "unmount")) {
221        if (argc != 3) {
222            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id>", false);
223            return 0;
224        }
225        if (vm->unmountAsec(argv[2])) {
226            cli->sendMsg(ResponseCode::OperationFailed, "Container unmount failed", true);
227        } else {
228            cli->sendMsg(ResponseCode::CommandOkay, "Container unmounted", false);
229        }
230    } else if (!strcmp(argv[1], "rename")) {
231        if (argc != 4) {
232            cli->sendMsg(ResponseCode::CommandSyntaxError,
233                    "Usage: asec rename <old_id> <new_id>", false);
234            return 0;
235        }
236        if (vm->renameAsec(argv[2], argv[3])) {
237            cli->sendMsg(ResponseCode::OperationFailed, "Container rename failed", true);
238        } else {
239            cli->sendMsg(ResponseCode::CommandOkay, "Container renamed", false);
240        }
241    } else if (!strcmp(argv[1], "path")) {
242        if (argc != 3) {
243            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
244            return 0;
245        }
246        char path[255];
247
248        if (vm->getAsecMountPath(argv[2], path, sizeof(path))) {
249            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get path", true);
250        } else {
251            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
252        }
253    } else {
254        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
255    }
256
257    return 0;
258}
259