CommandListener.cpp revision 4ba8948dc16463053e21cda5744f519a555080d0
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 25#define LOG_TAG "CommandListener" 26#include <cutils/log.h> 27 28#include <sysutils/SocketClient.h> 29 30#include "CommandListener.h" 31#include "VolumeManager.h" 32#include "ResponseCode.h" 33#include "Process.h" 34 35CommandListener::CommandListener() : 36 FrameworkListener("vold") { 37 registerCmd(new VolumeCmd()); 38 registerCmd(new AsecCmd()); 39 registerCmd(new ShareCmd()); 40 registerCmd(new StorageCmd()); 41} 42 43CommandListener::VolumeCmd::VolumeCmd() : 44 VoldCommand("volume") { 45} 46 47int CommandListener::VolumeCmd::runCommand(SocketClient *cli, 48 int argc, char **argv) { 49 if (argc < 2) { 50 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 51 return 0; 52 } 53 54 VolumeManager *vm = VolumeManager::Instance(); 55 int rc = 0; 56 57 if (!strcmp(argv[1], "list")) { 58 return vm->listVolumes(cli); 59 } else if (!strcmp(argv[1], "mount")) { 60 rc = vm->mountVolume(argv[2]); 61 } else if (!strcmp(argv[1], "unmount")) { 62 bool force = false; 63 if (argc >= 4 && !strcmp(argv[3], "force")) { 64 force = true; 65 } 66 rc = vm->unmountVolume(argv[2], force); 67 } else if (!strcmp(argv[1], "format")) { 68 rc = vm->formatVolume(argv[2]); 69 } else if (!strcmp(argv[1], "share")) { 70 rc = vm->shareVolume(argv[2], argv[3]); 71 } else if (!strcmp(argv[1], "unshare")) { 72 rc = vm->unshareVolume(argv[2], argv[3]); 73 } else if (!strcmp(argv[1], "shared")) { 74 bool enabled = false; 75 76 if (vm->shareEnabled(argv[2], argv[3], &enabled)) { 77 cli->sendMsg( 78 ResponseCode::OperationFailed, "Failed to determine share enable state", true); 79 } else { 80 cli->sendMsg(ResponseCode::ShareEnabledResult, 81 (enabled ? "Share enabled" : "Share disabled"), false); 82 } 83 return 0; 84 } else { 85 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false); 86 } 87 88 if (!rc) { 89 cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false); 90 } else { 91 /* 92 * Failed 93 */ 94 if (errno == ENODEV) { 95 rc = ResponseCode::OpFailedNoMedia; 96 } else if (errno == ENODATA) { 97 rc = ResponseCode::OpFailedMediaBlank; 98 } else if (errno == EIO) { 99 rc = ResponseCode::OpFailedMediaCorrupt; 100 } else if (errno == EBUSY) { 101 rc = ResponseCode::OpFailedVolBusy; 102 } else { 103 LOGW("Returning OperationFailed - no handler for errno %d", errno); 104 rc = ResponseCode::OperationFailed; 105 } 106 cli->sendMsg(rc, "volume operation failed", true); 107 } 108 109 return 0; 110} 111 112CommandListener::ShareCmd::ShareCmd() : 113 VoldCommand("share") { 114} 115 116int CommandListener::ShareCmd::runCommand(SocketClient *cli, 117 int argc, char **argv) { 118 if (argc < 2) { 119 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 120 return 0; 121 } 122 123 VolumeManager *vm = VolumeManager::Instance(); 124 int rc = 0; 125 126 if (!strcmp(argv[1], "status")) { 127 bool avail = false; 128 129 if (vm->shareAvailable(argv[2], &avail)) { 130 cli->sendMsg( 131 ResponseCode::OperationFailed, "Failed to determine share availability", true); 132 } else { 133 cli->sendMsg(ResponseCode::ShareStatusResult, 134 (avail ? "Share available" : "Share unavailable"), false); 135 } 136 } else { 137 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown share cmd", false); 138 } 139 140 return 0; 141} 142 143CommandListener::StorageCmd::StorageCmd() : 144 VoldCommand("storage") { 145} 146 147int CommandListener::StorageCmd::runCommand(SocketClient *cli, 148 int argc, char **argv) { 149 if (argc < 2) { 150 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 151 return 0; 152 } 153 154 if (!strcmp(argv[1], "users")) { 155 DIR *dir; 156 struct dirent *de; 157 158 if (!(dir = opendir("/proc"))) { 159 cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true); 160 return 0; 161 } 162 163 while ((de = readdir(dir))) { 164 int pid = Process::getPid(de->d_name); 165 166 if (pid < 0) { 167 continue; 168 } 169 170 char processName[255]; 171 Process::getProcessName(pid, processName, sizeof(processName)); 172 173 if (Process::checkFileDescriptorSymLinks(pid, argv[2]) || 174 Process::checkFileMaps(pid, argv[2]) || 175 Process::checkSymLink(pid, argv[2], "cwd") || 176 Process::checkSymLink(pid, argv[2], "root") || 177 Process::checkSymLink(pid, argv[2], "exe")) { 178 179 char msg[1024]; 180 snprintf(msg, sizeof(msg), "%d %s", pid, processName); 181 cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false); 182 } 183 } 184 closedir(dir); 185 cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false); 186 } else { 187 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false); 188 } 189 return 0; 190} 191 192CommandListener::AsecCmd::AsecCmd() : 193 VoldCommand("asec") { 194} 195 196int CommandListener::AsecCmd::runCommand(SocketClient *cli, 197 int argc, char **argv) { 198 if (argc < 2) { 199 cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false); 200 return 0; 201 } 202 203 VolumeManager *vm = VolumeManager::Instance(); 204 int rc = 0; 205 206 if (!strcmp(argv[1], "list")) { 207 DIR *d = opendir("/sdcard/android_secure"); 208 209 if (!d) { 210 cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true); 211 return 0; 212 } 213 214 struct dirent *dent; 215 while ((dent = readdir(d))) { 216 if (dent->d_name[0] == '.') 217 continue; 218 if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) { 219 char id[255]; 220 memset(id, 0, sizeof(id)); 221 strncpy(id, dent->d_name, strlen(dent->d_name) -5); 222 cli->sendMsg(ResponseCode::AsecListResult, id, false); 223 } 224 } 225 closedir(d); 226 cli->sendMsg(ResponseCode::CommandOkay, "ASEC listing complete", false); 227 } else if (!strcmp(argv[1], "create")) { 228 if (argc != 7) { 229 cli->sendMsg(ResponseCode::CommandSyntaxError, 230 "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false); 231 return 0; 232 } 233 234 unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512; 235 if (vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]))) { 236 cli->sendMsg(ResponseCode::OperationFailed, "Container creation failed", true); 237 } else { 238 cli->sendMsg(ResponseCode::CommandOkay, "Container created", false); 239 } 240 } else if (!strcmp(argv[1], "finalize")) { 241 if (argc != 3) { 242 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false); 243 return 0; 244 } 245 if (vm->finalizeAsec(argv[2])) { 246 cli->sendMsg(ResponseCode::OperationFailed, "Container finalize failed", true); 247 } else { 248 cli->sendMsg(ResponseCode::CommandOkay, "Container finalized", false); 249 } 250 } else if (!strcmp(argv[1], "destroy")) { 251 if (argc < 3) { 252 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false); 253 return 0; 254 } 255 bool force = false; 256 if (argc > 3 && !strcmp(argv[3], "force")) { 257 force = true; 258 } 259 if (vm->destroyAsec(argv[2], force)) { 260 cli->sendMsg(ResponseCode::OperationFailed, "Container destroy failed", true); 261 } else { 262 cli->sendMsg(ResponseCode::CommandOkay, "Container destroyed", false); 263 } 264 } else if (!strcmp(argv[1], "mount")) { 265 if (argc != 5) { 266 cli->sendMsg(ResponseCode::CommandSyntaxError, 267 "Usage: asec mount <namespace-id> <key> <ownerUid>", false); 268 return 0; 269 } 270 271 int rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4])); 272 273 if (rc < 0) { 274 cli->sendMsg(ResponseCode::OperationFailed, "Mount failed", true); 275 } else { 276 cli->sendMsg(ResponseCode::CommandOkay, "Mount succeeded", false); 277 } 278 } else if (!strcmp(argv[1], "unmount")) { 279 if (argc < 3) { 280 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false); 281 return 0; 282 } 283 bool force = false; 284 if (argc > 3 && !strcmp(argv[3], "force")) { 285 force = true; 286 } 287 if (vm->unmountAsec(argv[2], force)) { 288 cli->sendMsg(ResponseCode::OperationFailed, "Container unmount failed", true); 289 } else { 290 cli->sendMsg(ResponseCode::CommandOkay, "Container unmounted", false); 291 } 292 } else if (!strcmp(argv[1], "rename")) { 293 if (argc != 4) { 294 cli->sendMsg(ResponseCode::CommandSyntaxError, 295 "Usage: asec rename <old_id> <new_id>", false); 296 return 0; 297 } 298 if (vm->renameAsec(argv[2], argv[3])) { 299 cli->sendMsg(ResponseCode::OperationFailed, "Container rename failed", true); 300 } else { 301 cli->sendMsg(ResponseCode::CommandOkay, "Container renamed", false); 302 } 303 } else if (!strcmp(argv[1], "path")) { 304 if (argc != 3) { 305 cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false); 306 return 0; 307 } 308 char path[255]; 309 310 if (vm->getAsecMountPath(argv[2], path, sizeof(path))) { 311 cli->sendMsg(ResponseCode::OperationFailed, "Failed to get path", true); 312 } else { 313 cli->sendMsg(ResponseCode::AsecPathResult, path, false); 314 } 315 } else { 316 cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false); 317 } 318 319 return 0; 320} 321