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