2
/* Lefteris Koutsofios - AT&T Bell Laboratories */
13
#ifndef HAVE_TERMIOS_H
19
#include <sys/socket.h>
20
#include <netinet/in.h>
34
static FILE *serverconnect (char *);
35
static void ptyopen (char *, FILE **, FILE **, int *);
36
static int findpty (int *);
37
static void pipeopen (char *, FILE **, FILE **, int *);
38
static void socketopen (char *, int, FILE **, FILE **, int *);
40
static void sigchldhandler (int);
46
if (!(shell = getenv ("SHELL")))
48
if (shell[0] != '/' && shell[0] != '.') {
49
if (!(shell = buildpath (shell, TRUE)))
52
shell = strdup (shell);
54
shbname = shell + strlen (shell) - 1;
55
while (shbname >= shell && *shbname != '/')
60
for (ioi = FD_SETSIZE - 1; ioi >= 0; ioi--) {
61
if (fstat (ioi, &statbuf) == 0) {
62
ion = (ioi / IOINCR + 1) * IOINCR;
66
iop = Marrayalloc ((long) ion * IOSIZE);
67
for (ioi = 0; ioi < ion; ioi++)
68
iop[ioi].inuse = FALSE;
69
for (ioi = 0; ioi < ion; ioi++) {
70
if (fstat (ioi, &statbuf) == 0) {
71
if ((iop[ioi].ifp = iop[ioi].ofp = fdopen (ioi,
72
(ioi == 0 ? "r" : "w")))) {
73
iop[ioi].inuse = TRUE;
74
iop[ioi].type = IO_FILE;
75
iop[ioi].ismonitored = FALSE;
81
signal (SIGCHLD, sigchldhandler);
82
signal (SIGPIPE, SIG_IGN);
88
for (ioi = 3; ioi < ion; ioi++)
91
Marrayfree (iop), iop = NULL, ion = 0;
94
int IOopen (char *kind, char *name, char *mode, char *fmt) {
101
struct sockaddr_in sname;
103
if (Strcmp (kind, "file") == 0)
105
else if (Strcmp (kind, "pty") == 0)
107
else if (Strcmp (kind, "pipe") == 0)
109
else if (Strcmp (kind, "socket") == 0)
112
else if (Strcmp (kind, "cs") == 0)
117
for (i = 0; i < ion; i++)
121
iop = Marraygrow (iop, (long) (ion + IOINCR) * IOSIZE);
122
for (i = ion + IOINCR - 1; i >= ion; i--)
123
iop[i].inuse = FALSE;
131
if (!(p->ifp = p->ofp = fopen (name, mode))) {
132
if (strncmp (name, "/dev/tcp/", 9) == 0) {
133
if (!(p->ifp = p->ofp = serverconnect (name)))
137
path = buildpath (name, FALSE);
138
if (!path || !(p->ifp = p->ofp = fopen (path, mode)))
145
if (!(path = buildpath (name, TRUE)) ||
146
!(command = buildcommand (path, NULL, -1, -1, fmt)))
148
ptyopen (command, &p->ifp, &p->ofp, &p->pid);
149
if (!p->ifp || !p->ofp)
155
if (!(path = buildpath (name, TRUE)) ||
156
!(command = buildcommand (path, NULL, -1, -1, fmt)))
158
pipeopen (command, &p->ifp, &p->ofp, &p->pid);
159
if (!p->ifp || !p->ofp)
165
if ((sfd = socket (AF_INET, SOCK_STREAM, 0)) < 0)
167
sname.sin_family = AF_INET;
169
sname.sin_addr.s_addr = htonl (INADDR_ANY);
170
slen = sizeof (sname);
171
if (bind (sfd, (struct sockaddr *) &sname, slen) < 0 ||
172
getsockname (sfd, (struct sockaddr *) &sname, &slen) < 0)
174
if (listen (sfd, 5) < 0)
176
gethostname (hname, sizeof (hname));
177
if (!(path = buildpath (name, TRUE)) ||
178
!(command = buildcommand (path, hname,
179
(int) ntohs (sname.sin_port),
180
(int) ntohs (sname.sin_port), fmt)))
182
socketopen (command, sfd, &p->ifp, &p->ofp, &p->pid);
183
if (!p->ifp || !p->ofp)
189
if (C2Lopen (name, mode, &p->ifp, &p->ofp) == -1)
195
FD_CLR (fileno (p->ifp), &inputfds);
196
FD_CLR (fileno (p->ofp), &inputfds);
200
int IOclose (int ioi, char *action) {
203
if (ioi < 0 || ioi >= ion || !iop[ioi].inuse)
206
FD_CLR (fileno (p->ifp), &inputfds);
207
FD_CLR (fileno (p->ofp), &inputfds);
208
if (p->ifp != p->ofp)
212
if (action && Strcmp (action, "kill") == 0 && p->pid != -1)
217
int IOreadline (int ioi, char *bufp, int bufn) {
221
if (ioi < 0 || ioi >= ion || !iop[ioi].inuse)
224
fseek (p->ofp, 0L, 1);
225
if (fgets (bufp, bufn, p->ifp) == NULL)
227
l = strlen (bufp) - 1;
228
while (bufp[l] == '\n' || bufp[l] == '\r')
233
int IOread (int ioi, char *bufp, int bufn) {
237
if (ioi < 0 || ioi >= ion || !iop[ioi].inuse)
240
if ((l = read (fileno (p->ifp), bufp, bufn - 1)) == -1)
248
int IOwriteline (int ioi, char *bufp) {
251
if (ioi < 0 || ioi >= ion || !iop[ioi].inuse)
254
fseek (p->ofp, 0L, 1);
255
if (fputs (bufp, p->ofp) == EOF || fputs ("\n", p->ofp) == EOF)
258
fseek (p->ofp, 0L, 1);
262
static FILE *serverconnect (char *name) {
263
char *host, *portp, buf[1024];
266
struct sockaddr_in sin;
271
portp = strchr (host, '/');
272
if (*host == 0 || !portp)
274
*portp++ = 0, port = atoi (portp);
275
if (!(hp = gethostbyname (host)))
277
memset ((char *) &sin, 1, sizeof (sin));
278
memcpy ((char *) &sin.sin_addr, hp->h_addr, hp->h_length);
279
sin.sin_family = hp->h_addrtype;
280
sin.sin_port = htons (port);
281
if ((cfd = socket (hp->h_addrtype, SOCK_STREAM, 0)) < 0)
283
if (connect (cfd, (struct sockaddr *) &sin, sizeof (sin)) < 0)
285
return fdopen (cfd, "w+");
288
static void ptyopen (char *cmd, FILE **ifp, FILE **ofp, int *pidp) {
291
if (findpty (fd) == -1) {
295
switch ((*pidp = FORK ())) {
297
panic2 (POS, "ptyopen", "cannot fork");
299
close (fd[0]), close (0), dup (fd[1]);
300
close (1), dup (fd[1]), close (fd[1]);
301
execl (shell, shbname, "-c", cmd, 0);
302
panic2 (POS, "ptyopen", "child cannot exec: %s\n", cmd);
306
fcntl (fd[0], F_SETFD, FD_CLOEXEC);
307
*ifp = fdopen (fd[0], "r"), *ofp = fdopen (fd[0], "a+");
311
static int findpty (int *fd) {
312
char *majorp, *minorp;
313
char pty[32], tty[32];
314
#ifndef HAVE_TERMIOS_H
319
static char ptymajor[] = "pqrs";
320
static char ptyminor[] = "0123456789abcdefghijklmnopqrstuvwxyz";
322
for (majorp = ptymajor; *majorp; majorp++) {
323
for (minorp = ptyminor; *minorp; minorp++) {
324
sprintf (pty, "/dev/pty%c%c", *majorp, *minorp);
325
if ((fd[0] = open (pty, O_RDWR)) >= 0) {
326
sprintf (tty, "/dev/tty%c%c", *majorp, *minorp);
327
if ((fd[1] = open (tty, O_RDWR)) >= 0) {
328
#ifndef HAVE_TERMIOS_H
329
ioctl (fd[1], TCGETA, &tio);
330
tio.c_lflag &= ~ECHO;
331
ioctl (fd[1], TCSETA, &tio);
333
tcgetattr(fd[1], &tio);
334
tio.c_lflag &= ~ECHO;
335
tcsetattr(fd[1], TCSANOW, &tio);
346
static void pipeopen (char *cmd, FILE **ifp, FILE **ofp, int *pidp) {
351
if (pipe (p1) == -1 || pipe (p2) == -1) {
355
switch ((*pidp = FORK ())) {
357
panic2 (POS, "pipeopen", "cannot fork");
359
close (p1[0]), close (p2[1]);
360
for (s = cmd; *s; s++)
361
if (*s == '%' && *(s + 1) && *(s + 1) == 'd') {
362
sprintf (cmd2, cmd, p2[0], p1[1]);
363
execl (shell, shbname, "-c", cmd2, 0);
364
panic2 (POS, "pipeopen", "child cannot exec: %s\n", cmd2);
366
close (1), dup (p1[1]), close (p1[1]);
367
close (0), dup (p2[0]), close (p2[0]);
368
execl (shell, shbname, "-c", cmd, 0);
369
panic2 (POS, "pipeopen", "child cannot exec: %s\n", cmd);
371
close (p1[1]), close (p2[0]);
373
fcntl (p1[0], F_SETFD, FD_CLOEXEC);
374
fcntl (p2[1], F_SETFD, FD_CLOEXEC);
375
*ifp = fdopen (p1[0], "r"), *ofp = fdopen (p2[1], "a");
379
static void socketopen (char *cmd, int sfd, FILE **ifp, FILE **ofp, int *pidp) {
382
switch ((*pidp = FORK ())) {
384
panic2 (POS, "socketopen", "cannot fork");
386
execl (shell, shbname, "-c", cmd, 0);
387
panic2 (POS, "socketopen", "child cannot exec: %s\n", cmd);
389
if ((fd = accept (sfd, NULL, NULL)) < 0) {
394
fcntl (fd, F_SETFD, FD_CLOEXEC);
395
*ifp = fdopen (fd, "r"), *ofp = fdopen (fd, "a+");
399
static void sigchldhandler (int data) {
400
while (waitpid (-1, NULL, WNOHANG) > 0)
402
signal (SIGCHLD, sigchldhandler);