Home | History | Annotate | Download | only in logcat
      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