16dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn/*
26dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn * Copyright (C) 2017 The Android Open Source Project
36dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn *
46dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn * Licensed under the Apache License, Version 2.0 (the "License");
56dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn * you may not use this file except in compliance with the License.
66dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn * You may obtain a copy of the License at
76dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn *
86dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn *      http://www.apache.org/licenses/LICENSE-2.0
96dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn *
106dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn * Unless required by applicable law or agreed to in writing, software
116dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn * distributed under the License is distributed on an "AS IS" BASIS,
126dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn * See the License for the specific language governing permissions and
146dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn * limitations under the License.
156dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn */
166dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
176dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn#include <ctype.h>
1803d055d6ff38993c04fcc3ec24becda35b119a52Josh Gao#include <fcntl.h>
196dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn#include <stdio.h>
206dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn#include <string.h>
216dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn#include <unistd.h>
226dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
236dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn#include <string>
246dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn#include <vector>
256dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
266dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn#include <log/logcat.h>
276dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
286dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzynstatic std::string unquote(const char*& cp, const char*& delim) {
296dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    if ((*cp == '\'') || (*cp == '"')) {
306dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        // KISS: Simple quotes. Do not handle the case
316dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        //       of concatenation like "blah"foo'bar'
326dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        char quote = *cp++;
336dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        delim = strchr(cp, quote);
346dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        if (!delim) delim = cp + strlen(cp);
356dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        std::string str(cp, delim);
366dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        if (*delim) ++delim;
376dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        return str;
386dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    }
396dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    delim = strpbrk(cp, " \t\f\r\n");
406dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    if (!delim) delim = cp + strlen(cp);
416dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    return std::string(cp, delim);
426dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn}
436dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
446dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzynstatic bool __android_logcat_parse(const char* command,
456dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn                                   std::vector<std::string>& args,
466dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn                                   std::vector<std::string>& envs) {
476dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    for (const char *delim, *cp = command; cp && *cp; cp = delim) {
486dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        while (isspace(*cp)) ++cp;
496dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        if ((args.size() == 0) && (*cp != '=') && !isdigit(*cp)) {
506dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn            const char* env = cp;
516dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn            while (isalnum(*cp) || (*cp == '_')) ++cp;
526dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn            if (cp && (*cp == '=')) {
536dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn                std::string str(env, ++cp);
546dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn                str += unquote(cp, delim);
556dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn                envs.push_back(str);
566dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn                continue;
576dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn            }
586dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn            cp = env;
596dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        }
606dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        args.push_back(unquote(cp, delim));
616dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        if ((args.size() == 1) && (args[0] != "logcat") &&
626dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn            (args[0] != "/system/bin/logcat")) {
636dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn            return false;
646dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        }
656dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    }
666dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    return args.size() != 0;
676dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn}
686dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
696dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark SalyzynFILE* android_logcat_popen(android_logcat_context* ctx, const char* command) {
706dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    *ctx = NULL;
716dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
726dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    std::vector<std::string> args;
736dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    std::vector<std::string> envs;
746dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    if (!__android_logcat_parse(command, args, envs)) return NULL;
756dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
766dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    std::vector<const char*> argv;
776dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    for (auto& str : args) {
786dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        argv.push_back(str.c_str());
796dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    }
806dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    argv.push_back(NULL);
816dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
826dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    std::vector<const char*> envp;
836dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    for (auto& str : envs) {
846dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        envp.push_back(str.c_str());
856dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    }
866dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    envp.push_back(NULL);
876dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
886dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    *ctx = create_android_logcat();
896dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    if (!*ctx) return NULL;
906dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
916dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    int fd = android_logcat_run_command_thread(
926dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        *ctx, argv.size() - 1, (char* const*)&argv[0], (char* const*)&envp[0]);
936dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    argv.clear();
946dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    args.clear();
956dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    envp.clear();
966dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    envs.clear();
976dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    if (fd < 0) {
986dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        android_logcat_destroy(ctx);
996dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        return NULL;
1006dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    }
1016dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
10203d055d6ff38993c04fcc3ec24becda35b119a52Josh Gao    int duped = dup(fd);
10303d055d6ff38993c04fcc3ec24becda35b119a52Josh Gao    FILE* retval = fdopen(duped, "reb");
10403d055d6ff38993c04fcc3ec24becda35b119a52Josh Gao    if (!retval) {
10503d055d6ff38993c04fcc3ec24becda35b119a52Josh Gao        close(duped);
10603d055d6ff38993c04fcc3ec24becda35b119a52Josh Gao        android_logcat_destroy(ctx);
10703d055d6ff38993c04fcc3ec24becda35b119a52Josh Gao    }
1086dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    return retval;
1096dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn}
1106dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
1116dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzynint android_logcat_pclose(android_logcat_context* ctx, FILE* output) {
1126dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    if (*ctx) {
1136dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        static const useconds_t wait_sample = 20000;
1146dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        // Wait two seconds maximum
1156dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        for (size_t retry = ((2 * 1000000) + wait_sample - 1) / wait_sample;
1166dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn             android_logcat_run_command_thread_running(*ctx) && retry; --retry) {
1176dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn            usleep(wait_sample);
1186dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        }
1196dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    }
1206dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
1216dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    if (output) fclose(output);
1226dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    return android_logcat_destroy(ctx);
1236dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn}
1246dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
1256dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzynint android_logcat_system(const char* command) {
1266dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    std::vector<std::string> args;
1276dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    std::vector<std::string> envs;
1286dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    if (!__android_logcat_parse(command, args, envs)) return -1;
1296dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
1306dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    std::vector<const char*> argv;
1316dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    for (auto& str : args) {
1326dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        argv.push_back(str.c_str());
1336dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    }
1346dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    argv.push_back(NULL);
1356dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
1366dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    std::vector<const char*> envp;
1376dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    for (auto& str : envs) {
1386dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn        envp.push_back(str.c_str());
1396dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    }
1406dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    envp.push_back(NULL);
1416dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn
1426dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    android_logcat_context ctx = create_android_logcat();
1436dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    if (!ctx) return -1;
1446dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    /* Command return value */
1456dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    int retval = android_logcat_run_command(ctx, -1, -1, argv.size() - 1,
1466dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn                                            (char* const*)&argv[0],
1476dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn                                            (char* const*)&envp[0]);
1486dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    /* destroy return value */
1496dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    int ret = android_logcat_destroy(&ctx);
1506dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    /* Paranoia merging any discrepancies between the two return values */
1516dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    if (!ret) ret = retval;
1526dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn    return ret;
1536dabc81a0b7eac772209e8eef70ff3b156e5cc6bMark Salyzyn}
154