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:
Ned T. Crigler 2001-11-05 20:02:58 +00:00
parent ba4a3a502f
commit 203193838d
11 changed files with 3271 additions and 1184 deletions

View File

@ -1,9 +1,9 @@
srcdir = @srcdir@
CC = @CC@
CFLAGS = -W -Wall -I. @CFLAGS@
CFLAGS = @CFLAGS@ -I.
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
VERSION = 0.3
VERSION = 0.4
VPATH = $(srcdir)
OBJ = attach.o master.o main.o
@ -14,10 +14,10 @@ TARFILES = $(srcdir)/README $(srcdir)/COPYING $(srcdir)/*.in $(srcdir)/*.c \
$(srcdir)/dtach.1
dtach: $(OBJ)
$(CC) -o $@ $(LDFLAGS) $^ $(LIBS)
$(CC) -o $@ $(LDFLAGS) $(OBJ) $(LIBS)
clean:
rm -f .depend dtach $(OBJ) dtach-$(VERSION).tar.gz
rm -f dtach $(OBJ) dtach-$(VERSION).tar.gz
distclean: clean
rm -f config.h Makefile config.log config.status config.cache
@ -29,7 +29,7 @@ tar:
gzip -9f dtach-$(VERSION).tar
rm -rf dtach-$(VERSION)
.depend:
@$(CC) $(CFLAGS) -MM $(SRC) > $@
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
-include .depend

4
README
View File

@ -96,8 +96,10 @@ to dtach when attaching.
5. CHANGES
The changes since version 0.3 are:
The changes in version 0.4 are:
- 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:
- Fixed a typo in dtach.1

View File

@ -26,49 +26,52 @@
#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;
// 1 if the window size changed
/* 1 if the window size changed */
static int win_changed;
// 1 if we want a redraw
/* 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"
// Restores the original terminal settings.
/* Restores the original terminal settings. */
static void
restore_term(void)
{
tcsetattr(0, TCSADRAIN, &orig_term);
// Make cursor visible. Assumes VT100.
/* Make cursor visible. Assumes VT100. */
printf("\033[?25h\033[?0c");
fflush(stdout);
}
// Connects to a unix domain socket
/* Connects to a unix domain socket */
static int
connect_socket(char *name)
{
int s;
struct sockaddr_un sun;
struct sockaddr_un sockun;
s = socket(PF_UNIX, SOCK_STREAM, 0);
if (s < 0)
return -1;
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, name);
if (connect(s, (struct sockaddr*)&sun, sizeof(sun)) < 0)
sockun.sun_family = AF_UNIX;
strcpy(sockun.sun_path, name);
if (connect(s, (struct sockaddr*)&sockun, sizeof(sockun)) < 0)
return -1;
return s;
}
// Signal
/* Signal */
static RETSIGTYPE
die(int sig)
{
// Print a nice pretty message for some things.
/* Print a nice pretty message for some things. */
if (sig == SIGHUP || sig == SIGINT)
printf(EOS "\r\n[detached]\r\n");
else
@ -76,50 +79,51 @@ die(int sig)
exit(1);
}
// Window size change.
/* Window size change. */
static RETSIGTYPE
win_change()
{
win_changed = 1;
}
// Handles input from the keyboard.
/* Handles input from the keyboard. */
static void
process_kbd(int s, struct packet *pkt)
{
// Suspend?
/* Suspend? */
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;
write(s, pkt, sizeof(*pkt));
// And suspend...
/* And suspend... */
tcsetattr(0, TCSADRAIN, &orig_term);
printf(EOS "\r\n");
kill(getpid(), SIGTSTP);
tcsetattr(0, TCSADRAIN, &cur_term);
// Tell the master that we are returning.
/* Tell the master that we are returning. */
pkt->type = MSG_ATTACH;
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.
/* 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?
/* Detach char? */
else if (pkt->u.buf[0] == detach_char)
{
printf(EOS "\r\n[detached]\r\n");
exit(1);
}
// Just in case something pukes out.
/* Just in case something pukes out. */
else if (pkt->u.buf[0] == '\f')
win_changed = 1;
// Push it out
/* Push it out */
write(s, pkt, sizeof(*pkt));
}
@ -131,14 +135,14 @@ attach_main(int noerror)
struct packet pkt;
unsigned char buf[BUFSIZE];
// The current terminal settings are equal to the original terminal
// settings at this point.
/* The current terminal settings are equal to the original terminal
** settings at this point. */
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);
// Set some signals.
/* Set some signals. */
signal(SIGPIPE, SIG_IGN);
signal(SIGXFSZ, SIG_IGN);
signal(SIGHUP, die);
@ -147,8 +151,8 @@ attach_main(int noerror)
signal(SIGQUIT, die);
signal(SIGWINCH, win_change);
// Attempt to open the socket. Don't display an error if noerror is
// set.
/* Attempt to open the socket. Don't display an error if noerror is
** set. */
s = connect_socket(sockname);
if (s < 0)
{
@ -158,20 +162,22 @@ attach_main(int noerror)
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_oflag &= ~(OPOST);
cur_term.c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
cur_term.c_cflag &= ~(CSIZE|PARENB);
cur_term.c_cflag |= CS8;
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.
/* Clear the screen. This assumes VT100. */
write(1, "\33[H\33[J", 6);
// Set up the poll structures
/* Set up the poll structures */
polls[0].fd = 0;
polls[0].events = POLLIN;
polls[0].revents = 0;
@ -179,15 +185,15 @@ attach_main(int noerror)
polls[1].events = POLLIN;
polls[1].revents = 0;
// Send our window size.
/* Send our window size. */
pkt.type = MSG_WINCH;
ioctl(0, TIOCGWINSZ, &pkt.u.ws);
write(s, &pkt, sizeof(pkt));
// We would like a redraw, too.
/* 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)
{
if (poll(polls, 2, -1) < 0)
@ -198,7 +204,7 @@ attach_main(int noerror)
exit(1);
}
}
// Pty activity
/* Pty activity */
if (polls[1].revents != 0)
{
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");
exit(1);
}
// Send the data to the terminal.
/* Send the data to the terminal. */
write(1, buf, len);
}
// stdin activity
/* stdin activity */
if (polls[0].revents != 0)
{
pkt.type = MSG_PUSH;
@ -228,7 +234,7 @@ attach_main(int noerror)
exit(1);
process_kbd(s, &pkt);
}
// Window size changed?
/* Window size changed? */
if (win_changed)
{
win_changed = 0;
@ -237,7 +243,7 @@ attach_main(int noerror)
ioctl(0, TIOCGWINSZ, &pkt.u.ws);
write(s, &pkt, sizeof(pkt));
}
// Want a redraw?
/* Want a redraw? */
if (want_redraw)
{
want_redraw = 0;

View File

@ -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. */
#undef HAVE_FORKPTY
@ -6,30 +6,75 @@
/* Define if you have the `getrlimit' function. */
#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). */
#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. */
#undef HAVE_PTY_H
/* Define if you have the `socket' function. */
#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. */
#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. */
#undef HAVE_SYS_IOCTL_H
/* Define if you have the <sys/resource.h> header file. */
#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. */
#undef HAVE_TERMIOS_H
/* Define if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
/* Define if you have the `unlockpt' function. */
#undef HAVE_UNLOCKPT
/* Define if you have the <util.h> header file. */
#undef HAVE_UTIL_H

3887
configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -4,12 +4,18 @@ 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, forkpty)
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
@ -17,7 +23,7 @@ AC_TYPE_PID_T
dnl Checks for library functions.
AC_PROG_GCC_TRADITIONAL
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_OUTPUT(Makefile)

View File

@ -22,6 +22,7 @@
#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
@ -35,6 +36,14 @@
#include <util.h>
#endif
#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
#endif
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
@ -67,7 +76,7 @@ enum
MSG_DETACH
};
// The client to master protocol.
/* The client to master protocol. */
struct packet
{
unsigned char type;
@ -79,13 +88,19 @@ struct packet
} 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
// future. In the meantime, however, we minimize the amount of data sent back
// and forth between the client and the master. BUFSIZE is the size of the
// buffer used for the text stream.
/*
** 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
** future. In the meantime, however, we minimize the amount of data sent back
** and forth between the client and the master. BUFSIZE is the size of the
** buffer used for the text stream.
*/
#define BUFSIZE 4096
int attach_main(int noerror);
int master_main(char **argv);
#ifdef sun
#define BROKEN_MASTER
#endif
#endif

View File

@ -1,4 +1,4 @@
.TH dtach 1 "September 2001" "dtach 0.3"
.TH dtach 1 "September 2001" "dtach 0.4"
.SH NAME
dtach \- simple program that emulates the detach feature of screen.
.SH SYNOPSIS

View File

@ -1,6 +1,6 @@
Summary: A simple program that emulates the detach feature of screen.
Name: dtach
Version: 0.3
Version: 0.4
Release: 1
Copyright: GPL
URL: http://dtach.sourceforge.net
@ -45,6 +45,11 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version}
%{_mandir}/man1/*
%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>
- Modified spec file URL: to point to http://dtach.sourceforge.net

32
main.c
View File

@ -24,24 +24,26 @@
** does not keep track of the screen or anything like that.
*/
// The program version
#define VERSION "0.3"
/* The program version */
#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";
// argv[0] from the program
/* argv[0] from the program */
char *progname;
// The name of the passed in socket.
/* The name of the passed in socket. */
char *sockname;
// The character used for detaching. Defaults to '^\'
/* The character used for detaching. Defaults to '^\' */
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;
// The original terminal settings. Shared between the master and attach
// processes. The master uses it to initialize the pty, and the attacher uses
// it to restore the original settings.
/*
** The original terminal settings. Shared between the master and attach
** processes. The master uses it to initialize the pty, and the attacher uses
** it to restore the original settings.
*/
struct termios orig_term;
static void
@ -75,11 +77,11 @@ main(int argc, char **argv)
{
int mode = 0;
// Save the program name
/* Save the program name */
progname = argv[0];
++argv; --argc;
// Parse the arguments
/* Parse the arguments */
if (argc >= 1 && **argv == '-')
{
if (strncmp(*argv, "--help", strlen(*argv)) == 0)
@ -174,7 +176,7 @@ main(int argc, char **argv)
return 1;
}
// Save the original terminal settings.
/* Save the original terminal settings. */
if (tcgetattr(0, &orig_term) < 0)
{
printf("%s: tcgetattr: %s\n", progname, strerror(errno));
@ -203,8 +205,8 @@ main(int argc, char **argv)
}
else if (mode == 'A')
{
// Try to attach first. If that doesn't work, create a new
// socket.
/* Try to attach first. If that doesn't work, create a new
** socket. */
if (attach_main(1) != 0)
{
if (master_main(argv) != 0)

261
master.c
View File

@ -18,58 +18,73 @@
*/
#include "detach.h"
// The pty struct - The pty information is stored here.
/* The pty struct - The pty information is stored here. */
struct pty
{
// File descriptor of the pty
/* File descriptor of the pty */
int fd;
// The terminal parameters of the pty. Old and new for comparision
// purposes.
#ifdef BROKEN_MASTER
/* 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;
// The current window size of the pty.
/* The current window size of the pty. */
struct winsize ws;
};
// The poll structures
/* The poll structures */
static struct pollfd *polls;
// The number of active poll slots
/* The number of active poll slots */
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;
// The highest file descriptor possible, as returned by getrlimit.
/* The highest file descriptor possible, as returned by getrlimit. */
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
// 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
unlink_socket(void)
{
unlink(sockname);
}
// Signal
/* Signal */
static RETSIGTYPE
die(int sig)
{
// Well, the child died.
/* Well, the child died. */
if (sig == SIGCHLD)
{
#ifdef BROKEN_MASTER
/* Damn you Solaris! */
close(polls[1].fd);
#endif
return;
}
exit(1);
}
// Initialize the pty structure.
/* Initialize the pty structure. */
static int
init_pty(struct pty *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.
/* 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;
// Create the pty process
/* Create the pty process */
pid = forkpty(&pty->fd, NULL, &pty->term, NULL);
if (pid < 0)
return -1;
@ -77,59 +92,74 @@ init_pty(struct pty *pty, char **argv)
{
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)
close(i);
execvp(*argv, argv);
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;
}
// Creates a new unix domain socket.
/* Creates a new unix domain socket. */
static int
create_socket(char *name)
{
int s;
struct sockaddr_un sun;
struct sockaddr_un sockun;
s = socket(PF_UNIX, SOCK_STREAM, 0);
if (s < 0)
return -1;
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, name);
if (bind(s, (struct sockaddr*)&sun, sizeof(sun)) < 0)
sockun.sun_family = AF_UNIX;
strcpy(sockun.sun_path, name);
if (bind(s, (struct sockaddr*)&sockun, sizeof(sockun)) < 0)
return -1;
if (listen(s, 128) < 0)
return -1;
// chmod it to prevent any suprises
/* chmod it to prevent any suprises */
if (chmod(name, 0600) < 0)
return -1;
return s;
}
// Process activity on a pty - Input and terminal changes are sent out to
// the attached clients. If the pty goes away, we die.
/* Process activity on a 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)
{
int i, len;
unsigned char buf[BUFSIZE];
// Read the pty activity
/* Read the pty activity */
len = read(pty->fd, buf, sizeof(buf));
// Error -> die
/* Error -> die */
if (len <= 0)
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)
exit(1);
#endif
// Send it out to the clients.
/* Send it out to the clients. */
for (i = FIXED_SLOTS; i < num_polls; ++i)
{
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
control_activity(int s)
{
int fd;
// Accept the new client and link it in.
/* Accept the new client and link it in. */
fd = accept(s, 0, 0);
if (fd < 0)
return;
// Link it in.
/* Link it in. */
polls[num_polls].fd = fd;
polls[num_polls].events = POLLIN;
polls[num_polls].revents = 0;
@ -156,18 +186,18 @@ control_activity(int s)
++num_polls;
}
// Process activity from a client.
/* Process activity from a client. */
static void
client_activity(int i, struct pty *pty)
{
int len;
struct packet pkt;
// Read the activity.
/* Read the activity. */
len = read(polls[i].fd, &pkt, sizeof(pkt));
if (len <= 0)
{
// Close the socket and go bye bye
/* 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);
@ -175,36 +205,36 @@ client_activity(int i, struct pty *pty)
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)
write(pty->fd, pkt.u.buf, pkt.len);
// Window size change.
/* Window size change. */
else if (pkt.type == MSG_WINCH)
{
pty->ws = pkt.u.ws;
ioctl(pty->fd, TIOCSWINSZ, &pty->ws);
}
// Redraw request?
/* Redraw request? */
else if (pkt.type == MSG_REDRAW)
{
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) &&
(pty->term.c_cc[VMIN] == 1))
{
write(pty->fd, &c, sizeof(c));
}
}
// Attach request?
/* 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
// clients.
/* The master process - It watches over the pty process and the attached */
/* clients. */
static void
master_process(int s, char **argv)
{
@ -214,8 +244,8 @@ master_process(int s, char **argv)
#ifdef HAVE_GETRLIMIT
struct rlimit rlim;
// Dynamically allocate structures based on the number of file
// descriptors.
/* Dynamically allocate structures based on the number of file
** descriptors. */
if (getrlimit(RLIMIT_NOFILE, &rlim) < 0)
{
@ -224,25 +254,25 @@ master_process(int s, char **argv)
}
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.
/* 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
// don't care what happens to it.
/* 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.
/* Create a pty in which the process is running. */
if (init_pty(&pty, argv) < 0)
{
printf("%s: init_pty: %s\n", progname, strerror(errno));
exit(1);
}
// Set up some signals.
/* Set up some signals. */
signal(SIGPIPE, SIG_IGN);
signal(SIGXFSZ, SIG_IGN);
signal(SIGHUP, SIG_IGN);
@ -252,16 +282,16 @@ master_process(int s, char **argv)
signal(SIGTERM, 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(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.
/* 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;
@ -270,23 +300,23 @@ master_process(int s, char **argv)
polls[1].revents = 0;
num_polls = FIXED_SLOTS;
// Loop forever.
/* Loop forever. */
while (1)
{
// Wait for something to happen.
/* Wait for something to happen. */
if (poll(polls, num_polls, -1) < 0)
{
if (errno == EINTR || errno == EAGAIN)
continue;
exit(1);
}
// pty activity?
/* pty activity? */
if (polls[1].revents != 0)
pty_activity(&pty);
// New client?
/* New client? */
if (polls[0].revents != 0)
control_activity(s);
// Activity on a client?
/* Activity on a client? */
for (i = 2; i < num_polls; ++i)
{
if (polls[i].revents != 0)
@ -301,7 +331,7 @@ master_main(char **argv)
int s;
pid_t pid;
// Create the unix domain socket.
/* Create the unix domain socket. */
s = create_socket(sockname);
if (s < 0)
{
@ -309,7 +339,7 @@ master_main(char **argv)
return 1;
}
// Fork off so we can daemonize and such
/* Fork off so we can daemonize and such */
pid = fork();
if (pid < 0)
{
@ -318,10 +348,111 @@ master_main(char **argv)
}
else if (pid == 0)
{
// Child - this becomes the master
/* Child - this becomes the master */
master_process(s, argv);
return 0;
}
// Parent - just return.
/* Parent - just return. */
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