simple-xinit.c revision 1b5d61b8
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 631b5d61b8Smrg/* Starts the X server, returning its pid. */ 641b5d61b8Smrgstatic int 651b5d61b8Smrgstart_server(char *const *server_args) 661b5d61b8Smrg{ 671b5d61b8Smrg int server_pid = fork(); 681b5d61b8Smrg 691b5d61b8Smrg if (server_pid == -1) { 701b5d61b8Smrg fprintf(stderr, "Fork failed: %s\n", strerror(errno)); 711b5d61b8Smrg exit(1); 721b5d61b8Smrg } else if (server_pid != 0) { 731b5d61b8Smrg /* Continue along the main process that will exec the client. */ 741b5d61b8Smrg return server_pid; 751b5d61b8Smrg } 761b5d61b8Smrg 771b5d61b8Smrg /* Execute the server. This only returns if an error occurred. */ 781b5d61b8Smrg execvp(server_args[0], server_args); 791b5d61b8Smrg fprintf(stderr, "Error starting the server: %s\n", strerror(errno)); 801b5d61b8Smrg exit(1); 811b5d61b8Smrg} 821b5d61b8Smrg 831b5d61b8Smrg/* Reads the display number out of the started server's display socket. */ 841b5d61b8Smrgstatic int 851b5d61b8Smrgget_display(int displayfd) 861b5d61b8Smrg{ 871b5d61b8Smrg char display_string[10]; 881b5d61b8Smrg ssize_t ret; 891b5d61b8Smrg 901b5d61b8Smrg ret = read(displayfd, display_string, sizeof(display_string) - 1); 911b5d61b8Smrg if (ret <= 0) { 921b5d61b8Smrg fprintf(stderr, "Failed reading displayfd: %s\n", strerror(errno)); 931b5d61b8Smrg exit(1); 941b5d61b8Smrg } 951b5d61b8Smrg 961b5d61b8Smrg /* We've read in the display number as a string terminated by 971b5d61b8Smrg * '\n', but not '\0'. Cap it and parse the number. 981b5d61b8Smrg */ 991b5d61b8Smrg display_string[ret] = '\0'; 1001b5d61b8Smrg return atoi(display_string); 1011b5d61b8Smrg} 1021b5d61b8Smrg 1031b5d61b8Smrgstatic int 1041b5d61b8Smrgstart_client(char *const *client_args, int display) 1051b5d61b8Smrg{ 1061b5d61b8Smrg char *display_string; 1071b5d61b8Smrg int ret; 1081b5d61b8Smrg int client_pid; 1091b5d61b8Smrg 1101b5d61b8Smrg ret = asprintf(&display_string, ":%d", display); 1111b5d61b8Smrg if (ret < 0) { 1121b5d61b8Smrg fprintf(stderr, "asprintf fail\n"); 1131b5d61b8Smrg exit(1); 1141b5d61b8Smrg } 1151b5d61b8Smrg 1161b5d61b8Smrg ret = setenv("DISPLAY", display_string, true); 1171b5d61b8Smrg if (ret) { 1181b5d61b8Smrg fprintf(stderr, "Failed to set DISPLAY\n"); 1191b5d61b8Smrg exit(1); 1201b5d61b8Smrg } 1211b5d61b8Smrg 1221b5d61b8Smrg client_pid = fork(); 1231b5d61b8Smrg if (client_pid == -1) { 1241b5d61b8Smrg fprintf(stderr, "Fork failed: %s\n", strerror(errno)); 1251b5d61b8Smrg exit(1); 1261b5d61b8Smrg } else if (client_pid) { 1271b5d61b8Smrg int wstatus; 1281b5d61b8Smrg 1291b5d61b8Smrg ret = waitpid(client_pid, &wstatus, 0); 1301b5d61b8Smrg if (ret < 0) { 1311b5d61b8Smrg fprintf(stderr, "Error waiting for client to start: %s\n", 1321b5d61b8Smrg strerror(errno)); 1331b5d61b8Smrg return 1; 1341b5d61b8Smrg } 1351b5d61b8Smrg 1361b5d61b8Smrg if (!WIFEXITED(wstatus)) 1371b5d61b8Smrg return 1; 1381b5d61b8Smrg 1391b5d61b8Smrg return WEXITSTATUS(wstatus); 1401b5d61b8Smrg } else { 1411b5d61b8Smrg execvp(client_args[0], client_args); 1421b5d61b8Smrg /* exec only returns if an error occurred. */ 1431b5d61b8Smrg fprintf(stderr, "Error starting the client: %s\n", strerror(errno)); 1441b5d61b8Smrg exit(1); 1451b5d61b8Smrg } 1461b5d61b8Smrg} 1471b5d61b8Smrg 1481b5d61b8Smrg/* Splits the incoming argc/argv into a pair of NULL-terminated arrays 1491b5d61b8Smrg * of args. 1501b5d61b8Smrg */ 1511b5d61b8Smrgstatic void 1521b5d61b8Smrgparse_args(int argc, char **argv, 1531b5d61b8Smrg char * const **out_client_args, 1541b5d61b8Smrg char * const **out_server_args, 1551b5d61b8Smrg int displayfd) 1561b5d61b8Smrg{ 1571b5d61b8Smrg /* We're stripping the -- and the program name, inserting two 1581b5d61b8Smrg * NULLs, and also the -displayfd and fd number. 1591b5d61b8Smrg */ 1601b5d61b8Smrg char **args_storage = calloc(argc + 2, sizeof(char *)); 1611b5d61b8Smrg char *const *client_args; 1621b5d61b8Smrg char *const *server_args = NULL; 1631b5d61b8Smrg char **next_arg = args_storage; 1641b5d61b8Smrg bool parsing_client = true; 1651b5d61b8Smrg int i, ret; 1661b5d61b8Smrg char *displayfd_string; 1671b5d61b8Smrg 1681b5d61b8Smrg if (!args_storage) 1691b5d61b8Smrg exit(1); 1701b5d61b8Smrg 1711b5d61b8Smrg client_args = args_storage; 1721b5d61b8Smrg for (i = 1; i < argc; i++) { 1731b5d61b8Smrg if (strcmp(argv[i], "--") == 0) { 1741b5d61b8Smrg if (!parsing_client) 1751b5d61b8Smrg usage(argc, argv); 1761b5d61b8Smrg 1771b5d61b8Smrg /* Cap the client list */ 1781b5d61b8Smrg *next_arg = NULL; 1791b5d61b8Smrg next_arg++; 1801b5d61b8Smrg 1811b5d61b8Smrg /* Move to adding into server_args. */ 1821b5d61b8Smrg server_args = next_arg; 1831b5d61b8Smrg parsing_client = false; 1841b5d61b8Smrg continue; 1851b5d61b8Smrg } 1861b5d61b8Smrg 1871b5d61b8Smrg *next_arg = argv[i]; 1881b5d61b8Smrg next_arg++; 1891b5d61b8Smrg } 1901b5d61b8Smrg 1911b5d61b8Smrg if (client_args[0] == NULL || !server_args || server_args[0] == NULL) 1921b5d61b8Smrg usage(argc, argv); 1931b5d61b8Smrg 1941b5d61b8Smrg /* Give the server -displayfd X */ 1951b5d61b8Smrg *next_arg = (char *)"-displayfd"; 1961b5d61b8Smrg next_arg++; 1971b5d61b8Smrg 1981b5d61b8Smrg ret = asprintf(&displayfd_string, "%d", displayfd); 1991b5d61b8Smrg if (ret < 0) { 2001b5d61b8Smrg fprintf(stderr, "asprintf fail\n"); 2011b5d61b8Smrg exit(1); 2021b5d61b8Smrg } 2031b5d61b8Smrg *next_arg = displayfd_string; 2041b5d61b8Smrg next_arg++; 2051b5d61b8Smrg 2061b5d61b8Smrg *out_client_args = client_args; 2071b5d61b8Smrg *out_server_args = server_args; 2081b5d61b8Smrg} 2091b5d61b8Smrg 2101b5d61b8Smrgint 2111b5d61b8Smrgmain(int argc, char **argv) 2121b5d61b8Smrg{ 2131b5d61b8Smrg char * const *client_args; 2141b5d61b8Smrg char * const *server_args; 2151b5d61b8Smrg int displayfd_pipe[2]; 2161b5d61b8Smrg int display, server_pid; 2171b5d61b8Smrg int ret; 2181b5d61b8Smrg 2191b5d61b8Smrg ret = pipe(displayfd_pipe); 2201b5d61b8Smrg if (ret) { 2211b5d61b8Smrg fprintf(stderr, "Pipe creation failure: %s", strerror(errno)); 2221b5d61b8Smrg exit(1); 2231b5d61b8Smrg } 2241b5d61b8Smrg 2251b5d61b8Smrg parse_args(argc, argv, &client_args, &server_args, displayfd_pipe[1]); 2261b5d61b8Smrg server_pid = start_server(server_args); 2271b5d61b8Smrg display = get_display(displayfd_pipe[0]); 2281b5d61b8Smrg ret = start_client(client_args, display); 2291b5d61b8Smrg kill_server(server_pid); 2301b5d61b8Smrg 2311b5d61b8Smrg exit(ret); 2321b5d61b8Smrg} 233