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 "devmgr.h" 6 7#include <launchpad/launchpad.h> 8#include <launchpad/vmo.h> 9 10#include <lib/fdio/io.h> 11#include <lib/fdio/util.h> 12 13#include <zircon/paths.h> 14#include <zircon/processargs.h> 15#include <zircon/syscalls.h> 16#include <zircon/syscalls/log.h> 17 18#include <limits.h> 19#include <stdio.h> 20#include <stdlib.h> 21#include <string.h> 22#include <unistd.h> 23 24void devmgr_io_init() { 25 // setup stdout 26 zx_handle_t h; 27 if (zx_debuglog_create(ZX_HANDLE_INVALID, 0, &h) < 0) { 28 return; 29 } 30 fdio_t* logger; 31 if ((logger = fdio_logger_create(h)) == nullptr) { 32 return; 33 } 34 close(1); 35 fdio_bind_to_fd(logger, 1, 0); 36} 37 38#define USER_MAX_HANDLES 4 39#define MAX_ENVP 16 40#define CHILD_JOB_RIGHTS (ZX_RIGHTS_BASIC | ZX_RIGHT_READ | ZX_RIGHT_WRITE) 41 42static struct { 43 const char* mount; 44 const char* name; 45 uint32_t flags; 46} FSTAB[] = { 47 { "/svc", "svc", FS_SVC }, 48 { "/hub", "hub", FS_HUB }, 49 { "/dev", "dev", FS_DEV }, 50 { "/boot", "boot", FS_BOOT }, 51 { "/data", "data", FS_DATA }, 52 { "/system", "system", FS_SYSTEM }, 53 { "/install", "install", FS_INSTALL }, 54 { "/volume", "volume", FS_VOLUME }, 55 { "/blob", "blob", FS_BLOB }, 56 { "/pkgfs", "pkgfs", FS_PKGFS }, 57 { "/tmp", "tmp", FS_TMP }, 58}; 59 60void devmgr_disable_appmgr_services() { 61 FSTAB[1].flags = 0; 62} 63 64zx_status_t devmgr_launch( 65 zx_handle_t job, const char* name, 66 zx_status_t (*load)(void*, launchpad_t*, const char*), void* ctx, 67 int argc, const char* const* argv, 68 const char** _envp, int stdiofd, 69 const zx_handle_t* handles, const uint32_t* types, size_t hcount, 70 zx_handle_t* proc, uint32_t flags) { 71 zx_status_t status; 72 const char* envp[MAX_ENVP + 1]; 73 unsigned envn = 0; 74 75 if (getenv(LDSO_TRACE_CMDLINE)) { 76 envp[envn++] = LDSO_TRACE_ENV; 77 } 78 envp[envn++] = ZX_SHELL_ENV_PATH; 79 while ((_envp && _envp[0]) && (envn < MAX_ENVP)) { 80 envp[envn++] = *_envp++; 81 } 82 envp[envn++] = nullptr; 83 84 zx_handle_t job_copy = ZX_HANDLE_INVALID; 85 zx_handle_duplicate(job, CHILD_JOB_RIGHTS, &job_copy); 86 87 launchpad_t* lp; 88 launchpad_create(job_copy, name, &lp); 89 90 status = (*load)(ctx, lp, argv[0]); 91 if (status != ZX_OK) { 92 launchpad_abort(lp, status, "cannot load file"); 93 } 94 launchpad_set_args(lp, argc, argv); 95 launchpad_set_environ(lp, envp); 96 97 // create namespace based on FS_* flags 98 const char* nametable[countof(FSTAB)] = { }; 99 uint32_t count = 0; 100 zx_handle_t h; 101 for (unsigned n = 0; n < countof(FSTAB); n++) { 102 if (!(FSTAB[n].flags & flags)) { 103 continue; 104 } 105 if ((h = fs_clone(FSTAB[n].name).release()) != ZX_HANDLE_INVALID) { 106 nametable[count] = FSTAB[n].mount; 107 launchpad_add_handle(lp, h, PA_HND(PA_NS_DIR, count++)); 108 } 109 } 110 launchpad_set_nametable(lp, count, nametable); 111 112 if (stdiofd < 0) { 113 if ((status = zx_debuglog_create(ZX_HANDLE_INVALID, 0, &h) < 0)) { 114 launchpad_abort(lp, status, "devmgr: cannot create debuglog handle"); 115 } else { 116 launchpad_add_handle(lp, h, PA_HND(PA_FDIO_LOGGER, FDIO_FLAG_USE_FOR_STDIO | 0)); 117 } 118 } else { 119 launchpad_clone_fd(lp, stdiofd, FDIO_FLAG_USE_FOR_STDIO | 0); 120 close(stdiofd); 121 } 122 123 launchpad_add_handles(lp, hcount, handles, types); 124 125 const char* errmsg; 126 if ((status = launchpad_go(lp, proc, &errmsg)) < 0) { 127 printf("devmgr: launchpad %s (%s) failed: %s: %d\n", 128 argv[0], name, errmsg, status); 129 } else { 130 printf("devmgr: launch %s (%s) OK\n", argv[0], name); 131 } 132 zx_handle_close(job_copy); 133 return status; 134} 135 136zx_status_t devmgr_launch_cmdline( 137 const char* me, zx_handle_t job, const char* name, 138 zx_status_t (*load)(void* ctx, launchpad_t*, const char* file), void* ctx, 139 const char* cmdline, 140 const zx_handle_t* handles, const uint32_t* types, size_t hcount, 141 zx_handle_t* proc, uint32_t flags) { 142 143 // Get the full commandline by splitting on '+'. 144 char* buf = strdup(cmdline); 145 if (buf == nullptr) { 146 printf("%s: Can't parse + command: %s\n", me, cmdline); 147 return ZX_ERR_UNAVAILABLE; 148 } 149 const int MAXARGS = 8; 150 char* argv[MAXARGS]; 151 int argc = 0; 152 char* token; 153 char* rest = buf; 154 while (argc < MAXARGS && (token = strtok_r(rest, "+", &rest))) { 155 argv[argc++] = token; 156 } 157 158 printf("%s: starting", me); 159 for (int i = 0; i < argc; i++) { 160 printf(" '%s'", argv[i]); 161 } 162 printf("...\n"); 163 164 zx_status_t status = devmgr_launch( 165 job, name, load, ctx, argc, (const char* const*)argv, nullptr, -1, 166 handles, types, hcount, proc, flags); 167 168 free(buf); 169 170 return status; 171} 172 173zx_status_t copy_vmo(zx_handle_t src, zx_off_t offset, size_t length, zx_handle_t* out_dest) { 174 zx_handle_t dest; 175 zx_status_t status = zx_vmo_create(length, 0, &dest); 176 if (status != ZX_OK) { 177 return status; 178 } 179 180 char buffer[PAGE_SIZE]; 181 zx_off_t src_offset = offset; 182 zx_off_t dest_offset = 0; 183 184 while (length > 0) { 185 size_t copy = (length > sizeof(buffer) ? sizeof(buffer) : length); 186 if ((status = zx_vmo_read(src, buffer, src_offset, copy)) != ZX_OK) { 187 goto fail; 188 } 189 if ((status = zx_vmo_write(dest, buffer, dest_offset, copy)) != ZX_OK) { 190 goto fail; 191 } 192 src_offset += copy; 193 dest_offset += copy; 194 length -= copy; 195 } 196 197 *out_dest = dest; 198 return ZX_OK; 199 200fail: 201 zx_handle_close(dest); 202 return status; 203} 204