• 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 #include <fs_mgr.h>
26 #include <string.h>
27 
28 #define LOG_TAG "VoldCmdListener"
29 #include <cutils/log.h>
30 
31 #include <sysutils/SocketClient.h>
32 #include <private/android_filesystem_config.h>
33 
34 #include "CommandListener.h"
35 #include "VolumeManager.h"
36 #include "ResponseCode.h"
37 #include "Process.h"
38 #include "Loop.h"
39 #include "Devmapper.h"
40 #include "cryptfs.h"
41 #include "fstrim.h"
42 
43 #define DUMP_ARGS 0
44 
CommandListener()45 CommandListener::CommandListener() :
46                  FrameworkListener("vold", true) {
47     registerCmd(new DumpCmd());
48     registerCmd(new VolumeCmd());
49     registerCmd(new AsecCmd());
50     registerCmd(new ObbCmd());
51     registerCmd(new StorageCmd());
52     registerCmd(new CryptfsCmd());
53     registerCmd(new FstrimCmd());
54 }
55 
56 #if DUMP_ARGS
dumpArgs(int argc,char ** argv,int argObscure)57 void CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
58     char buffer[4096];
59     char *p = buffer;
60 
61     memset(buffer, 0, sizeof(buffer));
62     int i;
63     for (i = 0; i < argc; i++) {
64         unsigned int len = strlen(argv[i]) + 1; // Account for space
65         if (i == argObscure) {
66             len += 2; // Account for {}
67         }
68         if (((p - buffer) + len) < (sizeof(buffer)-1)) {
69             if (i == argObscure) {
70                 *p++ = '{';
71                 *p++ = '}';
72                 *p++ = ' ';
73                 continue;
74             }
75             strcpy(p, argv[i]);
76             p+= strlen(argv[i]);
77             if (i != (argc -1)) {
78                 *p++ = ' ';
79             }
80         }
81     }
82     SLOGD("%s", buffer);
83 }
84 #else
dumpArgs(int,char **,int)85 void CommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
86 #endif
87 
DumpCmd()88 CommandListener::DumpCmd::DumpCmd() :
89                  VoldCommand("dump") {
90 }
91 
runCommand(SocketClient * cli,int,char **)92 int CommandListener::DumpCmd::runCommand(SocketClient *cli,
93                                          int /*argc*/, char ** /*argv*/) {
94     cli->sendMsg(0, "Dumping loop status", false);
95     if (Loop::dumpState(cli)) {
96         cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);
97     }
98     cli->sendMsg(0, "Dumping DM status", false);
99     if (Devmapper::dumpState(cli)) {
100         cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);
101     }
102     cli->sendMsg(0, "Dumping mounted filesystems", false);
103     FILE *fp = fopen("/proc/mounts", "r");
104     if (fp) {
105         char line[1024];
106         while (fgets(line, sizeof(line), fp)) {
107             line[strlen(line)-1] = '\0';
108             cli->sendMsg(0, line, false);;
109         }
110         fclose(fp);
111     }
112 
113     cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
114     return 0;
115 }
116 
VolumeCmd()117 CommandListener::VolumeCmd::VolumeCmd() :
118                  VoldCommand("volume") {
119 }
120 
runCommand(SocketClient * cli,int argc,char ** argv)121 int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
122                                            int argc, char **argv) {
123     dumpArgs(argc, argv, -1);
124 
125     if (argc < 2) {
126         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
127         return 0;
128     }
129 
130     VolumeManager *vm = VolumeManager::Instance();
131     int rc = 0;
132 
133     if (!strcmp(argv[1], "list")) {
134         bool broadcast = argc >= 3 && !strcmp(argv[2], "broadcast");
135         return vm->listVolumes(cli, broadcast);
136     } else if (!strcmp(argv[1], "debug")) {
137         if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {
138             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);
139             return 0;
140         }
141         vm->setDebug(!strcmp(argv[2], "on") ? true : false);
142     } else if (!strcmp(argv[1], "mount")) {
143         if (argc != 3) {
144             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
145             return 0;
146         }
147         rc = vm->mountVolume(argv[2]);
148     } else if (!strcmp(argv[1], "unmount")) {
149         if (argc < 3 || argc > 4 ||
150            ((argc == 4 && strcmp(argv[3], "force")) &&
151             (argc == 4 && strcmp(argv[3], "force_and_revert")))) {
152             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force|force_and_revert]", false);
153             return 0;
154         }
155 
156         bool force = false;
157         bool revert = false;
158         if (argc >= 4 && !strcmp(argv[3], "force")) {
159             force = true;
160         } else if (argc >= 4 && !strcmp(argv[3], "force_and_revert")) {
161             force = true;
162             revert = true;
163         }
164         rc = vm->unmountVolume(argv[2], force, revert);
165     } else if (!strcmp(argv[1], "format")) {
166         if (argc < 3 || argc > 4 ||
167             (argc == 4 && strcmp(argv[3], "wipe"))) {
168             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path> [wipe]", false);
169             return 0;
170         }
171         bool wipe = false;
172         if (argc >= 4 && !strcmp(argv[3], "wipe")) {
173             wipe = true;
174         }
175         rc = vm->formatVolume(argv[2], wipe);
176     } else if (!strcmp(argv[1], "share")) {
177         if (argc != 4) {
178             cli->sendMsg(ResponseCode::CommandSyntaxError,
179                     "Usage: volume share <path> <method>", false);
180             return 0;
181         }
182         rc = vm->shareVolume(argv[2], argv[3]);
183     } else if (!strcmp(argv[1], "unshare")) {
184         if (argc != 4) {
185             cli->sendMsg(ResponseCode::CommandSyntaxError,
186                     "Usage: volume unshare <path> <method>", false);
187             return 0;
188         }
189         rc = vm->unshareVolume(argv[2], argv[3]);
190     } else if (!strcmp(argv[1], "shared")) {
191         bool enabled = false;
192         if (argc != 4) {
193             cli->sendMsg(ResponseCode::CommandSyntaxError,
194                     "Usage: volume shared <path> <method>", false);
195             return 0;
196         }
197 
198         if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
199             cli->sendMsg(
200                     ResponseCode::OperationFailed, "Failed to determine share enable state", true);
201         } else {
202             cli->sendMsg(ResponseCode::ShareEnabledResult,
203                     (enabled ? "Share enabled" : "Share disabled"), false);
204         }
205         return 0;
206     } else if (!strcmp(argv[1], "mkdirs")) {
207         if (argc != 3) {
208             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mkdirs <path>", false);
209             return 0;
210         }
211         rc = vm->mkdirs(argv[2]);
212     } else {
213         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
214     }
215 
216     if (!rc) {
217         cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
218     } else {
219         int erno = errno;
220         rc = ResponseCode::convertFromErrno();
221         cli->sendMsg(rc, "volume operation failed", true);
222     }
223 
224     return 0;
225 }
226 
StorageCmd()227 CommandListener::StorageCmd::StorageCmd() :
228                  VoldCommand("storage") {
229 }
230 
runCommand(SocketClient * cli,int argc,char ** argv)231 int CommandListener::StorageCmd::runCommand(SocketClient *cli,
232                                                       int argc, char **argv) {
233     /* Guarantied to be initialized by vold's main() before the CommandListener is active */
234     extern struct fstab *fstab;
235 
236     dumpArgs(argc, argv, -1);
237 
238     if (argc < 2) {
239         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
240         return 0;
241     }
242 
243     if (!strcmp(argv[1], "mountall")) {
244         if (argc != 2) {
245             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: mountall", false);
246             return 0;
247         }
248         fs_mgr_mount_all(fstab);
249         cli->sendMsg(ResponseCode::CommandOkay, "Mountall ran successfully", false);
250         return 0;
251     }
252     if (!strcmp(argv[1], "users")) {
253         DIR *dir;
254         struct dirent *de;
255 
256         if (argc < 3) {
257             cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument: user <mountpoint>", false);
258             return 0;
259         }
260         if (!(dir = opendir("/proc"))) {
261             cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
262             return 0;
263         }
264 
265         while ((de = readdir(dir))) {
266             int pid = Process::getPid(de->d_name);
267 
268             if (pid < 0) {
269                 continue;
270             }
271 
272             char processName[255];
273             Process::getProcessName(pid, processName, sizeof(processName));
274 
275             if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
276                 Process::checkFileMaps(pid, argv[2]) ||
277                 Process::checkSymLink(pid, argv[2], "cwd") ||
278                 Process::checkSymLink(pid, argv[2], "root") ||
279                 Process::checkSymLink(pid, argv[2], "exe")) {
280 
281                 char msg[1024];
282                 snprintf(msg, sizeof(msg), "%d %s", pid, processName);
283                 cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
284             }
285         }
286         closedir(dir);
287         cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
288     } else {
289         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
290     }
291     return 0;
292 }
293 
AsecCmd()294 CommandListener::AsecCmd::AsecCmd() :
295                  VoldCommand("asec") {
296 }
297 
listAsecsInDirectory(SocketClient * cli,const char * directory)298 void CommandListener::AsecCmd::listAsecsInDirectory(SocketClient *cli, const char *directory) {
299     DIR *d = opendir(directory);
300 
301     if (!d) {
302         cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
303         return;
304     }
305 
306     size_t dirent_len = offsetof(struct dirent, d_name) +
307             fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
308 
309     struct dirent *dent = (struct dirent *) malloc(dirent_len);
310     if (dent == NULL) {
311         cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", true);
312         return;
313     }
314 
315     struct dirent *result;
316 
317     while (!readdir_r(d, dent, &result) && result != NULL) {
318         if (dent->d_name[0] == '.')
319             continue;
320         if (dent->d_type != DT_REG)
321             continue;
322         size_t name_len = strlen(dent->d_name);
323         if (name_len > 5 && name_len < 260 &&
324                 !strcmp(&dent->d_name[name_len - 5], ".asec")) {
325             char id[255];
326             memset(id, 0, sizeof(id));
327             strlcpy(id, dent->d_name, name_len - 4);
328             cli->sendMsg(ResponseCode::AsecListResult, id, false);
329         }
330     }
331     closedir(d);
332 
333     free(dent);
334 }
335 
runCommand(SocketClient * cli,int argc,char ** argv)336 int CommandListener::AsecCmd::runCommand(SocketClient *cli,
337                                                       int argc, char **argv) {
338     if (argc < 2) {
339         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
340         return 0;
341     }
342 
343     VolumeManager *vm = VolumeManager::Instance();
344     int rc = 0;
345 
346     if (!strcmp(argv[1], "list")) {
347         dumpArgs(argc, argv, -1);
348 
349         listAsecsInDirectory(cli, Volume::SEC_ASECDIR_EXT);
350         listAsecsInDirectory(cli, Volume::SEC_ASECDIR_INT);
351     } else if (!strcmp(argv[1], "create")) {
352         dumpArgs(argc, argv, 5);
353         if (argc != 8) {
354             cli->sendMsg(ResponseCode::CommandSyntaxError,
355                     "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid> "
356                     "<isExternal>", false);
357             return 0;
358         }
359 
360         unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
361         const bool isExternal = (atoi(argv[7]) == 1);
362         rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]), isExternal);
363     } else if (!strcmp(argv[1], "resize")) {
364         dumpArgs(argc, argv, -1);
365         if (argc != 5) {
366             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec resize <container-id> <size_mb> <key>", false);
367             return 0;
368         }
369         unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
370         rc = vm->resizeAsec(argv[2], numSectors, argv[4]);
371     } else if (!strcmp(argv[1], "finalize")) {
372         dumpArgs(argc, argv, -1);
373         if (argc != 3) {
374             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
375             return 0;
376         }
377         rc = vm->finalizeAsec(argv[2]);
378     } else if (!strcmp(argv[1], "fixperms")) {
379         dumpArgs(argc, argv, -1);
380         if  (argc != 5) {
381             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
382             return 0;
383         }
384 
385         char *endptr;
386         gid_t gid = (gid_t) strtoul(argv[3], &endptr, 10);
387         if (*endptr != '\0') {
388             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
389             return 0;
390         }
391 
392         rc = vm->fixupAsecPermissions(argv[2], gid, argv[4]);
393     } else if (!strcmp(argv[1], "destroy")) {
394         dumpArgs(argc, argv, -1);
395         if (argc < 3) {
396             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
397             return 0;
398         }
399         bool force = false;
400         if (argc > 3 && !strcmp(argv[3], "force")) {
401             force = true;
402         }
403         rc = vm->destroyAsec(argv[2], force);
404     } else if (!strcmp(argv[1], "mount")) {
405         dumpArgs(argc, argv, 3);
406         if (argc != 6) {
407             cli->sendMsg(ResponseCode::CommandSyntaxError,
408                     "Usage: asec mount <namespace-id> <key> <ownerUid> <ro|rw>", false);
409             return 0;
410         }
411         bool readOnly = true;
412         if (!strcmp(argv[5], "rw")) {
413             readOnly = false;
414         }
415         rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]), readOnly);
416     } else if (!strcmp(argv[1], "unmount")) {
417         dumpArgs(argc, argv, -1);
418         if (argc < 3) {
419             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
420             return 0;
421         }
422         bool force = false;
423         if (argc > 3 && !strcmp(argv[3], "force")) {
424             force = true;
425         }
426         rc = vm->unmountAsec(argv[2], force);
427     } else if (!strcmp(argv[1], "rename")) {
428         dumpArgs(argc, argv, -1);
429         if (argc != 4) {
430             cli->sendMsg(ResponseCode::CommandSyntaxError,
431                     "Usage: asec rename <old_id> <new_id>", false);
432             return 0;
433         }
434         rc = vm->renameAsec(argv[2], argv[3]);
435     } else if (!strcmp(argv[1], "path")) {
436         dumpArgs(argc, argv, -1);
437         if (argc != 3) {
438             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
439             return 0;
440         }
441         char path[255];
442 
443         if (!(rc = vm->getAsecMountPath(argv[2], path, sizeof(path)))) {
444             cli->sendMsg(ResponseCode::AsecPathResult, path, false);
445             return 0;
446         }
447     } else if (!strcmp(argv[1], "fspath")) {
448         dumpArgs(argc, argv, -1);
449         if (argc != 3) {
450             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fspath <container-id>", false);
451             return 0;
452         }
453         char path[255];
454 
455         if (!(rc = vm->getAsecFilesystemPath(argv[2], path, sizeof(path)))) {
456             cli->sendMsg(ResponseCode::AsecPathResult, path, false);
457             return 0;
458         }
459     } else {
460         dumpArgs(argc, argv, -1);
461         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
462     }
463 
464     if (!rc) {
465         cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
466     } else {
467         rc = ResponseCode::convertFromErrno();
468         cli->sendMsg(rc, "asec operation failed", true);
469     }
470 
471     return 0;
472 }
473 
ObbCmd()474 CommandListener::ObbCmd::ObbCmd() :
475                  VoldCommand("obb") {
476 }
477 
runCommand(SocketClient * cli,int argc,char ** argv)478 int CommandListener::ObbCmd::runCommand(SocketClient *cli,
479                                                       int argc, char **argv) {
480     if (argc < 2) {
481         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
482         return 0;
483     }
484 
485     VolumeManager *vm = VolumeManager::Instance();
486     int rc = 0;
487 
488     if (!strcmp(argv[1], "list")) {
489         dumpArgs(argc, argv, -1);
490 
491         rc = vm->listMountedObbs(cli);
492     } else if (!strcmp(argv[1], "mount")) {
493             dumpArgs(argc, argv, 3);
494             if (argc != 5) {
495                 cli->sendMsg(ResponseCode::CommandSyntaxError,
496                         "Usage: obb mount <filename> <key> <ownerGid>", false);
497                 return 0;
498             }
499             rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
500     } else if (!strcmp(argv[1], "unmount")) {
501         dumpArgs(argc, argv, -1);
502         if (argc < 3) {
503             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
504             return 0;
505         }
506         bool force = false;
507         if (argc > 3 && !strcmp(argv[3], "force")) {
508             force = true;
509         }
510         rc = vm->unmountObb(argv[2], force);
511     } else if (!strcmp(argv[1], "path")) {
512         dumpArgs(argc, argv, -1);
513         if (argc != 3) {
514             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
515             return 0;
516         }
517         char path[255];
518 
519         if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
520             cli->sendMsg(ResponseCode::AsecPathResult, path, false);
521             return 0;
522         }
523     } else {
524         dumpArgs(argc, argv, -1);
525         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
526     }
527 
528     if (!rc) {
529         cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
530     } else {
531         rc = ResponseCode::convertFromErrno();
532         cli->sendMsg(rc, "obb operation failed", true);
533     }
534 
535     return 0;
536 }
537 
CryptfsCmd()538 CommandListener::CryptfsCmd::CryptfsCmd() :
539                  VoldCommand("cryptfs") {
540 }
541 
getType(const char * type)542 static int getType(const char* type)
543 {
544     if (!strcmp(type, "default")) {
545         return CRYPT_TYPE_DEFAULT;
546     } else if (!strcmp(type, "password")) {
547         return CRYPT_TYPE_PASSWORD;
548     } else if (!strcmp(type, "pin")) {
549         return CRYPT_TYPE_PIN;
550     } else if (!strcmp(type, "pattern")) {
551         return CRYPT_TYPE_PATTERN;
552     } else {
553         return -1;
554     }
555 }
556 
runCommand(SocketClient * cli,int argc,char ** argv)557 int CommandListener::CryptfsCmd::runCommand(SocketClient *cli,
558                                                       int argc, char **argv) {
559     if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
560         cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run cryptfs commands", false);
561         return 0;
562     }
563 
564     if (argc < 2) {
565         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
566         return 0;
567     }
568 
569     int rc = 0;
570 
571     if (!strcmp(argv[1], "checkpw")) {
572         if (argc != 3) {
573             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
574             return 0;
575         }
576         dumpArgs(argc, argv, 2);
577         rc = cryptfs_check_passwd(argv[2]);
578     } else if (!strcmp(argv[1], "restart")) {
579         if (argc != 2) {
580             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs restart", false);
581             return 0;
582         }
583         dumpArgs(argc, argv, -1);
584         rc = cryptfs_restart();
585     } else if (!strcmp(argv[1], "cryptocomplete")) {
586         if (argc != 2) {
587             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs cryptocomplete", false);
588             return 0;
589         }
590         dumpArgs(argc, argv, -1);
591         rc = cryptfs_crypto_complete();
592     } else if (!strcmp(argv[1], "enablecrypto")) {
593         const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> "
594                              "default|password|pin|pattern [passwd]";
595         if ( (argc != 4 && argc != 5)
596              || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) {
597             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
598             return 0;
599         }
600         dumpArgs(argc, argv, 4);
601 
602         int tries;
603         for (tries = 0; tries < 2; ++tries) {
604             int type = getType(argv[3]);
605             if (type == -1) {
606                 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax,
607                              false);
608                 return 0;
609             } else if (type == CRYPT_TYPE_DEFAULT) {
610               rc = cryptfs_enable_default(argv[2], /*allow_reboot*/false);
611             } else {
612                 rc = cryptfs_enable(argv[2], type, argv[4],
613                                     /*allow_reboot*/false);
614             }
615 
616             if (rc == 0) {
617                 break;
618             } else if (tries == 0) {
619                 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, 2);
620             }
621         }
622     } else if (!strcmp(argv[1], "changepw")) {
623         const char* syntax = "Usage: cryptfs changepw "
624                              "default|password|pin|pattern [newpasswd]";
625         const char* password;
626         if (argc == 3) {
627             password = "";
628         } else if (argc == 4) {
629             password = argv[3];
630         } else {
631             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
632             return 0;
633         }
634         int type = getType(argv[2]);
635         if (type == -1) {
636             cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false);
637             return 0;
638         }
639         SLOGD("cryptfs changepw %s {}", argv[2]);
640         rc = cryptfs_changepw(type, password);
641     } else if (!strcmp(argv[1], "verifypw")) {
642         if (argc != 3) {
643             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false);
644             return 0;
645         }
646         SLOGD("cryptfs verifypw {}");
647         rc = cryptfs_verify_passwd(argv[2]);
648     } else if (!strcmp(argv[1], "getfield")) {
649         char valbuf[PROPERTY_VALUE_MAX];
650 
651         if (argc != 3) {
652             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs getfield <fieldname>", false);
653             return 0;
654         }
655         dumpArgs(argc, argv, -1);
656         rc = cryptfs_getfield(argv[2], valbuf, sizeof(valbuf));
657         if (rc == 0) {
658             cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false);
659         }
660     } else if (!strcmp(argv[1], "setfield")) {
661         if (argc != 4) {
662             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false);
663             return 0;
664         }
665         dumpArgs(argc, argv, -1);
666         rc = cryptfs_setfield(argv[2], argv[3]);
667     } else if (!strcmp(argv[1], "mountdefaultencrypted")) {
668         SLOGD("cryptfs mountdefaultencrypted");
669         dumpArgs(argc, argv, -1);
670         rc = cryptfs_mount_default_encrypted();
671     } else if (!strcmp(argv[1], "getpwtype")) {
672         SLOGD("cryptfs getpwtype");
673         dumpArgs(argc, argv, -1);
674         switch(cryptfs_get_password_type()) {
675         case CRYPT_TYPE_PASSWORD:
676             cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false);
677             return 0;
678         case CRYPT_TYPE_PATTERN:
679             cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false);
680             return 0;
681         case CRYPT_TYPE_PIN:
682             cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false);
683             return 0;
684         case CRYPT_TYPE_DEFAULT:
685             cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false);
686             return 0;
687         default:
688           /** @TODO better error and make sure handled by callers */
689             cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false);
690             return 0;
691         }
692     } else if (!strcmp(argv[1], "getpw")) {
693         SLOGD("cryptfs getpw");
694         dumpArgs(argc, argv, -1);
695         char* password = cryptfs_get_password();
696         if (password) {
697             cli->sendMsg(ResponseCode::CommandOkay, password, false);
698             return 0;
699         }
700         rc = -1;
701     } else if (!strcmp(argv[1], "clearpw")) {
702         SLOGD("cryptfs clearpw");
703         dumpArgs(argc, argv, -1);
704         cryptfs_clear_password();
705         rc = 0;
706     } else {
707         dumpArgs(argc, argv, -1);
708         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
709         return 0;
710     }
711 
712     // Always report that the command succeeded and return the error code.
713     // The caller will check the return value to see what the error was.
714     char msg[255];
715     snprintf(msg, sizeof(msg), "%d", rc);
716     cli->sendMsg(ResponseCode::CommandOkay, msg, false);
717 
718     return 0;
719 }
720 
FstrimCmd()721 CommandListener::FstrimCmd::FstrimCmd() :
722                  VoldCommand("fstrim") {
723 }
runCommand(SocketClient * cli,int argc,char ** argv)724 int CommandListener::FstrimCmd::runCommand(SocketClient *cli,
725                                                       int argc, char **argv) {
726     if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
727         cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false);
728         return 0;
729     }
730 
731     if (argc < 2) {
732         cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
733         return 0;
734     }
735 
736     int rc = 0;
737 
738     if (!strcmp(argv[1], "dotrim")) {
739         if (argc != 2) {
740             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dotrim", false);
741             return 0;
742         }
743         dumpArgs(argc, argv, -1);
744         rc = fstrim_filesystems(0);
745     } else if (!strcmp(argv[1], "dodtrim")) {
746         if (argc != 2) {
747             cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dodtrim", false);
748             return 0;
749         }
750         dumpArgs(argc, argv, -1);
751         rc = fstrim_filesystems(1);   /* Do Deep Discard trim */
752     } else {
753         dumpArgs(argc, argv, -1);
754         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fstrim cmd", false);
755     }
756 
757     // Always report that the command succeeded and return the error code.
758     // The caller will check the return value to see what the error was.
759     char msg[255];
760     snprintf(msg, sizeof(msg), "%d", rc);
761     cli->sendMsg(ResponseCode::CommandOkay, msg, false);
762 
763     return 0;
764 }
765