xinit.c revision 5c47cad4
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 start_of_client_args, start_of_server_args; 15529004570Smrg struct sigaction sa, si; 15672e81212Smrg#ifdef __APPLE__ 157bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 15829004570Smrg vproc_transaction_t vt; 15972e81212Smrg#endif 16072e81212Smrg#endif 161a73027baSmrg 16229004570Smrg program = *argv++; 16329004570Smrg argc--; 16429004570Smrg /* 16529004570Smrg * copy the client args. 16629004570Smrg */ 16729004570Smrg if (argc == 0 || 16829004570Smrg (**argv != '/' && **argv != '.')) { 16929004570Smrg for (ptr = default_client; *ptr; ) 17029004570Smrg *cptr++ = *ptr++; 17129004570Smrg } else { 17229004570Smrg client_given = 1; 17329004570Smrg } 17429004570Smrg start_of_client_args = (cptr - client); 17529004570Smrg while (argc && strcmp(*argv, "--")) { 1765c47cad4Smrg if (cptr > clientargv + sizeof(clientargv) / sizeof(*clientargv) - 2) 1775c47cad4Smrg Fatalx("too many client arguments"); 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) { 2055c47cad4Smrg if (sptr > serverargv + sizeof(serverargv) / sizeof(*serverargv) - 2) 2065c47cad4Smrg Fatalx("too many server arguments"); 20729004570Smrg *sptr++ = *argv++; 20829004570Smrg } 20929004570Smrg *sptr = NULL; 21029004570Smrg 21129004570Smrg /* 21229004570Smrg * if no client arguments given, check for a startup file and copy 21329004570Smrg * that into the argument list 21429004570Smrg */ 21529004570Smrg if (!client_given) { 21629004570Smrg char *cp; 21729004570Smrg Bool required = False; 21829004570Smrg 21929004570Smrg xinitrcbuf[0] = '\0'; 22029004570Smrg if ((cp = getenv("XINITRC")) != NULL) { 22129004570Smrg snprintf(xinitrcbuf, sizeof(xinitrcbuf), "%s", cp); 22229004570Smrg required = True; 22329004570Smrg } else if ((cp = getenv("HOME")) != NULL) { 22429004570Smrg snprintf(xinitrcbuf, sizeof(xinitrcbuf), 22529004570Smrg "%s/%s", cp, XINITRC); 22629004570Smrg } 22729004570Smrg if (xinitrcbuf[0]) { 22829004570Smrg if (access(xinitrcbuf, F_OK) == 0) { 22929004570Smrg client += start_of_client_args - 1; 23029004570Smrg client[0] = xinitrcbuf; 23129004570Smrg } else if (required) { 23229004570Smrg Error("warning, no client init file \"%s\"", xinitrcbuf); 23329004570Smrg } 23429004570Smrg } 23529004570Smrg } 23629004570Smrg 23729004570Smrg /* 23829004570Smrg * if no server arguments given, check for a startup file and copy 23929004570Smrg * that into the argument list 24029004570Smrg */ 24129004570Smrg if (!server_given) { 24229004570Smrg char *cp; 24329004570Smrg Bool required = False; 24429004570Smrg 24529004570Smrg xserverrcbuf[0] = '\0'; 24629004570Smrg if ((cp = getenv("XSERVERRC")) != NULL) { 24729004570Smrg snprintf(xserverrcbuf, sizeof(xserverrcbuf), "%s", cp); 24829004570Smrg required = True; 24929004570Smrg } else if ((cp = getenv("HOME")) != NULL) { 25029004570Smrg snprintf(xserverrcbuf, sizeof(xserverrcbuf), 25129004570Smrg "%s/%s", cp, XSERVERRC); 25229004570Smrg } 25329004570Smrg if (xserverrcbuf[0]) { 25429004570Smrg if (access(xserverrcbuf, F_OK) == 0) { 25529004570Smrg server += start_of_server_args - 1; 25629004570Smrg server[0] = xserverrcbuf; 25729004570Smrg } else if (required) { 25829004570Smrg Error("warning, no server init file \"%s\"", xserverrcbuf); 25929004570Smrg } 26029004570Smrg } 26129004570Smrg } 26229004570Smrg 26329004570Smrg /* 26429004570Smrg * Start the server and client. 26529004570Smrg */ 26629004570Smrg signal(SIGCHLD, SIG_DFL); /* Insurance */ 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); 28772e81212Smrg 28872e81212Smrg#ifdef __APPLE__ 289bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 29029004570Smrg vt = vproc_transaction_begin(NULL); 29172e81212Smrg#endif 29272e81212Smrg#endif 29372e81212Smrg 29429004570Smrg if (startServer(server) > 0 29529004570Smrg && startClient(client) > 0) { 29629004570Smrg pid = -1; 29729004570Smrg while (pid != clientpid && pid != serverpid 29829004570Smrg && gotSignal == 0 29929004570Smrg ) 30029004570Smrg pid = wait(NULL); 30129004570Smrg } 30272e81212Smrg 30372e81212Smrg#ifdef __APPLE__ 304bf4a254eSmrg#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060 30529004570Smrg vproc_transaction_end(NULL, vt); 30672e81212Smrg#endif 30772e81212Smrg#endif 30872e81212Smrg 30929004570Smrg signal(SIGTERM, SIG_IGN); 31029004570Smrg signal(SIGQUIT, SIG_IGN); 31129004570Smrg signal(SIGINT, SIG_IGN); 31229004570Smrg signal(SIGHUP, SIG_IGN); 31329004570Smrg signal(SIGPIPE, SIG_IGN); 314a73027baSmrg 31529004570Smrg shutdown(); 316a73027baSmrg 31729004570Smrg if (gotSignal != 0) { 31829004570Smrg Errorx("unexpected signal %d", gotSignal); 31929004570Smrg exit(EXIT_FAILURE); 32029004570Smrg } 321a73027baSmrg 32229004570Smrg if (serverpid < 0) 32329004570Smrg Fatalx("server error"); 32429004570Smrg if (clientpid < 0) 32529004570Smrg Fatalx("client error"); 32629004570Smrg exit(EXIT_SUCCESS); 327a73027baSmrg} 328a73027baSmrg 329a73027baSmrg 330a73027baSmrg/* 33129004570Smrg * waitforserver - wait for X server to start up 332a73027baSmrg */ 333a73027baSmrgstatic Bool 334a73027baSmrgwaitforserver(void) 335a73027baSmrg{ 33629004570Smrg int ncycles = 120; /* # of cycles to wait */ 33729004570Smrg int cycles; /* Wait cycle count */ 338a73027baSmrg 33972e81212Smrg#ifdef __APPLE__ 34029004570Smrg /* For Apple, we don't get signaled by the server when it's ready, so we just 34129004570Smrg * want to sleep now since we're going to sleep later anyways and this allows us 34229004570Smrg * to avoid the awkard, "why is there an error message in the log" questions 34329004570Smrg * from users. 34429004570Smrg */ 34529004570Smrg 34629004570Smrg sleep(2); 34729004570Smrg#endif 34829004570Smrg 34929004570Smrg for (cycles = 0; cycles < ncycles; cycles++) { 35029004570Smrg if ((xd = XOpenDisplay(displayNum))) { 35129004570Smrg return(TRUE); 35229004570Smrg } 35329004570Smrg else { 35429004570Smrg if (!processTimeout(1, "X server to begin accepting connections")) 35529004570Smrg break; 35629004570Smrg } 35729004570Smrg } 35872e81212Smrg 35929004570Smrg Errorx("giving up"); 36072e81212Smrg 36129004570Smrg return(FALSE); 362a73027baSmrg} 363a73027baSmrg 364a73027baSmrg/* 365a73027baSmrg * return TRUE if we timeout waiting for pid to exit, FALSE otherwise. 366a73027baSmrg */ 367a73027baSmrgstatic Bool 36836ffeb23SmrgprocessTimeout(int timeout, const char *string) 369a73027baSmrg{ 37036ffeb23Smrg int i = 0; 37136ffeb23Smrg pid_t pidfound = -1; 37236ffeb23Smrg static const 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 39336ffeb23Smrgstatic pid_t 39441667ceaSmrgstartServer(char *server_argv[]) 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()); 42641667ceaSmrg Execute(server_argv); 42729004570Smrg 42841667ceaSmrg Error("unable to run server \"%s\"", server_argv[0]); 42929004570Smrg 43029004570Smrg fprintf(stderr, "Use the -- option, or make sure that %s is in your path and\n", bindir); 43141667ceaSmrg fprintf(stderr, "that \"%s\" is a program or a link to the right type of server\n", server_argv[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 55936ffeb23Smrgstatic pid_t 56041667ceaSmrgstartClient(char *client_argv[]) 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()); 57241667ceaSmrg Execute(client_argv); 57341667ceaSmrg Error("Unable to run program \"%s\"", client_argv[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"); 63236ffeb23Smrg#ifdef __sun 63336ffeb23Smrg else { 63436ffeb23Smrg /* Restore keyboard mode. */ 63536ffeb23Smrg serverpid = fork(); 63636ffeb23Smrg switch (serverpid) { 63736ffeb23Smrg case 0: 63836ffeb23Smrg execlp ("kbd_mode", "kbd_mode", "-a", NULL); 63936ffeb23Smrg Fatal("Unable to run program \"%s\"", "kbd_mode"); 64036ffeb23Smrg break; 64136ffeb23Smrg 642d712a854Smrg case -1: 64336ffeb23Smrg Error("fork failed"); 64436ffeb23Smrg break; 64536ffeb23Smrg 64636ffeb23Smrg default: 64736ffeb23Smrg fprintf (stderr, "\r\nRestoring keyboard mode\r\n"); 64836ffeb23Smrg processTimeout(1, "kbd_mode"); 64936ffeb23Smrg } 65036ffeb23Smrg } 65136ffeb23Smrg#endif 65229004570Smrg} 65329004570Smrg 65429004570Smrgstatic void 655a73027baSmrgset_environment(void) 656a73027baSmrg{ 65729004570Smrg if (setenv("DISPLAY", displayNum, TRUE) == -1) 65829004570Smrg Fatal("unable to set DISPLAY"); 65929004570Smrg} 660a73027baSmrg 66136ffeb23Smrgstatic void _X_ATTRIBUTE_PRINTF(1,0) 66229004570Smrgverror(const char *fmt, va_list ap) 66329004570Smrg{ 66429004570Smrg fprintf(stderr, "%s: ", program); 66529004570Smrg vfprintf(stderr, fmt, ap); 66629004570Smrg fprintf(stderr, ": %s\n", strerror(errno)); 66729004570Smrg} 66829004570Smrg 66936ffeb23Smrgstatic void _X_ATTRIBUTE_PRINTF(1,0) 67029004570Smrgverrorx(const char *fmt, va_list ap) 67129004570Smrg{ 67229004570Smrg fprintf(stderr, "%s: ", program); 67329004570Smrg vfprintf(stderr, fmt, ap); 67429004570Smrg fprintf(stderr, "\n"); 67529004570Smrg} 67629004570Smrg 67729004570Smrgstatic void 67829004570SmrgFatal(const char *fmt, ...) 67929004570Smrg{ 68029004570Smrg va_list ap; 68129004570Smrg va_start(ap, fmt); 68229004570Smrg verror(fmt, ap); 68329004570Smrg va_end(ap); 68429004570Smrg exit(EXIT_FAILURE); 68529004570Smrg} 68629004570Smrg 68729004570Smrgstatic void 68829004570SmrgFatalx(const char *fmt, ...) 68929004570Smrg{ 69029004570Smrg va_list ap; 69129004570Smrg va_start(ap, fmt); 69229004570Smrg verrorx(fmt, ap); 69329004570Smrg va_end(ap); 69429004570Smrg exit(EXIT_FAILURE); 695a73027baSmrg} 696a73027baSmrg 697a73027baSmrgstatic void 69829004570SmrgError(const char *fmt, ...) 699a73027baSmrg{ 70029004570Smrg va_list ap; 70129004570Smrg va_start(ap, fmt); 70229004570Smrg verror(fmt, ap); 70329004570Smrg va_end(ap); 704a73027baSmrg} 705a73027baSmrg 706a73027baSmrgstatic void 70729004570SmrgErrorx(const char *fmt, ...) 708a73027baSmrg{ 70929004570Smrg va_list ap; 71029004570Smrg va_start(ap, fmt); 71129004570Smrg verrorx(fmt, ap); 71229004570Smrg va_end(ap); 713a73027baSmrg} 714