blob: ea393bd67de2ded63f8aae8b9899d31ff8aa3150 [file] [log] [blame]
Mark Salyzyn5a4f06c2017-02-10 13:09:07 -08001/*
2 * Copyright (C) 2017 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 <ctype.h>
18#include <stdio.h>
19#include <string.h>
20#include <unistd.h>
21
22#include <string>
23#include <vector>
24
25#include <log/logcat.h>
26
27static std::string unquote(const char*& cp, const char*& delim) {
28 if ((*cp == '\'') || (*cp == '"')) {
29 // KISS: Simple quotes. Do not handle the case
30 // of concatenation like "blah"foo'bar'
31 char quote = *cp++;
32 delim = strchr(cp, quote);
33 if (!delim) delim = cp + strlen(cp);
34 std::string str(cp, delim);
35 if (*delim) ++delim;
36 return str;
37 }
38 delim = strpbrk(cp, " \t\f\r\n");
39 if (!delim) delim = cp + strlen(cp);
40 return std::string(cp, delim);
41}
42
43static bool __android_logcat_parse(const char* command,
44 std::vector<std::string>& args,
45 std::vector<std::string>& envs) {
46 for (const char *delim, *cp = command; cp && *cp; cp = delim) {
47 while (isspace(*cp)) ++cp;
48 if ((args.size() == 0) && (*cp != '=') && !isdigit(*cp)) {
49 const char* env = cp;
50 while (isalnum(*cp) || (*cp == '_')) ++cp;
51 if (cp && (*cp == '=')) {
52 std::string str(env, ++cp);
53 str += unquote(cp, delim);
54 envs.push_back(str);
55 continue;
56 }
57 cp = env;
58 }
59 args.push_back(unquote(cp, delim));
60 if ((args.size() == 1) && (args[0] != "logcat") &&
61 (args[0] != "/system/bin/logcat")) {
62 return false;
63 }
64 }
65 return args.size() != 0;
66}
67
68FILE* android_logcat_popen(android_logcat_context* ctx, const char* command) {
69 *ctx = NULL;
70
71 std::vector<std::string> args;
72 std::vector<std::string> envs;
73 if (!__android_logcat_parse(command, args, envs)) return NULL;
74
75 std::vector<const char*> argv;
76 for (auto& str : args) {
77 argv.push_back(str.c_str());
78 }
79 argv.push_back(NULL);
80
81 std::vector<const char*> envp;
82 for (auto& str : envs) {
83 envp.push_back(str.c_str());
84 }
85 envp.push_back(NULL);
86
87 *ctx = create_android_logcat();
88 if (!*ctx) return NULL;
89
90 int fd = android_logcat_run_command_thread(
91 *ctx, argv.size() - 1, (char* const*)&argv[0], (char* const*)&envp[0]);
92 argv.clear();
93 args.clear();
94 envp.clear();
95 envs.clear();
96 if (fd < 0) {
97 android_logcat_destroy(ctx);
98 return NULL;
99 }
100
101 FILE* retval = fdopen(fd, "reb");
102 if (!retval) android_logcat_destroy(ctx);
103 return retval;
104}
105
106int android_logcat_pclose(android_logcat_context* ctx, FILE* output) {
107 if (*ctx) {
108 static const useconds_t wait_sample = 20000;
109 // Wait two seconds maximum
110 for (size_t retry = ((2 * 1000000) + wait_sample - 1) / wait_sample;
111 android_logcat_run_command_thread_running(*ctx) && retry; --retry) {
112 usleep(wait_sample);
113 }
114 }
115
116 if (output) fclose(output);
117 return android_logcat_destroy(ctx);
118}
119
120int android_logcat_system(const char* command) {
121 std::vector<std::string> args;
122 std::vector<std::string> envs;
123 if (!__android_logcat_parse(command, args, envs)) return -1;
124
125 std::vector<const char*> argv;
126 for (auto& str : args) {
127 argv.push_back(str.c_str());
128 }
129 argv.push_back(NULL);
130
131 std::vector<const char*> envp;
132 for (auto& str : envs) {
133 envp.push_back(str.c_str());
134 }
135 envp.push_back(NULL);
136
137 android_logcat_context ctx = create_android_logcat();
138 if (!ctx) return -1;
139 /* Command return value */
140 int retval = android_logcat_run_command(ctx, -1, -1, argv.size() - 1,
141 (char* const*)&argv[0],
142 (char* const*)&envp[0]);
143 /* destroy return value */
144 int ret = android_logcat_destroy(&ctx);
145 /* Paranoia merging any discrepancies between the two return values */
146 if (!ret) ret = retval;
147 return ret;
148}