blob: 73d274fbb8ca284a38014d99f6cb19046d878431 [file] [log] [blame]
Dianne Hackborn23eb1e22015-10-07 17:35:27 -07001/*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "cmd"
18
19#include <utils/Log.h>
20#include <binder/Parcel.h>
21#include <binder/ProcessState.h>
22#include <binder/IResultReceiver.h>
23#include <binder/IServiceManager.h>
Dianne Hackborn1941a402016-08-29 12:30:43 -070024#include <binder/IShellCallback.h>
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070025#include <binder/TextOutput.h>
Dianne Hackborn3d9eb952016-10-17 17:40:47 -070026#include <utils/Condition.h>
27#include <utils/Mutex.h>
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070028#include <utils/Vector.h>
29
30#include <getopt.h>
31#include <stdlib.h>
32#include <stdio.h>
33#include <string.h>
34#include <unistd.h>
Dianne Hackborn1941a402016-08-29 12:30:43 -070035#include <fcntl.h>
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070036#include <sys/time.h>
Dianne Hackborn1941a402016-08-29 12:30:43 -070037#include <errno.h>
38
39#include "selinux/selinux.h"
40#include "selinux/android.h"
41
42#include <UniquePtr.h>
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070043
Dianne Hackborn3d9eb952016-10-17 17:40:47 -070044#define DEBUG 0
45
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070046using namespace android;
47
48static int sort_func(const String16* lhs, const String16* rhs)
49{
50 return lhs->compare(*rhs);
51}
52
Dianne Hackborn1941a402016-08-29 12:30:43 -070053struct SecurityContext_Delete {
54 void operator()(security_context_t p) const {
55 freecon(p);
56 }
57};
58typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
59
60class MyShellCallback : public BnShellCallback
61{
62public:
Dianne Hackborne5ed1992016-10-10 16:35:45 -070063 bool mActive = true;
64
Dianne Hackborn1941a402016-08-29 12:30:43 -070065 virtual int openOutputFile(const String16& path, const String16& seLinuxContext) {
66 String8 path8(path);
67 char cwd[256];
68 getcwd(cwd, 256);
69 String8 fullPath(cwd);
70 fullPath.appendPath(path8);
Dianne Hackborne5ed1992016-10-10 16:35:45 -070071 if (!mActive) {
72 aerr << "Open attempt after active for: " << fullPath << endl;
73 return -EPERM;
74 }
Dianne Hackborn1941a402016-08-29 12:30:43 -070075 int fd = open(fullPath.string(), O_WRONLY|O_CREAT|O_TRUNC, S_IRWXU|S_IRWXG);
76 if (fd < 0) {
77 return fd;
78 }
79 if (is_selinux_enabled() && seLinuxContext.size() > 0) {
80 String8 seLinuxContext8(seLinuxContext);
81 security_context_t tmp = NULL;
82 int ret = getfilecon(fullPath.string(), &tmp);
83 Unique_SecurityContext context(tmp);
84 int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
85 "file", "write", NULL);
86 if (accessGranted != 0) {
87 close(fd);
88 aerr << "System server has no access to file context " << context.get()
89 << " (from path " << fullPath.string() << ", context "
90 << seLinuxContext8.string() << ")" << endl;
91 return -EPERM;
92 }
93 }
94 return fd;
95 }
96};
97
Dianne Hackborn23eb1e22015-10-07 17:35:27 -070098class MyResultReceiver : public BnResultReceiver
99{
100public:
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700101 Mutex mMutex;
102 Condition mCondition;
103 bool mHaveResult = false;
104 int32_t mResult = 0;
105
106 virtual void send(int32_t resultCode) {
107 AutoMutex _l(mMutex);
108 mResult = resultCode;
109 mHaveResult = true;
110 mCondition.signal();
111 }
112
113 int32_t waitForResult() {
114 AutoMutex _l(mMutex);
115 while (!mHaveResult) {
116 mCondition.wait(mMutex);
117 }
118 return mResult;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700119 }
120};
121
122int main(int argc, char* const argv[])
123{
124 signal(SIGPIPE, SIG_IGN);
125 sp<ProcessState> proc = ProcessState::self();
126 proc->startThreadPool();
127
128 sp<IServiceManager> sm = defaultServiceManager();
129 fflush(stdout);
130 if (sm == NULL) {
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700131 ALOGW("Unable to get default service manager!");
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700132 aerr << "cmd: Unable to get default service manager!" << endl;
133 return 20;
134 }
135
136 if (argc == 1) {
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700137 aerr << "cmd: No service specified; use -l to list all services" << endl;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700138 return 20;
139 }
140
141 if ((argc == 2) && (strcmp(argv[1], "-l") == 0)) {
142 Vector<String16> services = sm->listServices();
143 services.sort(sort_func);
144 aout << "Currently running services:" << endl;
145
146 for (size_t i=0; i<services.size(); i++) {
147 sp<IBinder> service = sm->checkService(services[i]);
148 if (service != NULL) {
149 aout << " " << services[i] << endl;
150 }
151 }
152 return 0;
153 }
154
155 Vector<String16> args;
156 for (int i=2; i<argc; i++) {
157 args.add(String16(argv[i]));
158 }
159 String16 cmd = String16(argv[1]);
160 sp<IBinder> service = sm->checkService(cmd);
161 if (service == NULL) {
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700162 ALOGW("Can't find service %s", argv[1]);
163 aerr << "cmd: Can't find service: " << argv[1] << endl;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700164 return 20;
165 }
166
Dianne Hackborne5ed1992016-10-10 16:35:45 -0700167 sp<MyShellCallback> cb = new MyShellCallback();
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700168 sp<MyResultReceiver> result = new MyResultReceiver();
169
170#if DEBUG
171 ALOGD("cmd: Invoking %s in=%d, out=%d, err=%d", argv[1], STDIN_FILENO, STDOUT_FILENO,
172 STDERR_FILENO);
173#endif
Dianne Hackborne5ed1992016-10-10 16:35:45 -0700174
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700175 // TODO: block until a result is returned to MyResultReceiver.
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700176 status_t err = IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,
177 cb, result);
178 if (err < 0) {
179 const char* errstr;
180 switch (err) {
181 case BAD_TYPE: errstr = "Bad type"; break;
182 case FAILED_TRANSACTION: errstr = "Failed transaction"; break;
183 case FDS_NOT_ALLOWED: errstr = "File descriptors not allowed"; break;
184 case UNEXPECTED_NULL: errstr = "Unexpected null"; break;
185 default: errstr = strerror(-err); break;
186 }
187 ALOGW("Failure calling service %s: %s (%d)", argv[1], errstr, -err);
188 aout << "cmd: Failure calling service " << argv[1] << ": " << errstr << " ("
189 << (-err) << ")" << endl;
190 return err;
191 }
Dianne Hackborne5ed1992016-10-10 16:35:45 -0700192
193 cb->mActive = false;
Dianne Hackborn3d9eb952016-10-17 17:40:47 -0700194 status_t res = result->waitForResult();
195#if DEBUG
196 ALOGD("result=%d", (int)res);
197#endif
198 return res;
Dianne Hackborn23eb1e22015-10-07 17:35:27 -0700199}