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