xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

simple-xinit.c (7271B)


      1 /*
      2  * Copyright © 2016 Broadcom
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #ifdef HAVE_DIX_CONFIG_H
     25 #include <dix-config.h>
     26 #endif
     27 
     28 #include <errno.h>
     29 #include <signal.h>
     30 #include <stdbool.h>
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <sys/wait.h>
     35 #include <unistd.h>
     36 
     37 static void
     38 kill_server(int server_pid)
     39 {
     40     int ret = kill(server_pid, SIGTERM);
     41     int wstatus;
     42 
     43     if (ret) {
     44         fprintf(stderr, "Failed to send kill to the server: %s\n",
     45                 strerror(errno));
     46         exit(1);
     47     }
     48 
     49     ret = waitpid(server_pid, &wstatus, 0);
     50     if (ret < 0) {
     51         fprintf(stderr, "Failed to wait for X to die: %s\n", strerror(errno));
     52         exit(1);
     53     }
     54 }
     55 
     56 static void
     57 usage(int argc, char **argv)
     58 {
     59     fprintf(stderr, "%s <client command> -- <server command>\n", argv[0]);
     60     exit(1);
     61 }
     62 
     63 static int server_displayfd;
     64 static const char *server_dead = "server_dead";
     65 
     66 static void
     67 handle_sigchld(int sig)
     68 {
     69     write(server_displayfd, server_dead, strlen(server_dead));
     70 }
     71 
     72 /* Starts the X server, returning its pid. */
     73 static int
     74 start_server(char *const *server_args)
     75 {
     76     int server_pid = fork();
     77 
     78     if (server_pid == -1) {
     79         fprintf(stderr, "Fork failed: %s\n", strerror(errno));
     80         exit(1);
     81     } else if (server_pid != 0) {
     82         /* Continue along the main process that will exec the client. */
     83 
     84         struct sigaction sa;
     85         sa.sa_handler = handle_sigchld;
     86         sigemptyset(&sa.sa_mask);
     87         sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
     88         if (sigaction(SIGCHLD, &sa, 0) == -1) {
     89             fprintf(stderr, "Failed to set up signal handler: %s\n",
     90                     strerror(errno));
     91             exit(1);
     92         }
     93 
     94         return server_pid;
     95     }
     96 
     97     /* Execute the server.  This only returns if an error occurred. */
     98     execvp(server_args[0], server_args);
     99     fprintf(stderr, "Error starting the server: %s\n", strerror(errno));
    100     exit(1);
    101 }
    102 
    103 /* Reads the display number out of the started server's display socket. */
    104 static int
    105 get_display(int displayfd)
    106 {
    107     char display_string[20];
    108     ssize_t ret;
    109 
    110     ret = read(displayfd, display_string, sizeof(display_string) - 1);
    111     if (ret <= 0) {
    112         fprintf(stderr, "Failed reading displayfd: %s\n", strerror(errno));
    113         exit(1);
    114     }
    115 
    116     /* We've read in the display number as a string terminated by
    117      * '\n', but not '\0'.  Cap it and parse the number.
    118      */
    119     display_string[ret] = '\0';
    120 
    121     if (strncmp(display_string, server_dead, strlen(server_dead)) == 0) {
    122         fprintf(stderr, "Server failed to start before setting up displayfd\n");
    123         exit(1);
    124     }
    125 
    126     return atoi(display_string);
    127 }
    128 
    129 static int
    130 start_client(char *const *client_args, int display)
    131 {
    132     char *display_string;
    133     int ret;
    134     int client_pid;
    135 
    136     ret = asprintf(&display_string, ":%d", display);
    137     if (ret < 0) {
    138         fprintf(stderr, "asprintf fail\n");
    139         exit(1);
    140     }
    141 
    142     ret = setenv("DISPLAY", display_string, true);
    143     if (ret) {
    144         fprintf(stderr, "Failed to set DISPLAY\n");
    145         exit(1);
    146     }
    147 
    148     client_pid = fork();
    149     if (client_pid == -1) {
    150         fprintf(stderr, "Fork failed: %s\n", strerror(errno));
    151         exit(1);
    152     } else if (client_pid) {
    153         int wstatus;
    154 
    155         ret = waitpid(client_pid, &wstatus, 0);
    156         if (ret < 0) {
    157             fprintf(stderr, "Error waiting for client to start: %s\n",
    158                     strerror(errno));
    159             return 1;
    160         }
    161 
    162         if (!WIFEXITED(wstatus))
    163             return 1;
    164 
    165         return WEXITSTATUS(wstatus);
    166     } else {
    167         execvp(client_args[0], client_args);
    168         /* exec only returns if an error occurred. */
    169         fprintf(stderr, "Error starting the client: %s\n", strerror(errno));
    170         exit(1);
    171     }
    172 }
    173 
    174 /* Splits the incoming argc/argv into a pair of NULL-terminated arrays
    175  * of args.
    176  */
    177 static void
    178 parse_args(int argc, char **argv,
    179            char * const **out_client_args,
    180            char * const **out_server_args,
    181            int displayfd)
    182 {
    183     /* We're stripping the -- and the program name, inserting two
    184      * NULLs, and also the -displayfd and fd number.
    185      */
    186     char **args_storage = calloc(argc + 2, sizeof(char *));
    187     char *const *client_args;
    188     char *const *server_args = NULL;
    189     char **next_arg = args_storage;
    190     bool parsing_client = true;
    191     int i, ret;
    192     char *displayfd_string;
    193 
    194     if (!args_storage)
    195         exit(1);
    196 
    197     client_args = args_storage;
    198     for (i = 1; i < argc; i++) {
    199         if (strcmp(argv[i], "--") == 0) {
    200             if (!parsing_client)
    201                 usage(argc, argv);
    202 
    203             /* Cap the client list */
    204             *next_arg = NULL;
    205             next_arg++;
    206 
    207             /* Move to adding into server_args. */
    208             server_args = next_arg;
    209             parsing_client = false;
    210             continue;
    211         }
    212 
    213         /* A sort of escaped "--" argument so we can nest server
    214          * invocations for testing.
    215          */
    216         if (strcmp(argv[i], "----") == 0)
    217             *next_arg = (char *)"--";
    218         else
    219             *next_arg = argv[i];
    220         next_arg++;
    221     }
    222 
    223     if (client_args[0] == NULL || !server_args || server_args[0] == NULL)
    224         usage(argc, argv);
    225 
    226     /* Give the server -displayfd X */
    227     *next_arg = (char *)"-displayfd";
    228     next_arg++;
    229 
    230     ret = asprintf(&displayfd_string, "%d", displayfd);
    231     if (ret < 0) {
    232         fprintf(stderr, "asprintf fail\n");
    233         exit(1);
    234     }
    235     *next_arg = displayfd_string;
    236     next_arg++;
    237 
    238     *out_client_args = client_args;
    239     *out_server_args = server_args;
    240 }
    241 
    242 int
    243 main(int argc, char **argv)
    244 {
    245     char * const *client_args;
    246     char * const *server_args;
    247     int displayfd_pipe[2];
    248     int display, server_pid;
    249     int ret;
    250 
    251     ret = pipe(displayfd_pipe);
    252     if (ret) {
    253         fprintf(stderr, "Pipe creation failure: %s", strerror(errno));
    254         exit(1);
    255     }
    256 
    257     server_displayfd = displayfd_pipe[1];
    258     parse_args(argc, argv, &client_args, &server_args, server_displayfd);
    259     server_pid = start_server(server_args);
    260     display = get_display(displayfd_pipe[0]);
    261     ret = start_client(client_args, display);
    262     kill_server(server_pid);
    263 
    264     exit(ret);
    265 }