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 <sstream>
32 
33 namespace fastboot {
34 
35 namespace {
36 constexpr int rand_seed = 0;
37 std::default_random_engine rnd(rand_seed);
38 }  // namespace
39 
rand_legal()40 char rand_legal() {
41     return rnd() % 128;
42 }
43 
rand_illegal()44 char rand_illegal() {
45     return rand_legal() + 128;
46 }
47 
rand_char()48 char rand_char() {
49     return rnd() % 256;
50 }
51 
random_int(int start,int end)52 int random_int(int start, int end) {
53     std::uniform_int_distribution<int> uni(start, end);
54     return uni(rnd);
55 }
56 
RandomString(size_t length,std::function<char (void)> provider)57 std::string RandomString(size_t length, std::function<char(void)> provider) {
58     std::string str(length, 0);
59     std::generate_n(str.begin(), length, provider);
60     return str;
61 }
62 
RandomBuf(size_t length,std::function<char (void)> provider)63 std::vector<char> RandomBuf(size_t length, std::function<char(void)> provider) {
64     std::vector<char> ret;
65     ret.resize(length);
66     std::generate_n(ret.begin(), length, provider);
67     return ret;
68 }
69 
SplitBySpace(const std::string & s)70 std::vector<std::string> SplitBySpace(const std::string& s) {
71     std::istringstream iss(s);
72     return std::vector<std::string>{std::istream_iterator<std::string>{iss},
73                                     std::istream_iterator<std::string>{}};
74 }
75 
GeneratePartitionNames(const std::string & base,int num_slots)76 std::vector<std::string> GeneratePartitionNames(const std::string& base, int num_slots) {
77     if (!num_slots) {
78         return std::vector<std::string>{base};
79     }
80     std::vector<std::string> ret;
81     for (char c = 'a'; c < 'a' + num_slots; c++) {
82         ret.push_back(base + '_' + c);
83     }
84 
85     return ret;
86 }
87 
ParseArgs(int argc,char ** argv,std::string * err_msg)88 std::unordered_map<std::string, std::string> ParseArgs(int argc, char** argv,
89                                                        std::string* err_msg) {
90     // We ignore any gtest stuff
91     std::unordered_map<std::string, std::string> ret;
92 
93     for (int i = 1; i < argc - 1; i++) {
94         std::string arg(argv[i]);
95 
96         const std::string gtest_start("--gtest");
97         // We found a non gtest argument
98         if (!arg.find("-h") ||
99             (!arg.find("--") && arg.find("--gtest") && arg.find("=") != arg.npos)) {
100             const std::string start(arg.begin() + 2, arg.begin() + arg.find("="));
101             const std::string end(arg.begin() + arg.find("=") + 1, arg.end());
102             ret[start] = end;
103         } else if (arg.find("--gtest") != 0) {
104             *err_msg = android::base::StringPrintf("Illegal argument '%s'\n", arg.c_str());
105             return ret;
106         }
107     }
108 
109     return ret;
110 }
111 
ConfigureSerial(const std::string & port)112 int ConfigureSerial(const std::string& port) {
113     int fd = open(port.c_str(), O_RDONLY | O_NOCTTY | O_NONBLOCK);
114 
115     if (fd <= 0) {
116         return fd;
117     }
118 
119     struct termios tty;
120     tcgetattr(fd, &tty);
121 
122     cfsetospeed(&tty, (speed_t)B115200);
123     cfsetispeed(&tty, (speed_t)B115200);
124 
125     tty.c_cflag &= ~PARENB;
126     tty.c_cflag &= ~CSTOPB;
127     tty.c_cflag &= ~CSIZE;
128     tty.c_cflag |= CS8;
129 
130     tty.c_cflag &= ~CRTSCTS;
131     tty.c_cc[VMIN] = 0;
132     tty.c_cc[VTIME] = 2;
133     tty.c_cflag &= ~(ICANON | ECHO | ECHOE | ISIG);
134 
135     cfmakeraw(&tty);
136 
137     tcflush(fd, TCIFLUSH);
138     if (tcsetattr(fd, TCSANOW, &tty) != 0) {
139         return -1;
140     }
141 
142     return fd;
143 }
144 
StartProgram(const std::string program,const std::vector<std::string> args,int * rpipe)145 int StartProgram(const std::string program, const std::vector<std::string> args, int* rpipe) {
146     int link[2];
147     if (pipe(link) < 0) {
148         return -1;
149     }
150 
151     pid_t pid = fork();
152     if (pid < 0) {  // error
153         return -1;
154     }
155 
156     if (pid) {  // parent
157         close(link[1]);
158         *rpipe = link[0];
159         fcntl(*rpipe, F_SETFL, O_NONBLOCK);  // Non-blocking
160     } else {                                 // child
161         std::vector<const char*> argv(args.size() + 2, nullptr);
162         argv[0] = program.c_str();
163 
164         for (int i = 0; i < args.size(); i++) {
165             argv[i + 1] = args[i].c_str();
166         }
167 
168         // We pipe any stderr writes to the parent test process
169         dup2(link[1], STDERR_FILENO);  // close stdout and have it now be link[1]
170         // Close duplicates
171         close(link[0]);
172         close(link[1]);
173 
174         execvp(program.c_str(), const_cast<char* const*>(argv.data()));
175         fprintf(stderr, "Launching validator process '%s' failed with: %s\n", program.c_str(),
176                 strerror(errno));
177         exit(-1);
178     }
179 
180     return pid;
181 }
182 
WaitProgram(const int pid,const int pipe,std::string * error_msg)183 int WaitProgram(const int pid, const int pipe, std::string* error_msg) {
184     int status;
185     if (waitpid(pid, &status, 0) != pid) {
186         close(pipe);
187         return -1;
188     }
189     // Read from pipe
190     char buf[1024];
191     int n;
192     while ((n = read(pipe, buf, sizeof(buf))) > 0) {
193         buf[n] = 0; /* terminate the string */
194         error_msg->append(buf, n);
195     }
196     close(pipe);
197 
198     if (WIFEXITED(status)) {
199         // This WEXITSTATUS macro masks off lower bytes, with no sign extension
200         // casting it as a signed char fixes the sign extension issue
201         int retmask = WEXITSTATUS(status);
202         return reinterpret_cast<int8_t*>(&retmask)[0];
203     }
204 
205     return -1;
206 }
207 
208 }  // namespace fastboot
209