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