3 Copyright 1986, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
33 #include <X11/Xatom.h>
45 #include <AvailabilityMacros.h>
46 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
51 /* For PRIO_PROCESS and setpriority() */
53 #include <sys/resource.h>
61 const char *bindir = BINDIR;
62 const char * const server_names[] = {
64 "Xquartz Mac OSX Quartz displays.",
67 "XWin X Server for the Cygwin environment on Microsoft Windows",
69 "Xorg Common X server for most displays",
72 "Xvfb Virtual frame buffer",
73 "Xfake kdrive-based virtual frame buffer",
74 "Xnest X server nested in a window on another X server",
75 "Xephyr kdrive-based nested X server",
76 "Xvnc X server accessed over VNC's RFB protocol",
77 "Xdmx Distributed Multi-head X server",
81 #define XINITRC ".xinitrc"
86 #define XSERVERRC ".xserverrc"
88 char xserverrcbuf[256];
93 static char *default_server = "X";
94 static char *default_display = ":0"; /* choose most efficient */
95 static char *default_client[] = {"xterm", "-geometry", "+1+1", "-n", "login", NULL};
96 static char *serverargv[100];
97 static char *clientargv[100];
98 static char **server = serverargv + 2; /* make sure room for sh .xserverrc args */
99 static char **client = clientargv + 2; /* make sure room for sh .xinitrc args */
100 static char *displayNum = NULL;
101 static char *program = NULL;
102 static Display *xd = NULL; /* server connection */
106 volatile int gotSignal = 0;
108 static void Execute(char **vec);
109 static Bool waitforserver(void);
110 static Bool processTimeout(int timeout, char *string);
111 static int startServer(char *server[]);
112 static int startClient(char *client[]);
113 static int ignorexio(Display *dpy);
114 static void shutdown(void);
115 static void set_environment(void);
117 static void Fatal(const char *fmt, ...);
118 static void Error(const char *fmt, ...);
119 static void Fatalx(const char *fmt, ...);
120 static void Errorx(const char *fmt, ...);
125 /* On system with POSIX signals, just interrupt the system call */
135 Execute(char **vec) /* has room from up above */
138 if (access(vec[0], R_OK) == 0) {
139 vec--; /* back it up to stuff shell in */
147 main(int argc, char *argv[])
149 register char **sptr = server;
150 register char **cptr = client;
153 int client_given = 0, server_given = 0;
154 int client_args_given = 0, server_args_given = 0;
155 int start_of_client_args, start_of_server_args;
156 struct sigaction sa, si;
158 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
159 vproc_transaction_t vt;
166 * copy the client args.
169 (**argv != '/' && **argv != '.')) {
170 for (ptr = default_client; *ptr; )
175 start_of_client_args = (cptr - client);
176 while (argc && strcmp(*argv, "--")) {
188 * Copy the server args.
191 (**argv != '/' && **argv != '.')) {
192 *sptr++ = default_server;
198 if (argc > 0 && (argv[0][0] == ':' && isdigit(argv[0][1])))
201 displayNum = *sptr++ = default_display;
203 start_of_server_args = (sptr - server);
204 while (--argc >= 0) {
211 * if no client arguments given, check for a startup file and copy
212 * that into the argument list
216 Bool required = False;
218 xinitrcbuf[0] = '\0';
219 if ((cp = getenv("XINITRC")) != NULL) {
220 snprintf(xinitrcbuf, sizeof(xinitrcbuf), "%s", cp);
222 } else if ((cp = getenv("HOME")) != NULL) {
223 snprintf(xinitrcbuf, sizeof(xinitrcbuf),
224 "%s/%s", cp, XINITRC);
227 if (access(xinitrcbuf, F_OK) == 0) {
228 client += start_of_client_args - 1;
229 client[0] = xinitrcbuf;
230 } else if (required) {
231 Error("warning, no client init file \"%s\"", xinitrcbuf);
237 * if no server arguments given, check for a startup file and copy
238 * that into the argument list
242 Bool required = False;
244 xserverrcbuf[0] = '\0';
245 if ((cp = getenv("XSERVERRC")) != NULL) {
246 snprintf(xserverrcbuf, sizeof(xserverrcbuf), "%s", cp);
248 } else if ((cp = getenv("HOME")) != NULL) {
249 snprintf(xserverrcbuf, sizeof(xserverrcbuf),
250 "%s/%s", cp, XSERVERRC);
252 if (xserverrcbuf[0]) {
253 if (access(xserverrcbuf, F_OK) == 0) {
254 server += start_of_server_args - 1;
255 server[0] = xserverrcbuf;
256 } else if (required) {
257 Error("warning, no server init file \"%s\"", xserverrcbuf);
263 * Start the server and client.
265 signal(SIGCHLD, SIG_DFL); /* Insurance */
267 /* Let those signal interrupt the wait() call in the main loop */
268 memset(&sa, 0, sizeof sa);
269 sa.sa_handler = sigCatch;
270 sigemptyset(&sa.sa_mask);
271 sa.sa_flags = 0; /* do not set SA_RESTART */
273 sigaction(SIGTERM, &sa, NULL);
274 sigaction(SIGQUIT, &sa, NULL);
275 sigaction(SIGINT, &sa, NULL);
276 sigaction(SIGHUP, &sa, NULL);
277 sigaction(SIGPIPE, &sa, NULL);
279 memset(&si, 0, sizeof(si));
280 si.sa_handler = sigIgnore;
281 sigemptyset(&si.sa_mask);
282 si.sa_flags = SA_RESTART;
284 sigaction(SIGALRM, &si, NULL);
285 sigaction(SIGUSR1, &si, NULL);
288 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
289 vt = vproc_transaction_begin(NULL);
293 if (startServer(server) > 0
294 && startClient(client) > 0) {
295 #ifdef _F_EXIT_AFTER_XORG_AND_XCLIENT_LAUNCHED_
297 #endif//_F_EXIT_AFTER_XORG_AND_XCLIENT_LAUNCHED_
299 while (pid != clientpid && pid != serverpid
306 #if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
307 vproc_transaction_end(NULL, vt);
311 signal(SIGTERM, SIG_IGN);
312 signal(SIGQUIT, SIG_IGN);
313 signal(SIGINT, SIG_IGN);
314 signal(SIGHUP, SIG_IGN);
315 signal(SIGPIPE, SIG_IGN);
319 if (gotSignal != 0) {
320 Errorx("unexpected signal %d", gotSignal);
325 Fatalx("server error");
327 Fatalx("client error");
333 * waitforserver - wait for X server to start up
338 int ncycles = 120; /* # of cycles to wait */
339 int cycles; /* Wait cycle count */
342 /* For Apple, we don't get signaled by the server when it's ready, so we just
343 * want to sleep now since we're going to sleep later anyways and this allows us
344 * to avoid the awkard, "why is there an error message in the log" questions
351 for (cycles = 0; cycles < ncycles; cycles++) {
352 if ((xd = XOpenDisplay(displayNum))) {
356 if (!processTimeout(1, "X server to begin accepting connections"))
367 * return TRUE if we timeout waiting for pid to exit, FALSE otherwise.
370 processTimeout(int timeout, char *string)
372 int i = 0, pidfound = -1;
373 static char *laststring;
376 if ((pidfound = waitpid(serverpid, &status, WNOHANG)) == serverpid)
379 if (i == 0 && string != laststring)
380 fprintf(stderr, "\r\nwaiting for %s ", string);
382 fprintf(stderr, ".");
389 if (i > 0) fputc('\n', stderr); /* tidy up after message */
391 return (serverpid != pidfound);
395 startServer(char *server[])
398 const char * const *cpp;
401 sigaddset(&mask, SIGUSR1);
402 sigprocmask(SIG_BLOCK, &mask, &old);
409 sigprocmask(SIG_SETMASK, &old, NULL);
412 * don't hang on read/write to control tty
414 signal(SIGTTIN, SIG_IGN);
415 signal(SIGTTOU, SIG_IGN);
417 * ignore SIGUSR1 in child. The server
418 * will notice this and send SIGUSR1 back
419 * at xinit when ready to accept connections
421 signal(SIGUSR1, SIG_IGN);
423 * prevent server from getting sighup from vhangup()
424 * if client is xterm -L
429 Error("unable to run server \"%s\"", server[0]);
431 fprintf(stderr, "Use the -- option, or make sure that %s is in your path and\n", bindir);
432 fprintf(stderr, "that \"%s\" is a program or a link to the right type of server\n", server[0]);
433 fprintf(stderr, "for your display. Possible server names include:\n\n");
434 for (cpp = server_names; *cpp; cpp++)
435 fprintf(stderr, " %s\n", *cpp);
436 fprintf(stderr, "\n");
447 setpriority(PRIO_PROCESS, serverpid, -1);
450 if(! processTimeout(0, "")) {
455 * kludge to avoid race with TCP, giving server time to
456 * set his socket options before we try to open it,
457 * either use the 15 second timeout, or await SIGUSR1.
459 * If your machine is substantially slower than 15 seconds,
460 * you can easily adjust this value.
466 sigprocmask(SIG_SETMASK, &old, NULL);
468 if (waitforserver() == 0) {
469 Error("unable to connect to X server");
482 /* setting WINDOWPATH for clients */
486 unsigned long nitems;
487 unsigned long bytes_after;
489 const char *windowpath;
495 prop = XInternAtom(xd, "XFree86_VT", False);
497 Errorx("Unable to intern XFree86_VT atom");
500 if (XGetWindowProperty(xd, DefaultRootWindow(xd), prop, 0, 1,
501 False, AnyPropertyType, &actualtype, &actualformat,
502 &nitems, &bytes_after, &buf)) {
503 Errorx("No XFree86_VT property detected on X server, WINDOWPATH won't be set");
507 Errorx("XFree86_VT property unexpectedly has %lu items instead of 1", nitems);
511 switch (actualtype) {
515 switch (actualformat) {
517 num = (*(uint8_t *)(void *)buf);
520 num = (*(uint16_t *)(void *)buf);
523 num = (*(uint32_t *)(void *)buf);
526 Errorx("XFree86_VT property has unexpected format %d", actualformat);
532 Errorx("XFree86_VT property has unexpected type %lx", actualtype);
537 windowpath = getenv("WINDOWPATH");
538 numn = snprintf(nums, sizeof(nums), "%lu", num);
541 newwindowpath = malloc(len);
542 if (newwindowpath == NULL)
544 snprintf(newwindowpath, len, "%s", nums);
546 len = strlen(windowpath) + 1 + numn + 1;
547 newwindowpath = malloc(len);
548 if (newwindowpath == NULL)
550 snprintf(newwindowpath, len, "%s:%s",
553 if (setenv("WINDOWPATH", newwindowpath, TRUE) == -1)
554 Error("unable to set WINDOWPATH");
561 startClient(char *client[])
564 if (clientpid == 0) {
568 if (setuid(getuid()) == -1) {
569 Error("cannot change uid");
572 setpgid(0, getpid());
574 Error("Unable to run program \"%s\"", client[0]);
576 fprintf(stderr, "Specify a program on the command line or make sure that %s\n", bindir);
577 fprintf(stderr, "is in your path.\n\n");
585 static jmp_buf close_env;
588 ignorexio(Display *dpy)
590 Errorx("connection to X server lost");
591 longjmp(close_env, 1);
599 /* have kept display opened, so close it now */
601 XSetIOErrorHandler(ignorexio);
602 if (! setjmp(close_env)) {
606 /* HUP all local clients to allow them to clean up */
607 if (killpg(clientpid, SIGHUP) < 0 && errno != ESRCH)
608 Error("can't send HUP to process group %d", clientpid);
614 if (killpg(serverpid, SIGTERM) < 0) {
617 Fatal("can't kill X server");
620 if (!processTimeout(10, "X server to shut down"))
623 Errorx("X server slow to shut down, sending KILL signal");
625 if (killpg(serverpid, SIGKILL) < 0) {
628 Error("can't SIGKILL X server");
631 if (processTimeout(3, "server to die"))
632 Fatalx("X server refuses to die");
636 set_environment(void)
638 if (setenv("DISPLAY", displayNum, TRUE) == -1)
639 Fatal("unable to set DISPLAY");
643 verror(const char *fmt, va_list ap)
645 fprintf(stderr, "%s: ", program);
646 vfprintf(stderr, fmt, ap);
647 fprintf(stderr, ": %s\n", strerror(errno));
651 verrorx(const char *fmt, va_list ap)
653 fprintf(stderr, "%s: ", program);
654 vfprintf(stderr, fmt, ap);
655 fprintf(stderr, "\n");
659 Fatal(const char *fmt, ...)
669 Fatalx(const char *fmt, ...)
679 Error(const char *fmt, ...)
688 Errorx(const char *fmt, ...)