Home | History | Annotate | Download | only in vold
      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 
     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 
     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 
     87 CommandListener::DumpCmd::DumpCmd() :
     88                  VoldCommand("dump") {
     89 }
     90 
     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 
    117 CommandListener::VolumeCmd::VolumeCmd() :
    118                  VoldCommand("volume") {
    119 }
    120 
    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 
    226 CommandListener::StorageCmd::StorageCmd() :
    227                  VoldCommand("storage") {
    228 }
    229 
    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 
    277 CommandListener::AsecCmd::AsecCmd() :
    278                  VoldCommand("asec") {
    279 }
    280 
    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 
    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 
    445 CommandListener::ObbCmd::ObbCmd() :
    446                  VoldCommand("obb") {
    447 }
    448 
    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 
    509 CommandListener::XwarpCmd::XwarpCmd() :
    510                  VoldCommand("xwarp") {
    511 }
    512 
    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 
    552 CommandListener::CryptfsCmd::CryptfsCmd() :
    553                  VoldCommand("cryptfs") {
    554 }
    555 
    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 
    645 CommandListener::FstrimCmd::FstrimCmd() :
    646                  VoldCommand("fstrim") {
    647 }
    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