Portability updates thanks to sourceforge's compile farm. dtach should now
work on: FreeBSD, Debian/alpha, Debian/sparc, Debian/PPC, and Solaris. Bump version.
This commit is contained in:
parent
ba4a3a502f
commit
203193838d
14
Makefile.in
14
Makefile.in
|
|
@ -1,9 +1,9 @@
|
||||||
srcdir = @srcdir@
|
srcdir = @srcdir@
|
||||||
CC = @CC@
|
CC = @CC@
|
||||||
CFLAGS = -W -Wall -I. @CFLAGS@
|
CFLAGS = @CFLAGS@ -I.
|
||||||
LDFLAGS = @LDFLAGS@
|
LDFLAGS = @LDFLAGS@
|
||||||
LIBS = @LIBS@
|
LIBS = @LIBS@
|
||||||
VERSION = 0.3
|
VERSION = 0.4
|
||||||
VPATH = $(srcdir)
|
VPATH = $(srcdir)
|
||||||
|
|
||||||
OBJ = attach.o master.o main.o
|
OBJ = attach.o master.o main.o
|
||||||
|
|
@ -14,10 +14,10 @@ TARFILES = $(srcdir)/README $(srcdir)/COPYING $(srcdir)/*.in $(srcdir)/*.c \
|
||||||
$(srcdir)/dtach.1
|
$(srcdir)/dtach.1
|
||||||
|
|
||||||
dtach: $(OBJ)
|
dtach: $(OBJ)
|
||||||
$(CC) -o $@ $(LDFLAGS) $^ $(LIBS)
|
$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f .depend dtach $(OBJ) dtach-$(VERSION).tar.gz
|
rm -f dtach $(OBJ) dtach-$(VERSION).tar.gz
|
||||||
|
|
||||||
distclean: clean
|
distclean: clean
|
||||||
rm -f config.h Makefile config.log config.status config.cache
|
rm -f config.h Makefile config.log config.status config.cache
|
||||||
|
|
@ -29,7 +29,7 @@ tar:
|
||||||
gzip -9f dtach-$(VERSION).tar
|
gzip -9f dtach-$(VERSION).tar
|
||||||
rm -rf dtach-$(VERSION)
|
rm -rf dtach-$(VERSION)
|
||||||
|
|
||||||
.depend:
|
attach.o: @srcdir@/attach.c @srcdir@/detach.h config.h
|
||||||
@$(CC) $(CFLAGS) -MM $(SRC) > $@
|
master.o: @srcdir@/master.c @srcdir@/detach.h config.h
|
||||||
|
main.o: @srcdir@/main.c @srcdir@/detach.h config.h
|
||||||
|
|
||||||
-include .depend
|
|
||||||
|
|
|
||||||
4
README
4
README
|
|
@ -96,8 +96,10 @@ to dtach when attaching.
|
||||||
|
|
||||||
5. CHANGES
|
5. CHANGES
|
||||||
|
|
||||||
The changes since version 0.3 are:
|
The changes in version 0.4 are:
|
||||||
- Slightly improved README and dtach.1
|
- Slightly improved README and dtach.1
|
||||||
|
- Portability updates thanks to sourceforge's compile farm. dtach should now
|
||||||
|
work on: FreeBSD, Debian/alpha, Debian/sparc, Debian/PPC, and Solaris.
|
||||||
|
|
||||||
The changes in version 0.3 are:
|
The changes in version 0.3 are:
|
||||||
- Fixed a typo in dtach.1
|
- Fixed a typo in dtach.1
|
||||||
|
|
|
||||||
90
attach.c
90
attach.c
|
|
@ -26,49 +26,52 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The current terminal settings. After coming back from a suspend, we
|
/*
|
||||||
// restore this.
|
** The current terminal settings. After coming back from a suspend, we
|
||||||
|
** restore this.
|
||||||
|
*/
|
||||||
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
|
/* 1 if we want a redraw */
|
||||||
static int want_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"
|
||||||
|
|
||||||
// Restores the original terminal settings.
|
/* Restores the original terminal settings. */
|
||||||
static void
|
static void
|
||||||
restore_term(void)
|
restore_term(void)
|
||||||
{
|
{
|
||||||
tcsetattr(0, TCSADRAIN, &orig_term);
|
tcsetattr(0, TCSADRAIN, &orig_term);
|
||||||
// Make cursor visible. Assumes VT100.
|
|
||||||
|
/* Make cursor visible. Assumes VT100. */
|
||||||
printf("\033[?25h\033[?0c");
|
printf("\033[?25h\033[?0c");
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Connects to a unix domain socket
|
/* Connects to a unix domain socket */
|
||||||
static int
|
static int
|
||||||
connect_socket(char *name)
|
connect_socket(char *name)
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
struct sockaddr_un sun;
|
struct sockaddr_un sockun;
|
||||||
|
|
||||||
s = socket(PF_UNIX, SOCK_STREAM, 0);
|
s = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
if (s < 0)
|
if (s < 0)
|
||||||
return -1;
|
return -1;
|
||||||
sun.sun_family = AF_UNIX;
|
sockun.sun_family = AF_UNIX;
|
||||||
strcpy(sun.sun_path, name);
|
strcpy(sockun.sun_path, name);
|
||||||
if (connect(s, (struct sockaddr*)&sun, sizeof(sun)) < 0)
|
if (connect(s, (struct sockaddr*)&sockun, sizeof(sockun)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signal
|
/* Signal */
|
||||||
static RETSIGTYPE
|
static RETSIGTYPE
|
||||||
die(int sig)
|
die(int sig)
|
||||||
{
|
{
|
||||||
// Print a nice pretty message for some things.
|
/* Print a nice pretty message for some things. */
|
||||||
if (sig == SIGHUP || sig == SIGINT)
|
if (sig == SIGHUP || sig == SIGINT)
|
||||||
printf(EOS "\r\n[detached]\r\n");
|
printf(EOS "\r\n[detached]\r\n");
|
||||||
else
|
else
|
||||||
|
|
@ -76,50 +79,51 @@ die(int sig)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Window size change.
|
/* Window size change. */
|
||||||
static RETSIGTYPE
|
static RETSIGTYPE
|
||||||
win_change()
|
win_change()
|
||||||
{
|
{
|
||||||
win_changed = 1;
|
win_changed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles input from the keyboard.
|
/* Handles input from the keyboard. */
|
||||||
static void
|
static void
|
||||||
process_kbd(int s, struct packet *pkt)
|
process_kbd(int s, struct packet *pkt)
|
||||||
{
|
{
|
||||||
// Suspend?
|
/* Suspend? */
|
||||||
if (!no_suspend && (pkt->u.buf[0] == cur_term.c_cc[VSUSP]))
|
if (!no_suspend && (pkt->u.buf[0] == cur_term.c_cc[VSUSP]))
|
||||||
{
|
{
|
||||||
// Tell the master that we are suspending.
|
/* Tell the master that we are suspending. */
|
||||||
pkt->type = MSG_DETACH;
|
pkt->type = MSG_DETACH;
|
||||||
write(s, pkt, sizeof(*pkt));
|
write(s, pkt, sizeof(*pkt));
|
||||||
|
|
||||||
// And suspend...
|
/* And suspend... */
|
||||||
tcsetattr(0, TCSADRAIN, &orig_term);
|
tcsetattr(0, TCSADRAIN, &orig_term);
|
||||||
|
printf(EOS "\r\n");
|
||||||
kill(getpid(), SIGTSTP);
|
kill(getpid(), SIGTSTP);
|
||||||
tcsetattr(0, TCSADRAIN, &cur_term);
|
tcsetattr(0, TCSADRAIN, &cur_term);
|
||||||
|
|
||||||
// Tell the master that we are returning.
|
/* Tell the master that we are returning. */
|
||||||
pkt->type = MSG_ATTACH;
|
pkt->type = MSG_ATTACH;
|
||||||
write(s, pkt, sizeof(*pkt));
|
write(s, pkt, sizeof(*pkt));
|
||||||
|
|
||||||
// The window size might have changed, and we definately want
|
/* The window size might have changed, and we definately want
|
||||||
// a redraw. We don't want to pass the suspend, though.
|
** a redraw. We don't want to pass the suspend, though. */
|
||||||
win_changed = 1;
|
win_changed = 1;
|
||||||
want_redraw = 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(1);
|
||||||
}
|
}
|
||||||
// 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')
|
||||||
win_changed = 1;
|
win_changed = 1;
|
||||||
|
|
||||||
// Push it out
|
/* Push it out */
|
||||||
write(s, pkt, sizeof(*pkt));
|
write(s, pkt, sizeof(*pkt));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -131,14 +135,14 @@ attach_main(int noerror)
|
||||||
struct packet pkt;
|
struct packet pkt;
|
||||||
unsigned char buf[BUFSIZE];
|
unsigned char buf[BUFSIZE];
|
||||||
|
|
||||||
// The current terminal settings are equal to the original terminal
|
/* The current terminal settings are equal to the original terminal
|
||||||
// settings at this point.
|
** settings at this point. */
|
||||||
cur_term = orig_term;
|
cur_term = orig_term;
|
||||||
|
|
||||||
// Set a trap to restore the terminal when we die.
|
/* Set a trap to restore the terminal when we die. */
|
||||||
atexit(restore_term);
|
atexit(restore_term);
|
||||||
|
|
||||||
// Set some signals.
|
/* Set some signals. */
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
signal(SIGXFSZ, SIG_IGN);
|
signal(SIGXFSZ, SIG_IGN);
|
||||||
signal(SIGHUP, die);
|
signal(SIGHUP, die);
|
||||||
|
|
@ -147,8 +151,8 @@ attach_main(int noerror)
|
||||||
signal(SIGQUIT, die);
|
signal(SIGQUIT, die);
|
||||||
signal(SIGWINCH, win_change);
|
signal(SIGWINCH, win_change);
|
||||||
|
|
||||||
// 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. */
|
||||||
s = connect_socket(sockname);
|
s = connect_socket(sockname);
|
||||||
if (s < 0)
|
if (s < 0)
|
||||||
{
|
{
|
||||||
|
|
@ -158,20 +162,22 @@ attach_main(int noerror)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set raw mode, almost. We allow flow control to work, for instance.
|
/* Set raw mode, almost. We allow flow control to work, for instance. */
|
||||||
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_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);
|
||||||
cur_term.c_cflag |= CS8;
|
cur_term.c_cflag |= CS8;
|
||||||
cur_term.c_cc[VLNEXT] = VDISABLE;
|
cur_term.c_cc[VLNEXT] = VDISABLE;
|
||||||
|
cur_term.c_cc[VMIN] = 1;
|
||||||
|
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
|
/* Set up the poll structures */
|
||||||
polls[0].fd = 0;
|
polls[0].fd = 0;
|
||||||
polls[0].events = POLLIN;
|
polls[0].events = POLLIN;
|
||||||
polls[0].revents = 0;
|
polls[0].revents = 0;
|
||||||
|
|
@ -179,15 +185,15 @@ attach_main(int noerror)
|
||||||
polls[1].events = POLLIN;
|
polls[1].events = POLLIN;
|
||||||
polls[1].revents = 0;
|
polls[1].revents = 0;
|
||||||
|
|
||||||
// Send our window size.
|
/* Send our window size. */
|
||||||
pkt.type = MSG_WINCH;
|
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.
|
/* We would like a redraw, too. */
|
||||||
pkt.type = MSG_REDRAW;
|
pkt.type = MSG_REDRAW;
|
||||||
write(s, &pkt, sizeof(pkt));
|
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)
|
if (poll(polls, 2, -1) < 0)
|
||||||
|
|
@ -198,7 +204,7 @@ attach_main(int noerror)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Pty activity
|
/* Pty activity */
|
||||||
if (polls[1].revents != 0)
|
if (polls[1].revents != 0)
|
||||||
{
|
{
|
||||||
int len = read(s, buf, sizeof(buf));
|
int len = read(s, buf, sizeof(buf));
|
||||||
|
|
@ -214,10 +220,10 @@ attach_main(int noerror)
|
||||||
printf(EOS "\r\n[read returned an error]\r\n");
|
printf(EOS "\r\n[read returned an error]\r\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
// Send the data to the terminal.
|
/* Send the data to the terminal. */
|
||||||
write(1, buf, len);
|
write(1, buf, len);
|
||||||
}
|
}
|
||||||
// stdin activity
|
/* stdin activity */
|
||||||
if (polls[0].revents != 0)
|
if (polls[0].revents != 0)
|
||||||
{
|
{
|
||||||
pkt.type = MSG_PUSH;
|
pkt.type = MSG_PUSH;
|
||||||
|
|
@ -228,7 +234,7 @@ attach_main(int noerror)
|
||||||
exit(1);
|
exit(1);
|
||||||
process_kbd(s, &pkt);
|
process_kbd(s, &pkt);
|
||||||
}
|
}
|
||||||
// Window size changed?
|
/* Window size changed? */
|
||||||
if (win_changed)
|
if (win_changed)
|
||||||
{
|
{
|
||||||
win_changed = 0;
|
win_changed = 0;
|
||||||
|
|
@ -237,7 +243,7 @@ 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?
|
/* Want a redraw? */
|
||||||
if (want_redraw)
|
if (want_redraw)
|
||||||
{
|
{
|
||||||
want_redraw = 0;
|
want_redraw = 0;
|
||||||
|
|
|
||||||
47
config.h.in
47
config.h.in
|
|
@ -1,4 +1,4 @@
|
||||||
/* config.h.in. Generated automatically from configure.in by autoheader. */
|
/* config.h.in. Generated from configure.in by autoheader. */
|
||||||
|
|
||||||
/* Define if you have the `forkpty' function. */
|
/* Define if you have the `forkpty' function. */
|
||||||
#undef HAVE_FORKPTY
|
#undef HAVE_FORKPTY
|
||||||
|
|
@ -6,30 +6,75 @@
|
||||||
/* Define if you have the `getrlimit' function. */
|
/* Define if you have the `getrlimit' function. */
|
||||||
#undef HAVE_GETRLIMIT
|
#undef HAVE_GETRLIMIT
|
||||||
|
|
||||||
|
/* Define if you have the `grantpt' function. */
|
||||||
|
#undef HAVE_GRANTPT
|
||||||
|
|
||||||
|
/* Define if you have the <inttypes.h> header file. */
|
||||||
|
#undef HAVE_INTTYPES_H
|
||||||
|
|
||||||
|
/* Define if you have the `socket' library (-lsocket). */
|
||||||
|
#undef HAVE_LIBSOCKET
|
||||||
|
|
||||||
/* Define if you have the `util' library (-lutil). */
|
/* Define if you have the `util' library (-lutil). */
|
||||||
#undef HAVE_LIBUTIL
|
#undef HAVE_LIBUTIL
|
||||||
|
|
||||||
|
/* Define if you have the <libutil.h> header file. */
|
||||||
|
#undef HAVE_LIBUTIL_H
|
||||||
|
|
||||||
|
/* Define if you have the <memory.h> header file. */
|
||||||
|
#undef HAVE_MEMORY_H
|
||||||
|
|
||||||
|
/* Define if you have the `openpty' function. */
|
||||||
|
#undef HAVE_OPENPTY
|
||||||
|
|
||||||
|
/* Define if you have the `ptsname' function. */
|
||||||
|
#undef HAVE_PTSNAME
|
||||||
|
|
||||||
/* Define if you have the <pty.h> header file. */
|
/* Define if you have the <pty.h> header file. */
|
||||||
#undef HAVE_PTY_H
|
#undef HAVE_PTY_H
|
||||||
|
|
||||||
/* Define if you have the `socket' function. */
|
/* Define if you have the `socket' function. */
|
||||||
#undef HAVE_SOCKET
|
#undef HAVE_SOCKET
|
||||||
|
|
||||||
|
/* Define if you have the <stdint.h> header file. */
|
||||||
|
#undef HAVE_STDINT_H
|
||||||
|
|
||||||
|
/* Define if you have the <stdlib.h> header file. */
|
||||||
|
#undef HAVE_STDLIB_H
|
||||||
|
|
||||||
/* Define if you have the `strerror' function. */
|
/* Define if you have the `strerror' function. */
|
||||||
#undef HAVE_STRERROR
|
#undef HAVE_STRERROR
|
||||||
|
|
||||||
|
/* Define if you have the <strings.h> header file. */
|
||||||
|
#undef HAVE_STRINGS_H
|
||||||
|
|
||||||
|
/* Define if you have the <string.h> header file. */
|
||||||
|
#undef HAVE_STRING_H
|
||||||
|
|
||||||
|
/* Define if you have the <stropts.h> header file. */
|
||||||
|
#undef HAVE_STROPTS_H
|
||||||
|
|
||||||
/* Define if you have the <sys/ioctl.h> header file. */
|
/* Define 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 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. */
|
||||||
|
#undef HAVE_SYS_STAT_H
|
||||||
|
|
||||||
|
/* Define if you have the <sys/types.h> header file. */
|
||||||
|
#undef HAVE_SYS_TYPES_H
|
||||||
|
|
||||||
/* Define if you have the <termios.h> header file. */
|
/* Define 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 if you have the <unistd.h> header file. */
|
||||||
#undef HAVE_UNISTD_H
|
#undef HAVE_UNISTD_H
|
||||||
|
|
||||||
|
/* Define if you have the `unlockpt' function. */
|
||||||
|
#undef HAVE_UNLOCKPT
|
||||||
|
|
||||||
/* Define if you have the <util.h> header file. */
|
/* Define if you have the <util.h> header file. */
|
||||||
#undef HAVE_UTIL_H
|
#undef HAVE_UTIL_H
|
||||||
|
|
||||||
|
|
|
||||||
12
configure.in
12
configure.in
|
|
@ -4,12 +4,18 @@ AC_INIT(main.c)
|
||||||
dnl Checks for programs.
|
dnl Checks for programs.
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
|
|
||||||
|
if test "$GCC" = yes; then
|
||||||
|
CFLAGS="$CFLAGS -W -Wall";
|
||||||
|
fi
|
||||||
|
|
||||||
dnl Checks for libraries.
|
dnl Checks for libraries.
|
||||||
AC_CHECK_LIB(util, forkpty)
|
AC_CHECK_LIB(util, openpty)
|
||||||
|
AC_CHECK_LIB(socket, socket)
|
||||||
|
|
||||||
dnl Checks for header files.
|
dnl Checks for header files.
|
||||||
AC_HEADER_STDC
|
AC_HEADER_STDC
|
||||||
AC_CHECK_HEADERS(sys/ioctl.h sys/resource.h pty.h termios.h util.h unistd.h)
|
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.
|
dnl Checks for typedefs, structures, and compiler characteristics.
|
||||||
AC_TYPE_PID_T
|
AC_TYPE_PID_T
|
||||||
|
|
@ -17,7 +23,7 @@ AC_TYPE_PID_T
|
||||||
dnl Checks for library functions.
|
dnl Checks for library functions.
|
||||||
AC_PROG_GCC_TRADITIONAL
|
AC_PROG_GCC_TRADITIONAL
|
||||||
AC_TYPE_SIGNAL
|
AC_TYPE_SIGNAL
|
||||||
AC_CHECK_FUNCS(socket strerror forkpty getrlimit)
|
AC_CHECK_FUNCS(socket strerror getrlimit)
|
||||||
|
AC_CHECK_FUNCS(openpty forkpty ptsname grantpt unlockpt)
|
||||||
AC_CONFIG_HEADER(config.h)
|
AC_CONFIG_HEADER(config.h)
|
||||||
AC_OUTPUT(Makefile)
|
AC_OUTPUT(Makefile)
|
||||||
|
|
|
||||||
27
detach.h
27
detach.h
|
|
@ -22,6 +22,7 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
@ -35,6 +36,14 @@
|
||||||
#include <util.h>
|
#include <util.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBUTIL_H
|
||||||
|
#include <libutil.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_STROPTS_H
|
||||||
|
#include <stropts.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -67,7 +76,7 @@ enum
|
||||||
MSG_DETACH
|
MSG_DETACH
|
||||||
};
|
};
|
||||||
|
|
||||||
// The client to master protocol.
|
/* The client to master protocol. */
|
||||||
struct packet
|
struct packet
|
||||||
{
|
{
|
||||||
unsigned char type;
|
unsigned char type;
|
||||||
|
|
@ -79,13 +88,19 @@ struct packet
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The master sends a simple stream of text to the attaching clients, without
|
/*
|
||||||
// any protocol. This might change back to the packet based protocol in the
|
** The master sends a simple stream of text to the attaching clients, without
|
||||||
// future. In the meantime, however, we minimize the amount of data sent back
|
** any protocol. This might change back to the packet based protocol in the
|
||||||
// and forth between the client and the master. BUFSIZE is the size of the
|
** future. In the meantime, however, we minimize the amount of data sent back
|
||||||
// buffer used for the text stream.
|
** and forth between the client and the master. BUFSIZE is the size of the
|
||||||
|
** buffer used for the text stream.
|
||||||
|
*/
|
||||||
#define BUFSIZE 4096
|
#define BUFSIZE 4096
|
||||||
|
|
||||||
int attach_main(int noerror);
|
int attach_main(int noerror);
|
||||||
int master_main(char **argv);
|
int master_main(char **argv);
|
||||||
|
|
||||||
|
#ifdef sun
|
||||||
|
#define BROKEN_MASTER
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
2
dtach.1
2
dtach.1
|
|
@ -1,4 +1,4 @@
|
||||||
.TH dtach 1 "September 2001" "dtach 0.3"
|
.TH dtach 1 "September 2001" "dtach 0.4"
|
||||||
.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
|
||||||
|
|
|
||||||
|
|
@ -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.3
|
Version: 0.4
|
||||||
Release: 1
|
Release: 1
|
||||||
Copyright: GPL
|
Copyright: GPL
|
||||||
URL: http://dtach.sourceforge.net
|
URL: http://dtach.sourceforge.net
|
||||||
|
|
@ -45,6 +45,11 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version}
|
||||||
%{_mandir}/man1/*
|
%{_mandir}/man1/*
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Sat Nov 03 2001 Ned T. Crigler <crigler@hell-city.org> 0.4
|
||||||
|
- Portability updates thanks to sourceforge's compile farm. dtach should now
|
||||||
|
work on: FreeBSD, Debian/alpha, Debian/PPC, Debian/sparc, Debian/PPC, and
|
||||||
|
Solaris.
|
||||||
|
|
||||||
* Thu Sep 27 2001 Ned T. Crigler <crigler@hell-city.org>
|
* Thu Sep 27 2001 Ned T. Crigler <crigler@hell-city.org>
|
||||||
- Modified spec file URL: to point to http://dtach.sourceforge.net
|
- Modified spec file URL: to point to http://dtach.sourceforge.net
|
||||||
|
|
||||||
|
|
|
||||||
32
main.c
32
main.c
|
|
@ -24,24 +24,26 @@
|
||||||
** 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
|
/* The program version */
|
||||||
#define VERSION "0.3"
|
#define VERSION "0.4"
|
||||||
|
|
||||||
// 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 " VERSION " (C)Copyright 2001 Ned T. Crigler";
|
||||||
|
|
||||||
// argv[0] from the program
|
/* argv[0] from the program */
|
||||||
char *progname;
|
char *progname;
|
||||||
// The name of the passed in socket.
|
/* The name of the passed in socket. */
|
||||||
char *sockname;
|
char *sockname;
|
||||||
// The character used for detaching. Defaults to '^\'
|
/* The character used for detaching. Defaults to '^\' */
|
||||||
int detach_char = '\\' - 64;
|
int detach_char = '\\' - 64;
|
||||||
// 1 if we should not interpret the suspend character.
|
/* 1 if we should not interpret the suspend character. */
|
||||||
int no_suspend;
|
int no_suspend;
|
||||||
|
|
||||||
// The original terminal settings. Shared between the master and attach
|
/*
|
||||||
// processes. The master uses it to initialize the pty, and the attacher uses
|
** The original terminal settings. Shared between the master and attach
|
||||||
// it to restore the original settings.
|
** processes. The master uses it to initialize the pty, and the attacher uses
|
||||||
|
** it to restore the original settings.
|
||||||
|
*/
|
||||||
struct termios orig_term;
|
struct termios orig_term;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -75,11 +77,11 @@ main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int mode = 0;
|
int mode = 0;
|
||||||
|
|
||||||
// Save the program name
|
/* Save the program name */
|
||||||
progname = argv[0];
|
progname = argv[0];
|
||||||
++argv; --argc;
|
++argv; --argc;
|
||||||
|
|
||||||
// Parse the arguments
|
/* Parse the arguments */
|
||||||
if (argc >= 1 && **argv == '-')
|
if (argc >= 1 && **argv == '-')
|
||||||
{
|
{
|
||||||
if (strncmp(*argv, "--help", strlen(*argv)) == 0)
|
if (strncmp(*argv, "--help", strlen(*argv)) == 0)
|
||||||
|
|
@ -174,7 +176,7 @@ main(int argc, char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save the original terminal settings.
|
/* Save the original terminal settings. */
|
||||||
if (tcgetattr(0, &orig_term) < 0)
|
if (tcgetattr(0, &orig_term) < 0)
|
||||||
{
|
{
|
||||||
printf("%s: tcgetattr: %s\n", progname, strerror(errno));
|
printf("%s: tcgetattr: %s\n", progname, strerror(errno));
|
||||||
|
|
@ -203,8 +205,8 @@ main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
else if (mode == 'A')
|
else if (mode == 'A')
|
||||||
{
|
{
|
||||||
// Try to attach first. If that doesn't work, create a new
|
/* Try to attach first. If that doesn't work, create a new
|
||||||
// socket.
|
** socket. */
|
||||||
if (attach_main(1) != 0)
|
if (attach_main(1) != 0)
|
||||||
{
|
{
|
||||||
if (master_main(argv) != 0)
|
if (master_main(argv) != 0)
|
||||||
|
|
|
||||||
261
master.c
261
master.c
|
|
@ -18,58 +18,73 @@
|
||||||
*/
|
*/
|
||||||
#include "detach.h"
|
#include "detach.h"
|
||||||
|
|
||||||
// The pty struct - The pty information is stored here.
|
/* The pty struct - The pty information is stored here. */
|
||||||
struct pty
|
struct pty
|
||||||
{
|
{
|
||||||
// File descriptor of the pty
|
/* File descriptor of the pty */
|
||||||
int fd;
|
int fd;
|
||||||
// The terminal parameters of the pty. Old and new for comparision
|
#ifdef BROKEN_MASTER
|
||||||
// purposes.
|
/* File descriptor of the slave side of the pty. For broken systems. */
|
||||||
|
int slave;
|
||||||
|
#endif
|
||||||
|
/* The terminal parameters of the pty. Old and new for comparision
|
||||||
|
** purposes. */
|
||||||
struct termios term;
|
struct termios term;
|
||||||
// The current window size of the pty.
|
/* The current window size of the pty. */
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
};
|
};
|
||||||
|
|
||||||
// The poll structures
|
/* The poll structures */
|
||||||
static struct pollfd *polls;
|
static struct pollfd *polls;
|
||||||
// The number of active poll slots
|
/* The number of active poll slots */
|
||||||
static int num_polls;
|
static int num_polls;
|
||||||
// Boolean array for whether a particular connection is attached.
|
/* Boolean array for whether a particular connection is attached. */
|
||||||
static int *attached;
|
static int *attached;
|
||||||
// The highest file descriptor possible, as returned by getrlimit.
|
/* The highest file descriptor possible, as returned by getrlimit. */
|
||||||
static int highest_fd;
|
static int highest_fd;
|
||||||
|
|
||||||
// The number of fixed slots in the poll structures
|
/* The number of fixed slots in the poll structures */
|
||||||
#define FIXED_SLOTS 2
|
#define FIXED_SLOTS 2
|
||||||
|
|
||||||
// Unlink the socket
|
#ifndef HAVE_FORKPTY
|
||||||
|
pid_t forkpty(int *amaster, char *name, struct termios *termp,
|
||||||
|
struct winsize *winp);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Unlink the socket */
|
||||||
static void
|
static void
|
||||||
unlink_socket(void)
|
unlink_socket(void)
|
||||||
{
|
{
|
||||||
unlink(sockname);
|
unlink(sockname);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signal
|
/* Signal */
|
||||||
static RETSIGTYPE
|
static RETSIGTYPE
|
||||||
die(int sig)
|
die(int sig)
|
||||||
{
|
{
|
||||||
// Well, the child died.
|
/* Well, the child died. */
|
||||||
if (sig == SIGCHLD)
|
if (sig == SIGCHLD)
|
||||||
|
{
|
||||||
|
#ifdef BROKEN_MASTER
|
||||||
|
/* Damn you Solaris! */
|
||||||
|
close(polls[1].fd);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the pty structure.
|
/* Initialize the pty structure. */
|
||||||
static int
|
static int
|
||||||
init_pty(struct pty *pty, char **argv)
|
init_pty(struct pty *pty, char **argv)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
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;
|
pty->term = orig_term;
|
||||||
|
|
||||||
// Create the pty process
|
/* Create the pty process */
|
||||||
pid = forkpty(&pty->fd, NULL, &pty->term, NULL);
|
pid = forkpty(&pty->fd, NULL, &pty->term, NULL);
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
@ -77,59 +92,74 @@ init_pty(struct pty *pty, char **argv)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// Child.. Close some file descriptors and execute the program.
|
/* Child.. Close some file descriptors and execute the
|
||||||
|
** program. */
|
||||||
for (i = highest_fd; i > 2; --i)
|
for (i = highest_fd; i > 2; --i)
|
||||||
close(i);
|
close(i);
|
||||||
|
|
||||||
execvp(*argv, argv);
|
execvp(*argv, argv);
|
||||||
exit(127);
|
exit(127);
|
||||||
}
|
}
|
||||||
// Parent.. Finish up and return
|
/* Parent.. Finish up and return */
|
||||||
|
#ifdef BROKEN_MASTER
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
buf = ptsname(pty->fd);
|
||||||
|
pty->slave = open(buf, O_RDWR|O_NOCTTY);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a new unix domain socket.
|
/* Creates a new unix domain socket. */
|
||||||
static int
|
static int
|
||||||
create_socket(char *name)
|
create_socket(char *name)
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
struct sockaddr_un sun;
|
struct sockaddr_un sockun;
|
||||||
|
|
||||||
s = socket(PF_UNIX, SOCK_STREAM, 0);
|
s = socket(PF_UNIX, SOCK_STREAM, 0);
|
||||||
if (s < 0)
|
if (s < 0)
|
||||||
return -1;
|
return -1;
|
||||||
sun.sun_family = AF_UNIX;
|
sockun.sun_family = AF_UNIX;
|
||||||
strcpy(sun.sun_path, name);
|
strcpy(sockun.sun_path, name);
|
||||||
if (bind(s, (struct sockaddr*)&sun, sizeof(sun)) < 0)
|
if (bind(s, (struct sockaddr*)&sockun, sizeof(sockun)) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (listen(s, 128) < 0)
|
if (listen(s, 128) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
// chmod it to prevent any suprises
|
/* chmod it to prevent any suprises */
|
||||||
if (chmod(name, 0600) < 0)
|
if (chmod(name, 0600) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process activity on a pty - Input and terminal changes are sent out to
|
/* Process activity on a 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(struct pty *pty)
|
||||||
{
|
{
|
||||||
int i, len;
|
int i, len;
|
||||||
unsigned char buf[BUFSIZE];
|
unsigned char buf[BUFSIZE];
|
||||||
|
|
||||||
// Read the pty activity
|
/* Read the pty activity */
|
||||||
len = read(pty->fd, buf, sizeof(buf));
|
len = read(pty->fd, buf, sizeof(buf));
|
||||||
|
|
||||||
// Error -> die
|
/* Error -> die */
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
// Get the current terminal settings.
|
#ifdef BROKEN_MASTER
|
||||||
|
/* Get the current terminal settings. */
|
||||||
|
if (tcgetattr(pty->slave, &pty->term) < 0)
|
||||||
|
exit(1);
|
||||||
|
#else
|
||||||
|
/* Get the current terminal settings. */
|
||||||
if (tcgetattr(pty->fd, &pty->term) < 0)
|
if (tcgetattr(pty->fd, &pty->term) < 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
#endif
|
||||||
|
|
||||||
// Send it out to the clients.
|
/* Send it out to the clients. */
|
||||||
for (i = FIXED_SLOTS; i < num_polls; ++i)
|
for (i = FIXED_SLOTS; i < num_polls; ++i)
|
||||||
{
|
{
|
||||||
if (attached[polls[i].fd])
|
if (attached[polls[i].fd])
|
||||||
|
|
@ -137,18 +167,18 @@ pty_activity(struct pty *pty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process activity on the control socket
|
/* Process activity on the control socket */
|
||||||
static void
|
static void
|
||||||
control_activity(int s)
|
control_activity(int s)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
// Accept the new client and link it in.
|
/* Accept the new client and link it in. */
|
||||||
fd = accept(s, 0, 0);
|
fd = accept(s, 0, 0);
|
||||||
if (fd < 0)
|
if (fd < 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Link it in.
|
/* Link it in. */
|
||||||
polls[num_polls].fd = fd;
|
polls[num_polls].fd = fd;
|
||||||
polls[num_polls].events = POLLIN;
|
polls[num_polls].events = POLLIN;
|
||||||
polls[num_polls].revents = 0;
|
polls[num_polls].revents = 0;
|
||||||
|
|
@ -156,18 +186,18 @@ control_activity(int s)
|
||||||
++num_polls;
|
++num_polls;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process activity from a client.
|
/* Process activity from a client. */
|
||||||
static void
|
static void
|
||||||
client_activity(int i, struct pty *pty)
|
client_activity(int i, struct pty *pty)
|
||||||
{
|
{
|
||||||
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(polls[i].fd, &pkt, sizeof(pkt));
|
||||||
if (len <= 0)
|
if (len <= 0)
|
||||||
{
|
{
|
||||||
// Close the socket and go bye bye
|
/* Close the socket and go bye bye */
|
||||||
attached[polls[i].fd]=0;
|
attached[polls[i].fd]=0;
|
||||||
close(polls[i].fd);
|
close(polls[i].fd);
|
||||||
memcpy(polls + i, polls + i + 1, num_polls - i);
|
memcpy(polls + i, polls + i + 1, num_polls - i);
|
||||||
|
|
@ -175,36 +205,36 @@ client_activity(int i, struct pty *pty)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Okay, check the command byte. Push out data if we need to.
|
/* Okay, check the command byte. Push out data if we need to. */
|
||||||
if (pkt.type == MSG_PUSH)
|
if (pkt.type == MSG_PUSH)
|
||||||
write(pty->fd, pkt.u.buf, pkt.len);
|
write(pty->fd, pkt.u.buf, pkt.len);
|
||||||
// Window size change.
|
/* Window size change. */
|
||||||
else if (pkt.type == MSG_WINCH)
|
else if (pkt.type == MSG_WINCH)
|
||||||
{
|
{
|
||||||
pty->ws = pkt.u.ws;
|
pty->ws = pkt.u.ws;
|
||||||
ioctl(pty->fd, TIOCSWINSZ, &pty->ws);
|
ioctl(pty->fd, TIOCSWINSZ, &pty->ws);
|
||||||
}
|
}
|
||||||
// Redraw request?
|
/* Redraw request? */
|
||||||
else if (pkt.type == MSG_REDRAW)
|
else if (pkt.type == MSG_REDRAW)
|
||||||
{
|
{
|
||||||
char c = '\f';
|
char c = '\f';
|
||||||
|
|
||||||
// Guess that ^L might work under certain conditions.
|
/* Guess that ^L might work under certain conditions. */
|
||||||
if (((pty->term.c_lflag & (ECHO|ICANON)) == 0) &&
|
if (((pty->term.c_lflag & (ECHO|ICANON)) == 0) &&
|
||||||
(pty->term.c_cc[VMIN] == 1))
|
(pty->term.c_cc[VMIN] == 1))
|
||||||
{
|
{
|
||||||
write(pty->fd, &c, sizeof(c));
|
write(pty->fd, &c, sizeof(c));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Attach request?
|
/* Attach request? */
|
||||||
else if (pkt.type == MSG_ATTACH)
|
else if (pkt.type == MSG_ATTACH)
|
||||||
attached[polls[i].fd] = 1;
|
attached[polls[i].fd] = 1;
|
||||||
else if (pkt.type == MSG_DETACH)
|
else if (pkt.type == MSG_DETACH)
|
||||||
attached[polls[i].fd] = 0;
|
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 */
|
||||||
// clients.
|
/* clients. */
|
||||||
static void
|
static void
|
||||||
master_process(int s, char **argv)
|
master_process(int s, char **argv)
|
||||||
{
|
{
|
||||||
|
|
@ -214,8 +244,8 @@ master_process(int s, char **argv)
|
||||||
#ifdef HAVE_GETRLIMIT
|
#ifdef HAVE_GETRLIMIT
|
||||||
struct rlimit rlim;
|
struct rlimit rlim;
|
||||||
|
|
||||||
// Dynamically allocate structures based on the number of file
|
/* Dynamically allocate structures based on the number of file
|
||||||
// descriptors.
|
** descriptors. */
|
||||||
|
|
||||||
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
|
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
|
||||||
{
|
{
|
||||||
|
|
@ -224,25 +254,25 @@ master_process(int s, char **argv)
|
||||||
}
|
}
|
||||||
highest_fd = rlim.rlim_cur;
|
highest_fd = rlim.rlim_cur;
|
||||||
#else
|
#else
|
||||||
// We can't query the OS for the number of file descriptors, so
|
/* We can't query the OS for the number of file descriptors, so
|
||||||
// we pull a number out of the air.
|
** we pull a number out of the air. */
|
||||||
highest_fd = 1024;
|
highest_fd = 1024;
|
||||||
#endif
|
#endif
|
||||||
polls = (struct pollfd*)malloc(highest_fd * sizeof(struct pollfd));
|
polls = (struct pollfd*)malloc(highest_fd * sizeof(struct pollfd));
|
||||||
attached = (int*)malloc(highest_fd * sizeof(int));
|
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(&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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set up some signals.
|
/* Set up some signals. */
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
signal(SIGXFSZ, SIG_IGN);
|
signal(SIGXFSZ, SIG_IGN);
|
||||||
signal(SIGHUP, SIG_IGN);
|
signal(SIGHUP, SIG_IGN);
|
||||||
|
|
@ -252,16 +282,16 @@ master_process(int s, char **argv)
|
||||||
signal(SIGTERM, die);
|
signal(SIGTERM, die);
|
||||||
signal(SIGCHLD, die);
|
signal(SIGCHLD, die);
|
||||||
|
|
||||||
// Close the original terminal. We are now a daemon.
|
/* Close the original terminal. We are now a daemon. */
|
||||||
fclose(stdin);
|
fclose(stdin);
|
||||||
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
|
/* Set up the poll structures. Slot 0 is the control socket, slot 1
|
||||||
// is the pty, and slot 2 .. n is the connected clients.
|
** is the pty, and slot 2 .. n is the connected clients. */
|
||||||
polls[0].fd = s;
|
polls[0].fd = s;
|
||||||
polls[0].events = POLLIN;
|
polls[0].events = POLLIN;
|
||||||
polls[0].revents = 0;
|
polls[0].revents = 0;
|
||||||
|
|
@ -270,23 +300,23 @@ master_process(int s, char **argv)
|
||||||
polls[1].revents = 0;
|
polls[1].revents = 0;
|
||||||
num_polls = FIXED_SLOTS;
|
num_polls = FIXED_SLOTS;
|
||||||
|
|
||||||
// Loop forever.
|
/* Loop forever. */
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
// Wait for something to happen.
|
/* Wait for something to happen. */
|
||||||
if (poll(polls, num_polls, -1) < 0)
|
if (poll(polls, num_polls, -1) < 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 (polls[1].revents != 0)
|
||||||
pty_activity(&pty);
|
pty_activity(&pty);
|
||||||
// New client?
|
/* New client? */
|
||||||
if (polls[0].revents != 0)
|
if (polls[0].revents != 0)
|
||||||
control_activity(s);
|
control_activity(s);
|
||||||
// Activity on a client?
|
/* Activity on a client? */
|
||||||
for (i = 2; i < num_polls; ++i)
|
for (i = 2; i < num_polls; ++i)
|
||||||
{
|
{
|
||||||
if (polls[i].revents != 0)
|
if (polls[i].revents != 0)
|
||||||
|
|
@ -301,7 +331,7 @@ master_main(char **argv)
|
||||||
int s;
|
int s;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
// Create the unix domain socket.
|
/* Create the unix domain socket. */
|
||||||
s = create_socket(sockname);
|
s = create_socket(sockname);
|
||||||
if (s < 0)
|
if (s < 0)
|
||||||
{
|
{
|
||||||
|
|
@ -309,7 +339,7 @@ master_main(char **argv)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fork off so we can daemonize and such
|
/* Fork off so we can daemonize and such */
|
||||||
pid = fork();
|
pid = fork();
|
||||||
if (pid < 0)
|
if (pid < 0)
|
||||||
{
|
{
|
||||||
|
|
@ -318,10 +348,111 @@ master_main(char **argv)
|
||||||
}
|
}
|
||||||
else if (pid == 0)
|
else if (pid == 0)
|
||||||
{
|
{
|
||||||
// Child - this becomes the master
|
/* Child - this becomes the master */
|
||||||
master_process(s, argv);
|
master_process(s, argv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// Parent - just return.
|
/* Parent - just return. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* BSDish functions for systems that don't have them. */
|
||||||
|
#ifndef HAVE_OPENPTY
|
||||||
|
#define HAVE_OPENPTY
|
||||||
|
/* openpty: Use /dev/ptmx and Unix98 if we have it. */
|
||||||
|
#if defined(HAVE_PTSNAME) && defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT)
|
||||||
|
int
|
||||||
|
openpty(int *amaster, int *aslave, char *name, struct termios *termp,
|
||||||
|
struct winsize *winp)
|
||||||
|
{
|
||||||
|
int master, slave;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
master = open("/dev/ptmx", O_RDWR);
|
||||||
|
if (master < 0)
|
||||||
|
return -1;
|
||||||
|
if (grantpt(master) < 0)
|
||||||
|
return -1;
|
||||||
|
if (unlockpt(master) < 0)
|
||||||
|
return -1;
|
||||||
|
buf = ptsname(master);
|
||||||
|
if (!buf)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
slave = open(buf, O_RDWR|O_NOCTTY);
|
||||||
|
if (slave < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
#ifdef I_PUSH
|
||||||
|
if (ioctl(slave, I_PUSH, "ptem") < 0)
|
||||||
|
return -1;
|
||||||
|
if (ioctl(slave, I_PUSH, "ldterm") < 0)
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*amaster = master;
|
||||||
|
*aslave = slave;
|
||||||
|
if (name)
|
||||||
|
strcpy(name, buf);
|
||||||
|
if (termp)
|
||||||
|
tcsetattr(slave, TCSAFLUSH, termp);
|
||||||
|
if (winp)
|
||||||
|
ioctl(slave, TIOCSWINSZ, winp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error Do not know how to define openpty.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_FORKPTY
|
||||||
|
#if defined(HAVE_OPENPTY)
|
||||||
|
pid_t
|
||||||
|
forkpty(int *amaster, char *name, struct termios *termp,
|
||||||
|
struct winsize *winp)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int master, slave;
|
||||||
|
|
||||||
|
if (openpty(&master, &slave, name, termp, winp) < 0)
|
||||||
|
return -1;
|
||||||
|
*amaster = master;
|
||||||
|
|
||||||
|
/* Fork off... */
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0)
|
||||||
|
return -1;
|
||||||
|
else if (pid == 0)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
setsid();
|
||||||
|
#ifdef TIOCSCTTY
|
||||||
|
buf = NULL;
|
||||||
|
if (ioctl(slave, TIOCSCTTY, NULL) < 0)
|
||||||
|
_exit(1);
|
||||||
|
#else
|
||||||
|
buf = ptsname(master);
|
||||||
|
fd = open(buf, O_RDWR);
|
||||||
|
close(fd);
|
||||||
|
#endif
|
||||||
|
dup2(slave, 0);
|
||||||
|
dup2(slave, 1);
|
||||||
|
dup2(slave, 2);
|
||||||
|
|
||||||
|
if (slave > 2)
|
||||||
|
close(slave);
|
||||||
|
close(master);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
close(slave);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error Do not know how to define forkpty.
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue