| // 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/processargs.h> |
| #include <magenta/syscalls.h> |
| #include <magenta/syscalls/object.h> |
| #include <memory> |
| #include <mxio/util.h> |
| #include <string> |
| |
| #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() |
| { |
| launchpad_t* lp; |
| mx_status_t status = launchpad_create(0u, "noname", &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_arguments(process->launchpad(), cmdLine->numArgs - 1, |
| (const char* const*)&cmdLine->args[1]); |
| assert(status == NO_ERROR); |
| |
| status = launchpad_load_vdso(process->launchpad(), MX_HANDLE_INVALID); |
| assert(status == NO_ERROR); |
| |
| status = launchpad_add_vdso_vmo(process->launchpad()); |
| assert(status == NO_ERROR); |
| |
| status = launchpad_clone_mxio_root(process->launchpad()); |
| assert(status == NO_ERROR); |
| |
| mx_handle_t vmo = launchpad_vmo_from_file(cmdLine->args[0]); |
| assert(vmo != MX_HANDLE_INVALID); |
| |
| status = launchpad_elf_load(process->launchpad(), vmo); |
| 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; |
| } |