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