simple-xinit.c revision ed6184df
11b5d61b8Smrg/* 21b5d61b8Smrg * Copyright © 2016 Broadcom 31b5d61b8Smrg * 41b5d61b8Smrg * Permission is hereby granted, free of charge, to any person obtaining a 51b5d61b8Smrg * copy of this software and associated documentation files (the "Software"), 61b5d61b8Smrg * to deal in the Software without restriction, including without limitation 71b5d61b8Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 81b5d61b8Smrg * and/or sell copies of the Software, and to permit persons to whom the 91b5d61b8Smrg * Software is furnished to do so, subject to the following conditions: 101b5d61b8Smrg * 111b5d61b8Smrg * The above copyright notice and this permission notice (including the next 121b5d61b8Smrg * paragraph) shall be included in all copies or substantial portions of the 131b5d61b8Smrg * Software. 141b5d61b8Smrg * 151b5d61b8Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 161b5d61b8Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 171b5d61b8Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 181b5d61b8Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 191b5d61b8Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 201b5d61b8Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 211b5d61b8Smrg * IN THE SOFTWARE. 221b5d61b8Smrg */ 231b5d61b8Smrg 241b5d61b8Smrg#ifdef HAVE_DIX_CONFIG_H 251b5d61b8Smrg#include <dix-config.h> 261b5d61b8Smrg#endif 271b5d61b8Smrg 281b5d61b8Smrg#include <errno.h> 291b5d61b8Smrg#include <signal.h> 301b5d61b8Smrg#include <stdbool.h> 311b5d61b8Smrg#include <stdio.h> 321b5d61b8Smrg#include <stdlib.h> 331b5d61b8Smrg#include <string.h> 341b5d61b8Smrg#include <sys/wait.h> 351b5d61b8Smrg#include <unistd.h> 361b5d61b8Smrg 371b5d61b8Smrgstatic void 381b5d61b8Smrgkill_server(int server_pid) 391b5d61b8Smrg{ 401b5d61b8Smrg int ret = kill(server_pid, SIGTERM); 411b5d61b8Smrg int wstatus; 421b5d61b8Smrg 431b5d61b8Smrg if (ret) { 441b5d61b8Smrg fprintf(stderr, "Failed to send kill to the server: %s\n", 451b5d61b8Smrg strerror(errno)); 461b5d61b8Smrg exit(1); 471b5d61b8Smrg } 481b5d61b8Smrg 491b5d61b8Smrg ret = waitpid(server_pid, &wstatus, 0); 501b5d61b8Smrg if (ret < 0) { 511b5d61b8Smrg fprintf(stderr, "Failed to wait for X to die: %s\n", strerror(errno)); 521b5d61b8Smrg exit(1); 531b5d61b8Smrg } 541b5d61b8Smrg} 551b5d61b8Smrg 561b5d61b8Smrgstatic void 571b5d61b8Smrgusage(int argc, char **argv) 581b5d61b8Smrg{ 591b5d61b8Smrg fprintf(stderr, "%s <client command> -- <server command>\n", argv[0]); 601b5d61b8Smrg exit(1); 611b5d61b8Smrg} 621b5d61b8Smrg 63ed6184dfSmrgstatic int server_displayfd; 64ed6184dfSmrgstatic const char *server_dead = "server_dead"; 65ed6184dfSmrg 66ed6184dfSmrgstatic void 67ed6184dfSmrghandle_sigchld(int sig) 68ed6184dfSmrg{ 69ed6184dfSmrg write(server_displayfd, server_dead, strlen(server_dead)); 70ed6184dfSmrg} 71ed6184dfSmrg 721b5d61b8Smrg/* Starts the X server, returning its pid. */ 731b5d61b8Smrgstatic int 741b5d61b8Smrgstart_server(char *const *server_args) 751b5d61b8Smrg{ 761b5d61b8Smrg int server_pid = fork(); 771b5d61b8Smrg 781b5d61b8Smrg if (server_pid == -1) { 791b5d61b8Smrg fprintf(stderr, "Fork failed: %s\n", strerror(errno)); 801b5d61b8Smrg exit(1); 811b5d61b8Smrg } else if (server_pid != 0) { 821b5d61b8Smrg /* Continue along the main process that will exec the client. */ 83ed6184dfSmrg 84ed6184dfSmrg struct sigaction sa; 85ed6184dfSmrg sa.sa_handler = handle_sigchld; 86ed6184dfSmrg sigemptyset(&sa.sa_mask); 87ed6184dfSmrg sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; 88ed6184dfSmrg if (sigaction(SIGCHLD, &sa, 0) == -1) { 89ed6184dfSmrg fprintf(stderr, "Failed to set up signal handler: %s\n", 90ed6184dfSmrg strerror(errno)); 91ed6184dfSmrg exit(1); 92ed6184dfSmrg } 93ed6184dfSmrg 941b5d61b8Smrg return server_pid; 951b5d61b8Smrg } 961b5d61b8Smrg 971b5d61b8Smrg /* Execute the server. This only returns if an error occurred. */ 981b5d61b8Smrg execvp(server_args[0], server_args); 991b5d61b8Smrg fprintf(stderr, "Error starting the server: %s\n", strerror(errno)); 1001b5d61b8Smrg exit(1); 1011b5d61b8Smrg} 1021b5d61b8Smrg 1031b5d61b8Smrg/* Reads the display number out of the started server's display socket. */ 1041b5d61b8Smrgstatic int 1051b5d61b8Smrgget_display(int displayfd) 1061b5d61b8Smrg{ 107ed6184dfSmrg char display_string[20]; 1081b5d61b8Smrg ssize_t ret; 1091b5d61b8Smrg 1101b5d61b8Smrg ret = read(displayfd, display_string, sizeof(display_string) - 1); 1111b5d61b8Smrg if (ret <= 0) { 1121b5d61b8Smrg fprintf(stderr, "Failed reading displayfd: %s\n", strerror(errno)); 1131b5d61b8Smrg exit(1); 1141b5d61b8Smrg } 1151b5d61b8Smrg 1161b5d61b8Smrg /* We've read in the display number as a string terminated by 1171b5d61b8Smrg * '\n', but not '\0'. Cap it and parse the number. 1181b5d61b8Smrg */ 1191b5d61b8Smrg display_string[ret] = '\0'; 120ed6184dfSmrg 121ed6184dfSmrg if (strncmp(display_string, server_dead, strlen(server_dead)) == 0) { 122ed6184dfSmrg fprintf(stderr, "Server failed to start before setting up displayfd\n"); 123ed6184dfSmrg exit(1); 124ed6184dfSmrg } 125ed6184dfSmrg 1261b5d61b8Smrg return atoi(display_string); 1271b5d61b8Smrg} 1281b5d61b8Smrg 1291b5d61b8Smrgstatic int 1301b5d61b8Smrgstart_client(char *const *client_args, int display) 1311b5d61b8Smrg{ 1321b5d61b8Smrg char *display_string; 1331b5d61b8Smrg int ret; 1341b5d61b8Smrg int client_pid; 1351b5d61b8Smrg 1361b5d61b8Smrg ret = asprintf(&display_string, ":%d", display); 1371b5d61b8Smrg if (ret < 0) { 1381b5d61b8Smrg fprintf(stderr, "asprintf fail\n"); 1391b5d61b8Smrg exit(1); 1401b5d61b8Smrg } 1411b5d61b8Smrg 1421b5d61b8Smrg ret = setenv("DISPLAY", display_string, true); 1431b5d61b8Smrg if (ret) { 1441b5d61b8Smrg fprintf(stderr, "Failed to set DISPLAY\n"); 1451b5d61b8Smrg exit(1); 1461b5d61b8Smrg } 1471b5d61b8Smrg 1481b5d61b8Smrg client_pid = fork(); 1491b5d61b8Smrg if (client_pid == -1) { 1501b5d61b8Smrg fprintf(stderr, "Fork failed: %s\n", strerror(errno)); 1511b5d61b8Smrg exit(1); 1521b5d61b8Smrg } else if (client_pid) { 1531b5d61b8Smrg int wstatus; 1541b5d61b8Smrg 1551b5d61b8Smrg ret = waitpid(client_pid, &wstatus, 0); 1561b5d61b8Smrg if (ret < 0) { 1571b5d61b8Smrg fprintf(stderr, "Error waiting for client to start: %s\n", 1581b5d61b8Smrg strerror(errno)); 1591b5d61b8Smrg return 1; 1601b5d61b8Smrg } 1611b5d61b8Smrg 1621b5d61b8Smrg if (!WIFEXITED(wstatus)) 1631b5d61b8Smrg return 1; 1641b5d61b8Smrg 1651b5d61b8Smrg return WEXITSTATUS(wstatus); 1661b5d61b8Smrg } else { 1671b5d61b8Smrg execvp(client_args[0], client_args); 1681b5d61b8Smrg /* exec only returns if an error occurred. */ 1691b5d61b8Smrg fprintf(stderr, "Error starting the client: %s\n", strerror(errno)); 1701b5d61b8Smrg exit(1); 1711b5d61b8Smrg } 1721b5d61b8Smrg} 1731b5d61b8Smrg 1741b5d61b8Smrg/* Splits the incoming argc/argv into a pair of NULL-terminated arrays 1751b5d61b8Smrg * of args. 1761b5d61b8Smrg */ 1771b5d61b8Smrgstatic void 1781b5d61b8Smrgparse_args(int argc, char **argv, 1791b5d61b8Smrg char * const **out_client_args, 1801b5d61b8Smrg char * const **out_server_args, 1811b5d61b8Smrg int displayfd) 1821b5d61b8Smrg{ 1831b5d61b8Smrg /* We're stripping the -- and the program name, inserting two 1841b5d61b8Smrg * NULLs, and also the -displayfd and fd number. 1851b5d61b8Smrg */ 1861b5d61b8Smrg char **args_storage = calloc(argc + 2, sizeof(char *)); 1871b5d61b8Smrg char *const *client_args; 1881b5d61b8Smrg char *const *server_args = NULL; 1891b5d61b8Smrg char **next_arg = args_storage; 1901b5d61b8Smrg bool parsing_client = true; 1911b5d61b8Smrg int i, ret; 1921b5d61b8Smrg char *displayfd_string; 1931b5d61b8Smrg 1941b5d61b8Smrg if (!args_storage) 1951b5d61b8Smrg exit(1); 1961b5d61b8Smrg 1971b5d61b8Smrg client_args = args_storage; 1981b5d61b8Smrg for (i = 1; i < argc; i++) { 1991b5d61b8Smrg if (strcmp(argv[i], "--") == 0) { 2001b5d61b8Smrg if (!parsing_client) 2011b5d61b8Smrg usage(argc, argv); 2021b5d61b8Smrg 2031b5d61b8Smrg /* Cap the client list */ 2041b5d61b8Smrg *next_arg = NULL; 2051b5d61b8Smrg next_arg++; 2061b5d61b8Smrg 2071b5d61b8Smrg /* Move to adding into server_args. */ 2081b5d61b8Smrg server_args = next_arg; 2091b5d61b8Smrg parsing_client = false; 2101b5d61b8Smrg continue; 2111b5d61b8Smrg } 2121b5d61b8Smrg 213ed6184dfSmrg /* A sort of escaped "--" argument so we can nest server 214ed6184dfSmrg * invocations for testing. 215ed6184dfSmrg */ 216ed6184dfSmrg if (strcmp(argv[i], "----") == 0) 217ed6184dfSmrg *next_arg = (char *)"--"; 218ed6184dfSmrg else 219ed6184dfSmrg *next_arg = argv[i]; 2201b5d61b8Smrg next_arg++; 2211b5d61b8Smrg } 2221b5d61b8Smrg 2231b5d61b8Smrg if (client_args[0] == NULL || !server_args || server_args[0] == NULL) 2241b5d61b8Smrg usage(argc, argv); 2251b5d61b8Smrg 2261b5d61b8Smrg /* Give the server -displayfd X */ 2271b5d61b8Smrg *next_arg = (char *)"-displayfd"; 2281b5d61b8Smrg next_arg++; 2291b5d61b8Smrg 2301b5d61b8Smrg ret = asprintf(&displayfd_string, "%d", displayfd); 2311b5d61b8Smrg if (ret < 0) { 2321b5d61b8Smrg fprintf(stderr, "asprintf fail\n"); 2331b5d61b8Smrg exit(1); 2341b5d61b8Smrg } 2351b5d61b8Smrg *next_arg = displayfd_string; 2361b5d61b8Smrg next_arg++; 2371b5d61b8Smrg 2381b5d61b8Smrg *out_client_args = client_args; 2391b5d61b8Smrg *out_server_args = server_args; 2401b5d61b8Smrg} 2411b5d61b8Smrg 2421b5d61b8Smrgint 2431b5d61b8Smrgmain(int argc, char **argv) 2441b5d61b8Smrg{ 2451b5d61b8Smrg char * const *client_args; 2461b5d61b8Smrg char * const *server_args; 2471b5d61b8Smrg int displayfd_pipe[2]; 2481b5d61b8Smrg int display, server_pid; 2491b5d61b8Smrg int ret; 2501b5d61b8Smrg 2511b5d61b8Smrg ret = pipe(displayfd_pipe); 2521b5d61b8Smrg if (ret) { 2531b5d61b8Smrg fprintf(stderr, "Pipe creation failure: %s", strerror(errno)); 2541b5d61b8Smrg exit(1); 2551b5d61b8Smrg } 2561b5d61b8Smrg 257ed6184dfSmrg server_displayfd = displayfd_pipe[1]; 258ed6184dfSmrg parse_args(argc, argv, &client_args, &server_args, server_displayfd); 2591b5d61b8Smrg server_pid = start_server(server_args); 2601b5d61b8Smrg display = get_display(displayfd_pipe[0]); 2611b5d61b8Smrg ret = start_client(client_args, display); 2621b5d61b8Smrg kill_server(server_pid); 2631b5d61b8Smrg 2641b5d61b8Smrg exit(ret); 2651b5d61b8Smrg} 266