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
18static zx_handle_t log_handle;
19
20#define LOGBUF_MAX (ZX_LOG_RECORD_MAX - sizeof(zx_log_record_t))
21
22static 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
36static zx_handle_t root_resource;
37
38void __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
49zx_handle_t get_root_resource(void) {
50    return root_resource;
51}
52
53ssize_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
60ssize_t readv(int fd, const struct iovec* iov, int num) {
61    return 0;
62}
63
64ssize_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
86off_t lseek(int fd, off_t offset, int whence) {
87    ERROR();
88}
89
90int isatty(int fd) {
91    return 1;
92}
93
94int 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