blob: 49338521f874c8f18af1d25e949b222c0a9c740b [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <errno.h>
#include <fcntl.h>
#include <libgen.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <wordexp.h>
#include <filesystem>
#include "platform_interface.h"
#include "src/virtualization/lib/guest_interaction/common.h"
int32_t PosixPlatform::OpenFile(std::string file_path, FileOpenMode mode) {
int32_t flags = O_NONBLOCK;
if (mode == WRITE) {
flags |= O_WRONLY | O_TRUNC | O_CREAT;
} else {
flags |= O_RDONLY;
}
int32_t fd = open(file_path.c_str(), flags);
if (fd < 0) {
return -errno;
}
return fd;
}
int32_t PosixPlatform::WriteFile(int32_t fd, const char* file_contents, uint32_t write_size) {
ssize_t bytes_written = 0;
while (bytes_written < write_size) {
ssize_t curr_bytes_written =
write(fd, file_contents + bytes_written, write_size - bytes_written);
if (curr_bytes_written < 0) {
return -errno;
}
bytes_written += curr_bytes_written;
}
return bytes_written;
}
int32_t PosixPlatform::ReadFile(int32_t fd, char* file_buf, uint32_t read_size) {
ssize_t bytes_read = read(fd, file_buf, read_size);
if (bytes_read < 0) {
return -errno;
}
return bytes_read;
}
int32_t PosixPlatform::CloseFile(int32_t fd) {
int32_t close_status = close(fd);
if (close_status < 0) {
return -errno;
}
return close_status;
}
bool PosixPlatform::FileExists(std::string file_path) {
struct stat file_stat;
if (stat(file_path.c_str(), &file_stat) != 0) {
return false;
}
return S_ISREG(file_stat.st_mode);
}
bool PosixPlatform::DirectoryExists(std::string dir_path) {
struct stat dir_stat;
if (stat(dir_path.c_str(), &dir_stat) != 0) {
return false;
}
return S_ISDIR(dir_stat.st_mode);
}
bool PosixPlatform::CreateDirectory(std::string dir_path) {
if (dir_path.size() == 0) {
return false;
}
if (DirectoryExists(dir_path)) {
return true;
}
char* dir_path_copy = strdup(dir_path.c_str());
bool create_status = CreateDirectory(std::string(dirname(dir_path_copy)));
free(dir_path_copy);
if (!create_status) {
return false;
}
if (mkdir(dir_path.c_str(), S_IRWXU | S_IRWXG | S_IRWXO) != 0) {
return false;
}
return true;
}
int32_t PosixPlatform::GetStubFD(uint32_t cid, uint32_t port) {
int sockfd = socket(AF_VSOCK, SOCK_STREAM | SOCK_NONBLOCK, 0);
sockaddr_vm addr = {
.svm_family = AF_VSOCK,
.svm_reserved1 = 0,
.svm_port = port,
.svm_cid = cid,
.svm_zero = {0},
};
return connect(sockfd, (sockaddr*)&addr, sizeof(sockaddr_vm));
}
int32_t PosixPlatform::GetServerFD(uint32_t cid, uint32_t port) {
int sockfd = socket(AF_VSOCK, SOCK_STREAM | SOCK_NONBLOCK, 0);
sockaddr_vm addr = {
.svm_family = AF_VSOCK,
.svm_reserved1 = 0,
.svm_port = port,
.svm_cid = cid,
.svm_zero = {0},
};
if (bind(sockfd, (sockaddr*)&addr, sizeof(sockaddr_vm)) != 0) {
return errno;
}
if (listen(sockfd, 100) != 0) {
return errno;
}
return sockfd;
}
void PosixPlatform::AcceptClient(grpc::Server* server, uint32_t sockfd) {
sockaddr addr;
socklen_t addr_len;
int new_fd = accept(sockfd, &addr, &addr_len);
if (new_fd > 0) {
fcntl(new_fd, F_SETFL, fcntl(new_fd, F_GETFL, 0) | O_NONBLOCK);
grpc::AddInsecureChannelFromFd(server, new_fd);
}
}
int32_t PosixPlatform::Exec(char** args, char** env, int32_t* user_std_in, int32_t* user_std_out,
int32_t* user_std_err) {
int std_in[2];
int std_out[2];
int std_err[2];
if (pipe(std_in) != 0 || pipe(std_out) != 0 || pipe(std_err) != 0) {
return -errno;
}
pid_t child_pid = fork();
if (child_pid == 0) {
if (close(std_in[1]) != 0 || close(std_out[0]) != 0 || close(std_err[0]) != 0) {
exit(-errno);
}
if (dup2(std_in[0], STDIN_FILENO) < 0 || dup2(std_out[1], STDOUT_FILENO) < 0 ||
dup2(std_err[1], STDERR_FILENO) < 0) {
exit(-errno);
}
execve(args[0], &args[0], &env[0]);
exit(-errno);
} else if (child_pid < 0) {
return -errno;
} else {
if (close(std_in[0]) != 0 || close(std_out[1]) != 0 || close(std_err[1]) != 0) {
return -errno;
}
// Set read FD's to nonblocking mode.
int flags = fcntl(std_out[0], F_GETFL, 0);
fcntl(std_out[0], F_SETFL, flags | O_NONBLOCK);
flags = fcntl(std_err[0], F_GETFL, 0);
fcntl(std_err[0], F_SETFL, flags | O_NONBLOCK);
*user_std_in = std_in[1];
*user_std_out = std_out[0];
*user_std_err = std_err[0];
return child_pid;
}
}
int32_t PosixPlatform::WaitPid(int32_t pid, int32_t* status, int32_t flags) {
int32_t poll_pid = waitpid(pid, status, flags);
if (poll_pid < 0) {
return -errno;
}
return poll_pid;
}
int32_t PosixPlatform::KillPid(int32_t pid, int32_t signal) {
int32_t ret = kill(pid, signal);
if (ret < 0) {
return -errno;
}
return ret;
}
void PosixPlatform::SetFileNonblocking(int32_t fd) {
int flags = fcntl(fd, F_GETFL, 0);
fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}
std::vector<std::string> PosixPlatform::ParseCommand(std::string command) {
wordexp_t command_line;
int32_t parse_result = wordexp(command.c_str(), &command_line, 0);
std::vector<std::string> argv;
if (parse_result == 0) {
for (uint32_t i = 0; i < command_line.we_wordc; i++) {
argv.push_back(command_line.we_wordv[i]);
}
}
wordfree(&command_line);
return argv;
}