CommandListener.cpp revision d9a4e358614a0c5f60cc76c0636ee4bb02004a32
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
92    cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
93    return 0;
94}
95
96
97CommandListener::VolumeCmd::VolumeCmd() :
98                 VoldCommand("volume") {
99}
100
101int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
102                                                      int argc, char **argv) {
103    dumpArgs(argc, argv, -1);
104
105    if (argc < 2) {
106        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
107        return 0;
108    }
109
110    VolumeManager *vm = VolumeManager::Instance();
111    int rc = 0;
112
113    if (!strcmp(argv[1], "list")) {
114        return vm->listVolumes(cli);
115    } else if (!strcmp(argv[1], "debug")) {
116        vm->setDebug(true);
117    } else if (!strcmp(argv[1], "mount")) {
118        rc = vm->mountVolume(argv[2]);
119    } else if (!strcmp(argv[1], "unmount")) {
120        bool force = false;
121        if (argc >= 4 && !strcmp(argv[3], "force")) {
122            force = true;
123        }
124        rc = vm->unmountVolume(argv[2], force);
125    } else if (!strcmp(argv[1], "format")) {
126        rc = vm->formatVolume(argv[2]);
127    } else if (!strcmp(argv[1], "share")) {
128        rc = vm->shareVolume(argv[2], argv[3]);
129    } else if (!strcmp(argv[1], "unshare")) {
130        rc = vm->unshareVolume(argv[2], argv[3]);
131    } else if (!strcmp(argv[1], "shared")) {
132        bool enabled = false;
133
134        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
135            cli->sendMsg(
136                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);
137        } else {
138            cli->sendMsg(ResponseCode::ShareEnabledResult,
139                    (enabled ? "Share enabled" : "Share disabled"), false);
140        }
141        return 0;
142    } else {
143        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
144    }
145
146    if (!rc) {
147        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
148    } else {
149        int erno = errno;
150        rc = ResponseCode::convertFromErrno();
151        cli->sendMsg(rc, "volume operation failed", true);
152    }
153
154    return 0;
155}
156
157CommandListener::ShareCmd::ShareCmd() :
158                 VoldCommand("share") {
159}
160
161int CommandListener::ShareCmd::runCommand(SocketClient *cli,
162                                                      int argc, char **argv) {
163    dumpArgs(argc, argv, -1);
164
165    if (argc < 2) {
166        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
167        return 0;
168    }
169
170    VolumeManager *vm = VolumeManager::Instance();
171    int rc = 0;
172
173    if (!strcmp(argv[1], "status")) {
174        bool avail = false;
175
176        if (vm->shareAvailable(argv[2], &avail)) {
177            cli->sendMsg(
178                    ResponseCode::OperationFailed, "Failed to determine share availability", true);
179        } else {
180            cli->sendMsg(ResponseCode::ShareStatusResult,
181                    (avail ? "Share available" : "Share unavailable"), false);
182        }
183    } else {
184        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown share cmd", false);
185    }
186
187    return 0;
188}
189
190CommandListener::StorageCmd::StorageCmd() :
191                 VoldCommand("storage") {
192}
193
194int CommandListener::StorageCmd::runCommand(SocketClient *cli,
195                                                      int argc, char **argv) {
196    dumpArgs(argc, argv, -1);
197
198    if (argc < 2) {
199        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
200        return 0;
201    }
202
203    if (!strcmp(argv[1], "users")) {
204        DIR *dir;
205        struct dirent *de;
206
207        if (!(dir = opendir("/proc"))) {
208            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
209            return 0;
210        }
211
212        while ((de = readdir(dir))) {
213            int pid = Process::getPid(de->d_name);
214
215            if (pid < 0) {
216                continue;
217            }
218
219            char processName[255];
220            Process::getProcessName(pid, processName, sizeof(processName));
221
222            if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
223                Process::checkFileMaps(pid, argv[2]) ||
224                Process::checkSymLink(pid, argv[2], "cwd") ||
225                Process::checkSymLink(pid, argv[2], "root") ||
226                Process::checkSymLink(pid, argv[2], "exe")) {
227
228                char msg[1024];
229                snprintf(msg, sizeof(msg), "%d %s", pid, processName);
230                cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
231            }
232        }
233        closedir(dir);
234        cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
235    } else {
236        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
237    }
238    return 0;
239}
240
241CommandListener::AsecCmd::AsecCmd() :
242                 VoldCommand("asec") {
243}
244
245int CommandListener::AsecCmd::runCommand(SocketClient *cli,
246                                                      int argc, char **argv) {
247    if (argc < 2) {
248        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
249        return 0;
250    }
251
252    VolumeManager *vm = VolumeManager::Instance();
253    int rc = 0;
254
255    if (!strcmp(argv[1], "list")) {
256        dumpArgs(argc, argv, -1);
257        DIR *d = opendir(Volume::SEC_ASECDIR);
258
259        if (!d) {
260            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
261            return 0;
262        }
263
264        struct dirent *dent;
265        while ((dent = readdir(d))) {
266            if (dent->d_name[0] == '.')
267                continue;
268            if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) {
269                char id[255];
270                memset(id, 0, sizeof(id));
271                strncpy(id, dent->d_name, strlen(dent->d_name) -5);
272                cli->sendMsg(ResponseCode::AsecListResult, id, false);
273            }
274        }
275        closedir(d);
276    } else if (!strcmp(argv[1], "create")) {
277        dumpArgs(argc, argv, 5);
278        if (argc != 7) {
279            cli->sendMsg(ResponseCode::CommandSyntaxError,
280                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false);
281            return 0;
282        }
283
284        unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
285        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]));
286    } else if (!strcmp(argv[1], "finalize")) {
287        dumpArgs(argc, argv, -1);
288        if (argc != 3) {
289            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
290            return 0;
291        }
292        rc = vm->finalizeAsec(argv[2]);
293    } else if (!strcmp(argv[1], "destroy")) {
294        dumpArgs(argc, argv, -1);
295        if (argc < 3) {
296            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
297            return 0;
298        }
299        bool force = false;
300        if (argc > 3 && !strcmp(argv[3], "force")) {
301            force = true;
302        }
303        rc = vm->destroyAsec(argv[2], force);
304    } else if (!strcmp(argv[1], "mount")) {
305        dumpArgs(argc, argv, 3);
306        if (argc != 5) {
307            cli->sendMsg(ResponseCode::CommandSyntaxError,
308                    "Usage: asec mount <namespace-id> <key> <ownerUid>", false);
309            return 0;
310        }
311        rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]));
312    } else if (!strcmp(argv[1], "unmount")) {
313        dumpArgs(argc, argv, -1);
314        if (argc < 3) {
315            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
316            return 0;
317        }
318        bool force = false;
319        if (argc > 3 && !strcmp(argv[3], "force")) {
320            force = true;
321        }
322        rc = vm->unmountAsec(argv[2], force);
323    } else if (!strcmp(argv[1], "rename")) {
324        dumpArgs(argc, argv, -1);
325        if (argc != 4) {
326            cli->sendMsg(ResponseCode::CommandSyntaxError,
327                    "Usage: asec rename <old_id> <new_id>", false);
328            return 0;
329        }
330        rc = vm->renameAsec(argv[2], argv[3]);
331    } else if (!strcmp(argv[1], "path")) {
332        dumpArgs(argc, argv, -1);
333        if (argc != 3) {
334            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
335            return 0;
336        }
337        char path[255];
338
339        if (vm->getAsecMountPath(argv[2], path, sizeof(path))) {
340            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get path", true);
341        } else {
342            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
343        }
344        return 0;
345    } else {
346        dumpArgs(argc, argv, -1);
347        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
348    }
349
350    if (!rc) {
351        cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
352    } else {
353        rc = ResponseCode::convertFromErrno();
354        cli->sendMsg(rc, "asec operation failed", true);
355    }
356
357    return 0;
358}
359
360CommandListener::XwarpCmd::XwarpCmd() :
361                 VoldCommand("xwarp") {
362}
363
364int CommandListener::XwarpCmd::runCommand(SocketClient *cli,
365                                                      int argc, char **argv) {
366    if (argc < 2) {
367        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
368        return 0;
369    }
370
371    if (!strcmp(argv[1], "enable")) {
372        if (Xwarp::enable()) {
373            cli->sendMsg(ResponseCode::OperationFailed, "Failed to enable xwarp", true);
374            return 0;
375        }
376
377        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp mirroring started", false);
378    } else if (!strcmp(argv[1], "disable")) {
379        if (Xwarp::disable()) {
380            cli->sendMsg(ResponseCode::OperationFailed, "Failed to disable xwarp", true);
381            return 0;
382        }
383
384        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp disabled", false);
385    } else if (!strcmp(argv[1], "status")) {
386        char msg[255];
387        bool r;
388        unsigned mirrorPos, maxSize;
389
390        if (Xwarp::status(&r, &mirrorPos, &maxSize)) {
391            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get xwarp status", true);
392            return 0;
393        }
394        snprintf(msg, sizeof(msg), "%s %u %u", (r ? "ready" : "not-ready"), mirrorPos, maxSize);
395        cli->sendMsg(ResponseCode::XwarpStatusResult, msg, false);
396    } else {
397        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
398    }
399
400    return 0;
401}
402
403