blob: 7ed7536046d62eaccc47dfbdcb7507cfbe99271c [file] [log] [blame]
// Copyright 2017 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 <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fs-management/mount.h>
#include <lib/fdio/io.h>
#include <lib/fdio/spawn.h>
#include <lib/fdio/fd.h>
#include <lib/fdio/fdio.h>
#include <lib/fdio/directory.h>
#include <lib/zx/process.h>
#include <zircon/compiler.h>
#include <zircon/processargs.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
namespace {
void InitArgvAndActions(zx_handle_t* handles, uint32_t* types, size_t len,
fdio_spawn_action_t* actions_out) {
for (size_t i = 0; i < len; ++i) {
actions_out[i].action = FDIO_SPAWN_ACTION_ADD_HANDLE;
actions_out[i].h.id = types[i];
actions_out[i].h.handle = handles[i];
}
}
constexpr size_t kMaxStdioActions = 1;
enum class StdioType {
kLog,
kClone,
kNone,
};
// Initializes Stdio.
//
// If necessary, updates the |actions| which will be sent to fdio_spawn.
// |action_count| is an in/out parameter which may be increased if an action is
// added.
// |flags| is an in/out parameter which may be modified to alter the cloning of
// STDIO.
void InitStdio(StdioType stdio, fdio_spawn_action_t* actions,
size_t* action_count, uint32_t* flags) {
switch (stdio) {
case StdioType::kLog:
zx_handle_t h;
zx_debuglog_create(ZX_HANDLE_INVALID, 0, &h);
if (h != ZX_HANDLE_INVALID) {
actions[*action_count].action = FDIO_SPAWN_ACTION_ADD_HANDLE;
actions[*action_count].h.id = PA_HND(PA_FD, FDIO_FLAG_USE_FOR_STDIO);
actions[*action_count].h.handle = h;
*action_count += 1;
}
*flags &= ~FDIO_SPAWN_CLONE_STDIO;
break;
case StdioType::kClone:
*flags |= FDIO_SPAWN_CLONE_STDIO;
break;
case StdioType::kNone:
*flags &= ~FDIO_SPAWN_CLONE_STDIO;
break;
}
}
enum class ProcessAction {
kBlock,
kNonBlock,
};
// Spawns a process.
//
// Optionally blocks, waiting for the process to terminate, depending
// the value provided in |block|.
zx_status_t Spawn(ProcessAction proc_action, uint32_t flags, const char** argv,
size_t action_count, const fdio_spawn_action_t* actions) {
zx::process proc;
char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
zx_status_t status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, argv[0], argv, nullptr,
action_count, actions, proc.reset_and_get_address(),
err_msg);
if (status != ZX_OK) {
fprintf(stderr, "fs-management: Cannot spawn %s: %d (%s): %s\n",
argv[0], status, zx_status_get_string(status), err_msg);
return status;
}
if (proc_action == ProcessAction::kBlock) {
status = proc.wait_one(ZX_PROCESS_TERMINATED, zx::time::infinite(), nullptr);
if (status != ZX_OK) {
fprintf(stderr, "spawn: Error waiting for process to terminate\n");
return status;
}
zx_info_process_t info;
status = proc.get_info(ZX_INFO_PROCESS, &info, sizeof(info), nullptr, nullptr);
if (status != ZX_OK) {
fprintf(stderr, "spawn: Failed to get process info\n");
return status;
}
if (!info.exited || info.return_code != 0) {
return ZX_ERR_BAD_STATE;
}
}
return ZX_OK;
}
zx_status_t Launch(StdioType stdio, ProcessAction proc_action, int argc,
const char** argv, zx_handle_t* handles, uint32_t* types, size_t len) {
fdio_spawn_action_t actions[len + kMaxStdioActions];
InitArgvAndActions(handles, types, len, actions);
size_t action_count = len;
uint32_t flags = FDIO_SPAWN_CLONE_ALL;
InitStdio(stdio, actions, &action_count, &flags);
return Spawn(proc_action, flags, argv, action_count, actions);
}
} // namespace
zx_status_t launch_silent_sync(int argc, const char** argv, zx_handle_t* handles,
uint32_t* types, size_t len) {
return Launch(StdioType::kNone, ProcessAction::kBlock, argc, argv, handles, types, len);
}
zx_status_t launch_silent_async(int argc, const char** argv, zx_handle_t* handles,
uint32_t* types, size_t len) {
return Launch(StdioType::kNone, ProcessAction::kNonBlock, argc, argv, handles, types, len);
}
zx_status_t launch_stdio_sync(int argc, const char** argv, zx_handle_t* handles,
uint32_t* types, size_t len) {
return Launch(StdioType::kClone, ProcessAction::kBlock, argc, argv, handles, types, len);
}
zx_status_t launch_stdio_async(int argc, const char** argv, zx_handle_t* handles,
uint32_t* types, size_t len) {
return Launch(StdioType::kClone, ProcessAction::kNonBlock, argc, argv, handles, types, len);
}
zx_status_t launch_logs_async(int argc, const char** argv, zx_handle_t* handles,
uint32_t* types, size_t len) {
return Launch(StdioType::kLog, ProcessAction::kNonBlock, argc, argv, handles, types, len);
}