1f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat/*
2f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Copyright (C) 2008 The Android Open Source Project
3f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
4f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
5f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * you may not use this file except in compliance with the License.
6f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * You may obtain a copy of the License at
7f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
8f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
9f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat *
10f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * Unless required by applicable law or agreed to in writing, software
11f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
12f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * See the License for the specific language governing permissions and
14f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat * limitations under the License.
15f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat */
16f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
17f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <stdlib.h>
188575a350ff725842f076500eab161b39e8720938Daichi Hirono#include <sys/mount.h>
19f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <sys/socket.h>
208575a350ff725842f076500eab161b39e8720938Daichi Hirono#include <sys/stat.h>
21a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat#include <sys/types.h>
2210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono#include <sys/wait.h>
23f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <netinet/in.h>
24f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <arpa/inet.h>
25a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat#include <dirent.h>
26f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <errno.h>
272350c44ff39b4cb2940893964a05f778fc80a436San Mehat#include <fcntl.h>
287929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash#include <fs_mgr.h>
29d1104f75a736210a95ba890473d78e8dfc8b8915Yabin Cui#include <stdio.h>
3037dcda68d334f70e1f7f69a9817def65fe3ee717Olivier Bailly#include <string.h>
315a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey#include <stdint.h>
325a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey#include <inttypes.h>
3347ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono#include <ctype.h>
34f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
35d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#define LOG_TAG "VoldCmdListener"
365a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey
3710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono#include <android-base/logging.h>
387e128fbe212c64492afa98bfd6d7fab6f1956831Elliott Hughes#include <android-base/stringprintf.h>
39fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkey#include <android-base/unique_fd.h>
405a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey#include <cutils/fs.h>
41f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
42f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <sysutils/SocketClient.h>
433ad9072a5d6f6bda32123b367545649364e3c11dKen Sumrall#include <private/android_filesystem_config.h>
44f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
45f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include "CommandListener.h"
46f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include "VolumeManager.h"
4736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey#include "VolumeBase.h"
48a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#include "ResponseCode.h"
49586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat#include "Process.h"
50d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#include "Loop.h"
51d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#include "Devmapper.h"
521d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey#include "MoveTask.h"
53c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include "TrimTask.h"
54f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
553fd60b428202a0f5f324fccc67c0c0402b9131baDianne Hackborn#define DUMP_ARGS 0
562d6555f33a5b0fd1e9f0db87e3a2146c3c26add0Daichi Hirono#define DEBUG_APPFUSE 0
573fd60b428202a0f5f324fccc67c0c0402b9131baDianne Hackborn
58fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkeyusing android::base::unique_fd;
59fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkey
60f1b736bc5605e92e917ab27f5abf3ba839be2270San MehatCommandListener::CommandListener() :
61149aa3eb65a8cb878781206b1476aae110e0e1fdRobert Greenwalt                 FrameworkListener("vold", true) {
62d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    registerCmd(new DumpCmd());
63eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    registerCmd(new VolumeCmd());
64eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    registerCmd(new AsecCmd());
65508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    registerCmd(new ObbCmd());
66586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    registerCmd(new StorageCmd());
67b87937cdea689594a293979b30b13054e7455deeKen Sumrall    registerCmd(new FstrimCmd());
688575a350ff725842f076500eab161b39e8720938Daichi Hirono    registerCmd(new AppFuseCmd());
69f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
70f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
713fd60b428202a0f5f324fccc67c0c0402b9131baDianne Hackborn#if DUMP_ARGS
723e971277db0d87652af5622c989233e7159ab909Mark Salyzynvoid CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
73d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    char buffer[4096];
74d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    char *p = buffer;
75d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
76d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    memset(buffer, 0, sizeof(buffer));
77d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    int i;
78d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    for (i = 0; i < argc; i++) {
798f869aa1bc685b505c58e97b4e11a9c7491a16f9Ken Sumrall        unsigned int len = strlen(argv[i]) + 1; // Account for space
80d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        if (i == argObscure) {
81d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            len += 2; // Account for {}
82d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        }
83d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        if (((p - buffer) + len) < (sizeof(buffer)-1)) {
84d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            if (i == argObscure) {
85d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                *p++ = '{';
86d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                *p++ = '}';
87d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                *p++ = ' ';
88d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                continue;
89d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            }
90d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            strcpy(p, argv[i]);
91d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            p+= strlen(argv[i]);
92d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            if (i != (argc -1)) {
93d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                *p++ = ' ';
94d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            }
95d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        }
96d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
9797ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat    SLOGD("%s", buffer);
98d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat}
993e971277db0d87652af5622c989233e7159ab909Mark Salyzyn#else
1003e971277db0d87652af5622c989233e7159ab909Mark Salyzynvoid CommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
1013e971277db0d87652af5622c989233e7159ab909Mark Salyzyn#endif
102d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
10336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkeyint CommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
10436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    if (!cond) {
10536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
10636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else {
10736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
10836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    }
10936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey}
11036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
111d9a4e358614a0c5f60cc76c0636ee4bb02004a32San MehatCommandListener::DumpCmd::DumpCmd() :
112d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                 VoldCommand("dump") {
113d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat}
114d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
115d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehatint CommandListener::DumpCmd::runCommand(SocketClient *cli,
1163e971277db0d87652af5622c989233e7159ab909Mark Salyzyn                                         int /*argc*/, char ** /*argv*/) {
117d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    cli->sendMsg(0, "Dumping loop status", false);
118d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (Loop::dumpState(cli)) {
119d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);
120d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
121d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    cli->sendMsg(0, "Dumping DM status", false);
122d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (Devmapper::dumpState(cli)) {
123d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);
124d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
12596597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat    cli->sendMsg(0, "Dumping mounted filesystems", false);
126fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkey    FILE *fp = fopen("/proc/mounts", "re");
12796597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat    if (fp) {
12896597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat        char line[1024];
12996597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat        while (fgets(line, sizeof(line), fp)) {
13096597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat            line[strlen(line)-1] = '\0';
13196597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat            cli->sendMsg(0, line, false);;
13296597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat        }
13396597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat        fclose(fp);
13496597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat    }
135d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
136d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
137d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    return 0;
138d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat}
139d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
140eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan MehatCommandListener::VolumeCmd::VolumeCmd() :
141eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat                 VoldCommand("volume") {
142f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
143f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
144eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehatint CommandListener::VolumeCmd::runCommand(SocketClient *cli,
1457929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash                                           int argc, char **argv) {
146d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    dumpArgs(argc, argv, -1);
147d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
148eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    if (argc < 2) {
149eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
150eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        return 0;
151eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    }
152f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
153eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    VolumeManager *vm = VolumeManager::Instance();
154c8e04c5a8285de07d2c84bfbda8eda2c14a9457dJeff Sharkey    std::lock_guard<std::mutex> lock(vm->getLock());
155eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat
15636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    // TODO: tease out methods not directly related to volumes
15757df7bf33968d65c23f3d0dc9f30a8ce2625b1d0San Mehat
15836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    std::string cmd(argv[1]);
15936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    if (cmd == "reset") {
16036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return sendGenericOkFail(cli, vm->reset());
16136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
16236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else if (cmd == "shutdown") {
16336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return sendGenericOkFail(cli, vm->shutdown());
16436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
165f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey    } else if (cmd == "debug") {
166f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey        return sendGenericOkFail(cli, vm->setDebug(true));
167f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey
16836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else if (cmd == "partition" && argc > 3) {
16936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        // partition [diskId] [public|private|mixed] [ratio]
17036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        std::string id(argv[2]);
17136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        auto disk = vm->findDisk(id);
17236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (disk == nullptr) {
17336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown disk", false);
1749caab76c6b5aefdeeb1715a3695491ca793b8c18Ken Sumrall        }
17536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
17636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        std::string type(argv[3]);
17736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (type == "public") {
17836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return sendGenericOkFail(cli, disk->partitionPublic());
17936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        } else if (type == "private") {
18036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return sendGenericOkFail(cli, disk->partitionPrivate());
18136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        } else if (type == "mixed") {
18236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            if (argc < 4) {
18336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey                return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
18436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            }
18536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            int frac = atoi(argv[4]);
18636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return sendGenericOkFail(cli, disk->partitionMixed(frac));
18736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        } else {
18836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
18957df7bf33968d65c23f3d0dc9f30a8ce2625b1d0San Mehat        }
19036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
19136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else if (cmd == "mkdirs" && argc > 2) {
19236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        // mkdirs [path]
19336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return sendGenericOkFail(cli, vm->mkdirs(argv[2]));
19436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
195bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey    } else if (cmd == "user_added" && argc > 3) {
196bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        // user_added [user] [serial]
197bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        return sendGenericOkFail(cli, vm->onUserAdded(atoi(argv[2]), atoi(argv[3])));
19836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
199bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey    } else if (cmd == "user_removed" && argc > 2) {
200bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        // user_removed [user]
201bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        return sendGenericOkFail(cli, vm->onUserRemoved(atoi(argv[2])));
202bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey
203bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey    } else if (cmd == "user_started" && argc > 2) {
204bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        // user_started [user]
205bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        return sendGenericOkFail(cli, vm->onUserStarted(atoi(argv[2])));
206bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey
207bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey    } else if (cmd == "user_stopped" && argc > 2) {
208bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        // user_stopped [user]
209bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        return sendGenericOkFail(cli, vm->onUserStopped(atoi(argv[2])));
21036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
21136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else if (cmd == "mount" && argc > 2) {
21236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        // mount [volId] [flags] [user]
21336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        std::string id(argv[2]);
21436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        auto vol = vm->findVolume(id);
21536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (vol == nullptr) {
21636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
21757df7bf33968d65c23f3d0dc9f30a8ce2625b1d0San Mehat        }
21836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
219f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey        int mountFlags = (argc > 3) ? atoi(argv[3]) : 0;
220f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey        userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1;
22136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
222f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey        vol->setMountFlags(mountFlags);
223f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey        vol->setMountUserId(mountUserId);
22436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
2251bfb375f77c093a8e16bef4ddeab2681ca126d56Jeff Sharkey        int res = vol->mount();
2261bfb375f77c093a8e16bef4ddeab2681ca126d56Jeff Sharkey        if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
2271bfb375f77c093a8e16bef4ddeab2681ca126d56Jeff Sharkey            vm->setPrimary(vol);
2281bfb375f77c093a8e16bef4ddeab2681ca126d56Jeff Sharkey        }
2291bfb375f77c093a8e16bef4ddeab2681ca126d56Jeff Sharkey        return sendGenericOkFail(cli, res);
23036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
23136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else if (cmd == "unmount" && argc > 2) {
23236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        // unmount [volId]
23336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        std::string id(argv[2]);
23436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        auto vol = vm->findVolume(id);
23536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (vol == nullptr) {
23636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
237eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
23836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
23936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return sendGenericOkFail(cli, vol->unmount());
24036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
241d0640f6358041f7e2657167560b357078db73526Jeff Sharkey    } else if (cmd == "format" && argc > 3) {
242d0640f6358041f7e2657167560b357078db73526Jeff Sharkey        // format [volId] [fsType|auto]
24336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        std::string id(argv[2]);
244d0640f6358041f7e2657167560b357078db73526Jeff Sharkey        std::string fsType(argv[3]);
24536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        auto vol = vm->findVolume(id);
24636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (vol == nullptr) {
24736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
24871ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey        }
24949e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
250d0640f6358041f7e2657167560b357078db73526Jeff Sharkey        return sendGenericOkFail(cli, vol->format(fsType));
2511d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey
2521d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey    } else if (cmd == "move_storage" && argc > 3) {
2531d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        // move_storage [fromVolId] [toVolId]
2541d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        auto fromVol = vm->findVolume(std::string(argv[2]));
2551d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        auto toVol = vm->findVolume(std::string(argv[3]));
2561d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        if (fromVol == nullptr || toVol == nullptr) {
2571d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
2581d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        }
2591d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey
2601d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        (new android::vold::MoveTask(fromVol, toVol))->start();
2611d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        return sendGenericOkFail(cli, 0);
2625a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey
2635a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey    } else if (cmd == "benchmark" && argc > 2) {
2645a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey        // benchmark [volId]
2655a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey        std::string id(argv[2]);
266c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        nsecs_t res = vm->benchmarkPrivate(id);
2675a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey        return cli->sendMsg(ResponseCode::CommandOkay,
2685a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey                android::base::StringPrintf("%" PRId64, res).c_str(), false);
269bc40cc8f07f69e0e26fc41516e2a83f0a8becbe0Jeff Sharkey
270bc40cc8f07f69e0e26fc41516e2a83f0a8becbe0Jeff Sharkey    } else if (cmd == "forget_partition" && argc > 2) {
271bc40cc8f07f69e0e26fc41516e2a83f0a8becbe0Jeff Sharkey        // forget_partition [partGuid]
272bc40cc8f07f69e0e26fc41516e2a83f0a8becbe0Jeff Sharkey        std::string partGuid(argv[2]);
273bc40cc8f07f69e0e26fc41516e2a83f0a8becbe0Jeff Sharkey        return sendGenericOkFail(cli, vm->forgetPartition(partGuid));
27466270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey
27566270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    } else if (cmd == "remount_uid" && argc > 3) {
27666270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        // remount_uid [uid] [none|default|read|write]
27766270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        uid_t uid = atoi(argv[2]);
27866270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        std::string mode(argv[3]);
27966270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        return sendGenericOkFail(cli, vm->remountUid(uid, mode));
280a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
281a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
28236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
283a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
284a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
285586536c60b773e3517531ad8a6cb0de6722c67fcSan MehatCommandListener::StorageCmd::StorageCmd() :
286586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                 VoldCommand("storage") {
287586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat}
288586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
289586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehatint CommandListener::StorageCmd::runCommand(SocketClient *cli,
290586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                                                      int argc, char **argv) {
2917929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash    /* Guarantied to be initialized by vold's main() before the CommandListener is active */
2927929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash    extern struct fstab *fstab;
2937929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash
294d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    dumpArgs(argc, argv, -1);
295d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
296586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    if (argc < 2) {
297586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
298586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        return 0;
299586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    }
300586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
3017929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash    if (!strcmp(argv[1], "mountall")) {
3027929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash        if (argc != 2) {
3037929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: mountall", false);
3047929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash            return 0;
3057929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash        }
3061d6476c3c848ebc8fbdfa6945e1c3be447beb5a3Wei Wang        fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
3077929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash        cli->sendMsg(ResponseCode::CommandOkay, "Mountall ran successfully", false);
3087929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash        return 0;
3097929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash    }
310586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    if (!strcmp(argv[1], "users")) {
311586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        DIR *dir;
312586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        struct dirent *de;
313586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
314edf7adf21e1c210e5954b1128efb61b62f6da274JP Abgrall        if (argc < 3) {
315edf7adf21e1c210e5954b1128efb61b62f6da274JP Abgrall            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument: user <mountpoint>", false);
316edf7adf21e1c210e5954b1128efb61b62f6da274JP Abgrall            return 0;
317edf7adf21e1c210e5954b1128efb61b62f6da274JP Abgrall        }
318586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        if (!(dir = opendir("/proc"))) {
319586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
320586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            return 0;
321586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        }
322586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
323586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        while ((de = readdir(dir))) {
324586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            int pid = Process::getPid(de->d_name);
325586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
326586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            if (pid < 0) {
327586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                continue;
328586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            }
329586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
330586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            char processName[255];
331586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            Process::getProcessName(pid, processName, sizeof(processName));
332586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
333586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
334586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                Process::checkFileMaps(pid, argv[2]) ||
335586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                Process::checkSymLink(pid, argv[2], "cwd") ||
336586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                Process::checkSymLink(pid, argv[2], "root") ||
337586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                Process::checkSymLink(pid, argv[2], "exe")) {
338586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
339586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                char msg[1024];
340586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                snprintf(msg, sizeof(msg), "%d %s", pid, processName);
341586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
342586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            }
343586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        }
344586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        closedir(dir);
345586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
346586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    } else {
347586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
348586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    }
349586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    return 0;
350586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat}
351586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
352eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan MehatCommandListener::AsecCmd::AsecCmd() :
353eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat                 VoldCommand("asec") {
354048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat}
355048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
356344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Rootvoid CommandListener::AsecCmd::listAsecsInDirectory(SocketClient *cli, const char *directory) {
357344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    DIR *d = opendir(directory);
358344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
359344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (!d) {
360344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
361344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return;
362344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
363344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
364344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    size_t dirent_len = offsetof(struct dirent, d_name) +
3658c480f73eed963eeca9b7df3e4c4543c6e43b0d7Elliott Hughes            fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
366344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
367344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    struct dirent *dent = (struct dirent *) malloc(dirent_len);
368344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (dent == NULL) {
369344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", true);
370344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return;
371344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
372344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
373344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    struct dirent *result;
374344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
375344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    while (!readdir_r(d, dent, &result) && result != NULL) {
376344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (dent->d_name[0] == '.')
377344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            continue;
378344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (dent->d_type != DT_REG)
379344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            continue;
380344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        size_t name_len = strlen(dent->d_name);
381344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (name_len > 5 && name_len < 260 &&
382344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                !strcmp(&dent->d_name[name_len - 5], ".asec")) {
383344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            char id[255];
384344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            memset(id, 0, sizeof(id));
3857b0bc8571465666d6cba79bda60b72a97f852c05Kenny Root            strlcpy(id, dent->d_name, name_len - 4);
386344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            cli->sendMsg(ResponseCode::AsecListResult, id, false);
387344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
388344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
389344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    closedir(d);
390344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
391344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    free(dent);
392344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root}
393344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
394eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehatint CommandListener::AsecCmd::runCommand(SocketClient *cli,
395eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat                                                      int argc, char **argv) {
396eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    if (argc < 2) {
397eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
398048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat        return 0;
399048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    }
400048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
401eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    VolumeManager *vm = VolumeManager::Instance();
402eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    int rc = 0;
403a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
404eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    if (!strcmp(argv[1], "list")) {
405d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
406a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
4079f18fe7807a4e4089778243dbbd08d154ec15540Jeff Sharkey        listAsecsInDirectory(cli, VolumeManager::SEC_ASECDIR_EXT);
4089f18fe7807a4e4089778243dbbd08d154ec15540Jeff Sharkey        listAsecsInDirectory(cli, VolumeManager::SEC_ASECDIR_INT);
409eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "create")) {
410d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, 5);
411344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (argc != 8) {
412eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError,
413344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid> "
414344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                    "<isExternal>", false);
415eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
416a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        }
417a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
418a4f48d0f44d09b6a9a3b16f6c0121ffd5123eef3Mateusz Nowak        unsigned long numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
419344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        const bool isExternal = (atoi(argv[7]) == 1);
420344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]), isExternal);
421fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    } else if (!strcmp(argv[1], "resize")) {
422fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        dumpArgs(argc, argv, -1);
423fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        if (argc != 5) {
424fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec resize <container-id> <size_mb> <key>", false);
425fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            return 0;
426fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        }
427a4f48d0f44d09b6a9a3b16f6c0121ffd5123eef3Mateusz Nowak        unsigned long numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
428fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        rc = vm->resizeAsec(argv[2], numSectors, argv[4]);
429eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "finalize")) {
430d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
431eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        if (argc != 3) {
432eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
433eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
434eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
4358f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        rc = vm->finalizeAsec(argv[2]);
436344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    } else if (!strcmp(argv[1], "fixperms")) {
437344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        dumpArgs(argc, argv, -1);
438344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if  (argc != 5) {
439344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
440344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            return 0;
441344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
442344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
443344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        char *endptr;
444344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        gid_t gid = (gid_t) strtoul(argv[3], &endptr, 10);
445344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (*endptr != '\0') {
446344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
447344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            return 0;
448344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
449344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
450344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        rc = vm->fixupAsecPermissions(argv[2], gid, argv[4]);
451eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "destroy")) {
452d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
4534ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (argc < 3) {
4544ba8948dc16463053e21cda5744f519a555080d0San Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
455eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
456eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
4574ba8948dc16463053e21cda5744f519a555080d0San Mehat        bool force = false;
4584ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (argc > 3 && !strcmp(argv[3], "force")) {
4594ba8948dc16463053e21cda5744f519a555080d0San Mehat            force = true;
4604ba8948dc16463053e21cda5744f519a555080d0San Mehat        }
4618f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        rc = vm->destroyAsec(argv[2], force);
462eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "mount")) {
463d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, 3);
46443ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        if (argc != 6) {
465eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError,
46643ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey                    "Usage: asec mount <namespace-id> <key> <ownerUid> <ro|rw>", false);
467eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
468eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
46943ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        bool readOnly = true;
47043ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        if (!strcmp(argv[5], "rw")) {
47143ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey            readOnly = false;
47243ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        }
47343ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]), readOnly);
474eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "unmount")) {
475d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
4764ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (argc < 3) {
4774ba8948dc16463053e21cda5744f519a555080d0San Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
478eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
479eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
4804ba8948dc16463053e21cda5744f519a555080d0San Mehat        bool force = false;
4814ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (argc > 3 && !strcmp(argv[3], "force")) {
4824ba8948dc16463053e21cda5744f519a555080d0San Mehat            force = true;
4834ba8948dc16463053e21cda5744f519a555080d0San Mehat        }
4848f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        rc = vm->unmountAsec(argv[2], force);
485eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "rename")) {
486d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
487eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        if (argc != 4) {
488eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError,
489eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat                    "Usage: asec rename <old_id> <new_id>", false);
490eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
491eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
4928f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        rc = vm->renameAsec(argv[2], argv[3]);
493eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "path")) {
494d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
495eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        if (argc != 3) {
496eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
497eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
498eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
499eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        char path[255];
500a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
50188ac2c06539485942bf414efda2d39647fa1a415San Mehat        if (!(rc = vm->getAsecMountPath(argv[2], path, sizeof(path)))) {
502eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
50388ac2c06539485942bf414efda2d39647fa1a415San Mehat            return 0;
504eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
505736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn    } else if (!strcmp(argv[1], "fspath")) {
506736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        dumpArgs(argc, argv, -1);
507736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        if (argc != 3) {
508736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fspath <container-id>", false);
509736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn            return 0;
510736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        }
511736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        char path[255];
512736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn
513736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        if (!(rc = vm->getAsecFilesystemPath(argv[2], path, sizeof(path)))) {
514736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
515736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn            return 0;
516736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        }
517a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    } else {
518d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
519eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
520a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
521a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
5228f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat    if (!rc) {
5238f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
5248f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat    } else {
5258f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        rc = ResponseCode::convertFromErrno();
5268f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        cli->sendMsg(rc, "asec operation failed", true);
5278f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat    }
5288f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat
529a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    return 0;
530a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat}
5312350c44ff39b4cb2940893964a05f778fc80a436San Mehat
532508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny RootCommandListener::ObbCmd::ObbCmd() :
533508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root                 VoldCommand("obb") {
534fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root}
535fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
536508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Rootint CommandListener::ObbCmd::runCommand(SocketClient *cli,
537fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root                                                      int argc, char **argv) {
538fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if (argc < 2) {
539fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
540fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        return 0;
541fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
542fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
543fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    VolumeManager *vm = VolumeManager::Instance();
544fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    int rc = 0;
545fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
546508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    if (!strcmp(argv[1], "list")) {
547508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        dumpArgs(argc, argv, -1);
548508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
549508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        rc = vm->listMountedObbs(cli);
550508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    } else if (!strcmp(argv[1], "mount")) {
551fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            dumpArgs(argc, argv, 3);
552fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            if (argc != 5) {
553fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root                cli->sendMsg(ResponseCode::CommandSyntaxError,
5546947904a76b69a1db20a3ddd30c0bcd281922fdeJeff Sharkey                        "Usage: obb mount <filename> <key> <ownerGid>", false);
555fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root                return 0;
556fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            }
557508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
558fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    } else if (!strcmp(argv[1], "unmount")) {
559fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        dumpArgs(argc, argv, -1);
560fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        if (argc < 3) {
561508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
562fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            return 0;
563fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        }
564fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        bool force = false;
565fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        if (argc > 3 && !strcmp(argv[3], "force")) {
566fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            force = true;
567fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        }
568508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        rc = vm->unmountObb(argv[2], force);
569508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    } else if (!strcmp(argv[1], "path")) {
570508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        dumpArgs(argc, argv, -1);
571508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        if (argc != 3) {
572508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
573508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            return 0;
574508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        }
575508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        char path[255];
576508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
577508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
578508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
579508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            return 0;
580508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        }
581fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    } else {
582fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        dumpArgs(argc, argv, -1);
583508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
584fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
585fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
586fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if (!rc) {
587508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
588fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    } else {
589fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        rc = ResponseCode::convertFromErrno();
590508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        cli->sendMsg(rc, "obb operation failed", true);
591fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
592fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
593fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    return 0;
594fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root}
595fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
596b87937cdea689594a293979b30b13054e7455deeKen SumrallCommandListener::FstrimCmd::FstrimCmd() :
597b87937cdea689594a293979b30b13054e7455deeKen Sumrall                 VoldCommand("fstrim") {
598b87937cdea689594a293979b30b13054e7455deeKen Sumrall}
599b87937cdea689594a293979b30b13054e7455deeKen Sumrallint CommandListener::FstrimCmd::runCommand(SocketClient *cli,
600b87937cdea689594a293979b30b13054e7455deeKen Sumrall                                                      int argc, char **argv) {
601b87937cdea689594a293979b30b13054e7455deeKen Sumrall    if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
602b87937cdea689594a293979b30b13054e7455deeKen Sumrall        cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false);
603b87937cdea689594a293979b30b13054e7455deeKen Sumrall        return 0;
604b87937cdea689594a293979b30b13054e7455deeKen Sumrall    }
605b87937cdea689594a293979b30b13054e7455deeKen Sumrall
606b87937cdea689594a293979b30b13054e7455deeKen Sumrall    if (argc < 2) {
607b87937cdea689594a293979b30b13054e7455deeKen Sumrall        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
608b87937cdea689594a293979b30b13054e7455deeKen Sumrall        return 0;
609b87937cdea689594a293979b30b13054e7455deeKen Sumrall    }
610b87937cdea689594a293979b30b13054e7455deeKen Sumrall
611c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    VolumeManager *vm = VolumeManager::Instance();
612c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    std::lock_guard<std::mutex> lock(vm->getLock());
613b87937cdea689594a293979b30b13054e7455deeKen Sumrall
614c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    int flags = 0;
615b87937cdea689594a293979b30b13054e7455deeKen Sumrall
616c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    std::string cmd(argv[1]);
617c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    if (cmd == "dotrim") {
618c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        flags = 0;
619c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    } else if (cmd == "dotrimbench") {
620c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        flags = android::vold::TrimTask::Flags::kBenchmarkAfter;
621c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    } else if (cmd == "dodtrim") {
622c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        flags = android::vold::TrimTask::Flags::kDeepTrim;
623c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    } else if (cmd == "dodtrimbench") {
624c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        flags = android::vold::TrimTask::Flags::kDeepTrim
625c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey                | android::vold::TrimTask::Flags::kBenchmarkAfter;
626c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    }
627b87937cdea689594a293979b30b13054e7455deeKen Sumrall
628c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    (new android::vold::TrimTask(flags))->start();
629c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    return sendGenericOkFail(cli, 0);
630b87937cdea689594a293979b30b13054e7455deeKen Sumrall}
6318575a350ff725842f076500eab161b39e8720938Daichi Hirono
63247ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hironostatic size_t kAppFuseMaxMountPointName = 32;
63347ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono
63410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hironostatic android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) {
63578b524ec463da25d6512dc791112c1335efd497bDaichi Hirono    if (name.size() > kAppFuseMaxMountPointName) {
63610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        LOG(ERROR) << "AppFuse mount name is too long.";
63710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -EINVAL;
63878b524ec463da25d6512dc791112c1335efd497bDaichi Hirono    }
63978b524ec463da25d6512dc791112c1335efd497bDaichi Hirono    for (size_t i = 0; i < name.size(); i++) {
64078b524ec463da25d6512dc791112c1335efd497bDaichi Hirono        if (!isalnum(name[i])) {
64110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "AppFuse mount name contains invalid character.";
64210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -EINVAL;
64378b524ec463da25d6512dc791112c1335efd497bDaichi Hirono        }
64478b524ec463da25d6512dc791112c1335efd497bDaichi Hirono    }
64510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    *path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str());
64610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    return android::OK;
64710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono}
64810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
64910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hironostatic android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
65010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    // Remove existing mount.
65110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    android::vold::ForceUnmount(path);
65210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
65310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    const auto opts = android::base::StringPrintf(
65410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            "fd=%i,"
65510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            "rootmode=40000,"
65610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            "default_permissions,"
65710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            "allow_other,"
6581c419e000eaee1758a04a5144dd07cdd20033c04Daichi Hirono            "user_id=%d,group_id=%d,"
6591c419e000eaee1758a04a5144dd07cdd20033c04Daichi Hirono            "context=\"u:object_r:app_fuse_file:s0\","
6601c419e000eaee1758a04a5144dd07cdd20033c04Daichi Hirono            "fscontext=u:object_r:app_fusefs:s0",
66110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            device_fd,
66210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            uid,
66310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            uid);
66410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
66510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    const int result = TEMP_FAILURE_RETRY(mount(
66610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            "/dev/fuse", path.c_str(), "fuse",
66710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()));
66810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (result != 0) {
66910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to mount " << path;
67010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
67110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
67210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
67310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    return android::OK;
67410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono}
67510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
67610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hironostatic android::status_t runCommandInNamespace(const std::string& command,
67710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                               uid_t uid,
67810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                               pid_t pid,
67910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                               const std::string& path,
68010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                               int device_fd) {
6812d6555f33a5b0fd1e9f0db87e3a2146c3c26add0Daichi Hirono    if (DEBUG_APPFUSE) {
6822d6555f33a5b0fd1e9f0db87e3a2146c3c26add0Daichi Hirono        LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
6832d6555f33a5b0fd1e9f0db87e3a2146c3c26add0Daichi Hirono                   << " in namespace " << uid;
6842d6555f33a5b0fd1e9f0db87e3a2146c3c26add0Daichi Hirono    }
68510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
686fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkey    unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
687fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkey    if (dir.get() == -1) {
68810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to open /proc";
68910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
69010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
69110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
69210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    // Obtains process file descriptor.
69310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    const std::string pid_str = android::base::StringPrintf("%d", pid);
694fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkey    const unique_fd pid_fd(
695fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkey            openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
69610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (pid_fd.get() == -1) {
69710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to open /proc/" << pid;
69810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
69910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
70010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
70110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    // Check UID of process.
70210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    {
70310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        struct stat sb;
70410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const int result = fstat(pid_fd.get(), &sb);
70510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (result == -1) {
70610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            PLOG(ERROR) << "Failed to stat /proc/" << pid;
70710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -errno;
70810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
70941514c19db4efb1e5d5d10c10d8d8e17030a113eDaichi Hirono        if (sb.st_uid != AID_SYSTEM) {
71041514c19db4efb1e5d5d10c10d8d8e17030a113eDaichi Hirono            LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM
71141514c19db4efb1e5d5d10c10d8d8e17030a113eDaichi Hirono                    << ", actual=" << sb.st_uid;
71210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -EPERM;
71310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
71410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
71510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
71610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    // Matches so far, but refuse to touch if in root namespace
71710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    {
71810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        char rootName[PATH_MAX];
71910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        char pidName[PATH_MAX];
72010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const int root_result =
721fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkey                android::vold::SaneReadLinkAt(dir.get(), "1/ns/mnt", rootName, PATH_MAX);
72210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const int pid_result =
72310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX);
72410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (root_result == -1) {
72510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt";
72610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -EPERM;
72710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
72810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (pid_result == -1) {
72910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt";
73010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -EPERM;
73110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
73210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (!strcmp(rootName, pidName)) {
73310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "Don't mount appfuse in root namespace";
73410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -EPERM;
73510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
73610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
73710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
73810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    // We purposefully leave the namespace open across the fork
739fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkey    unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
74010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (ns_fd.get() < 0) {
74110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
74210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
74310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
74410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
74510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    int child = fork();
74610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (child == 0) {
74710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
74810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            PLOG(ERROR) << "Failed to setns";
74910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            _exit(-errno);
75010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
75110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
75210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (command == "mount") {
75310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            _exit(mountInNamespace(uid, device_fd, path));
75410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        } else if (command == "unmount") {
75588108bd3bc8f6801310caa070745edc8f377c383Daichi Hirono            // If it's just after all FD opened on mount point are closed, umount2 can fail with
75688108bd3bc8f6801310caa070745edc8f377c383Daichi Hirono            // EBUSY. To avoid the case, specify MNT_DETACH.
75788108bd3bc8f6801310caa070745edc8f377c383Daichi Hirono            if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 &&
75888108bd3bc8f6801310caa070745edc8f377c383Daichi Hirono                    errno != EINVAL && errno != ENOENT) {
75988108bd3bc8f6801310caa070745edc8f377c383Daichi Hirono                PLOG(ERROR) << "Failed to unmount directory.";
76095b09469a30fc8c5972b9e7a3ff65db8ec705779Daichi Hirono                _exit(-errno);
76195b09469a30fc8c5972b9e7a3ff65db8ec705779Daichi Hirono            }
76295b09469a30fc8c5972b9e7a3ff65db8ec705779Daichi Hirono            if (rmdir(path.c_str()) != 0) {
76395b09469a30fc8c5972b9e7a3ff65db8ec705779Daichi Hirono                PLOG(ERROR) << "Failed to remove the mount directory.";
76488108bd3bc8f6801310caa070745edc8f377c383Daichi Hirono                _exit(-errno);
76588108bd3bc8f6801310caa070745edc8f377c383Daichi Hirono            }
76610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            _exit(android::OK);
76710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        } else {
76810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "Unknown appfuse command " << command;
76910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            _exit(-EPERM);
77010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
77110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
77210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
77310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (child == -1) {
77410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to folk child process";
77510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
77610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
77710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
77810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    android::status_t status;
77910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
78010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
78110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    return status;
78278b524ec463da25d6512dc791112c1335efd497bDaichi Hirono}
78378b524ec463da25d6512dc791112c1335efd497bDaichi Hirono
7848575a350ff725842f076500eab161b39e8720938Daichi HironoCommandListener::AppFuseCmd::AppFuseCmd() : VoldCommand("appfuse") {}
7858575a350ff725842f076500eab161b39e8720938Daichi Hirono
78610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hironoint CommandListener::AppFuseCmd::runCommand(SocketClient *cli, int argc, char **argv) {
7878575a350ff725842f076500eab161b39e8720938Daichi Hirono    if (argc < 2) {
78810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
7898575a350ff725842f076500eab161b39e8720938Daichi Hirono        return 0;
7908575a350ff725842f076500eab161b39e8720938Daichi Hirono    }
7918575a350ff725842f076500eab161b39e8720938Daichi Hirono
7928575a350ff725842f076500eab161b39e8720938Daichi Hirono    const std::string command(argv[1]);
7938575a350ff725842f076500eab161b39e8720938Daichi Hirono
79410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (command == "mount" && argc == 5) {
7958575a350ff725842f076500eab161b39e8720938Daichi Hirono        const uid_t uid = atoi(argv[2]);
79610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const pid_t pid = atoi(argv[3]);
79710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const std::string name(argv[4]);
79847ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono
79947ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        // Check mount point name.
80010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        std::string path;
80110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (getMountPath(uid, name, &path) != android::OK) {
80210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return cli->sendMsg(ResponseCode::CommandParameterError,
80310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                "Invalid mount point name.",
80410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                false);
80547ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        }
80647ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono
80747ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        // Create directories.
80847ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        {
80910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
81010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            if (result != android::OK) {
81110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                PLOG(ERROR) << "Failed to prepare directory " << path;
81247ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono                return sendGenericOkFail(cli, result);
81347ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono            }
81447ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        }
81547ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono
81647ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        // Open device FD.
817fd3dc3c076f30e19e7ac902ba0531c6bcfe2e042Jeff Sharkey        unique_fd device_fd(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC
81810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (device_fd.get() == -1) {
81910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            PLOG(ERROR) << "Failed to open /dev/fuse";
82010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return sendGenericOkFail(cli, -errno);
8218575a350ff725842f076500eab161b39e8720938Daichi Hirono        }
8228575a350ff725842f076500eab161b39e8720938Daichi Hirono
82347ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        // Mount.
82447ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        {
82510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            const android::status_t result =
82610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                    runCommandInNamespace(command, uid, pid, path, device_fd.get());
82710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            if (result != android::OK) {
82810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                return sendGenericOkFail(cli, result);
82947ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono            }
83047ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        }
83147ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono
83210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return sendFd(cli, device_fd.get());
83310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    } else if (command == "unmount" && argc == 5) {
83478b524ec463da25d6512dc791112c1335efd497bDaichi Hirono        const uid_t uid = atoi(argv[2]);
83510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const uid_t pid = atoi(argv[3]);
83610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const std::string name(argv[4]);
83778b524ec463da25d6512dc791112c1335efd497bDaichi Hirono
83878b524ec463da25d6512dc791112c1335efd497bDaichi Hirono        // Check mount point name.
83910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        std::string path;
84010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (getMountPath(uid, name, &path) != android::OK) {
84110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return cli->sendMsg(ResponseCode::CommandParameterError,
84210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                "Invalid mount point name.",
84310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                false);
84478b524ec463da25d6512dc791112c1335efd497bDaichi Hirono        }
84578b524ec463da25d6512dc791112c1335efd497bDaichi Hirono
84610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const android::status_t result =
84710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                runCommandInNamespace(command, uid, pid, path, -1 /* device_fd */);
84810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return sendGenericOkFail(cli, result);
8498575a350ff725842f076500eab161b39e8720938Daichi Hirono    }
8508575a350ff725842f076500eab161b39e8720938Daichi Hirono
85110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    return cli->sendMsg(ResponseCode::CommandSyntaxError,  "Unknown appfuse cmd", false);
8528575a350ff725842f076500eab161b39e8720938Daichi Hirono}
8538575a350ff725842f076500eab161b39e8720938Daichi Hirono
85410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hironoandroid::status_t CommandListener::AppFuseCmd::sendFd(SocketClient *cli, int fd) {
8558575a350ff725842f076500eab161b39e8720938Daichi Hirono    struct iovec data;
8568575a350ff725842f076500eab161b39e8720938Daichi Hirono    char dataBuffer[128];
8578575a350ff725842f076500eab161b39e8720938Daichi Hirono    char controlBuffer[CMSG_SPACE(sizeof(int))];
8588575a350ff725842f076500eab161b39e8720938Daichi Hirono    struct msghdr message;
8598575a350ff725842f076500eab161b39e8720938Daichi Hirono
8608575a350ff725842f076500eab161b39e8720938Daichi Hirono    // Message.
8618575a350ff725842f076500eab161b39e8720938Daichi Hirono    memset(&message, 0, sizeof(struct msghdr));
8628575a350ff725842f076500eab161b39e8720938Daichi Hirono    message.msg_iov = &data;
8638575a350ff725842f076500eab161b39e8720938Daichi Hirono    message.msg_iovlen = 1;
8648575a350ff725842f076500eab161b39e8720938Daichi Hirono    message.msg_control = controlBuffer;
8658575a350ff725842f076500eab161b39e8720938Daichi Hirono    message.msg_controllen = CMSG_SPACE(sizeof(int));
8668575a350ff725842f076500eab161b39e8720938Daichi Hirono
8678575a350ff725842f076500eab161b39e8720938Daichi Hirono    // Data.
8688575a350ff725842f076500eab161b39e8720938Daichi Hirono    data.iov_base = dataBuffer;
8698575a350ff725842f076500eab161b39e8720938Daichi Hirono    data.iov_len = snprintf(dataBuffer,
8708575a350ff725842f076500eab161b39e8720938Daichi Hirono                            sizeof(dataBuffer),
8718575a350ff725842f076500eab161b39e8720938Daichi Hirono                            "200 %d AppFuse command succeeded",
8728575a350ff725842f076500eab161b39e8720938Daichi Hirono                            cli->getCmdNum()) + 1;
8738575a350ff725842f076500eab161b39e8720938Daichi Hirono
8748575a350ff725842f076500eab161b39e8720938Daichi Hirono    // Control.
8758575a350ff725842f076500eab161b39e8720938Daichi Hirono    struct cmsghdr* const controlMessage = CMSG_FIRSTHDR(&message);
8768575a350ff725842f076500eab161b39e8720938Daichi Hirono    memset(controlBuffer, 0, CMSG_SPACE(sizeof(int)));
8778575a350ff725842f076500eab161b39e8720938Daichi Hirono    controlMessage->cmsg_level = SOL_SOCKET;
8788575a350ff725842f076500eab161b39e8720938Daichi Hirono    controlMessage->cmsg_type = SCM_RIGHTS;
8798575a350ff725842f076500eab161b39e8720938Daichi Hirono    controlMessage->cmsg_len = CMSG_LEN(sizeof(int));
8808575a350ff725842f076500eab161b39e8720938Daichi Hirono    *((int *) CMSG_DATA(controlMessage)) = fd;
8818575a350ff725842f076500eab161b39e8720938Daichi Hirono
88210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    const int result = TEMP_FAILURE_RETRY(sendmsg(cli->getSocket(), &message, 0));
88310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (result == -1) {
88410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to send FD from vold";
88510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
88610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
88710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
88810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    return android::OK;
8898575a350ff725842f076500eab161b39e8720938Daichi Hirono}
890