ftp.nice.ch/pub/next/unix/macintosh/uw.4.2.N.bs.tar.gz#/uw/server/uw_main.c

This is uw_main.c in view mode; [Download] [Up]

/*
 *	uw - UNIX windows program for the Macintosh (host end)
 *
 * Copyright 1985,1986 by John D. Bruner.  All rights reserved.  Permission to
 * copy this program is given provided that the copy is not sold and that
 * this copyright notice is included.
 */

#include <sys/types.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/ioctl.h>
#include <pwd.h>
#include <signal.h>
#include <errno.h>
#include <strings.h>
#include <stdio.h>

#include "uw_param.h"
#include "uw_clk.h"
#include "uw_opt.h"
#include "uw_win.h"
#include "uw_fd.h"
#include "uw_pcl.h"
#include "uw_ipc.h"
#include "openpty.h"

int nflag;			/* no startup file */
int sflag;			/* "secure" (hee hee) -- no network requests */
int errflag;			/* argument error */
char *rcfile;			/* ".uwrc" file name */

extern void rc_kludge();	/* horrible hack (see rc_kludge()) */

main(argc, argv)
char **argv;
{
	register int c;
	register fildes_t fd;
	extern int calloptscan;
	extern int errno;
	extern int optind;
	extern char *optarg;

	/*
	 * Make sure we don't accidentally try to run this inside itself.
	 */
	if (getenv(UIPC_ENV)) {
		fprintf(stderr, "%s is already running\n", *argv);
		exit(1);
	}

	/*
	 * Process command-line arguments.
	 */
	while ((c=getopt(argc, argv, "f:ns")) != EOF) {
		switch (c) {
		case 'f':
			if (nflag) {
				fprintf(stderr,
				    "Cannot specify both \"-f\" and \"-n\"\n");
				nflag = 0;
			}
			rcfile = optarg;
			break;
		case 'n':
			if (rcfile != (char *)0) {
				fprintf(stderr,
				    "Cannot specify both \"-f\" and \"-n\"\n");
				rcfile = (char *)0;
			}
			nflag = 1;
			break;
		case 's':
			sflag = 1;
			break;
		case '?':
		default:
			errflag = 1;
			break;
		}
	}
	if (errflag) {
		fprintf(stderr, "Usage: \"%s [-f file] [-n] [-s]\"\n", *argv);
		exit(1);
	}

	/*
	 * Initialize the file descriptor table.
	 */
	fd_init();
	FD_SET(0, &selmask[0].sm_rd);

	/*
	 * If we can open the "/etc/utmp" for write, do so.
	 * Immediately afterwards, we lose any magic powers that
	 * might have allowed us to do this.
	 */
#ifdef UTMP
	fd = open("/etc/utmp", O_WRONLY);
	(void)setgid(getgid());
	(void)setuid(getuid());
	if (fd >= 0)
		fdmap[fd].f_type = FDT_OTHER;
	utmp_init(fd);
#endif

	/*
	 * Initialize the window structures.
	 */
	win_init();

	/*
	 * Initialize timeouts.
	 */
	clk_init();


	/*
	 * Create a UNIX-domain network address, and put its name into
	 * the environment so that descendents can contact us with new
	 * window requests.  If we want to be "secure", we don't allow
	 * any UNIX-domain messages to come in.
	 */
	ipc_init(!sflag);
	if (!sflag)
		clk_timeout(5, rc_kludge, (toarg_t)0);


	/*
	 * Ignore interrupts, quits, and terminal stops.  Clean up and exit
	 * if a hangup or termination is received.  Also catch changes in
	 * child status (so that we can wait for them).  Set up the terminal
	 * modes.
	 */
	(void)signal(SIGHUP, done);
	(void)signal(SIGINT, SIG_IGN);
	(void)signal(SIGQUIT, SIG_IGN);
	(void)signal(SIGTERM, done);
	(void)signal(SIGTSTP, SIG_IGN);
	(void)signal(SIGCHLD, cwait);

	tty_mode(1);


	/*
	 * Tell the Macintosh to initialize.
	 */
	pcl_entry(0);

	
	/*
	 * Create window 1 (to start things off) and wait for input.
	 * When input is available, process it.
	 */
	if (!nflag)
		finduwrc();

	while (1) {
		CLK_CHECK();
		if (calloptscan && protocol->p_chkopt) {
			calloptscan = 0;
			(*protocol->p_chkopt)(0);
		}
		selmask[1] = selmask[0];
		if (select(nfds, &selmask[1].sm_rd, &selmask[1].sm_wt,
		    &selmask[1].sm_ex, (struct timeval *)0) < 0) {
			if (errno == EINTR)
				continue;
			perror("select");
			done(1);	/* for now -- fix this! */
		}
		for (fd=0; fd < nfds; fd++) {
			if (FD_ISSET(fd, &selmask[1].sm_rd)) {
				switch (fdmap[fd].f_type) {
				case FDT_MAC:
					PCL_RECV(0, (char *)0, 0);
					break;
				case FDT_UDSOCK:
					ipc_udrecv(fd);
					break;
				case FDT_ISSOCK:
					ipc_isrecv(fd);
					break;
				case FDT_DATA:
					PCL_XMIT(0, fdmap[fd].f_win);
					break;
				case FDT_CTL:
					ipc_ctlrecv(0, fd, fdmap[fd].f_win);
					break;
				default:
					/* "can't happen" */
					FD_CLR(fd, &selmask[0].sm_rd);
					break;
				}
			}
			if (FD_ISSET(fd, &selmask[1].sm_wt)) {
				/* "can't happen" */
				FD_CLR(fd, &selmask[0].sm_wt);
				break;
			}
			if (FD_ISSET(fd, &selmask[1].sm_ex)) {
				/* "can't happen" */
				FD_CLR(fd, &selmask[0].sm_ex);
				break;
			}
		}
	}
}

finduwrc()
{
	register struct passwd *pw;
	register char *homedir;

	/*
	 * If the global variable "rcfile" is non-NULL, then it specifies
	 * the name of the startup file.  Otherwise, the name of the startup
	 * file is "$HOME/.uwrc".  If $HOME is undefined or null, the password
	 * file is consulted.  The ".uwrc" file is an executable program or
	 * "/bin/sh" command file.  (For "csh" (ugh) use "#! /bin/csh".)
	 *
	 * Returns 0 if the ".uwrc" file doesn't exist, 1 if it does.  As
	 * a side-effect, this routine sets the global variable "rcfile"
	 * to the name of the ".uwrc" file.
	 */
	if (rcfile == (char *)0) {
		if ((homedir=getenv("HOME")) == NULL || !*homedir) {
			if ((pw = getpwuid(getuid())) != NULL)
				homedir = pw->pw_dir;
			else
				return;
		}
		rcfile = malloc((unsigned)(strlen(homedir) + sizeof "/.uwrc"));
		if (rcfile == (char *)0)
			return;
		(void)strcpy(rcfile, homedir);
		(void)strcat(rcfile, "/.uwrc");
	}
	if (access(rcfile, F_OK) < 0)
		rcfile = (char *)0;
}

runuwrc()
{
	register int pid;
	register fildes_t fd;
	struct ptydesc pt;

	/*
	 * We use a real fork (rather than a vfork()) because the parent
	 * doesn't wait for the child.  The caller knows that the file
	 * exists; however, it cannot determine whether or not it is
	 * successfully executed.
	 *
	 * We acquire a pseudo-terminal for rather convoluted reasons.
	 * Programs such as "uwtool" expect to be able to inherit tty
	 * modes from their controlling terminal.  By the time that we
	 * reach this point, we've already changed our controlling
	 * terminal to use cbreak mode with no special characters except
	 * XON/XOFF.  Therefore, we obtain a pseudo-terminal and
	 * restore our original modes onto it.  We double-fork (sigh,
	 * another miserable kludge) so that the server does not have
	 * to wait for the completion of the ".uwrc" file.  (The child
	 * waits for the grandchild so that the master side of the pty
	 * remains open until the grandchild is finished.)
	 */
	if (openpty(&pt) < 0)
		return;
	while ((pid = fork()) < 0)
		sleep(5);
	if (pid > 0) {
		(void)close(pt.pt_pfd);
		(void)close(pt.pt_tfd);
	} else {
		/* child */
		while ((pid = fork()) < 0)
			sleep(5);
		if (pid > 0) {
			while (wait((int *)0) < 0 && errno == EINTR)
				;
			_exit(1);
			/*NOTREACHED*/
		} else {
			/* grandchild */
			(void)setgid(getgid());
			(void)setuid(getuid());
			(void)close(pt.pt_pfd);
			if (pt.pt_tfd != 0)
				(void)dup2(pt.pt_tfd, 0);
			if (pt.pt_tfd != 1);
				(void)dup2(pt.pt_tfd, 1);
			if (pt.pt_tfd != 2)
				(void)dup2(pt.pt_tfd, 2);
			win_envinit(defwtype, (long)0);
			(void)signal(SIGHUP, SIG_DFL);
			(void)signal(SIGINT, SIG_DFL);
			(void)signal(SIGQUIT, SIG_DFL);
			(void)signal(SIGTERM, SIG_DFL);
			(void)signal(SIGTSTP, SIG_IGN);
			(void)signal(SIGCHLD, SIG_DFL);
			(void)ioctl(open("/dev/tty",O_RDWR),
			    (int)TIOCNOTTY, (char *)0);
			(void)open(pt.pt_tname, O_RDONLY);
			for (fd=3; fd < nfds; fd++)
				(void)close(fd);
			tty_mode(0);
			(void)execlp(rcfile, rcfile, (char *)0);
			(void)execl("/bin/sh", "sh", rcfile, (char *)0);
			_exit(1);
			/*NOTREACHED*/
		}
	}
}

void
rc_kludge()
{
	static int firsttime = 1;

	/*
	 * A problem which occurs with ".uwrc" file handling is that
	 * the "rc" file is interpreted immediately after the server
	 * begins, i.e. before it and the Macintosh have (possibly)
	 * changed from the default protocol to an extended one.
	 *
	 * To get around this problem, if a ".uwrc" file exists, it
	 * is not executed immediately.  Instead, it will be executed
	 * when this routine is called, either directly by pcl_newpcl()
	 * when the protocol changes, or after an initial timeout.
	 *
	 * It is most unfortunate that "pcl_newpcl" must call "upwards"
	 * into this source file.
	 */
	if (firsttime) {
		firsttime = 0;
		if (rcfile != (char *)0)
			runuwrc();
		else
			(void)PCL_NEWW(0, WC_INTERNAL, defwtype, (nwin_t)1, 0L,
			    (fildes_t)-1, (fildes_t)-1);
	}
}

void
done(s)
{
	/*
	 * Clean up and exit.  It is overkill to close all of the file
	 * descriptors, but it causes no harm.
	 */
	pcl_exit(0);
	utmp_exit();
	fd_exit();
	ipc_exit();
	tty_mode(0);
	exit(s);
}

void
cwait()
{
	register int pid;
	union wait status;
	struct rusage rusage;

	/*
	 * Collect dead children.  Restart any children that have stopped.
	 */
	while ((pid=wait3(&status, WNOHANG|WUNTRACED, &rusage)) > 0)
		if (WIFSTOPPED(status))
			(void)kill(pid, SIGCONT);
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.