xinit.c revision 41667cea
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>
34a73027baSmrg#include <stdio.h>
35a73027baSmrg#include <ctype.h>
36a73027baSmrg#include <stdint.h>
37a73027baSmrg
38a73027baSmrg#include <signal.h>
39a73027baSmrg#include <sys/wait.h>
40a73027baSmrg#include <errno.h>
41a73027baSmrg#include <setjmp.h>
42a73027baSmrg#include <stdarg.h>
43a73027baSmrg
4472e81212Smrg#ifdef __APPLE__
4572e81212Smrg#include <AvailabilityMacros.h>
46bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
4772e81212Smrg#include <vproc.h>
4872e81212Smrg#endif
4972e81212Smrg#endif
5072e81212Smrg
5129004570Smrg/* For PRIO_PROCESS and setpriority() */
5229004570Smrg#include <sys/time.h>
5329004570Smrg#include <sys/resource.h>
54a73027baSmrg
55a73027baSmrg#include <stdlib.h>
56a73027baSmrg
57a73027baSmrg#ifndef SHELL
58a73027baSmrg#define SHELL "sh"
59a73027baSmrg#endif
60a73027baSmrg
61a73027baSmrgconst char *bindir = BINDIR;
62a73027baSmrgconst char * const server_names[] = {
63a73027baSmrg#ifdef __APPLE__
64a73027baSmrg    "Xquartz     Mac OSX Quartz displays.",
65bf4a254eSmrg#else
66bf4a254eSmrg# ifdef __CYGWIN__
67bf4a254eSmrg    "XWin        X Server for the Cygwin environment on Microsoft Windows",
68bf4a254eSmrg# else
69bf4a254eSmrg    "Xorg        Common X server for most displays",
70bf4a254eSmrg# endif
71a73027baSmrg#endif
72a73027baSmrg    "Xvfb        Virtual frame buffer",
73a73027baSmrg    "Xfake       kdrive-based virtual frame buffer",
74a73027baSmrg    "Xnest       X server nested in a window on another X server",
75a73027baSmrg    "Xephyr      kdrive-based nested X server",
76bf4a254eSmrg    "Xvnc        X server accessed over VNC's RFB protocol",
77bf4a254eSmrg    "Xdmx        Distributed Multi-head X server",
78a73027baSmrg    NULL};
79a73027baSmrg
80a73027baSmrg#ifndef XINITRC
81a73027baSmrg#define XINITRC ".xinitrc"
82a73027baSmrg#endif
83a73027baSmrgchar xinitrcbuf[256];
84a73027baSmrg
85a73027baSmrg#ifndef XSERVERRC
86a73027baSmrg#define XSERVERRC ".xserverrc"
87a73027baSmrg#endif
88a73027baSmrgchar xserverrcbuf[256];
89a73027baSmrg
9029004570Smrg#define TRUE 1
9129004570Smrg#define FALSE 0
92a73027baSmrg
93a73027baSmrgstatic char *default_server = "X";
9429004570Smrgstatic char *default_display = ":0";        /* choose most efficient */
95a73027baSmrgstatic char *default_client[] = {"xterm", "-geometry", "+1+1", "-n", "login", NULL};
96a73027baSmrgstatic char *serverargv[100];
97a73027baSmrgstatic char *clientargv[100];
9829004570Smrgstatic char **server = serverargv + 2;        /* make sure room for sh .xserverrc args */
9929004570Smrgstatic char **client = clientargv + 2;        /* make sure room for sh .xinitrc args */
100a73027baSmrgstatic char *displayNum = NULL;
101a73027baSmrgstatic char *program = NULL;
10229004570Smrgstatic Display *xd = NULL;            /* server connection */
103a73027baSmrgint status;
10436ffeb23Smrgpid_t serverpid = -1;
10536ffeb23Smrgpid_t clientpid = -1;
106a73027baSmrgvolatile int gotSignal = 0;
107a73027baSmrg
10829004570Smrgstatic void Execute(char **vec);
10929004570Smrgstatic Bool waitforserver(void);
11036ffeb23Smrgstatic Bool processTimeout(int timeout, const char *string);
11136ffeb23Smrgstatic pid_t startServer(char *server[]);
11236ffeb23Smrgstatic pid_t startClient(char *client[]);
11329004570Smrgstatic int ignorexio(Display *dpy);
11429004570Smrgstatic void shutdown(void);
11529004570Smrgstatic void set_environment(void);
11629004570Smrg
11736ffeb23Smrgstatic void Fatal(const char *fmt, ...) _X_ATTRIBUTE_PRINTF(1,2) _X_NORETURN;
11836ffeb23Smrgstatic void Error(const char *fmt, ...) _X_ATTRIBUTE_PRINTF(1,2);
11936ffeb23Smrgstatic void Fatalx(const char *fmt, ...) _X_ATTRIBUTE_PRINTF(1,2) _X_NORETURN;
12036ffeb23Smrgstatic void Errorx(const char *fmt, ...) _X_ATTRIBUTE_PRINTF(1,2);
121a73027baSmrg
12229004570Smrgstatic void
12329004570SmrgsigCatch(int sig)
124a73027baSmrg{
12529004570Smrg    /* On system with POSIX signals, just interrupt the system call */
12629004570Smrg    gotSignal = sig;
127a73027baSmrg}
128a73027baSmrg
12929004570Smrgstatic void
13029004570SmrgsigIgnore(int sig)
131a73027baSmrg{
132a73027baSmrg}
133a73027baSmrg
13429004570Smrgstatic void
13529004570SmrgExecute(char **vec)		/* has room from up above */
136a73027baSmrg{
13729004570Smrg    execvp(vec[0], vec);
13829004570Smrg    if (access(vec[0], R_OK) == 0) {
139a73027baSmrg	vec--;				/* back it up to stuff shell in */
140a73027baSmrg	vec[0] = SHELL;
14129004570Smrg	execvp(vec[0], vec);
142a73027baSmrg    }
143a73027baSmrg    return;
144a73027baSmrg}
145a73027baSmrg
146a73027baSmrgint
147a73027baSmrgmain(int argc, char *argv[])
148a73027baSmrg{
14929004570Smrg    register char **sptr = server;
15029004570Smrg    register char **cptr = client;
15129004570Smrg    register char **ptr;
15236ffeb23Smrg    pid_t pid;
15329004570Smrg    int client_given = 0, server_given = 0;
15429004570Smrg    int client_args_given = 0, server_args_given = 0;
15529004570Smrg    int 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, "--")) {
17729004570Smrg        client_args_given++;
17829004570Smrg        *cptr++ = *argv++;
17929004570Smrg        argc--;
18029004570Smrg    }
18129004570Smrg    *cptr = NULL;
18229004570Smrg    if (argc) {
18329004570Smrg        argv++;
18429004570Smrg        argc--;
18529004570Smrg    }
18629004570Smrg
18729004570Smrg    /*
18829004570Smrg     * Copy the server args.
18929004570Smrg     */
19029004570Smrg    if (argc == 0 ||
19129004570Smrg        (**argv != '/' && **argv != '.')) {
19229004570Smrg        *sptr++ = default_server;
19329004570Smrg    } else {
19429004570Smrg        server_given = 1;
19529004570Smrg        *sptr++ = *argv++;
19629004570Smrg        argc--;
19729004570Smrg    }
19829004570Smrg    if (argc > 0 && (argv[0][0] == ':' && isdigit(argv[0][1])))
19929004570Smrg        displayNum = *argv;
20029004570Smrg    else
20129004570Smrg        displayNum = *sptr++ = default_display;
20229004570Smrg
20329004570Smrg    start_of_server_args = (sptr - server);
20429004570Smrg    while (--argc >= 0) {
20529004570Smrg        server_args_given++;
20629004570Smrg        *sptr++ = *argv++;
20729004570Smrg    }
20829004570Smrg    *sptr = NULL;
20929004570Smrg
21029004570Smrg    /*
21129004570Smrg     * if no client arguments given, check for a startup file and copy
21229004570Smrg     * that into the argument list
21329004570Smrg     */
21429004570Smrg    if (!client_given) {
21529004570Smrg        char *cp;
21629004570Smrg        Bool required = False;
21729004570Smrg
21829004570Smrg        xinitrcbuf[0] = '\0';
21929004570Smrg        if ((cp = getenv("XINITRC")) != NULL) {
22029004570Smrg            snprintf(xinitrcbuf, sizeof(xinitrcbuf), "%s", cp);
22129004570Smrg            required = True;
22229004570Smrg        } else if ((cp = getenv("HOME")) != NULL) {
22329004570Smrg            snprintf(xinitrcbuf, sizeof(xinitrcbuf),
22429004570Smrg                     "%s/%s", cp, XINITRC);
22529004570Smrg        }
22629004570Smrg        if (xinitrcbuf[0]) {
22729004570Smrg            if (access(xinitrcbuf, F_OK) == 0) {
22829004570Smrg                client += start_of_client_args - 1;
22929004570Smrg                client[0] = xinitrcbuf;
23029004570Smrg            } else if (required) {
23129004570Smrg                Error("warning, no client init file \"%s\"", xinitrcbuf);
23229004570Smrg            }
23329004570Smrg        }
23429004570Smrg    }
23529004570Smrg
23629004570Smrg    /*
23729004570Smrg     * if no server arguments given, check for a startup file and copy
23829004570Smrg     * that into the argument list
23929004570Smrg     */
24029004570Smrg    if (!server_given) {
24129004570Smrg        char *cp;
24229004570Smrg        Bool required = False;
24329004570Smrg
24429004570Smrg        xserverrcbuf[0] = '\0';
24529004570Smrg        if ((cp = getenv("XSERVERRC")) != NULL) {
24629004570Smrg            snprintf(xserverrcbuf, sizeof(xserverrcbuf), "%s", cp);
24729004570Smrg            required = True;
24829004570Smrg        } else if ((cp = getenv("HOME")) != NULL) {
24929004570Smrg            snprintf(xserverrcbuf, sizeof(xserverrcbuf),
25029004570Smrg                     "%s/%s", cp, XSERVERRC);
25129004570Smrg        }
25229004570Smrg        if (xserverrcbuf[0]) {
25329004570Smrg            if (access(xserverrcbuf, F_OK) == 0) {
25429004570Smrg                server += start_of_server_args - 1;
25529004570Smrg                server[0] = xserverrcbuf;
25629004570Smrg            } else if (required) {
25729004570Smrg                Error("warning, no server init file \"%s\"", xserverrcbuf);
25829004570Smrg            }
25929004570Smrg        }
26029004570Smrg    }
26129004570Smrg
26229004570Smrg    /*
26329004570Smrg     * Start the server and client.
26429004570Smrg     */
26529004570Smrg    signal(SIGCHLD, SIG_DFL);    /* Insurance */
26629004570Smrg
26729004570Smrg    /* Let those signal interrupt the wait() call in the main loop */
26829004570Smrg    memset(&sa, 0, sizeof sa);
26929004570Smrg    sa.sa_handler = sigCatch;
27029004570Smrg    sigemptyset(&sa.sa_mask);
27129004570Smrg    sa.sa_flags = 0;    /* do not set SA_RESTART */
27229004570Smrg
27329004570Smrg    sigaction(SIGTERM, &sa, NULL);
27429004570Smrg    sigaction(SIGQUIT, &sa, NULL);
27529004570Smrg    sigaction(SIGINT, &sa, NULL);
27629004570Smrg    sigaction(SIGHUP, &sa, NULL);
27729004570Smrg    sigaction(SIGPIPE, &sa, NULL);
278a73027baSmrg
27929004570Smrg    memset(&si, 0, sizeof(si));
28029004570Smrg    si.sa_handler = sigIgnore;
28129004570Smrg    sigemptyset(&si.sa_mask);
28229004570Smrg    si.sa_flags = SA_RESTART;
28329004570Smrg
28429004570Smrg    sigaction(SIGALRM, &si, NULL);
28529004570Smrg    sigaction(SIGUSR1, &si, NULL);
28672e81212Smrg
28772e81212Smrg#ifdef __APPLE__
288bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
28929004570Smrg    vt = vproc_transaction_begin(NULL);
29072e81212Smrg#endif
29172e81212Smrg#endif
29272e81212Smrg
29329004570Smrg    if (startServer(server) > 0
29429004570Smrg        && startClient(client) > 0) {
29529004570Smrg        pid = -1;
29629004570Smrg        while (pid != clientpid && pid != serverpid
29729004570Smrg               && gotSignal == 0
29829004570Smrg            )
29929004570Smrg            pid = wait(NULL);
30029004570Smrg    }
30172e81212Smrg
30272e81212Smrg#ifdef __APPLE__
303bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
30429004570Smrg    vproc_transaction_end(NULL, vt);
30572e81212Smrg#endif
30672e81212Smrg#endif
30772e81212Smrg
30829004570Smrg    signal(SIGTERM, SIG_IGN);
30929004570Smrg    signal(SIGQUIT, SIG_IGN);
31029004570Smrg    signal(SIGINT, SIG_IGN);
31129004570Smrg    signal(SIGHUP, SIG_IGN);
31229004570Smrg    signal(SIGPIPE, SIG_IGN);
313a73027baSmrg
31429004570Smrg    shutdown();
315a73027baSmrg
31629004570Smrg    if (gotSignal != 0) {
31729004570Smrg        Errorx("unexpected signal %d", gotSignal);
31829004570Smrg        exit(EXIT_FAILURE);
31929004570Smrg    }
320a73027baSmrg
32129004570Smrg    if (serverpid < 0)
32229004570Smrg        Fatalx("server error");
32329004570Smrg    if (clientpid < 0)
32429004570Smrg        Fatalx("client error");
32529004570Smrg    exit(EXIT_SUCCESS);
326a73027baSmrg}
327a73027baSmrg
328a73027baSmrg
329a73027baSmrg/*
33029004570Smrg *    waitforserver - wait for X server to start up
331a73027baSmrg */
332a73027baSmrgstatic Bool
333a73027baSmrgwaitforserver(void)
334a73027baSmrg{
33529004570Smrg    int    ncycles     = 120;        /* # of cycles to wait */
33629004570Smrg    int    cycles;            /* Wait cycle count */
337a73027baSmrg
33872e81212Smrg#ifdef __APPLE__
33929004570Smrg    /* For Apple, we don't get signaled by the server when it's ready, so we just
34029004570Smrg     * want to sleep now since we're going to sleep later anyways and this allows us
34129004570Smrg     * to avoid the awkard, "why is there an error message in the log" questions
34229004570Smrg     * from users.
34329004570Smrg     */
34429004570Smrg
34529004570Smrg    sleep(2);
34629004570Smrg#endif
34729004570Smrg
34829004570Smrg    for (cycles = 0; cycles < ncycles; cycles++) {
34929004570Smrg        if ((xd = XOpenDisplay(displayNum))) {
35029004570Smrg            return(TRUE);
35129004570Smrg        }
35229004570Smrg        else {
35329004570Smrg            if (!processTimeout(1, "X server to begin accepting connections"))
35429004570Smrg              break;
35529004570Smrg        }
35629004570Smrg    }
35772e81212Smrg
35829004570Smrg    Errorx("giving up");
35972e81212Smrg
36029004570Smrg    return(FALSE);
361a73027baSmrg}
362a73027baSmrg
363a73027baSmrg/*
364a73027baSmrg * return TRUE if we timeout waiting for pid to exit, FALSE otherwise.
365a73027baSmrg */
366a73027baSmrgstatic Bool
36736ffeb23SmrgprocessTimeout(int timeout, const char *string)
368a73027baSmrg{
36936ffeb23Smrg    int    i = 0;
37036ffeb23Smrg    pid_t  pidfound = -1;
37136ffeb23Smrg    static const char    *laststring;
37229004570Smrg
37329004570Smrg    for (;;) {
37429004570Smrg        if ((pidfound = waitpid(serverpid, &status, WNOHANG)) == serverpid)
37529004570Smrg            break;
37629004570Smrg        if (timeout) {
37729004570Smrg            if (i == 0 && string != laststring)
37829004570Smrg                fprintf(stderr, "\r\nwaiting for %s ", string);
37929004570Smrg            else
38029004570Smrg                fprintf(stderr, ".");
38129004570Smrg            fflush(stderr);
38229004570Smrg            sleep(1);
38311f750edSmrg        }
38429004570Smrg        if (++i > timeout)
38529004570Smrg            break;
38629004570Smrg    }
38729004570Smrg    if (i > 0) fputc('\n', stderr);     /* tidy up after message */
38829004570Smrg    laststring = string;
38929004570Smrg    return (serverpid != pidfound);
390a73027baSmrg}
391a73027baSmrg
39236ffeb23Smrgstatic pid_t
39341667ceaSmrgstartServer(char *server_argv[])
394a73027baSmrg{
39529004570Smrg    sigset_t mask, old;
39629004570Smrg    const char * const *cpp;
397a73027baSmrg
39829004570Smrg    sigemptyset(&mask);
39929004570Smrg    sigaddset(&mask, SIGUSR1);
40029004570Smrg    sigprocmask(SIG_BLOCK, &mask, &old);
401a73027baSmrg
40229004570Smrg    serverpid = fork();
403a73027baSmrg
40429004570Smrg    switch(serverpid) {
40529004570Smrg    case 0:
40629004570Smrg        /* Unblock */
40729004570Smrg        sigprocmask(SIG_SETMASK, &old, NULL);
408a73027baSmrg
40929004570Smrg        /*
41029004570Smrg         * don't hang on read/write to control tty
41129004570Smrg         */
41229004570Smrg        signal(SIGTTIN, SIG_IGN);
41329004570Smrg        signal(SIGTTOU, SIG_IGN);
41429004570Smrg        /*
41529004570Smrg         * ignore SIGUSR1 in child.  The server
41629004570Smrg         * will notice this and send SIGUSR1 back
41729004570Smrg         * at xinit when ready to accept connections
41829004570Smrg         */
41929004570Smrg        signal(SIGUSR1, SIG_IGN);
42029004570Smrg        /*
42129004570Smrg         * prevent server from getting sighup from vhangup()
42229004570Smrg         * if client is xterm -L
42329004570Smrg         */
42429004570Smrg        setpgid(0,getpid());
42541667ceaSmrg        Execute(server_argv);
42629004570Smrg
42741667ceaSmrg        Error("unable to run server \"%s\"", server_argv[0]);
42829004570Smrg
42929004570Smrg        fprintf(stderr, "Use the -- option, or make sure that %s is in your path and\n", bindir);
43041667ceaSmrg        fprintf(stderr, "that \"%s\" is a program or a link to the right type of server\n", server_argv[0]);
43129004570Smrg        fprintf(stderr, "for your display.  Possible server names include:\n\n");
43229004570Smrg        for (cpp = server_names; *cpp; cpp++)
43329004570Smrg            fprintf(stderr, "    %s\n", *cpp);
43429004570Smrg        fprintf(stderr, "\n");
43529004570Smrg
43629004570Smrg        exit(EXIT_FAILURE);
43729004570Smrg
43829004570Smrg        break;
43929004570Smrg    case -1:
44029004570Smrg        break;
44129004570Smrg    default:
44229004570Smrg        /*
44329004570Smrg         * don't nice server
44429004570Smrg         */
44529004570Smrg        setpriority(PRIO_PROCESS, serverpid, -1);
44629004570Smrg
44729004570Smrg        errno = 0;
44829004570Smrg        if(! processTimeout(0, "")) {
44929004570Smrg            serverpid = -1;
45029004570Smrg            break;
45129004570Smrg        }
45229004570Smrg        /*
45329004570Smrg         * kludge to avoid race with TCP, giving server time to
45429004570Smrg         * set his socket options before we try to open it,
45529004570Smrg         * either use the 15 second timeout, or await SIGUSR1.
45629004570Smrg         *
45729004570Smrg         * If your machine is substantially slower than 15 seconds,
45829004570Smrg         * you can easily adjust this value.
45929004570Smrg         */
46029004570Smrg        alarm(15);
46129004570Smrg
46229004570Smrg        sigsuspend(&old);
46329004570Smrg        alarm(0);
46429004570Smrg        sigprocmask(SIG_SETMASK, &old, NULL);
46529004570Smrg
46629004570Smrg        if (waitforserver() == 0) {
46729004570Smrg            Error("unable to connect to X server");
46829004570Smrg            shutdown();
46929004570Smrg            serverpid = -1;
47029004570Smrg        }
47129004570Smrg        break;
47229004570Smrg    }
473a73027baSmrg
47429004570Smrg    return(serverpid);
475a73027baSmrg}
476a73027baSmrg
477a73027baSmrgstatic void
478a73027baSmrgsetWindowPath(void)
479a73027baSmrg{
48029004570Smrg    /* setting WINDOWPATH for clients */
48129004570Smrg    Atom prop;
48229004570Smrg    Atom actualtype;
48329004570Smrg    int actualformat;
48429004570Smrg    unsigned long nitems;
48529004570Smrg    unsigned long bytes_after;
48629004570Smrg    unsigned char *buf;
48729004570Smrg    const char *windowpath;
48829004570Smrg    char *newwindowpath;
48929004570Smrg    unsigned long num;
49029004570Smrg    char nums[10];
49129004570Smrg    int numn;
49229004570Smrg    size_t len;
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");
53629004570Smrg    numn = snprintf(nums, sizeof(nums), "%lu", num);
53729004570Smrg    if (!windowpath) {
53829004570Smrg        len = numn + 1;
53929004570Smrg        newwindowpath = malloc(len);
54029004570Smrg        if (newwindowpath == NULL)
54129004570Smrg            return;
54229004570Smrg        snprintf(newwindowpath, len, "%s", nums);
54329004570Smrg    } else {
54429004570Smrg        len = strlen(windowpath) + 1 + numn + 1;
54529004570Smrg        newwindowpath = malloc(len);
54629004570Smrg        if (newwindowpath == NULL)
54729004570Smrg            return;
54829004570Smrg        snprintf(newwindowpath, len, "%s:%s",
54929004570Smrg                 windowpath, nums);
55029004570Smrg    }
55129004570Smrg    if (setenv("WINDOWPATH", newwindowpath, TRUE) == -1)
55229004570Smrg        Error("unable to set WINDOWPATH");
55329004570Smrg
55429004570Smrg
55529004570Smrg    free(newwindowpath);
556a73027baSmrg}
557a73027baSmrg
55836ffeb23Smrgstatic pid_t
55941667ceaSmrgstartClient(char *client_argv[])
560a73027baSmrg{
56129004570Smrg    clientpid = fork();
56229004570Smrg    if (clientpid == 0) {
56329004570Smrg        set_environment();
56429004570Smrg        setWindowPath();
56529004570Smrg
56629004570Smrg        if (setuid(getuid()) == -1) {
56729004570Smrg            Error("cannot change uid");
56829004570Smrg            _exit(EXIT_FAILURE);
56929004570Smrg        }
57029004570Smrg        setpgid(0, getpid());
57141667ceaSmrg        Execute(client_argv);
57241667ceaSmrg        Error("Unable to run program \"%s\"", client_argv[0]);
57329004570Smrg
57429004570Smrg        fprintf(stderr, "Specify a program on the command line or make sure that %s\n", bindir);
57529004570Smrg        fprintf(stderr, "is in your path.\n\n");
57629004570Smrg
57729004570Smrg        _exit(EXIT_FAILURE);
57829004570Smrg    } else {
57929004570Smrg        return clientpid;
58029004570Smrg    }
581a73027baSmrg}
582a73027baSmrg
583a73027baSmrgstatic jmp_buf close_env;
584a73027baSmrg
58529004570Smrgstatic int
586a73027baSmrgignorexio(Display *dpy)
587a73027baSmrg{
58829004570Smrg    Errorx("connection to X server lost");
58929004570Smrg    longjmp(close_env, 1);
590a73027baSmrg    /*NOTREACHED*/
591a73027baSmrg    return 0;
592a73027baSmrg}
593a73027baSmrg
59429004570Smrgstatic void
595a73027baSmrgshutdown(void)
596a73027baSmrg{
59729004570Smrg    /* have kept display opened, so close it now */
59829004570Smrg    if (clientpid > 0) {
59929004570Smrg        XSetIOErrorHandler(ignorexio);
60029004570Smrg        if (! setjmp(close_env)) {
60129004570Smrg            XCloseDisplay(xd);
60229004570Smrg        }
60329004570Smrg
60429004570Smrg        /* HUP all local clients to allow them to clean up */
60529004570Smrg        if (killpg(clientpid, SIGHUP) < 0 && errno != ESRCH)
60629004570Smrg            Error("can't send HUP to process group %d", clientpid);
60729004570Smrg    }
608a73027baSmrg
60929004570Smrg    if (serverpid < 0)
61029004570Smrg        return;
611a73027baSmrg
61229004570Smrg    if (killpg(serverpid, SIGTERM) < 0) {
61329004570Smrg        if (errno == ESRCH)
61429004570Smrg            return;
61529004570Smrg        Fatal("can't kill X server");
61629004570Smrg    }
61729004570Smrg
61829004570Smrg    if (!processTimeout(10, "X server to shut down"))
61929004570Smrg        return;
620a73027baSmrg
62111f750edSmrg    Errorx("X server slow to shut down, sending KILL signal");
62229004570Smrg
62329004570Smrg    if (killpg(serverpid, SIGKILL) < 0) {
62429004570Smrg        if (errno == ESRCH)
62529004570Smrg            return;
62629004570Smrg        Error("can't SIGKILL X server");
62729004570Smrg    }
62829004570Smrg
62929004570Smrg    if (processTimeout(3, "server to die"))
63029004570Smrg        Fatalx("X server refuses to die");
63136ffeb23Smrg#ifdef __sun
63236ffeb23Smrg    else {
63336ffeb23Smrg        /* Restore keyboard mode. */
63436ffeb23Smrg        serverpid = fork();
63536ffeb23Smrg        switch (serverpid) {
63636ffeb23Smrg        case 0:
63736ffeb23Smrg            execlp ("kbd_mode", "kbd_mode", "-a", NULL);
63836ffeb23Smrg            Fatal("Unable to run program \"%s\"", "kbd_mode");
63936ffeb23Smrg            break;
64036ffeb23Smrg
64136ffeb23Smrg        case 1:
64236ffeb23Smrg            Error("fork failed");
64336ffeb23Smrg            break;
64436ffeb23Smrg
64536ffeb23Smrg        default:
64636ffeb23Smrg            fprintf (stderr, "\r\nRestoring keyboard mode\r\n");
64736ffeb23Smrg            processTimeout(1, "kbd_mode");
64836ffeb23Smrg        }
64936ffeb23Smrg    }
65036ffeb23Smrg#endif
65129004570Smrg}
65229004570Smrg
65329004570Smrgstatic void
654a73027baSmrgset_environment(void)
655a73027baSmrg{
65629004570Smrg    if (setenv("DISPLAY", displayNum, TRUE) == -1)
65729004570Smrg        Fatal("unable to set DISPLAY");
65829004570Smrg}
659a73027baSmrg
66036ffeb23Smrgstatic void _X_ATTRIBUTE_PRINTF(1,0)
66129004570Smrgverror(const char *fmt, va_list ap)
66229004570Smrg{
66329004570Smrg    fprintf(stderr, "%s: ", program);
66429004570Smrg    vfprintf(stderr, fmt, ap);
66529004570Smrg    fprintf(stderr, ": %s\n", strerror(errno));
66629004570Smrg}
66729004570Smrg
66836ffeb23Smrgstatic void _X_ATTRIBUTE_PRINTF(1,0)
66929004570Smrgverrorx(const char *fmt, va_list ap)
67029004570Smrg{
67129004570Smrg    fprintf(stderr, "%s: ", program);
67229004570Smrg    vfprintf(stderr, fmt, ap);
67329004570Smrg    fprintf(stderr, "\n");
67429004570Smrg}
67529004570Smrg
67629004570Smrgstatic void
67729004570SmrgFatal(const char *fmt, ...)
67829004570Smrg{
67929004570Smrg    va_list ap;
68029004570Smrg    va_start(ap, fmt);
68129004570Smrg    verror(fmt, ap);
68229004570Smrg    va_end(ap);
68329004570Smrg    exit(EXIT_FAILURE);
68429004570Smrg}
68529004570Smrg
68629004570Smrgstatic void
68729004570SmrgFatalx(const char *fmt, ...)
68829004570Smrg{
68929004570Smrg    va_list ap;
69029004570Smrg    va_start(ap, fmt);
69129004570Smrg    verrorx(fmt, ap);
69229004570Smrg    va_end(ap);
69329004570Smrg    exit(EXIT_FAILURE);
694a73027baSmrg}
695a73027baSmrg
696a73027baSmrgstatic void
69729004570SmrgError(const char *fmt, ...)
698a73027baSmrg{
69929004570Smrg    va_list ap;
70029004570Smrg    va_start(ap, fmt);
70129004570Smrg    verror(fmt, ap);
70229004570Smrg    va_end(ap);
703a73027baSmrg}
704a73027baSmrg
705a73027baSmrgstatic void
70629004570SmrgErrorx(const char *fmt, ...)
707a73027baSmrg{
70829004570Smrg    va_list ap;
70929004570Smrg    va_start(ap, fmt);
71029004570Smrg    verrorx(fmt, ap);
71129004570Smrg    va_end(ap);
712a73027baSmrg}
713