CommandListener.cpp revision 37dcda68d334f70e1f7f69a9817def65fe3ee717
14f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber/*
24f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * Copyright (C) 2008 The Android Open Source Project
34f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber *
44f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * Licensed under the Apache License, Version 2.0 (the "License");
54f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * you may not use this file except in compliance with the License.
64f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * You may obtain a copy of the License at
74f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber *
84f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber *      http://www.apache.org/licenses/LICENSE-2.0
94f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber *
104f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * Unless required by applicable law or agreed to in writing, software
114f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * distributed under the License is distributed on an "AS IS" BASIS,
124f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * See the License for the specific language governing permissions and
144f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber * limitations under the License.
154f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber */
164f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
174f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <stdlib.h>
184f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <sys/socket.h>
194f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <sys/types.h>
204f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <netinet/in.h>
214f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <arpa/inet.h>
224f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <dirent.h>
234f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <errno.h>
244f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <fcntl.h>
254f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <string.h>
264f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
274f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#define LOG_TAG "VoldCmdListener"
284f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <cutils/log.h>
294f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
304f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include <sysutils/SocketClient.h>
314f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
324f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include "CommandListener.h"
334f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include "VolumeManager.h"
344f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include "ResponseCode.h"
354f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include "Process.h"
364f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include "Xwarp.h"
374f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include "Loop.h"
384f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber#include "Devmapper.h"
394f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
404f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas HuberCommandListener::CommandListener() :
414f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                 FrameworkListener("vold") {
424f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    registerCmd(new DumpCmd());
434f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    registerCmd(new VolumeCmd());
444f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    registerCmd(new AsecCmd());
454f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    registerCmd(new ObbCmd());
464f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    registerCmd(new ShareCmd());
474f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    registerCmd(new StorageCmd());
484f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    registerCmd(new XwarpCmd());
494f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber}
504f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
514f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Hubervoid CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
524f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    char buffer[4096];
534f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    char *p = buffer;
544f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
554f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    memset(buffer, 0, sizeof(buffer));
564f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    int i;
574f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    for (i = 0; i < argc; i++) {
584f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        int len = strlen(argv[i]) + 1; // Account for space
594f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (i == argObscure) {
604f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            len += 2; // Account for {}
614f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
624f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (((p - buffer) + len) < (sizeof(buffer)-1)) {
634f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            if (i == argObscure) {
644f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                *p++ = '{';
654f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                *p++ = '}';
664f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                *p++ = ' ';
674f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                continue;
684f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            }
694f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            strcpy(p, argv[i]);
704f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            p+= strlen(argv[i]);
714f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            if (i != (argc -1)) {
724f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                *p++ = ' ';
734f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            }
744f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
754f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
764f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    SLOGD("%s", buffer);
774f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber}
784f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
794f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas HuberCommandListener::DumpCmd::DumpCmd() :
804f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                 VoldCommand("dump") {
814f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber}
824f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
834f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberint CommandListener::DumpCmd::runCommand(SocketClient *cli,
844f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                                         int argc, char **argv) {
854f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    cli->sendMsg(0, "Dumping loop status", false);
864f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    if (Loop::dumpState(cli)) {
874f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);
884f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
894f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    cli->sendMsg(0, "Dumping DM status", false);
904f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    if (Devmapper::dumpState(cli)) {
914f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);
924f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
934f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    cli->sendMsg(0, "Dumping mounted filesystems", false);
944f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    FILE *fp = fopen("/proc/mounts", "r");
954f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    if (fp) {
964f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        char line[1024];
974f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        while (fgets(line, sizeof(line), fp)) {
984f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            line[strlen(line)-1] = '\0';
994f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cli->sendMsg(0, line, false);;
1004f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1014f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        fclose(fp);
1024f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
1034f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1044f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
1054f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    return 0;
1064f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber}
1074f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1084f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1094f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas HuberCommandListener::VolumeCmd::VolumeCmd() :
1104f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                 VoldCommand("volume") {
1114f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber}
1124f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1134f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberint CommandListener::VolumeCmd::runCommand(SocketClient *cli,
1144f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                                                      int argc, char **argv) {
1154f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    dumpArgs(argc, argv, -1);
1164f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1174f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    if (argc < 2) {
1184f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
1194f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        return 0;
1204f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
1214f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1224f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    VolumeManager *vm = VolumeManager::Instance();
1234f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    int rc = 0;
1244f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1254f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    if (!strcmp(argv[1], "list")) {
1264f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        return vm->listVolumes(cli);
1274f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    } else if (!strcmp(argv[1], "debug")) {
1284f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (argc != 3 || (argc == 3 && (strcmp(argv[2], "off") && strcmp(argv[2], "on")))) {
1294f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume debug <off/on>", false);
1304f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return 0;
1314f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1324f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        vm->setDebug(!strcmp(argv[2], "on") ? true : false);
1334f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    } else if (!strcmp(argv[1], "mount")) {
1344f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (argc != 3) {
1354f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume mount <path>", false);
1364f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return 0;
1374f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1384f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        rc = vm->mountVolume(argv[2]);
1394f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    } else if (!strcmp(argv[1], "unmount")) {
1404f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (argc < 3 || argc > 4 || (argc == 4 && strcmp(argv[3], "force"))) {
1414f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume unmount <path> [force]", false);
1424f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return 0;
1434f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1444f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1454f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        bool force = false;
1464f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (argc >= 4 && !strcmp(argv[3], "force")) {
1474f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            force = true;
1484f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1494f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        rc = vm->unmountVolume(argv[2], force);
1504f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    } else if (!strcmp(argv[1], "format")) {
1514f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (argc != 3) {
1524f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: volume format <path>", false);
1534f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return 0;
1544f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1554f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        rc = vm->formatVolume(argv[2]);
1564f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    } else if (!strcmp(argv[1], "share")) {
1574f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (argc != 4) {
1584f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cli->sendMsg(ResponseCode::CommandSyntaxError,
1594f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    "Usage: volume share <path> <method>", false);
1604f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return 0;
1614f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1624f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        rc = vm->shareVolume(argv[2], argv[3]);
1634f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    } else if (!strcmp(argv[1], "unshare")) {
1644f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (argc != 4) {
1654f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cli->sendMsg(ResponseCode::CommandSyntaxError,
1664f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    "Usage: volume unshare <path> <method>", false);
1674f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return 0;
1684f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1694f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        rc = vm->unshareVolume(argv[2], argv[3]);
1704f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    } else if (!strcmp(argv[1], "shared")) {
1714f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        bool enabled = false;
1724f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (argc != 4) {
1734f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cli->sendMsg(ResponseCode::CommandSyntaxError,
1744f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    "Usage: volume shared <path> <method>", false);
1754f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            return 0;
1764f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1774f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1784f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (vm->shareEnabled(argv[2], argv[3], &enabled)) {
1794f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cli->sendMsg(
1804f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    ResponseCode::OperationFailed, "Failed to determine share enable state", true);
1814f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        } else {
1824f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber            cli->sendMsg(ResponseCode::ShareEnabledResult,
1834f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                    (enabled ? "Share enabled" : "Share disabled"), false);
1844f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        }
1854f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        return 0;
1864f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    } else {
1874f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume cmd", false);
1884f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
1894f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1904f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    if (!rc) {
1914f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        cli->sendMsg(ResponseCode::CommandOkay, "volume operation succeeded", false);
1924f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    } else {
1934f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        int erno = errno;
1944f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        rc = ResponseCode::convertFromErrno();
1954f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        cli->sendMsg(rc, "volume operation failed", true);
1964f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
1974f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
1984f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    return 0;
1994f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber}
2004f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2014f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas HuberCommandListener::ShareCmd::ShareCmd() :
2024f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                 VoldCommand("share") {
2034f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber}
2044f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2054f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huberint CommandListener::ShareCmd::runCommand(SocketClient *cli,
2064f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber                                                      int argc, char **argv) {
2074f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    dumpArgs(argc, argv, -1);
2084f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2094f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    if (argc < 2) {
2104f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
2114f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        return 0;
2124f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    }
2134f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2144f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    VolumeManager *vm = VolumeManager::Instance();
2154f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    int rc = 0;
2164f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2174f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber    if (!strcmp(argv[1], "status")) {
2184f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        bool avail = false;
2194f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber
2204f1efc098cb5791c3e9f483f2af84aef70d2d0a0Andreas Huber        if (vm->shareAvailable(argv[2], &avail)) {
221            cli->sendMsg(
222                    ResponseCode::OperationFailed, "Failed to determine share availability", true);
223        } else {
224            cli->sendMsg(ResponseCode::ShareStatusResult,
225                    (avail ? "Share available" : "Share unavailable"), false);
226        }
227    } else {
228        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown share cmd", false);
229    }
230
231    return 0;
232}
233
234CommandListener::StorageCmd::StorageCmd() :
235                 VoldCommand("storage") {
236}
237
238int CommandListener::StorageCmd::runCommand(SocketClient *cli,
239                                                      int argc, char **argv) {
240    dumpArgs(argc, argv, -1);
241
242    if (argc < 2) {
243        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
244        return 0;
245    }
246
247    if (!strcmp(argv[1], "users")) {
248        DIR *dir;
249        struct dirent *de;
250
251        if (!(dir = opendir("/proc"))) {
252            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
253            return 0;
254        }
255
256        while ((de = readdir(dir))) {
257            int pid = Process::getPid(de->d_name);
258
259            if (pid < 0) {
260                continue;
261            }
262
263            char processName[255];
264            Process::getProcessName(pid, processName, sizeof(processName));
265
266            if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
267                Process::checkFileMaps(pid, argv[2]) ||
268                Process::checkSymLink(pid, argv[2], "cwd") ||
269                Process::checkSymLink(pid, argv[2], "root") ||
270                Process::checkSymLink(pid, argv[2], "exe")) {
271
272                char msg[1024];
273                snprintf(msg, sizeof(msg), "%d %s", pid, processName);
274                cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
275            }
276        }
277        closedir(dir);
278        cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
279    } else {
280        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
281    }
282    return 0;
283}
284
285CommandListener::AsecCmd::AsecCmd() :
286                 VoldCommand("asec") {
287}
288
289int CommandListener::AsecCmd::runCommand(SocketClient *cli,
290                                                      int argc, char **argv) {
291    if (argc < 2) {
292        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
293        return 0;
294    }
295
296    VolumeManager *vm = VolumeManager::Instance();
297    int rc = 0;
298
299    if (!strcmp(argv[1], "list")) {
300        dumpArgs(argc, argv, -1);
301        DIR *d = opendir(Volume::SEC_ASECDIR);
302
303        if (!d) {
304            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
305            return 0;
306        }
307
308        struct dirent *dent;
309        while ((dent = readdir(d))) {
310            if (dent->d_name[0] == '.')
311                continue;
312            if (!strcmp(&dent->d_name[strlen(dent->d_name)-5], ".asec")) {
313                char id[255];
314                memset(id, 0, sizeof(id));
315                strncpy(id, dent->d_name, strlen(dent->d_name) -5);
316                cli->sendMsg(ResponseCode::AsecListResult, id, false);
317            }
318        }
319        closedir(d);
320    } else if (!strcmp(argv[1], "create")) {
321        dumpArgs(argc, argv, 5);
322        if (argc != 7) {
323            cli->sendMsg(ResponseCode::CommandSyntaxError,
324                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid>", false);
325            return 0;
326        }
327
328        unsigned int numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
329        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]));
330    } else if (!strcmp(argv[1], "finalize")) {
331        dumpArgs(argc, argv, -1);
332        if (argc != 3) {
333            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
334            return 0;
335        }
336        rc = vm->finalizeAsec(argv[2]);
337    } else if (!strcmp(argv[1], "destroy")) {
338        dumpArgs(argc, argv, -1);
339        if (argc < 3) {
340            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
341            return 0;
342        }
343        bool force = false;
344        if (argc > 3 && !strcmp(argv[3], "force")) {
345            force = true;
346        }
347        rc = vm->destroyAsec(argv[2], force);
348    } else if (!strcmp(argv[1], "mount")) {
349        dumpArgs(argc, argv, 3);
350        if (argc != 5) {
351            cli->sendMsg(ResponseCode::CommandSyntaxError,
352                    "Usage: asec mount <namespace-id> <key> <ownerUid>", false);
353            return 0;
354        }
355        rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]));
356    } else if (!strcmp(argv[1], "unmount")) {
357        dumpArgs(argc, argv, -1);
358        if (argc < 3) {
359            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
360            return 0;
361        }
362        bool force = false;
363        if (argc > 3 && !strcmp(argv[3], "force")) {
364            force = true;
365        }
366        rc = vm->unmountAsec(argv[2], force);
367    } else if (!strcmp(argv[1], "rename")) {
368        dumpArgs(argc, argv, -1);
369        if (argc != 4) {
370            cli->sendMsg(ResponseCode::CommandSyntaxError,
371                    "Usage: asec rename <old_id> <new_id>", false);
372            return 0;
373        }
374        rc = vm->renameAsec(argv[2], argv[3]);
375    } else if (!strcmp(argv[1], "path")) {
376        dumpArgs(argc, argv, -1);
377        if (argc != 3) {
378            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
379            return 0;
380        }
381        char path[255];
382
383        if (!(rc = vm->getAsecMountPath(argv[2], path, sizeof(path)))) {
384            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
385            return 0;
386        }
387    } else {
388        dumpArgs(argc, argv, -1);
389        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
390    }
391
392    if (!rc) {
393        cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
394    } else {
395        rc = ResponseCode::convertFromErrno();
396        cli->sendMsg(rc, "asec operation failed", true);
397    }
398
399    return 0;
400}
401
402CommandListener::ObbCmd::ObbCmd() :
403                 VoldCommand("obb") {
404}
405
406int CommandListener::ObbCmd::runCommand(SocketClient *cli,
407                                                      int argc, char **argv) {
408    if (argc < 2) {
409        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
410        return 0;
411    }
412
413    VolumeManager *vm = VolumeManager::Instance();
414    int rc = 0;
415
416    if (!strcmp(argv[1], "list")) {
417        dumpArgs(argc, argv, -1);
418
419        rc = vm->listMountedObbs(cli);
420    } else if (!strcmp(argv[1], "mount")) {
421            dumpArgs(argc, argv, 3);
422            if (argc != 5) {
423                cli->sendMsg(ResponseCode::CommandSyntaxError,
424                        "Usage: obb mount <filename> <key> <ownerUid>", false);
425                return 0;
426            }
427            rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
428    } else if (!strcmp(argv[1], "unmount")) {
429        dumpArgs(argc, argv, -1);
430        if (argc < 3) {
431            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
432            return 0;
433        }
434        bool force = false;
435        if (argc > 3 && !strcmp(argv[3], "force")) {
436            force = true;
437        }
438        rc = vm->unmountObb(argv[2], force);
439    } else if (!strcmp(argv[1], "path")) {
440        dumpArgs(argc, argv, -1);
441        if (argc != 3) {
442            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
443            return 0;
444        }
445        char path[255];
446
447        if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
448            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
449            return 0;
450        }
451    } else {
452        dumpArgs(argc, argv, -1);
453        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
454    }
455
456    if (!rc) {
457        cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
458    } else {
459        rc = ResponseCode::convertFromErrno();
460        cli->sendMsg(rc, "obb operation failed", true);
461    }
462
463    return 0;
464}
465
466CommandListener::XwarpCmd::XwarpCmd() :
467                 VoldCommand("xwarp") {
468}
469
470int CommandListener::XwarpCmd::runCommand(SocketClient *cli,
471                                                      int argc, char **argv) {
472    if (argc < 2) {
473        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
474        return 0;
475    }
476
477    if (!strcmp(argv[1], "enable")) {
478        if (Xwarp::enable()) {
479            cli->sendMsg(ResponseCode::OperationFailed, "Failed to enable xwarp", true);
480            return 0;
481        }
482
483        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp mirroring started", false);
484    } else if (!strcmp(argv[1], "disable")) {
485        if (Xwarp::disable()) {
486            cli->sendMsg(ResponseCode::OperationFailed, "Failed to disable xwarp", true);
487            return 0;
488        }
489
490        cli->sendMsg(ResponseCode::CommandOkay, "Xwarp disabled", false);
491    } else if (!strcmp(argv[1], "status")) {
492        char msg[255];
493        bool r;
494        unsigned mirrorPos, maxSize;
495
496        if (Xwarp::status(&r, &mirrorPos, &maxSize)) {
497            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get xwarp status", true);
498            return 0;
499        }
500        snprintf(msg, sizeof(msg), "%s %u %u", (r ? "ready" : "not-ready"), mirrorPos, maxSize);
501        cli->sendMsg(ResponseCode::XwarpStatusResult, msg, false);
502    } else {
503        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
504    }
505
506    return 0;
507}
508