| // Copyright 2018 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 <lib/devmgr-launcher/launch.h> |
| |
| #include <stdint.h> |
| #include <utility> |
| |
| #include <fbl/algorithm.h> |
| #include <lib/fdio/directory.h> |
| #include <lib/fdio/fd.h> |
| #include <lib/fdio/fdio.h> |
| #include <lib/fdio/io.h> |
| #include <lib/fdio/namespace.h> |
| #include <lib/fdio/spawn.h> |
| #include <lib/zx/channel.h> |
| #include <lib/zx/process.h> |
| #include <zircon/assert.h> |
| #include <zircon/device/vfs.h> |
| #include <zircon/processargs.h> |
| #include <zircon/status.h> |
| |
| #include <lib/devmgr-launcher/processargs.h> |
| |
| namespace { |
| |
| constexpr const char* kDevmgrPath = "/boot/bin/devcoordinator"; |
| |
| } // namespace |
| |
| namespace devmgr_launcher { |
| |
| zx_status_t Launch(Args args, zx::channel bootsvc_client, zx::job* devmgr_job, |
| zx::channel* devfs_root) { |
| // Create containing job (and copy to send to devmgr) |
| zx::job job, job_copy; |
| zx_status_t status = zx::job::create(*zx::job::default_job(), 0, &job); |
| if (status != ZX_OK) { |
| return status; |
| } |
| status = job.duplicate(ZX_RIGHT_SAME_RIGHTS, &job_copy); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| // Create a new client to /boot to give to devmgr |
| zx::channel bootfs_client; |
| { |
| zx::channel bootfs_server; |
| status = zx::channel::create(0, &bootfs_client, &bootfs_server); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| fdio_ns_t* ns; |
| status = fdio_ns_get_installed(&ns); |
| if (status != ZX_OK) { |
| return status; |
| } |
| status = fdio_ns_connect(ns, "/boot", ZX_FS_RIGHT_READABLE, bootfs_server.release()); |
| if (status != ZX_OK) { |
| return status; |
| } |
| } |
| |
| // Create a new client to /svc to maybe give to devmgr |
| zx::channel svc_client; |
| { |
| zx::channel svc_server; |
| status = zx::channel::create(0, &svc_client, &svc_server); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| fdio_ns_t* ns; |
| status = fdio_ns_get_installed(&ns); |
| if (status != ZX_OK) { |
| return status; |
| } |
| status = fdio_ns_connect(ns, "/svc", ZX_FS_RIGHT_READABLE | ZX_FS_RIGHT_WRITABLE, |
| svc_server.release()); |
| if (status != ZX_OK) { |
| return status; |
| } |
| } |
| |
| // Create channel to connect to devfs |
| zx::channel devfs_client, devfs_server; |
| status = zx::channel::create(0, &devfs_client, &devfs_server); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| const bool clone_stdio = !args.stdio.is_valid(); |
| |
| fbl::Vector<const char*> argv; |
| argv.push_back(kDevmgrPath); |
| for (const char* path : args.driver_search_paths) { |
| argv.push_back("--driver-search-path"); |
| argv.push_back(path); |
| } |
| for (const char* path : args.load_drivers) { |
| argv.push_back("--load-driver"); |
| argv.push_back(path); |
| } |
| if (args.sys_device_driver != nullptr) { |
| argv.push_back("--sys-device-driver"); |
| argv.push_back(args.sys_device_driver); |
| } |
| if (args.use_system_svchost) { |
| argv.push_back("--use-system-svchost"); |
| } |
| if (args.disable_block_watcher) { |
| argv.push_back("--disable-block-watcher"); |
| } |
| if (args.disable_netsvc) { |
| argv.push_back("--disable-netsvc"); |
| } |
| argv.push_back(nullptr); |
| |
| fbl::Vector<fdio_spawn_action_t> actions; |
| actions.push_back(fdio_spawn_action_t{ |
| .action = FDIO_SPAWN_ACTION_SET_NAME, |
| .name = {.data = "test-devmgr"}, |
| }); |
| actions.push_back(fdio_spawn_action_t{ |
| .action = FDIO_SPAWN_ACTION_ADD_HANDLE, |
| .h = {.id = PA_HND(PA_JOB_DEFAULT, 0), .handle = job_copy.release()}, |
| }); |
| actions.push_back(fdio_spawn_action_t{ |
| .action = FDIO_SPAWN_ACTION_ADD_HANDLE, |
| .h = {.id = DEVMGR_LAUNCHER_DEVFS_ROOT_HND, .handle = devfs_server.release()}, |
| }); |
| actions.push_back(fdio_spawn_action_t{ |
| .action = FDIO_SPAWN_ACTION_ADD_NS_ENTRY, |
| .ns = {.prefix = "/boot", .handle = bootfs_client.release()}, |
| }); |
| actions.push_back(fdio_spawn_action_t{ |
| .action = FDIO_SPAWN_ACTION_ADD_NS_ENTRY, |
| .ns = {.prefix = "/bootsvc", .handle = bootsvc_client.release()}, |
| }); |
| if (args.use_system_svchost) { |
| actions.push_back(fdio_spawn_action_t{ |
| .action = FDIO_SPAWN_ACTION_ADD_NS_ENTRY, |
| .ns = {.prefix = "/svc", .handle = svc_client.release()}, |
| }); |
| } |
| if (!clone_stdio) { |
| actions.push_back(fdio_spawn_action_t{ |
| .action = FDIO_SPAWN_ACTION_TRANSFER_FD, |
| .fd = {.local_fd = args.stdio.release(), .target_fd = FDIO_FLAG_USE_FOR_STDIO}, |
| }); |
| } |
| |
| uint32_t flags = FDIO_SPAWN_DEFAULT_LDSVC; |
| if (clone_stdio) { |
| flags |= FDIO_SPAWN_CLONE_STDIO; |
| } |
| |
| zx::process new_process; |
| status = fdio_spawn_etc(job.get(), |
| flags, |
| kDevmgrPath, |
| argv.get(), |
| nullptr /* environ */, |
| actions.size(), |
| actions.get(), |
| new_process.reset_and_get_address(), |
| nullptr /* err_msg */); |
| if (status != ZX_OK) { |
| return status; |
| } |
| |
| *devmgr_job = std::move(job); |
| *devfs_root = std::move(devfs_client); |
| return ZX_OK; |
| } |
| |
| } // namespace devmgr_launcher |