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