/* * Copyright (C) 2018 The Android Open Source Project * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "test_utils.h" #include #include #include namespace fastboot { namespace { constexpr int rand_seed = 0; std::default_random_engine rnd(rand_seed); } // namespace char rand_legal() { return rnd() % 128; } char rand_illegal() { return rand_legal() + 128; } char rand_char() { return rnd() % 256; } int random_int(int start, int end) { std::uniform_int_distribution uni(start, end); return uni(rnd); } std::string RandomString(size_t length, std::function provider) { std::string str(length, 0); std::generate_n(str.begin(), length, provider); return str; } std::vector RandomBuf(size_t length, std::function provider) { std::vector ret; ret.resize(length); std::generate_n(ret.begin(), length, provider); return ret; } std::vector SplitBySpace(const std::string& s) { std::istringstream iss(s); return std::vector{std::istream_iterator{iss}, std::istream_iterator{}}; } std::vector GeneratePartitionNames(const std::string& base, int num_slots) { if (!num_slots) { return std::vector{base}; } std::vector ret; for (char c = 'a'; c < 'a' + num_slots; c++) { ret.push_back(base + '_' + c); } return ret; } std::unordered_map ParseArgs(int argc, char** argv, std::string* err_msg) { // We ignore any gtest stuff std::unordered_map ret; for (int i = 1; i < argc - 1; i++) { std::string arg(argv[i]); const std::string gtest_start("--gtest"); // We found a non gtest argument if (!arg.find("-h") || (!arg.find("--") && arg.find("--gtest") && arg.find("=") != arg.npos)) { const std::string start(arg.begin() + 2, arg.begin() + arg.find("=")); const std::string end(arg.begin() + arg.find("=") + 1, arg.end()); ret[start] = end; } else if (arg.find("--gtest") != 0) { *err_msg = android::base::StringPrintf("Illegal argument '%s'\n", arg.c_str()); return ret; } } return ret; } int ConfigureSerial(const std::string& port) { int fd = open(port.c_str(), O_RDONLY | O_NOCTTY | O_NONBLOCK); if (fd <= 0) { return fd; } struct termios tty; tcgetattr(fd, &tty); cfsetospeed(&tty, (speed_t)B115200); cfsetispeed(&tty, (speed_t)B115200); tty.c_cflag &= ~PARENB; tty.c_cflag &= ~CSTOPB; tty.c_cflag &= ~CSIZE; tty.c_cflag |= CS8; tty.c_cflag &= ~CRTSCTS; tty.c_cc[VMIN] = 0; tty.c_cc[VTIME] = 2; tty.c_cflag &= ~(ICANON | ECHO | ECHOE | ISIG); cfmakeraw(&tty); tcflush(fd, TCIFLUSH); if (tcsetattr(fd, TCSANOW, &tty) != 0) { return -1; } return fd; } int StartProgram(const std::string program, const std::vector args, int* rpipe) { int link[2]; if (pipe(link) < 0) { return -1; } pid_t pid = fork(); if (pid < 0) { // error return -1; } if (pid) { // parent close(link[1]); *rpipe = link[0]; fcntl(*rpipe, F_SETFL, O_NONBLOCK); // Non-blocking } else { // child std::vector argv(args.size() + 2, nullptr); argv[0] = program.c_str(); for (int i = 0; i < args.size(); i++) { argv[i + 1] = args[i].c_str(); } // We pipe any stderr writes to the parent test process dup2(link[1], STDERR_FILENO); // close stdout and have it now be link[1] // Close duplicates close(link[0]); close(link[1]); execvp(program.c_str(), const_cast(argv.data())); fprintf(stderr, "Launching validator process '%s' failed with: %s\n", program.c_str(), strerror(errno)); exit(-1); } return pid; } int WaitProgram(const int pid, const int pipe, std::string* error_msg) { int status; if (waitpid(pid, &status, 0) != pid) { close(pipe); return -1; } // Read from pipe char buf[1024]; int n; while ((n = read(pipe, buf, sizeof(buf))) > 0) { buf[n] = 0; /* terminate the string */ error_msg->append(buf, n); } close(pipe); if (WIFEXITED(status)) { // This WEXITSTATUS macro masks off lower bytes, with no sign extension // casting it as a signed char fixes the sign extension issue int retmask = WEXITSTATUS(status); return reinterpret_cast(&retmask)[0]; } return -1; } } // namespace fastboot