CommandListener.cpp revision c61895ac3a9717dac6b24ce210aab0ccae6747f4
1/*
2 * Copyright (C) 2012-2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <arpa/inet.h>
18#include <dirent.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <netinet/in.h>
22#include <string.h>
23#include <stdlib.h>
24#include <sys/prctl.h>
25#include <sys/socket.h>
26#include <sys/types.h>
27
28#include <cutils/sockets.h>
29#include <private/android_filesystem_config.h>
30#include <sysutils/SocketClient.h>
31
32#include "CommandListener.h"
33#include "LogCommand.h"
34
35CommandListener::CommandListener(LogBuffer *buf, LogReader * /*reader*/,
36                                 LogListener * /*swl*/)
37        : FrameworkListener(getLogSocket())
38        , mBuf(*buf) {
39    // registerCmd(new ShutdownCmd(buf, writer, swl));
40    registerCmd(new ClearCmd(buf));
41    registerCmd(new GetBufSizeCmd(buf));
42    registerCmd(new SetBufSizeCmd(buf));
43    registerCmd(new GetBufSizeUsedCmd(buf));
44    registerCmd(new GetStatisticsCmd(buf));
45    registerCmd(new SetPruneListCmd(buf));
46    registerCmd(new GetPruneListCmd(buf));
47}
48
49CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
50                                          LogListener *swl)
51        : LogCommand("shutdown")
52        , mBuf(*buf)
53        , mReader(*reader)
54        , mSwl(*swl)
55{ }
56
57int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
58                                             int /*argc*/,
59                                             char ** /*argv*/) {
60    mSwl.stopListener();
61    mReader.stopListener();
62    exit(0);
63}
64
65CommandListener::ClearCmd::ClearCmd(LogBuffer *buf)
66        : LogCommand("clear")
67        , mBuf(*buf)
68{ }
69
70static void setname() {
71    prctl(PR_SET_NAME, "logd.control");
72}
73
74int CommandListener::ClearCmd::runCommand(SocketClient *cli,
75                                         int argc, char **argv) {
76    setname();
77    if (!clientHasLogCredentials(cli)) {
78        cli->sendMsg("Permission Denied");
79        return 0;
80    }
81
82    if (argc < 2) {
83        cli->sendMsg("Missing Argument");
84        return 0;
85    }
86
87    int id = atoi(argv[1]);
88    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
89        cli->sendMsg("Range Error");
90        return 0;
91    }
92
93    mBuf.clear((log_id_t) id);
94    cli->sendMsg("success");
95    return 0;
96}
97
98CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf)
99        : LogCommand("getLogSize")
100        , mBuf(*buf)
101{ }
102
103int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
104                                         int argc, char **argv) {
105    setname();
106    if (argc < 2) {
107        cli->sendMsg("Missing Argument");
108        return 0;
109    }
110
111    int id = atoi(argv[1]);
112    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
113        cli->sendMsg("Range Error");
114        return 0;
115    }
116
117    unsigned long size = mBuf.getSize((log_id_t) id);
118    char buf[512];
119    snprintf(buf, sizeof(buf), "%lu", size);
120    cli->sendMsg(buf);
121    return 0;
122}
123
124CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf)
125        : LogCommand("setLogSize")
126        , mBuf(*buf)
127{ }
128
129int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
130                                         int argc, char **argv) {
131    setname();
132    if (!clientHasLogCredentials(cli)) {
133        cli->sendMsg("Permission Denied");
134        return 0;
135    }
136
137    if (argc < 3) {
138        cli->sendMsg("Missing Argument");
139        return 0;
140    }
141
142    int id = atoi(argv[1]);
143    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
144        cli->sendMsg("Range Error");
145        return 0;
146    }
147
148    unsigned long size = atol(argv[2]);
149    if (mBuf.setSize((log_id_t) id, size)) {
150        cli->sendMsg("Range Error");
151        return 0;
152    }
153
154    cli->sendMsg("success");
155    return 0;
156}
157
158CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf)
159        : LogCommand("getLogSizeUsed")
160        , mBuf(*buf)
161{ }
162
163int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
164                                         int argc, char **argv) {
165    setname();
166    if (argc < 2) {
167        cli->sendMsg("Missing Argument");
168        return 0;
169    }
170
171    int id = atoi(argv[1]);
172    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
173        cli->sendMsg("Range Error");
174        return 0;
175    }
176
177    unsigned long size = mBuf.getSizeUsed((log_id_t) id);
178    char buf[512];
179    snprintf(buf, sizeof(buf), "%lu", size);
180    cli->sendMsg(buf);
181    return 0;
182}
183
184CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf)
185        : LogCommand("getStatistics")
186        , mBuf(*buf)
187{ }
188
189static void package_string(char **strp) {
190    const char *a = *strp;
191    if (!a) {
192        a = "";
193    }
194
195    // Calculate total buffer size prefix, count is the string length w/o nul
196    char fmt[32];
197    for(size_t l = strlen(a), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
198        snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
199    }
200
201    char *b = *strp;
202    *strp = NULL;
203    asprintf(strp, fmt, a);
204    free(b);
205}
206
207int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
208                                         int argc, char **argv) {
209    setname();
210    uid_t uid = cli->getUid();
211    if (clientHasLogCredentials(cli)) {
212        uid = AID_ROOT;
213    }
214
215    unsigned int logMask = -1;
216    if (argc > 1) {
217        logMask = 0;
218        for (int i = 1; i < argc; ++i) {
219            int id = atoi(argv[i]);
220            if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
221                cli->sendMsg("Range Error");
222                return 0;
223            }
224            logMask |= 1 << id;
225        }
226    }
227
228    char *buf = NULL;
229
230    mBuf.formatStatistics(&buf, uid, logMask);
231    if (!buf) {
232        cli->sendMsg("Failed");
233    } else {
234        package_string(&buf);
235        cli->sendMsg(buf);
236        free(buf);
237    }
238    return 0;
239}
240
241CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf)
242        : LogCommand("getPruneList")
243        , mBuf(*buf)
244{ }
245
246int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
247                                         int /*argc*/, char ** /*argv*/) {
248    setname();
249    char *buf = NULL;
250    mBuf.formatPrune(&buf);
251    if (!buf) {
252        cli->sendMsg("Failed");
253    } else {
254        package_string(&buf);
255        cli->sendMsg(buf);
256        free(buf);
257    }
258    return 0;
259}
260
261CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf)
262        : LogCommand("setPruneList")
263        , mBuf(*buf)
264{ }
265
266int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
267                                         int argc, char **argv) {
268    setname();
269    if (!clientHasLogCredentials(cli)) {
270        cli->sendMsg("Permission Denied");
271        return 0;
272    }
273
274    char *cp = NULL;
275    for (int i = 1; i < argc; ++i) {
276        char *p = cp;
277        if (p) {
278            cp = NULL;
279            asprintf(&cp, "%s %s", p, argv[i]);
280            free(p);
281        } else {
282            asprintf(&cp, "%s", argv[i]);
283        }
284    }
285
286    int ret = mBuf.initPrune(cp);
287    free(cp);
288
289    if (ret) {
290        cli->sendMsg("Invalid");
291        return 0;
292    }
293
294    cli->sendMsg("success");
295
296    return 0;
297}
298
299int CommandListener::getLogSocket() {
300    static const char socketName[] = "logd";
301    int sock = android_get_control_socket(socketName);
302
303    if (sock < 0) {
304        sock = socket_local_server(socketName,
305                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
306                                   SOCK_STREAM);
307    }
308
309    return sock;
310}
311