CommandListener.cpp revision 96597e8b840ef671fe5279f8bd64fb09a8b38d4c
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 "VoldCmdListener"
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#include "Loop.h"
37#include "Devmapper.h"
38
39CommandListener::CommandListener() :
40                 FrameworkListener("vold") {
41    registerCmd(new DumpCmd());
42    registerCmd(new VolumeCmd());
43    registerCmd(new AsecCmd());
44    registerCmd(new ShareCmd());
45    registerCmd(new StorageCmd());
46    registerCmd(new XwarpCmd());
47}
48
49void CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
50    char buffer[4096];
51    char *p = buffer;
52
53    memset(buffer, 0, sizeof(buffer));
54    int i;
55    for (i = 0; i < argc; i++) {
56        int len = strlen(argv[i]) + 1; // Account for space
57        if (i == argObscure) {
58            len += 2; // Account for {}
59        }
60        if (((p - buffer) + len) < (sizeof(buffer)-1)) {
61            if (i == argObscure) {
62                *p++ = '{';
63                *p++ = '}';
64                *p++ = ' ';
65                continue;
66            }
67            strcpy(p, argv[i]);
68            p+= strlen(argv[i]);
69            if (i != (argc -1)) {
70                *p++ = ' ';
71            }
72        }
73    }
74    LOGD("%s", buffer);
75}
76
77CommandListener::DumpCmd::DumpCmd() :
78                 VoldCommand("dump") {
79}
80
81int CommandListener::DumpCmd::runCommand(SocketClient *cli,
82                                         int argc, char **argv) {
83    cli->sendMsg(0, "Dumping loop status", false);
84    if (Loop::dumpState(cli)) {
85        cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);
86    }
87    cli->sendMsg(0, "Dumping DM status", false);
88    if (Devmapper::dumpState(cli)) {
89        cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);
90    }
91    cli->sendMsg(0, "Dumping mounted filesystems", false);
92    FILE *fp = fopen("/proc/mounts", "r");
93    if (fp) {
94        char line[1024];
95        while (fgets(line, sizeof(line), fp)) {
96            line[strlen(line)-1] = '\0';
97            cli->sendMsg(0, line, false);;
98        }
99        fclose(fp);
100    }
101
102    cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
103    return 0;
104}
105
106
107CommandListener::VolumeCmd::VolumeCmd() :
108                 VoldCommand("volume") {
109}
110
111int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
112                                                      int argc, char **argv) {
113    dumpArgs(argc, argv, -1);
114
115    if (argc < 2) {
116        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
117        return 0;
118    }
119
120    VolumeManager *vm = VolumeManager::Instance();
121    int rc = 0;
122
123    if (!strcmp(argv[1], "list")) {
124        return vm->listVolumes(cli);
125    } else if (!strcmp(argv[1], "debug")) {
126        if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {
127            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);
128            return 0;
129        }
130        vm->setDebug(!strcmp(argv[2], "on") ? true : false);
131    } else if (!strcmp(argv[1], "mount")) {
132        if (argc != 3) {
133            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
134            return 0;
135        }
136        rc = vm->mountVolume(argv[2]);
137    } else if (!strcmp(argv[1], "unmount")) {
138        if (argc < 3 || argc > 4 || (argc == 4 && strcmp(argv[3], "force"))) {
139            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force]", false);
140            return 0;
141        }
142
143        bool force = false;
144        if (argc >= 4 && !strcmp(argv[3], "force")) {
145            force = true;
146        }
147        rc = vm->unmountVolume(argv[2], force);
148    } else if (!strcmp(argv[1], "format")) {
149        if (argc != 3) {
150            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path>", false);
151            return 0;
152        }
153        rc = vm->formatVolume(argv[2]);
154    } else if (!strcmp(argv[1], "share")) {
155        if (argc != 4) {
156            cli->sendMsg(ResponseCode::CommandSyntaxError,
157                    "Usage: volume share <path> <method>", false);
158            return 0;
159        }
160        rc = vm->shareVolume(argv[2], argv[3]);
161    } else if (!strcmp(argv[1], "unshare")) {
162        if (argc != 4) {
163            cli->sendMsg(ResponseCode::CommandSyntaxError,
164                    "Usage: volume unshare <path> <method>", false);
165            return 0;
166        }
167        rc = vm->unshareVolume(argv[2], argv[3]);
168    } else if (!strcmp(argv[1], "shared")) {
169        bool enabled = false;
170        if (argc != 4) {
171            cli->sendMsg(ResponseCode::CommandSyntaxError,
172                    "Usage: volume shared <path> <method>", false);
173            return 0;
174        }
175
176        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
177            cli->sendMsg(
178                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);
179        } else {
180            cli->sendMsg(ResponseCode::ShareEnabledResult,
181                    (enabled ? "Share enabled" : "Share disabled"), false);
182        }
183        return 0;
184    } else {
185        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
186    }
187
188    if (!rc) {
189        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
190    } else {
191        int erno = errno;
192        rc = ResponseCode::convertFromErrno();
193        cli->sendMsg(rc, "volume operation failed", true);
194    }
195
196    return 0;
197}
198
199CommandListener::ShareCmd::ShareCmd() :
200                 VoldCommand("share") {
201}
202
203int CommandListener::ShareCmd::runCommand(SocketClient *cli,
204                                                      int argc, char **argv) {
205    dumpArgs(argc, argv, -1);
206
207    if (argc < 2) {
208        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
209        return 0;
210    }
211
212    VolumeManager *vm = VolumeManager::Instance();
213    int rc = 0;
214
215    if (!strcmp(argv[1], "status")) {
216        bool avail = false;
217
218        if (vm->shareAvailable(argv[2], &avail)) {
219            cli->sendMsg(
220                    ResponseCode::OperationFailed, "Failed to determine share availability", true);
221        } else {
222            cli->sendMsg(ResponseCode::ShareStatusResult,
223                    (avail ? "Share available" : "Share unavailable"), false);
224        }
225    } else {
226        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown share cmd", false);
227    }
228
229    return 0;
230}
231
232CommandListener::StorageCmd::StorageCmd() :
233                 VoldCommand("storage") {
234}
235
236int CommandListener::StorageCmd::runCommand(SocketClient *cli,
237                                                      int argc, char **argv) {
238    dumpArgs(argc, argv, -1);
239
240    if (argc < 2) {
241        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
242        return 0;
243    }
244
245    if (!strcmp(argv[1], "users")) {
246        DIR *dir;
247        struct dirent *de;
248
249        if (!(dir = opendir("/proc"))) {
250            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
251            return 0;
252        }
253
254        while ((de = readdir(dir))) {
255            int pid = Process::getPid(de->d_name);
256
257            if (pid < 0) {
258                continue;
259            }
260
261            char processName[255];
262            Process::getProcessName(pid, processName, sizeof(processName));
263
264            if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
265                Process::checkFileMaps(pid, argv[2]) ||
266                Process::checkSymLink(pid, argv[2], "cwd") ||
267                Process::checkSymLink(pid, argv[2], "root") ||
268                Process::checkSymLink(pid, argv[2], "exe")) {
269
270                char msg[1024];
271                snprintf(msg, sizeof(msg), "%d %s", pid, processName);
272                cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
273            }
274        }
275        closedir(dir);
276        cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
277    } else {
278        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
279    }
280    return 0;
281}
282
283CommandListener::AsecCmd::AsecCmd() :
284                 VoldCommand("asec") {
285}
286
287int CommandListener::AsecCmd::runCommand(SocketClient *cli,
288                                                      int argc, char **argv) {
289    if (argc < 2) {
290        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
291        return 0;
292    }
293
294    VolumeManager *vm = VolumeManager::Instance();
295    int rc = 0;
296
297    if (!strcmp(argv[1], "list")) {
298        dumpArgs(argc, argv, -1);
299        DIR *d = opendir(Volume::SEC_ASECDIR);
300
301        if (!d) {
302            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
303            return 0;
304        }
305
306        struct dirent *dent;
307        while ((dent = readdir(d))) {
308            if (dent->d_name[0] == '.')
309                continue;
310            if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) {
311                char id[255];
312                memset(id, 0, sizeof(id));
313                strncpy(id, dent->d_name, strlen(dent->d_name) -5);
314                cli->sendMsg(ResponseCode::AsecListResult, id, false);
315            }
316        }
317        closedir(d);
318    } else if (!strcmp(argv[1], "create")) {
319        dumpArgs(argc, argv, 5);
320        if (argc != 7) {
321            cli->sendMsg(ResponseCode::CommandSyntaxError,
322                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false);
323            return 0;
324        }
325
326        unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
327        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]));
328    } else if (!strcmp(argv[1], "finalize")) {
329        dumpArgs(argc, argv, -1);
330        if (argc != 3) {
331            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
332            return 0;
333        }
334        rc = vm->finalizeAsec(argv[2]);
335    } else if (!strcmp(argv[1], "destroy")) {
336        dumpArgs(argc, argv, -1);
337        if (argc < 3) {
338            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
339            return 0;
340        }
341        bool force = false;
342        if (argc > 3 && !strcmp(argv[3], "force")) {
343            force = true;
344        }
345        rc = vm->destroyAsec(argv[2], force);
346    } else if (!strcmp(argv[1], "mount")) {
347        dumpArgs(argc, argv, 3);
348        if (argc != 5) {
349            cli->sendMsg(ResponseCode::CommandSyntaxError,
350                    "Usage: asec mount <namespace-id> <key> <ownerUid>", false);
351            return 0;
352        }
353        rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]));
354    } else if (!strcmp(argv[1], "unmount")) {
355        dumpArgs(argc, argv, -1);
356        if (argc < 3) {
357            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
358            return 0;
359        }
360        bool force = false;
361        if (argc > 3 && !strcmp(argv[3], "force")) {
362            force = true;
363        }
364        rc = vm->unmountAsec(argv[2], force);
365    } else if (!strcmp(argv[1], "rename")) {
366        dumpArgs(argc, argv, -1);
367        if (argc != 4) {
368            cli->sendMsg(ResponseCode::CommandSyntaxError,
369                    "Usage: asec rename <old_id> <new_id>", false);
370            return 0;
371        }
372        rc = vm->renameAsec(argv[2], argv[3]);
373    } else if (!strcmp(argv[1], "path")) {
374        dumpArgs(argc, argv, -1);
375        if (argc != 3) {
376            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
377            return 0;
378        }
379        char path[255];
380
381        if (vm->getAsecMountPath(argv[2], path, sizeof(path))) {
382            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get path", true);
383        } else {
384            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
385        }
386        return 0;
387    } else {
388        dumpArgs(argc, argv, -1);
389        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
390    }
391
392    if (!rc) {
393        cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
394    } else {
395        rc = ResponseCode::convertFromErrno();
396        cli->sendMsg(rc, "asec operation failed", true);
397    }
398
399    return 0;
400}
401
402CommandListener::XwarpCmd::XwarpCmd() :
403                 VoldCommand("xwarp") {
404}
405
406int CommandListener::XwarpCmd::runCommand(SocketClient *cli,
407                                                      int argc, char **argv) {
408    if (argc < 2) {
409        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
410        return 0;
411    }
412
413    if (!strcmp(argv[1], "enable")) {
414        if (Xwarp::enable()) {
415            cli->sendMsg(ResponseCode::OperationFailed, "Failed to enable xwarp", true);
416            return 0;
417        }
418
419        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp mirroring started", false);
420    } else if (!strcmp(argv[1], "disable")) {
421        if (Xwarp::disable()) {
422            cli->sendMsg(ResponseCode::OperationFailed, "Failed to disable xwarp", true);
423            return 0;
424        }
425
426        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp disabled", false);
427    } else if (!strcmp(argv[1], "status")) {
428        char msg[255];
429        bool r;
430        unsigned mirrorPos, maxSize;
431
432        if (Xwarp::status(&r, &mirrorPos, &maxSize)) {
433            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get xwarp status", true);
434            return 0;
435        }
436        snprintf(msg, sizeof(msg), "%s %u %u", (r ? "ready" : "not-ready"), mirrorPos, maxSize);
437        cli->sendMsg(ResponseCode::XwarpStatusResult, msg, false);
438    } else {
439        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
440    }
441
442    return 0;
443}
444
445