1 /* 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 27 static 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 43 static 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 68 FILE* 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 106 int 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 120 int 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 } 149