2 * Copyright © 2016 Broadcom
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:
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
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
24 #include <dix-config.h>
26 #include <X11/Xfuncproto.h>
38 kill_server(int server_pid
)
40 int ret
= kill(server_pid
, SIGTERM
);
44 fprintf(stderr
, "Failed to send kill to the server: %s\n",
49 ret
= waitpid(server_pid
, &wstatus
, 0);
51 fprintf(stderr
, "Failed to wait for X to die: %s\n", strerror(errno
));
56 _X_NORETURN
static void
57 usage(int argc
, char **argv
)
59 fprintf(stderr
, "%s <client command> -- <server command>\n", argv
[0]);
63 static int server_displayfd
;
64 static const char *server_dead
= "server_dead";
67 handle_sigchld(int sig
)
69 write(server_displayfd
, server_dead
, strlen(server_dead
));
72 /* Starts the X server, returning its pid. */
74 start_server(char *const *server_args
)
76 int server_pid
= fork();
78 if (server_pid
== -1) {
79 fprintf(stderr
, "Fork failed: %s\n", strerror(errno
));
81 } else if (server_pid
!= 0) {
82 /* Continue along the main process that will exec the client. */
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",
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
));
103 /* Reads the display number out of the started server's display socket. */
105 get_display(int displayfd
)
107 char display_string
[20];
110 ret
= read(displayfd
, display_string
, sizeof(display_string
) - 1);
112 fprintf(stderr
, "Failed reading displayfd: %s\n", strerror(errno
));
116 /* We've read in the display number as a string terminated by
117 * '\n', but not '\0'. Cap it and parse the number.
119 display_string
[ret
] = '\0';
121 if (strncmp(display_string
, server_dead
, strlen(server_dead
)) == 0) {
122 fprintf(stderr
, "Server failed to start before setting up displayfd\n");
126 return atoi(display_string
);
130 start_client(char *const *client_args
, int display
)
132 char *display_string
;
136 ret
= asprintf(&display_string
, ":%d", display
);
138 fprintf(stderr
, "asprintf fail\n");
142 ret
= setenv("DISPLAY", display_string
, true);
144 fprintf(stderr
, "Failed to set DISPLAY\n");
149 if (client_pid
== -1) {
150 fprintf(stderr
, "Fork failed: %s\n", strerror(errno
));
152 } else if (client_pid
) {
155 ret
= waitpid(client_pid
, &wstatus
, 0);
157 fprintf(stderr
, "Error waiting for client to start: %s\n",
162 if (!WIFEXITED(wstatus
))
165 return WEXITSTATUS(wstatus
);
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
));
174 /* Splits the incoming argc/argv into a pair of NULL-terminated arrays
178 parse_args(int argc
, char **argv
,
179 char * const **out_client_args
,
180 char * const **out_server_args
,
183 /* We're stripping the -- and the program name, inserting two
184 * NULLs, and also the -displayfd and fd number.
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;
192 char *displayfd_string
;
197 client_args
= args_storage
;
198 for (i
= 1; i
< argc
; i
++) {
199 if (strcmp(argv
[i
], "--") == 0) {
203 /* Cap the client list */
207 /* Move to adding into server_args. */
208 server_args
= next_arg
;
209 parsing_client
= false;
213 /* A sort of escaped "--" argument so we can nest server
214 * invocations for testing.
216 if (strcmp(argv
[i
], "----") == 0)
217 *next_arg
= (char *)"--";
223 if (client_args
[0] == NULL
|| !server_args
|| server_args
[0] == NULL
)
226 /* Give the server -displayfd X */
227 *next_arg
= (char *)"-displayfd";
230 ret
= asprintf(&displayfd_string
, "%d", displayfd
);
232 fprintf(stderr
, "asprintf fail\n");
235 *next_arg
= displayfd_string
;
238 *out_client_args
= client_args
;
239 *out_server_args
= server_args
;
243 main(int argc
, char **argv
)
245 char * const *client_args
;
246 char * const *server_args
;
247 int displayfd_pipe
[2];
248 int display
, server_pid
;
251 ret
= pipe(displayfd_pipe
);
253 fprintf(stderr
, "Pipe creation failure: %s", strerror(errno
));
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
);