blob: 9ad98be60acf10faa551968f284d7d62fabe6a55 [file] [log] [blame]
/*
* 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