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