1 /* 2 * Copyright 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "ShellDriver.h" 18 19 #include <stdio.h> 20 #include <stdlib.h> 21 #include <sys/socket.h> 22 #include <sys/types.h> 23 #include <sys/un.h> 24 #include <unistd.h> 25 26 #include <iostream> 27 #include <sstream> 28 29 #include <VtsDriverCommUtil.h> 30 #include <VtsDriverFileUtil.h> 31 #include "test/vts/proto/VtsDriverControlMessage.pb.h" 32 33 using namespace std; 34 35 namespace android { 36 namespace vts { 37 38 int VtsShellDriver::Close() { 39 cout << __func__ << endl; 40 int result = 0; 41 42 if (!this->socket_address_.empty()) { 43 result = unlink(this->socket_address_.c_str()); 44 if (result != 0) { 45 cerr << __func__ << ":" << __LINE__ 46 << " ERROR closing socket (errno = " << errno << ")" << endl; 47 } 48 this->socket_address_.clear(); 49 } 50 51 return result; 52 } 53 54 CommandResult* VtsShellDriver::ExecShellCommandPopen(const string& command) { 55 CommandResult* result = new CommandResult(); 56 57 // TODO: handle no output case. 58 FILE* output_fp; 59 60 cout << "[Driver] Running command: " << command << endl << endl; 61 62 // execute the command. 63 output_fp = popen(command.c_str(), "r"); 64 if (output_fp == NULL) { 65 cerr << "Failed to run command: " << command << endl; 66 result->exit_code = errno; 67 return result; 68 } 69 70 char buff[4096]; 71 stringstream ss; 72 73 int bytes_read; 74 while (!feof(output_fp)) { 75 bytes_read = fread(buff, 1, sizeof(buff) - 1, output_fp); 76 // TODO: catch stderr 77 if (ferror(output_fp)) { 78 cerr << __func__ << ":" << __LINE__ << "ERROR reading shell output" 79 << endl; 80 result->exit_code = -1; 81 return result; 82 } 83 84 cout << "[Driver] bytes read from output: " << bytes_read << endl; 85 buff[bytes_read] = '\0'; 86 ss << buff; 87 } 88 89 cout << "[Driver] Returning output: " << ss.str() << endl << endl; 90 result->stdout = ss.str(); 91 92 result->exit_code = pclose(output_fp) / 256; 93 return result; 94 } 95 96 CommandResult* VtsShellDriver::ExecShellCommandNohup(const string& command) { 97 CommandResult* result = new CommandResult(); 98 99 string temp_dir = GetDirFromFilePath(this->socket_address_); 100 string temp_file_name_pattern = temp_dir + "/nohupXXXXXX"; 101 int temp_file_name_len = temp_file_name_pattern.length() + 1; 102 char stdout_file_name[temp_file_name_len]; 103 char stderr_file_name[temp_file_name_len]; 104 strcpy(stdout_file_name, temp_file_name_pattern.c_str()); 105 strcpy(stderr_file_name, temp_file_name_pattern.c_str()); 106 int stdout_file = mkstemp(stdout_file_name); 107 int stderr_file = mkstemp(stderr_file_name); 108 close(stdout_file); 109 close(stderr_file); 110 111 stringstream ss; 112 ss << "nohup sh -c '" << command << "' >" << stdout_file_name << " 2>" 113 << stderr_file_name; 114 115 // execute the command. 116 int exit_code = system(ss.str().c_str()) / 256; 117 118 result->exit_code = exit_code; 119 result->stdout = ReadFile(stdout_file_name); 120 result->stderr = ReadFile(stderr_file_name); 121 122 remove(stdout_file_name); 123 remove(stderr_file_name); 124 125 return result; 126 } 127 128 int VtsShellDriver::ExecShellCommand( 129 const string& command, VtsDriverControlResponseMessage* responseMessage) { 130 CommandResult* result = this->ExecShellCommandNohup(command); 131 132 responseMessage->add_stdout(result->stdout); 133 responseMessage->add_stderr(result->stderr); 134 135 int exit_code = result->exit_code; 136 responseMessage->add_exit_code(result->exit_code); 137 138 delete result; 139 return exit_code; 140 } 141 142 int VtsShellDriver::HandleShellCommandConnection(int connection_fd) { 143 VtsDriverCommUtil driverUtil(connection_fd); 144 VtsDriverControlCommandMessage cmd_msg; 145 int numberOfFailure = 0; 146 147 while (1) { 148 if (!driverUtil.VtsSocketRecvMessage( 149 static_cast<google::protobuf::Message*>(&cmd_msg))) { 150 cerr << "[Shell driver] receiving message failure." << endl; 151 return -1; 152 } 153 154 if (cmd_msg.command_type() == EXIT) { 155 cout << "[Shell driver] received exit command." << endl; 156 break; 157 } else if (cmd_msg.command_type() != EXECUTE_COMMAND) { 158 cerr << "[Shell driver] unknown command type " << cmd_msg.command_type() 159 << endl; 160 continue; 161 } 162 cout << "[Shell driver] received " << cmd_msg.shell_command_size() 163 << " command(s). Processing... " << endl; 164 165 // execute command and write back output 166 VtsDriverControlResponseMessage responseMessage; 167 168 for (const auto& command : cmd_msg.shell_command()) { 169 if (ExecShellCommand(command, &responseMessage) != 0) { 170 cerr << "[Shell driver] error during executing command [" << command 171 << "]" << endl; 172 --numberOfFailure; 173 } 174 } 175 176 // TODO: other response code conditions 177 responseMessage.set_response_code(VTS_DRIVER_RESPONSE_SUCCESS); 178 if (!driverUtil.VtsSocketSendMessage(responseMessage)) { 179 fprintf(stderr, "Driver: write output to socket error.\n"); 180 --numberOfFailure; 181 } 182 cout << "[Shell driver] finished processing commands." << endl; 183 } 184 185 if (driverUtil.Close() != 0) { 186 cerr << "[Driver] failed to close connection. errno: " << errno << endl; 187 --numberOfFailure; 188 } 189 190 return numberOfFailure; 191 } 192 193 int VtsShellDriver::StartListen() { 194 if (this->socket_address_.empty()) { 195 cerr << "[Driver] NULL socket address." << endl; 196 return -1; 197 } 198 199 cout << "[Driver] start listening on " << this->socket_address_ << endl; 200 201 struct sockaddr_un address; 202 int socket_fd, connection_fd; 203 socklen_t address_length; 204 pid_t child; 205 206 socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); 207 if (socket_fd < 0) { 208 cerr << "Driver: socket() failed: " << strerror(errno) << endl; 209 return socket_fd; 210 } 211 212 unlink(this->socket_address_.c_str()); 213 memset(&address, 0, sizeof(struct sockaddr_un)); 214 address.sun_family = AF_UNIX; 215 strncpy(address.sun_path, this->socket_address_.c_str(), 216 sizeof(address.sun_path) - 1); 217 218 if (::bind(socket_fd, (struct sockaddr*)&address, 219 sizeof(struct sockaddr_un)) != 0) { 220 cerr << "Driver: bind() failed: " << strerror(errno) << endl; 221 return 1; 222 } 223 224 if (listen(socket_fd, 5) != 0) { 225 cerr << "Driver: listen() failed: " << strerror(errno) << endl; 226 return errno; 227 } 228 229 while (1) { 230 address_length = sizeof(address); 231 232 // TODO(yuexima) exit message to break loop 233 connection_fd = 234 accept(socket_fd, (struct sockaddr*)&address, &address_length); 235 if (connection_fd == -1) { 236 cerr << "Driver: accept error: " << strerror(errno) << endl; 237 break; 238 } 239 240 child = fork(); 241 if (child == 0) { 242 close(socket_fd); 243 // now inside newly created connection handling process 244 if (HandleShellCommandConnection(connection_fd) != 0) { 245 cerr << "[Driver] failed to handle connection." << endl; 246 close(connection_fd); 247 exit(1); 248 } 249 close(connection_fd); 250 exit(0); 251 } else if (child > 0) { 252 close(connection_fd); 253 } else { 254 cerr << "[Driver] create child process failed. Exiting..." << endl; 255 return (errno); 256 } 257 } 258 close(socket_fd); 259 260 return 0; 261 } 262 263 } // namespace vts 264 } // namespace android 265