dtach 0.6
This commit is contained in:
parent
b87318d1f3
commit
abf2db3509
|
|
@ -3,7 +3,7 @@ CC = @CC@
|
||||||
CFLAGS = @CFLAGS@ -I.
|
CFLAGS = @CFLAGS@ -I.
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
VERSION = 0.5
|
VERSION = @PACKAGE_VERSION@
|
||||||
VPATH = $(srcdir)
|
VPATH = $(srcdir)
|
||||||
|
|
||||||
OBJ = attach.o master.o main.o
|
OBJ = attach.o master.o main.o
|
||||||
|
|
@ -29,7 +29,7 @@ tar:
|
||||||
gzip -9f dtach-$(VERSION).tar
|
gzip -9f dtach-$(VERSION).tar
|
||||||
rm -rf dtach-$(VERSION)
|
rm -rf dtach-$(VERSION)
|
||||||
|
|
||||||
attach.o: @srcdir@/attach.c @srcdir@/detach.h config.h
|
attach.o: @srcdir@/attach.c @srcdir@/dtach.h config.h
|
||||||
master.o: @srcdir@/master.c @srcdir@/detach.h config.h
|
master.o: @srcdir@/master.c @srcdir@/dtach.h config.h
|
||||||
main.o: @srcdir@/main.c @srcdir@/detach.h config.h
|
main.o: @srcdir@/main.c @srcdir@/dtach.h config.h
|
||||||
|
|
||||||
|
|
|
||||||
16
README
16
README
|
|
@ -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
|
For example, let's create a new session that is running ircII. We will use
|
||||||
/tmp/foozle as the session's socket:
|
/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
|
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
|
existing session. If the session at /tmp/foozle does not exist yet, the
|
||||||
|
|
@ -96,6 +96,16 @@ to dtach when attaching.
|
||||||
|
|
||||||
5. CHANGES
|
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:
|
The changes in version 0.5 are:
|
||||||
- Fix fd leakage.
|
- Fix fd leakage.
|
||||||
- Prevent atexit from being called twice on dtach -A.
|
- Prevent atexit from being called twice on dtach -A.
|
||||||
|
|
@ -119,8 +129,8 @@ The changes in version 0.3 are:
|
||||||
|
|
||||||
6. AUTHOR
|
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.
|
Public License.
|
||||||
|
|
||||||
Comments and suggestions about dtach are welcome, and can be sent to
|
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>.
|
||||||
|
|
|
||||||
58
attach.c
58
attach.c
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
dtach - A simple program that emulates the detach feature of screen.
|
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
|
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
|
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
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#include "detach.h"
|
#include "dtach.h"
|
||||||
|
|
||||||
#ifndef VDISABLE
|
#ifndef VDISABLE
|
||||||
#ifdef _POSIX_VDISABLE
|
#ifdef _POSIX_VDISABLE
|
||||||
|
|
@ -33,8 +33,6 @@
|
||||||
static struct termios cur_term;
|
static struct termios cur_term;
|
||||||
/* 1 if the window size changed */
|
/* 1 if the window size changed */
|
||||||
static int win_changed;
|
static int win_changed;
|
||||||
/* 1 if we want a redraw */
|
|
||||||
static int want_redraw;
|
|
||||||
|
|
||||||
/* This hopefully moves to the bottom of the screen */
|
/* This hopefully moves to the bottom of the screen */
|
||||||
#define EOS "\033[999H"
|
#define EOS "\033[999H"
|
||||||
|
|
@ -108,19 +106,15 @@ process_kbd(int s, struct packet *pkt)
|
||||||
|
|
||||||
/* Tell the master that we are returning. */
|
/* Tell the master that we are returning. */
|
||||||
pkt->type = MSG_ATTACH;
|
pkt->type = MSG_ATTACH;
|
||||||
|
ioctl(0, TIOCGWINSZ, &pkt->u.ws);
|
||||||
write(s, pkt, sizeof(*pkt));
|
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;
|
return;
|
||||||
}
|
}
|
||||||
/* Detach char? */
|
/* Detach char? */
|
||||||
else if (pkt->u.buf[0] == detach_char)
|
else if (pkt->u.buf[0] == detach_char)
|
||||||
{
|
{
|
||||||
printf(EOS "\r\n[detached]\r\n");
|
printf(EOS "\r\n[detached]\r\n");
|
||||||
exit(1);
|
exit(0);
|
||||||
}
|
}
|
||||||
/* Just in case something pukes out. */
|
/* Just in case something pukes out. */
|
||||||
else if (pkt->u.buf[0] == '\f')
|
else if (pkt->u.buf[0] == '\f')
|
||||||
|
|
@ -133,10 +127,10 @@ process_kbd(int s, struct packet *pkt)
|
||||||
int
|
int
|
||||||
attach_main(int noerror)
|
attach_main(int noerror)
|
||||||
{
|
{
|
||||||
int s;
|
|
||||||
struct pollfd polls[2];
|
|
||||||
struct packet pkt;
|
struct packet pkt;
|
||||||
unsigned char buf[BUFSIZE];
|
unsigned char buf[BUFSIZE];
|
||||||
|
fd_set readfds;
|
||||||
|
int s;
|
||||||
|
|
||||||
/* Attempt to open the socket. Don't display an error if noerror is
|
/* Attempt to open the socket. Don't display an error if noerror is
|
||||||
** set. */
|
** set. */
|
||||||
|
|
@ -165,8 +159,9 @@ attach_main(int noerror)
|
||||||
signal(SIGQUIT, die);
|
signal(SIGQUIT, die);
|
||||||
signal(SIGWINCH, win_change);
|
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 &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL);
|
||||||
|
cur_term.c_iflag &= ~(IXON|IXOFF);
|
||||||
cur_term.c_oflag &= ~(OPOST);
|
cur_term.c_oflag &= ~(OPOST);
|
||||||
cur_term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
cur_term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
|
||||||
cur_term.c_cflag &= ~(CSIZE|PARENB);
|
cur_term.c_cflag &= ~(CSIZE|PARENB);
|
||||||
|
|
@ -174,41 +169,32 @@ attach_main(int noerror)
|
||||||
cur_term.c_cc[VLNEXT] = VDISABLE;
|
cur_term.c_cc[VLNEXT] = VDISABLE;
|
||||||
cur_term.c_cc[VMIN] = 1;
|
cur_term.c_cc[VMIN] = 1;
|
||||||
cur_term.c_cc[VTIME] = 0;
|
cur_term.c_cc[VTIME] = 0;
|
||||||
|
|
||||||
tcsetattr(0, TCSADRAIN, &cur_term);
|
tcsetattr(0, TCSADRAIN, &cur_term);
|
||||||
|
|
||||||
/* Clear the screen. This assumes VT100. */
|
/* Clear the screen. This assumes VT100. */
|
||||||
write(1, "\33[H\33[J", 6);
|
write(1, "\33[H\33[J", 6);
|
||||||
|
|
||||||
/* Set up the poll structures */
|
/* Tell the master that we want to attach. */
|
||||||
polls[0].fd = 0;
|
pkt.type = MSG_ATTACH;
|
||||||
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;
|
|
||||||
ioctl(0, TIOCGWINSZ, &pkt.u.ws);
|
ioctl(0, TIOCGWINSZ, &pkt.u.ws);
|
||||||
write(s, &pkt, sizeof(pkt));
|
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 */
|
/* Wait for things to happen */
|
||||||
while (1)
|
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)
|
if (errno != EINTR && errno != EAGAIN)
|
||||||
{
|
{
|
||||||
printf(EOS "\r\n[poll failed]\r\n");
|
printf(EOS "\r\n[select failed]\r\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Pty activity */
|
/* Pty activity */
|
||||||
if (polls[1].revents != 0)
|
if (FD_ISSET(s, &readfds))
|
||||||
{
|
{
|
||||||
int len = read(s, buf, sizeof(buf));
|
int len = read(s, buf, sizeof(buf));
|
||||||
|
|
||||||
|
|
@ -216,7 +202,7 @@ attach_main(int noerror)
|
||||||
{
|
{
|
||||||
printf(EOS "\r\n[EOF - dtach terminating]"
|
printf(EOS "\r\n[EOF - dtach terminating]"
|
||||||
"\r\n");
|
"\r\n");
|
||||||
exit(1);
|
exit(0);
|
||||||
}
|
}
|
||||||
else if (len < 0)
|
else if (len < 0)
|
||||||
{
|
{
|
||||||
|
|
@ -227,7 +213,7 @@ attach_main(int noerror)
|
||||||
write(1, buf, len);
|
write(1, buf, len);
|
||||||
}
|
}
|
||||||
/* stdin activity */
|
/* stdin activity */
|
||||||
if (polls[0].revents != 0)
|
if (FD_ISSET(0, &readfds))
|
||||||
{
|
{
|
||||||
pkt.type = MSG_PUSH;
|
pkt.type = MSG_PUSH;
|
||||||
memset(pkt.u.buf, 0, sizeof(pkt.u.buf));
|
memset(pkt.u.buf, 0, sizeof(pkt.u.buf));
|
||||||
|
|
@ -246,14 +232,6 @@ attach_main(int noerror)
|
||||||
ioctl(0, TIOCGWINSZ, &pkt.u.ws);
|
ioctl(0, TIOCGWINSZ, &pkt.u.ws);
|
||||||
write(s, &pkt, sizeof(pkt));
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
102
config.h.in
102
config.h.in
|
|
@ -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
|
#undef HAVE_FORKPTY
|
||||||
|
|
||||||
/* Define if you have the `getrlimit' function. */
|
/* Define to 1 if you have the `grantpt' function. */
|
||||||
#undef HAVE_GETRLIMIT
|
|
||||||
|
|
||||||
/* Define if you have the `grantpt' function. */
|
|
||||||
#undef HAVE_GRANTPT
|
#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
|
#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
|
#undef HAVE_LIBSOCKET
|
||||||
|
|
||||||
/* Define if you have the `util' library (-lutil). */
|
/* Define to 1 if you have the `util' library (-lutil). */
|
||||||
#undef HAVE_LIBUTIL
|
#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
|
#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
|
#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
|
#undef HAVE_OPENPTY
|
||||||
|
|
||||||
/* Define if you have the `ptsname' function. */
|
/* Define to 1 if you have the `ptsname' function. */
|
||||||
#undef HAVE_PTSNAME
|
#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
|
#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
|
#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
|
#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
|
#undef HAVE_STDLIB_H
|
||||||
|
|
||||||
/* Define if you have the `strerror' function. */
|
/* Define to 1 if you have the `strerror' function. */
|
||||||
#undef HAVE_STRERROR
|
#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
|
#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
|
#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
|
#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
|
#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
|
#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
|
#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
|
#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
|
#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
|
#undef HAVE_UNISTD_H
|
||||||
|
|
||||||
/* Define if you have the `unlockpt' function. */
|
/* Define to 1 if you have the `unlockpt' function. */
|
||||||
#undef HAVE_UNLOCKPT
|
#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
|
#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'). */
|
/* Define as the return type of signal handlers (`int' or `void'). */
|
||||||
#undef RETSIGTYPE
|
#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
|
#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. */
|
/* Define to `int' if <sys/types.h> does not define. */
|
||||||
#undef pid_t
|
#undef pid_t
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
29
configure.in
29
configure.in
|
|
@ -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)
|
|
||||||
8
dtach.1
8
dtach.1
|
|
@ -1,4 +1,4 @@
|
||||||
.TH dtach 1 "November 2001" "dtach 0.5"
|
.TH dtach 1 "May 2004" "dtach 0.6"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
dtach \- simple program that emulates the detach feature of screen.
|
dtach \- simple program that emulates the detach feature of screen.
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
|
|
@ -119,7 +119,7 @@ way to detach from the session is then by sending the attaching process an
|
||||||
appropriate signal.
|
appropriate signal.
|
||||||
.TP
|
.TP
|
||||||
.B \-z
|
.B \-z
|
||||||
Inhibits processing of the suspend key.
|
Disables processing of the suspend key.
|
||||||
Normally,
|
Normally,
|
||||||
.B dtach
|
.B dtach
|
||||||
will suspend itself when the suspend key is pressed. With this option, the
|
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
|
.fi
|
||||||
|
|
||||||
.PP
|
.PP
|
||||||
.SH AUTHORS
|
.SH AUTHOR
|
||||||
Ned T. Crigler <crigler@hell-city.org>.
|
Ned T. Crigler <crigler@users.sourceforge.net>.
|
||||||
|
|
||||||
.SH "SEE ALSO"
|
.SH "SEE ALSO"
|
||||||
.BR screen "(1)"
|
.BR screen "(1)"
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
dtach - A simple program that emulates the detach feature of screen.
|
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
|
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
|
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
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
#ifndef detach_h
|
#ifndef dtach_h
|
||||||
#define detach_h
|
#define dtach_h
|
||||||
|
|
||||||
#include "config.h"
|
#include <config.h>
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
@ -28,6 +28,17 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.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
|
#ifdef HAVE_PTY_H
|
||||||
#include <pty.h>
|
#include <pty.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -56,9 +67,8 @@
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <poll.h>
|
|
||||||
#include <termios.h>
|
#include <termios.h>
|
||||||
|
#include <sys/select.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
|
|
@ -70,10 +80,9 @@ extern struct termios orig_term;
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
MSG_PUSH,
|
MSG_PUSH,
|
||||||
MSG_WINCH,
|
|
||||||
MSG_REDRAW,
|
|
||||||
MSG_ATTACH,
|
MSG_ATTACH,
|
||||||
MSG_DETACH
|
MSG_DETACH,
|
||||||
|
MSG_WINCH,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The client to master protocol. */
|
/* The client to master protocol. */
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
Summary: A simple program that emulates the detach feature of screen.
|
Summary: A simple program that emulates the detach feature of screen.
|
||||||
Name: dtach
|
Name: dtach
|
||||||
Version: 0.5
|
Version: 0.6
|
||||||
Release: 1
|
Release: 1
|
||||||
License: GPL
|
License: GPL
|
||||||
URL: http://dtach.sourceforge.net
|
URL: http://dtach.sourceforge.net
|
||||||
|
|
|
||||||
33
main.c
33
main.c
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
dtach - A simple program that emulates the detach feature of screen.
|
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
|
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
|
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
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
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
|
** 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.
|
** 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. */
|
/* 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 */
|
/* argv[0] from the program */
|
||||||
char *progname;
|
char *progname;
|
||||||
|
|
@ -66,9 +63,9 @@ usage()
|
||||||
" -e <char>\tSet the detach character to <char>, defaults "
|
" -e <char>\tSet the detach character to <char>, defaults "
|
||||||
"to ^\\.\n"
|
"to ^\\.\n"
|
||||||
" -E\t\tDisable the detach character.\n"
|
" -E\t\tDisable the detach character.\n"
|
||||||
" -z\t\tInhibit processing of the suspend key.\n"
|
" -z\t\tDisable processing of the suspend key.\n"
|
||||||
"\nReport any bugs to <crigler@hell-city.org>.\n",
|
"\nReport any bugs to <" PACKAGE_BUGREPORT ">.\n",
|
||||||
VERSION, __DATE__, __TIME__);
|
PACKAGE_VERSION, __DATE__, __TIME__);
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,7 +86,7 @@ main(int argc, char **argv)
|
||||||
else if (strncmp(*argv, "--version", strlen(*argv)) == 0)
|
else if (strncmp(*argv, "--version", strlen(*argv)) == 0)
|
||||||
{
|
{
|
||||||
printf("dtach - version %s, compiled on %s at %s.\n",
|
printf("dtach - version %s, compiled on %s at %s.\n",
|
||||||
VERSION, __DATE__, __TIME__);
|
PACKAGE_VERSION, __DATE__, __TIME__);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +97,7 @@ main(int argc, char **argv)
|
||||||
mode != 'A')
|
mode != 'A')
|
||||||
{
|
{
|
||||||
printf("%s: Invalid mode '-%c'\n", progname, mode);
|
printf("%s: Invalid mode '-%c'\n", progname, mode);
|
||||||
printf("Try '%s -?' for more information.\n",
|
printf("Try '%s --help' for more information.\n",
|
||||||
progname);
|
progname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +105,7 @@ main(int argc, char **argv)
|
||||||
if (!mode)
|
if (!mode)
|
||||||
{
|
{
|
||||||
printf("%s: No mode was specified.\n", progname);
|
printf("%s: No mode was specified.\n", progname);
|
||||||
printf("Try '%s -?' for more information.\n",
|
printf("Try '%s --help' for more information.\n",
|
||||||
progname);
|
progname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -117,7 +114,7 @@ main(int argc, char **argv)
|
||||||
if (argc < 1)
|
if (argc < 1)
|
||||||
{
|
{
|
||||||
printf("%s: No socket was specified.\n", progname);
|
printf("%s: No socket was specified.\n", progname);
|
||||||
printf("Try '%s -?' for more information.\n",
|
printf("Try '%s --help' for more information.\n",
|
||||||
progname);
|
progname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -141,7 +138,7 @@ main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
printf("%s: No escape character "
|
printf("%s: No escape character "
|
||||||
"specified.\n", progname);
|
"specified.\n", progname);
|
||||||
printf("Try '%s -?' for more "
|
printf("Try '%s --help' for more "
|
||||||
"information.\n", progname);
|
"information.\n", progname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -160,7 +157,7 @@ main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
printf("%s: Invalid option '-%c'\n",
|
printf("%s: Invalid option '-%c'\n",
|
||||||
progname, *p);
|
progname, *p);
|
||||||
printf("Try '%s -?' for more information.\n",
|
printf("Try '%s --help' for more information.\n",
|
||||||
progname);
|
progname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -171,7 +168,7 @@ main(int argc, char **argv)
|
||||||
if (mode != 'a' && argc < 1)
|
if (mode != 'a' && argc < 1)
|
||||||
{
|
{
|
||||||
printf("%s: No command was specified.\n", progname);
|
printf("%s: No command was specified.\n", progname);
|
||||||
printf("Try '%s -?' for more information.\n",
|
printf("Try '%s --help' for more information.\n",
|
||||||
progname);
|
progname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -189,7 +186,7 @@ main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
printf("%s: Invalid number of arguments.\n",
|
printf("%s: Invalid number of arguments.\n",
|
||||||
progname);
|
progname);
|
||||||
printf("Try '%s -?' for more information.\n",
|
printf("Try '%s --help' for more information.\n",
|
||||||
progname);
|
progname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
227
master.c
227
master.c
|
|
@ -1,6 +1,6 @@
|
||||||
/*
|
/*
|
||||||
dtach - A simple program that emulates the detach feature of screen.
|
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
|
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
|
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
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
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. */
|
/* The pty struct - The pty information is stored here. */
|
||||||
struct pty
|
struct pty
|
||||||
|
|
@ -27,6 +27,8 @@ struct pty
|
||||||
/* File descriptor of the slave side of the pty. For broken systems. */
|
/* File descriptor of the slave side of the pty. For broken systems. */
|
||||||
int slave;
|
int slave;
|
||||||
#endif
|
#endif
|
||||||
|
/* Process id of the child. */
|
||||||
|
pid_t pid;
|
||||||
/* The terminal parameters of the pty. Old and new for comparision
|
/* The terminal parameters of the pty. Old and new for comparision
|
||||||
** purposes. */
|
** purposes. */
|
||||||
struct termios term;
|
struct termios term;
|
||||||
|
|
@ -34,17 +36,23 @@ struct pty
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The poll structures */
|
/* A connected client */
|
||||||
static struct pollfd *polls;
|
struct client
|
||||||
/* The number of active poll slots */
|
{
|
||||||
static int num_polls;
|
/* The next client in the linked list. */
|
||||||
/* Boolean array for whether a particular connection is attached. */
|
struct client *next;
|
||||||
static int *attached;
|
/* The previous client in the linked list. */
|
||||||
/* The highest file descriptor possible, as returned by getrlimit. */
|
struct client **pprev;
|
||||||
static int highest_fd;
|
/* 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 */
|
/* The list of connected clients. */
|
||||||
#define FIXED_SLOTS 2
|
static struct client *clients;
|
||||||
|
/* The pseudo-terminal created for the child process. */
|
||||||
|
static struct pty the_pty;
|
||||||
|
|
||||||
#ifndef HAVE_FORKPTY
|
#ifndef HAVE_FORKPTY
|
||||||
pid_t forkpty(int *amaster, char *name, struct termios *termp,
|
pid_t forkpty(int *amaster, char *name, struct termios *termp,
|
||||||
|
|
@ -67,7 +75,7 @@ die(int sig)
|
||||||
{
|
{
|
||||||
#ifdef BROKEN_MASTER
|
#ifdef BROKEN_MASTER
|
||||||
/* Damn you Solaris! */
|
/* Damn you Solaris! */
|
||||||
close(polls[1].fd);
|
close(the_pty.fd);
|
||||||
#endif
|
#endif
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -76,27 +84,20 @@ die(int sig)
|
||||||
|
|
||||||
/* Initialize the pty structure. */
|
/* Initialize the pty structure. */
|
||||||
static int
|
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
|
/* 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. */
|
** 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 */
|
/* Create the pty process */
|
||||||
pid = forkpty(&pty->fd, NULL, &pty->term, NULL);
|
the_pty.pid = forkpty(&the_pty.fd, NULL, &the_pty.term, NULL);
|
||||||
if (pid < 0)
|
if (the_pty.pid < 0)
|
||||||
return -1;
|
return -1;
|
||||||
else if (pid == 0)
|
else if (the_pty.pid == 0)
|
||||||
{
|
{
|
||||||
int i;
|
/* Child.. Execute the program. */
|
||||||
|
|
||||||
/* Child.. Close some file descriptors and execute the
|
|
||||||
** program. */
|
|
||||||
for (i = highest_fd; i > 2; --i)
|
|
||||||
close(i);
|
|
||||||
|
|
||||||
execvp(*argv, argv);
|
execvp(*argv, argv);
|
||||||
exit(127);
|
exit(127);
|
||||||
}
|
}
|
||||||
|
|
@ -105,8 +106,8 @@ init_pty(struct pty *pty, char **argv)
|
||||||
{
|
{
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
buf = ptsname(pty->fd);
|
buf = ptsname(the_pty.fd);
|
||||||
pty->slave = open(buf, O_RDWR|O_NOCTTY);
|
the_pty.slave = open(buf, O_RDWR|O_NOCTTY);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -143,16 +144,17 @@ create_socket(char *name)
|
||||||
return s;
|
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. */
|
** the attached clients. If the pty goes away, we die. */
|
||||||
static void
|
static void
|
||||||
pty_activity(struct pty *pty)
|
pty_activity()
|
||||||
{
|
{
|
||||||
int i, len;
|
|
||||||
unsigned char buf[BUFSIZE];
|
unsigned char buf[BUFSIZE];
|
||||||
|
struct client *p;
|
||||||
|
int len;
|
||||||
|
|
||||||
/* Read the pty activity */
|
/* Read the pty activity */
|
||||||
len = read(pty->fd, buf, sizeof(buf));
|
len = read(the_pty.fd, buf, sizeof(buf));
|
||||||
|
|
||||||
/* Error -> die */
|
/* Error -> die */
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
|
|
@ -160,19 +162,19 @@ pty_activity(struct pty *pty)
|
||||||
|
|
||||||
#ifdef BROKEN_MASTER
|
#ifdef BROKEN_MASTER
|
||||||
/* Get the current terminal settings. */
|
/* Get the current terminal settings. */
|
||||||
if (tcgetattr(pty->slave, &pty->term) < 0)
|
if (tcgetattr(the_pty.slave, &the_pty.term) < 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
#else
|
#else
|
||||||
/* Get the current terminal settings. */
|
/* Get the current terminal settings. */
|
||||||
if (tcgetattr(pty->fd, &pty->term) < 0)
|
if (tcgetattr(the_pty.fd, &the_pty.term) < 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Send it out to the clients. */
|
/* 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])
|
if (p->attached)
|
||||||
write(polls[i].fd, buf, len);
|
write(p->fd, buf, len);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -181,65 +183,75 @@ static void
|
||||||
control_activity(int s)
|
control_activity(int s)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
struct client *p;
|
||||||
|
|
||||||
/* Accept the new client and link it in. */
|
/* Accept the new client and link it in. */
|
||||||
fd = accept(s, 0, 0);
|
fd = accept(s, NULL, NULL);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Link it in. */
|
/* Link it in. */
|
||||||
polls[num_polls].fd = fd;
|
p = malloc(sizeof(struct client));
|
||||||
polls[num_polls].events = POLLIN;
|
p->fd = fd;
|
||||||
polls[num_polls].revents = 0;
|
p->attached = 0;
|
||||||
attached[fd] = 1;
|
p->pprev = &clients;
|
||||||
++num_polls;
|
p->next = *(p->pprev);
|
||||||
|
if (p->next)
|
||||||
|
p->next->pprev = &p->next;
|
||||||
|
*(p->pprev) = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Process activity from a client. */
|
/* Process activity from a client. */
|
||||||
static void
|
static void
|
||||||
client_activity(int i, struct pty *pty)
|
client_activity(struct client *p)
|
||||||
{
|
{
|
||||||
int len;
|
int len;
|
||||||
struct packet pkt;
|
struct packet pkt;
|
||||||
|
|
||||||
/* Read the activity. */
|
/* 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)
|
if (len <= 0)
|
||||||
{
|
{
|
||||||
/* Close the socket and go bye bye */
|
close(p->fd);
|
||||||
attached[polls[i].fd]=0;
|
if (p->next)
|
||||||
close(polls[i].fd);
|
p->next->pprev = p->pprev;
|
||||||
memcpy(polls + i, polls + i + 1, num_polls - i);
|
*(p->pprev) = p->next;
|
||||||
--num_polls;
|
free(p);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Okay, check the command byte. Push out data if we need to. */
|
/* Push out data to the program. */
|
||||||
if (pkt.type == MSG_PUSH)
|
if (pkt.type == MSG_PUSH)
|
||||||
write(pty->fd, pkt.u.buf, pkt.len);
|
write(the_pty.fd, pkt.u.buf, pkt.len);
|
||||||
/* Window size change. */
|
|
||||||
|
/* 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)
|
else if (pkt.type == MSG_WINCH)
|
||||||
{
|
{
|
||||||
pty->ws = pkt.u.ws;
|
the_pty.ws = pkt.u.ws;
|
||||||
ioctl(pty->fd, TIOCSWINSZ, &pty->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 */
|
/* 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
|
static void
|
||||||
master_process(int s, char **argv)
|
master_process(int s, char **argv)
|
||||||
{
|
{
|
||||||
struct pty pty;
|
struct client *p, *next;
|
||||||
int i;
|
fd_set readfds;
|
||||||
|
int highest_fd;
|
||||||
#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));
|
|
||||||
|
|
||||||
/* Okay, disassociate ourselves from the original terminal, as we
|
/* Okay, disassociate ourselves from the original terminal, as we
|
||||||
** don't care what happens to it. */
|
** don't care what happens to it. */
|
||||||
setsid();
|
setsid();
|
||||||
|
|
||||||
/* Create a pty in which the process is running. */
|
/* 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));
|
printf("%s: init_pty: %s\n", progname, strerror(errno));
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
@ -296,40 +289,46 @@ master_process(int s, char **argv)
|
||||||
fclose(stdout);
|
fclose(stdout);
|
||||||
fclose(stderr);
|
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);
|
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. */
|
/* Loop forever. */
|
||||||
while (1)
|
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. */
|
/* 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)
|
if (errno == EINTR || errno == EAGAIN)
|
||||||
continue;
|
continue;
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
/* pty activity? */
|
/* pty activity? */
|
||||||
if (polls[1].revents != 0)
|
if (FD_ISSET(the_pty.fd, &readfds))
|
||||||
pty_activity(&pty);
|
pty_activity(&the_pty);
|
||||||
/* New client? */
|
/* New client? */
|
||||||
if (polls[0].revents != 0)
|
if (FD_ISSET(s, &readfds))
|
||||||
control_activity(s);
|
control_activity(s);
|
||||||
/* Activity on a client? */
|
/* Activity on a client? */
|
||||||
for (i = 2; i < num_polls; ++i)
|
for (p = clients; p; p = next)
|
||||||
{
|
{
|
||||||
if (polls[i].revents != 0)
|
next = p->next;
|
||||||
client_activity(i, &pty);
|
if (FD_ISSET(p->fd, &readfds))
|
||||||
|
client_activity(p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue