CommandListener.cpp revision 2b22552f9a3b077f9d0a3624ac6f9b8b332f8a7a
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[1], argv[2]);
65    } else if (!strcmp(argv[1], "unshare")) {
66        rc = vm->unshareVolume(argv[1], argv[2]);
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    } else {
78        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
79    }
80
81    if (!rc) {
82        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
83    } else {
84        /*
85         * Failed
86         */
87        if (errno == ENODEV) {
88            rc = ResponseCode::OpFailedNoMedia;
89        } else if (errno == ENODATA) {
90            rc = ResponseCode::OpFailedMediaBlank;
91        } else if (errno == EIO) {
92            rc = ResponseCode::OpFailedMediaCorrupt;
93        } else if (errno == EBUSY) {
94            rc = ResponseCode::OpFailedVolBusy;
95        } else {
96            rc = ResponseCode::OperationFailed;
97        }
98        cli->sendMsg(rc, "volume operation failed", true);
99    }
100
101    return 0;
102}
103
104CommandListener::ShareCmd::ShareCmd() :
105                 VoldCommand("share") {
106}
107
108int CommandListener::ShareCmd::runCommand(SocketClient *cli,
109                                                      int argc, char **argv) {
110    if (argc < 2) {
111        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
112        return 0;
113    }
114
115    VolumeManager *vm = VolumeManager::Instance();
116    int rc = 0;
117
118    if (!strcmp(argv[1], "status")) {
119        bool avail = false;
120
121        if (vm->shareAvailable(argv[2], &avail)) {
122            cli->sendMsg(
123                    ResponseCode::OperationFailed, "Failed to determine share availability", true);
124        } else {
125            cli->sendMsg(ResponseCode::ShareStatusResult,
126                    (avail ? "Share available" : "Share unavailable"), false);
127        }
128    } else {
129        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown share cmd", false);
130    }
131
132    return 0;
133}
134
135CommandListener::AsecCmd::AsecCmd() :
136                 VoldCommand("asec") {
137}
138
139int CommandListener::AsecCmd::runCommand(SocketClient *cli,
140                                                      int argc, char **argv) {
141    if (argc < 2) {
142        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
143        return 0;
144    }
145
146    VolumeManager *vm = VolumeManager::Instance();
147    int rc = 0;
148
149    if (!strcmp(argv[1], "list")) {
150        DIR *d = opendir("/sdcard/android_secure");
151
152        if (!d) {
153            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
154            return 0;
155        }
156
157        struct dirent *dent;
158        while ((dent = readdir(d))) {
159            if (dent->d_name[0] == '.')
160                continue;
161            if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) {
162                char id[255];
163                memset(id, 0, sizeof(id));
164                strncpy(id, dent->d_name, strlen(dent->d_name) -5);
165                cli->sendMsg(ResponseCode::AsecListResult, id, false);
166            }
167        }
168        closedir(d);
169        cli->sendMsg(ResponseCode::CommandOkay, "ASEC listing complete", false);
170    } else if (!strcmp(argv[1], "create")) {
171        if (argc != 7) {
172            cli->sendMsg(ResponseCode::CommandSyntaxError,
173                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false);
174            return 0;
175        }
176
177        unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
178        if (vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]))) {
179            cli->sendMsg(ResponseCode::OperationFailed, "Container creation failed", true);
180        } else {
181            cli->sendMsg(ResponseCode::CommandOkay, "Container created", false);
182        }
183    } else if (!strcmp(argv[1], "finalize")) {
184        if (argc != 3) {
185            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
186            return 0;
187        }
188        if (vm->finalizeAsec(argv[2])) {
189            cli->sendMsg(ResponseCode::OperationFailed, "Container finalize failed", true);
190        } else {
191            cli->sendMsg(ResponseCode::CommandOkay, "Container finalized", false);
192        }
193    } else if (!strcmp(argv[1], "destroy")) {
194        if (argc != 3) {
195            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id>", false);
196            return 0;
197        }
198        if (vm->destroyAsec(argv[2])) {
199            cli->sendMsg(ResponseCode::OperationFailed, "Container destroy failed", true);
200        } else {
201            cli->sendMsg(ResponseCode::CommandOkay, "Container destroyed", false);
202        }
203    } else if (!strcmp(argv[1], "mount")) {
204        if (argc != 5) {
205            cli->sendMsg(ResponseCode::CommandSyntaxError,
206                    "Usage: asec mount <namespace-id> <key> <ownerUid>", false);
207            return 0;
208        }
209
210        int rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]));
211
212        if (rc < 0) {
213            cli->sendMsg(ResponseCode::OperationFailed, "Mount failed", true);
214        } else {
215            cli->sendMsg(ResponseCode::CommandOkay, "Mount succeeded", false);
216        }
217
218    } else if (!strcmp(argv[1], "unmount")) {
219        if (argc != 3) {
220            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id>", false);
221            return 0;
222        }
223        if (vm->unmountAsec(argv[2])) {
224            cli->sendMsg(ResponseCode::OperationFailed, "Container unmount failed", true);
225        } else {
226            cli->sendMsg(ResponseCode::CommandOkay, "Container unmounted", false);
227        }
228    } else if (!strcmp(argv[1], "rename")) {
229        if (argc != 4) {
230            cli->sendMsg(ResponseCode::CommandSyntaxError,
231                    "Usage: asec rename <old_id> <new_id>", false);
232            return 0;
233        }
234        if (vm->renameAsec(argv[2], argv[3])) {
235            cli->sendMsg(ResponseCode::OperationFailed, "Container rename failed", true);
236        } else {
237            cli->sendMsg(ResponseCode::CommandOkay, "Container renamed", false);
238        }
239    } else if (!strcmp(argv[1], "path")) {
240        if (argc != 3) {
241            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
242            return 0;
243        }
244        char path[255];
245
246        if (vm->getAsecMountPath(argv[2], path, sizeof(path))) {
247            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get path", true);
248        } else {
249            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
250        }
251    } else {
252        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
253    }
254
255    return 0;
256}
257