|
|
1.1 root 1: #ifndef lint
2: static char *rcsid_xinit_c = "$XConsortium: xinit.c,v 11.32 88/10/05 09:27:45 jim Exp $";
3: #endif /* lint */
4: #include <X11/copyright.h>
5:
6: /* Copyright Massachusetts Institute of Technology 1986 */
7:
8: #include <X11/Xos.h>
9: #include <X11/Xlib.h>
10: #include <stdio.h>
11: #include <ctype.h>
12: #include <signal.h>
13: #include <sys/resource.h>
14: #ifndef SYSV
15: #include <sys/wait.h>
16: #endif
17: #include <errno.h>
18: extern int sys_nerr;
19: #ifdef hpux
20: #include <sys/utsname.h>
21: #endif
22: #include <setjmp.h>
23:
24: extern char *getenv();
25: extern char **environ;
26: char **newenviron = NULL;
27:
28: #ifndef SHELL
29: #define SHELL "sh"
30: #endif
31:
32: #ifdef macII
33: #define vfork() fork()
34: #endif /* macII */
35:
36: #if defined(SYSV) && !defined(hpux)
37: #define vfork() fork()
38: #endif /* SYSV and not hpux */
39:
40: char *bindir = BINDIR;
41: char *server_names[] = {
42: #ifdef vax /* Digital */
43: "Xqvss Digital monochrome display on Microvax II or III series",
44: "Xqdss Digital color display on Microvax II or III series",
45: #endif
46: #ifdef sun /* Sun */
47: "Xsun Sun monochrome and color displays on Sun 2, 3, or 4 series",
48: #endif
49: #ifdef hpux /* HP */
50: "Xhp HP monochrome and colors displays on 9000/300 series",
51: #endif
52: #ifdef apollo /* Apollo */
53: "Xapollo Apollo monochrome and color displays",
54: #endif
55: #ifdef ibm /* IBM */
56: "Xibm IBM AED, APA, 8514a, megapel, VGA displays on PC/RT",
57: #endif
58: #ifdef macII /* MacII */
59: "XmacII Apple monochrome display on Macintosh II",
60: #endif
61: #ifdef M4310 /* Tektronix Pegasus */
62: "Xpeg Tektronix Pegasus display on 4310",
63: #endif
64: #if defined(vax) || defined(sun) /* Parallax */
65: "Xplx Parallax color and video graphics controller",
66: #endif
67: NULL};
68:
69: #ifndef XINITRC
70: #define XINITRC ".xinitrc"
71: #endif
72: char xinitrcbuf[256];
73:
74: #ifndef XSERVERRC
75: #define XSERVERRC ".xserverrc"
76: #endif
77: char xserverrcbuf[256];
78:
79: #define TRUE 1
80: #define FALSE 0
81: #define OK_EXIT 0
82: #define ERR_EXIT 1
83: #ifdef ISOCONN
84: char displayname[100] = ":X0";
85: #else /* ISOCONN */
86: char displayname[100] = "unix";
87: #endif /* ISOCONN */
88: char client_display[100];
89:
90: #ifdef ISOCONN
91: char *default_server = "Xsun";
92: char *default_display = ":X0"; /* choose most efficient */
93: char *default_client[] = {"xt", NULL};
94: #else /* ISOCONN */
95: char *default_server = "X";
96: char *default_display = ":0"; /* choose most efficient */
97: char *default_client[] = {"xterm", "-geometry", "+1+1", "-n", "login", "-display perky:X0", NULL};
98: #endif /* ISOCONN */
99: char *serverargv[100];
100: char *clientargv[100];
101: char **server = serverargv + 2; /* make sure room for sh .xserverrc args */
102: char **client = clientargv + 2; /* make sure room for sh .xinitrc args */
103: char *displayNum;
104: char *program;
105: Display *xd; /* server connection */
106: #ifndef SYSV
107: union wait status;
108: #endif /* SYSV */
109: int serverpid = -1;
110: int clientpid = -1;
111: extern int errno;
112:
113: sigCatch(sig)
114: int sig;
115: {
116: signal(SIGQUIT, SIG_IGN);
117: signal(SIGINT, SIG_IGN);
118: Error("unexpected signal %d\r\n", sig);
119: shutdown(serverpid, clientpid);
120: exit(1);
121: }
122:
123: #ifdef SYSV
124: sigAlarm(sig)
125: int sig;
126: {
127: signal (sig, sigAlarm);
128: }
129: #endif /* SYSV */
130:
131: static Execute (vec)
132: char **vec; /* has room from up above */
133: {
134: execvp (vec[0], vec);
135: if (access (vec[0], R_OK) == 0) {
136: vec--; /* back it up to stuff shell in */
137: vec[0] = SHELL;
138: execvp (vec[0], vec);
139: }
140: return;
141: }
142:
143: main(argc, argv)
144: int argc;
145: register char **argv;
146: {
147: register char **sptr = server;
148: register char **cptr = client;
149: register char **ptr;
150: int pid, i;
151: int client_given = 0, server_given = 0;
152: int client_args_given = 0, server_args_given = 0;
153: int start_of_client_args, start_of_server_args;
154: #ifdef ISOCONN
155: extern char *index();
156: char *cd;
157: #endif /* ISOCONN */
158:
159: program = *argv++;
160: argc--;
161:
162: #ifndef UNIXCONN
163: #ifdef hpux
164: /* Why not use gethostname()? Well, at least on my system, I've had to
165: * make an ugly kernel patch to get a name longer than 8 characters, and
166: * uname() lets me access to the whole string (it smashes release, you
167: * see), whereas gethostname() kindly truncates it for me.
168: */
169: {
170: struct utsname name;
171:
172: uname(&name);
173: strcpy(displayname, name.nodename);
174: }
175: #else
176: gethostname(displayname, sizeof(displayname));
177: #ifdef ISOCONN
178: if ((cd = index(displayname, '.')) != NULL)
179: *cd = '\0';
180: #endif /* ISOCONN */
181: #endif
182: #endif /* UNIXCONN */
183: /*
184: * copy the client args.
185: */
186: if (argc == 0 ||
187: (**argv != '/' && **argv != '.' && !isalpha(**argv))) {
188: for (ptr = default_client; *ptr; )
189: *cptr++ = *ptr++;
190: strcpy(client_display, displayname);
191: strcat(client_display, default_display);
192: *cptr++ = client_display;
193: #ifdef sun
194: /*
195: * If running on a sun, and if WINDOW_PARENT isn't defined,
196: * that means SunWindows isn't running, so we should pass
197: * the -C flag to xterm so that it sets up a console.
198: */
199: if ( getenv("WINDOW_PARENT") == NULL )
200: *cptr++ = "-C";
201: #endif /* sun */
202: } else {
203: client_given = 1;
204: }
205: start_of_client_args = (cptr - client);
206: while (argc && strcmp(*argv, "--")) {
207: client_args_given++;
208: *cptr++ = *argv++;
209: argc--;
210: }
211: *cptr = NULL;
212: if (argc) {
213: argv++;
214: argc--;
215: }
216:
217: /*
218: * Copy the server args.
219: */
220: if (argc == 0 ||
221: (**argv != '/' && **argv != '.' && !isalpha(**argv))) {
222: *sptr++ = default_server;
223: } else {
224: server_given = 1;
225: *sptr++ = *argv++;
226: argc--;
227: }
228: if (argc > 0 && (argv[0][0] == ':' && isdigit(argv[0][1])))
229: displayNum = *argv;
230: else
231: displayNum = *sptr++ = default_display;
232:
233: start_of_server_args = (sptr - server);
234: while (--argc >= 0) {
235: server_args_given++;
236: *sptr++ = *argv++;
237: }
238: *sptr = NULL;
239:
240:
241: strcat(displayname, displayNum);
242:
243: /*
244: * if no client arguments given, check for a startup file and copy
245: * that into the argument list
246: */
247: if (!client_given) {
248: char *cp;
249: Bool required = False;
250:
251: xinitrcbuf[0] = '\0';
252: if ((cp = getenv ("XINITRC")) != NULL) {
253: strcpy (xinitrcbuf, cp);
254: required = True;
255: } else if ((cp = getenv ("HOME")) != NULL) {
256: (void) sprintf (xinitrcbuf, "%s/%s", cp, XINITRC);
257: }
258: if (xinitrcbuf[0]) {
259: if (access (xinitrcbuf, F_OK) == 0) {
260: client += start_of_client_args - 1;
261: client[0] = xinitrcbuf;
262: } else if (required) {
263: fprintf (stderr,
264: "%s: warning, no client init file \"%s\"\n",
265: program, xinitrcbuf);
266: }
267: }
268: }
269:
270: /*
271: * if no server arguments given, check for a startup file and copy
272: * that into the argument list
273: */
274: if (!server_given) {
275: char *cp;
276: Bool required = False;
277:
278: xserverrcbuf[0] = '\0';
279: if ((cp = getenv ("XSERVERRC")) != NULL) {
280: strcpy (xserverrcbuf, cp);
281: required = True;
282: } else if ((cp = getenv ("HOME")) != NULL) {
283: (void) sprintf (xserverrcbuf, "%s/%s", cp, XSERVERRC);
284: }
285: if (xserverrcbuf[0]) {
286: if (access (xserverrcbuf, F_OK) == 0) {
287: server += start_of_server_args - 1;
288: server[0] = xserverrcbuf;
289: } else if (required) {
290: fprintf (stderr,
291: "%s: warning, no server init file \"%s\"\n",
292: program, xserverrcbuf);
293: }
294: }
295: }
296:
297:
298: /*
299: * put the display name into the environment
300: */
301: set_environment ();
302:
303: /*
304: * Start the server and client.
305: */
306: signal(SIGQUIT, sigCatch);
307: signal(SIGINT, sigCatch);
308: #ifdef SYSV
309: signal(SIGALRM, sigAlarm);
310: #endif /* SYSV */
311: if ((serverpid = startServer(server)) > 0
312: && (clientpid = startClient(client)) > 0) {
313: pid = -1;
314: while (pid != clientpid && pid != serverpid)
315: pid = wait(NULL);
316: }
317: signal(SIGQUIT, SIG_IGN);
318: signal(SIGINT, SIG_IGN);
319:
320: shutdown(serverpid, clientpid);
321:
322: if (serverpid < 0 || clientpid < 0)
323: exit(ERR_EXIT);
324: exit(OK_EXIT);
325: }
326:
327:
328: /*
329: * waitforserver - wait for X server to start up
330: */
331:
332: waitforserver(serverpid)
333: int serverpid;
334: {
335: int ncycles = 120; /* # of cycles to wait */
336: int cycles; /* Wait cycle count */
337:
338: #ifdef ISOCONN
339: sleep(2);
340: #endif
341: for (cycles = 0; cycles < ncycles; cycles++) {
342: if (xd = XOpenDisplay(displayname)) {
343: return(TRUE);
344: }
345: else {
346: #define MSG "X server to begin accepting connections"
347: if (!processTimeout (serverpid, 1, MSG))
348: break;
349: #undef MSG
350: }
351: }
352:
353: fprintf (stderr, "giving up.\r\n");
354: return(FALSE);
355: }
356:
357: /*
358: * return TRUE if we timeout waiting for pid to exit, FALSE otherwise.
359: */
360: processTimeout(pid, timeout, string)
361: int pid, timeout;
362: char *string;
363: {
364: int i = 0, pidfound = -1;
365: static char *laststring;
366:
367: for (;;) {
368: #ifdef SYSV
369: alarm(1);
370: if ((pidfound = wait(NULL)) == pid)
371: break;
372: alarm(0);
373: #else /* SYSV */
374: if ((pidfound = wait3(&status, WNOHANG, NULL)) == pid)
375: break;
376: #endif /* SYSV */
377: if (timeout) {
378: if (i == 0 && string != laststring)
379: fprintf(stderr, "\r\nwaiting for %s ", string);
380: else
381: fprintf(stderr, ".");
382: fflush(stderr);
383: }
384: if (timeout)
385: sleep (1);
386: if (++i > timeout)
387: break;
388: }
389: laststring = string;
390: return( pid != pidfound );
391: }
392:
393: Error(fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
394: char *fmt;
395: {
396: extern char *sys_errlist[];
397:
398: fprintf(stderr, "%s: ", program);
399: if (errno > 0 && errno < sys_nerr)
400: fprintf (stderr, "%s (errno %d): ", sys_errlist[errno], errno);
401: fprintf(stderr, fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
402: }
403:
404: Fatal(fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)
405: char *fmt;
406: {
407: Error(fmt, x0,x1,x2,x3,x4,x5,x6,x7,x8,x9);
408: exit(ERR_EXIT);
409: }
410:
411: startServer(server)
412: char *server[];
413: {
414: int serverpid;
415:
416: serverpid = vfork();
417: switch(serverpid) {
418: case 0:
419: close(0);
420: close(1);
421:
422: /*
423: * don't hang on read/write to control tty
424: */
425: #ifdef SIGTTIN
426: (void) signal(SIGTTIN, SIG_IGN);
427: #endif
428: #ifdef SIGTTOU
429: (void) signal(SIGTTOU, SIG_IGN);
430: #endif
431:
432: /*
433: * prevent server from getting sighup from vhangup()
434: * if client is xterm -L
435: */
436: setpgrp(0,getpid());
437:
438: Execute (server);
439: Error ("no server \"%s\" in PATH\n", server[0]);
440: {
441: char **cpp;
442:
443: fprintf (stderr,
444: "\nUse the -- option, or make sure that %s is in your path and\n",
445: bindir);
446: fprintf (stderr,
447: "that \"%s\" is a program or a link to the right type of server\n",
448: server[0]);
449: fprintf (stderr,
450: "for your display. Possible server names include:\n\n");
451: for (cpp = server_names; *cpp; cpp++) {
452: fprintf (stderr, " %s\n", *cpp);
453: }
454: fprintf (stderr, "\n");
455: }
456: exit (ERR_EXIT);
457:
458: break;
459: case -1:
460: break;
461: default:
462: /*
463: * don't nice server
464: */
465: #ifdef PRIO_PROCESS
466: setpriority( PRIO_PROCESS, serverpid, -1 );
467: #endif
468:
469: errno = 0;
470: if (! processTimeout(serverpid, 0, "")) {
471: serverpid = -1;
472: break;
473: }
474: /*
475: * kludge to avoid race with TCP, giving server time to
476: * set his socket options before we try to open it
477: */
478: sleep(5);
479:
480: if (waitforserver(serverpid) == 0) {
481: Error("unable to connect to X server\r\n");
482: shutdown(serverpid, -1);
483: serverpid = -1;
484: }
485: break;
486: }
487:
488: return(serverpid);
489: }
490:
491: startClient(client)
492: char *client[];
493: {
494: int clientpid;
495:
496: if ((clientpid = vfork()) == 0) {
497: setuid(getuid());
498: setpgrp(0, getpid());
499: environ = newenviron;
500: Execute (client);
501: Error ("no program named \"%s\" in PATH\r\n", client[0]);
502: fprintf (stderr,
503: "\nSpecify a program on the command line or make sure that %s\r\n", bindir);
504: fprintf (stderr,
505: "is in your path.\r\n");
506: fprintf (stderr, "\n");
507: exit (ERR_EXIT);
508: }
509: return (clientpid);
510: }
511:
512: #ifdef SYSV
513: #define killpg(pgrp, sig) kill(-(pgrp), sig)
514: #endif /* SYSV */
515:
516: static jmp_buf close_env;
517:
518: static int ignorexio (dpy)
519: Display *dpy;
520: {
521: fprintf (stderr, "%s: connection to X server lost.\r\n", program);
522: longjmp (close_env, 1);
523: return;
524: }
525:
526: static
527: shutdown(serverpid, clientpid)
528: int serverpid, clientpid;
529: {
530: /* have kept display opened, so close it now */
531: if (clientpid > 0) {
532: XSetIOErrorHandler (ignorexio);
533: if (! setjmp(close_env)) {
534: XCloseDisplay(xd);
535: }
536:
537: /* HUP all local clients to allow them to clean up */
538: errno = 0;
539: if ((killpg(clientpid, SIGHUP) != 0) &&
540: (errno != ESRCH))
541: Error("can't send HUP to process group %d\r\n",
542: clientpid);
543: }
544:
545: if (serverpid < 0)
546: return;
547: errno = 0;
548: if (killpg(serverpid, SIGTERM) < 0) {
549: if (errno == EPERM)
550: Fatal("Can't kill X server\r\n");
551: if (errno == ESRCH)
552: return;
553: }
554: if (! processTimeout(serverpid, 10, "X server to shut down")) {
555: fprintf (stderr, "\r\n");
556: return;
557: }
558:
559: fprintf(stderr,
560: "\r\n%s: X server slow to shut down, sending KILL signal.\r\n",
561: program);
562: fflush(stderr);
563: errno = 0;
564: if (killpg(serverpid, SIGKILL) < 0) {
565: if (errno == ESRCH)
566: return;
567: }
568: if (processTimeout(serverpid, 3, "server to die")) {
569: fprintf (stderr, "\r\n");
570: Fatal("Can't kill server\r\n");
571: }
572: fprintf (stderr, "\r\n");
573: return;
574: }
575:
576:
577: /*
578: * make a new copy of environment that has room for DISPLAY
579: */
580:
581: set_environment ()
582: {
583: int nenvvars;
584: char **newPtr, **oldPtr;
585: static char displaybuf[256];
586:
587: /* count number of environment variables */
588: for (oldPtr = environ; *oldPtr; oldPtr++) ;
589:
590: nenvvars = (oldPtr - environ);
591: newenviron = (char **) malloc ((nenvvars + 2) * sizeof(char **));
592: if (!newenviron) {
593: fprintf (stderr,
594: "%s: unable to allocate %d pointers for environment\n",
595: program, nenvvars + 2);
596: exit (1);
597: }
598:
599: /* put DISPLAY=displayname as first element */
600: strcpy (displaybuf, "DISPLAY=");
601: strcpy (displaybuf + 8, displayname);
602: newPtr = newenviron;
603: *newPtr++ = displaybuf;
604:
605: /* copy pointers to other variables */
606: for (oldPtr = environ; *oldPtr; oldPtr++) {
607: if (strncmp (*oldPtr, "DISPLAY=", 8) != 0) {
608: *newPtr++ = *oldPtr;
609: }
610: }
611: *newPtr = NULL;
612: return;
613: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.