xinit.c revision 11f750ed
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() */
52117614e6Smrg#if defined(__DragonFly__) || defined(__NetBSD__)
5329004570Smrg#include <sys/time.h>
5429004570Smrg#include <sys/resource.h>
5529004570Smrg#endif /* __DragonFly__ */
56a73027baSmrg
57a73027baSmrg#include <stdlib.h>
58a73027baSmrg
59a73027baSmrg#ifndef SHELL
60a73027baSmrg#define SHELL "sh"
61a73027baSmrg#endif
62a73027baSmrg
63a73027baSmrgconst char *bindir = BINDIR;
64a73027baSmrgconst 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",
79bf4a254eSmrg    "Xdmx        Distributed Multi-head X server",
80a73027baSmrg    NULL};
81a73027baSmrg
82a73027baSmrg#ifndef XINITRC
83a73027baSmrg#define XINITRC ".xinitrc"
84a73027baSmrg#endif
85a73027baSmrgchar xinitrcbuf[256];
86a73027baSmrg
87a73027baSmrg#ifndef XSERVERRC
88a73027baSmrg#define XSERVERRC ".xserverrc"
89a73027baSmrg#endif
90a73027baSmrgchar xserverrcbuf[256];
91a73027baSmrg
9229004570Smrg#define TRUE 1
9329004570Smrg#define FALSE 0
94a73027baSmrg
95a73027baSmrgstatic char *default_server = "X";
9629004570Smrgstatic char *default_display = ":0";        /* choose most efficient */
97a73027baSmrgstatic char *default_client[] = {"xterm", "-geometry", "+1+1", "-n", "login", NULL};
98a73027baSmrgstatic char *serverargv[100];
99a73027baSmrgstatic char *clientargv[100];
10029004570Smrgstatic char **server = serverargv + 2;        /* make sure room for sh .xserverrc args */
10129004570Smrgstatic char **client = clientargv + 2;        /* make sure room for sh .xinitrc args */
102a73027baSmrgstatic char *displayNum = NULL;
103a73027baSmrgstatic char *program = NULL;
10429004570Smrgstatic Display *xd = NULL;            /* server connection */
105a73027baSmrgint status;
106a73027baSmrgint serverpid = -1;
107a73027baSmrgint clientpid = -1;
108a73027baSmrgvolatile int gotSignal = 0;
109a73027baSmrg
11029004570Smrgstatic void Execute(char **vec);
11129004570Smrgstatic Bool waitforserver(void);
11229004570Smrgstatic Bool processTimeout(int timeout, char *string);
11329004570Smrgstatic int startServer(char *server[]);
11429004570Smrgstatic int startClient(char *client[]);
11529004570Smrgstatic int ignorexio(Display *dpy);
11629004570Smrgstatic void shutdown(void);
11729004570Smrgstatic void set_environment(void);
11829004570Smrg
11929004570Smrgstatic void Fatal(const char *fmt, ...);
12029004570Smrgstatic void Error(const char *fmt, ...);
12129004570Smrgstatic void Fatalx(const char *fmt, ...);
12229004570Smrgstatic void Errorx(const char *fmt, ...);
123a73027baSmrg
12429004570Smrgstatic void
12529004570SmrgsigCatch(int sig)
126a73027baSmrg{
12729004570Smrg    /* On system with POSIX signals, just interrupt the system call */
12829004570Smrg    gotSignal = sig;
129a73027baSmrg}
130a73027baSmrg
13129004570Smrgstatic void
13229004570SmrgsigIgnore(int sig)
133a73027baSmrg{
134a73027baSmrg}
135a73027baSmrg
13629004570Smrgstatic void
13729004570SmrgExecute(char **vec)		/* has room from up above */
138a73027baSmrg{
13929004570Smrg    execvp(vec[0], vec);
14029004570Smrg    if (access(vec[0], R_OK) == 0) {
141a73027baSmrg	vec--;				/* back it up to stuff shell in */
142a73027baSmrg	vec[0] = SHELL;
14329004570Smrg	execvp(vec[0], vec);
144a73027baSmrg    }
145a73027baSmrg    return;
146a73027baSmrg}
147a73027baSmrg
148a73027baSmrgint
149a73027baSmrgmain(int argc, char *argv[])
150a73027baSmrg{
15129004570Smrg    register char **sptr = server;
15229004570Smrg    register char **cptr = client;
15329004570Smrg    register char **ptr;
15429004570Smrg    int pid;
15529004570Smrg    int client_given = 0, server_given = 0;
15629004570Smrg    int client_args_given = 0, server_args_given = 0;
15729004570Smrg    int start_of_client_args, start_of_server_args;
15829004570Smrg    struct sigaction sa, si;
15972e81212Smrg#ifdef __APPLE__
160bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060
16129004570Smrg    vproc_transaction_t vt;
16272e81212Smrg#endif
16372e81212Smrg#endif
164a73027baSmrg
16529004570Smrg    program = *argv++;
16629004570Smrg    argc--;
16729004570Smrg    /*
16829004570Smrg     * copy the client args.
16929004570Smrg     */
17029004570Smrg    if (argc == 0 ||
17129004570Smrg        (**argv != '/' && **argv != '.')) {
17229004570Smrg        for (ptr = default_client; *ptr; )
17329004570Smrg            *cptr++ = *ptr++;
17429004570Smrg    } else {
17529004570Smrg        client_given = 1;
17629004570Smrg    }
17729004570Smrg    start_of_client_args = (cptr - client);
17829004570Smrg    while (argc && strcmp(*argv, "--")) {
17929004570Smrg        client_args_given++;
18029004570Smrg        *cptr++ = *argv++;
18129004570Smrg        argc--;
18229004570Smrg    }
18329004570Smrg    *cptr = NULL;
18429004570Smrg    if (argc) {
18529004570Smrg        argv++;
18629004570Smrg        argc--;
18729004570Smrg    }
18829004570Smrg
18929004570Smrg    /*
19029004570Smrg     * Copy the server args.
19129004570Smrg     */
19229004570Smrg    if (argc == 0 ||
19329004570Smrg        (**argv != '/' && **argv != '.')) {
19429004570Smrg        *sptr++ = default_server;
19529004570Smrg    } else {
19629004570Smrg        server_given = 1;
19729004570Smrg        *sptr++ = *argv++;
19829004570Smrg        argc--;
19929004570Smrg    }
20029004570Smrg    if (argc > 0 && (argv[0][0] == ':' && isdigit(argv[0][1])))
20129004570Smrg        displayNum = *argv;
20229004570Smrg    else
20329004570Smrg        displayNum = *sptr++ = default_display;
20429004570Smrg
20529004570Smrg    start_of_server_args = (sptr - server);
20629004570Smrg    while (--argc >= 0) {
20729004570Smrg        server_args_given++;
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    signal(SIGCHLD, SIG_DFL);    /* Insurance */
26829004570Smrg
26929004570Smrg    /* Let those signal interrupt the wait() call in the main loop */
27029004570Smrg    memset(&sa, 0, sizeof sa);
27129004570Smrg    sa.sa_handler = sigCatch;
27229004570Smrg    sigemptyset(&sa.sa_mask);
27329004570Smrg    sa.sa_flags = 0;    /* do not set SA_RESTART */
27429004570Smrg
27529004570Smrg    sigaction(SIGTERM, &sa, NULL);
27629004570Smrg    sigaction(SIGQUIT, &sa, NULL);
27729004570Smrg    sigaction(SIGINT, &sa, NULL);
27829004570Smrg    sigaction(SIGHUP, &sa, NULL);
27929004570Smrg    sigaction(SIGPIPE, &sa, NULL);
280a73027baSmrg
28129004570Smrg    memset(&si, 0, sizeof(si));
28229004570Smrg    si.sa_handler = sigIgnore;
28329004570Smrg    sigemptyset(&si.sa_mask);
28429004570Smrg    si.sa_flags = SA_RESTART;
28529004570Smrg
28629004570Smrg    sigaction(SIGALRM, &si, NULL);
28729004570Smrg    sigaction(SIGUSR1, &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 (gotSignal != 0) {
31929004570Smrg        Errorx("unexpected signal %d", gotSignal);
32029004570Smrg        exit(EXIT_FAILURE);
32129004570Smrg    }
322a73027baSmrg
32329004570Smrg    if (serverpid < 0)
32429004570Smrg        Fatalx("server error");
32529004570Smrg    if (clientpid < 0)
32629004570Smrg        Fatalx("client error");
32729004570Smrg    exit(EXIT_SUCCESS);
328a73027baSmrg}
329a73027baSmrg
330a73027baSmrg
331a73027baSmrg/*
33229004570Smrg *    waitforserver - wait for X server to start up
333a73027baSmrg */
334a73027baSmrgstatic Bool
335a73027baSmrgwaitforserver(void)
336a73027baSmrg{
33729004570Smrg    int    ncycles     = 120;        /* # of cycles to wait */
33829004570Smrg    int    cycles;            /* Wait cycle count */
339a73027baSmrg
34072e81212Smrg#ifdef __APPLE__
34129004570Smrg    /* For Apple, we don't get signaled by the server when it's ready, so we just
34229004570Smrg     * want to sleep now since we're going to sleep later anyways and this allows us
34329004570Smrg     * to avoid the awkard, "why is there an error message in the log" questions
34429004570Smrg     * from users.
34529004570Smrg     */
34629004570Smrg
34729004570Smrg    sleep(2);
34829004570Smrg#endif
34929004570Smrg
35029004570Smrg    for (cycles = 0; cycles < ncycles; cycles++) {
35129004570Smrg        if ((xd = XOpenDisplay(displayNum))) {
35229004570Smrg            return(TRUE);
35329004570Smrg        }
35429004570Smrg        else {
35529004570Smrg            if (!processTimeout(1, "X server to begin accepting connections"))
35629004570Smrg              break;
35729004570Smrg        }
35829004570Smrg    }
35972e81212Smrg
36029004570Smrg    Errorx("giving up");
36172e81212Smrg
36229004570Smrg    return(FALSE);
363a73027baSmrg}
364a73027baSmrg
365a73027baSmrg/*
366a73027baSmrg * return TRUE if we timeout waiting for pid to exit, FALSE otherwise.
367a73027baSmrg */
368a73027baSmrgstatic Bool
369a73027baSmrgprocessTimeout(int timeout, char *string)
370a73027baSmrg{
37129004570Smrg    int    i = 0, pidfound = -1;
37229004570Smrg    static char    *laststring;
37329004570Smrg
37429004570Smrg    for (;;) {
37529004570Smrg        if ((pidfound = waitpid(serverpid, &status, WNOHANG)) == serverpid)
37629004570Smrg            break;
37729004570Smrg        if (timeout) {
37829004570Smrg            if (i == 0 && string != laststring)
37929004570Smrg                fprintf(stderr, "\r\nwaiting for %s ", string);
38029004570Smrg            else
38129004570Smrg                fprintf(stderr, ".");
38229004570Smrg            fflush(stderr);
38329004570Smrg            sleep(1);
38411f750edSmrg        }
38529004570Smrg        if (++i > timeout)
38629004570Smrg            break;
38729004570Smrg    }
38829004570Smrg    if (i > 0) fputc('\n', stderr);     /* tidy up after message */
38929004570Smrg    laststring = string;
39029004570Smrg    return (serverpid != pidfound);
391a73027baSmrg}
392a73027baSmrg
393a73027baSmrgstatic int
394a73027baSmrgstartServer(char *server[])
395a73027baSmrg{
39629004570Smrg    sigset_t mask, old;
39729004570Smrg    const char * const *cpp;
398a73027baSmrg
39929004570Smrg    sigemptyset(&mask);
40029004570Smrg    sigaddset(&mask, SIGUSR1);
40129004570Smrg    sigprocmask(SIG_BLOCK, &mask, &old);
402a73027baSmrg
40329004570Smrg    serverpid = fork();
404a73027baSmrg
40529004570Smrg    switch(serverpid) {
40629004570Smrg    case 0:
40729004570Smrg        /* Unblock */
40829004570Smrg        sigprocmask(SIG_SETMASK, &old, NULL);
409a73027baSmrg
41029004570Smrg        /*
41129004570Smrg         * don't hang on read/write to control tty
41229004570Smrg         */
41329004570Smrg        signal(SIGTTIN, SIG_IGN);
41429004570Smrg        signal(SIGTTOU, SIG_IGN);
41529004570Smrg        /*
41629004570Smrg         * ignore SIGUSR1 in child.  The server
41729004570Smrg         * will notice this and send SIGUSR1 back
41829004570Smrg         * at xinit when ready to accept connections
41929004570Smrg         */
42029004570Smrg        signal(SIGUSR1, SIG_IGN);
42129004570Smrg        /*
42229004570Smrg         * prevent server from getting sighup from vhangup()
42329004570Smrg         * if client is xterm -L
42429004570Smrg         */
42529004570Smrg        setpgid(0,getpid());
42629004570Smrg        Execute(server);
42729004570Smrg
42829004570Smrg        Error("unable to run server \"%s\"", server[0]);
42929004570Smrg
43029004570Smrg        fprintf(stderr, "Use the -- option, or make sure that %s is in your path and\n", bindir);
43129004570Smrg        fprintf(stderr, "that \"%s\" is a program or a link to the right type of server\n", server[0]);
43229004570Smrg        fprintf(stderr, "for your display.  Possible server names include:\n\n");
43329004570Smrg        for (cpp = server_names; *cpp; cpp++)
43429004570Smrg            fprintf(stderr, "    %s\n", *cpp);
43529004570Smrg        fprintf(stderr, "\n");
43629004570Smrg
43729004570Smrg        exit(EXIT_FAILURE);
43829004570Smrg
43929004570Smrg        break;
44029004570Smrg    case -1:
44129004570Smrg        break;
44229004570Smrg    default:
44329004570Smrg        /*
44429004570Smrg         * don't nice server
44529004570Smrg         */
44629004570Smrg        setpriority(PRIO_PROCESS, serverpid, -1);
44729004570Smrg
44829004570Smrg        errno = 0;
44929004570Smrg        if(! processTimeout(0, "")) {
45029004570Smrg            serverpid = -1;
45129004570Smrg            break;
45229004570Smrg        }
45329004570Smrg        /*
45429004570Smrg         * kludge to avoid race with TCP, giving server time to
45529004570Smrg         * set his socket options before we try to open it,
45629004570Smrg         * either use the 15 second timeout, or await SIGUSR1.
45729004570Smrg         *
45829004570Smrg         * If your machine is substantially slower than 15 seconds,
45929004570Smrg         * you can easily adjust this value.
46029004570Smrg         */
46129004570Smrg        alarm(15);
46229004570Smrg
46329004570Smrg        sigsuspend(&old);
46429004570Smrg        alarm(0);
46529004570Smrg        sigprocmask(SIG_SETMASK, &old, NULL);
46629004570Smrg
46729004570Smrg        if (waitforserver() == 0) {
46829004570Smrg            Error("unable to connect to X server");
46929004570Smrg            shutdown();
47029004570Smrg            serverpid = -1;
47129004570Smrg        }
47229004570Smrg        break;
47329004570Smrg    }
474a73027baSmrg
47529004570Smrg    return(serverpid);
476a73027baSmrg}
477a73027baSmrg
478a73027baSmrgstatic void
479a73027baSmrgsetWindowPath(void)
480a73027baSmrg{
48129004570Smrg    /* setting WINDOWPATH for clients */
48229004570Smrg    Atom prop;
48329004570Smrg    Atom actualtype;
48429004570Smrg    int actualformat;
48529004570Smrg    unsigned long nitems;
48629004570Smrg    unsigned long bytes_after;
48729004570Smrg    unsigned char *buf;
48829004570Smrg    const char *windowpath;
48929004570Smrg    char *newwindowpath;
49029004570Smrg    unsigned long num;
49129004570Smrg    char nums[10];
49229004570Smrg    int numn;
49329004570Smrg    size_t len;
49429004570Smrg    prop = XInternAtom(xd, "XFree86_VT", False);
49529004570Smrg    if (prop == None) {
49629004570Smrg        Errorx("Unable to intern XFree86_VT atom");
49729004570Smrg        return;
49829004570Smrg    }
49929004570Smrg    if (XGetWindowProperty(xd, DefaultRootWindow(xd), prop, 0, 1,
50029004570Smrg        False, AnyPropertyType, &actualtype, &actualformat,
50129004570Smrg        &nitems, &bytes_after, &buf)) {
50229004570Smrg        Errorx("No XFree86_VT property detected on X server, WINDOWPATH won't be set");
50329004570Smrg        return;
50429004570Smrg    }
50529004570Smrg    if (nitems != 1) {
50629004570Smrg        Errorx("XFree86_VT property unexpectedly has %lu items instead of 1", nitems);
50729004570Smrg        XFree(buf);
50829004570Smrg        return;
50929004570Smrg    }
51029004570Smrg    switch (actualtype) {
51129004570Smrg    case XA_CARDINAL:
51229004570Smrg    case XA_INTEGER:
51329004570Smrg    case XA_WINDOW:
51429004570Smrg        switch (actualformat) {
51529004570Smrg        case  8:
51629004570Smrg            num = (*(uint8_t  *)(void *)buf);
51729004570Smrg            break;
51829004570Smrg        case 16:
51929004570Smrg            num = (*(uint16_t *)(void *)buf);
52029004570Smrg            break;
52129004570Smrg        case 32:
52229004570Smrg            num = (*(uint32_t *)(void *)buf);
52329004570Smrg            break;
52429004570Smrg        default:
52529004570Smrg            Errorx("XFree86_VT property has unexpected format %d", actualformat);
52629004570Smrg            XFree(buf);
52729004570Smrg            return;
52829004570Smrg        }
52929004570Smrg        break;
53029004570Smrg    default:
53129004570Smrg        Errorx("XFree86_VT property has unexpected type %lx", actualtype);
53229004570Smrg        XFree(buf);
53329004570Smrg        return;
53429004570Smrg    }
53529004570Smrg    XFree(buf);
53629004570Smrg    windowpath = getenv("WINDOWPATH");
53729004570Smrg    numn = snprintf(nums, sizeof(nums), "%lu", num);
53829004570Smrg    if (!windowpath) {
53929004570Smrg        len = numn + 1;
54029004570Smrg        newwindowpath = malloc(len);
54129004570Smrg        if (newwindowpath == NULL)
54229004570Smrg            return;
54329004570Smrg        snprintf(newwindowpath, len, "%s", nums);
54429004570Smrg    } else {
54529004570Smrg        len = strlen(windowpath) + 1 + numn + 1;
54629004570Smrg        newwindowpath = malloc(len);
54729004570Smrg        if (newwindowpath == NULL)
54829004570Smrg            return;
54929004570Smrg        snprintf(newwindowpath, len, "%s:%s",
55029004570Smrg                 windowpath, nums);
55129004570Smrg    }
55229004570Smrg    if (setenv("WINDOWPATH", newwindowpath, TRUE) == -1)
55329004570Smrg        Error("unable to set WINDOWPATH");
55429004570Smrg
55529004570Smrg
55629004570Smrg    free(newwindowpath);
557a73027baSmrg}
558a73027baSmrg
559a73027baSmrgstatic int
560a73027baSmrgstartClient(char *client[])
561a73027baSmrg{
56229004570Smrg    clientpid = fork();
56329004570Smrg    if (clientpid == 0) {
56429004570Smrg        set_environment();
56529004570Smrg        setWindowPath();
56629004570Smrg
56729004570Smrg        if (setuid(getuid()) == -1) {
56829004570Smrg            Error("cannot change uid");
56929004570Smrg            _exit(EXIT_FAILURE);
57029004570Smrg        }
57129004570Smrg        setpgid(0, getpid());
57229004570Smrg        Execute(client);
57329004570Smrg        Error("Unable to run program \"%s\"", client[0]);
57429004570Smrg
57529004570Smrg        fprintf(stderr, "Specify a program on the command line or make sure that %s\n", bindir);
57629004570Smrg        fprintf(stderr, "is in your path.\n\n");
57729004570Smrg
57829004570Smrg        _exit(EXIT_FAILURE);
57929004570Smrg    } else {
58029004570Smrg        return clientpid;
58129004570Smrg    }
582a73027baSmrg}
583a73027baSmrg
584a73027baSmrgstatic jmp_buf close_env;
585a73027baSmrg
58629004570Smrgstatic int
587a73027baSmrgignorexio(Display *dpy)
588a73027baSmrg{
58929004570Smrg    Errorx("connection to X server lost");
59029004570Smrg    longjmp(close_env, 1);
591a73027baSmrg    /*NOTREACHED*/
592a73027baSmrg    return 0;
593a73027baSmrg}
594a73027baSmrg
59529004570Smrgstatic void
596a73027baSmrgshutdown(void)
597a73027baSmrg{
59829004570Smrg    /* have kept display opened, so close it now */
59929004570Smrg    if (clientpid > 0) {
60029004570Smrg        XSetIOErrorHandler(ignorexio);
60129004570Smrg        if (! setjmp(close_env)) {
60229004570Smrg            XCloseDisplay(xd);
60329004570Smrg        }
60429004570Smrg
60529004570Smrg        /* HUP all local clients to allow them to clean up */
60629004570Smrg        if (killpg(clientpid, SIGHUP) < 0 && errno != ESRCH)
60729004570Smrg            Error("can't send HUP to process group %d", clientpid);
60829004570Smrg    }
609a73027baSmrg
61029004570Smrg    if (serverpid < 0)
61129004570Smrg        return;
612a73027baSmrg
61329004570Smrg    if (killpg(serverpid, SIGTERM) < 0) {
61429004570Smrg        if (errno == ESRCH)
61529004570Smrg            return;
61629004570Smrg        Fatal("can't kill X server");
61729004570Smrg    }
61829004570Smrg
61929004570Smrg    if (!processTimeout(10, "X server to shut down"))
62029004570Smrg        return;
621a73027baSmrg
62211f750edSmrg    Errorx("X server slow to shut down, sending KILL signal");
62329004570Smrg
62429004570Smrg    if (killpg(serverpid, SIGKILL) < 0) {
62529004570Smrg        if (errno == ESRCH)
62629004570Smrg            return;
62729004570Smrg        Error("can't SIGKILL X server");
62829004570Smrg    }
62929004570Smrg
63029004570Smrg    if (processTimeout(3, "server to die"))
63129004570Smrg        Fatalx("X server refuses to die");
63229004570Smrg}
63329004570Smrg
63429004570Smrgstatic void
635a73027baSmrgset_environment(void)
636a73027baSmrg{
63729004570Smrg    if (setenv("DISPLAY", displayNum, TRUE) == -1)
63829004570Smrg        Fatal("unable to set DISPLAY");
63929004570Smrg}
640a73027baSmrg
64129004570Smrgstatic void
64229004570Smrgverror(const char *fmt, va_list ap)
64329004570Smrg{
64429004570Smrg    fprintf(stderr, "%s: ", program);
64529004570Smrg    vfprintf(stderr, fmt, ap);
64629004570Smrg    fprintf(stderr, ": %s\n", strerror(errno));
64729004570Smrg}
64829004570Smrg
64929004570Smrgstatic void
65029004570Smrgverrorx(const char *fmt, va_list ap)
65129004570Smrg{
65229004570Smrg    fprintf(stderr, "%s: ", program);
65329004570Smrg    vfprintf(stderr, fmt, ap);
65429004570Smrg    fprintf(stderr, "\n");
65529004570Smrg}
65629004570Smrg
65729004570Smrgstatic void
65829004570SmrgFatal(const char *fmt, ...)
65929004570Smrg{
66029004570Smrg    va_list ap;
66129004570Smrg    va_start(ap, fmt);
66229004570Smrg    verror(fmt, ap);
66329004570Smrg    va_end(ap);
66429004570Smrg    exit(EXIT_FAILURE);
66529004570Smrg}
66629004570Smrg
66729004570Smrgstatic void
66829004570SmrgFatalx(const char *fmt, ...)
66929004570Smrg{
67029004570Smrg    va_list ap;
67129004570Smrg    va_start(ap, fmt);
67229004570Smrg    verrorx(fmt, ap);
67329004570Smrg    va_end(ap);
67429004570Smrg    exit(EXIT_FAILURE);
675a73027baSmrg}
676a73027baSmrg
677a73027baSmrgstatic void
67829004570SmrgError(const char *fmt, ...)
679a73027baSmrg{
68029004570Smrg    va_list ap;
68129004570Smrg    va_start(ap, fmt);
68229004570Smrg    verror(fmt, ap);
68329004570Smrg    va_end(ap);
684a73027baSmrg}
685a73027baSmrg
686a73027baSmrgstatic void
68729004570SmrgErrorx(const char *fmt, ...)
688a73027baSmrg{
68929004570Smrg    va_list ap;
69029004570Smrg    va_start(ap, fmt);
69129004570Smrg    verrorx(fmt, ap);
69229004570Smrg    va_end(ap);
693a73027baSmrg}
694