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