1a73027baSmrg/*
2a73027baSmrg
3a73027baSmrgCopyright 1986, 1998  The Open Group
4a73027baSmrg
5a73027baSmrgPermission to use, copy, modify, distribute, and sell this software and its
6a73027baSmrgdocumentation for any purpose is hereby granted without fee, provided that
7a73027baSmrgthe above copyright notice appear in all copies and that both that
8a73027baSmrgcopyright notice and this permission notice appear in supporting
9a73027baSmrgdocumentation.
10a73027baSmrg
11a73027baSmrgThe above copyright notice and this permission notice shall be included in
12a73027baSmrgall copies or substantial portions of the Software.
13a73027baSmrg
14a73027baSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15a73027baSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16a73027baSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17a73027baSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18a73027baSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19a73027baSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20a73027baSmrg
21a73027baSmrgExcept as contained in this notice, the name of The Open Group shall not be
22a73027baSmrgused in advertising or otherwise to promote the sale, use or other dealings
23a73027baSmrgin this Software without prior written authorization from The Open Group.
24a73027baSmrg
25a73027baSmrg*/
26a73027baSmrg
27a73027baSmrg#ifdef HAVE_CONFIG_H
28a73027baSmrg# include "config.h"
29a73027baSmrg#endif
30a73027baSmrg
31a73027baSmrg#include <X11/Xlib.h>
32a73027baSmrg#include <X11/Xos.h>
33a73027baSmrg#include <X11/Xatom.h>
34ac57ed83Smrg#include <X11/Xfuncproto.h>
35a73027baSmrg#include <stdio.h>
36a73027baSmrg#include <ctype.h>
37ac57ed83Smrg#include <stddef.h>
38a73027baSmrg#include <stdint.h>
39a73027baSmrg
40a73027baSmrg#include <signal.h>
41a73027baSmrg#include <sys/wait.h>
42a73027baSmrg#include <errno.h>
43a73027baSmrg#include <setjmp.h>
44a73027baSmrg#include <stdarg.h>
45a73027baSmrg
4672e81212Smrg#ifdef __APPLE__
4772e81212Smrg#include <AvailabilityMacros.h>
48bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
4972e81212Smrg#include <vproc.h>
5072e81212Smrg#endif
5172e81212Smrg#endif
5272e81212Smrg
5329004570Smrg/* For PRIO_PROCESS and setpriority() */
5429004570Smrg#include <sys/time.h>
5529004570Smrg#include <sys/resource.h>
56a73027baSmrg
57a73027baSmrg#include <stdlib.h>
58a73027baSmrg
59a73027baSmrg#ifndef SHELL
60a73027baSmrg#define SHELL "sh"
61a73027baSmrg#endif
62a73027baSmrg
63ac57ed83Smrgstatic const char *bindir = BINDIR;
64ac57ed83Smrgstatic const char * const server_names[] = {
65a73027baSmrg#ifdef __APPLE__
66a73027baSmrg    "Xquartz     Mac OSX Quartz displays.",
67bf4a254eSmrg#else
68bf4a254eSmrg# ifdef __CYGWIN__
69bf4a254eSmrg    "XWin        X Server for the Cygwin environment on Microsoft Windows",
70bf4a254eSmrg# else
71bf4a254eSmrg    "Xorg        Common X server for most displays",
72bf4a254eSmrg# endif
73a73027baSmrg#endif
74a73027baSmrg    "Xvfb        Virtual frame buffer",
75a73027baSmrg    "Xfake       kdrive-based virtual frame buffer",
76a73027baSmrg    "Xnest       X server nested in a window on another X server",
77a73027baSmrg    "Xephyr      kdrive-based nested X server",
78bf4a254eSmrg    "Xvnc        X server accessed over VNC's RFB protocol",
79a73027baSmrg    NULL};
80a73027baSmrg
81a73027baSmrg#ifndef XINITRC
82a73027baSmrg#define XINITRC ".xinitrc"
83a73027baSmrg#endif
84ac57ed83Smrgstatic char xinitrcbuf[256];
85a73027baSmrg
86a73027baSmrg#ifndef XSERVERRC
87a73027baSmrg#define XSERVERRC ".xserverrc"
88a73027baSmrg#endif
89ac57ed83Smrgstatic char xserverrcbuf[256];
90a73027baSmrg
9129004570Smrg#define TRUE 1
9229004570Smrg#define FALSE 0
93a73027baSmrg
94a73027baSmrgstatic char *default_server = "X";
9529004570Smrgstatic char *default_display = ":0";        /* choose most efficient */
96a73027baSmrgstatic char *default_client[] = {"xterm", "-geometry", "+1+1", "-n", "login", NULL};
97a73027baSmrgstatic char *serverargv[100];
98a73027baSmrgstatic char *clientargv[100];
9929004570Smrgstatic char **server = serverargv + 2;        /* make sure room for sh .xserverrc args */
10029004570Smrgstatic char **client = clientargv + 2;        /* make sure room for sh .xinitrc args */
101a73027baSmrgstatic char *displayNum = NULL;
102a73027baSmrgstatic char *program = NULL;
10329004570Smrgstatic Display *xd = NULL;            /* server connection */
104ac57ed83Smrgstatic int status;
105ac57ed83Smrgstatic pid_t serverpid = -1;
106ac57ed83Smrgstatic pid_t clientpid = -1;
107ac57ed83Smrgstatic volatile int gotSignal = 0;
108a73027baSmrg
10929004570Smrgstatic void Execute(char **vec);
11029004570Smrgstatic Bool waitforserver(void);
11136ffeb23Smrgstatic Bool processTimeout(int timeout, const char *string);
11236ffeb23Smrgstatic pid_t startServer(char *server[]);
11336ffeb23Smrgstatic pid_t startClient(char *client[]);
11429004570Smrgstatic int ignorexio(Display *dpy);
11529004570Smrgstatic void shutdown(void);
11629004570Smrgstatic void set_environment(void);
11729004570Smrg
11836ffeb23Smrgstatic void Fatal(const char *fmt, ...) _X_ATTRIBUTE_PRINTF(1,2) _X_NORETURN;
11936ffeb23Smrgstatic void Error(const char *fmt, ...) _X_ATTRIBUTE_PRINTF(1,2);
12036ffeb23Smrgstatic void Fatalx(const char *fmt, ...) _X_ATTRIBUTE_PRINTF(1,2) _X_NORETURN;
12136ffeb23Smrgstatic void Errorx(const char *fmt, ...) _X_ATTRIBUTE_PRINTF(1,2);
122a73027baSmrg
12329004570Smrgstatic void
12429004570SmrgsigCatch(int sig)
125a73027baSmrg{
12629004570Smrg    /* On system with POSIX signals, just interrupt the system call */
12729004570Smrg    gotSignal = sig;
128a73027baSmrg}
129a73027baSmrg
13029004570Smrgstatic void
131ac57ed83SmrgsigIgnore(_X_UNUSED int sig)
132a73027baSmrg{
133a73027baSmrg}
134a73027baSmrg
13529004570Smrgstatic void
13629004570SmrgExecute(char **vec)		/* has room from up above */
137a73027baSmrg{
13829004570Smrg    execvp(vec[0], vec);
13929004570Smrg    if (access(vec[0], R_OK) == 0) {
140a73027baSmrg	vec--;				/* back it up to stuff shell in */
141a73027baSmrg	vec[0] = SHELL;
14229004570Smrg	execvp(vec[0], vec);
143a73027baSmrg    }
144a73027baSmrg    return;
145a73027baSmrg}
146a73027baSmrg
147a73027baSmrgint
148a73027baSmrgmain(int argc, char *argv[])
149a73027baSmrg{
15029004570Smrg    register char **sptr = server;
15129004570Smrg    register char **cptr = client;
15229004570Smrg    register char **ptr;
15336ffeb23Smrg    pid_t pid;
15429004570Smrg    int client_given = 0, server_given = 0;
155ac57ed83Smrg    ptrdiff_t start_of_client_args, start_of_server_args;
15629004570Smrg    struct sigaction sa, si;
15772e81212Smrg#ifdef __APPLE__
158bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
15929004570Smrg    vproc_transaction_t vt;
16072e81212Smrg#endif
16172e81212Smrg#endif
162a73027baSmrg
16329004570Smrg    program = *argv++;
16429004570Smrg    argc--;
16529004570Smrg    /*
16629004570Smrg     * copy the client args.
16729004570Smrg     */
16829004570Smrg    if (argc == 0 ||
16929004570Smrg        (**argv != '/' && **argv != '.')) {
17029004570Smrg        for (ptr = default_client; *ptr; )
17129004570Smrg            *cptr++ = *ptr++;
17229004570Smrg    } else {
17329004570Smrg        client_given = 1;
17429004570Smrg    }
17529004570Smrg    start_of_client_args = (cptr - client);
17629004570Smrg    while (argc && strcmp(*argv, "--")) {
1775c47cad4Smrg        if (cptr > clientargv + sizeof(clientargv) / sizeof(*clientargv) - 2)
1785c47cad4Smrg            Fatalx("too many client arguments");
17929004570Smrg        *cptr++ = *argv++;
18029004570Smrg        argc--;
18129004570Smrg    }
18229004570Smrg    *cptr = NULL;
18329004570Smrg    if (argc) {
18429004570Smrg        argv++;
18529004570Smrg        argc--;
18629004570Smrg    }
18729004570Smrg
18829004570Smrg    /*
18929004570Smrg     * Copy the server args.
19029004570Smrg     */
19129004570Smrg    if (argc == 0 ||
19229004570Smrg        (**argv != '/' && **argv != '.')) {
19329004570Smrg        *sptr++ = default_server;
19429004570Smrg    } else {
19529004570Smrg        server_given = 1;
19629004570Smrg        *sptr++ = *argv++;
19729004570Smrg        argc--;
19829004570Smrg    }
19929004570Smrg    if (argc > 0 && (argv[0][0] == ':' && isdigit(argv[0][1])))
20029004570Smrg        displayNum = *argv;
20129004570Smrg    else
20229004570Smrg        displayNum = *sptr++ = default_display;
20329004570Smrg
20429004570Smrg    start_of_server_args = (sptr - server);
20529004570Smrg    while (--argc >= 0) {
2065c47cad4Smrg        if (sptr > serverargv + sizeof(serverargv) / sizeof(*serverargv) - 2)
2075c47cad4Smrg            Fatalx("too many server arguments");
20829004570Smrg        *sptr++ = *argv++;
20929004570Smrg    }
21029004570Smrg    *sptr = NULL;
21129004570Smrg
21229004570Smrg    /*
21329004570Smrg     * if no client arguments given, check for a startup file and copy
21429004570Smrg     * that into the argument list
21529004570Smrg     */
21629004570Smrg    if (!client_given) {
21729004570Smrg        char *cp;
21829004570Smrg        Bool required = False;
21929004570Smrg
22029004570Smrg        xinitrcbuf[0] = '\0';
22129004570Smrg        if ((cp = getenv("XINITRC")) != NULL) {
22229004570Smrg            snprintf(xinitrcbuf, sizeof(xinitrcbuf), "%s", cp);
22329004570Smrg            required = True;
22429004570Smrg        } else if ((cp = getenv("HOME")) != NULL) {
22529004570Smrg            snprintf(xinitrcbuf, sizeof(xinitrcbuf),
22629004570Smrg                     "%s/%s", cp, XINITRC);
22729004570Smrg        }
22829004570Smrg        if (xinitrcbuf[0]) {
22929004570Smrg            if (access(xinitrcbuf, F_OK) == 0) {
23029004570Smrg                client += start_of_client_args - 1;
23129004570Smrg                client[0] = xinitrcbuf;
23229004570Smrg            } else if (required) {
23329004570Smrg                Error("warning, no client init file \"%s\"", xinitrcbuf);
23429004570Smrg            }
23529004570Smrg        }
23629004570Smrg    }
23729004570Smrg
23829004570Smrg    /*
23929004570Smrg     * if no server arguments given, check for a startup file and copy
24029004570Smrg     * that into the argument list
24129004570Smrg     */
24229004570Smrg    if (!server_given) {
24329004570Smrg        char *cp;
24429004570Smrg        Bool required = False;
24529004570Smrg
24629004570Smrg        xserverrcbuf[0] = '\0';
24729004570Smrg        if ((cp = getenv("XSERVERRC")) != NULL) {
24829004570Smrg            snprintf(xserverrcbuf, sizeof(xserverrcbuf), "%s", cp);
24929004570Smrg            required = True;
25029004570Smrg        } else if ((cp = getenv("HOME")) != NULL) {
25129004570Smrg            snprintf(xserverrcbuf, sizeof(xserverrcbuf),
25229004570Smrg                     "%s/%s", cp, XSERVERRC);
25329004570Smrg        }
25429004570Smrg        if (xserverrcbuf[0]) {
25529004570Smrg            if (access(xserverrcbuf, F_OK) == 0) {
25629004570Smrg                server += start_of_server_args - 1;
25729004570Smrg                server[0] = xserverrcbuf;
25829004570Smrg            } else if (required) {
25929004570Smrg                Error("warning, no server init file \"%s\"", xserverrcbuf);
26029004570Smrg            }
26129004570Smrg        }
26229004570Smrg    }
26329004570Smrg
26429004570Smrg    /*
26529004570Smrg     * Start the server and client.
26629004570Smrg     */
26729004570Smrg
26829004570Smrg    /* Let those signal interrupt the wait() call in the main loop */
26929004570Smrg    memset(&sa, 0, sizeof sa);
27029004570Smrg    sa.sa_handler = sigCatch;
27129004570Smrg    sigemptyset(&sa.sa_mask);
27229004570Smrg    sa.sa_flags = 0;    /* do not set SA_RESTART */
27329004570Smrg
27429004570Smrg    sigaction(SIGTERM, &sa, NULL);
27529004570Smrg    sigaction(SIGQUIT, &sa, NULL);
27629004570Smrg    sigaction(SIGINT, &sa, NULL);
27729004570Smrg    sigaction(SIGHUP, &sa, NULL);
27829004570Smrg    sigaction(SIGPIPE, &sa, NULL);
279a73027baSmrg
28029004570Smrg    memset(&si, 0, sizeof(si));
28129004570Smrg    si.sa_handler = sigIgnore;
28229004570Smrg    sigemptyset(&si.sa_mask);
28329004570Smrg    si.sa_flags = SA_RESTART;
28429004570Smrg
28529004570Smrg    sigaction(SIGALRM, &si, NULL);
28629004570Smrg    sigaction(SIGUSR1, &si, NULL);
2877aed6334Smrg    sigaction(SIGCHLD, &si, NULL);
28872e81212Smrg
28972e81212Smrg#ifdef __APPLE__
290bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
29129004570Smrg    vt = vproc_transaction_begin(NULL);
29272e81212Smrg#endif
29372e81212Smrg#endif
29472e81212Smrg
29529004570Smrg    if (startServer(server) > 0
29629004570Smrg        && startClient(client) > 0) {
29729004570Smrg        pid = -1;
29829004570Smrg        while (pid != clientpid && pid != serverpid
29929004570Smrg               && gotSignal == 0
30029004570Smrg            )
30129004570Smrg            pid = wait(NULL);
30229004570Smrg    }
30372e81212Smrg
30472e81212Smrg#ifdef __APPLE__
305bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
30629004570Smrg    vproc_transaction_end(NULL, vt);
30772e81212Smrg#endif
30872e81212Smrg#endif
30972e81212Smrg
31029004570Smrg    signal(SIGTERM, SIG_IGN);
31129004570Smrg    signal(SIGQUIT, SIG_IGN);
31229004570Smrg    signal(SIGINT, SIG_IGN);
31329004570Smrg    signal(SIGHUP, SIG_IGN);
31429004570Smrg    signal(SIGPIPE, SIG_IGN);
315a73027baSmrg
31629004570Smrg    shutdown();
317a73027baSmrg
31829004570Smrg    if (serverpid < 0)
31929004570Smrg        Fatalx("server error");
32029004570Smrg    if (clientpid < 0)
32129004570Smrg        Fatalx("client error");
32229004570Smrg    exit(EXIT_SUCCESS);
323a73027baSmrg}
324a73027baSmrg
325a73027baSmrg
326a73027baSmrg/*
32729004570Smrg *    waitforserver - wait for X server to start up
328a73027baSmrg */
329a73027baSmrgstatic Bool
330a73027baSmrgwaitforserver(void)
331a73027baSmrg{
33229004570Smrg    int    ncycles     = 120;        /* # of cycles to wait */
33329004570Smrg    int    cycles;            /* Wait cycle count */
334a73027baSmrg
33572e81212Smrg#ifdef __APPLE__
33629004570Smrg    /* For Apple, we don't get signaled by the server when it's ready, so we just
33729004570Smrg     * want to sleep now since we're going to sleep later anyways and this allows us
33829004570Smrg     * to avoid the awkard, "why is there an error message in the log" questions
33929004570Smrg     * from users.
34029004570Smrg     */
34129004570Smrg
34229004570Smrg    sleep(2);
34329004570Smrg#endif
34429004570Smrg
34529004570Smrg    for (cycles = 0; cycles < ncycles; cycles++) {
34629004570Smrg        if ((xd = XOpenDisplay(displayNum))) {
34729004570Smrg            return(TRUE);
34829004570Smrg        }
34929004570Smrg        else {
35029004570Smrg            if (!processTimeout(1, "X server to begin accepting connections"))
35129004570Smrg              break;
35229004570Smrg        }
35329004570Smrg    }
35472e81212Smrg
35529004570Smrg    Errorx("giving up");
35672e81212Smrg
35729004570Smrg    return(FALSE);
358a73027baSmrg}
359a73027baSmrg
360a73027baSmrg/*
361a73027baSmrg * return TRUE if we timeout waiting for pid to exit, FALSE otherwise.
362a73027baSmrg */
363a73027baSmrgstatic Bool
36436ffeb23SmrgprocessTimeout(int timeout, const char *string)
365a73027baSmrg{
36636ffeb23Smrg    int    i = 0;
36736ffeb23Smrg    pid_t  pidfound = -1;
36836ffeb23Smrg    static const char    *laststring;
36929004570Smrg
37029004570Smrg    for (;;) {
37129004570Smrg        if ((pidfound = waitpid(serverpid, &status, WNOHANG)) == serverpid)
37229004570Smrg            break;
37329004570Smrg        if (timeout) {
37429004570Smrg            if (i == 0 && string != laststring)
37529004570Smrg                fprintf(stderr, "\r\nwaiting for %s ", string);
37629004570Smrg            else
37729004570Smrg                fprintf(stderr, ".");
37829004570Smrg            fflush(stderr);
37929004570Smrg            sleep(1);
38011f750edSmrg        }
38129004570Smrg        if (++i > timeout)
38229004570Smrg            break;
38329004570Smrg    }
38429004570Smrg    if (i > 0) fputc('\n', stderr);     /* tidy up after message */
38529004570Smrg    laststring = string;
38629004570Smrg    return (serverpid != pidfound);
387a73027baSmrg}
388a73027baSmrg
38936ffeb23Smrgstatic pid_t
39041667ceaSmrgstartServer(char *server_argv[])
391a73027baSmrg{
39229004570Smrg    sigset_t mask, old;
39329004570Smrg    const char * const *cpp;
394a73027baSmrg
39529004570Smrg    sigemptyset(&mask);
39629004570Smrg    sigaddset(&mask, SIGUSR1);
39729004570Smrg    sigprocmask(SIG_BLOCK, &mask, &old);
398a73027baSmrg
39929004570Smrg    serverpid = fork();
400a73027baSmrg
40129004570Smrg    switch(serverpid) {
40229004570Smrg    case 0:
40329004570Smrg        /* Unblock */
40429004570Smrg        sigprocmask(SIG_SETMASK, &old, NULL);
405a73027baSmrg
40629004570Smrg        /*
40729004570Smrg         * don't hang on read/write to control tty
40829004570Smrg         */
40929004570Smrg        signal(SIGTTIN, SIG_IGN);
41029004570Smrg        signal(SIGTTOU, SIG_IGN);
41129004570Smrg        /*
41229004570Smrg         * ignore SIGUSR1 in child.  The server
41329004570Smrg         * will notice this and send SIGUSR1 back
41429004570Smrg         * at xinit when ready to accept connections
41529004570Smrg         */
41629004570Smrg        signal(SIGUSR1, SIG_IGN);
41729004570Smrg        /*
41829004570Smrg         * prevent server from getting sighup from vhangup()
41929004570Smrg         * if client is xterm -L
42029004570Smrg         */
42129004570Smrg        setpgid(0,getpid());
42241667ceaSmrg        Execute(server_argv);
42329004570Smrg
42441667ceaSmrg        Error("unable to run server \"%s\"", server_argv[0]);
42529004570Smrg
42629004570Smrg        fprintf(stderr, "Use the -- option, or make sure that %s is in your path and\n", bindir);
42741667ceaSmrg        fprintf(stderr, "that \"%s\" is a program or a link to the right type of server\n", server_argv[0]);
42829004570Smrg        fprintf(stderr, "for your display.  Possible server names include:\n\n");
42929004570Smrg        for (cpp = server_names; *cpp; cpp++)
43029004570Smrg            fprintf(stderr, "    %s\n", *cpp);
43129004570Smrg        fprintf(stderr, "\n");
43229004570Smrg
43329004570Smrg        exit(EXIT_FAILURE);
43429004570Smrg
43529004570Smrg        break;
43629004570Smrg    case -1:
43729004570Smrg        break;
43829004570Smrg    default:
43929004570Smrg        /*
44029004570Smrg         * don't nice server
44129004570Smrg         */
44229004570Smrg        setpriority(PRIO_PROCESS, serverpid, -1);
44329004570Smrg
44429004570Smrg        errno = 0;
44529004570Smrg        if(! processTimeout(0, "")) {
44629004570Smrg            serverpid = -1;
44729004570Smrg            break;
44829004570Smrg        }
44929004570Smrg        /*
45029004570Smrg         * kludge to avoid race with TCP, giving server time to
45129004570Smrg         * set his socket options before we try to open it,
45229004570Smrg         * either use the 15 second timeout, or await SIGUSR1.
45329004570Smrg         *
45429004570Smrg         * If your machine is substantially slower than 15 seconds,
45529004570Smrg         * you can easily adjust this value.
45629004570Smrg         */
45729004570Smrg        alarm(15);
45829004570Smrg
45929004570Smrg        sigsuspend(&old);
46029004570Smrg        alarm(0);
46129004570Smrg        sigprocmask(SIG_SETMASK, &old, NULL);
46229004570Smrg
46329004570Smrg        if (waitforserver() == 0) {
46429004570Smrg            Error("unable to connect to X server");
46529004570Smrg            shutdown();
46629004570Smrg            serverpid = -1;
46729004570Smrg        }
46829004570Smrg        break;
46929004570Smrg    }
470a73027baSmrg
47129004570Smrg    return(serverpid);
472a73027baSmrg}
473a73027baSmrg
474a73027baSmrgstatic void
475a73027baSmrgsetWindowPath(void)
476a73027baSmrg{
47729004570Smrg    /* setting WINDOWPATH for clients */
47829004570Smrg    Atom prop;
47929004570Smrg    Atom actualtype;
48029004570Smrg    int actualformat;
48129004570Smrg    unsigned long nitems;
48229004570Smrg    unsigned long bytes_after;
48329004570Smrg    unsigned char *buf;
48429004570Smrg    const char *windowpath;
48529004570Smrg    char *newwindowpath;
48629004570Smrg    unsigned long num;
487ac57ed83Smrg#ifndef HAVE_ASPRINTF
48829004570Smrg    char nums[10];
48929004570Smrg    int numn;
49029004570Smrg    size_t len;
491ac57ed83Smrg#endif
492ac57ed83Smrg
49329004570Smrg    prop = XInternAtom(xd, "XFree86_VT", False);
49429004570Smrg    if (prop == None) {
49529004570Smrg        Errorx("Unable to intern XFree86_VT atom");
49629004570Smrg        return;
49729004570Smrg    }
49829004570Smrg    if (XGetWindowProperty(xd, DefaultRootWindow(xd), prop, 0, 1,
49929004570Smrg        False, AnyPropertyType, &actualtype, &actualformat,
50029004570Smrg        &nitems, &bytes_after, &buf)) {
50129004570Smrg        Errorx("No XFree86_VT property detected on X server, WINDOWPATH won't be set");
50229004570Smrg        return;
50329004570Smrg    }
50429004570Smrg    if (nitems != 1) {
50529004570Smrg        Errorx("XFree86_VT property unexpectedly has %lu items instead of 1", nitems);
50629004570Smrg        XFree(buf);
50729004570Smrg        return;
50829004570Smrg    }
50929004570Smrg    switch (actualtype) {
51029004570Smrg    case XA_CARDINAL:
51129004570Smrg    case XA_INTEGER:
51229004570Smrg    case XA_WINDOW:
51329004570Smrg        switch (actualformat) {
51429004570Smrg        case  8:
51529004570Smrg            num = (*(uint8_t  *)(void *)buf);
51629004570Smrg            break;
51729004570Smrg        case 16:
51829004570Smrg            num = (*(uint16_t *)(void *)buf);
51929004570Smrg            break;
52029004570Smrg        case 32:
52129004570Smrg            num = (*(uint32_t *)(void *)buf);
52229004570Smrg            break;
52329004570Smrg        default:
52429004570Smrg            Errorx("XFree86_VT property has unexpected format %d", actualformat);
52529004570Smrg            XFree(buf);
52629004570Smrg            return;
52729004570Smrg        }
52829004570Smrg        break;
52929004570Smrg    default:
53029004570Smrg        Errorx("XFree86_VT property has unexpected type %lx", actualtype);
53129004570Smrg        XFree(buf);
53229004570Smrg        return;
53329004570Smrg    }
53429004570Smrg    XFree(buf);
53529004570Smrg    windowpath = getenv("WINDOWPATH");
536ac57ed83Smrg#ifdef HAVE_ASPRINTF
537ac57ed83Smrg    if (!windowpath) {
538ac57ed83Smrg        if (asprintf(&newwindowpath, "%lu", num) < 0)
539ac57ed83Smrg            return;
540ac57ed83Smrg    } else {
541ac57ed83Smrg        if (asprintf(&newwindowpath, "%s:%lu", windowpath, num) < 0)
542ac57ed83Smrg            return;
543ac57ed83Smrg    }
544ac57ed83Smrg#else
54529004570Smrg    numn = snprintf(nums, sizeof(nums), "%lu", num);
54629004570Smrg    if (!windowpath) {
54729004570Smrg        len = numn + 1;
54829004570Smrg        newwindowpath = malloc(len);
54929004570Smrg        if (newwindowpath == NULL)
55029004570Smrg            return;
55129004570Smrg        snprintf(newwindowpath, len, "%s", nums);
55229004570Smrg    } else {
55329004570Smrg        len = strlen(windowpath) + 1 + numn + 1;
55429004570Smrg        newwindowpath = malloc(len);
55529004570Smrg        if (newwindowpath == NULL)
55629004570Smrg            return;
55729004570Smrg        snprintf(newwindowpath, len, "%s:%s",
55829004570Smrg                 windowpath, nums);
55929004570Smrg    }
560ac57ed83Smrg#endif /* HAVE_ASPRINTF */
56129004570Smrg    if (setenv("WINDOWPATH", newwindowpath, TRUE) == -1)
56229004570Smrg        Error("unable to set WINDOWPATH");
56329004570Smrg
56429004570Smrg
56529004570Smrg    free(newwindowpath);
566a73027baSmrg}
567a73027baSmrg
56836ffeb23Smrgstatic pid_t
56941667ceaSmrgstartClient(char *client_argv[])
570a73027baSmrg{
57129004570Smrg    clientpid = fork();
57229004570Smrg    if (clientpid == 0) {
57329004570Smrg        set_environment();
57429004570Smrg        setWindowPath();
57529004570Smrg
57629004570Smrg        if (setuid(getuid()) == -1) {
57729004570Smrg            Error("cannot change uid");
57829004570Smrg            _exit(EXIT_FAILURE);
57929004570Smrg        }
58029004570Smrg        setpgid(0, getpid());
58141667ceaSmrg        Execute(client_argv);
58241667ceaSmrg        Error("Unable to run program \"%s\"", client_argv[0]);
58329004570Smrg
58429004570Smrg        fprintf(stderr, "Specify a program on the command line or make sure that %s\n", bindir);
58529004570Smrg        fprintf(stderr, "is in your path.\n\n");
58629004570Smrg
58729004570Smrg        _exit(EXIT_FAILURE);
58829004570Smrg    } else {
58929004570Smrg        return clientpid;
59029004570Smrg    }
591a73027baSmrg}
592a73027baSmrg
593a73027baSmrgstatic jmp_buf close_env;
594a73027baSmrg
59529004570Smrgstatic int
596ac57ed83Smrgignorexio(_X_UNUSED Display *dpy)
597a73027baSmrg{
59829004570Smrg    Errorx("connection to X server lost");
59929004570Smrg    longjmp(close_env, 1);
600a73027baSmrg    /*NOTREACHED*/
601a73027baSmrg    return 0;
602a73027baSmrg}
603a73027baSmrg
60429004570Smrgstatic void
605a73027baSmrgshutdown(void)
606a73027baSmrg{
60729004570Smrg    /* have kept display opened, so close it now */
60829004570Smrg    if (clientpid > 0) {
60929004570Smrg        XSetIOErrorHandler(ignorexio);
61029004570Smrg        if (! setjmp(close_env)) {
61129004570Smrg            XCloseDisplay(xd);
61229004570Smrg        }
61329004570Smrg
61429004570Smrg        /* HUP all local clients to allow them to clean up */
61529004570Smrg        if (killpg(clientpid, SIGHUP) < 0 && errno != ESRCH)
61629004570Smrg            Error("can't send HUP to process group %d", clientpid);
61729004570Smrg    }
618a73027baSmrg
61929004570Smrg    if (serverpid < 0)
62029004570Smrg        return;
621a73027baSmrg
62229004570Smrg    if (killpg(serverpid, SIGTERM) < 0) {
62329004570Smrg        if (errno == ESRCH)
62429004570Smrg            return;
62529004570Smrg        Fatal("can't kill X server");
62629004570Smrg    }
62729004570Smrg
62829004570Smrg    if (!processTimeout(10, "X server to shut down"))
62929004570Smrg        return;
630a73027baSmrg
63111f750edSmrg    Errorx("X server slow to shut down, sending KILL signal");
63229004570Smrg
63329004570Smrg    if (killpg(serverpid, SIGKILL) < 0) {
63429004570Smrg        if (errno == ESRCH)
63529004570Smrg            return;
63629004570Smrg        Error("can't SIGKILL X server");
63729004570Smrg    }
63829004570Smrg
63929004570Smrg    if (processTimeout(3, "server to die"))
64029004570Smrg        Fatalx("X server refuses to die");
64136ffeb23Smrg#ifdef __sun
64236ffeb23Smrg    else {
64336ffeb23Smrg        /* Restore keyboard mode. */
64436ffeb23Smrg        serverpid = fork();
64536ffeb23Smrg        switch (serverpid) {
64636ffeb23Smrg        case 0:
64736ffeb23Smrg            execlp ("kbd_mode", "kbd_mode", "-a", NULL);
64836ffeb23Smrg            Fatal("Unable to run program \"%s\"", "kbd_mode");
64936ffeb23Smrg            break;
65036ffeb23Smrg
651d712a854Smrg        case -1:
65236ffeb23Smrg            Error("fork failed");
65336ffeb23Smrg            break;
65436ffeb23Smrg
65536ffeb23Smrg        default:
65636ffeb23Smrg            fprintf (stderr, "\r\nRestoring keyboard mode\r\n");
65736ffeb23Smrg            processTimeout(1, "kbd_mode");
65836ffeb23Smrg        }
65936ffeb23Smrg    }
66036ffeb23Smrg#endif
66129004570Smrg}
66229004570Smrg
66329004570Smrgstatic void
664a73027baSmrgset_environment(void)
665a73027baSmrg{
66629004570Smrg    if (setenv("DISPLAY", displayNum, TRUE) == -1)
66729004570Smrg        Fatal("unable to set DISPLAY");
66829004570Smrg}
669a73027baSmrg
67036ffeb23Smrgstatic void _X_ATTRIBUTE_PRINTF(1,0)
67129004570Smrgverror(const char *fmt, va_list ap)
67229004570Smrg{
67329004570Smrg    fprintf(stderr, "%s: ", program);
67429004570Smrg    vfprintf(stderr, fmt, ap);
67529004570Smrg    fprintf(stderr, ": %s\n", strerror(errno));
67629004570Smrg}
67729004570Smrg
67836ffeb23Smrgstatic void _X_ATTRIBUTE_PRINTF(1,0)
67929004570Smrgverrorx(const char *fmt, va_list ap)
68029004570Smrg{
68129004570Smrg    fprintf(stderr, "%s: ", program);
68229004570Smrg    vfprintf(stderr, fmt, ap);
68329004570Smrg    fprintf(stderr, "\n");
68429004570Smrg}
68529004570Smrg
68629004570Smrgstatic void
68729004570SmrgFatal(const char *fmt, ...)
68829004570Smrg{
68929004570Smrg    va_list ap;
69029004570Smrg    va_start(ap, fmt);
69129004570Smrg    verror(fmt, ap);
69229004570Smrg    va_end(ap);
69329004570Smrg    exit(EXIT_FAILURE);
69429004570Smrg}
69529004570Smrg
69629004570Smrgstatic void
69729004570SmrgFatalx(const char *fmt, ...)
69829004570Smrg{
69929004570Smrg    va_list ap;
70029004570Smrg    va_start(ap, fmt);
70129004570Smrg    verrorx(fmt, ap);
70229004570Smrg    va_end(ap);
70329004570Smrg    exit(EXIT_FAILURE);
704a73027baSmrg}
705a73027baSmrg
706a73027baSmrgstatic void
70729004570SmrgError(const char *fmt, ...)
708a73027baSmrg{
70929004570Smrg    va_list ap;
71029004570Smrg    va_start(ap, fmt);
71129004570Smrg    verror(fmt, ap);
71229004570Smrg    va_end(ap);
713a73027baSmrg}
714a73027baSmrg
715a73027baSmrgstatic void
71629004570SmrgErrorx(const char *fmt, ...)
717a73027baSmrg{
71829004570Smrg    va_list ap;
71929004570Smrg    va_start(ap, fmt);
72029004570Smrg    verrorx(fmt, ap);
72129004570Smrg    va_end(ap);
722a73027baSmrg}
723