CommandListener.cpp revision d9a4e358614a0c5f60cc76c0636ee4bb02004a32
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 26#define LOG_TAG "VoldCmdListener" 27#include <cutils/log.h> 28 29#include <sysutils/SocketClient.h> 30 31#include "CommandListener.h" 32#include "VolumeManager.h" 33#include "ResponseCode.h" 34#include "Process.h" 35#include "Xwarp.h" 36#include "Loop.h" 37#include "Devmapper.h" 38 39CommandListener::CommandListener() : 40 FrameworkListener("vold") { 41 registerCmd(new DumpCmd()); 42 registerCmd(new VolumeCmd()); 43 registerCmd(new AsecCmd()); 44 registerCmd(new ShareCmd()); 45 registerCmd(new StorageCmd()); 46 registerCmd(new XwarpCmd()); 47} 48 49void CommandListener::dumpArgs(int argc, char **argv, int argObscure) { 50 char buffer[4096]; 51 char *p = buffer; 52 53 memset(buffer, 0, sizeof(buffer)); 54 int i; 55 for (i = 0; i < argc; i++) { 56 int len = strlen(argv[i]) + 1; // Account for space 57 if (i == argObscure) { 58 len += 2; // Account for {} 59 } 60 if (((p - buffer) + len) < (sizeof(buffer)-1)) { 61 if (i == argObscure) { 62 *p++ = '{'; 63 *p++ = '}'; 64 *p++ = ' '; 65 continue; 66 } 67 strcpy(p, argv[i]); 68 p+= strlen(argv[i]); 69 if (i != (argc -1)) { 70 *p++ = ' '; 71 } 72 } 73 } 74 LOGD("%s", buffer); 75} 76 77CommandListener::DumpCmd::DumpCmd() : 78 VoldCommand("dump") { 79} 80 81int CommandListener::DumpCmd::runCommand(SocketClient *cli, 82 int argc, char **argv) { 83 cli->sendMsg(0, "Dumping loop status", false); 84 if (Loop::dumpState(cli)) { 85 cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true); 86 } 87 cli->sendMsg(0, "Dumping DM status", false); 88 if (Devmapper::dumpState(cli)) { 89 cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true); 90 } 91 92 cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false); 93 return 0; 94} 95 96 97CommandListener::VolumeCmd::VolumeCmd() : 98 VoldCommand("volume") { 99} 100 101int CommandListener::VolumeCmd::runCommand(SocketClient *cli, 102 int argc, char **argv) { 103 dumpArgs(argc, argv, -1); 104 105 if (argc < 2) { 106 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 107 return 0; 108 } 109 110 VolumeManager *vm = VolumeManager::Instance(); 111 int rc = 0; 112 113 if (!strcmp(argv[1], "list")) { 114 return vm->listVolumes(cli); 115 } else if (!strcmp(argv[1], "debug")) { 116 vm->setDebug(true); 117 } else if (!strcmp(argv[1], "mount")) { 118 rc = vm->mountVolume(argv[2]); 119 } else if (!strcmp(argv[1], "unmount")) { 120 bool force = false; 121 if (argc >= 4 && !strcmp(argv[3], "force")) { 122 force = true; 123 } 124 rc = vm->unmountVolume(argv[2], force); 125 } else if (!strcmp(argv[1], "format")) { 126 rc = vm->formatVolume(argv[2]); 127 } else if (!strcmp(argv[1], "share")) { 128 rc = vm->shareVolume(argv[2], argv[3]); 129 } else if (!strcmp(argv[1], "unshare")) { 130 rc = vm->unshareVolume(argv[2], argv[3]); 131 } else if (!strcmp(argv[1], "shared")) { 132 bool enabled = false; 133 134 if (vm->shareEnabled(argv[2], argv[3], &enabled)) { 135 cli->sendMsg( 136 ResponseCode::OperationFailed, "Failed to determine share enable state", true); 137 } else { 138 cli->sendMsg(ResponseCode::ShareEnabledResult, 139 (enabled ? "Share enabled" : "Share disabled"), false); 140 } 141 return 0; 142 } else { 143 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false); 144 } 145 146 if (!rc) { 147 cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false); 148 } else { 149 int erno = errno; 150 rc = ResponseCode::convertFromErrno(); 151 cli->sendMsg(rc, "volume operation failed", true); 152 } 153 154 return 0; 155} 156 157CommandListener::ShareCmd::ShareCmd() : 158 VoldCommand("share") { 159} 160 161int CommandListener::ShareCmd::runCommand(SocketClient *cli, 162 int argc, char **argv) { 163 dumpArgs(argc, argv, -1); 164 165 if (argc < 2) { 166 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 167 return 0; 168 } 169 170 VolumeManager *vm = VolumeManager::Instance(); 171 int rc = 0; 172 173 if (!strcmp(argv[1], "status")) { 174 bool avail = false; 175 176 if (vm->shareAvailable(argv[2], &avail)) { 177 cli->sendMsg( 178 ResponseCode::OperationFailed, "Failed to determine share availability", true); 179 } else { 180 cli->sendMsg(ResponseCode::ShareStatusResult, 181 (avail ? "Share available" : "Share unavailable"), false); 182 } 183 } else { 184 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown share cmd", false); 185 } 186 187 return 0; 188} 189 190CommandListener::StorageCmd::StorageCmd() : 191 VoldCommand("storage") { 192} 193 194int CommandListener::StorageCmd::runCommand(SocketClient *cli, 195 int argc, char **argv) { 196 dumpArgs(argc, argv, -1); 197 198 if (argc < 2) { 199 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 200 return 0; 201 } 202 203 if (!strcmp(argv[1], "users")) { 204 DIR *dir; 205 struct dirent *de; 206 207 if (!(dir = opendir("/proc"))) { 208 cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true); 209 return 0; 210 } 211 212 while ((de = readdir(dir))) { 213 int pid = Process::getPid(de->d_name); 214 215 if (pid < 0) { 216 continue; 217 } 218 219 char processName[255]; 220 Process::getProcessName(pid, processName, sizeof(processName)); 221 222 if (Process::checkFileDescriptorSymLinks(pid, argv[2]) || 223 Process::checkFileMaps(pid, argv[2]) || 224 Process::checkSymLink(pid, argv[2], "cwd") || 225 Process::checkSymLink(pid, argv[2], "root") || 226 Process::checkSymLink(pid, argv[2], "exe")) { 227 228 char msg[1024]; 229 snprintf(msg, sizeof(msg), "%d %s", pid, processName); 230 cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false); 231 } 232 } 233 closedir(dir); 234 cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false); 235 } else { 236 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false); 237 } 238 return 0; 239} 240 241CommandListener::AsecCmd::AsecCmd() : 242 VoldCommand("asec") { 243} 244 245int CommandListener::AsecCmd::runCommand(SocketClient *cli, 246 int argc, char **argv) { 247 if (argc < 2) { 248 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 249 return 0; 250 } 251 252 VolumeManager *vm = VolumeManager::Instance(); 253 int rc = 0; 254 255 if (!strcmp(argv[1], "list")) { 256 dumpArgs(argc, argv, -1); 257 DIR *d = opendir(Volume::SEC_ASECDIR); 258 259 if (!d) { 260 cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true); 261 return 0; 262 } 263 264 struct dirent *dent; 265 while ((dent = readdir(d))) { 266 if (dent->d_name[0] == '.') 267 continue; 268 if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) { 269 char id[255]; 270 memset(id, 0, sizeof(id)); 271 strncpy(id, dent->d_name, strlen(dent->d_name) -5); 272 cli->sendMsg(ResponseCode::AsecListResult, id, false); 273 } 274 } 275 closedir(d); 276 } else if (!strcmp(argv[1], "create")) { 277 dumpArgs(argc, argv, 5); 278 if (argc != 7) { 279 cli->sendMsg(ResponseCode::CommandSyntaxError, 280 "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false); 281 return 0; 282 } 283 284 unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512; 285 rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6])); 286 } else if (!strcmp(argv[1], "finalize")) { 287 dumpArgs(argc, argv, -1); 288 if (argc != 3) { 289 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false); 290 return 0; 291 } 292 rc = vm->finalizeAsec(argv[2]); 293 } else if (!strcmp(argv[1], "destroy")) { 294 dumpArgs(argc, argv, -1); 295 if (argc < 3) { 296 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false); 297 return 0; 298 } 299 bool force = false; 300 if (argc > 3 && !strcmp(argv[3], "force")) { 301 force = true; 302 } 303 rc = vm->destroyAsec(argv[2], force); 304 } else if (!strcmp(argv[1], "mount")) { 305 dumpArgs(argc, argv, 3); 306 if (argc != 5) { 307 cli->sendMsg(ResponseCode::CommandSyntaxError, 308 "Usage: asec mount <namespace-id> <key> <ownerUid>", false); 309 return 0; 310 } 311 rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4])); 312 } else if (!strcmp(argv[1], "unmount")) { 313 dumpArgs(argc, argv, -1); 314 if (argc < 3) { 315 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false); 316 return 0; 317 } 318 bool force = false; 319 if (argc > 3 && !strcmp(argv[3], "force")) { 320 force = true; 321 } 322 rc = vm->unmountAsec(argv[2], force); 323 } else if (!strcmp(argv[1], "rename")) { 324 dumpArgs(argc, argv, -1); 325 if (argc != 4) { 326 cli->sendMsg(ResponseCode::CommandSyntaxError, 327 "Usage: asec rename <old_id> <new_id>", false); 328 return 0; 329 } 330 rc = vm->renameAsec(argv[2], argv[3]); 331 } else if (!strcmp(argv[1], "path")) { 332 dumpArgs(argc, argv, -1); 333 if (argc != 3) { 334 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false); 335 return 0; 336 } 337 char path[255]; 338 339 if (vm->getAsecMountPath(argv[2], path, sizeof(path))) { 340 cli->sendMsg(ResponseCode::OperationFailed, "Failed to get path", true); 341 } else { 342 cli->sendMsg(ResponseCode::AsecPathResult, path, false); 343 } 344 return 0; 345 } else { 346 dumpArgs(argc, argv, -1); 347 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false); 348 } 349 350 if (!rc) { 351 cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false); 352 } else { 353 rc = ResponseCode::convertFromErrno(); 354 cli->sendMsg(rc, "asec operation failed", true); 355 } 356 357 return 0; 358} 359 360CommandListener::XwarpCmd::XwarpCmd() : 361 VoldCommand("xwarp") { 362} 363 364int CommandListener::XwarpCmd::runCommand(SocketClient *cli, 365 int argc, char **argv) { 366 if (argc < 2) { 367 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 368 return 0; 369 } 370 371 if (!strcmp(argv[1], "enable")) { 372 if (Xwarp::enable()) { 373 cli->sendMsg(ResponseCode::OperationFailed, "Failed to enable xwarp", true); 374 return 0; 375 } 376 377 cli->sendMsg(ResponseCode::CommandOkay, "Xwarp mirroring started", false); 378 } else if (!strcmp(argv[1], "disable")) { 379 if (Xwarp::disable()) { 380 cli->sendMsg(ResponseCode::OperationFailed, "Failed to disable xwarp", true); 381 return 0; 382 } 383 384 cli->sendMsg(ResponseCode::CommandOkay, "Xwarp disabled", false); 385 } else if (!strcmp(argv[1], "status")) { 386 char msg[255]; 387 bool r; 388 unsigned mirrorPos, maxSize; 389 390 if (Xwarp::status(&r, &mirrorPos, &maxSize)) { 391 cli->sendMsg(ResponseCode::OperationFailed, "Failed to get xwarp status", true); 392 return 0; 393 } 394 snprintf(msg, sizeof(msg), "%s %u %u", (r ? "ready" : "not-ready"), mirrorPos, maxSize); 395 cli->sendMsg(ResponseCode::XwarpStatusResult, msg, false); 396 } else { 397 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false); 398 } 399 400 return 0; 401} 402 403