1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
|
/* This directory contains the PseudoTTYPlugin, a means for Squeak to
* fork an interactive program that believes itself to be running on a
* login terminal when, in fact, Squeak is providing it with data for
* its stdin and recovering the output it writes to its stdout/stderr.
*
* The Squeak plugin source code is in `PseudoTTYPlugin.st'.
* The Squeak class needed to use the plugin is in `PseudoTTY.st'.
*
* The plugin has been built and tested on the following architecures:
*
* GNU/Linux (libc2.3)
* NetBSD 1.5ZC
* Solaris 2.8
*
* The remainder of this file is a C program designed to ease the
* process of porting this plugin to unsupported architectures.
*
* ----------------------------------------------------------------
*
* This program forks a child process to run /bin/stty and then
* collects and prints its output. If the child is not connected to a
* login terminal then stty will complain (printing something like
* "stdin: not a tty") and you have a problem somewhere in "opentty.h"
* which you must FIND AND FIX before the plugin will work. OTOH, if
* it prints a bunch (about ten lines) of tty mode information then
* all is well and the plugin should work just fine.
*
* (Do I really need to mention that you have to rename this file to
* "pty.c" or somesuch before trying to compile it? ;)
*/
/* For the plugin the HAVE_* macros are set in config.h by acinclude.m4.
* In this test file you need to set them manually for your architecture.
* If you invent new HAVE_* macros then you'll need to modify acinclude.m4
* and regenerate configure (run `make' in ../../config) before building
* the VM.
*
* If it is available then we use openpty() in preference to Unix98 ptys:
*
* HAVE_OPENPTY -- defined if you have openpty() and login_tty()
* HAVE_UTIL_H -- defined if you have /usr/include/util.h
* HAVE_PTY_H -- defined if you have /usr/include/pty.h
*
* If you don't have openpty() then we fake it from /dev/ptmx:
*
* HAVE_UNIX98_PTY -- defined if you have /dev/ptmx and grantpt() et al.
* HAVE_STROPTS_H -- defined if you have /usr/include/stropts.h
*
* We assume you have /usr/include/utmp.h; if you don't then you need to
* buy a real computer before trying to compile this plugin.
*
* Suggested compile command is shown with each architecture.
* If you have to add new libraries then you'll need to modify acinclude.m4
* and regenerate configure (run `make' in ../../config) before building the
* VM.
*/
#if defined(__NetBSD__) /* cc -o pty pty.c -lutil */
# define HAVE_OPENPTY
# define HAVE_UTIL_H
#elif defined(__OpenBSD__) /* cc -o pty pty.c -lutil */
# define HAVE_OPENPTY
# define HAVE_UTIL_H
#elif defined(__linux__) /* cc -o pty pty.c -lutil */
# define HAVE_UNIX98_PTY
# define HAVE_OPENPTY
# define HAVE_PTY_H
#elif defined(__sun__) /* cc -o pty pty.c */
# define HAVE_UNIX98_PTY
# define HAVE_STROPTS_H
#else
# error: defines for your architecture go here
#endif
/* Absolutely everybody has these. */
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
#include <errno.h>
#include <stdio.h>
/* This gets the obscure (interesting ;) stuff. */
#include "openpty.h"
/* Here we go! ... */
static char *prog= "/bin/stty";
static char *argv[]= { "stty", "-a", 0 };
extern char **environ;
static int ptm= -1, pts= -1;
static void sigchld(int signum)
{
close(pts); /* force i/o error or EOF on ptm */
}
int main()
{
char tty[32];
pid_t pid= 0;
if (openpty(&ptm, &pts, tty, 0, 0) == -1)
{
perror("openpty");
exit(1);
}
printf("using %s (ptm %d pts %d)\n", tty, ptm, pts);
signal(SIGCHLD, sigchld);
pid= fork();
switch (pid)
{
case -1:
perror("fork");
exit(1);
break;
case 0: /* child */
close(ptm);
if (login_tty(pts) == -1)
{
perror("login_tty");
exit(1);
}
execve(prog, argv, environ);
perror(argv[0]);
exit(1);
break;
default: /* parent */
{
char buf[128];
int n, status;
printf("---------------- from child:\n");
while (((n= read(ptm, buf, sizeof(buf) - 1)) > 0)
|| ((n == -1) && (errno == EINTR)))
if (n > 0)
{
buf[n]= '\0';
printf("%s", buf);
}
printf("----------------\n");
if (n < 0)
perror("read");
else
printf("EOF\n");
close(ptm);
pid= wait(&status);
printf("child exited with status %d\n", status);
}
break;
}
return 0;
}
|