summaryrefslogtreecommitdiff
path: root/xinit.c
diff options
context:
space:
mode:
authorKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:54 +0000
committerKaleb Keithley <kaleb@freedesktop.org>2003-11-14 15:54:54 +0000
commitf18e25ab379836d0885660ad9c42ed588b1152b8 (patch)
tree727c1863369990c7f3acf97d37b29e434a8a99e0 /xinit.c
R6.6 is the Xorg base-lineXORG-MAIN
Diffstat (limited to 'xinit.c')
-rw-r--r--xinit.c638
1 files changed, 638 insertions, 0 deletions
diff --git a/xinit.c b/xinit.c
new file mode 100644
index 0000000..30d8c19
--- /dev/null
+++ b/xinit.c
@@ -0,0 +1,638 @@
+/* $Xorg: xinit.c,v 1.5 2001/02/09 02:05:49 xorgcvs Exp $ */
+
+/*
+
+Copyright 1986, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+
+*/
+
+#include <X11/Xlib.h>
+#include <X11/Xos.h>
+#include <X11/Xmu/SysUtil.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#ifndef SYSV
+#include <sys/wait.h>
+#endif
+#include <errno.h>
+#include <setjmp.h>
+
+#ifndef X_NOT_STDC_ENV
+#include <stdlib.h>
+#else
+extern char *getenv();
+#endif
+extern char **environ;
+char **newenviron = NULL;
+
+#ifndef SHELL
+#define SHELL "sh"
+#endif
+
+#ifndef HAS_VFORK
+#define vfork() fork()
+#else
+#if defined(sun) && !defined(SVR4)
+#include <vfork.h>
+#endif
+#endif
+
+/* A/UX setpgid incorrectly removes the controlling terminal.
+ Per Posix, only setsid should do that. */
+#if !defined(X_NOT_POSIX) && !defined(macII)
+#define setpgrp setpgid
+#endif
+
+char *bindir = BINDIR;
+char *server_names[] = {
+#if defined(ultrix) && defined(mips)
+ "Xdec Digital color display on DECstation",
+#endif
+#ifdef sun /* Sun */
+ "Xsun Sun BW2, CG2, CG3, CG4, or CG6 on Sun 2, 3, 4, or 386i",
+ "Xsunmono Sun BW2 on Sun 2, 3, 4, or 386i ",
+ "Xsun24 Sun BW2, CG2, CG3, CG4, CG6, or CG8 on Sun 4",
+#endif
+#ifdef hpux /* HP */
+ "Xhp HP monochrome and colors displays on 9000/300 series",
+#endif
+#ifdef ibm /* IBM */
+ "Xibm IBM AED, APA, 8514a, megapel, VGA displays on PC/RT",
+#endif
+#ifdef macII /* MacII */
+ "XmacII Apple monochrome display on Macintosh II",
+#endif
+#ifdef XFREE86
+ "XF86_SVGA SVGA color display on i386 PC",
+ "XF86_Mono monochrome display on i386 PC",
+ "XF86_VGA16 16 color VGA display on i386 PC",
+ "XF86_S3 S3 color display on i386 PC",
+ "XF86_8514 IBM 8514/A color display on i386 PC",
+ "XF86_Mach8 ATI Mach8 color display on i386 PC",
+ "XF86_Mach32 ATI Mach32 color display on i386 PC",
+ "XF86_Mach64 ATI Mach64 color display on i386 PC",
+ "XF86_P9000 Weitek P9000 color display on i386 PC",
+ "XF86_AGX IIT AGX color display on i386 PC",
+ "XF86_W32 Tseng ET4000/W32 color display on i386 PC",
+ "XF86_I128 #9 I128 color display on i386 PC",
+#endif
+ NULL};
+
+#ifndef XINITRC
+#define XINITRC ".xinitrc"
+#endif
+char xinitrcbuf[256];
+
+#ifndef XSERVERRC
+#define XSERVERRC ".xserverrc"
+#endif
+char xserverrcbuf[256];
+
+#define TRUE 1
+#define FALSE 0
+#define OK_EXIT 0
+#define ERR_EXIT 1
+
+char *default_server = "X";
+char *default_display = ":0"; /* choose most efficient */
+char *default_client[] = {"xterm", "-geometry", "+1+1", "-n", "login", NULL};
+char *serverargv[100];
+char *clientargv[100];
+char **server = serverargv + 2; /* make sure room for sh .xserverrc args */
+char **client = clientargv + 2; /* make sure room for sh .xinitrc args */
+char *displayNum;
+char *program;
+Display *xd; /* server connection */
+#ifndef SYSV
+#if defined(SVR4) || defined(_POSIX_SOURCE) || defined(CSRG_BASED)
+int status;
+#else
+union wait status;
+#endif
+#endif /* SYSV */
+int serverpid = -1;
+int clientpid = -1;
+
+#ifdef X_NOT_STDC_ENV
+extern int errno;
+#endif
+
+
+static void shutdown();
+static void set_environment();
+
+#ifdef SIGNALRETURNSINT
+#define SIGVAL int
+#else
+#define SIGVAL void
+#endif
+
+SIGVAL sigCatch(sig)
+ int sig;
+{
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+ Error("unexpected signal %d\r\n", sig);
+ shutdown();
+ exit(1);
+}
+
+SIGVAL sigAlarm(sig)
+ int sig;
+{
+#if defined(SYSV) || defined(SVR4) || defined(linux)
+ signal (sig, sigAlarm);
+#endif
+}
+
+SIGVAL
+sigUsr1(sig)
+ int sig;
+{
+#if defined(SYSV) || defined(SVR4) || defined(linux)
+ signal (sig, sigUsr1);
+#endif
+}
+
+static void Execute (vec)
+ char **vec; /* has room from up above */
+{
+ execvp (vec[0], vec);
+ if (access (vec[0], R_OK) == 0) {
+ vec--; /* back it up to stuff shell in */
+ vec[0] = SHELL;
+ execvp (vec[0], vec);
+ }
+ return;
+}
+
+main(argc, argv)
+int argc;
+register char **argv;
+{
+ register char **sptr = server;
+ register char **cptr = client;
+ register char **ptr;
+ int pid;
+ int client_given = 0, server_given = 0;
+ int client_args_given = 0, server_args_given = 0;
+ int start_of_client_args, start_of_server_args;
+
+ program = *argv++;
+ argc--;
+
+ /*
+ * copy the client args.
+ */
+ if (argc == 0 ||
+ (**argv != '/' && **argv != '.')) {
+ for (ptr = default_client; *ptr; )
+ *cptr++ = *ptr++;
+#ifdef sun
+ /*
+ * If running on a sun, and if WINDOW_PARENT isn't defined,
+ * that means SunWindows isn't running, so we should pass
+ * the -C flag to xterm so that it sets up a console.
+ */
+ if ( getenv("WINDOW_PARENT") == NULL )
+ *cptr++ = "-C";
+#endif /* sun */
+ } else {
+ client_given = 1;
+ }
+ start_of_client_args = (cptr - client);
+ while (argc && strcmp(*argv, "--")) {
+ client_args_given++;
+ *cptr++ = *argv++;
+ argc--;
+ }
+ *cptr = NULL;
+ if (argc) {
+ argv++;
+ argc--;
+ }
+
+ /*
+ * Copy the server args.
+ */
+ if (argc == 0 ||
+ (**argv != '/' && **argv != '.')) {
+ *sptr++ = default_server;
+ } else {
+ server_given = 1;
+ *sptr++ = *argv++;
+ argc--;
+ }
+ if (argc > 0 && (argv[0][0] == ':' && isdigit(argv[0][1])))
+ displayNum = *argv;
+ else
+ displayNum = *sptr++ = default_display;
+
+ start_of_server_args = (sptr - server);
+ while (--argc >= 0) {
+ server_args_given++;
+ *sptr++ = *argv++;
+ }
+ *sptr = NULL;
+
+ /*
+ * if no client arguments given, check for a startup file and copy
+ * that into the argument list
+ */
+ if (!client_given) {
+ char *cp;
+ Bool required = False;
+
+ xinitrcbuf[0] = '\0';
+ if ((cp = getenv ("XINITRC")) != NULL) {
+ strcpy (xinitrcbuf, cp);
+ required = True;
+ } else if ((cp = getenv ("HOME")) != NULL) {
+ (void) sprintf (xinitrcbuf, "%s/%s", cp, XINITRC);
+ }
+ if (xinitrcbuf[0]) {
+ if (access (xinitrcbuf, F_OK) == 0) {
+ client += start_of_client_args - 1;
+ client[0] = xinitrcbuf;
+ } else if (required) {
+ fprintf (stderr,
+ "%s: warning, no client init file \"%s\"\n",
+ program, xinitrcbuf);
+ }
+ }
+ }
+
+ /*
+ * if no server arguments given, check for a startup file and copy
+ * that into the argument list
+ */
+ if (!server_given) {
+ char *cp;
+ Bool required = False;
+
+ xserverrcbuf[0] = '\0';
+ if ((cp = getenv ("XSERVERRC")) != NULL) {
+ strcpy (xserverrcbuf, cp);
+ required = True;
+ } else if ((cp = getenv ("HOME")) != NULL) {
+ (void) sprintf (xserverrcbuf, "%s/%s", cp, XSERVERRC);
+ }
+ if (xserverrcbuf[0]) {
+ if (access (xserverrcbuf, F_OK) == 0) {
+ server += start_of_server_args - 1;
+ server[0] = xserverrcbuf;
+ } else if (required) {
+ fprintf (stderr,
+ "%s: warning, no server init file \"%s\"\n",
+ program, xserverrcbuf);
+ }
+ }
+ }
+
+
+ /*
+ * put the display name into the environment
+ */
+ set_environment ();
+
+ /*
+ * Start the server and client.
+ */
+ signal(SIGQUIT, sigCatch);
+ signal(SIGINT, sigCatch);
+ signal(SIGHUP, sigCatch);
+ signal(SIGPIPE, sigCatch);
+ signal(SIGALRM, sigAlarm);
+ signal(SIGUSR1, sigUsr1);
+ if (startServer(server) > 0
+ && startClient(client) > 0) {
+ pid = -1;
+ while (pid != clientpid && pid != serverpid)
+ pid = wait(NULL);
+ }
+ signal(SIGQUIT, SIG_IGN);
+ signal(SIGINT, SIG_IGN);
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGPIPE, SIG_IGN);
+
+ shutdown();
+
+ if (serverpid < 0 )
+ Fatal("Server error.\n");
+ if (clientpid < 0)
+ Fatal("Client error.\n");
+ exit(OK_EXIT);
+}
+
+
+/*
+ * waitforserver - wait for X server to start up
+ */
+
+waitforserver()
+{
+ int ncycles = 120; /* # of cycles to wait */
+ int cycles; /* Wait cycle count */
+
+ for (cycles = 0; cycles < ncycles; cycles++) {
+ if ((xd = XOpenDisplay(displayNum))) {
+ return(TRUE);
+ }
+ else {
+#define MSG "X server to begin accepting connections"
+ if (!processTimeout (1, MSG))
+ break;
+#undef MSG
+ }
+ }
+
+ fprintf (stderr, "giving up.\r\n");
+ return(FALSE);
+}
+
+/*
+ * return TRUE if we timeout waiting for pid to exit, FALSE otherwise.
+ */
+processTimeout(timeout, string)
+ int timeout;
+ char *string;
+{
+ int i = 0, pidfound = -1;
+ static char *laststring;
+
+ for (;;) {
+#ifdef SYSV
+ alarm(1);
+ if ((pidfound = wait(NULL)) == serverpid)
+ break;
+ alarm(0);
+#else /* SYSV */
+#if defined(SVR4) || defined(_POSIX_SOURCE)
+ if ((pidfound = waitpid(serverpid, &status, WNOHANG)) == serverpid)
+ break;
+#else
+ if ((pidfound = wait3(&status, WNOHANG, NULL)) == serverpid)
+ break;
+#endif
+#endif /* SYSV */
+ if (timeout) {
+ if (i == 0 && string != laststring)
+ fprintf(stderr, "\r\nwaiting for %s ", string);
+ else
+ fprintf(stderr, ".");
+ fflush(stderr);
+ }
+ if (timeout)
+ sleep (1);
+ if (++i > timeout)
+ break;
+ }
+ if ( i > 0 ) fputc( '\n', stderr ); /* tidy up after message */
+ laststring = string;
+ return( serverpid != pidfound );
+}
+
+startServer(server)
+ char *server[];
+{
+ serverpid = vfork();
+ switch(serverpid) {
+ case 0:
+ /*
+ * don't hang on read/write to control tty
+ */
+#ifdef SIGTTIN
+ (void) signal(SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+ (void) signal(SIGTTOU, SIG_IGN);
+#endif
+ /*
+ * ignore SIGUSR1 in child. The server
+ * will notice this and send SIGUSR1 back
+ * at xinit when ready to accept connections
+ */
+ (void) signal(SIGUSR1, SIG_IGN);
+ /*
+ * prevent server from getting sighup from vhangup()
+ * if client is xterm -L
+ */
+ setpgrp(0,getpid());
+
+ Execute (server);
+ Error ("no server \"%s\" in PATH\n", server[0]);
+ {
+ char **cpp;
+
+ fprintf (stderr,
+"\nUse the -- option, or make sure that %s is in your path and\n",
+ bindir);
+ fprintf (stderr,
+"that \"%s\" is a program or a link to the right type of server\n",
+ server[0]);
+ fprintf (stderr,
+"for your display. Possible server names include:\n\n");
+ for (cpp = server_names; *cpp; cpp++) {
+ fprintf (stderr, " %s\n", *cpp);
+ }
+ fprintf (stderr, "\n");
+ }
+ exit (ERR_EXIT);
+
+ break;
+ case -1:
+ break;
+ default:
+ /*
+ * don't nice server
+ */
+#ifdef PRIO_PROCESS
+ setpriority( PRIO_PROCESS, serverpid, -1 );
+#endif
+
+ errno = 0;
+ if (! processTimeout(0, "")) {
+ serverpid = -1;
+ break;
+ }
+ /*
+ * kludge to avoid race with TCP, giving server time to
+ * set his socket options before we try to open it,
+ * either use the 15 second timeout, or await SIGUSR1.
+ *
+ * If your machine is substantially slower than 15 seconds,
+ * you can easily adjust this value.
+ */
+ alarm (15);
+ pause ();
+ alarm (0);
+
+ if (waitforserver() == 0) {
+ Error("unable to connect to X server\r\n");
+ shutdown();
+ serverpid = -1;
+ }
+ break;
+ }
+
+ return(serverpid);
+}
+
+startClient(client)
+ char *client[];
+{
+ if ((clientpid = vfork()) == 0) {
+ setuid(getuid());
+ setpgrp(0, getpid());
+ environ = newenviron;
+ Execute (client);
+ Error ("no program named \"%s\" in PATH\r\n", client[0]);
+ fprintf (stderr,
+"\nSpecify a program on the command line or make sure that %s\r\n", bindir);
+ fprintf (stderr,
+"is in your path.\r\n");
+ fprintf (stderr, "\n");
+ exit (ERR_EXIT);
+ }
+ return (clientpid);
+}
+
+#if !defined(X_NOT_POSIX) || defined(SYSV)
+#define killpg(pgrp, sig) kill(-(pgrp), sig)
+#endif
+
+static jmp_buf close_env;
+
+static int ignorexio (dpy)
+ Display *dpy;
+{
+ fprintf (stderr, "%s: connection to X server lost.\r\n", program);
+ longjmp (close_env, 1);
+ /*NOTREACHED*/
+}
+
+static
+void shutdown()
+{
+ /* have kept display opened, so close it now */
+ if (clientpid > 0) {
+ XSetIOErrorHandler (ignorexio);
+ if (! setjmp(close_env)) {
+ XCloseDisplay(xd);
+ }
+
+ /* HUP all local clients to allow them to clean up */
+ errno = 0;
+ if ((killpg(clientpid, SIGHUP) != 0) &&
+ (errno != ESRCH))
+ Error("can't send HUP to process group %d\r\n",
+ clientpid);
+ }
+
+ if (serverpid < 0)
+ return;
+ errno = 0;
+ if (killpg(serverpid, SIGTERM) < 0) {
+ if (errno == EPERM)
+ Fatal("Can't kill X server\r\n");
+ if (errno == ESRCH)
+ return;
+ }
+ if (! processTimeout(10, "X server to shut down")) {
+ fprintf (stderr, "\r\n");
+ return;
+ }
+
+ fprintf(stderr,
+ "\r\n%s: X server slow to shut down, sending KILL signal.\r\n",
+ program);
+ fflush(stderr);
+ errno = 0;
+ if (killpg(serverpid, SIGKILL) < 0) {
+ if (errno == ESRCH)
+ return;
+ }
+ if (processTimeout(3, "server to die")) {
+ fprintf (stderr, "\r\n");
+ Fatal("Can't kill server\r\n");
+ }
+ fprintf (stderr, "\r\n");
+ return;
+}
+
+
+/*
+ * make a new copy of environment that has room for DISPLAY
+ */
+
+static void set_environment ()
+{
+ int nenvvars;
+ char **newPtr, **oldPtr;
+ static char displaybuf[256];
+
+ /* count number of environment variables */
+ for (oldPtr = environ; *oldPtr; oldPtr++) ;
+
+ nenvvars = (oldPtr - environ);
+ newenviron = (char **) malloc ((nenvvars + 2) * sizeof(char **));
+ if (!newenviron) {
+ fprintf (stderr,
+ "%s: unable to allocate %d pointers for environment\n",
+ program, nenvvars + 2);
+ exit (1);
+ }
+
+ /* put DISPLAY=displayname as first element */
+ strcpy (displaybuf, "DISPLAY=");
+ strcpy (displaybuf + 8, displayNum);
+ newPtr = newenviron;
+ *newPtr++ = displaybuf;
+
+ /* copy pointers to other variables */
+ for (oldPtr = environ; *oldPtr; oldPtr++) {
+ if (strncmp (*oldPtr, "DISPLAY=", 8) != 0) {
+ *newPtr++ = *oldPtr;
+ }
+ }
+ *newPtr = NULL;
+ return;
+}
+
+Fatal(fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
+ char *fmt;
+{
+ Error(fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
+ exit(ERR_EXIT);
+}
+
+Error(fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
+ char *fmt;
+{
+ fprintf(stderr, "%s: ", program);
+ fprintf (stderr, "%s (errno %d): ", strerror(errno), errno);
+ fprintf(stderr, fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
+}