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 <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 
     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
     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
     85 void CommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
     86 #endif
     87 
     88 CommandListener::DumpCmd::DumpCmd() :
     89                  VoldCommand("dump") {
     90 }
     91 
     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 
    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         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 
    227 CommandListener::StorageCmd::StorageCmd() :
    228                  VoldCommand("storage") {
    229 }
    230 
    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 
    294 CommandListener::AsecCmd::AsecCmd() :
    295                  VoldCommand("asec") {
    296 }
    297 
    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 
    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 
    474 CommandListener::ObbCmd::ObbCmd() :
    475                  VoldCommand("obb") {
    476 }
    477 
    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 
    538 CommandListener::CryptfsCmd::CryptfsCmd() :
    539                  VoldCommand("cryptfs") {
    540 }
    541 
    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 
    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 
    721 CommandListener::FstrimCmd::FstrimCmd() :
    722                  VoldCommand("fstrim") {
    723 }
    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