CommandListener.cpp 17.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdlib.h>
#include <sys/socket.h>
19
#include <sys/types.h>
20 21
#include <netinet/in.h>
#include <arpa/inet.h>
22
#include <dirent.h>
23
#include <errno.h>
San Mehat's avatar
San Mehat committed
24
#include <fcntl.h>
25
#include <string.h>
26

San Mehat's avatar
San Mehat committed
27
#define LOG_TAG "VoldCmdListener"
28 29 30 31 32 33
#include <cutils/log.h>

#include <sysutils/SocketClient.h>

#include "CommandListener.h"
#include "VolumeManager.h"
34
#include "ResponseCode.h"
35
#include "Process.h"
San Mehat's avatar
San Mehat committed
36
#include "Xwarp.h"
San Mehat's avatar
San Mehat committed
37 38
#include "Loop.h"
#include "Devmapper.h"
39
#include "cryptfs.h"
40 41 42

CommandListener::CommandListener() :
                 FrameworkListener("vold") {
San Mehat's avatar
San Mehat committed
43
    registerCmd(new DumpCmd());
San Mehat's avatar
San Mehat committed
44 45
    registerCmd(new VolumeCmd());
    registerCmd(new AsecCmd());
Kenny Root's avatar
Kenny Root committed
46
    registerCmd(new ObbCmd());
47
    registerCmd(new ShareCmd());
48
    registerCmd(new StorageCmd());
San Mehat's avatar
San Mehat committed
49
    registerCmd(new XwarpCmd());
50
    registerCmd(new CryptfsCmd());
51 52
}

San Mehat's avatar
San Mehat committed
53 54 55 56 57 58 59
void CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
    char buffer[4096];
    char *p = buffer;

    memset(buffer, 0, sizeof(buffer));
    int i;
    for (i = 0; i < argc; i++) {
60
        unsigned int len = strlen(argv[i]) + 1; // Account for space
San Mehat's avatar
San Mehat committed
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
        if (i == argObscure) {
            len += 2; // Account for {}
        }
        if (((p - buffer) + len) < (sizeof(buffer)-1)) {
            if (i == argObscure) {
                *p++ = '{';
                *p++ = '}';
                *p++ = ' ';
                continue;
            }
            strcpy(p, argv[i]);
            p+= strlen(argv[i]);
            if (i != (argc -1)) {
                *p++ = ' ';
            }
        }
    }
San Mehat's avatar
San Mehat committed
78
    SLOGD("%s", buffer);
San Mehat's avatar
San Mehat committed
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
}

CommandListener::DumpCmd::DumpCmd() :
                 VoldCommand("dump") {
}

int CommandListener::DumpCmd::runCommand(SocketClient *cli,
                                         int argc, char **argv) {
    cli->sendMsg(0, "Dumping loop status", false);
    if (Loop::dumpState(cli)) {
        cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);
    }
    cli->sendMsg(0, "Dumping DM status", false);
    if (Devmapper::dumpState(cli)) {
        cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);
    }
95 96 97 98 99 100 101 102 103 104
    cli->sendMsg(0, "Dumping mounted filesystems", false);
    FILE *fp = fopen("/proc/mounts", "r");
    if (fp) {
        char line[1024];
        while (fgets(line, sizeof(line), fp)) {
            line[strlen(line)-1] = '\0';
            cli->sendMsg(0, line, false);;
        }
        fclose(fp);
    }
San Mehat's avatar
San Mehat committed
105 106 107 108 109 110

    cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
    return 0;
}


San Mehat's avatar
San Mehat committed
111 112
CommandListener::VolumeCmd::VolumeCmd() :
                 VoldCommand("volume") {
113 114
}

San Mehat's avatar
San Mehat committed
115
int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
116
                                                      int argc, char **argv) {
San Mehat's avatar
San Mehat committed
117 118
    dumpArgs(argc, argv, -1);

San Mehat's avatar
San Mehat committed
119 120 121 122
    if (argc < 2) {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
        return 0;
    }
123

San Mehat's avatar
San Mehat committed
124 125 126 127 128
    VolumeManager *vm = VolumeManager::Instance();
    int rc = 0;

    if (!strcmp(argv[1], "list")) {
        return vm->listVolumes(cli);
San Mehat's avatar
San Mehat committed
129
    } else if (!strcmp(argv[1], "debug")) {
130 131 132 133 134
        if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);
            return 0;
        }
        vm->setDebug(!strcmp(argv[2], "on") ? true : false);
San Mehat's avatar
San Mehat committed
135
    } else if (!strcmp(argv[1], "mount")) {
136 137 138 139
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
            return 0;
        }
San Mehat's avatar
San Mehat committed
140 141
        rc = vm->mountVolume(argv[2]);
    } else if (!strcmp(argv[1], "unmount")) {
142 143 144 145 146
        if (argc < 3 || argc > 4 || (argc == 4 && strcmp(argv[3], "force"))) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force]", false);
            return 0;
        }

147 148 149 150 151
        bool force = false;
        if (argc >= 4 && !strcmp(argv[3], "force")) {
            force = true;
        }
        rc = vm->unmountVolume(argv[2], force);
San Mehat's avatar
San Mehat committed
152
    } else if (!strcmp(argv[1], "format")) {
153 154 155 156
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path>", false);
            return 0;
        }
San Mehat's avatar
San Mehat committed
157 158
        rc = vm->formatVolume(argv[2]);
    } else if (!strcmp(argv[1], "share")) {
159 160 161 162 163
        if (argc != 4) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                    "Usage: volume share <path> <method>", false);
            return 0;
        }
San Mehat's avatar
San Mehat committed
164
        rc = vm->shareVolume(argv[2], argv[3]);
San Mehat's avatar
San Mehat committed
165
    } else if (!strcmp(argv[1], "unshare")) {
166 167 168 169 170
        if (argc != 4) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                    "Usage: volume unshare <path> <method>", false);
            return 0;
        }
San Mehat's avatar
San Mehat committed
171
        rc = vm->unshareVolume(argv[2], argv[3]);
San Mehat's avatar
San Mehat committed
172 173
    } else if (!strcmp(argv[1], "shared")) {
        bool enabled = false;
174 175 176 177 178
        if (argc != 4) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                    "Usage: volume shared <path> <method>", false);
            return 0;
        }
San Mehat's avatar
San Mehat committed
179

180
        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
San Mehat's avatar
San Mehat committed
181 182 183 184 185 186
            cli->sendMsg(
                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);
        } else {
            cli->sendMsg(ResponseCode::ShareEnabledResult,
                    (enabled ? "Share enabled" : "Share disabled"), false);
        }
San Mehat's avatar
San Mehat committed
187
        return 0;
188
    } else {
San Mehat's avatar
San Mehat committed
189
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
190 191
    }

San Mehat's avatar
San Mehat committed
192 193
    if (!rc) {
        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
194
    } else {
195 196
        int erno = errno;
        rc = ResponseCode::convertFromErrno();
San Mehat's avatar
San Mehat committed
197
        cli->sendMsg(rc, "volume operation failed", true);
198 199 200 201 202 203 204 205 206 207 208
    }

    return 0;
}

CommandListener::ShareCmd::ShareCmd() :
                 VoldCommand("share") {
}

int CommandListener::ShareCmd::runCommand(SocketClient *cli,
                                                      int argc, char **argv) {
San Mehat's avatar
San Mehat committed
209 210
    dumpArgs(argc, argv, -1);

San Mehat's avatar
San Mehat committed
211 212
    if (argc < 2) {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
213 214 215
        return 0;
    }

San Mehat's avatar
San Mehat committed
216 217
    VolumeManager *vm = VolumeManager::Instance();
    int rc = 0;
218

San Mehat's avatar
San Mehat committed
219 220
    if (!strcmp(argv[1], "status")) {
        bool avail = false;
221

San Mehat's avatar
San Mehat committed
222 223 224 225 226 227 228
        if (vm->shareAvailable(argv[2], &avail)) {
            cli->sendMsg(
                    ResponseCode::OperationFailed, "Failed to determine share availability", true);
        } else {
            cli->sendMsg(ResponseCode::ShareStatusResult,
                    (avail ? "Share available" : "Share unavailable"), false);
        }
229
    } else {
San Mehat's avatar
San Mehat committed
230
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown share cmd", false);
231
    }
232 233 234 235

    return 0;
}

236 237 238 239 240 241
CommandListener::StorageCmd::StorageCmd() :
                 VoldCommand("storage") {
}

int CommandListener::StorageCmd::runCommand(SocketClient *cli,
                                                      int argc, char **argv) {
San Mehat's avatar
San Mehat committed
242 243
    dumpArgs(argc, argv, -1);

244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286
    if (argc < 2) {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
        return 0;
    }

    if (!strcmp(argv[1], "users")) {
        DIR *dir;
        struct dirent *de;

        if (!(dir = opendir("/proc"))) {
            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
            return 0;
        }

        while ((de = readdir(dir))) {
            int pid = Process::getPid(de->d_name);

            if (pid < 0) {
                continue;
            }

            char processName[255];
            Process::getProcessName(pid, processName, sizeof(processName));

            if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
                Process::checkFileMaps(pid, argv[2]) ||
                Process::checkSymLink(pid, argv[2], "cwd") ||
                Process::checkSymLink(pid, argv[2], "root") ||
                Process::checkSymLink(pid, argv[2], "exe")) {

                char msg[1024];
                snprintf(msg, sizeof(msg), "%d %s", pid, processName);
                cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
            }
        }
        closedir(dir);
        cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
    } else {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
    }
    return 0;
}

San Mehat's avatar
San Mehat committed
287 288
CommandListener::AsecCmd::AsecCmd() :
                 VoldCommand("asec") {
289 290
}

San Mehat's avatar
San Mehat committed
291 292 293 294
int CommandListener::AsecCmd::runCommand(SocketClient *cli,
                                                      int argc, char **argv) {
    if (argc < 2) {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
295 296 297
        return 0;
    }

San Mehat's avatar
San Mehat committed
298 299
    VolumeManager *vm = VolumeManager::Instance();
    int rc = 0;
300

San Mehat's avatar
San Mehat committed
301
    if (!strcmp(argv[1], "list")) {
San Mehat's avatar
San Mehat committed
302
        dumpArgs(argc, argv, -1);
303
        DIR *d = opendir(Volume::SEC_ASECDIR);
304

San Mehat's avatar
San Mehat committed
305 306 307 308
        if (!d) {
            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
            return 0;
        }
309

San Mehat's avatar
San Mehat committed
310 311 312 313 314 315 316 317 318 319 320 321 322
        struct dirent *dent;
        while ((dent = readdir(d))) {
            if (dent->d_name[0] == '.')
                continue;
            if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) {
                char id[255];
                memset(id, 0, sizeof(id));
                strncpy(id, dent->d_name, strlen(dent->d_name) -5);
                cli->sendMsg(ResponseCode::AsecListResult, id, false);
            }
        }
        closedir(d);
    } else if (!strcmp(argv[1], "create")) {
San Mehat's avatar
San Mehat committed
323
        dumpArgs(argc, argv, 5);
San Mehat's avatar
San Mehat committed
324 325 326 327
        if (argc != 7) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false);
            return 0;
328 329
        }

San Mehat's avatar
San Mehat committed
330
        unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
331
        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]));
San Mehat's avatar
San Mehat committed
332
    } else if (!strcmp(argv[1], "finalize")) {
San Mehat's avatar
San Mehat committed
333
        dumpArgs(argc, argv, -1);
San Mehat's avatar
San Mehat committed
334 335 336 337
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
            return 0;
        }
338
        rc = vm->finalizeAsec(argv[2]);
San Mehat's avatar
San Mehat committed
339
    } else if (!strcmp(argv[1], "destroy")) {
San Mehat's avatar
San Mehat committed
340
        dumpArgs(argc, argv, -1);
341 342
        if (argc < 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
San Mehat's avatar
San Mehat committed
343 344
            return 0;
        }
345 346 347 348
        bool force = false;
        if (argc > 3 && !strcmp(argv[3], "force")) {
            force = true;
        }
349
        rc = vm->destroyAsec(argv[2], force);
San Mehat's avatar
San Mehat committed
350
    } else if (!strcmp(argv[1], "mount")) {
San Mehat's avatar
San Mehat committed
351
        dumpArgs(argc, argv, 3);
San Mehat's avatar
San Mehat committed
352 353 354 355 356
        if (argc != 5) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                    "Usage: asec mount <namespace-id> <key> <ownerUid>", false);
            return 0;
        }
357
        rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]));
San Mehat's avatar
San Mehat committed
358
    } else if (!strcmp(argv[1], "unmount")) {
San Mehat's avatar
San Mehat committed
359
        dumpArgs(argc, argv, -1);
360 361
        if (argc < 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
San Mehat's avatar
San Mehat committed
362 363
            return 0;
        }
364 365 366 367
        bool force = false;
        if (argc > 3 && !strcmp(argv[3], "force")) {
            force = true;
        }
368
        rc = vm->unmountAsec(argv[2], force);
San Mehat's avatar
San Mehat committed
369
    } else if (!strcmp(argv[1], "rename")) {
San Mehat's avatar
San Mehat committed
370
        dumpArgs(argc, argv, -1);
San Mehat's avatar
San Mehat committed
371 372 373 374 375
        if (argc != 4) {
            cli->sendMsg(ResponseCode::CommandSyntaxError,
                    "Usage: asec rename <old_id> <new_id>", false);
            return 0;
        }
376
        rc = vm->renameAsec(argv[2], argv[3]);
San Mehat's avatar
San Mehat committed
377
    } else if (!strcmp(argv[1], "path")) {
San Mehat's avatar
San Mehat committed
378
        dumpArgs(argc, argv, -1);
San Mehat's avatar
San Mehat committed
379 380 381 382 383
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
            return 0;
        }
        char path[255];
384

385
        if (!(rc = vm->getAsecMountPath(argv[2], path, sizeof(path)))) {
San Mehat's avatar
San Mehat committed
386
            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
387
            return 0;
San Mehat's avatar
San Mehat committed
388
        }
389
    } else {
San Mehat's avatar
San Mehat committed
390
        dumpArgs(argc, argv, -1);
San Mehat's avatar
San Mehat committed
391
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
392 393
    }

394 395 396 397 398 399 400
    if (!rc) {
        cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
    } else {
        rc = ResponseCode::convertFromErrno();
        cli->sendMsg(rc, "asec operation failed", true);
    }

401 402
    return 0;
}
San Mehat's avatar
San Mehat committed
403

Kenny Root's avatar
Kenny Root committed
404 405
CommandListener::ObbCmd::ObbCmd() :
                 VoldCommand("obb") {
406 407
}

Kenny Root's avatar
Kenny Root committed
408
int CommandListener::ObbCmd::runCommand(SocketClient *cli,
409 410 411 412 413 414 415 416 417
                                                      int argc, char **argv) {
    if (argc < 2) {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
        return 0;
    }

    VolumeManager *vm = VolumeManager::Instance();
    int rc = 0;

Kenny Root's avatar
Kenny Root committed
418 419 420 421 422
    if (!strcmp(argv[1], "list")) {
        dumpArgs(argc, argv, -1);

        rc = vm->listMountedObbs(cli);
    } else if (!strcmp(argv[1], "mount")) {
423 424 425
            dumpArgs(argc, argv, 3);
            if (argc != 5) {
                cli->sendMsg(ResponseCode::CommandSyntaxError,
Kenny Root's avatar
Kenny Root committed
426
                        "Usage: obb mount <filename> <key> <ownerUid>", false);
427 428
                return 0;
            }
Kenny Root's avatar
Kenny Root committed
429
            rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
430 431 432
    } else if (!strcmp(argv[1], "unmount")) {
        dumpArgs(argc, argv, -1);
        if (argc < 3) {
Kenny Root's avatar
Kenny Root committed
433
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
434 435 436 437 438 439
            return 0;
        }
        bool force = false;
        if (argc > 3 && !strcmp(argv[3], "force")) {
            force = true;
        }
Kenny Root's avatar
Kenny Root committed
440 441 442 443 444 445 446 447 448 449 450 451 452
        rc = vm->unmountObb(argv[2], force);
    } else if (!strcmp(argv[1], "path")) {
        dumpArgs(argc, argv, -1);
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
            return 0;
        }
        char path[255];

        if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
            return 0;
        }
453 454
    } else {
        dumpArgs(argc, argv, -1);
Kenny Root's avatar
Kenny Root committed
455
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
456 457 458
    }

    if (!rc) {
Kenny Root's avatar
Kenny Root committed
459
        cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
460 461
    } else {
        rc = ResponseCode::convertFromErrno();
Kenny Root's avatar
Kenny Root committed
462
        cli->sendMsg(rc, "obb operation failed", true);
463 464 465 466 467
    }

    return 0;
}

San Mehat's avatar
San Mehat committed
468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509
CommandListener::XwarpCmd::XwarpCmd() :
                 VoldCommand("xwarp") {
}

int CommandListener::XwarpCmd::runCommand(SocketClient *cli,
                                                      int argc, char **argv) {
    if (argc < 2) {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
        return 0;
    }

    if (!strcmp(argv[1], "enable")) {
        if (Xwarp::enable()) {
            cli->sendMsg(ResponseCode::OperationFailed, "Failed to enable xwarp", true);
            return 0;
        }

        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp mirroring started", false);
    } else if (!strcmp(argv[1], "disable")) {
        if (Xwarp::disable()) {
            cli->sendMsg(ResponseCode::OperationFailed, "Failed to disable xwarp", true);
            return 0;
        }

        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp disabled", false);
    } else if (!strcmp(argv[1], "status")) {
        char msg[255];
        bool r;
        unsigned mirrorPos, maxSize;

        if (Xwarp::status(&r, &mirrorPos, &maxSize)) {
            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get xwarp status", true);
            return 0;
        }
        snprintf(msg, sizeof(msg), "%s %u %u", (r ? "ready" : "not-ready"), mirrorPos, maxSize);
        cli->sendMsg(ResponseCode::XwarpStatusResult, msg, false);
    } else {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
    }

    return 0;
}
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552

CommandListener::CryptfsCmd::CryptfsCmd() :
                 VoldCommand("cryptfs") {
}

int CommandListener::CryptfsCmd::runCommand(SocketClient *cli,
                                                      int argc, char **argv) {
    dumpArgs(argc, argv, -1);

    if (argc < 2) {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
        return 0;
    }

    int rc = 0;

    if (!strcmp(argv[1], "checkpw")) {
        if (argc != 3) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs checkpw <passwd>", false);
            return 0;
        }
        rc = cryptfs_check_passwd(argv[2]);
    } else if (!strcmp(argv[1], "enablecrypto")) {
        if ( (argc != 4) || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) {
            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs enablecrypto <wipe|inplace> <passwd>", false);
            return 0;
        }
        rc = cryptfs_enable(argv[2], argv[3]);
    } else {
        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false);
    }

    if (!rc) {
        cli->sendMsg(ResponseCode::CommandOkay, "cryptfs operation succeeded", false);
    } else {
        int erno = errno;
        rc = ResponseCode::convertFromErrno();
        cli->sendMsg(rc, "cryptfs operation failed", true);
    }

    return 0;
}