blob: 33890b15907dd40d6052e76521e72056bd93c7c2 [file] [log] [blame]
// Copyright 2016 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 <assert.h>
#include <launchpad/launchpad.h>
#include <launchpad/vmo.h>
#include <magenta/process.h>
#include <magenta/processargs.h>
#include <magenta/syscalls.h>
#include <magenta/syscalls/object.h>
#include <memory>
#include <mxio/io.h>
#include <mxio/util.h>
#include <string>
#include <unistd.h>
#include "deProcess.h"
#if (DE_OS != DE_OS_FUCHSIA)
#error DE_OS_FUCHSIA expected
#endif
#include "deCommandLine.h"
struct deProcess_s {
};
class DeProcess : public deProcess_s {
public:
static std::unique_ptr<DeProcess> Create()
{
mx_handle_t job_copy = MX_HANDLE_INVALID;
mx_handle_duplicate(mx_job_default(), MX_RIGHT_SAME_RIGHTS, &job_copy);
launchpad_t *lp;
mx_status_t status = launchpad_create(job_copy, "DeProcess", &lp);
if (status != NO_ERROR)
return std::unique_ptr<DeProcess>();
return std::unique_ptr<DeProcess>(new DeProcess(lp));
}
DeProcess(launchpad_t* lp)
: lp_(lp), proc_(MX_HANDLE_INVALID), fstdin_(nullptr), fstdout_(nullptr), fstderr_(nullptr)
{
}
~DeProcess()
{
launchpad_destroy(lp_);
if (proc_ != MX_HANDLE_INVALID)
mx_handle_close(proc_);
closeStdIn();
closeStdOut();
closeStdErr();
}
launchpad_t* launchpad() { return lp_; }
bool start()
{
mx_status_t status;
status = launchpad_add_pipe(launchpad(), &remote_stdin_fd_, STDIN_FILENO);
assert(status == NO_ERROR);
int stdout_fd;
status = launchpad_add_pipe(launchpad(), &stdout_fd, STDOUT_FILENO);
assert(status == NO_ERROR);
int stderr_fd;
status = launchpad_add_pipe(launchpad(), &stderr_fd, STDERR_FILENO);
assert(status == NO_ERROR);
fstdin_ = deFile_createFromHandle(remote_stdin_fd_);
fstdout_ = deFile_createFromHandle(stdout_fd);
fstderr_ = deFile_createFromHandle(stderr_fd);
proc_ = launchpad_start(lp_);
if (proc_ == MX_HANDLE_INVALID)
return false;
return true;
}
bool IsRunning()
{
mx_signals_t pending = 0;
mx_status_t status = mx_object_wait_one(proc_, MX_TASK_TERMINATED, 0, &pending);
if (pending & MX_TASK_TERMINATED)
return false;
assert(status == ERR_TIMED_OUT);
return true;
}
bool Wait()
{
mx_status_t status = mx_object_wait_one(proc_, MX_TASK_TERMINATED, MX_TIME_INFINITE, NULL);
return status == NO_ERROR;
}
int GetExitCode()
{
mx_info_process_t info;
mx_status_t status =
mx_object_get_info(proc_, MX_INFO_PROCESS, &info, sizeof(info), NULL, NULL);
assert(status == NO_ERROR);
return info.return_code;
}
static DeProcess* cast(deProcess* process) { return static_cast<DeProcess*>(process); }
deFile* fstdin() { return fstdin_; }
deFile* fstdout() { return fstdout_; }
deFile* fstderr() { return fstderr_; }
void closeStdIn()
{
if (fstdin_) {
deFile_destroy(fstdin_);
fstdin_ = nullptr;
}
}
void closeStdOut()
{
if (fstdout_) {
deFile_destroy(fstdout_);
fstdout_ = nullptr;
}
}
void closeStdErr()
{
if (fstderr_) {
deFile_destroy(fstderr_);
fstderr_ = nullptr;
}
}
private:
launchpad_t* lp_;
mx_handle_t proc_;
int remote_stdin_fd_;
deFile* fstdin_;
deFile* fstdout_;
deFile* fstderr_;
};
deProcess* deProcess_create()
{
std::unique_ptr<DeProcess> process = DeProcess::Create();
if (!process)
return nullptr;
return process.release();
}
void deProcess_destroy(deProcess* process) { delete DeProcess::cast(process); }
deBool deProcess_start(deProcess* de_process, const char* commandLine, const char* workingDirectory)
{
(void)workingDirectory;
DeProcess* process = DeProcess::cast(de_process);
deCommandLine* cmdLine = deCommandLine_parse(commandLine);
mx_status_t status;
status = launchpad_set_args(process->launchpad(), cmdLine->numArgs - 1,
(const char *const *)&cmdLine->args[1]);
if (status != NO_ERROR)
fprintf(stderr, "launcpad_set_args failed: %d\n", status);
assert(status == NO_ERROR);
mx_handle_t vfs_root;
uint32_t vfs_root_type;
status = mxio_clone_root(&vfs_root, &vfs_root_type);
if (status <= 0) { // positive values apparently are ok
fprintf(stderr, "mxio_clone_root failed: %d\n", status);
assert(false);
}
status =
launchpad_add_handle(process->launchpad(), vfs_root, vfs_root_type);
if (status != NO_ERROR)
fprintf(stderr, "launchpad_add_handle failed: %d\n", status);
assert(status == NO_ERROR);
status = launchpad_load_from_file(process->launchpad(), cmdLine->args[0]);
if (status != NO_ERROR)
fprintf(stderr, "launchpad_load_from_file failed: %d\n", status);
assert(status == NO_ERROR);
if (!process->start())
return false;
return true;
}
deBool deProcess_isRunning(deProcess* process) { return DeProcess::cast(process)->IsRunning(); }
deBool deProcess_waitForFinish(deProcess* process)
{
return DeProcess::cast(process)->Wait() ? DE_TRUE : DE_FALSE;
}
const char* deProcess_getLastError(const deProcess*) { return nullptr; }
int deProcess_getExitCode(const deProcess* process)
{
return DeProcess::cast((deProcess*)process)->GetExitCode();
}
deBool deProcess_terminate(deProcess*)
{
printf("%s:%d Not implemented\n", __FILE__, __LINE__);
return DE_FALSE;
}
deBool deProcess_kill(deProcess*)
{
printf("%s:%d Not implemented\n", __FILE__, __LINE__);
return DE_FALSE;
}
deFile* deProcess_getStdIn(deProcess* process) { return DeProcess::cast(process)->fstdin(); }
deFile* deProcess_getStdOut(deProcess* process) { return DeProcess::cast(process)->fstdout(); }
deFile* deProcess_getStdErr(deProcess* process) { return DeProcess::cast(process)->fstderr(); }
deBool deProcess_closeStdIn(deProcess* process)
{
DeProcess::cast(process)->closeStdIn();
return DE_TRUE;
}
deBool deProcess_closeStdOut(deProcess* process)
{
DeProcess::cast(process)->closeStdOut();
return DE_TRUE;
}
deBool deProcess_closeStdErr(deProcess* process)
{
DeProcess::cast(process)->closeStdErr();
return DE_TRUE;
}