1 /*
2 * Copyright (C) 2018 The Android Open Source Project
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in
12 * the documentation and/or other materials provided with the
13 * distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
18 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
19 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
22 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28 #include "test_utils.h"
29 #include <fcntl.h>
30 #include <termios.h>
31 #include <algorithm>
32 #include <iterator>
33 #include <sstream>
34
35 namespace fastboot {
36
37 namespace {
38 constexpr int rand_seed = 0;
39 std::default_random_engine rnd(rand_seed);
40 } // namespace
41
rand_legal()42 char rand_legal() {
43 return rnd() % 128;
44 }
45
rand_illegal()46 char rand_illegal() {
47 return rand_legal() + 128;
48 }
49
rand_char()50 char rand_char() {
51 return rnd() % 256;
52 }
53
random_int(int start,int end)54 int random_int(int start, int end) {
55 std::uniform_int_distribution<int> uni(start, end);
56 return uni(rnd);
57 }
58
RandomString(size_t length,std::function<char (void)> provider)59 std::string RandomString(size_t length, std::function<char(void)> provider) {
60 std::string str(length, 0);
61 std::generate_n(str.begin(), length, provider);
62 return str;
63 }
64
RandomBuf(size_t length,std::function<char (void)> provider)65 std::vector<char> RandomBuf(size_t length, std::function<char(void)> provider) {
66 std::vector<char> ret;
67 ret.resize(length);
68 std::generate_n(ret.begin(), length, provider);
69 return ret;
70 }
71
SplitBySpace(const std::string & s)72 std::vector<std::string> SplitBySpace(const std::string& s) {
73 std::istringstream iss(s);
74 return std::vector<std::string>{std::istream_iterator<std::string>{iss},
75 std::istream_iterator<std::string>{}};
76 }
77
GeneratePartitionNames(const std::string & base,int num_slots)78 std::vector<std::string> GeneratePartitionNames(const std::string& base, int num_slots) {
79 if (!num_slots) {
80 return std::vector<std::string>{base};
81 }
82 std::vector<std::string> ret;
83 for (char c = 'a'; c < 'a' + num_slots; c++) {
84 ret.push_back(base + '_' + c);
85 }
86
87 return ret;
88 }
89
ParseArgs(int argc,char ** argv,std::string * err_msg)90 std::unordered_map<std::string, std::string> ParseArgs(int argc, char** argv,
91 std::string* err_msg) {
92 // We ignore any gtest stuff
93 std::unordered_map<std::string, std::string> ret;
94
95 for (int i = 1; i < argc - 1; i++) {
96 std::string arg(argv[i]);
97
98 const std::string gtest_start("--gtest");
99 // We found a non gtest argument
100 if (!arg.find("-h") ||
101 (!arg.find("--") && arg.find("--gtest") && arg.find("=") != arg.npos)) {
102 const std::string start(arg.begin() + 2, arg.begin() + arg.find("="));
103 const std::string end(arg.begin() + arg.find("=") + 1, arg.end());
104 ret[start] = end;
105 } else if (arg.find("--gtest") != 0) {
106 *err_msg = android::base::StringPrintf("Illegal argument '%s'\n", arg.c_str());
107 return ret;
108 }
109 }
110
111 return ret;
112 }
113
ConfigureSerial(const std::string & port)114 int ConfigureSerial(const std::string& port) {
115 int fd = open(port.c_str(), O_RDONLY | O_NOCTTY | O_NONBLOCK);
116
117 if (fd <= 0) {
118 return fd;
119 }
120
121 struct termios tty;
122 tcgetattr(fd, &tty);
123
124 cfsetospeed(&tty, (speed_t)B115200);
125 cfsetispeed(&tty, (speed_t)B115200);
126
127 tty.c_cflag &= ~PARENB;
128 tty.c_cflag &= ~CSTOPB;
129 tty.c_cflag &= ~CSIZE;
130 tty.c_cflag |= CS8;
131
132 tty.c_cflag &= ~CRTSCTS;
133 tty.c_cc[VMIN] = 0;
134 tty.c_cc[VTIME] = 2;
135 tty.c_cflag &= ~(ICANON | ECHO | ECHOE | ISIG);
136
137 cfmakeraw(&tty);
138
139 tcflush(fd, TCIFLUSH);
140 if (tcsetattr(fd, TCSANOW, &tty) != 0) {
141 return -1;
142 }
143
144 return fd;
145 }
146
StartProgram(const std::string program,const std::vector<std::string> args,int * rpipe)147 int StartProgram(const std::string program, const std::vector<std::string> args, int* rpipe) {
148 int link[2];
149 if (pipe(link) < 0) {
150 return -1;
151 }
152
153 pid_t pid = fork();
154 if (pid < 0) { // error
155 return -1;
156 }
157
158 if (pid) { // parent
159 close(link[1]);
160 *rpipe = link[0];
161 fcntl(*rpipe, F_SETFL, O_NONBLOCK); // Non-blocking
162 } else { // child
163 std::vector<const char*> argv(args.size() + 2, nullptr);
164 argv[0] = program.c_str();
165
166 for (int i = 0; i < args.size(); i++) {
167 argv[i + 1] = args[i].c_str();
168 }
169
170 // We pipe any stderr writes to the parent test process
171 dup2(link[1], STDERR_FILENO); // close stdout and have it now be link[1]
172 // Close duplicates
173 close(link[0]);
174 close(link[1]);
175
176 execvp(program.c_str(), const_cast<char* const*>(argv.data()));
177 fprintf(stderr, "Launching validator process '%s' failed with: %s\n", program.c_str(),
178 strerror(errno));
179 exit(-1);
180 }
181
182 return pid;
183 }
184
WaitProgram(const int pid,const int pipe,std::string * error_msg)185 int WaitProgram(const int pid, const int pipe, std::string* error_msg) {
186 int status;
187 if (waitpid(pid, &status, 0) != pid) {
188 close(pipe);
189 return -1;
190 }
191 // Read from pipe
192 char buf[1024];
193 int n;
194 while ((n = read(pipe, buf, sizeof(buf))) > 0) {
195 buf[n] = 0; /* terminate the string */
196 error_msg->append(buf, n);
197 }
198 close(pipe);
199
200 if (WIFEXITED(status)) {
201 // This WEXITSTATUS macro masks off lower bytes, with no sign extension
202 // casting it as a signed char fixes the sign extension issue
203 int retmask = WEXITSTATUS(status);
204 return reinterpret_cast<int8_t*>(&retmask)[0];
205 }
206
207 return -1;
208 }
209
210 } // namespace fastboot
211