CommandListener.cpp revision 2350c44ff39b4cb2940893964a05f778fc80a436
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#include <fcntl.h>
25
26#define LOG_TAG "CommandListener"
27#include <cutils/log.h>
28
29#include <sysutils/SocketClient.h>
30
31#include "CommandListener.h"
32#include "VolumeManager.h"
33#include "ResponseCode.h"
34#include "Process.h"
35#include "Xwarp.h"
36
37CommandListener::CommandListener() :
38                 FrameworkListener("vold") {
39    registerCmd(new VolumeCmd());
40    registerCmd(new AsecCmd());
41    registerCmd(new ShareCmd());
42    registerCmd(new StorageCmd());
43    registerCmd(new XwarpCmd());
44}
45
46CommandListener::VolumeCmd::VolumeCmd() :
47                 VoldCommand("volume") {
48}
49
50int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
51                                                      int argc, char **argv) {
52    if (argc < 2) {
53        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
54        return 0;
55    }
56
57    VolumeManager *vm = VolumeManager::Instance();
58    int rc = 0;
59
60    if (!strcmp(argv[1], "list")) {
61        return vm->listVolumes(cli);
62    } else if (!strcmp(argv[1], "mount")) {
63        rc = vm->mountVolume(argv[2]);
64    } else if (!strcmp(argv[1], "unmount")) {
65        bool force = false;
66        if (argc >= 4 && !strcmp(argv[3], "force")) {
67            force = true;
68        }
69        rc = vm->unmountVolume(argv[2], force);
70    } else if (!strcmp(argv[1], "format")) {
71        rc = vm->formatVolume(argv[2]);
72    } else if (!strcmp(argv[1], "share")) {
73        rc = vm->shareVolume(argv[2], argv[3]);
74    } else if (!strcmp(argv[1], "unshare")) {
75        rc = vm->unshareVolume(argv[2], argv[3]);
76    } else if (!strcmp(argv[1], "shared")) {
77        bool enabled = false;
78
79        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
80            cli->sendMsg(
81                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);
82        } else {
83            cli->sendMsg(ResponseCode::ShareEnabledResult,
84                    (enabled ? "Share enabled" : "Share disabled"), false);
85        }
86        return 0;
87    } else {
88        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
89    }
90
91    if (!rc) {
92        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
93    } else {
94        int erno = errno;
95        rc = ResponseCode::convertFromErrno();
96        cli->sendMsg(rc, "volume operation failed", true);
97    }
98
99    return 0;
100}
101
102CommandListener::ShareCmd::ShareCmd() :
103                 VoldCommand("share") {
104}
105
106int CommandListener::ShareCmd::runCommand(SocketClient *cli,
107                                                      int argc, char **argv) {
108    if (argc < 2) {
109        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
110        return 0;
111    }
112
113    VolumeManager *vm = VolumeManager::Instance();
114    int rc = 0;
115
116    if (!strcmp(argv[1], "status")) {
117        bool avail = false;
118
119        if (vm->shareAvailable(argv[2], &avail)) {
120            cli->sendMsg(
121                    ResponseCode::OperationFailed, "Failed to determine share availability", true);
122        } else {
123            cli->sendMsg(ResponseCode::ShareStatusResult,
124                    (avail ? "Share available" : "Share unavailable"), false);
125        }
126    } else {
127        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown share cmd", false);
128    }
129
130    return 0;
131}
132
133CommandListener::StorageCmd::StorageCmd() :
134                 VoldCommand("storage") {
135}
136
137int CommandListener::StorageCmd::runCommand(SocketClient *cli,
138                                                      int argc, char **argv) {
139    if (argc < 2) {
140        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
141        return 0;
142    }
143
144    if (!strcmp(argv[1], "users")) {
145        DIR *dir;
146        struct dirent *de;
147
148        if (!(dir = opendir("/proc"))) {
149            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
150            return 0;
151        }
152
153        while ((de = readdir(dir))) {
154            int pid = Process::getPid(de->d_name);
155
156            if (pid < 0) {
157                continue;
158            }
159
160            char processName[255];
161            Process::getProcessName(pid, processName, sizeof(processName));
162
163            if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
164                Process::checkFileMaps(pid, argv[2]) ||
165                Process::checkSymLink(pid, argv[2], "cwd") ||
166                Process::checkSymLink(pid, argv[2], "root") ||
167                Process::checkSymLink(pid, argv[2], "exe")) {
168
169                char msg[1024];
170                snprintf(msg, sizeof(msg), "%d %s", pid, processName);
171                cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
172            }
173        }
174        closedir(dir);
175        cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
176    } else {
177        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
178    }
179    return 0;
180}
181
182CommandListener::AsecCmd::AsecCmd() :
183                 VoldCommand("asec") {
184}
185
186int CommandListener::AsecCmd::runCommand(SocketClient *cli,
187                                                      int argc, char **argv) {
188    if (argc < 2) {
189        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
190        return 0;
191    }
192
193    VolumeManager *vm = VolumeManager::Instance();
194    int rc = 0;
195
196    if (!strcmp(argv[1], "list")) {
197        DIR *d = opendir(Volume::SEC_ASECDIR);
198
199        if (!d) {
200            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
201            return 0;
202        }
203
204        struct dirent *dent;
205        while ((dent = readdir(d))) {
206            if (dent->d_name[0] == '.')
207                continue;
208            if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) {
209                char id[255];
210                memset(id, 0, sizeof(id));
211                strncpy(id, dent->d_name, strlen(dent->d_name) -5);
212                cli->sendMsg(ResponseCode::AsecListResult, id, false);
213            }
214        }
215        closedir(d);
216    } else if (!strcmp(argv[1], "create")) {
217        if (argc != 7) {
218            cli->sendMsg(ResponseCode::CommandSyntaxError,
219                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false);
220            return 0;
221        }
222
223        unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
224        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]));
225    } else if (!strcmp(argv[1], "finalize")) {
226        if (argc != 3) {
227            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
228            return 0;
229        }
230        rc = vm->finalizeAsec(argv[2]);
231    } else if (!strcmp(argv[1], "destroy")) {
232        if (argc < 3) {
233            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
234            return 0;
235        }
236        bool force = false;
237        if (argc > 3 && !strcmp(argv[3], "force")) {
238            force = true;
239        }
240        rc = vm->destroyAsec(argv[2], force);
241    } else if (!strcmp(argv[1], "mount")) {
242        if (argc != 5) {
243            cli->sendMsg(ResponseCode::CommandSyntaxError,
244                    "Usage: asec mount <namespace-id> <key> <ownerUid>", false);
245            return 0;
246        }
247        rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]));
248    } else if (!strcmp(argv[1], "unmount")) {
249        if (argc < 3) {
250            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
251            return 0;
252        }
253        bool force = false;
254        if (argc > 3 && !strcmp(argv[3], "force")) {
255            force = true;
256        }
257        rc = vm->unmountAsec(argv[2], force);
258    } else if (!strcmp(argv[1], "rename")) {
259        if (argc != 4) {
260            cli->sendMsg(ResponseCode::CommandSyntaxError,
261                    "Usage: asec rename <old_id> <new_id>", false);
262            return 0;
263        }
264        rc = vm->renameAsec(argv[2], argv[3]);
265    } else if (!strcmp(argv[1], "path")) {
266        if (argc != 3) {
267            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
268            return 0;
269        }
270        char path[255];
271
272        if (vm->getAsecMountPath(argv[2], path, sizeof(path))) {
273            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get path", true);
274        } else {
275            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
276        }
277        return 0;
278    } else {
279        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
280    }
281
282    if (!rc) {
283        cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
284    } else {
285        rc = ResponseCode::convertFromErrno();
286        cli->sendMsg(rc, "asec operation failed", true);
287    }
288
289    return 0;
290}
291
292CommandListener::XwarpCmd::XwarpCmd() :
293                 VoldCommand("xwarp") {
294}
295
296int CommandListener::XwarpCmd::runCommand(SocketClient *cli,
297                                                      int argc, char **argv) {
298    if (argc < 2) {
299        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
300        return 0;
301    }
302
303    if (!strcmp(argv[1], "enable")) {
304        if (Xwarp::enable()) {
305            cli->sendMsg(ResponseCode::OperationFailed, "Failed to enable xwarp", true);
306            return 0;
307        }
308
309        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp mirroring started", false);
310    } else if (!strcmp(argv[1], "disable")) {
311        if (Xwarp::disable()) {
312            cli->sendMsg(ResponseCode::OperationFailed, "Failed to disable xwarp", true);
313            return 0;
314        }
315
316        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp disabled", false);
317    } else if (!strcmp(argv[1], "status")) {
318        char msg[255];
319        bool r;
320        unsigned mirrorPos, maxSize;
321
322        if (Xwarp::status(&r, &mirrorPos, &maxSize)) {
323            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get xwarp status", true);
324            return 0;
325        }
326        snprintf(msg, sizeof(msg), "%s %u %u", (r ? "ready" : "not-ready"), mirrorPos, maxSize);
327        cli->sendMsg(ResponseCode::XwarpStatusResult, msg, false);
328    } else {
329        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
330    }
331
332    return 0;
333}
334
335