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 29static 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 53static 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 148BEGIN_TEST_CASE(launchpad_tests) 149RUN_TEST(stdio_pipe_test); 150RUN_TEST(stdio_launchpad_pipe_test); 151END_TEST_CASE(launchpad_tests) 152 153int main(int argc, char **argv) 154{ 155 bool success = unittest_run_all_tests(argc, argv); 156 157 return success ? 0 : -1; 158} 159