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 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
|
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/file.h>
#include <signal.h>
#include <stdio.h>
ptyopen(cmd, ifp, ofp)
char *cmd;
FILE **ifp, **ofp;
{
int i;
char *args[16];
register int tty;
long ldisc, lmode;
register char *s, *t;
struct sgttyb sgttyb;
struct tchars tchars;
struct ltchars ltchars;
char ttybuf[16], ptybuf[16];
/*
* Split up the arguments in the command
* into an argv-like structure.
*/
i = 0;
s = cmd;
while (*s) {
/*
* Skip white space.
*/
while ((*s == ' ') || (*s == '\t'))
*s++ = NULL;
args[i++] = s;
/*
* Skip over this word to next white space.
*/
while ((*s != NULL) && (*s != ' ') && (*s != '\t'))
s++;
}
args[i] = NULL;
/*
* Get a pseudo-tty. We do this by cycling through all
* the possible names. The operating system will not
* allow us to open a master which is already in use,
* so we simply go until the open succeeds.
*/
for (s = "pqrs"; *s != NULL; s++) {
for (t = "0123456789abcdef"; *t != NULL; t++) {
sprintf(ptybuf, "/dev/pty%c%c", *s, *t);
if ((tty = open(ptybuf, O_RDWR)) >= 0)
goto out;
}
}
out:
/*
* If s and t are NULL, we ran out of pseudo ttys
* before we found one we can use.
*/
if ((*s == NULL) && (*t == NULL))
return(-1);
/*
* Change "ptyXX" (master) to "ttyXX" (slave).
*/
strcpy(ttybuf, ptybuf);
ttybuf[5] = 't';
/*
* Get the modes of the current terminal. We
* will duplicate these on the pseudo terminal.
*/
ioctl(0, TIOCGETD, &ldisc);
ioctl(0, TIOCLGET, &lmode);
ioctl(0, TIOCGETP, &sgttyb);
ioctl(0, TIOCGETC, &tchars);
ioctl(0, TIOCGLTC, <chars);
/*
* Fork a child process.
*/
if ((i = fork()) < 0) {
close(tty);
return(-1);
}
/*
* In the child...
*/
if (i == 0) {
/*
* Close all open files.
*/
for (i = 0; i < NOFILE; i++)
close(i);
/*
* Clear the controlling tty. This means
* that we will not have a controlling
* tty until we open another terminal
* device.
*/
if ((i = open("/dev/tty", O_RDWR)) >= 0) {
ioctl(i, TIOCNOTTY, 0);
close(i);
}
/*
* Make our controlling tty the pseudo tty.
* This happens because we cleared our
* original controlling terminal above.
*/
i = open(ttybuf, O_RDWR);
/*
* Set stdin, stdout, and stderr to be the
* pseudo terminal.
*/
dup2(i, 0);
dup2(i, 1);
dup2(i, 2);
/*
* Set the pseudo terminal's tty modes to
* those of the original terminal. We
* turn off ECHO and CBREAK modes, since
* we don't want characters "typed" to be
* printed.
*/
sgttyb.sg_flags &= ~ECHO;
sgttyb.sg_flags &= ~CRMOD;
ioctl(0, TIOCSETD, &ldisc);
ioctl(0, TIOCLGET, &lmode);
ioctl(0, TIOCSETP, &sgttyb);
ioctl(0, TIOCSETC, &tchars);
ioctl(0, TIOCSLTC, <chars);
/*
* Set the process group of the process
* to be the process group of the
* terminal.
*/
ioctl(0, TIOCGPGRP, &i);
setpgrp(0, i);
/*
* Now change the process group of the
* terminal and process to be the
* process id; this takes them out
* of the calling process's process
* group.
*/
i = getpid();
ioctl(0, TIOCSPGRP, &i);
setpgrp(0, i);
/*
* Execute the program.
*/
execv(*args, args);
exit(1);
}
/*
* Set up the input and output file pointers
* so that they can write and read the pseudo
* terminal.
*/
*ifp = fdopen(tty, "w");
*ofp = fdopen(tty, "r");
return(0);
}
|