diff --git a/egl/wayland-egl-symbols-check b/egl/wayland-egl-symbols-check index d04fd042..2b00765c 100755 --- a/egl/wayland-egl-symbols-check +++ b/egl/wayland-egl-symbols-check @@ -14,7 +14,15 @@ if ! test -n "$NM"; then exit 99 fi -AVAIL_FUNCS="$($NM -D --format=bsd --defined-only $LIB | awk '{print $3}')" +# darwin prefixes C symbols with _ and uses a different nm invocation +case "$(uname -s)" in +Darwin) + AVAIL_FUNCS="$($NM -g --defined-only $LIB | awk '{print $3}' | sed 's:^_::')" + ;; +*) + AVAIL_FUNCS="$($NM -D --format=bsd --defined-only $LIB | awk '{print $3}')" + ;; +esac # Official ABI, taken from the header. REQ_FUNCS="wl_egl_window_resize diff --git a/meson.build b/meson.build index cb6c2385..e264aecd 100644 --- a/meson.build +++ b/meson.build @@ -23,6 +23,10 @@ cc_args = [] if host_machine.system() not in ['freebsd', 'openbsd'] cc_args += ['-D_POSIX_C_SOURCE=200809L'] endif +if host_machine.system() == 'darwin' + # For CMSG_LEN(), which is an RFC 2292 addition and not part of POSIX.1-2008 + cc_args += ['-D_DARWIN_C_SOURCE'] +endif add_project_arguments(cc_args, language: 'c') compiler_flags = [ @@ -44,8 +48,11 @@ endforeach have_funcs = [ 'accept4', + 'getpeereid', + 'memrchr', 'mkostemp', 'posix_fallocate', + 'ppoll', 'prctl', 'memfd_create', 'mremap', @@ -74,15 +81,20 @@ endif config_h.set10('HAVE_BROKEN_MSG_CMSG_CLOEXEC', have_broken_msg_cmsg_cloexec) if get_option('libraries') - if host_machine.system() in ['freebsd', 'openbsd'] - # When building for FreeBSD, epoll(7) is provided by a userspace - # wrapper around kqueue(2). + if host_machine.system() in ['darwin', 'freebsd', 'openbsd'] + # When building for darwin, FreeBSD, or OpenBSD, epoll(7) is + # provided by a userspace wrapper around kqueue(2). epoll_dep = dependency('epoll-shim') else # Otherwise, assume that epoll(7) is supported natively. epoll_dep = [] endif - ffi_dep = dependency('libffi') + + if host_machine.system() == 'darwin' + ffi_dep = cc.find_library('ffi') + else + ffi_dep = dependency('libffi') + endif decls = [ { 'header': 'sys/signalfd.h', 'symbol': 'SFD_CLOEXEC' }, diff --git a/src/connection.c b/src/connection.c index 2d1e8d1d..e75da3af 100644 --- a/src/connection.c +++ b/src/connection.c @@ -40,7 +40,11 @@ #include #include #include +#ifdef __APPLE__ +#include +#else #include +#endif #include "wayland-util.h" #include "wayland-private.h" diff --git a/src/meson.build b/src/meson.build index b3b9ea57..980dac20 100644 --- a/src/meson.build +++ b/src/meson.build @@ -29,7 +29,12 @@ wayland_util_dep = declare_dependency( if get_option('scanner') # wayland-scanner - scanner_deps = [ dependency('expat') ] + if host_machine.system() == 'darwin' + scanner_deps = [ cc.find_library('expat') ] + else + scanner_deps = [ dependency('expat') ] + endif + scanner_args = [ '-include', 'config.h' ] if get_option('dtd_validation') diff --git a/src/wayland-client.c b/src/wayland-client.c index 50b3b4b2..ee596b08 100644 --- a/src/wayland-client.c +++ b/src/wayland-client.c @@ -26,12 +26,15 @@ #define _GNU_SOURCE +#include "../config.h" + #include #include #include #include #include #include +#include #include #include #include @@ -2055,7 +2058,20 @@ wl_display_poll(struct wl_display *display, timespec_sub_saturate(&result, &deadline, &now); remaining_timeout = &result; } +#ifdef HAVE_PPOLL ret = ppoll(pfd, 1, remaining_timeout, NULL); +#else + if (remaining_timeout) { + long timeout_ms = + remaining_timeout->tv_sec * 1000 + + (remaining_timeout->tv_nsec + 999999) / 1000000; + if (timeout_ms > INT_MAX) + timeout_ms = INT_MAX; + ret = poll(pfd, 1, (int)timeout_ms); + } else { + ret = poll(pfd, 1, -1); + } +#endif } while (ret == -1 && errno == EINTR); return ret; diff --git a/src/wayland-os.c b/src/wayland-os.c index f00ead4b..f1e6c55f 100644 --- a/src/wayland-os.c +++ b/src/wayland-os.c @@ -75,16 +75,46 @@ wl_os_socket_cloexec(int domain, int type, int protocol) { int fd; +#ifdef SOCK_CLOEXEC fd = wl_socket(domain, type | SOCK_CLOEXEC, protocol); if (fd >= 0) return fd; if (errno != EINVAL) return -1; +#endif fd = wl_socket(domain, type, protocol); return set_cloexec_or_close(fd); } +int +wl_os_socketpair_cloexec(int domain, int type, int protocol, int sv[2]) +{ + int retval; + +#ifdef SOCK_CLOEXEC + retval = socketpair(domain, type | SOCK_CLOEXEC, protocol, sv); + if (retval >= 0) + return retval; + if (errno != EINVAL) + return -1; +#endif + + retval = socketpair(domain, type, protocol, sv); + if (retval < 0) + return retval; + + sv[0] = set_cloexec_or_close(sv[0]); + sv[1] = set_cloexec_or_close(sv[1]); + if (sv[0] == -1 || sv[1] == -1) { + close(sv[0]); + close(sv[1]); + return -1; + } + + return 0; +} + #if defined(__FreeBSD__) int wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid) @@ -125,6 +155,20 @@ wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid) *pid = ucred.pid; return 0; } +#elif defined(HAVE_GETPEEREID) && defined(LOCAL_PEERPID) +int +wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid) +{ + socklen_t len; + + if (getpeereid(sockfd, uid, gid) != 0) + return -1; + + len = sizeof(pid_t); + if (getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERPID, pid, &len) != 0) + return -1; + return 0; +} #else #error "Don't know how to read ucred on this platform" #endif @@ -134,11 +178,13 @@ wl_os_dupfd_cloexec(int fd, int minfd) { int newfd; +#ifdef F_DUPFD_CLOEXEC newfd = wl_fcntl(fd, F_DUPFD_CLOEXEC, minfd); if (newfd >= 0) return newfd; if (errno != EINVAL) return -1; +#endif newfd = wl_fcntl(fd, F_DUPFD, minfd); return set_cloexec_or_close(newfd); @@ -186,7 +232,7 @@ wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags) * fix (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211). */ #pragma message("Using fallback directly since MSG_CMSG_CLOEXEC is broken.") -#else +#elif defined(MSG_CMSG_CLOEXEC) ssize_t len; len = wl_recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC); diff --git a/src/wayland-os.h b/src/wayland-os.h index 068fd2fe..42e28007 100644 --- a/src/wayland-os.h +++ b/src/wayland-os.h @@ -32,6 +32,9 @@ int wl_os_socket_cloexec(int domain, int type, int protocol); +int +wl_os_socketpair_cloexec(int domain, int type, int protocol, int sv[2]); + int wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid); diff --git a/src/wayland-shm.c b/src/wayland-shm.c index 3ac4add2..8d27df5b 100644 --- a/src/wayland-shm.c +++ b/src/wayland-shm.c @@ -357,8 +357,10 @@ shm_create_pool(struct wl_client *client, struct wl_resource *resource, uint32_t id, int fd, int32_t size) { struct wl_shm_pool *pool; +#ifdef HAVE_MEMFD_CREATE struct stat statbuf; int seals; +#endif int prot; int flags; uint32_t version; diff --git a/tests/client-test.c b/tests/client-test.c index 5585c0cd..83bdead6 100644 --- a/tests/client-test.c +++ b/tests/client-test.c @@ -34,6 +34,7 @@ #include #include +#include "wayland-os.h" #include "wayland-private.h" #include "wayland-server.h" #include "test-runner.h" @@ -97,7 +98,7 @@ TEST(client_destroy_listener) bool user_data_destroyed = false; int s[2]; - assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + assert(wl_os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); @@ -184,7 +185,7 @@ TEST(client_destroy_removes_link) struct client_destroy_listener destroy_listener; int s[2]; - assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + assert(wl_os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); diff --git a/tests/connection-test.c b/tests/connection-test.c index aed97a0a..753091c6 100644 --- a/tests/connection-test.c +++ b/tests/connection-test.c @@ -37,6 +37,7 @@ #include #include +#include "wayland-os.h" #include "wayland-private.h" #include "test-runner.h" #include "test-compositor.h" @@ -48,7 +49,7 @@ setup(int *s) { struct wl_connection *connection; - assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + assert(wl_os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, s) == 0); connection = wl_connection_create(s[0], WL_BUFFER_DEFAULT_MAX_SIZE); assert(connection); @@ -181,8 +182,8 @@ struct marshal_data { static void setup_marshal_data(struct marshal_data *data) { - assert(socketpair(AF_UNIX, - SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0); + assert(wl_os_socketpair_cloexec(AF_UNIX, + SOCK_STREAM, 0, data->s) == 0); data->read_connection = wl_connection_create(data->s[0], WL_BUFFER_DEFAULT_MAX_SIZE); assert(data->read_connection); @@ -885,7 +886,7 @@ TEST(request_bogus_size) for (bogus_size = 11; bogus_size >= 0; bogus_size--) { fprintf(stderr, "* bogus size %d\n", bogus_size); - assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + assert(wl_os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); diff --git a/tests/os-wrappers-test.c b/tests/os-wrappers-test.c index 061d29e6..36e1ef42 100644 --- a/tests/os-wrappers-test.c +++ b/tests/os-wrappers-test.c @@ -61,10 +61,12 @@ socket_wrapper(int domain, int type, int protocol) { wrapped_calls_socket++; +#ifdef SOCK_CLOEXEC if (fall_back && (type & SOCK_CLOEXEC)) { errno = EINVAL; return -1; } +#endif return socket(domain, type, protocol); } @@ -78,12 +80,16 @@ fcntl_wrapper(int fd, int cmd, ...) wrapped_calls_fcntl++; +#ifdef F_DUPFD_CLOEXEC if (fall_back && (cmd == F_DUPFD_CLOEXEC)) { errno = EINVAL; return -1; } +#endif switch (cmd) { +#ifdef F_DUPFD_CLOEXEC case F_DUPFD_CLOEXEC: +#endif case F_DUPFD: case F_SETFD: va_start(ap, cmd); @@ -110,10 +116,12 @@ recvmsg_wrapper(int sockfd, struct msghdr *msg, int flags) { wrapped_calls_recvmsg++; +#ifdef MSG_CMSG_CLOEXEC if (fall_back && (flags & MSG_CMSG_CLOEXEC)) { errno = EINVAL; return -1; } +#endif return recvmsg(sockfd, msg, flags); } @@ -158,7 +166,11 @@ do_os_wrappers_socket_cloexec(int n) * Must have 2 calls if falling back, but must also allow * falling back without a forced fallback. */ +#ifdef SOCK_CLOEXEC assert(wrapped_calls_socket > n); +#else + assert(wrapped_calls_socket == 1); +#endif exec_fd_leak_check(nr_fds); } @@ -232,8 +244,8 @@ struct marshal_data { static void setup_marshal_data(struct marshal_data *data) { - assert(socketpair(AF_UNIX, - SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0); + assert(wl_os_socketpair_cloexec(AF_UNIX, + SOCK_STREAM, 0, data->s) == 0); data->read_connection = wl_connection_create(data->s[0], WL_BUFFER_DEFAULT_MAX_SIZE); @@ -323,9 +335,10 @@ do_os_wrappers_recvmsg_cloexec(int n) struct marshal_data data; data.nr_fds_begin = count_open_fds(); -#if HAVE_BROKEN_MSG_CMSG_CLOEXEC +#if HAVE_BROKEN_MSG_CMSG_CLOEXEC || !defined(MSG_CMSG_CLOEXEC) /* We call the fallback directly on FreeBSD versions with a broken - * MSG_CMSG_CLOEXEC, so we don't call the local recvmsg() wrapper. */ + * MSG_CMSG_CLOEXEC or platforms without MSG_CMSG_CLOEXEC, so we + * don't call the local recvmsg() wrapper. */ data.wrapped_calls = 0; #else data.wrapped_calls = n; diff --git a/tests/queue-test.c b/tests/queue-test.c index 2b2d9ad4..4867b5a3 100644 --- a/tests/queue-test.c +++ b/tests/queue-test.c @@ -24,6 +24,7 @@ */ #define _GNU_SOURCE /* For memrchr */ +#include "../config.h" #include #include #include @@ -36,6 +37,19 @@ #include #include +#ifndef HAVE_MEMRCHR +static void * +memrchr(const void *s, int c, size_t n) +{ + const unsigned char *p = (const unsigned char *)s + n; + while (n--) { + if (*--p == (unsigned char)c) + return (void *)p; + } + return NULL; +} +#endif + #include "wayland-client.h" #include "wayland-server.h" #include "test-runner.h" diff --git a/tests/resources-test.c b/tests/resources-test.c index 92707297..5a01785a 100644 --- a/tests/resources-test.c +++ b/tests/resources-test.c @@ -28,6 +28,7 @@ #include #include +#include "wayland-os.h" #include "wayland-server.h" #include "test-runner.h" @@ -40,7 +41,7 @@ TEST(create_resource_tst) int s[2]; uint32_t id; - assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + assert(wl_os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); @@ -111,7 +112,7 @@ TEST(destroy_res_tst) .notify = &destroy_notify }; - assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + assert(wl_os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); @@ -159,7 +160,7 @@ TEST(create_resource_with_same_id) int s[2]; uint32_t id; - assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + assert(wl_os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); @@ -243,7 +244,7 @@ TEST(resource_destroy_iteration) .notify = &resource_destroy_notify }; - assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0); + assert(wl_os_socketpair_cloexec(AF_UNIX, SOCK_STREAM, 0, s) == 0); display = wl_display_create(); assert(display); client = wl_client_create(display, s[0]); diff --git a/tests/test-runner.c b/tests/test-runner.c index 9a50d1dd..66e50546 100644 --- a/tests/test-runner.c +++ b/tests/test-runner.c @@ -63,7 +63,12 @@ static int timeouts_enabled = 1; /* set to one if the output goes to the terminal */ static int is_atty = 0; +#ifdef __APPLE__ +extern const struct test __start_test_section __asm("section$start$__RODATA$test_section"); +extern const struct test __stop_test_section __asm("section$end$__RODATA$test_section"); +#else extern const struct test __start_test_section, __stop_test_section; +#endif static const struct test * find_test(const char *name) diff --git a/tests/test-runner.h b/tests/test-runner.h index d0734009..2024fa13 100644 --- a/tests/test-runner.h +++ b/tests/test-runner.h @@ -31,6 +31,12 @@ #include +#ifdef __APPLE__ +#define TEST_SECTION "__RODATA,test_section" +#else +#define TEST_SECTION "test_section" +#endif + struct test { const char *name; void (*run)(void); @@ -41,7 +47,7 @@ struct test { static void name(void); \ \ const struct test test##name \ - __attribute__ ((used, section ("test_section"))) = { \ + __attribute__ ((used, section (TEST_SECTION))) = { \ #name, name, 0 \ }; \ \ @@ -51,7 +57,7 @@ struct test { static void name(void); \ \ const struct test test##name \ - __attribute__ ((used, section ("test_section"))) = { \ + __attribute__ ((used, section (TEST_SECTION))) = { \ #name, name, 1 \ }; \ \