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.