209 lines
6.1 KiB
C++
209 lines
6.1 KiB
C++
|
/*
|
||
|
* 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 <fcntl.h>
|
||
|
#include <termios.h>
|
||
|
#include <sstream>
|
||
|
|
||
|
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<int> uni(start, end);
|
||
|
return uni(rnd);
|
||
|
}
|
||
|
|
||
|
std::string RandomString(size_t length, std::function<char(void)> provider) {
|
||
|
std::string str(length, 0);
|
||
|
std::generate_n(str.begin(), length, provider);
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
std::vector<char> RandomBuf(size_t length, std::function<char(void)> provider) {
|
||
|
std::vector<char> ret;
|
||
|
ret.resize(length);
|
||
|
std::generate_n(ret.begin(), length, provider);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
std::vector<std::string> SplitBySpace(const std::string& s) {
|
||
|
std::istringstream iss(s);
|
||
|
return std::vector<std::string>{std::istream_iterator<std::string>{iss},
|
||
|
std::istream_iterator<std::string>{}};
|
||
|
}
|
||
|
|
||
|
std::vector<std::string> GeneratePartitionNames(const std::string& base, int num_slots) {
|
||
|
if (!num_slots) {
|
||
|
return std::vector<std::string>{base};
|
||
|
}
|
||
|
std::vector<std::string> ret;
|
||
|
for (char c = 'a'; c < 'a' + num_slots; c++) {
|
||
|
ret.push_back(base + '_' + c);
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
std::unordered_map<std::string, std::string> ParseArgs(int argc, char** argv,
|
||
|
std::string* err_msg) {
|
||
|
// We ignore any gtest stuff
|
||
|
std::unordered_map<std::string, std::string> 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<std::string> 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<const char*> 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<char* const*>(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<int8_t*>(&retmask)[0];
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
} // namespace fastboot
|