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