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    registerCmd(new ReinitCmd());
48}
49
50CommandListener::ShutdownCmd::ShutdownCmd(LogBuffer *buf, LogReader *reader,
51                                          LogListener *swl) :
52        LogCommand("shutdown"),
53        mBuf(*buf),
54        mReader(*reader),
55        mSwl(*swl) {
56}
57
58int CommandListener::ShutdownCmd::runCommand(SocketClient * /*cli*/,
59                                             int /*argc*/,
60                                             char ** /*argv*/) {
61    mSwl.stopListener();
62    mReader.stopListener();
63    exit(0);
64}
65
66CommandListener::ClearCmd::ClearCmd(LogBuffer *buf) :
67        LogCommand("clear"),
68        mBuf(*buf) {
69}
70
71static void setname() {
72    static bool name_set;
73    if (!name_set) {
74        prctl(PR_SET_NAME, "logd.control");
75        name_set = true;
76    }
77}
78
79int CommandListener::ClearCmd::runCommand(SocketClient *cli,
80                                         int argc, char **argv) {
81    setname();
82    uid_t uid = cli->getUid();
83    if (clientHasLogCredentials(cli)) {
84        uid = AID_ROOT;
85    }
86
87    if (argc < 2) {
88        cli->sendMsg("Missing Argument");
89        return 0;
90    }
91
92    int id = atoi(argv[1]);
93    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
94        cli->sendMsg("Range Error");
95        return 0;
96    }
97
98    mBuf.clear((log_id_t) id, uid);
99    cli->sendMsg("success");
100    return 0;
101}
102
103CommandListener::GetBufSizeCmd::GetBufSizeCmd(LogBuffer *buf) :
104        LogCommand("getLogSize"),
105        mBuf(*buf) {
106}
107
108int CommandListener::GetBufSizeCmd::runCommand(SocketClient *cli,
109                                         int argc, char **argv) {
110    setname();
111    if (argc < 2) {
112        cli->sendMsg("Missing Argument");
113        return 0;
114    }
115
116    int id = atoi(argv[1]);
117    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
118        cli->sendMsg("Range Error");
119        return 0;
120    }
121
122    unsigned long size = mBuf.getSize((log_id_t) id);
123    char buf[512];
124    snprintf(buf, sizeof(buf), "%lu", size);
125    cli->sendMsg(buf);
126    return 0;
127}
128
129CommandListener::SetBufSizeCmd::SetBufSizeCmd(LogBuffer *buf) :
130        LogCommand("setLogSize"),
131        mBuf(*buf) {
132}
133
134int CommandListener::SetBufSizeCmd::runCommand(SocketClient *cli,
135                                         int argc, char **argv) {
136    setname();
137    if (!clientHasLogCredentials(cli)) {
138        cli->sendMsg("Permission Denied");
139        return 0;
140    }
141
142    if (argc < 3) {
143        cli->sendMsg("Missing Argument");
144        return 0;
145    }
146
147    int id = atoi(argv[1]);
148    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
149        cli->sendMsg("Range Error");
150        return 0;
151    }
152
153    unsigned long size = atol(argv[2]);
154    if (mBuf.setSize((log_id_t) id, size)) {
155        cli->sendMsg("Range Error");
156        return 0;
157    }
158
159    cli->sendMsg("success");
160    return 0;
161}
162
163CommandListener::GetBufSizeUsedCmd::GetBufSizeUsedCmd(LogBuffer *buf) :
164        LogCommand("getLogSizeUsed"),
165        mBuf(*buf) {
166}
167
168int CommandListener::GetBufSizeUsedCmd::runCommand(SocketClient *cli,
169                                         int argc, char **argv) {
170    setname();
171    if (argc < 2) {
172        cli->sendMsg("Missing Argument");
173        return 0;
174    }
175
176    int id = atoi(argv[1]);
177    if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
178        cli->sendMsg("Range Error");
179        return 0;
180    }
181
182    unsigned long size = mBuf.getSizeUsed((log_id_t) id);
183    char buf[512];
184    snprintf(buf, sizeof(buf), "%lu", size);
185    cli->sendMsg(buf);
186    return 0;
187}
188
189CommandListener::GetStatisticsCmd::GetStatisticsCmd(LogBuffer *buf) :
190        LogCommand("getStatistics"),
191        mBuf(*buf) {
192}
193
194static void package_string(char **strp) {
195    const char *a = *strp;
196    if (!a) {
197        a = "";
198    }
199
200    // Calculate total buffer size prefix, count is the string length w/o nul
201    char fmt[32];
202    for(size_t l = strlen(a), y = 0, x = 6; y != x; y = x, x = strlen(fmt) - 2) {
203        snprintf(fmt, sizeof(fmt), "%zu\n%%s\n\f", l + x);
204    }
205
206    char *b = *strp;
207    *strp = NULL;
208    asprintf(strp, fmt, a);
209    free(b);
210}
211
212int CommandListener::GetStatisticsCmd::runCommand(SocketClient *cli,
213                                         int argc, char **argv) {
214    setname();
215    uid_t uid = cli->getUid();
216    if (clientHasLogCredentials(cli)) {
217        uid = AID_ROOT;
218    }
219
220    unsigned int logMask = -1;
221    if (argc > 1) {
222        logMask = 0;
223        for (int i = 1; i < argc; ++i) {
224            int id = atoi(argv[i]);
225            if ((id < LOG_ID_MIN) || (LOG_ID_MAX <= id)) {
226                cli->sendMsg("Range Error");
227                return 0;
228            }
229            logMask |= 1 << id;
230        }
231    }
232
233    char *buf = NULL;
234
235    mBuf.formatStatistics(&buf, uid, logMask);
236    if (!buf) {
237        cli->sendMsg("Failed");
238    } else {
239        package_string(&buf);
240        cli->sendMsg(buf);
241        free(buf);
242    }
243    return 0;
244}
245
246CommandListener::GetPruneListCmd::GetPruneListCmd(LogBuffer *buf) :
247        LogCommand("getPruneList"),
248        mBuf(*buf) {
249}
250
251int CommandListener::GetPruneListCmd::runCommand(SocketClient *cli,
252                                         int /*argc*/, char ** /*argv*/) {
253    setname();
254    char *buf = NULL;
255    mBuf.formatPrune(&buf);
256    if (!buf) {
257        cli->sendMsg("Failed");
258    } else {
259        package_string(&buf);
260        cli->sendMsg(buf);
261        free(buf);
262    }
263    return 0;
264}
265
266CommandListener::SetPruneListCmd::SetPruneListCmd(LogBuffer *buf) :
267        LogCommand("setPruneList"),
268        mBuf(*buf) {
269}
270
271int CommandListener::SetPruneListCmd::runCommand(SocketClient *cli,
272                                         int argc, char **argv) {
273    setname();
274    if (!clientHasLogCredentials(cli)) {
275        cli->sendMsg("Permission Denied");
276        return 0;
277    }
278
279    char *cp = NULL;
280    for (int i = 1; i < argc; ++i) {
281        char *p = cp;
282        if (p) {
283            cp = NULL;
284            asprintf(&cp, "%s %s", p, argv[i]);
285            free(p);
286        } else {
287            asprintf(&cp, "%s", argv[i]);
288        }
289    }
290
291    int ret = mBuf.initPrune(cp);
292    free(cp);
293
294    if (ret) {
295        cli->sendMsg("Invalid");
296        return 0;
297    }
298
299    cli->sendMsg("success");
300
301    return 0;
302}
303
304CommandListener::ReinitCmd::ReinitCmd() : LogCommand("reinit") {
305}
306
307int CommandListener::ReinitCmd::runCommand(SocketClient *cli,
308                                         int /*argc*/, char ** /*argv*/) {
309    setname();
310
311    reinit_signal_handler(SIGHUP);
312
313    cli->sendMsg("success");
314
315    return 0;
316}
317
318int CommandListener::getLogSocket() {
319    static const char socketName[] = "logd";
320    int sock = android_get_control_socket(socketName);
321
322    if (sock < 0) {
323        sock = socket_local_server(socketName,
324                                   ANDROID_SOCKET_NAMESPACE_RESERVED,
325                                   SOCK_STREAM);
326    }
327
328    return sock;
329}
330