CommandListener.cpp revision 6c78e7d7724a431dbdb2b0a5bb8cd2b07424cbe5
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 45CommandListener::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 57void 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 85void CommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { } 86#endif 87 88CommandListener::DumpCmd::DumpCmd() : 89 VoldCommand("dump") { 90} 91 92int 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 117CommandListener::VolumeCmd::VolumeCmd() : 118 VoldCommand("volume") { 119} 120 121int 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 rc = ResponseCode::convertFromErrno(); 220 cli->sendMsg(rc, "volume operation failed", true); 221 } 222 223 return 0; 224} 225 226CommandListener::StorageCmd::StorageCmd() : 227 VoldCommand("storage") { 228} 229 230int CommandListener::StorageCmd::runCommand(SocketClient *cli, 231 int argc, char **argv) { 232 /* Guarantied to be initialized by vold's main() before the CommandListener is active */ 233 extern struct fstab *fstab; 234 235 dumpArgs(argc, argv, -1); 236 237 if (argc < 2) { 238 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 239 return 0; 240 } 241 242 if (!strcmp(argv[1], "mountall")) { 243 if (argc != 2) { 244 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: mountall", false); 245 return 0; 246 } 247 fs_mgr_mount_all(fstab); 248 cli->sendMsg(ResponseCode::CommandOkay, "Mountall ran successfully", false); 249 return 0; 250 } 251 if (!strcmp(argv[1], "users")) { 252 DIR *dir; 253 struct dirent *de; 254 255 if (argc < 3) { 256 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument: user <mountpoint>", false); 257 return 0; 258 } 259 if (!(dir = opendir("/proc"))) { 260 cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true); 261 return 0; 262 } 263 264 while ((de = readdir(dir))) { 265 int pid = Process::getPid(de->d_name); 266 267 if (pid < 0) { 268 continue; 269 } 270 271 char processName[255]; 272 Process::getProcessName(pid, processName, sizeof(processName)); 273 274 if (Process::checkFileDescriptorSymLinks(pid, argv[2]) || 275 Process::checkFileMaps(pid, argv[2]) || 276 Process::checkSymLink(pid, argv[2], "cwd") || 277 Process::checkSymLink(pid, argv[2], "root") || 278 Process::checkSymLink(pid, argv[2], "exe")) { 279 280 char msg[1024]; 281 snprintf(msg, sizeof(msg), "%d %s", pid, processName); 282 cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false); 283 } 284 } 285 closedir(dir); 286 cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false); 287 } else { 288 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false); 289 } 290 return 0; 291} 292 293CommandListener::AsecCmd::AsecCmd() : 294 VoldCommand("asec") { 295} 296 297void CommandListener::AsecCmd::listAsecsInDirectory(SocketClient *cli, const char *directory) { 298 DIR *d = opendir(directory); 299 300 if (!d) { 301 cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true); 302 return; 303 } 304 305 size_t dirent_len = offsetof(struct dirent, d_name) + 306 fpathconf(dirfd(d), _PC_NAME_MAX) + 1; 307 308 struct dirent *dent = (struct dirent *) malloc(dirent_len); 309 if (dent == NULL) { 310 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", true); 311 return; 312 } 313 314 struct dirent *result; 315 316 while (!readdir_r(d, dent, &result) && result != NULL) { 317 if (dent->d_name[0] == '.') 318 continue; 319 if (dent->d_type != DT_REG) 320 continue; 321 size_t name_len = strlen(dent->d_name); 322 if (name_len > 5 && name_len < 260 && 323 !strcmp(&dent->d_name[name_len - 5], ".asec")) { 324 char id[255]; 325 memset(id, 0, sizeof(id)); 326 strlcpy(id, dent->d_name, name_len - 4); 327 cli->sendMsg(ResponseCode::AsecListResult, id, false); 328 } 329 } 330 closedir(d); 331 332 free(dent); 333} 334 335int CommandListener::AsecCmd::runCommand(SocketClient *cli, 336 int argc, char **argv) { 337 if (argc < 2) { 338 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 339 return 0; 340 } 341 342 VolumeManager *vm = VolumeManager::Instance(); 343 int rc = 0; 344 345 if (!strcmp(argv[1], "list")) { 346 dumpArgs(argc, argv, -1); 347 348 listAsecsInDirectory(cli, Volume::SEC_ASECDIR_EXT); 349 listAsecsInDirectory(cli, Volume::SEC_ASECDIR_INT); 350 } else if (!strcmp(argv[1], "create")) { 351 dumpArgs(argc, argv, 5); 352 if (argc != 8) { 353 cli->sendMsg(ResponseCode::CommandSyntaxError, 354 "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid> " 355 "<isExternal>", false); 356 return 0; 357 } 358 359 unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512; 360 const bool isExternal = (atoi(argv[7]) == 1); 361 rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]), isExternal); 362 } else if (!strcmp(argv[1], "resize")) { 363 dumpArgs(argc, argv, -1); 364 if (argc != 5) { 365 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec resize <container-id> <size_mb> <key>", false); 366 return 0; 367 } 368 unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512; 369 rc = vm->resizeAsec(argv[2], numSectors, argv[4]); 370 } else if (!strcmp(argv[1], "finalize")) { 371 dumpArgs(argc, argv, -1); 372 if (argc != 3) { 373 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false); 374 return 0; 375 } 376 rc = vm->finalizeAsec(argv[2]); 377 } else if (!strcmp(argv[1], "fixperms")) { 378 dumpArgs(argc, argv, -1); 379 if (argc != 5) { 380 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false); 381 return 0; 382 } 383 384 char *endptr; 385 gid_t gid = (gid_t) strtoul(argv[3], &endptr, 10); 386 if (*endptr != '\0') { 387 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false); 388 return 0; 389 } 390 391 rc = vm->fixupAsecPermissions(argv[2], gid, argv[4]); 392 } else if (!strcmp(argv[1], "destroy")) { 393 dumpArgs(argc, argv, -1); 394 if (argc < 3) { 395 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false); 396 return 0; 397 } 398 bool force = false; 399 if (argc > 3 && !strcmp(argv[3], "force")) { 400 force = true; 401 } 402 rc = vm->destroyAsec(argv[2], force); 403 } else if (!strcmp(argv[1], "mount")) { 404 dumpArgs(argc, argv, 3); 405 if (argc != 6) { 406 cli->sendMsg(ResponseCode::CommandSyntaxError, 407 "Usage: asec mount <namespace-id> <key> <ownerUid> <ro|rw>", false); 408 return 0; 409 } 410 bool readOnly = true; 411 if (!strcmp(argv[5], "rw")) { 412 readOnly = false; 413 } 414 rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]), readOnly); 415 } else if (!strcmp(argv[1], "unmount")) { 416 dumpArgs(argc, argv, -1); 417 if (argc < 3) { 418 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false); 419 return 0; 420 } 421 bool force = false; 422 if (argc > 3 && !strcmp(argv[3], "force")) { 423 force = true; 424 } 425 rc = vm->unmountAsec(argv[2], force); 426 } else if (!strcmp(argv[1], "rename")) { 427 dumpArgs(argc, argv, -1); 428 if (argc != 4) { 429 cli->sendMsg(ResponseCode::CommandSyntaxError, 430 "Usage: asec rename <old_id> <new_id>", false); 431 return 0; 432 } 433 rc = vm->renameAsec(argv[2], argv[3]); 434 } else if (!strcmp(argv[1], "path")) { 435 dumpArgs(argc, argv, -1); 436 if (argc != 3) { 437 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false); 438 return 0; 439 } 440 char path[255]; 441 442 if (!(rc = vm->getAsecMountPath(argv[2], path, sizeof(path)))) { 443 cli->sendMsg(ResponseCode::AsecPathResult, path, false); 444 return 0; 445 } 446 } else if (!strcmp(argv[1], "fspath")) { 447 dumpArgs(argc, argv, -1); 448 if (argc != 3) { 449 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fspath <container-id>", false); 450 return 0; 451 } 452 char path[255]; 453 454 if (!(rc = vm->getAsecFilesystemPath(argv[2], path, sizeof(path)))) { 455 cli->sendMsg(ResponseCode::AsecPathResult, path, false); 456 return 0; 457 } 458 } else { 459 dumpArgs(argc, argv, -1); 460 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false); 461 } 462 463 if (!rc) { 464 cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false); 465 } else { 466 rc = ResponseCode::convertFromErrno(); 467 cli->sendMsg(rc, "asec operation failed", true); 468 } 469 470 return 0; 471} 472 473CommandListener::ObbCmd::ObbCmd() : 474 VoldCommand("obb") { 475} 476 477int CommandListener::ObbCmd::runCommand(SocketClient *cli, 478 int argc, char **argv) { 479 if (argc < 2) { 480 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 481 return 0; 482 } 483 484 VolumeManager *vm = VolumeManager::Instance(); 485 int rc = 0; 486 487 if (!strcmp(argv[1], "list")) { 488 dumpArgs(argc, argv, -1); 489 490 rc = vm->listMountedObbs(cli); 491 } else if (!strcmp(argv[1], "mount")) { 492 dumpArgs(argc, argv, 3); 493 if (argc != 5) { 494 cli->sendMsg(ResponseCode::CommandSyntaxError, 495 "Usage: obb mount <filename> <key> <ownerGid>", false); 496 return 0; 497 } 498 rc = vm->mountObb(argv[2], argv[3], atoi(argv[4])); 499 } else if (!strcmp(argv[1], "unmount")) { 500 dumpArgs(argc, argv, -1); 501 if (argc < 3) { 502 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false); 503 return 0; 504 } 505 bool force = false; 506 if (argc > 3 && !strcmp(argv[3], "force")) { 507 force = true; 508 } 509 rc = vm->unmountObb(argv[2], force); 510 } else if (!strcmp(argv[1], "path")) { 511 dumpArgs(argc, argv, -1); 512 if (argc != 3) { 513 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false); 514 return 0; 515 } 516 char path[255]; 517 518 if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) { 519 cli->sendMsg(ResponseCode::AsecPathResult, path, false); 520 return 0; 521 } 522 } else { 523 dumpArgs(argc, argv, -1); 524 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false); 525 } 526 527 if (!rc) { 528 cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false); 529 } else { 530 rc = ResponseCode::convertFromErrno(); 531 cli->sendMsg(rc, "obb operation failed", true); 532 } 533 534 return 0; 535} 536 537CommandListener::CryptfsCmd::CryptfsCmd() : 538 VoldCommand("cryptfs") { 539} 540 541static int getType(const char* type) 542{ 543 if (!strcmp(type, "default")) { 544 return CRYPT_TYPE_DEFAULT; 545 } else if (!strcmp(type, "password")) { 546 return CRYPT_TYPE_PASSWORD; 547 } else if (!strcmp(type, "pin")) { 548 return CRYPT_TYPE_PIN; 549 } else if (!strcmp(type, "pattern")) { 550 return CRYPT_TYPE_PATTERN; 551 } else { 552 return -1; 553 } 554} 555 556int 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 const char* syntax = "Usage: cryptfs enablecrypto <wipe|inplace> " 593 "default|password|pin|pattern [passwd]"; 594 if ( (argc != 4 && argc != 5) 595 || (strcmp(argv[2], "wipe") && strcmp(argv[2], "inplace")) ) { 596 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false); 597 return 0; 598 } 599 dumpArgs(argc, argv, 4); 600 601 int tries; 602 for (tries = 0; tries < 2; ++tries) { 603 int type = getType(argv[3]); 604 if (type == -1) { 605 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, 606 false); 607 return 0; 608 } else if (type == CRYPT_TYPE_DEFAULT) { 609 rc = cryptfs_enable_default(argv[2], /*allow_reboot*/false); 610 } else { 611 rc = cryptfs_enable(argv[2], type, argv[4], 612 /*allow_reboot*/false); 613 } 614 615 if (rc == 0) { 616 break; 617 } else if (tries == 0) { 618 Process::killProcessesWithOpenFiles(DATA_MNT_POINT, 2); 619 } 620 } 621 } else if (!strcmp(argv[1], "changepw")) { 622 const char* syntax = "Usage: cryptfs changepw " 623 "default|password|pin|pattern [newpasswd]"; 624 const char* password; 625 if (argc == 3) { 626 password = ""; 627 } else if (argc == 4) { 628 password = argv[3]; 629 } else { 630 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false); 631 return 0; 632 } 633 int type = getType(argv[2]); 634 if (type == -1) { 635 cli->sendMsg(ResponseCode::CommandSyntaxError, syntax, false); 636 return 0; 637 } 638 SLOGD("cryptfs changepw %s {}", argv[2]); 639 rc = cryptfs_changepw(type, password); 640 } else if (!strcmp(argv[1], "verifypw")) { 641 if (argc != 3) { 642 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs verifypw <passwd>", false); 643 return 0; 644 } 645 SLOGD("cryptfs verifypw {}"); 646 rc = cryptfs_verify_passwd(argv[2]); 647 } else if (!strcmp(argv[1], "getfield")) { 648 char *valbuf; 649 int valbuf_len = 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 657 // Increase the buffer size until it is big enough for the field value stored. 658 while (1) { 659 valbuf = (char*)malloc(valbuf_len); 660 if (valbuf == NULL) { 661 cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", false); 662 return 0; 663 } 664 rc = cryptfs_getfield(argv[2], valbuf, valbuf_len); 665 if (rc != CRYPTO_GETFIELD_ERROR_BUF_TOO_SMALL) { 666 break; 667 } 668 free(valbuf); 669 valbuf_len *= 2; 670 } 671 if (rc == CRYPTO_GETFIELD_OK) { 672 cli->sendMsg(ResponseCode::CryptfsGetfieldResult, valbuf, false); 673 } 674 free(valbuf); 675 } else if (!strcmp(argv[1], "setfield")) { 676 if (argc != 4) { 677 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: cryptfs setfield <fieldname> <value>", false); 678 return 0; 679 } 680 dumpArgs(argc, argv, -1); 681 rc = cryptfs_setfield(argv[2], argv[3]); 682 } else if (!strcmp(argv[1], "mountdefaultencrypted")) { 683 SLOGD("cryptfs mountdefaultencrypted"); 684 dumpArgs(argc, argv, -1); 685 rc = cryptfs_mount_default_encrypted(); 686 } else if (!strcmp(argv[1], "getpwtype")) { 687 SLOGD("cryptfs getpwtype"); 688 dumpArgs(argc, argv, -1); 689 switch(cryptfs_get_password_type()) { 690 case CRYPT_TYPE_PASSWORD: 691 cli->sendMsg(ResponseCode::PasswordTypeResult, "password", false); 692 return 0; 693 case CRYPT_TYPE_PATTERN: 694 cli->sendMsg(ResponseCode::PasswordTypeResult, "pattern", false); 695 return 0; 696 case CRYPT_TYPE_PIN: 697 cli->sendMsg(ResponseCode::PasswordTypeResult, "pin", false); 698 return 0; 699 case CRYPT_TYPE_DEFAULT: 700 cli->sendMsg(ResponseCode::PasswordTypeResult, "default", false); 701 return 0; 702 default: 703 /** @TODO better error and make sure handled by callers */ 704 cli->sendMsg(ResponseCode::OpFailedStorageNotFound, "Error", false); 705 return 0; 706 } 707 } else if (!strcmp(argv[1], "getpw")) { 708 SLOGD("cryptfs getpw"); 709 dumpArgs(argc, argv, -1); 710 char* password = cryptfs_get_password(); 711 if (password) { 712 char* message = 0; 713 int size = asprintf(&message, "{{sensitive}} %s", password); 714 if (size != -1) { 715 cli->sendMsg(ResponseCode::CommandOkay, message, false); 716 memset(message, 0, size); 717 free (message); 718 return 0; 719 } 720 } 721 rc = -1; 722 } else if (!strcmp(argv[1], "clearpw")) { 723 SLOGD("cryptfs clearpw"); 724 dumpArgs(argc, argv, -1); 725 cryptfs_clear_password(); 726 rc = 0; 727 } else { 728 dumpArgs(argc, argv, -1); 729 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown cryptfs cmd", false); 730 return 0; 731 } 732 733 // Always report that the command succeeded and return the error code. 734 // The caller will check the return value to see what the error was. 735 char msg[255]; 736 snprintf(msg, sizeof(msg), "%d", rc); 737 cli->sendMsg(ResponseCode::CommandOkay, msg, false); 738 739 return 0; 740} 741 742CommandListener::FstrimCmd::FstrimCmd() : 743 VoldCommand("fstrim") { 744} 745int CommandListener::FstrimCmd::runCommand(SocketClient *cli, 746 int argc, char **argv) { 747 if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) { 748 cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false); 749 return 0; 750 } 751 752 if (argc < 2) { 753 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 754 return 0; 755 } 756 757 int rc = 0; 758 759 if (!strcmp(argv[1], "dotrim")) { 760 if (argc != 2) { 761 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dotrim", false); 762 return 0; 763 } 764 dumpArgs(argc, argv, -1); 765 rc = fstrim_filesystems(0); 766 } else if (!strcmp(argv[1], "dodtrim")) { 767 if (argc != 2) { 768 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: fstrim dodtrim", false); 769 return 0; 770 } 771 dumpArgs(argc, argv, -1); 772 rc = fstrim_filesystems(1); /* Do Deep Discard trim */ 773 } else { 774 dumpArgs(argc, argv, -1); 775 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown fstrim cmd", false); 776 } 777 778 // Always report that the command succeeded and return the error code. 779 // The caller will check the return value to see what the error was. 780 char msg[255]; 781 snprintf(msg, sizeof(msg), "%d", rc); 782 cli->sendMsg(ResponseCode::CommandOkay, msg, false); 783 784 return 0; 785} 786