dtach 0.6
This commit is contained in:
parent
b87318d1f3
commit
abf2db3509
|
|
@ -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
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
|
||||
/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>.
|
||||
|
|
|
|||
58
attach.c
58
attach.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
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
|
||||
|
||||
/* 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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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)"
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
@ -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
33
main.c
|
|
@ -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
227
master.c
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue