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 #define LOG_TAG "VtsShellDriver" 17 18 #include "ShellDriver.h" 19 20 #include <sys/socket.h> 21 #include <sys/stat.h> 22 #include <sys/un.h> 23 #include <sstream> 24 25 #include <VtsDriverCommUtil.h> 26 #include <VtsDriverFileUtil.h> 27 #include <android-base/logging.h> 28 29 #include "test/vts/proto/VtsDriverControlMessage.pb.h" 30 31 using namespace std; 32 33 // Threshold of serialized proto msg size sent over socket. 34 static constexpr long kProtoSizeThreshold = 1024 * 1024; // 1MB 35 36 namespace android { 37 namespace vts { 38 39 int VtsShellDriver::Close() { 40 int result = 0; 41 42 if (!this->socket_address_.empty()) { 43 result = unlink(this->socket_address_.c_str()); 44 if (result != 0) { 45 LOG(ERROR) << " ERROR closing socket (errno = " << errno << ")"; 46 } 47 this->socket_address_.clear(); 48 } 49 50 return result; 51 } 52 53 CommandResult* VtsShellDriver::ExecShellCommandPopen(const string& command) { 54 CommandResult* result = new CommandResult(); 55 56 // TODO: handle no output case. 57 FILE* output_fp; 58 59 // execute the command. 60 output_fp = popen(command.c_str(), "r"); 61 if (output_fp == NULL) { 62 LOG(ERROR) << "Failed to run command: " << command; 63 result->exit_code = errno; 64 return result; 65 } 66 67 char buff[4096]; 68 stringstream ss; 69 70 int bytes_read; 71 while (!feof(output_fp)) { 72 bytes_read = fread(buff, 1, sizeof(buff) - 1, output_fp); 73 // TODO: catch stderr 74 if (ferror(output_fp)) { 75 LOG(ERROR) << "ERROR reading shell output"; 76 result->exit_code = -1; 77 return result; 78 } 79 80 buff[bytes_read] = '\0'; 81 ss << buff; 82 } 83 84 LOG(DEBUG) << " Returning output: " << ss.str(); 85 result->stdout = ss.str(); 86 87 result->exit_code = pclose(output_fp) / 256; 88 return result; 89 } 90 91 CommandResult* VtsShellDriver::ExecShellCommandNohup(const string& command) { 92 CommandResult* result = new CommandResult(); 93 94 string temp_dir = GetDirFromFilePath(this->socket_address_); 95 string temp_file_name_pattern = temp_dir + "/nohupXXXXXX"; 96 int temp_file_name_len = temp_file_name_pattern.length() + 1; 97 char stdout_file_name[temp_file_name_len]; 98 char stderr_file_name[temp_file_name_len]; 99 strcpy(stdout_file_name, temp_file_name_pattern.c_str()); 100 strcpy(stderr_file_name, temp_file_name_pattern.c_str()); 101 int stdout_file = mkstemp(stdout_file_name); 102 int stderr_file = mkstemp(stderr_file_name); 103 close(stdout_file); 104 close(stderr_file); 105 106 stringstream ss; 107 ss << "nohup sh -c '" << command << "' >" << stdout_file_name << " 2>" 108 << stderr_file_name; 109 110 // execute the command. 111 int exit_code = system(ss.str().c_str()) / 256; 112 result->exit_code = exit_code; 113 114 // If stdout size larger than threshold, send back the temp file path. 115 // Otherwise, send back the context directly. 116 long stdout_size = GetFileSize(stdout_file_name); 117 if (stdout_size > kProtoSizeThreshold) { 118 result->stdout = string(stdout_file_name); 119 } else { 120 result->stdout = ReadFile(stdout_file_name); 121 remove(stdout_file_name); 122 } 123 124 // If stderr size larger than threshold, send back the temp file path. 125 // Otherwise, send back the context directly. 126 long stderr_size = GetFileSize(stderr_file_name); 127 if (stderr_size > kProtoSizeThreshold) { 128 result->stderr = string(stderr_file_name); 129 } else { 130 result->stderr = ReadFile(stderr_file_name); 131 remove(stderr_file_name); 132 } 133 134 return result; 135 } 136 137 int VtsShellDriver::ExecShellCommand( 138 const string& command, VtsDriverControlResponseMessage* responseMessage) { 139 CommandResult* result = this->ExecShellCommandNohup(command); 140 141 responseMessage->add_stdout(result->stdout); 142 responseMessage->add_stderr(result->stderr); 143 144 int exit_code = result->exit_code; 145 responseMessage->add_exit_code(result->exit_code); 146 147 delete result; 148 return exit_code; 149 } 150 151 int VtsShellDriver::HandleShellCommandConnection(int connection_fd) { 152 VtsDriverCommUtil driverUtil(connection_fd); 153 VtsDriverControlCommandMessage cmd_msg; 154 int numberOfFailure = 0; 155 156 while (1) { 157 if (!driverUtil.VtsSocketRecvMessage( 158 static_cast<google::protobuf::Message*>(&cmd_msg))) { 159 LOG(ERROR) << "Receiving message failure."; 160 return -1; 161 } 162 163 if (cmd_msg.command_type() == EXIT) { 164 LOG(ERROR) << "Received exit command."; 165 break; 166 } else if (cmd_msg.command_type() != EXECUTE_COMMAND) { 167 LOG(ERROR) << "Unknown command type " << cmd_msg.command_type(); 168 continue; 169 } 170 LOG(INFO) << "Received " << cmd_msg.shell_command_size() 171 << " command(s). Processing..."; 172 173 // execute command and write back output 174 VtsDriverControlResponseMessage responseMessage; 175 176 for (const auto& command : cmd_msg.shell_command()) { 177 if (ExecShellCommand(command, &responseMessage) != 0) { 178 LOG(ERROR) << "Error during executing command [" << command << "]"; 179 --numberOfFailure; 180 } 181 } 182 183 // TODO: other response code conditions 184 responseMessage.set_response_code(VTS_DRIVER_RESPONSE_SUCCESS); 185 if (!driverUtil.VtsSocketSendMessage(responseMessage)) { 186 LOG(ERROR) << "Write output to socket error."; 187 --numberOfFailure; 188 } 189 LOG(DEBUG) << "Finished processing commands."; 190 } 191 192 if (driverUtil.Close() != 0) { 193 LOG(ERROR) << "Failed to close connection. errno: " << errno; 194 --numberOfFailure; 195 } 196 197 return numberOfFailure; 198 } 199 200 int VtsShellDriver::StartListen() { 201 if (this->socket_address_.empty()) { 202 LOG(ERROR) << "NULL socket address."; 203 return -1; 204 } 205 206 LOG(INFO) << "Start listening on " << this->socket_address_; 207 208 struct sockaddr_un address; 209 int socket_fd, connection_fd; 210 socklen_t address_length; 211 pid_t child; 212 213 socket_fd = socket(PF_UNIX, SOCK_STREAM, 0); 214 if (socket_fd < 0) { 215 LOG(ERROR) << "Socket() failed: " << strerror(errno); 216 return socket_fd; 217 } 218 219 unlink(this->socket_address_.c_str()); 220 memset(&address, 0, sizeof(struct sockaddr_un)); 221 address.sun_family = AF_UNIX; 222 strncpy(address.sun_path, this->socket_address_.c_str(), 223 sizeof(address.sun_path) - 1); 224 225 if (::bind(socket_fd, (struct sockaddr*)&address, 226 sizeof(struct sockaddr_un)) != 0) { 227 LOG(ERROR) << "bind() failed: " << strerror(errno); 228 return 1; 229 } 230 231 if (listen(socket_fd, 5) != 0) { 232 LOG(ERROR) << "listen() failed: " << strerror(errno); 233 return errno; 234 } 235 236 while (1) { 237 address_length = sizeof(address); 238 239 // TODO(yuexima) exit message to break loop 240 connection_fd = 241 accept(socket_fd, (struct sockaddr*)&address, &address_length); 242 if (connection_fd == -1) { 243 LOG(ERROR) << "Accept error: " << strerror(errno); 244 break; 245 } 246 247 child = fork(); 248 if (child == 0) { 249 close(socket_fd); 250 // now inside newly created connection handling process 251 if (HandleShellCommandConnection(connection_fd) != 0) { 252 LOG(ERROR) << "Failed to handle connection."; 253 close(connection_fd); 254 exit(1); 255 } 256 close(connection_fd); 257 exit(0); 258 } else if (child > 0) { 259 close(connection_fd); 260 } else { 261 LOG(ERROR) << "Create child process failed. Exiting..."; 262 return (errno); 263 } 264 } 265 close(socket_fd); 266 267 return 0; 268 } 269 270 long VtsShellDriver::GetFileSize(const char* filename) { 271 struct stat stat_buf; 272 int rc = stat(filename, &stat_buf); 273 return rc == 0 ? stat_buf.st_size : -1; 274 } 275 276 } // namespace vts 277 } // namespace android 278