dtach 0.6

This commit is contained in:
Ned T. Crigler 2004-05-26 17:30:44 +00:00
parent b87318d1f3
commit abf2db3509
12 changed files with 2782 additions and 1224 deletions

View File

@ -3,7 +3,7 @@ CC = @CC@
CFLAGS = @CFLAGS@ -I.
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
VERSION = 0.5
VERSION = @PACKAGE_VERSION@
VPATH = $(srcdir)
OBJ = attach.o master.o main.o
@ -29,7 +29,7 @@ tar:
gzip -9f dtach-$(VERSION).tar
rm -rf dtach-$(VERSION)
attach.o: @srcdir@/attach.c @srcdir@/detach.h config.h
master.o: @srcdir@/master.c @srcdir@/detach.h config.h
main.o: @srcdir@/main.c @srcdir@/detach.h config.h
attach.o: @srcdir@/attach.c @srcdir@/dtach.h config.h
master.o: @srcdir@/master.c @srcdir@/dtach.h config.h
main.o: @srcdir@/main.c @srcdir@/dtach.h config.h

16
README
View File

@ -48,7 +48,7 @@ socket that dtach should use when creating or attaching to dtach sessions.
For example, let's create a new session that is running ircII. We will use
/tmp/foozle as the session's socket:
$ dtach -A /tmp/foozle irc RuneB irc.openprojects.net
$ dtach -A /tmp/foozle irc RuneB irc.freenode.net
Here, -A tells dtach to either create a new session or attach to the
existing session. If the session at /tmp/foozle does not exist yet, the
@ -96,6 +96,16 @@ to dtach when attaching.
5. CHANGES
The changes in version 0.6 are:
- Redraws are now handled by sending the child process a WINCH signal instead
of by sending a ^L character. This should help prevent line-oriented
programs (such as bash) from clearing the screen excessively.
- Flow control is now disabled when setting raw mode on the terminal.
- Switched to using select instead of poll.
- Changed some exits to exit succesfully instead of non-sucessfully.
- Updated my email address.
- Updated to Autoconf 2.59, renaming some files in the process.
The changes in version 0.5 are:
- Fix fd leakage.
- Prevent atexit from being called twice on dtach -A.
@ -119,8 +129,8 @@ The changes in version 0.3 are:
6. AUTHOR
dtach is (C)Copyright 2001 Ned T. Crigler, and is under the GNU General
dtach is (C)Copyright 2004 Ned T. Crigler, and is under the GNU General
Public License.
Comments and suggestions about dtach are welcome, and can be sent to
the author at: <crigler@hell-city.org>.
the author at: <crigler@users.sourceforge.net>.

View File

@ -1,6 +1,6 @@
/*
dtach - A simple program that emulates the detach feature of screen.
Copyright (C) 2001 Ned T. Crigler
Copyright (C) 2004 Ned T. Crigler
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -16,7 +16,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "detach.h"
#include "dtach.h"
#ifndef VDISABLE
#ifdef _POSIX_VDISABLE
@ -33,8 +33,6 @@
static struct termios cur_term;
/* 1 if the window size changed */
static int win_changed;
/* 1 if we want a redraw */
static int want_redraw;
/* This hopefully moves to the bottom of the screen */
#define EOS "\033[999H"
@ -108,19 +106,15 @@ process_kbd(int s, struct packet *pkt)
/* Tell the master that we are returning. */
pkt->type = MSG_ATTACH;
ioctl(0, TIOCGWINSZ, &pkt->u.ws);
write(s, pkt, sizeof(*pkt));
/* The window size might have changed, and we definately want
** a redraw. We don't want to pass the suspend, though. */
win_changed = 1;
want_redraw = 1;
return;
}
/* Detach char? */
else if (pkt->u.buf[0] == detach_char)
{
printf(EOS "\r\n[detached]\r\n");
exit(1);
exit(0);
}
/* Just in case something pukes out. */
else if (pkt->u.buf[0] == '\f')
@ -133,10 +127,10 @@ process_kbd(int s, struct packet *pkt)
int
attach_main(int noerror)
{
int s;
struct pollfd polls[2];
struct packet pkt;
unsigned char buf[BUFSIZE];
fd_set readfds;
int s;
/* Attempt to open the socket. Don't display an error if noerror is
** set. */
@ -165,8 +159,9 @@ attach_main(int noerror)
signal(SIGQUIT, die);
signal(SIGWINCH, win_change);
/* Set raw mode, almost. We allow flow control to work, for instance. */
/* Set raw mode. */
cur_term.c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
cur_term.c_iflag &= ~(IXON|IXOFF);
cur_term.c_oflag &= ~(OPOST);
cur_term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
cur_term.c_cflag &= ~(CSIZE|PARENB);
@ -174,41 +169,32 @@ attach_main(int noerror)
cur_term.c_cc[VLNEXT] = VDISABLE;
cur_term.c_cc[VMIN] = 1;
cur_term.c_cc[VTIME] = 0;
tcsetattr(0, TCSADRAIN, &cur_term);
/* Clear the screen. This assumes VT100. */
write(1, "\33[H\33[J", 6);
/* Set up the poll structures */
polls[0].fd = 0;
polls[0].events = POLLIN;
polls[0].revents = 0;
polls[1].fd = s;
polls[1].events = POLLIN;
polls[1].revents = 0;
/* Send our window size. */
pkt.type = MSG_WINCH;
/* Tell the master that we want to attach. */
pkt.type = MSG_ATTACH;
ioctl(0, TIOCGWINSZ, &pkt.u.ws);
write(s, &pkt, sizeof(pkt));
/* We would like a redraw, too. */
pkt.type = MSG_REDRAW;
write(s, &pkt, sizeof(pkt));
/* Wait for things to happen */
while (1)
{
if (poll(polls, 2, -1) < 0)
FD_ZERO(&readfds);
FD_SET(0, &readfds);
FD_SET(s, &readfds);
if (select(s + 1, &readfds, NULL, NULL, NULL) < 0)
{
if (errno != EINTR && errno != EAGAIN)
{
printf(EOS "\r\n[poll failed]\r\n");
printf(EOS "\r\n[select failed]\r\n");
exit(1);
}
}
/* Pty activity */
if (polls[1].revents != 0)
if (FD_ISSET(s, &readfds))
{
int len = read(s, buf, sizeof(buf));
@ -216,7 +202,7 @@ attach_main(int noerror)
{
printf(EOS "\r\n[EOF - dtach terminating]"
"\r\n");
exit(1);
exit(0);
}
else if (len < 0)
{
@ -227,7 +213,7 @@ attach_main(int noerror)
write(1, buf, len);
}
/* stdin activity */
if (polls[0].revents != 0)
if (FD_ISSET(0, &readfds))
{
pkt.type = MSG_PUSH;
memset(pkt.u.buf, 0, sizeof(pkt.u.buf));
@ -246,14 +232,6 @@ attach_main(int noerror)
ioctl(0, TIOCGWINSZ, &pkt.u.ws);
write(s, &pkt, sizeof(pkt));
}
/* Want a redraw? */
if (want_redraw)
{
want_redraw = 0;
pkt.type = MSG_REDRAW;
write(s, &pkt, sizeof(pkt));
}
}
return 0;
}

View File

@ -1,88 +1,130 @@
/* config.h.in. Generated from configure.in by autoheader. */
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if you have the `forkpty' function. */
/* Define to 1 if you have the `atexit' function. */
#undef HAVE_ATEXIT
/* Define to 1 if you have the `dup2' function. */
#undef HAVE_DUP2
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
/* Define to 1 if you have the `forkpty' function. */
#undef HAVE_FORKPTY
/* Define if you have the `getrlimit' function. */
#undef HAVE_GETRLIMIT
/* Define if you have the `grantpt' function. */
/* Define to 1 if you have the `grantpt' function. */
#undef HAVE_GRANTPT
/* Define if you have the <inttypes.h> header file. */
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
/* Define if you have the `socket' library (-lsocket). */
/* Define to 1 if you have the `socket' library (-lsocket). */
#undef HAVE_LIBSOCKET
/* Define if you have the `util' library (-lutil). */
/* Define to 1 if you have the `util' library (-lutil). */
#undef HAVE_LIBUTIL
/* Define if you have the <libutil.h> header file. */
/* Define to 1 if you have the <libutil.h> header file. */
#undef HAVE_LIBUTIL_H
/* Define if you have the <memory.h> header file. */
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define if you have the `openpty' function. */
/* Define to 1 if you have the `memset' function. */
#undef HAVE_MEMSET
/* Define to 1 if you have the `openpty' function. */
#undef HAVE_OPENPTY
/* Define if you have the `ptsname' function. */
/* Define to 1 if you have the `ptsname' function. */
#undef HAVE_PTSNAME
/* Define if you have the <pty.h> header file. */
/* Define to 1 if you have the <pty.h> header file. */
#undef HAVE_PTY_H
/* Define if you have the `socket' function. */
/* Define to 1 if you have the `select' function. */
#undef HAVE_SELECT
/* Define to 1 if you have the `socket' function. */
#undef HAVE_SOCKET
/* Define if you have the <stdint.h> header file. */
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
/* Define if you have the <stdlib.h> header file. */
/* Define to 1 if you have the <stdlib.h> header file. */
#undef HAVE_STDLIB_H
/* Define if you have the `strerror' function. */
/* Define to 1 if you have the `strerror' function. */
#undef HAVE_STRERROR
/* Define if you have the <strings.h> header file. */
/* Define to 1 if you have the <strings.h> header file. */
#undef HAVE_STRINGS_H
/* Define if you have the <string.h> header file. */
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define if you have the <stropts.h> header file. */
/* Define to 1 if you have the <stropts.h> header file. */
#undef HAVE_STROPTS_H
/* Define if you have the <sys/ioctl.h> header file. */
/* Define to 1 if you have the <sys/ioctl.h> header file. */
#undef HAVE_SYS_IOCTL_H
/* Define if you have the <sys/resource.h> header file. */
/* Define to 1 if you have the <sys/resource.h> header file. */
#undef HAVE_SYS_RESOURCE_H
/* Define if you have the <sys/stat.h> header file. */
/* Define to 1 if you have the <sys/select.h> header file. */
#undef HAVE_SYS_SELECT_H
/* Define to 1 if you have the <sys/socket.h> header file. */
#undef HAVE_SYS_SOCKET_H
/* Define to 1 if you have the <sys/stat.h> header file. */
#undef HAVE_SYS_STAT_H
/* Define if you have the <sys/types.h> header file. */
/* Define to 1 if you have the <sys/time.h> header file. */
#undef HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define if you have the <termios.h> header file. */
/* Define to 1 if you have the <termios.h> header file. */
#undef HAVE_TERMIOS_H
/* Define if you have the <unistd.h> header file. */
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define if you have the `unlockpt' function. */
/* Define to 1 if you have the `unlockpt' function. */
#undef HAVE_UNLOCKPT
/* Define if you have the <util.h> header file. */
/* Define to 1 if you have the <util.h> header file. */
#undef HAVE_UTIL_H
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define as the return type of signal handlers (`int' or `void'). */
#undef RETSIGTYPE
/* Define if you have the ANSI C header files. */
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
#undef TIME_WITH_SYS_TIME
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t

3300
configure vendored

File diff suppressed because it is too large Load Diff

36
configure.ac Normal file
View File

@ -0,0 +1,36 @@
# Process this file with autoconf to produce a configure script.
AC_INIT(dtach, 0.6, crigler@users.sourceforge.net)
AC_PREREQ(2.59)
AC_CONFIG_SRCDIR(main.c)
AC_CONFIG_HEADER(config.h)
# Checks for programs.
AC_PROG_CC
AC_PROG_GCC_TRADITIONAL
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -W -Wall";
fi
# Checks for libraries.
AC_CHECK_LIB(util, openpty)
AC_CHECK_LIB(socket, socket)
# Checks for header files.
AC_CHECK_HEADERS(fcntl.h sys/select.h sys/socket.h sys/time.h)
AC_CHECK_HEADERS(sys/ioctl.h sys/resource.h pty.h termios.h util.h)
AC_CHECK_HEADERS(libutil.h stropts.h)
AC_HEADER_TIME
# Checks for typedefs, structures, and compiler characteristics.
AC_C_CONST
AC_TYPE_PID_T
# Checks for library functions.
AC_TYPE_SIGNAL
AC_CHECK_FUNCS(atexit dup2 memset)
AC_CHECK_FUNCS(select socket strerror)
AC_CHECK_FUNCS(openpty forkpty ptsname grantpt unlockpt)
AC_CONFIG_FILES(Makefile)
AC_OUTPUT

View File

@ -1,29 +0,0 @@
dnl Process this file with autoconf to produce a configure script.
AC_INIT(main.c)
dnl Checks for programs.
AC_PROG_CC
if test "$GCC" = yes; then
CFLAGS="$CFLAGS -W -Wall";
fi
dnl Checks for libraries.
AC_CHECK_LIB(util, openpty)
AC_CHECK_LIB(socket, socket)
dnl Checks for header files.
AC_HEADER_STDC
AC_CHECK_HEADERS(sys/ioctl.h sys/resource.h pty.h termios.h util.h unistd.h)
AC_CHECK_HEADERS(libutil.h stropts.h)
dnl Checks for typedefs, structures, and compiler characteristics.
AC_TYPE_PID_T
dnl Checks for library functions.
AC_PROG_GCC_TRADITIONAL
AC_TYPE_SIGNAL
AC_CHECK_FUNCS(socket strerror getrlimit)
AC_CHECK_FUNCS(openpty forkpty ptsname grantpt unlockpt)
AC_CONFIG_HEADER(config.h)
AC_OUTPUT(Makefile)

View File

@ -1,4 +1,4 @@
.TH dtach 1 "November 2001" "dtach 0.5"
.TH dtach 1 "May 2004" "dtach 0.6"
.SH NAME
dtach \- simple program that emulates the detach feature of screen.
.SH SYNOPSIS
@ -119,7 +119,7 @@ way to detach from the session is then by sending the attaching process an
appropriate signal.
.TP
.B \-z
Inhibits processing of the suspend key.
Disables processing of the suspend key.
Normally,
.B dtach
will suspend itself when the suspend key is pressed. With this option, the
@ -146,8 +146,8 @@ Processing of the suspend character is also disabled for the attach instance.
.fi
.PP
.SH AUTHORS
Ned T. Crigler <crigler@hell-city.org>.
.SH AUTHOR
Ned T. Crigler <crigler@users.sourceforge.net>.
.SH "SEE ALSO"
.BR screen "(1)"

View File

@ -1,6 +1,6 @@
/*
dtach - A simple program that emulates the detach feature of screen.
Copyright (C) 2001 Ned T. Crigler
Copyright (C) 2001, 2004 Ned T. Crigler
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -16,10 +16,10 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef detach_h
#define detach_h
#ifndef dtach_h
#define dtach_h
#include "config.h"
#include <config.h>
#include <errno.h>
#include <fcntl.h>
@ -28,6 +28,17 @@
#include <stdlib.h>
#include <string.h>
#if TIME_WITH_SYS_TIME
#include <sys/time.h>
#include <time.h>
#else
#if HAVE_SYS_TIME_H
#include <sys/time.h>
#else
#include <time.h>
#endif
#endif
#ifdef HAVE_PTY_H
#include <pty.h>
#endif
@ -56,9 +67,8 @@
#include <sys/resource.h>
#endif
#include <poll.h>
#include <termios.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/un.h>
@ -70,10 +80,9 @@ extern struct termios orig_term;
enum
{
MSG_PUSH,
MSG_WINCH,
MSG_REDRAW,
MSG_ATTACH,
MSG_DETACH
MSG_DETACH,
MSG_WINCH,
};
/* The client to master protocol. */

View File

@ -1,6 +1,6 @@
Summary: A simple program that emulates the detach feature of screen.
Name: dtach
Version: 0.5
Version: 0.6
Release: 1
License: GPL
URL: http://dtach.sourceforge.net

33
main.c
View File

@ -1,6 +1,6 @@
/*
dtach - A simple program that emulates the detach feature of screen.
Copyright (C) 2001 Ned T. Crigler
Copyright (C) 2004 Ned T. Crigler
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -16,19 +16,16 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "detach.h"
#include "dtach.h"
/*
** detach is a quick hack, since I wanted the detach feature of screen without
** dtach is a quick hack, since I wanted the detach feature of screen without
** all the other crud. It'll work best with full-screen applications, as it
** does not keep track of the screen or anything like that.
*/
/* The program version */
#define VERSION "0.5"
/* Make sure the binary has a copyright. */
const char copyright[] = "dtach - version " VERSION " (C)Copyright 2001 Ned T. Crigler";
const char copyright[] = "dtach - version " PACKAGE_VERSION "(C)Copyright 2004 Ned T. Crigler";
/* argv[0] from the program */
char *progname;
@ -66,9 +63,9 @@ usage()
" -e <char>\tSet the detach character to <char>, defaults "
"to ^\\.\n"
" -E\t\tDisable the detach character.\n"
" -z\t\tInhibit processing of the suspend key.\n"
"\nReport any bugs to <crigler@hell-city.org>.\n",
VERSION, __DATE__, __TIME__);
" -z\t\tDisable processing of the suspend key.\n"
"\nReport any bugs to <" PACKAGE_BUGREPORT ">.\n",
PACKAGE_VERSION, __DATE__, __TIME__);
exit(0);
}
@ -89,7 +86,7 @@ main(int argc, char **argv)
else if (strncmp(*argv, "--version", strlen(*argv)) == 0)
{
printf("dtach - version %s, compiled on %s at %s.\n",
VERSION, __DATE__, __TIME__);
PACKAGE_VERSION, __DATE__, __TIME__);
return 0;
}
@ -100,7 +97,7 @@ main(int argc, char **argv)
mode != 'A')
{
printf("%s: Invalid mode '-%c'\n", progname, mode);
printf("Try '%s -?' for more information.\n",
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
@ -108,7 +105,7 @@ main(int argc, char **argv)
if (!mode)
{
printf("%s: No mode was specified.\n", progname);
printf("Try '%s -?' for more information.\n",
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
@ -117,7 +114,7 @@ main(int argc, char **argv)
if (argc < 1)
{
printf("%s: No socket was specified.\n", progname);
printf("Try '%s -?' for more information.\n",
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
@ -141,7 +138,7 @@ main(int argc, char **argv)
{
printf("%s: No escape character "
"specified.\n", progname);
printf("Try '%s -?' for more "
printf("Try '%s --help' for more "
"information.\n", progname);
return 1;
}
@ -160,7 +157,7 @@ main(int argc, char **argv)
{
printf("%s: Invalid option '-%c'\n",
progname, *p);
printf("Try '%s -?' for more information.\n",
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
@ -171,7 +168,7 @@ main(int argc, char **argv)
if (mode != 'a' && argc < 1)
{
printf("%s: No command was specified.\n", progname);
printf("Try '%s -?' for more information.\n",
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}
@ -189,7 +186,7 @@ main(int argc, char **argv)
{
printf("%s: Invalid number of arguments.\n",
progname);
printf("Try '%s -?' for more information.\n",
printf("Try '%s --help' for more information.\n",
progname);
return 1;
}

227
master.c
View File

@ -1,6 +1,6 @@
/*
dtach - A simple program that emulates the detach feature of screen.
Copyright (C) 2001 Ned T. Crigler
Copyright (C) 2004 Ned T. Crigler
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -16,7 +16,7 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "detach.h"
#include "dtach.h"
/* The pty struct - The pty information is stored here. */
struct pty
@ -27,6 +27,8 @@ struct pty
/* File descriptor of the slave side of the pty. For broken systems. */
int slave;
#endif
/* Process id of the child. */
pid_t pid;
/* The terminal parameters of the pty. Old and new for comparision
** purposes. */
struct termios term;
@ -34,17 +36,23 @@ struct pty
struct winsize ws;
};
/* The poll structures */
static struct pollfd *polls;
/* The number of active poll slots */
static int num_polls;
/* Boolean array for whether a particular connection is attached. */
static int *attached;
/* The highest file descriptor possible, as returned by getrlimit. */
static int highest_fd;
/* A connected client */
struct client
{
/* The next client in the linked list. */
struct client *next;
/* The previous client in the linked list. */
struct client **pprev;
/* File descriptor of the client. */
int fd;
/* Whether or not the client is attached. */
int attached;
};
/* The number of fixed slots in the poll structures */
#define FIXED_SLOTS 2
/* The list of connected clients. */
static struct client *clients;
/* The pseudo-terminal created for the child process. */
static struct pty the_pty;
#ifndef HAVE_FORKPTY
pid_t forkpty(int *amaster, char *name, struct termios *termp,
@ -67,7 +75,7 @@ die(int sig)
{
#ifdef BROKEN_MASTER
/* Damn you Solaris! */
close(polls[1].fd);
close(the_pty.fd);
#endif
return;
}
@ -76,27 +84,20 @@ die(int sig)
/* Initialize the pty structure. */
static int
init_pty(struct pty *pty, char **argv)
init_pty(char **argv)
{
pid_t pid;
/* Use the original terminal's settings. We don't have to set the
** window size here, because the attacher will send it in a packet. */
pty->term = orig_term;
the_pty.term = orig_term;
memset(&the_pty.ws, 0, sizeof(struct winsize));
/* Create the pty process */
pid = forkpty(&pty->fd, NULL, &pty->term, NULL);
if (pid < 0)
the_pty.pid = forkpty(&the_pty.fd, NULL, &the_pty.term, NULL);
if (the_pty.pid < 0)
return -1;
else if (pid == 0)
else if (the_pty.pid == 0)
{
int i;
/* Child.. Close some file descriptors and execute the
** program. */
for (i = highest_fd; i > 2; --i)
close(i);
/* Child.. Execute the program. */
execvp(*argv, argv);
exit(127);
}
@ -105,8 +106,8 @@ init_pty(struct pty *pty, char **argv)
{
char *buf;
buf = ptsname(pty->fd);
pty->slave = open(buf, O_RDWR|O_NOCTTY);
buf = ptsname(the_pty.fd);
the_pty.slave = open(buf, O_RDWR|O_NOCTTY);
}
#endif
return 0;
@ -143,16 +144,17 @@ create_socket(char *name)
return s;
}
/* Process activity on a pty - Input and terminal changes are sent out to
/* Process activity on the pty - Input and terminal changes are sent out to
** the attached clients. If the pty goes away, we die. */
static void
pty_activity(struct pty *pty)
pty_activity()
{
int i, len;
unsigned char buf[BUFSIZE];
struct client *p;
int len;
/* Read the pty activity */
len = read(pty->fd, buf, sizeof(buf));
len = read(the_pty.fd, buf, sizeof(buf));
/* Error -> die */
if (len <= 0)
@ -160,19 +162,19 @@ pty_activity(struct pty *pty)
#ifdef BROKEN_MASTER
/* Get the current terminal settings. */
if (tcgetattr(pty->slave, &pty->term) < 0)
if (tcgetattr(the_pty.slave, &the_pty.term) < 0)
exit(1);
#else
/* Get the current terminal settings. */
if (tcgetattr(pty->fd, &pty->term) < 0)
if (tcgetattr(the_pty.fd, &the_pty.term) < 0)
exit(1);
#endif
/* Send it out to the clients. */
for (i = FIXED_SLOTS; i < num_polls; ++i)
for (p = clients; p; p = p->next)
{
if (attached[polls[i].fd])
write(polls[i].fd, buf, len);
if (p->attached)
write(p->fd, buf, len);
}
}
@ -181,65 +183,75 @@ static void
control_activity(int s)
{
int fd;
struct client *p;
/* Accept the new client and link it in. */
fd = accept(s, 0, 0);
fd = accept(s, NULL, NULL);
if (fd < 0)
return;
/* Link it in. */
polls[num_polls].fd = fd;
polls[num_polls].events = POLLIN;
polls[num_polls].revents = 0;
attached[fd] = 1;
++num_polls;
p = malloc(sizeof(struct client));
p->fd = fd;
p->attached = 0;
p->pprev = &clients;
p->next = *(p->pprev);
if (p->next)
p->next->pprev = &p->next;
*(p->pprev) = p;
}
/* Process activity from a client. */
static void
client_activity(int i, struct pty *pty)
client_activity(struct client *p)
{
int len;
struct packet pkt;
/* Read the activity. */
len = read(polls[i].fd, &pkt, sizeof(pkt));
len = read(p->fd, &pkt, sizeof(pkt));
/* Close the client on an error. */
if (len <= 0)
{
/* Close the socket and go bye bye */
attached[polls[i].fd]=0;
close(polls[i].fd);
memcpy(polls + i, polls + i + 1, num_polls - i);
--num_polls;
close(p->fd);
if (p->next)
p->next->pprev = p->pprev;
*(p->pprev) = p->next;
free(p);
return;
}
/* Okay, check the command byte. Push out data if we need to. */
/* Push out data to the program. */
if (pkt.type == MSG_PUSH)
write(pty->fd, pkt.u.buf, pkt.len);
/* Window size change. */
write(the_pty.fd, pkt.u.buf, pkt.len);
/* When attaching, we set the window size and force a redraw by sending
** the WINCH signal to the program.
**
** XXX: Are there any programs that don't handle the WINCH signal
** properly? Full-screen programs should fully redraw themselves, and
** line-oriented programs should redraw the prompt, or do nothing.
*/
else if (pkt.type == MSG_ATTACH)
{
p->attached = 1;
if (memcmp(&the_pty.ws, &pkt.u.ws, sizeof(struct winsize)) != 0)
{
the_pty.ws = pkt.u.ws;
ioctl(the_pty.fd, TIOCSWINSZ, &the_pty.ws);
}
else
kill(-the_pty.pid, SIGWINCH);
}
else if (pkt.type == MSG_DETACH)
p->attached = 0;
/* Window size change request, without a forced redraw. */
else if (pkt.type == MSG_WINCH)
{
pty->ws = pkt.u.ws;
ioctl(pty->fd, TIOCSWINSZ, &pty->ws);
the_pty.ws = pkt.u.ws;
ioctl(the_pty.fd, TIOCSWINSZ, &the_pty.ws);
}
/* Redraw request? */
else if (pkt.type == MSG_REDRAW)
{
char c = '\f';
/* Guess that ^L might work under certain conditions. */
if (((pty->term.c_lflag & (ECHO|ICANON)) == 0) &&
(pty->term.c_cc[VMIN] == 1))
{
write(pty->fd, &c, sizeof(c));
}
}
/* Attach request? */
else if (pkt.type == MSG_ATTACH)
attached[polls[i].fd] = 1;
else if (pkt.type == MSG_DETACH)
attached[polls[i].fd] = 0;
}
/* The master process - It watches over the pty process and the attached */
@ -247,35 +259,16 @@ client_activity(int i, struct pty *pty)
static void
master_process(int s, char **argv)
{
struct pty pty;
int i;
#ifdef HAVE_GETRLIMIT
struct rlimit rlim;
/* Dynamically allocate structures based on the number of file
** descriptors. */
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
{
printf("%s: getrlimit: %s\n", progname, strerror(errno));
exit(1);
}
highest_fd = rlim.rlim_cur;
#else
/* We can't query the OS for the number of file descriptors, so
** we pull a number out of the air. */
highest_fd = 1024;
#endif
polls = (struct pollfd*)malloc(highest_fd * sizeof(struct pollfd));
attached = (int*)malloc(highest_fd * sizeof(int));
struct client *p, *next;
fd_set readfds;
int highest_fd;
/* Okay, disassociate ourselves from the original terminal, as we
** don't care what happens to it. */
setsid();
/* Create a pty in which the process is running. */
if (init_pty(&pty, argv) < 0)
if (init_pty(argv) < 0)
{
printf("%s: init_pty: %s\n", progname, strerror(errno));
exit(1);
@ -296,40 +289,46 @@ master_process(int s, char **argv)
fclose(stdout);
fclose(stderr);
/* Set a trap to unlink the socket when we die */
/* Set a trap to unlink the socket when we die. */
atexit(unlink_socket);
/* Set up the poll structures. Slot 0 is the control socket, slot 1
** is the pty, and slot 2 .. n is the connected clients. */
polls[0].fd = s;
polls[0].events = POLLIN;
polls[0].revents = 0;
polls[1].fd = pty.fd;
polls[1].events = POLLIN;
polls[1].revents = 0;
num_polls = FIXED_SLOTS;
/* Loop forever. */
while (1)
{
/* Re-initialize the file descriptor set for select. */
FD_ZERO(&readfds);
FD_SET(s, &readfds);
FD_SET(the_pty.fd, &readfds);
if (s > the_pty.fd)
highest_fd = s;
else
highest_fd = the_pty.fd;
for (p = clients; p; p = p->next)
{
FD_SET(p->fd, &readfds);
if (p->fd > highest_fd)
highest_fd = p->fd;
}
/* Wait for something to happen. */
if (poll(polls, num_polls, -1) < 0)
if (select(highest_fd + 1, &readfds, NULL, NULL, NULL) < 0)
{
if (errno == EINTR || errno == EAGAIN)
continue;
exit(1);
}
/* pty activity? */
if (polls[1].revents != 0)
pty_activity(&pty);
if (FD_ISSET(the_pty.fd, &readfds))
pty_activity(&the_pty);
/* New client? */
if (polls[0].revents != 0)
if (FD_ISSET(s, &readfds))
control_activity(s);
/* Activity on a client? */
for (i = 2; i < num_polls; ++i)
for (p = clients; p; p = next)
{
if (polls[i].revents != 0)
client_activity(i, &pty);
next = p->next;
if (FD_ISSET(p->fd, &readfds))
client_activity(p);
}
}
}