struct winsize ws;
TTYSIZE_STRUCT ts;
spawn(void)/* *  Inits pty and tty and forks a login process. *  Does not close fd Xsocket. *  If slave, the pty named in passedPty is already open for use */{    register TScreen *screen = &term->screen;    int Xsocket = ConnectionNumber(screen->display);    int tty = -1;    struct termio tio;    int status;    char termcap[TERMCAP_SIZE], newtc[TERMCAP_SIZE];    char *TermName = NULL;    char *ptr, *shname, buf[64];    int i, no_dev_tty = FALSE, envsize;    char *dev_tty_name = (char *) 0;    struct winsize ws;    int pgrp = getpid();    char numbuf[12], **envnew;    screen->uid = getuid();    screen->gid = getgid();    if (am_slave >= 0) {	screen->respond = am_slave;	ptydev[strlen(ptydev) - 2] =	    ttydev[strlen(ttydev) - 2] = passedPty[0];	ptydev[strlen(ptydev) - 1] =	    ttydev[strlen(ttydev) - 1] = passedPty[1];	setgid(screen->gid);	setuid(screen->uid);    } else {	Bool tty_got_hung;	/*	 * Sometimes /dev/tty hangs on open (as in the case of a pty	 * that has gone away).  Simply make up some reasonable	 * defaults.	 */	signal(SIGALRM, hungtty);	alarm(2);		/* alarm(1) might return too soon */	if (!setjmp(env)) {	    tty = open("/dev/tty", O_RDWR);	    alarm(0);	    tty_got_hung = False;	} else {	    tty_got_hung = True;	    tty = -1;	    errno = ENXIO;	}	signal(SIGALRM, SIG_DFL);	/*	 * Check results and ignore current control terminal if	 * necessary.  ENXIO is what is normally returned if there is	 * no controlling terminal, but some systems (e.g. SunOS 4.0)	 * seem to return EIO.  Solaris 2.3 is said to return EINVAL.	 */	if (tty < 0) {	    if (tty_got_hung || errno == ENXIO || errno == EIO ||		errno == EINVAL || errno == ENOTTY) {		no_dev_tty = TRUE;		tio = d_tio;	    } else {		SysError(ERROR_OPDEVTTY);	    }	} else {	    /* Get a copy of the current terminal's state,	     * if we can.  Some systems (e.g., SVR4 and MacII)	     * may not have a controlling terminal at this point	     * if started directly from xdm or xinit,	     * in which case we just use the defaults as above.	     */	    if (ioctl(tty, TCGETA, &tio) == -1)		tio = d_tio;	    close(tty);	    /* tty is no longer an open fd! */	    tty = -1;	}	if (get_pty(&screen->respond)) {	    /*  no ptys! */	    exit(ERROR_PTYS);	}    }    /* avoid double MapWindow requests */    XtSetMappedWhenManaged(XtParent(CURRENT_EMU(screen)), False);    wm_delete_window = XInternAtom(XtDisplay(toplevel), "WM_DELETE_WINDOW",				   False);    if (!TEK4014_ACTIVE(screen))	VTInit();		/* realize now so know window size for tty driver */    if (Console) {	/*	 * Inform any running xconsole program	 * that we are going to steal the console.	 */	XmuGetHostname(mit_console_name + MIT_CONSOLE_LEN, 255);	mit_console = XInternAtom(screen->display, mit_console_name, False);	/* the user told us to be the console, so we can use CurrentTime */	XtOwnSelection(XtParent(CURRENT_EMU(screen)),		       mit_console, CurrentTime,		       ConvertConsoleSelection, NULL, NULL);    }#if OPT_TEK4014    if (screen->TekEmu) {	envnew = tekterm;	ptr = newtc;    } else#endif    {	envnew = vtterm;	ptr = termcap;    }    /*     * This used to exit if no termcap entry was found for the specified     * terminal name.  That's a little unfriendly, so instead we'll allow     * the program to proceed (but not to set $TERMCAP) if the termcap     * entry is not found.     */    get_termcap(TermName = resource.term_name, ptr, newtc);    /*     * This block is invoked only if there was no terminal name specified     * by the command-line option "-tn".     */    if (!TermName) {	TermName = *envnew;	while (*envnew != NULL) {	    if (get_termcap(*envnew, ptr, newtc)) {		TermName = *envnew;		break;	    }	    envnew++;	}    }    /* tell tty how big window is */#if OPT_TEK4014    if (TEK4014_ACTIVE(screen)) {	ws.ws_row = 38;	ws.ws_col = 81;	ws.ws_xpixel = TFullWidth(screen);	ws.ws_ypixel = TFullHeight(screen);    } else#endif    {	ws.ws_row = screen->max_row + 1;	ws.ws_col = screen->max_col + 1;	ws.ws_xpixel = FullWidth(screen);	ws.ws_ypixel = FullHeight(screen);    }    if (am_slave < 0) {	char sema[40];	HEV sev;	/* start a child process	 * use an event sema for sync	 */	sprintf(sema, "\\SEM32\\xterm%s", &ptydev[8]);	if (DosCreateEventSem(sema, &sev, DC_SEM_SHARED, FALSE))	    SysError(ERROR_FORK);	switch ((screen->pid = fork())) {	case -1:		/* error */	    SysError(ERROR_FORK);	default:		/* parent */	    whoami = THE_PARENT;	    DosWaitEventSem(sev, 1000L);	    DosCloseEventSem(sev);	    break;	case 0:		/* child */	    whoami = THE_CHILD;/*debug fclose(confd);opencons();*/	    /* we don't need the socket, or the pty master anymore */	    close(ConnectionNumber(screen->display));	    close(screen->respond);	    /* Now is the time to set up our process group and	     * open up the pty slave.	     */	    if ((tty = open(ttydev, O_RDWR)) < 0) {		/* dumm gelaufen */		fprintf(stderr, "Cannot open slave side of PTY\n");		exit(1);	    }	    /* use the same tty name that everyone else will use	     * (from ttyname)	     */#ifdef EMXNOTBOGUS	    if ((ptr = ttyname(tty)) != 0) {		/* it may be bigger */		ttydev = realloc(ttydev,				 (unsigned) (strlen(ptr) + 1));		if (ttydev == NULL) {		    SysError(ERROR_SPREALLOC);		}		(void) strcpy(ttydev, ptr);	    }#else	    ptr = ttydev;#endif	    /* for safety: enable DUPs */	    ptioctl(tty, XTY_ENADUP, 0);	    /* change ownership of tty to real group and user id */	    set_owner(ttydev, screen->uid, screen->gid,		      (resource.messages ? 0622 : 0600));	    /* for the xf86sup-pty, we set the pty to bypass: OS/2 does	     * not have a line discipline structure	     */	    {		struct termio t, t1;		if (ptioctl(tty, TCGETA, (char *) &t) < 0)		    t = d_tio;		t.c_iflag = ICRNL;		t.c_oflag = OPOST | ONLCR;		t.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK;		/* ignore error code, user will see it :-) */		ptioctl(tty, TCSETA, (char *) &t);		/* set the console mode */		if (Console) {		    int on = 1;		    if (ioctl(tty, TIOCCONS, (char *) &on) == -1)			fprintf(stderr, "%s: cannot open console\n", xterm_name);		}	    }	    signal(SIGCHLD, SIG_DFL);	    signal(SIGHUP, SIG_IGN);	    /* restore various signals to their defaults */	    signal(SIGINT, SIG_DFL);	    signal(SIGQUIT, SIG_DFL);	    signal(SIGTERM, SIG_DFL);	    /* copy the environment before Setenving */	    for (i = 0; gblenvp[i] != NULL; i++) ;	    /* compute number of xtermSetenv() calls below */	    envsize = 1;	/* (NULL terminating entry) */	    envsize += 3;	/* TERM, WINDOWID, DISPLAY */	    envsize += 2;	/* COLUMNS, LINES */	    envnew = (char **) calloc((unsigned) i + envsize, sizeof(char *));	    memmove((char *) envnew, (char *) gblenvp, i * sizeof(char *));	    gblenvp = envnew;	    xtermSetenv("TERM=", TermName);	    if (!TermName)		*newtc = 0;	    sprintf(buf, "%lu",		    ((unsigned long) XtWindow(XtParent(CURRENT_EMU(screen)))));	    xtermSetenv("WINDOWID=", buf);	    /* put the display into the environment of the shell */	    xtermSetenv("DISPLAY=", XDisplayString(screen->display));	    signal(SIGTERM, SIG_DFL);	    /* this is the time to go and set up stdin, out, and err	     */	    /* dup the tty */	    for (i = 0; i <= 2; i++)		if (i != tty) {		    (void) close(i);		    (void) dup(tty);		}	    /* and close the tty */	    if (tty > 2)		(void) close(tty);	    setpgrp(0, pgrp);	    setgid(screen->gid);	    setuid(screen->uid);	    if (handshake.rows > 0 && handshake.cols > 0) {		screen->max_row = handshake.rows;		screen->max_col = handshake.cols;		ws.ws_row = screen->max_row + 1;		ws.ws_col = screen->max_col + 1;		ws.ws_xpixel = FullWidth(screen);		ws.ws_ypixel = FullHeight(screen);	    }	    sprintf(numbuf, "%d", screen->max_col + 1);	    xtermSetenv("COLUMNS=", numbuf);	    sprintf(numbuf, "%d", screen->max_row + 1);	    xtermSetenv("LINES=", numbuf);	    /* reconstruct dead environ variable */	    environ = gblenvp;	    /* need to reset after all the ioctl bashing we did above */	    ptioctl(0, TIOCSWINSZ, (char *) &ws);	    signal(SIGHUP, SIG_DFL);	    /* okay everything seems right, so tell the parent, we are going */	    {		char sema[40];		HEV sev;		sprintf(sema, "\\SEM32\\xterm%s", &ttydev[8]);		DosOpenEventSem(sema, &sev);		DosPostEventSem(sev);		DosCloseEventSem(sev);	    }#if OPT_LUIT_PROG	    /*	     * Use two copies of command_to_exec, in case luit is not actually	     * there, or refuses to run.  In that case we will fall-through to	     * to command that the user gave anyway.	     */	    if (command_to_exec_with_luit) {		TRACE(("spawning command \"%s\"\n", *command_to_exec_with_luit));		execvp(*command_to_exec_with_luit, command_to_exec_with_luit);		/* print error message on screen */		fprintf(stderr, "%s: Can't execvp %s: %s\n",			xterm_name, *command_to_exec_with_luit, strerror(errno));		fprintf(stderr, "%s: cannot support your locale.\n",			xterm_name);	    }#endif	    if (command_to_exec) {		TRACE(("spawning command \"%s\"\n", *command_to_exec));		execvpe(*command_to_exec, command_to_exec, gblenvp);		/* print error message on screen */		fprintf(stderr, "%s: Can't execvp %s\n",			xterm_name, *command_to_exec);	    }	    /* use a layered mechanism to find a shell */	    ptr = getenv("X11SHELL");	    if (!ptr)		ptr = getenv("SHELL");	    if (!ptr)		ptr = getenv("OS2_SHELL");	    if (!ptr)		ptr = "SORRY_NO_SHELL_FOUND";	    shname = x_basename(ptr);	    if (command_to_exec) {		char *exargv[10];	/*XXX */		exargv[0] = ptr;		exargv[1] = "/C";		exargv[2] = command_to_exec[0];		exargv[3] = command_to_exec[1];		exargv[4] = command_to_exec[2];		exargv[5] = command_to_exec[3];		exargv[6] = command_to_exec[4];		exargv[7] = command_to_exec[5];		exargv[8] = command_to_exec[6];		exargv[9] = 0;		execvpe(exargv[0], exargv, gblenvp);/*		execvpe(*command_to_exec, command_to_exec, gblenvp);*/		/* print error message on screen */		fprintf(stderr, "%s: Can't execvp %s\n",			xterm_name, *command_to_exec);	    } else {		execlpe(ptr, shname, 0, gblenvp);		/* Exec failed. */		fprintf(stderr, "%s: Could not exec %s!\n",			xterm_name, ptr);	    }	    sleep(5);	    /* preventively shoot the parent */	    kill(-getppid(), SIGTERM);	    exit(ERROR_EXEC);	}			/* endcase */    }    /* !am_slave */    signal(SIGHUP, SIG_IGN);/* * Unfortunately, System V seems to have trouble divorcing the child process * from the process group of xterm.  This is a problem because hitting the * INTR or QUIT characters on the keyboard will cause xterm to go away if we * don't ignore the signals.  This is annoying. *//*  signal (SIGINT, SIG_IGN);*/    signal(SIGINT, killit);    signal(SIGTERM, killit);    /* hung shell problem */    signal(SIGQUIT, SIG_IGN);/*  signal (SIGTERM, SIG_IGN);*/    return 0;}				/* end spawn */