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 // While not much will work if launchpad isn't already working, this test
6 // provides a place for testing aspects of launchpad that aren't necessarily
7 // normally used.
8 
9 #include <unistd.h>
10 #include <errno.h>
11 #include <stdlib.h>
12 
13 #include <elfload/elfload.h>
14 
15 #include <launchpad/launchpad.h>
16 #include <launchpad/vmo.h>
17 
18 #include <zircon/process.h>
19 #include <zircon/processargs.h>
20 #include <zircon/syscalls.h>
21 #include <zircon/syscalls/object.h>
22 
23 #include <lib/fdio/util.h>
24 
25 #include <unittest/unittest.h>
26 
27 #include "util.h"
28 
stdio_pipe_test(void)29 static bool stdio_pipe_test(void)
30 {
31     BEGIN_TEST;
32 
33     int fds[2];
34     ASSERT_EQ(pipe(fds), 0, "pipe creation failed");
35 
36     ASSERT_GT(write(fds[1], "hello", 5), 0, "pipe write failed");
37 
38     char buffer[5];
39     ASSERT_GT(read(fds[0], buffer, 5), 0, "pipe read failed");
40 
41     ASSERT_EQ(strncmp(buffer, "hello", 5), 0, "Incorrect buffer read from pipe");
42 
43     ASSERT_EQ(lseek(fds[0], 0, SEEK_SET), -1, "lseek should have failed");
44     ASSERT_EQ(errno, ESPIPE, "lseek error should have been pipe-related");
45 
46     ASSERT_EQ(close(fds[0]), 0, "");
47     ASSERT_EQ(close(fds[1]), 0, "");
48 
49     END_TEST;
50 }
51 
52 
stdio_launchpad_pipe_test(void)53 static bool stdio_launchpad_pipe_test(void)
54 {
55     BEGIN_TEST;
56 
57     // TODO(kulakowski): Consider another helper process
58     const char* file = "/boot/bin/lsusb";
59     launchpad_t* lp = NULL;
60 
61     zx_handle_t fdio_job = zx_job_default();
62     ASSERT_NE(fdio_job, ZX_HANDLE_INVALID, "no fdio job object");
63 
64     zx_handle_t job_copy = ZX_HANDLE_INVALID;
65     ASSERT_EQ(zx_handle_duplicate(fdio_job, ZX_RIGHT_SAME_RIGHTS, &job_copy),
66               ZX_OK, "zx_handle_duplicate failed");
67 
68     ASSERT_EQ(launchpad_create(job_copy,
69                                "launchpad_pipe_stdio_test", &lp),
70               ZX_OK, "launchpad_create failed");
71     ASSERT_EQ(launchpad_set_args(lp, 1, &file),
72               ZX_OK, "launchpad_arguments failed");
73     ASSERT_EQ(launchpad_add_vdso_vmo(lp), ZX_OK,
74               "launchpad_add_vdso_vmo failed");
75     ASSERT_EQ(launchpad_clone(lp, LP_CLONE_FDIO_NAMESPACE),
76               ZX_OK, "launchpad_clone failed");
77 
78     zx_handle_t vmo;
79     ASSERT_EQ(launchpad_vmo_from_file(file, &vmo), ZX_OK, "");
80     ASSERT_EQ(launchpad_elf_load(lp, vmo),
81               ZX_OK, "launchpad_elf_load failed");
82 
83     ASSERT_EQ(launchpad_load_vdso(lp, ZX_HANDLE_INVALID),
84               ZX_OK, "launchpad_load_vdso failed");
85 
86     // stdio pipe fds [ours, theirs]
87     int stdin_fds[2];
88     int stdout_fds[2];
89     int stderr_fds[2];
90 
91     ASSERT_EQ(stdio_pipe(stdin_fds, true), 0, "stdin pipe creation failed");
92     ASSERT_EQ(stdio_pipe(stdout_fds, false), 0, "stdout pipe creation failed");
93     ASSERT_EQ(stdio_pipe(stderr_fds, false), 0, "stderr pipe creation failed");
94 
95     // Transfer the child's stdio pipes
96     ASSERT_EQ(launchpad_transfer_fd(lp, stdin_fds[1], 0), ZX_OK,
97               "failed to transfer stdin pipe to child process");
98     ASSERT_EQ(launchpad_transfer_fd(lp, stdout_fds[1], 1), ZX_OK,
99               "failed to transfer stdout pipe to child process");
100     ASSERT_EQ(launchpad_transfer_fd(lp, stderr_fds[1], 2), ZX_OK,
101               "failed to transfer stderr pipe to child process");
102 
103     // Start the process
104     zx_handle_t p = ZX_HANDLE_INVALID;
105     zx_status_t status = launchpad_go(lp, &p, NULL);
106     ASSERT_EQ(status, ZX_OK, "");
107     ASSERT_NE(p, ZX_HANDLE_INVALID, "process handle != 0");
108 
109     // Read the stdio
110     uint8_t* out = NULL;
111     size_t out_size = 0;
112     uint8_t* err = NULL;
113     size_t err_size = 0;
114 
115     ASSERT_GE(read_to_end(stdout_fds[0], &out, &out_size), 0, "reading stdout failed");
116     ASSERT_GE(read_to_end(stderr_fds[0], &err, &err_size), 0, "reading stderr failed");
117 
118     ASSERT_EQ(strncmp((char*)out, "ID   ", 5), 0, "Got wrong stdout");
119     ASSERT_EQ(err_size, (size_t)0, "Got wrong stderr");
120 
121     free(out);
122     free(err);
123 
124     close(stdin_fds[0]);
125     close(stdout_fds[0]);
126     close(stderr_fds[0]);
127 
128     // Wait for the process to finish
129     zx_status_t r;
130 
131     r = zx_object_wait_one(p, ZX_PROCESS_TERMINATED,
132                            ZX_TIME_INFINITE, NULL);
133     ASSERT_EQ(r, ZX_OK, "zx_object_wait_one failed");
134 
135     // read the return code
136     zx_info_process_t proc_info;
137     size_t actual = 0;
138     zx_object_get_info(p, ZX_INFO_PROCESS, &proc_info,
139                        sizeof(proc_info), &actual, NULL);
140     ASSERT_EQ(actual, (size_t)1, "Must get one and only one process info");
141     ASSERT_EQ(proc_info.return_code, 0, "lsusb must return 0");
142 
143     zx_handle_close(p);
144 
145     END_TEST;
146 }
147 
148 BEGIN_TEST_CASE(launchpad_tests)
149 RUN_TEST(stdio_pipe_test);
150 RUN_TEST(stdio_launchpad_pipe_test);
END_TEST_CASE(launchpad_tests)151 END_TEST_CASE(launchpad_tests)
152 
153 int main(int argc, char **argv)
154 {
155     bool success = unittest_run_all_tests(argc, argv);
156 
157     return success ? 0 : -1;
158 }
159