1// Copyright 2016 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <fcntl.h>
6#include <lib/fdio/io.h>
7#include <lib/fdio/spawn.h>
8#include <lib/fdio/util.h>
9#include <lib/fdio/watcher.h>
10#include <limits.h>
11#include <stdbool.h>
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
15#include <unistd.h>
16#include <zircon/device/dmctl.h>
17#include <zircon/process.h>
18#include <zircon/processargs.h>
19#include <zircon/status.h>
20#include <zircon/syscalls.h>
21#include <zircon/types.h>
22
23int main(int argc, const char** argv) {
24    int fd;
25    int retry = 30;
26
27    while ((fd = open("/dev/misc/dmctl", O_RDWR)) < 0) {
28        if (--retry == 0) {
29            fprintf(stderr, "run-vc: could not connect to virtual console\n");
30            return -1;
31        }
32    }
33
34    zx_handle_t h0, h1;
35    if (zx_channel_create(0, &h0, &h1) < 0) {
36        return -1;
37    }
38    if (ioctl_dmctl_open_virtcon(fd, &h1) < 0) {
39        return -1;
40    }
41    close(fd);
42
43    zx_object_wait_one(h0, ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED,
44                       ZX_TIME_INFINITE, NULL);
45
46    uint32_t types[FDIO_MAX_HANDLES];
47    zx_handle_t handles[FDIO_MAX_HANDLES];
48    uint32_t dcount, hcount;
49    if (zx_channel_read(h0, 0, types, handles,
50                        sizeof(types), FDIO_MAX_HANDLES, &dcount, &hcount) < 0) {
51        return -1;
52    }
53    if (dcount / sizeof(uint32_t) != hcount) {
54        return -1;
55    }
56    zx_handle_close(h0);
57
58    // start shell if no arguments
59    if (argc == 1) {
60        argv[0] = "/boot/bin/sh";
61    } else {
62        argv++;
63    }
64
65    const char* pname = strrchr(argv[0], '/');
66    if (pname == NULL) {
67        pname = argv[0];
68    } else {
69        pname++;
70    }
71
72    uint32_t flags = FDIO_SPAWN_CLONE_ALL & ~FDIO_SPAWN_CLONE_STDIO;
73
74    fdio_spawn_action_t actions[1 + FDIO_MAX_HANDLES] = {
75        {.action = FDIO_SPAWN_ACTION_SET_NAME, .name = {.data = pname}},
76    };
77    for (uint32_t i = 0; i < hcount; i++) {
78        actions[1 + i].action = FDIO_SPAWN_ACTION_ADD_HANDLE;
79        actions[1 + i].h.id = types[i];
80        actions[1 + i].h.handle = handles[i];
81    };
82
83    char err_msg[FDIO_SPAWN_ERR_MSG_MAX_LENGTH];
84    zx_status_t status = fdio_spawn_etc(ZX_HANDLE_INVALID, flags, argv[0], argv,
85                                  NULL, 1 + hcount, actions, NULL, err_msg);
86    if (status != ZX_OK) {
87        fprintf(stderr, "error %d (%s) launching: %s\n", status,
88                zx_status_get_string(status), err_msg);
89        return -1;
90    }
91
92    return 0;
93}
94