| // 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 <fcntl.h> |
| #include <fuchsia/virtualconsole/c/fidl.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/fdio/fd.h> |
| #include <lib/fdio/fdio.h> |
| #include <lib/fdio/io.h> |
| #include <lib/fdio/spawn.h> |
| #include <lib/fdio/watcher.h> |
| #include <lib/zircon-internal/paths.h> |
| #include <limits.h> |
| #include <stdbool.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <zircon/process.h> |
| #include <zircon/processargs.h> |
| #include <zircon/status.h> |
| #include <zircon/syscalls.h> |
| #include <zircon/types.h> |
| |
| static zx_status_t connect_to_service(const char* service, zx_handle_t* channel) { |
| zx_handle_t channel_local, channel_remote; |
| zx_status_t status = zx_channel_create(0, &channel_local, &channel_remote); |
| if (status != ZX_OK) { |
| fprintf(stderr, "run-vc: failed to create channel: %s\n", zx_status_get_string(status)); |
| return false; |
| } |
| |
| status = fdio_service_connect(service, channel_remote); |
| if (status != ZX_OK) { |
| zx_handle_close(channel_local); |
| fprintf(stderr, "run-vc: failed to connect to service: %s\n", zx_status_get_string(status)); |
| return false; |
| } |
| |
| *channel = channel_local; |
| return true; |
| } |
| |
| int main(int argc, const char** argv) { |
| zx_handle_t session_manager = ZX_HANDLE_INVALID; |
| if (!connect_to_service("/svc/fuchsia.virtualconsole.SessionManager", &session_manager)) { |
| return -1; |
| } |
| |
| zx_handle_t session, session_remote; |
| if (zx_channel_create(0, &session, &session_remote) != ZX_OK) { |
| zx_handle_close(session_manager); |
| return -1; |
| } |
| |
| zx_status_t remote_status = ZX_OK; |
| zx_status_t status = fuchsia_virtualconsole_SessionManagerCreateSession( |
| session_manager, session_remote, &remote_status); |
| zx_handle_close(session_manager); |
| if (status != ZX_OK || remote_status != ZX_OK) { |
| zx_handle_close(session); |
| fprintf(stderr, "run-vc: failed to create session: local: %s remote: %s\n", |
| zx_status_get_string(status), zx_status_get_string(remote_status)); |
| return -1; |
| } |
| if (session == ZX_HANDLE_INVALID) { |
| fprintf(stderr, "run-vc: Received invalid handle from session manager!\n"); |
| return -1; |
| } |
| |
| // start shell if no arguments |
| if (argc == 1) { |
| argv[0] = ZX_SHELL_DEFAULT; |
| } else { |
| argv++; |
| } |
| |
| const char* pname = strrchr(argv[0], '/'); |
| if (pname == NULL) { |
| pname = argv[0]; |
| } else { |
| pname++; |
| } |
| |
| uint32_t flags = FDIO_SPAWN_CLONE_ALL & ~FDIO_SPAWN_CLONE_STDIO; |
| uint32_t type = PA_HND(PA_FD, FDIO_FLAG_USE_FOR_STDIO); |
| |
| fdio_spawn_action_t actions[2] = { |
| {.action = FDIO_SPAWN_ACTION_SET_NAME, .name.data = pname}, |
| {.action = FDIO_SPAWN_ACTION_ADD_HANDLE, .h.id = type, .h.handle = session}, |
| }; |
| // Clang static analyzer could not bind symexpr for session correctly to actions, so we need this |
| // unnecessary assignment to let it understand action array now contains the session handle. |
| // TODO(fxbug.dev/64385): Remove this line once the analyzer is improved. |
| actions[1].h.handle = session; |
| |
| char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH]; |
| status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, argv[0], argv, NULL, countof(actions), actions, |
| NULL, err_msg); |
| if (status != ZX_OK) { |
| fprintf(stderr, "error %d (%s) launching: %s\n", status, zx_status_get_string(status), err_msg); |
| return -1; |
| } |
| return 0; |
| } |