CommandListener.cpp revision 1d6476c3c848ebc8fbdfa6945e1c3be447beb5a3
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>
395a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey#include <cutils/fs.h>
40f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
41f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include <sysutils/SocketClient.h>
423ad9072a5d6f6bda32123b367545649364e3c11dKen Sumrall#include <private/android_filesystem_config.h>
43f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
44f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include "CommandListener.h"
45f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat#include "VolumeManager.h"
4636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey#include "VolumeBase.h"
47a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat#include "ResponseCode.h"
48586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat#include "Process.h"
49d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#include "Loop.h"
50d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat#include "Devmapper.h"
511d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey#include "MoveTask.h"
52c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey#include "TrimTask.h"
53f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
543fd60b428202a0f5f324fccc67c0c0402b9131baDianne Hackborn#define DUMP_ARGS 0
552d6555f33a5b0fd1e9f0db87e3a2146c3c26add0Daichi Hirono#define DEBUG_APPFUSE 0
563fd60b428202a0f5f324fccc67c0c0402b9131baDianne Hackborn
57f1b736bc5605e92e917ab27f5abf3ba839be2270San MehatCommandListener::CommandListener() :
58149aa3eb65a8cb878781206b1476aae110e0e1fdRobert Greenwalt                 FrameworkListener("vold", true) {
59d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    registerCmd(new DumpCmd());
60eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    registerCmd(new VolumeCmd());
61eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    registerCmd(new AsecCmd());
62508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    registerCmd(new ObbCmd());
63586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    registerCmd(new StorageCmd());
64b87937cdea689594a293979b30b13054e7455deeKen Sumrall    registerCmd(new FstrimCmd());
658575a350ff725842f076500eab161b39e8720938Daichi Hirono    registerCmd(new AppFuseCmd());
66f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
67f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
683fd60b428202a0f5f324fccc67c0c0402b9131baDianne Hackborn#if DUMP_ARGS
693e971277db0d87652af5622c989233e7159ab909Mark Salyzynvoid CommandListener::dumpArgs(int argc, char **argv, int argObscure) {
70d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    char buffer[4096];
71d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    char *p = buffer;
72d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
73d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    memset(buffer, 0, sizeof(buffer));
74d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    int i;
75d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    for (i = 0; i < argc; i++) {
768f869aa1bc685b505c58e97b4e11a9c7491a16f9Ken Sumrall        unsigned int len = strlen(argv[i]) + 1; // Account for space
77d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        if (i == argObscure) {
78d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            len += 2; // Account for {}
79d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        }
80d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        if (((p - buffer) + len) < (sizeof(buffer)-1)) {
81d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            if (i == argObscure) {
82d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                *p++ = '{';
83d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                *p++ = '}';
84d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                *p++ = ' ';
85d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                continue;
86d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            }
87d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            strcpy(p, argv[i]);
88d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            p+= strlen(argv[i]);
89d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            if (i != (argc -1)) {
90d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                *p++ = ' ';
91d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat            }
92d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        }
93d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
9497ac40e4e6f3ed0bd5d6878d7d8d4a54fcaecb76San Mehat    SLOGD("%s", buffer);
95d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat}
963e971277db0d87652af5622c989233e7159ab909Mark Salyzyn#else
973e971277db0d87652af5622c989233e7159ab909Mark Salyzynvoid CommandListener::dumpArgs(int /*argc*/, char ** /*argv*/, int /*argObscure*/) { }
983e971277db0d87652af5622c989233e7159ab909Mark Salyzyn#endif
99d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
10036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkeyint CommandListener::sendGenericOkFail(SocketClient *cli, int cond) {
10136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    if (!cond) {
10236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return cli->sendMsg(ResponseCode::CommandOkay, "Command succeeded", false);
10336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else {
10436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return cli->sendMsg(ResponseCode::OperationFailed, "Command failed", false);
10536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    }
10636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey}
10736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
108d9a4e358614a0c5f60cc76c0636ee4bb02004a32San MehatCommandListener::DumpCmd::DumpCmd() :
109d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat                 VoldCommand("dump") {
110d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat}
111d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
112d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehatint CommandListener::DumpCmd::runCommand(SocketClient *cli,
1133e971277db0d87652af5622c989233e7159ab909Mark Salyzyn                                         int /*argc*/, char ** /*argv*/) {
114d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    cli->sendMsg(0, "Dumping loop status", false);
115d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (Loop::dumpState(cli)) {
116d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        cli->sendMsg(ResponseCode::CommandOkay, "Loop dump failed", true);
117d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
118d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    cli->sendMsg(0, "Dumping DM status", false);
119d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    if (Devmapper::dumpState(cli)) {
120d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        cli->sendMsg(ResponseCode::CommandOkay, "Devmapper dump failed", true);
121d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    }
12296597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat    cli->sendMsg(0, "Dumping mounted filesystems", false);
12396597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat    FILE *fp = fopen("/proc/mounts", "r");
12496597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat    if (fp) {
12596597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat        char line[1024];
12696597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat        while (fgets(line, sizeof(line), fp)) {
12796597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat            line[strlen(line)-1] = '\0';
12896597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat            cli->sendMsg(0, line, false);;
12996597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat        }
13096597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat        fclose(fp);
13196597e8b840ef671fe5279f8bd64fb09a8b38d4cSan Mehat    }
132d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
133d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    cli->sendMsg(ResponseCode::CommandOkay, "dump complete", false);
134d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    return 0;
135d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat}
136d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
137eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan MehatCommandListener::VolumeCmd::VolumeCmd() :
138eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat                 VoldCommand("volume") {
139f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat}
140f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
141eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehatint CommandListener::VolumeCmd::runCommand(SocketClient *cli,
1427929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash                                           int argc, char **argv) {
143d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    dumpArgs(argc, argv, -1);
144d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
145eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    if (argc < 2) {
146eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
147eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        return 0;
148eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    }
149f1b736bc5605e92e917ab27f5abf3ba839be2270San Mehat
150eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    VolumeManager *vm = VolumeManager::Instance();
151c8e04c5a8285de07d2c84bfbda8eda2c14a9457dJeff Sharkey    std::lock_guard<std::mutex> lock(vm->getLock());
152eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat
15336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    // TODO: tease out methods not directly related to volumes
15457df7bf33968d65c23f3d0dc9f30a8ce2625b1d0San Mehat
15536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    std::string cmd(argv[1]);
15636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    if (cmd == "reset") {
15736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return sendGenericOkFail(cli, vm->reset());
15836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
15936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else if (cmd == "shutdown") {
16036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return sendGenericOkFail(cli, vm->shutdown());
16136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
162f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey    } else if (cmd == "debug") {
163f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey        return sendGenericOkFail(cli, vm->setDebug(true));
164f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey
16536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else if (cmd == "partition" && argc > 3) {
16636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        // partition [diskId] [public|private|mixed] [ratio]
16736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        std::string id(argv[2]);
16836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        auto disk = vm->findDisk(id);
16936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (disk == nullptr) {
17036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown disk", false);
1719caab76c6b5aefdeeb1715a3695491ca793b8c18Ken Sumrall        }
17236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
17336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        std::string type(argv[3]);
17436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (type == "public") {
17536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return sendGenericOkFail(cli, disk->partitionPublic());
17636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        } else if (type == "private") {
17736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return sendGenericOkFail(cli, disk->partitionPrivate());
17836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        } else if (type == "mixed") {
17936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            if (argc < 4) {
18036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey                return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
18136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            }
18236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            int frac = atoi(argv[4]);
18336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return sendGenericOkFail(cli, disk->partitionMixed(frac));
18436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        } else {
18536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
18657df7bf33968d65c23f3d0dc9f30a8ce2625b1d0San Mehat        }
18736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
18836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else if (cmd == "mkdirs" && argc > 2) {
18936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        // mkdirs [path]
19036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return sendGenericOkFail(cli, vm->mkdirs(argv[2]));
19136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
192bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey    } else if (cmd == "user_added" && argc > 3) {
193bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        // user_added [user] [serial]
194bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        return sendGenericOkFail(cli, vm->onUserAdded(atoi(argv[2]), atoi(argv[3])));
19536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
196bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey    } else if (cmd == "user_removed" && argc > 2) {
197bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        // user_removed [user]
198bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        return sendGenericOkFail(cli, vm->onUserRemoved(atoi(argv[2])));
199bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey
200bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey    } else if (cmd == "user_started" && argc > 2) {
201bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        // user_started [user]
202bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        return sendGenericOkFail(cli, vm->onUserStarted(atoi(argv[2])));
203bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey
204bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey    } else if (cmd == "user_stopped" && argc > 2) {
205bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        // user_stopped [user]
206bd3038df74ace540d46c530a11e3145f922e1b42Jeff Sharkey        return sendGenericOkFail(cli, vm->onUserStopped(atoi(argv[2])));
20736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
20836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else if (cmd == "mount" && argc > 2) {
20936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        // mount [volId] [flags] [user]
21036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        std::string id(argv[2]);
21136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        auto vol = vm->findVolume(id);
21236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (vol == nullptr) {
21336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
21457df7bf33968d65c23f3d0dc9f30a8ce2625b1d0San Mehat        }
21536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
216f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey        int mountFlags = (argc > 3) ? atoi(argv[3]) : 0;
217f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey        userid_t mountUserId = (argc > 4) ? atoi(argv[4]) : -1;
21836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
219f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey        vol->setMountFlags(mountFlags);
220f1b996df6f8283aac6953b22bd9e2496d8c30c86Jeff Sharkey        vol->setMountUserId(mountUserId);
22136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
2221bfb375f77c093a8e16bef4ddeab2681ca126d56Jeff Sharkey        int res = vol->mount();
2231bfb375f77c093a8e16bef4ddeab2681ca126d56Jeff Sharkey        if (mountFlags & android::vold::VolumeBase::MountFlags::kPrimary) {
2241bfb375f77c093a8e16bef4ddeab2681ca126d56Jeff Sharkey            vm->setPrimary(vol);
2251bfb375f77c093a8e16bef4ddeab2681ca126d56Jeff Sharkey        }
2261bfb375f77c093a8e16bef4ddeab2681ca126d56Jeff Sharkey        return sendGenericOkFail(cli, res);
22736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
22836801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    } else if (cmd == "unmount" && argc > 2) {
22936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        // unmount [volId]
23036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        std::string id(argv[2]);
23136801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        auto vol = vm->findVolume(id);
23236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (vol == nullptr) {
23336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
234eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
23536801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
23636801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        return sendGenericOkFail(cli, vol->unmount());
23736801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey
238d0640f6358041f7e2657167560b357078db73526Jeff Sharkey    } else if (cmd == "format" && argc > 3) {
239d0640f6358041f7e2657167560b357078db73526Jeff Sharkey        // format [volId] [fsType|auto]
24036801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        std::string id(argv[2]);
241d0640f6358041f7e2657167560b357078db73526Jeff Sharkey        std::string fsType(argv[3]);
24236801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        auto vol = vm->findVolume(id);
24336801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey        if (vol == nullptr) {
24436801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
24571ebe154a5fbbb4b394a439ff0b6b9c84fbd04f5Jeff Sharkey        }
24649e2bce5b74129c26a35e25d4693cbfe98c4688eSan Mehat
247d0640f6358041f7e2657167560b357078db73526Jeff Sharkey        return sendGenericOkFail(cli, vol->format(fsType));
2481d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey
2491d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey    } else if (cmd == "move_storage" && argc > 3) {
2501d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        // move_storage [fromVolId] [toVolId]
2511d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        auto fromVol = vm->findVolume(std::string(argv[2]));
2521d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        auto toVol = vm->findVolume(std::string(argv[3]));
2531d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        if (fromVol == nullptr || toVol == nullptr) {
2541d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey            return cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown volume", false);
2551d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        }
2561d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey
2571d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        (new android::vold::MoveTask(fromVol, toVol))->start();
2581d6fbcc389ecb9f418076e8ab5f4c93a5d911de9Jeff Sharkey        return sendGenericOkFail(cli, 0);
2595a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey
2605a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey    } else if (cmd == "benchmark" && argc > 2) {
2615a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey        // benchmark [volId]
2625a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey        std::string id(argv[2]);
263c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        nsecs_t res = vm->benchmarkPrivate(id);
2645a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey        return cli->sendMsg(ResponseCode::CommandOkay,
2655a6bfca1638760b87cf64c5ffb48ff3557cc0563Jeff Sharkey                android::base::StringPrintf("%" PRId64, res).c_str(), false);
266bc40cc8f07f69e0e26fc41516e2a83f0a8becbe0Jeff Sharkey
267bc40cc8f07f69e0e26fc41516e2a83f0a8becbe0Jeff Sharkey    } else if (cmd == "forget_partition" && argc > 2) {
268bc40cc8f07f69e0e26fc41516e2a83f0a8becbe0Jeff Sharkey        // forget_partition [partGuid]
269bc40cc8f07f69e0e26fc41516e2a83f0a8becbe0Jeff Sharkey        std::string partGuid(argv[2]);
270bc40cc8f07f69e0e26fc41516e2a83f0a8becbe0Jeff Sharkey        return sendGenericOkFail(cli, vm->forgetPartition(partGuid));
27166270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey
27266270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey    } else if (cmd == "remount_uid" && argc > 3) {
27366270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        // remount_uid [uid] [none|default|read|write]
27466270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        uid_t uid = atoi(argv[2]);
27566270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        std::string mode(argv[3]);
27666270a21df1058434e4d63691221f11ff5387a0fJeff Sharkey        return sendGenericOkFail(cli, vm->remountUid(uid, mode));
277a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat    }
278a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
27936801cccf27152c9eca5aab6ba3527221525110fJeff Sharkey    return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
280a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat}
281a2677e4ad01f250b0765f04adf0acfa6627efc98San Mehat
282586536c60b773e3517531ad8a6cb0de6722c67fcSan MehatCommandListener::StorageCmd::StorageCmd() :
283586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                 VoldCommand("storage") {
284586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat}
285586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
286586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehatint CommandListener::StorageCmd::runCommand(SocketClient *cli,
287586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                                                      int argc, char **argv) {
2887929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash    /* Guarantied to be initialized by vold's main() before the CommandListener is active */
2897929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash    extern struct fstab *fstab;
2907929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash
291d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat    dumpArgs(argc, argv, -1);
292d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat
293586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    if (argc < 2) {
294586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
295586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        return 0;
296586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    }
297586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
2987929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash    if (!strcmp(argv[1], "mountall")) {
2997929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash        if (argc != 2) {
3007929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: mountall", false);
3017929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash            return 0;
3027929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash        }
3031d6476c3c848ebc8fbdfa6945e1c3be447beb5a3Wei Wang        fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
3047929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash        cli->sendMsg(ResponseCode::CommandOkay, "Mountall ran successfully", false);
3057929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash        return 0;
3067929aa73d0c1fa75e8e0fcd4272361ad0ea9b0e6Mohamad Ayyash    }
307586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    if (!strcmp(argv[1], "users")) {
308586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        DIR *dir;
309586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        struct dirent *de;
310586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
311edf7adf21e1c210e5954b1128efb61b62f6da274JP Abgrall        if (argc < 3) {
312edf7adf21e1c210e5954b1128efb61b62f6da274JP Abgrall            cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument: user <mountpoint>", false);
313edf7adf21e1c210e5954b1128efb61b62f6da274JP Abgrall            return 0;
314edf7adf21e1c210e5954b1128efb61b62f6da274JP Abgrall        }
315586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        if (!(dir = opendir("/proc"))) {
316586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            cli->sendMsg(ResponseCode::OperationFailed, "Failed to open /proc", true);
317586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            return 0;
318586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        }
319586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
320586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        while ((de = readdir(dir))) {
321586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            int pid = Process::getPid(de->d_name);
322586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
323586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            if (pid < 0) {
324586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                continue;
325586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            }
326586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
327586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            char processName[255];
328586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            Process::getProcessName(pid, processName, sizeof(processName));
329586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
330586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            if (Process::checkFileDescriptorSymLinks(pid, argv[2]) ||
331586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                Process::checkFileMaps(pid, argv[2]) ||
332586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                Process::checkSymLink(pid, argv[2], "cwd") ||
333586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                Process::checkSymLink(pid, argv[2], "root") ||
334586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                Process::checkSymLink(pid, argv[2], "exe")) {
335586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
336586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                char msg[1024];
337586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                snprintf(msg, sizeof(msg), "%d %s", pid, processName);
338586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat                cli->sendMsg(ResponseCode::StorageUsersListResult, msg, false);
339586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat            }
340586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        }
341586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        closedir(dir);
342586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        cli->sendMsg(ResponseCode::CommandOkay, "Storage user list complete", false);
343586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    } else {
344586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown storage cmd", false);
345586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    }
346586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat    return 0;
347586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat}
348586536c60b773e3517531ad8a6cb0de6722c67fcSan Mehat
349eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan MehatCommandListener::AsecCmd::AsecCmd() :
350eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat                 VoldCommand("asec") {
351048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat}
352048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
353344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Rootvoid CommandListener::AsecCmd::listAsecsInDirectory(SocketClient *cli, const char *directory) {
354344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    DIR *d = opendir(directory);
355344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
356344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (!d) {
357344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        cli->sendMsg(ResponseCode::OperationFailed, "Failed to open asec dir", true);
358344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return;
359344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
360344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
361344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    size_t dirent_len = offsetof(struct dirent, d_name) +
3628c480f73eed963eeca9b7df3e4c4543c6e43b0d7Elliott Hughes            fpathconf(dirfd(d), _PC_NAME_MAX) + 1;
363344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
364344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    struct dirent *dent = (struct dirent *) malloc(dirent_len);
365344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    if (dent == NULL) {
366344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        cli->sendMsg(ResponseCode::OperationFailed, "Failed to allocate memory", true);
367344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        return;
368344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
369344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
370344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    struct dirent *result;
371344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
372344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    while (!readdir_r(d, dent, &result) && result != NULL) {
373344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (dent->d_name[0] == '.')
374344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            continue;
375344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (dent->d_type != DT_REG)
376344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            continue;
377344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        size_t name_len = strlen(dent->d_name);
378344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (name_len > 5 && name_len < 260 &&
379344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                !strcmp(&dent->d_name[name_len - 5], ".asec")) {
380344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            char id[255];
381344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            memset(id, 0, sizeof(id));
3827b0bc8571465666d6cba79bda60b72a97f852c05Kenny Root            strlcpy(id, dent->d_name, name_len - 4);
383344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            cli->sendMsg(ResponseCode::AsecListResult, id, false);
384344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
385344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    }
386344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    closedir(d);
387344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
388344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    free(dent);
389344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root}
390344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
391eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehatint CommandListener::AsecCmd::runCommand(SocketClient *cli,
392eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat                                                      int argc, char **argv) {
393eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    if (argc < 2) {
394eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
395048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat        return 0;
396048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat    }
397048b0801fcd6fcfbb8fa812284c751181e4821b8San Mehat
398eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    VolumeManager *vm = VolumeManager::Instance();
399eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    int rc = 0;
400a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
401eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    if (!strcmp(argv[1], "list")) {
402d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
403a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
4049f18fe7807a4e4089778243dbbd08d154ec15540Jeff Sharkey        listAsecsInDirectory(cli, VolumeManager::SEC_ASECDIR_EXT);
4059f18fe7807a4e4089778243dbbd08d154ec15540Jeff Sharkey        listAsecsInDirectory(cli, VolumeManager::SEC_ASECDIR_INT);
406eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "create")) {
407d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, 5);
408344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (argc != 8) {
409eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError,
410344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                    "Usage: asec create <container-id> <size_mb> <fstype> <key> <ownerUid> "
411344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root                    "<isExternal>", false);
412eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
413a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat        }
414a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
415a4f48d0f44d09b6a9a3b16f6c0121ffd5123eef3Mateusz Nowak        unsigned long numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
416344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        const bool isExternal = (atoi(argv[7]) == 1);
417344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        rc = vm->createAsec(argv[2], numSectors, argv[4], argv[5], atoi(argv[6]), isExternal);
418fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg    } else if (!strcmp(argv[1], "resize")) {
419fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        dumpArgs(argc, argv, -1);
420fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        if (argc != 5) {
421fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec resize <container-id> <size_mb> <key>", false);
422fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg            return 0;
423fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        }
424a4f48d0f44d09b6a9a3b16f6c0121ffd5123eef3Mateusz Nowak        unsigned long numSectors = (atoi(argv[3]) * (1024 * 1024)) / 512;
425fcd34a0ddd45db83b7bc71ff47cba9b789089fddDaniel Rosenberg        rc = vm->resizeAsec(argv[2], numSectors, argv[4]);
426eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "finalize")) {
427d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
428eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        if (argc != 3) {
429eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec finalize <container-id>", false);
430eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
431eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
4328f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        rc = vm->finalizeAsec(argv[2]);
433344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root    } else if (!strcmp(argv[1], "fixperms")) {
434344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        dumpArgs(argc, argv, -1);
435344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if  (argc != 5) {
436344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
437344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            return 0;
438344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
439344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
440344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        char *endptr;
441344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        gid_t gid = (gid_t) strtoul(argv[3], &endptr, 10);
442344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        if (*endptr != '\0') {
443344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fixperms <container-id> <gid> <filename>", false);
444344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root            return 0;
445344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        }
446344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root
447344ca10856f3d3087a3288ce8f91ad83665d93fbKenny Root        rc = vm->fixupAsecPermissions(argv[2], gid, argv[4]);
448eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "destroy")) {
449d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
4504ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (argc < 3) {
4514ba8948dc16463053e21cda5744f519a555080d0San Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec destroy <container-id> [force]", false);
452eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
453eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
4544ba8948dc16463053e21cda5744f519a555080d0San Mehat        bool force = false;
4554ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (argc > 3 && !strcmp(argv[3], "force")) {
4564ba8948dc16463053e21cda5744f519a555080d0San Mehat            force = true;
4574ba8948dc16463053e21cda5744f519a555080d0San Mehat        }
4588f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        rc = vm->destroyAsec(argv[2], force);
459eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "mount")) {
460d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, 3);
46143ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        if (argc != 6) {
462eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError,
46343ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey                    "Usage: asec mount <namespace-id> <key> <ownerUid> <ro|rw>", false);
464eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
465eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
46643ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        bool readOnly = true;
46743ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        if (!strcmp(argv[5], "rw")) {
46843ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey            readOnly = false;
46943ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        }
47043ed123d3fc1a3edf3660cd0e2528e971abc399eJeff Sharkey        rc = vm->mountAsec(argv[2], argv[3], atoi(argv[4]), readOnly);
471eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "unmount")) {
472d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
4734ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (argc < 3) {
4744ba8948dc16463053e21cda5744f519a555080d0San Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec unmount <container-id> [force]", false);
475eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
476eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
4774ba8948dc16463053e21cda5744f519a555080d0San Mehat        bool force = false;
4784ba8948dc16463053e21cda5744f519a555080d0San Mehat        if (argc > 3 && !strcmp(argv[3], "force")) {
4794ba8948dc16463053e21cda5744f519a555080d0San Mehat            force = true;
4804ba8948dc16463053e21cda5744f519a555080d0San Mehat        }
4818f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        rc = vm->unmountAsec(argv[2], force);
482eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "rename")) {
483d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
484eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        if (argc != 4) {
485eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError,
486eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat                    "Usage: asec rename <old_id> <new_id>", false);
487eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
488eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
4898f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        rc = vm->renameAsec(argv[2], argv[3]);
490eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat    } else if (!strcmp(argv[1], "path")) {
491d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
492eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        if (argc != 3) {
493eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec path <container-id>", false);
494eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            return 0;
495eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
496eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        char path[255];
497a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
49888ac2c06539485942bf414efda2d39647fa1a415San Mehat        if (!(rc = vm->getAsecMountPath(argv[2], path, sizeof(path)))) {
499eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
50088ac2c06539485942bf414efda2d39647fa1a415San Mehat            return 0;
501eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        }
502736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn    } else if (!strcmp(argv[1], "fspath")) {
503736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        dumpArgs(argc, argv, -1);
504736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        if (argc != 3) {
505736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: asec fspath <container-id>", false);
506736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn            return 0;
507736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        }
508736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        char path[255];
509736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn
510736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        if (!(rc = vm->getAsecFilesystemPath(argv[2], path, sizeof(path)))) {
511736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
512736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn            return 0;
513736910ca99a40b9add4353bf619e778c40938948Dianne Hackborn        }
514a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    } else {
515d9a4e358614a0c5f60cc76c0636ee4bb02004a32San Mehat        dumpArgs(argc, argv, -1);
516eba65e9d438a05f1c5dfd0f8d31bc463a5d08eeeSan Mehat        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown asec cmd", false);
517a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    }
518a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat
5198f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat    if (!rc) {
5208f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        cli->sendMsg(ResponseCode::CommandOkay, "asec operation succeeded", false);
5218f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat    } else {
5228f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        rc = ResponseCode::convertFromErrno();
5238f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat        cli->sendMsg(rc, "asec operation failed", true);
5248f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat    }
5258f2875b29780312f4edda3d831cc8a99e1648dd5San Mehat
526a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat    return 0;
527a19b250bd273455933ca3502cf2c2e0a803aff77San Mehat}
5282350c44ff39b4cb2940893964a05f778fc80a436San Mehat
529508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny RootCommandListener::ObbCmd::ObbCmd() :
530508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root                 VoldCommand("obb") {
531fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root}
532fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
533508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Rootint CommandListener::ObbCmd::runCommand(SocketClient *cli,
534fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root                                                      int argc, char **argv) {
535fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if (argc < 2) {
536fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
537fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        return 0;
538fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
539fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
540fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    VolumeManager *vm = VolumeManager::Instance();
541fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    int rc = 0;
542fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
543508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    if (!strcmp(argv[1], "list")) {
544508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        dumpArgs(argc, argv, -1);
545508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
546508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        rc = vm->listMountedObbs(cli);
547508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    } else if (!strcmp(argv[1], "mount")) {
548fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            dumpArgs(argc, argv, 3);
549fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            if (argc != 5) {
550fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root                cli->sendMsg(ResponseCode::CommandSyntaxError,
5516947904a76b69a1db20a3ddd30c0bcd281922fdeJeff Sharkey                        "Usage: obb mount <filename> <key> <ownerGid>", false);
552fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root                return 0;
553fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            }
554508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            rc = vm->mountObb(argv[2], argv[3], atoi(argv[4]));
555fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    } else if (!strcmp(argv[1], "unmount")) {
556fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        dumpArgs(argc, argv, -1);
557fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        if (argc < 3) {
558508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb unmount <source file> [force]", false);
559fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            return 0;
560fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        }
561fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        bool force = false;
562fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        if (argc > 3 && !strcmp(argv[3], "force")) {
563fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root            force = true;
564fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        }
565508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        rc = vm->unmountObb(argv[2], force);
566508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root    } else if (!strcmp(argv[1], "path")) {
567508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        dumpArgs(argc, argv, -1);
568508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        if (argc != 3) {
569508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            cli->sendMsg(ResponseCode::CommandSyntaxError, "Usage: obb path <source file>", false);
570508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            return 0;
571508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        }
572508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        char path[255];
573508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root
574508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        if (!(rc = vm->getObbMountPath(argv[2], path, sizeof(path)))) {
575508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            cli->sendMsg(ResponseCode::AsecPathResult, path, false);
576508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root            return 0;
577508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        }
578fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    } else {
579fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        dumpArgs(argc, argv, -1);
580508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown obb cmd", false);
581fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
582fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
583fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    if (!rc) {
584508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        cli->sendMsg(ResponseCode::CommandOkay, "obb operation succeeded", false);
585fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    } else {
586fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root        rc = ResponseCode::convertFromErrno();
587508c0e1605b795bbb51cb47d955b89f3df26ca94Kenny Root        cli->sendMsg(rc, "obb operation failed", true);
588fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    }
589fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
590fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root    return 0;
591fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root}
592fb7c4d5a8a1031cf0e493ff182dcf458e5fe8c77Kenny Root
593b87937cdea689594a293979b30b13054e7455deeKen SumrallCommandListener::FstrimCmd::FstrimCmd() :
594b87937cdea689594a293979b30b13054e7455deeKen Sumrall                 VoldCommand("fstrim") {
595b87937cdea689594a293979b30b13054e7455deeKen Sumrall}
596b87937cdea689594a293979b30b13054e7455deeKen Sumrallint CommandListener::FstrimCmd::runCommand(SocketClient *cli,
597b87937cdea689594a293979b30b13054e7455deeKen Sumrall                                                      int argc, char **argv) {
598b87937cdea689594a293979b30b13054e7455deeKen Sumrall    if ((cli->getUid() != 0) && (cli->getUid() != AID_SYSTEM)) {
599b87937cdea689594a293979b30b13054e7455deeKen Sumrall        cli->sendMsg(ResponseCode::CommandNoPermission, "No permission to run fstrim commands", false);
600b87937cdea689594a293979b30b13054e7455deeKen Sumrall        return 0;
601b87937cdea689594a293979b30b13054e7455deeKen Sumrall    }
602b87937cdea689594a293979b30b13054e7455deeKen Sumrall
603b87937cdea689594a293979b30b13054e7455deeKen Sumrall    if (argc < 2) {
604b87937cdea689594a293979b30b13054e7455deeKen Sumrall        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing Argument", false);
605b87937cdea689594a293979b30b13054e7455deeKen Sumrall        return 0;
606b87937cdea689594a293979b30b13054e7455deeKen Sumrall    }
607b87937cdea689594a293979b30b13054e7455deeKen Sumrall
608c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    VolumeManager *vm = VolumeManager::Instance();
609c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    std::lock_guard<std::mutex> lock(vm->getLock());
610b87937cdea689594a293979b30b13054e7455deeKen Sumrall
611c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    int flags = 0;
612b87937cdea689594a293979b30b13054e7455deeKen Sumrall
613c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    std::string cmd(argv[1]);
614c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    if (cmd == "dotrim") {
615c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        flags = 0;
616c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    } else if (cmd == "dotrimbench") {
617c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        flags = android::vold::TrimTask::Flags::kBenchmarkAfter;
618c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    } else if (cmd == "dodtrim") {
619c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        flags = android::vold::TrimTask::Flags::kDeepTrim;
620c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    } else if (cmd == "dodtrimbench") {
621c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey        flags = android::vold::TrimTask::Flags::kDeepTrim
622c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey                | android::vold::TrimTask::Flags::kBenchmarkAfter;
623c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    }
624b87937cdea689594a293979b30b13054e7455deeKen Sumrall
625c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    (new android::vold::TrimTask(flags))->start();
626c86ab6f538bec63638c168d6c843fe7cf73add3bJeff Sharkey    return sendGenericOkFail(cli, 0);
627b87937cdea689594a293979b30b13054e7455deeKen Sumrall}
6288575a350ff725842f076500eab161b39e8720938Daichi Hirono
62947ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hironostatic size_t kAppFuseMaxMountPointName = 32;
63047ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono
63110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hironostatic android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) {
63278b524ec463da25d6512dc791112c1335efd497bDaichi Hirono    if (name.size() > kAppFuseMaxMountPointName) {
63310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        LOG(ERROR) << "AppFuse mount name is too long.";
63410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -EINVAL;
63578b524ec463da25d6512dc791112c1335efd497bDaichi Hirono    }
63678b524ec463da25d6512dc791112c1335efd497bDaichi Hirono    for (size_t i = 0; i < name.size(); i++) {
63778b524ec463da25d6512dc791112c1335efd497bDaichi Hirono        if (!isalnum(name[i])) {
63810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "AppFuse mount name contains invalid character.";
63910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -EINVAL;
64078b524ec463da25d6512dc791112c1335efd497bDaichi Hirono        }
64178b524ec463da25d6512dc791112c1335efd497bDaichi Hirono    }
64210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    *path = android::base::StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str());
64310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    return android::OK;
64410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono}
64510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
64610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hironostatic android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
64710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    // Remove existing mount.
64810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    android::vold::ForceUnmount(path);
64910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
65010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    const auto opts = android::base::StringPrintf(
65110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            "fd=%i,"
65210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            "rootmode=40000,"
65310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            "default_permissions,"
65410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            "allow_other,"
6551c419e000eaee1758a04a5144dd07cdd20033c04Daichi Hirono            "user_id=%d,group_id=%d,"
6561c419e000eaee1758a04a5144dd07cdd20033c04Daichi Hirono            "context=\"u:object_r:app_fuse_file:s0\","
6571c419e000eaee1758a04a5144dd07cdd20033c04Daichi Hirono            "fscontext=u:object_r:app_fusefs:s0",
65810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            device_fd,
65910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            uid,
66010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            uid);
66110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
66210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    const int result = TEMP_FAILURE_RETRY(mount(
66310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            "/dev/fuse", path.c_str(), "fuse",
66410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str()));
66510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (result != 0) {
66610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to mount " << path;
66710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
66810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
66910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
67010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    return android::OK;
67110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono}
67210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
67310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hironostatic android::status_t runCommandInNamespace(const std::string& command,
67410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                               uid_t uid,
67510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                               pid_t pid,
67610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                               const std::string& path,
67710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                               int device_fd) {
6782d6555f33a5b0fd1e9f0db87e3a2146c3c26add0Daichi Hirono    if (DEBUG_APPFUSE) {
6792d6555f33a5b0fd1e9f0db87e3a2146c3c26add0Daichi Hirono        LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
6802d6555f33a5b0fd1e9f0db87e3a2146c3c26add0Daichi Hirono                   << " in namespace " << uid;
6812d6555f33a5b0fd1e9f0db87e3a2146c3c26add0Daichi Hirono    }
68210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
68310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    const android::vold::ScopedDir dir(opendir("/proc"));
68410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (dir.get() == nullptr) {
68510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to open /proc";
68610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
68710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
68810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
68910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    // Obtains process file descriptor.
69010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    const std::string pid_str = android::base::StringPrintf("%d", pid);
69110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    const android::vold::ScopedFd pid_fd(
69210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            openat(dirfd(dir.get()), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
69310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (pid_fd.get() == -1) {
69410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to open /proc/" << pid;
69510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
69610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
69710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
69810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    // Check UID of process.
69910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    {
70010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        struct stat sb;
70110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const int result = fstat(pid_fd.get(), &sb);
70210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (result == -1) {
70310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            PLOG(ERROR) << "Failed to stat /proc/" << pid;
70410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -errno;
70510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
70610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (sb.st_uid != uid) {
70710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "Mismatch UID expected=" << uid << ", actual=" << sb.st_uid;
70810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -EPERM;
70910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
71010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
71110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
71210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    // Matches so far, but refuse to touch if in root namespace
71310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    {
71410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        char rootName[PATH_MAX];
71510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        char pidName[PATH_MAX];
71610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const int root_result =
71710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                android::vold::SaneReadLinkAt(dirfd(dir.get()), "1/ns/mnt", rootName, PATH_MAX);
71810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const int pid_result =
71910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                android::vold::SaneReadLinkAt(pid_fd.get(), "ns/mnt", pidName, PATH_MAX);
72010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (root_result == -1) {
72110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "Failed to readlink for /proc/1/ns/mnt";
72210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -EPERM;
72310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
72410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (pid_result == -1) {
72510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "Failed to readlink for /proc/" << pid << "/ns/mnt";
72610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -EPERM;
72710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
72810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (!strcmp(rootName, pidName)) {
72910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "Don't mount appfuse in root namespace";
73010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return -EPERM;
73110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
73210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
73310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
73410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    // We purposefully leave the namespace open across the fork
73510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    android::vold::ScopedFd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY));
73610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (ns_fd.get() < 0) {
73710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
73810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
73910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
74010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
74110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    int child = fork();
74210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (child == 0) {
74310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
74410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            PLOG(ERROR) << "Failed to setns";
74510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            _exit(-errno);
74610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
74710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
74810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (command == "mount") {
74910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            _exit(mountInNamespace(uid, device_fd, path));
75010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        } else if (command == "unmount") {
75110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            android::vold::ForceUnmount(path);
75210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            _exit(android::OK);
75310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        } else {
75410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            LOG(ERROR) << "Unknown appfuse command " << command;
75510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            _exit(-EPERM);
75610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        }
75710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
75810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
75910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (child == -1) {
76010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to folk child process";
76110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
76210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
76310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
76410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    android::status_t status;
76510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
76610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
76710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    return status;
76878b524ec463da25d6512dc791112c1335efd497bDaichi Hirono}
76978b524ec463da25d6512dc791112c1335efd497bDaichi Hirono
7708575a350ff725842f076500eab161b39e8720938Daichi HironoCommandListener::AppFuseCmd::AppFuseCmd() : VoldCommand("appfuse") {}
7718575a350ff725842f076500eab161b39e8720938Daichi Hirono
77210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hironoint CommandListener::AppFuseCmd::runCommand(SocketClient *cli, int argc, char **argv) {
7738575a350ff725842f076500eab161b39e8720938Daichi Hirono    if (argc < 2) {
77410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
7758575a350ff725842f076500eab161b39e8720938Daichi Hirono        return 0;
7768575a350ff725842f076500eab161b39e8720938Daichi Hirono    }
7778575a350ff725842f076500eab161b39e8720938Daichi Hirono
7788575a350ff725842f076500eab161b39e8720938Daichi Hirono    const std::string command(argv[1]);
7798575a350ff725842f076500eab161b39e8720938Daichi Hirono
78010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (command == "mount" && argc == 5) {
7818575a350ff725842f076500eab161b39e8720938Daichi Hirono        const uid_t uid = atoi(argv[2]);
78210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const pid_t pid = atoi(argv[3]);
78310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const std::string name(argv[4]);
78447ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono
78547ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        // Check mount point name.
78610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        std::string path;
78710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (getMountPath(uid, name, &path) != android::OK) {
78810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return cli->sendMsg(ResponseCode::CommandParameterError,
78910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                "Invalid mount point name.",
79010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                false);
79147ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        }
79247ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono
79347ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        // Create directories.
79447ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        {
79510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0);
79610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            if (result != android::OK) {
79710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                PLOG(ERROR) << "Failed to prepare directory " << path;
79847ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono                return sendGenericOkFail(cli, result);
79947ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono            }
80047ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        }
80147ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono
80247ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        // Open device FD.
80310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        android::vold::ScopedFd device_fd(open("/dev/fuse", O_RDWR));
80410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (device_fd.get() == -1) {
80510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            PLOG(ERROR) << "Failed to open /dev/fuse";
80610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return sendGenericOkFail(cli, -errno);
8078575a350ff725842f076500eab161b39e8720938Daichi Hirono        }
8088575a350ff725842f076500eab161b39e8720938Daichi Hirono
80947ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        // Mount.
81047ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        {
81110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            const android::status_t result =
81210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                    runCommandInNamespace(command, uid, pid, path, device_fd.get());
81310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            if (result != android::OK) {
81410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                return sendGenericOkFail(cli, result);
81547ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono            }
81647ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono        }
81747ef9bcad2399df05df0cef516bacb2cda6431f4Daichi Hirono
81810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return sendFd(cli, device_fd.get());
81910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    } else if (command == "unmount" && argc == 5) {
82078b524ec463da25d6512dc791112c1335efd497bDaichi Hirono        const uid_t uid = atoi(argv[2]);
82110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const uid_t pid = atoi(argv[3]);
82210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const std::string name(argv[4]);
82378b524ec463da25d6512dc791112c1335efd497bDaichi Hirono
82478b524ec463da25d6512dc791112c1335efd497bDaichi Hirono        // Check mount point name.
82510d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        std::string path;
82610d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        if (getMountPath(uid, name, &path) != android::OK) {
82710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono            return cli->sendMsg(ResponseCode::CommandParameterError,
82810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                "Invalid mount point name.",
82910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                                false);
83078b524ec463da25d6512dc791112c1335efd497bDaichi Hirono        }
83178b524ec463da25d6512dc791112c1335efd497bDaichi Hirono
83210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        const android::status_t result =
83310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono                runCommandInNamespace(command, uid, pid, path, -1 /* device_fd */);
83410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return sendGenericOkFail(cli, result);
8358575a350ff725842f076500eab161b39e8720938Daichi Hirono    }
8368575a350ff725842f076500eab161b39e8720938Daichi Hirono
83710d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    return cli->sendMsg(ResponseCode::CommandSyntaxError,  "Unknown appfuse cmd", false);
8388575a350ff725842f076500eab161b39e8720938Daichi Hirono}
8398575a350ff725842f076500eab161b39e8720938Daichi Hirono
84010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hironoandroid::status_t CommandListener::AppFuseCmd::sendFd(SocketClient *cli, int fd) {
8418575a350ff725842f076500eab161b39e8720938Daichi Hirono    struct iovec data;
8428575a350ff725842f076500eab161b39e8720938Daichi Hirono    char dataBuffer[128];
8438575a350ff725842f076500eab161b39e8720938Daichi Hirono    char controlBuffer[CMSG_SPACE(sizeof(int))];
8448575a350ff725842f076500eab161b39e8720938Daichi Hirono    struct msghdr message;
8458575a350ff725842f076500eab161b39e8720938Daichi Hirono
8468575a350ff725842f076500eab161b39e8720938Daichi Hirono    // Message.
8478575a350ff725842f076500eab161b39e8720938Daichi Hirono    memset(&message, 0, sizeof(struct msghdr));
8488575a350ff725842f076500eab161b39e8720938Daichi Hirono    message.msg_iov = &data;
8498575a350ff725842f076500eab161b39e8720938Daichi Hirono    message.msg_iovlen = 1;
8508575a350ff725842f076500eab161b39e8720938Daichi Hirono    message.msg_control = controlBuffer;
8518575a350ff725842f076500eab161b39e8720938Daichi Hirono    message.msg_controllen = CMSG_SPACE(sizeof(int));
8528575a350ff725842f076500eab161b39e8720938Daichi Hirono
8538575a350ff725842f076500eab161b39e8720938Daichi Hirono    // Data.
8548575a350ff725842f076500eab161b39e8720938Daichi Hirono    data.iov_base = dataBuffer;
8558575a350ff725842f076500eab161b39e8720938Daichi Hirono    data.iov_len = snprintf(dataBuffer,
8568575a350ff725842f076500eab161b39e8720938Daichi Hirono                            sizeof(dataBuffer),
8578575a350ff725842f076500eab161b39e8720938Daichi Hirono                            "200 %d AppFuse command succeeded",
8588575a350ff725842f076500eab161b39e8720938Daichi Hirono                            cli->getCmdNum()) + 1;
8598575a350ff725842f076500eab161b39e8720938Daichi Hirono
8608575a350ff725842f076500eab161b39e8720938Daichi Hirono    // Control.
8618575a350ff725842f076500eab161b39e8720938Daichi Hirono    struct cmsghdr* const controlMessage = CMSG_FIRSTHDR(&message);
8628575a350ff725842f076500eab161b39e8720938Daichi Hirono    memset(controlBuffer, 0, CMSG_SPACE(sizeof(int)));
8638575a350ff725842f076500eab161b39e8720938Daichi Hirono    controlMessage->cmsg_level = SOL_SOCKET;
8648575a350ff725842f076500eab161b39e8720938Daichi Hirono    controlMessage->cmsg_type = SCM_RIGHTS;
8658575a350ff725842f076500eab161b39e8720938Daichi Hirono    controlMessage->cmsg_len = CMSG_LEN(sizeof(int));
8668575a350ff725842f076500eab161b39e8720938Daichi Hirono    *((int *) CMSG_DATA(controlMessage)) = fd;
8678575a350ff725842f076500eab161b39e8720938Daichi Hirono
86810d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    const int result = TEMP_FAILURE_RETRY(sendmsg(cli->getSocket(), &message, 0));
86910d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    if (result == -1) {
87010d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        PLOG(ERROR) << "Failed to send FD from vold";
87110d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono        return -errno;
87210d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    }
87310d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono
87410d34887b3e00e603604e0301487f9b8222c66f4Daichi Hirono    return android::OK;
8758575a350ff725842f076500eab161b39e8720938Daichi Hirono}
876