251 lines
5.5 KiB
C
251 lines
5.5 KiB
C
/*
|
|
dtach - A simple program that emulates the detach feature of screen.
|
|
Copyright (C) 2001 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
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
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"
|
|
|
|
#ifndef VDISABLE
|
|
#ifdef _POSIX_VDISABLE
|
|
#define VDISABLE _POSIX_VDISABLE
|
|
#else
|
|
#define VDISABLE 0377
|
|
#endif
|
|
#endif
|
|
|
|
// The current terminal settings. After coming back from a suspend, we
|
|
// restore this.
|
|
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"
|
|
|
|
// Restores the original terminal settings.
|
|
static void
|
|
restore_term(void)
|
|
{
|
|
tcsetattr(0, TCSADRAIN, &orig_term);
|
|
// Make cursor visible. Assumes VT100.
|
|
printf("\033[?25h\033[?0c");
|
|
fflush(stdout);
|
|
}
|
|
|
|
// Connects to a unix domain socket
|
|
static int
|
|
connect_socket(char *name)
|
|
{
|
|
int s;
|
|
struct sockaddr_un sun;
|
|
|
|
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)
|
|
return -1;
|
|
return s;
|
|
}
|
|
|
|
// Signal
|
|
static RETSIGTYPE
|
|
die(int sig)
|
|
{
|
|
// Print a nice pretty message for some things.
|
|
if (sig == SIGHUP || sig == SIGINT)
|
|
printf(EOS "\r\n[detached]\r\n");
|
|
else
|
|
printf(EOS "\r\n[got signal %d - dying]\r\n", sig);
|
|
exit(1);
|
|
}
|
|
|
|
// Window size change.
|
|
static RETSIGTYPE
|
|
win_change()
|
|
{
|
|
win_changed = 1;
|
|
}
|
|
|
|
// Handles input from the keyboard.
|
|
static void
|
|
process_kbd(int s, struct packet *pkt)
|
|
{
|
|
// Suspend?
|
|
if (!no_suspend && (pkt->u.buf[0] == cur_term.c_cc[VSUSP]))
|
|
{
|
|
// Tell the master that we are suspending.
|
|
pkt->type = MSG_DETACH;
|
|
write(s, pkt, sizeof(*pkt));
|
|
|
|
// And suspend...
|
|
tcsetattr(0, TCSADRAIN, &orig_term);
|
|
kill(getpid(), SIGTSTP);
|
|
tcsetattr(0, TCSADRAIN, &cur_term);
|
|
|
|
// 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.
|
|
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);
|
|
}
|
|
// Just in case something pukes out.
|
|
else if (pkt->u.buf[0] == '\f')
|
|
win_changed = 1;
|
|
|
|
// Push it out
|
|
write(s, pkt, sizeof(*pkt));
|
|
}
|
|
|
|
int
|
|
attach_main(int noerror)
|
|
{
|
|
int s;
|
|
struct pollfd polls[2];
|
|
struct packet pkt;
|
|
unsigned char buf[BUFSIZE];
|
|
|
|
// 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.
|
|
atexit(restore_term);
|
|
|
|
// Set some signals.
|
|
signal(SIGPIPE, SIG_IGN);
|
|
signal(SIGXFSZ, SIG_IGN);
|
|
signal(SIGHUP, die);
|
|
signal(SIGTERM, die);
|
|
signal(SIGINT, die);
|
|
signal(SIGQUIT, die);
|
|
signal(SIGWINCH, win_change);
|
|
|
|
// Attempt to open the socket. Don't display an error if noerror is
|
|
// set.
|
|
s = connect_socket(sockname);
|
|
if (s < 0)
|
|
{
|
|
if (!noerror)
|
|
printf("%s: %s: %s\n", progname, sockname,
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
|
|
// 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;
|
|
|
|
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;
|
|
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)
|
|
{
|
|
if (errno != EINTR && errno != EAGAIN)
|
|
{
|
|
printf(EOS "\r\n[poll failed]\r\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
// Pty activity
|
|
if (polls[1].revents != 0)
|
|
{
|
|
int len = read(s, buf, sizeof(buf));
|
|
|
|
if (len == 0)
|
|
{
|
|
printf(EOS "\r\n[EOF - dtach terminating]"
|
|
"\r\n");
|
|
exit(1);
|
|
}
|
|
else if (len < 0)
|
|
{
|
|
printf(EOS "\r\n[read returned an error]\r\n");
|
|
exit(1);
|
|
}
|
|
// Send the data to the terminal.
|
|
write(1, buf, len);
|
|
}
|
|
// stdin activity
|
|
if (polls[0].revents != 0)
|
|
{
|
|
pkt.type = MSG_PUSH;
|
|
memset(pkt.u.buf, 0, sizeof(pkt.u.buf));
|
|
pkt.len = read(0, pkt.u.buf, sizeof(pkt.u.buf));
|
|
|
|
if (pkt.len <= 0)
|
|
exit(1);
|
|
process_kbd(s, &pkt);
|
|
}
|
|
// Window size changed?
|
|
if (win_changed)
|
|
{
|
|
win_changed = 0;
|
|
|
|
pkt.type = MSG_WINCH;
|
|
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;
|
|
}
|