blob: 042e702364283d682aa348c1f3b67a89b9eb3c81 [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 <zircon/process.h>
#include <zircon/processargs.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>
#include <memory>
#include <fdio/io.h>
#include <fdio/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()
{
zx_handle_t job_copy = ZX_HANDLE_INVALID;
zx_handle_duplicate(zx_job_default(), ZX_RIGHT_SAME_RIGHTS, &job_copy);
launchpad_t *lp;
zx_status_t status = launchpad_create(job_copy, "DeProcess", &lp);
if (status != ZX_OK)
return std::unique_ptr<DeProcess>();
return std::unique_ptr<DeProcess>(new DeProcess(lp));
}
DeProcess(launchpad_t* lp)
: lp_(lp), proc_(ZX_HANDLE_INVALID), fstdin_(nullptr), fstdout_(nullptr), fstderr_(nullptr)
{
}
~DeProcess()
{
launchpad_destroy(lp_);
if (proc_ != ZX_HANDLE_INVALID)
zx_handle_close(proc_);
closeStdIn();
closeStdOut();
closeStdErr();
}
launchpad_t* launchpad() { return lp_; }
bool start()
{
zx_status_t status;
status = launchpad_add_pipe(launchpad(), &remote_stdin_fd_, STDIN_FILENO);
assert(status == ZX_OK);
int stdout_fd;
status = launchpad_add_pipe(launchpad(), &stdout_fd, STDOUT_FILENO);
assert(status == ZX_OK);
int stderr_fd;
status = launchpad_add_pipe(launchpad(), &stderr_fd, STDERR_FILENO);
assert(status == ZX_OK);
fstdin_ = deFile_createFromHandle(remote_stdin_fd_);
fstdout_ = deFile_createFromHandle(stdout_fd);
fstderr_ = deFile_createFromHandle(stderr_fd);
const char* errmsg = NULL;
status = launchpad_go(lp_, &proc_, &errmsg);
if (status != ZX_OK)
return false;
return true;
}
bool IsRunning()
{
zx_signals_t pending = 0;
zx_status_t status = zx_object_wait_one(proc_, ZX_TASK_TERMINATED, 0, &pending);
if (pending & ZX_TASK_TERMINATED)
return false;
assert(status == ERR_TIMED_OUT);
return true;
}
bool Wait()
{
zx_status_t status = zx_object_wait_one(proc_, ZX_TASK_TERMINATED, ZX_TIME_INFINITE, NULL);
return status == ZX_OK;
}
int GetExitCode()
{
zx_info_process_t info;
zx_status_t status =
zx_object_get_info(proc_, ZX_INFO_PROCESS, &info, sizeof(info), NULL, NULL);
assert(status == ZX_OK);
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_;
zx_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);
zx_status_t status;
status = launchpad_set_args(process->launchpad(), cmdLine->numArgs - 1,
(const char *const *)&cmdLine->args[1]);
if (status != ZX_OK)
fprintf(stderr, "launcpad_set_args failed: %d\n", status);
assert(status == ZX_OK);
status = launchpad_clone(process->launchpad(), LP_CLONE_FDIO_NAMESPACE | LP_CLONE_FDIO_CWD);
assert(status == ZX_OK);
if (status != ZX_OK)
fprintf(stderr, "launchpad_clone failed: %d\n", status);
status = launchpad_load_from_file(process->launchpad(), cmdLine->args[0]);
if (status != ZX_OK)
fprintf(stderr, "launchpad_load_from_file failed: %d\n", status);
assert(status == ZX_OK);
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;
}