2 * Copyright © 2014 Ran Benita <ran234@gmail.com>
3 * Copyright © 2023 Pierre Le Marre <dev@wismill.eu>
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
31 #include <sys/types.h>
35 #include "xvfb-wrapper.h"
36 #include "xkbcommon/xkbcommon-x11.h"
38 static bool xvfb_is_ready;
41 sigusr1_handler(int signal)
47 xvfb_wrapper(int (*test_func)(char* display))
51 char display_fd_string[32];
55 (char *) "Xvfb", (char *) "-displayfd", display_fd_string, NULL
57 char *envp[] = { NULL };
60 char display[32] = ":";
63 /* File descriptor to retrieve the display number */
64 display_fd = tmpfile();
65 if (display_fd == NULL){
66 fprintf(stderr, "Unable to create temporary file.\n");
69 snprintf(display_fd_string, sizeof(display_fd_string), "%d", fileno(display_fd));
71 /* Set SIGUSR1 to SIG_IGN so Xvfb will send us that signal
72 * when it's ready to accept connections */
74 sigaddset(&mask, SIGUSR1);
75 sigprocmask(SIG_BLOCK, &mask, NULL);
76 sa.sa_handler = SIG_IGN;
78 sigemptyset(&sa.sa_mask);
79 sigaction(SIGUSR1, &sa, NULL);
81 xvfb_is_ready = false;
84 * Xvfb command: let the server find an available display.
86 * Note that it may generate multiple times the following output in stderr:
87 * _XSERVTransSocketUNIXCreateListener: ...SocketCreateListener() failed
88 * It is expected: this is the server trying the ports until it finds one
91 ret = posix_spawnp(&xvfb_pid, "Xvfb", NULL, NULL, xvfb_argv, envp);
97 sa.sa_handler = SIG_DFL;
99 sigemptyset(&sa.sa_mask);
100 sigaction(SIGUSR1, &sa, NULL);
101 signal(SIGUSR1, sigusr1_handler);
102 sigprocmask (SIG_UNBLOCK, &mask, NULL);
104 /* Now wait for the SIGUSR1 signal that Xvfb is ready */
105 while (!xvfb_is_ready) {
107 if (++counter >= 3000) /* 3 seconds max wait */
111 signal(SIGUSR1, SIG_DFL);
113 /* Retrieve the display number: Xvfd writes the display number as a newline-
114 * terminated string; copy this number to form a proper display string. */
116 length = fread(&display[1], 1, sizeof(display) - 1, display_fd);
121 /* Drop the newline character */
122 display[length] = '\0';
125 /* Run the function requiring a running X server */
126 ret = test_func(display);
130 kill(xvfb_pid, SIGTERM);
136 /* All X11_TEST functions are in the test_functions_section ELF section.
137 * __start and __stop point to the start and end of that section. See the
138 * __attribute__(section) documentation.
140 extern const struct test_function __start_test_functions_section, __stop_test_functions_section;
145 size_t count = 1; /* For NULL-terminated entry */
147 for (const struct test_function *t = &__start_test_functions_section;
148 t < &__stop_test_functions_section;
153 for (const struct test_function *t = &__start_test_functions_section;
154 t < &__stop_test_functions_section;
156 fprintf(stderr, "Running test: %s from %s\n", t->name, t->file);
157 rc = xvfb_wrapper(t->func);