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