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 <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