/*
* Copyright Colten Edwards (July 1/1998).
* This code is for the purpose of re-attaching to a detached BitchX session.
* The idea for this program was by kasper@efnet after I mentioned the trouble
* I was having reconnecting to a detached terminal.
*/
/*
* Version 1.0 released with BitchX 75
* $Id: scr-bx.c,v 1.1.1.1 2003/04/11 01:09:07 dan Exp $
*/
#include "irc.h"
#include "struct.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#ifdef USING_CURSES
#include <curses.h>
#endif
#include <stdarg.h>
#include <string.h>
#include "ircterm.h"
#include "screen.h"
#include "ircaux.h"
#if defined(_ALL_SOURCE) || defined(__EMX__) || defined(__QNX__)
#include <termios.h>
#else
#include <sys/termios.h>
#endif
#include <sys/ioctl.h>
#ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
#ifdef MEM_DEBUG
#include <dmalloc.h>
#endif
#ifdef TRANSLATE
char translation = 0;
unsigned char transToClient[256]; /* Server to client translation. */
#endif
int dumb_mode = 0;
int already_detached = 1;
int do_check_pid = 0;
char socket_path[500];
char attach_ttyname[500];
struct param
{
pid_t pgrp,
pid;
uid_t uid;
int cols;
int rows;
char tty[80];
char cookie[30];
char password[80];
char termid[81];
};
struct param parm;
char *old_pass = NULL;
Screen *output_screen = NULL, *last_input_screen = NULL, *main_screen = NULL;
char empty_string[] = "";
int foreground = 0;
int use_input = 1;
int use_flow_control = 0;
static int displays = 0;
#define SOCKMODE (S_IWRITE | S_IREAD | (displays ? S_IEXEC : 0))
#ifdef CLOAKED
extern char proctitlestr[140];
extern char **Argv; /* pointer to argument vector */
extern char *LastArgv; /* end of argv */
#endif
char *n_m_strdup (const char *str, const char *module, const char *file, const int line)
{
char *ptr;
if (!str)
str = empty_string;
ptr = (char *)malloc(strlen(str) + 1);
return strcpy(ptr, str);
}
void ircpanic(char *string, ...)
{
return;
}
int get_int_var(int var)
{
return 1;
}
char *ltoa (long foo)
{
static char buffer[BIG_BUFFER_SIZE/8+1];
char *pos = buffer + BIG_BUFFER_SIZE/8-1;
unsigned long absv;
int negative;
absv = (foo < 0) ? (unsigned long)-foo : (unsigned long)foo;
negative = (foo < 0) ? 1 : 0;
buffer[BIG_BUFFER_SIZE/8] = 0;
for (; absv > 9; absv /= 10)
*pos-- = (absv % 10) + '0';
*pos = (absv) + '0';
if (negative)
*--pos = '-';
return pos;
}
char *lower(char *str)
{
register char *ptr = NULL;
if (str)
{
ptr = str;
for (; *str; str++)
{
if (isupper(*str))
*str = tolower(*str);
}
}
return (ptr);
}
#ifndef HAVE_GETPASS
char *getpass(char *);
char *get_string_var(int var)
{
return NULL;
}
#endif
#ifdef WINNT
void refresh_screen(int i, char *u)
{
return;
}
#endif
char *find_tty_name(char *name)
{
static char tty[20];
char *q, *s;
*tty = 0;
if ((q = strrchr(name, '/')))
{
q++;
if ((q = strchr(q, '.')))
{
q++;
if ((s = strchr(q, '.')))
strncpy(tty, q, s-q);
}
}
return tty;
}
char *find_tty_path(char *name)
{
static char ttypath[200];
char *q;
*ttypath = 0;
if ((q = strrchr(name, '/')))
strncpy(ttypath, name, q - name);
return ttypath;
}
void display_socket_list(char *path, int unl, char *arg)
{
DIR *dptr;
struct dirent *dir;
struct stat st;
char buffer[2000];
char *new_path, *p;
int count = 0;
int doit = 0;
new_path = alloca(strlen(path)+1);
strcpy(new_path, path);
if ((p = strrchr(new_path, '/')))
*p = 0;
if (!(dptr = opendir(new_path)))
{
fprintf(stderr, "No such directory %s\r\n ", new_path);
exit(1);
}
while ((dir = readdir(dptr)))
{
doit = 0;
if (!dir->d_ino)
continue;
if (dir->d_name[0] == '.')
continue;
sprintf(buffer, "%s/%s", new_path, dir->d_name);
if ((stat(buffer, &st) == -1))
continue;
if (arg && strstr(dir->d_name, arg))
doit++;
if (!count && !unl)
fprintf(stderr, "There is more than one sockets available - \r\n");
else if (!count)
fprintf(stderr, "unlinking the following\r\n");
count++;
if (unl)
{
if (!((st.st_mode & 0700) == 0600) || doit)
{
fprintf(stderr, "%30s\r\n", dir->d_name);
unlink(buffer);
}
}
else if ((!doit && !arg) || (doit && arg))
fprintf(stderr, "%30s %s\r\n", dir->d_name, ((st.st_mode & 0700) == 0600) ? "detached":"Attached or dead");
}
if (!count)
fprintf(stderr, "No sockets to attach too\r\n");
closedir(dptr);
exit(1);
}
char *find_detach_socket(char *path, char *name)
{
char *new_path;
DIR *dptr;
struct dirent *dir;
struct stat st;
char *ret = NULL, *p;
int count = 0;
new_path = alloca(strlen(path)+1);
strcpy(new_path, path);
if ((p = strrchr(new_path, '/')))
*p = 0;
else
return NULL;
if (!(dptr = opendir(new_path)))
return NULL;
ret = malloc(2000);
*ret = 0;
while ((dir = readdir(dptr)))
{
*ret = 0;
if (!dir->d_ino)
continue;
if (dir->d_name[0] == '.')
continue;
sprintf(ret, "%s/%s", new_path, dir->d_name);
p = strrchr(ret, '/'); p++;
if ((stat(ret, &st) == -1) || (st.st_uid != getuid()) || S_ISDIR(st.st_mode))
{
*ret = 0;
continue;
}
if (name)
{
char *pid, *n_tty, *h_name;
pid = alloca(strlen(p)+1);
strcpy(pid, p);
n_tty = strchr(pid, '.'); *n_tty++ = 0;
h_name = strchr(n_tty, '.'); *h_name++ = 0;
if (strcmp(name, pid))
{
if (strcmp(n_tty, name))
{
if (strcmp(h_name, name))
{
if (strcmp(p, name))
{
if (!strstr(p, name))
{
*ret = 0;
continue;
}
}
}
}
}
}
if ((st.st_mode & 0700) == 0600)
break;
count++;
*ret = 0;
}
closedir(dptr);
if (ret && !*ret)
{
free(ret);
ret = NULL;
}
switch (count)
{
case 0:
break;
case 1:
break;
default:
display_socket_list(path, 0, name);
if (ret) free(ret);
ret = NULL;
}
return ret;
}
void charset_ibmpc (void)
{
fwrite("\033(U", 3, 1, stdout); /* switch to IBM code page 437 */
}
SIGNAL_HANDLER(handle_pipe)
{
term_cr();
term_clear_to_eol();
term_reset2();
fprintf(stdout, "\rdetached from %s. To re-attach type scr-bx %s\n\r", attach_ttyname, old_pass? "password":"");
fflush(stdout);
exit(0);
}
SIGNAL_HANDLER(handle_hup)
{
term_cr();
term_clear_to_eol();
term_reset2();
fprintf(stdout, "\r");
fflush(stdout);
exit(0);
}
volatile int ctrl_c = 0;
SIGNAL_HANDLER(handle_ctrlc)
{
ctrl_c++;
}
/* set's socket options */
void set_socket_options (int s)
{
int opt = 1;
int optlen = sizeof(opt);
#ifndef NO_STRUCT_LINGER
struct linger lin;
lin.l_onoff = lin.l_linger = 0;
setsockopt(s, SOL_SOCKET, SO_LINGER, (char *)&lin, optlen);
#endif
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, optlen);
opt = 1;
setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char *)&opt, optlen);
}
char *get_cookie(char *name)
{
static char cookie[80];
FILE *fp = NULL;
*cookie = 0;
if ((fp = fopen(name, "r")))
{
fread(cookie, 40, 1, fp);
fclose(fp);
if (*cookie)
cookie[strlen(cookie)-1] = 0;
}
return cookie;
}
void reattach_tty(char *tty, char *password)
{
int s = -1;
char *name;
struct sockaddr_in addr;
struct hostent *hp;
int len = 0;
fd_set rd_fd;
struct timeval tm = {0};
char chr_c[] = "\003";
/*
* this buffer has to be big enough to handle a full screen of
* information from the detached process.
*/
unsigned char buffer[6 * BIG_BUFFER_SIZE+1];
char *p;
int port = 0;
#if defined (TIOCGWINSZ)
struct winsize window;
#endif
memset(&parm, 0, sizeof(struct param));
if (!(name = find_detach_socket(socket_path, tty)))
{
fprintf(stderr, "No detached process to attach too\r\n");
_exit(1);
}
strcpy(parm.cookie, get_cookie(name));
if (!*parm.cookie)
_exit(1);
if ((p = strrchr(name, '/')))
p++;
sscanf(p, "%d.%*s.%*s", &port);
displays = 1;
if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
displays = 0;
_exit(1);
}
chmod(name, SOCKMODE);
set_socket_options(s);
memset(&addr, 0, sizeof(struct sockaddr_in));
addr.sin_port = htons(port);
addr.sin_family = AF_INET;
if((hp = gethostbyname("localhost")))
memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
else
inet_aton("127.0.0.1", (struct in_addr *)&addr.sin_addr);
if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
fprintf(stderr, "connection refused for %s\r\n", name);
_exit(1);
}
parm.pid = getpid();
parm.pgrp = getpgrp();
parm.uid = getuid();
strcpy(parm.tty, ttyname(0));
strncpy(parm.termid, getenv("TERM"), 80);
if (password)
strncpy(parm.password, password, 60);
fprintf(stderr, "attempting to wakeup %s\r\n", find_tty_name(name));
#if defined (TIOCGWINSZ)
if (ioctl(0, TIOCGWINSZ, &window) > -1)
{
parm.cols = window.ws_col;
parm.rows = window.ws_row;
}
else
#endif
{
parm.cols = 79;
parm.rows = 25;
}
write(s, &parm, sizeof(struct param));
sleep(2);
alarm(15);
len = read(s, &parm, sizeof(struct param));
alarm(0);
if (len <= 0)
{
fprintf(stderr, "[1;37merror[0;37m reconnecting to %s\r\n", find_tty_name(name));
displays = 0;
chmod(name, SOCKMODE);
exit(1);
}
unlink(name);
term_init(parm.termid);
set_term_eight_bit(1);
charset_ibmpc();
term_clear_screen();
term_resize();
term_move_cursor(0,0);
my_signal(SIGPIPE, handle_pipe, 0);
my_signal(SIGINT, handle_ctrlc, 0);
my_signal(SIGHUP, handle_hup, 0);
/*
* according to MHacker we need to set errno to 0 under BSD.
* for some reason we get a address in use from a socket
*
*/
errno = 0;
while (1)
{
FD_ZERO(&rd_fd);
FD_SET(0, &rd_fd);
FD_SET(s, &rd_fd);
tm.tv_sec = 2;
switch(select(s+1, &rd_fd, NULL, NULL, &tm))
{
case -1:
if (ctrl_c)
{
write(s, chr_c, 1);
ctrl_c = 0;
}
else if (errno != EINTR)
{
close(s);
_exit(1);
}
break;
case 0:
break;
default:
{
if (FD_ISSET(0, &rd_fd))
{
len = read(0, buffer, sizeof(buffer)-1);
write(s, buffer, len);
}
if (FD_ISSET(s, &rd_fd))
{
len = read(s, buffer, sizeof(buffer)-1);
write(1, buffer, len);
}
}
}
}
close(s);
fprintf(stderr, "Never should have got here");
_exit(1);
return; /* error return */
}
char *stripdev(char *ttynam)
{
if (ttynam == NULL)
return NULL;
#ifdef SVR4
/* unixware has /dev/pts012 as synonym for /dev/pts/12 */
if (!strncmp(ttynam, "/dev/pts", 8) && ttynam[8] >= '0' && ttynam[8] <= '9')
{
static char b[13];
sprintf(b, "pts/%d", atoi(ttynam + 8));
return b;
}
#endif /* SVR4 */
if (!strncmp(ttynam, "/dev/", 5))
return ttynam + 5;
return ttynam;
}
void init_socketpath(void)
{
#if !defined(__EMX__) && !defined(WINNT)
struct stat st;
extern char socket_path[], attach_ttyname[];
sprintf(socket_path, "%s/.BitchX/screens", getenv("HOME"));
if (access(socket_path, F_OK))
return;
if (stat(socket_path, &st) != -1)
{
char host[BIG_BUFFER_SIZE+1];
char *ap;
if (!S_ISDIR(st.st_mode))
return;
gethostname(host, BIG_BUFFER_SIZE);
if ((ap = strchr(host, '.')))
*ap = 0;
ap = &socket_path[strlen(socket_path)];
sprintf(ap, "/%%d.%s.%s", stripdev(attach_ttyname), host);
ap++;
for ( ; *ap; ap++)
if (*ap == '/')
*ap = '-';
}
#endif
}
char *old_tty = NULL;
void parse_args(int argc, char **argv)
{
int ac = 1;
int disp_sock = 0;
for (; ac < argc; ac++)
{
if (!strncasecmp(argv[ac], "tty", 3))
{
old_tty = malloc(strlen(argv[ac])+1);
strcpy(old_tty, argv[ac]);
}
else if (argv[ac][0] == '-' && argv[ac][1] == 'p')
{
char *pass;
pass = getpass("Enter password : ");
old_pass = malloc(strlen(pass)+1);
strcpy(old_pass, pass);
}
else if (argv[ac][0] == '-' && argv[ac][1] == 'h')
{
char *p;
if ((p = strrchr(argv[0], '/')))
p++;
else
p = argv[0];
fprintf(stderr, "Usage %s: [tty] [-p] [-h] [-l]\r\n\t\ttty is the name of a tty\r\n\t\t-p to specify a password\r\n\t\t-l to list available sockets\r\n\t\t-w to wipe out dead sockets\r\n", p);
exit(0);
}
else if (argv[ac][0] == '-' && argv[ac][1] == 'l')
disp_sock = 1;
else if (argv[ac][0] == '-' && argv[ac][1] == 'w')
disp_sock = 2;
else if (!old_tty)
{
old_tty = malloc(strlen(argv[ac])+1);
strcpy(old_tty, argv[ac]);
}
}
if (disp_sock)
display_socket_list(socket_path, disp_sock - 1, old_tty);
}
int main(int argc, char **argv)
{
#ifdef MEM_DEBUG
dmalloc_debug(0x1df47dfb);
#endif
*socket_path = 0;
strcpy(attach_ttyname, ttyname(0));
init_socketpath();
parse_args(argc, argv);
chdir(getenv("HOME"));
reattach_tty(old_tty, old_pass);
return 0;
}
syntax highlighted by Code2HTML, v. 0.9.1