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 <errno.h>
6 #include <stdio.h>
7 #include <unistd.h>
8 #include <sys/uio.h>
9 
10 #include <zircon/processargs.h>
11 #include <zircon/syscalls.h>
12 #include <zircon/syscalls/log.h>
13 
14 #include <unittest/unittest.h>
15 
16 // output via debuglog syscalls
17 
18 static zx_handle_t log_handle;
19 
20 #define LOGBUF_MAX (ZX_LOG_RECORD_MAX - sizeof(zx_log_record_t))
21 
log_write(const void * data,size_t len)22 static void log_write(const void* data, size_t len) {
23     while (len > 0) {
24         size_t xfer = (len > LOGBUF_MAX) ? LOGBUF_MAX : len;
25         zx_debuglog_write(log_handle, 0, data, xfer);
26         data += xfer;
27         len -= xfer;
28     }
29 }
30 
31 
32 // libc init and io stubs
33 // The reason these are here is that the "core" tests intentionally do not
34 // use fdio. See ./README.md.
35 
36 static zx_handle_t root_resource;
37 
__libc_extensions_init(uint32_t count,zx_handle_t handle[],uint32_t info[])38 void __libc_extensions_init(uint32_t count, zx_handle_t handle[], uint32_t info[]) {
39     for (unsigned n = 0; n < count; n++) {
40         if (info[n] == PA_HND(PA_RESOURCE, 0)) {
41             root_resource = handle[n];
42             handle[n] = 0;
43             info[n] = 0;
44             break;
45         }
46     }
47 }
48 
get_root_resource(void)49 zx_handle_t get_root_resource(void) {
50     return root_resource;
51 }
52 
write(int fd,const void * data,size_t count)53 ssize_t write(int fd, const void* data, size_t count) {
54     if ((fd == 1) || (fd == 2)) {
55         log_write(data, count);
56     }
57     return count;
58 }
59 
readv(int fd,const struct iovec * iov,int num)60 ssize_t readv(int fd, const struct iovec* iov, int num) {
61     return 0;
62 }
63 
writev(int fd,const struct iovec * iov,int num)64 ssize_t writev(int fd, const struct iovec* iov, int num) {
65     ssize_t count = 0;
66     ssize_t r;
67     while (num > 0) {
68         if (iov->iov_len != 0) {
69             r = write(fd, iov->iov_base, iov->iov_len);
70             if (r < 0) {
71                 return count ? count : r;
72             }
73             if ((size_t)r < iov->iov_len) {
74                 return count + r;
75             }
76             count += r;
77         }
78         iov++;
79         num--;
80     }
81     return count;
82 }
83 
84 #define ERROR() do { errno = ENOSYS; return -1; } while (0)
85 
lseek(int fd,off_t offset,int whence)86 off_t lseek(int fd, off_t offset, int whence) {
87     ERROR();
88 }
89 
isatty(int fd)90 int isatty(int fd) {
91     return 1;
92 }
93 
main(int argc,char ** argv)94 int main(int argc, char** argv) {
95     if (zx_debuglog_create(ZX_HANDLE_INVALID, 0, &log_handle) < 0) {
96         return -2;
97     }
98     zx_debuglog_write(log_handle, 0, "TEST", 4);
99 
100     if (get_root_resource() == ZX_HANDLE_INVALID) {
101         fprintf(stderr, "Cannot access root resource, refusing to run tests.\n");
102         fprintf(stderr, "core-tests must be invoked by userboot (e.g. userboot=bin/core-tests).\n");
103         return -1;
104     }
105     const bool success = unittest_run_all_tests(argc, argv);
106     if (!success) {
107         return EXIT_FAILURE;
108     }
109 
110     // The continuous integration infrastructure looks for this string in the output. This exact
111     // string is matched in the recipe code. They need to be kept in sync. This random value was
112     // chosen because it's unlikely to be produced by other code paths.
113     fprintf(stderr, "core-tests succeeded RZMm59f7zOSs6aZUIXZR\n");
114 
115     return EXIT_SUCCESS;
116 }
117