home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume14
/
3bconnect
/
connect.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-05-08
|
6KB
|
271 lines
/*
* Copyright (C) 1988 Dave Settle. All rights reserved.
* Permission is granted to use, copy and modify this software, providing
* that it is not sold for profit, and that this copyright notice is retained
* in any copies of the source.
*/
/*
* connect.c: connect tty to remote host.
*/
#include <sys/types.h>
#include <sys/signal.h>
#include <sys/errno.h>
#include <sys/utsname.h>
#include <termio.h>
#include <pwd.h>
struct passwd *getpwuid(), *getpwnam();
char *getlogin();
int (*signal())();
extern int errno;
#include <stdio.h>
#define MAIN
#include "ni.h"
char remoteshell[] = {0,0,0,0,0,0};
struct request request;
int reader, writer; /* Processes */
int login = 0; /* Are we doing a login? */
#define COOKED 0
#define RAW 1
struct termio raw, cooked; /* To allow screen mode changes */
int screenmode = COOKED, toggle(), trap();
wakeup(){
signal(SIGALRM, wakeup);
}
/*
* Got a signal - die. Writer is child process here.
*/
die(sig){
if(sig) printf("Connection closed.\r\n");
if((getpid() == writer) && reader) kill(reader, SIGTERM);
else if(writer) terminate(writer);
send(&request, 0, TERMINATE, server);
if(cooked.c_oflag) ioctl(fileno(stdout), TCSETA, &cooked);
exit(0);
}
sendsig(sig)
{
struct request request;
signal(sig, sendsig);
if(sig == SIGINT) send(&request, 0, RMTSIGINT, server);
if(sig == SIGQUIT) send(&request, 0, RMTSIGQUIT, server);
}
main(argc, argv)
char **argv;
{
struct utsname uts;
register char *sys = argv[argc - 1];
int i;
if(argc < 2) {
printf("usage: %s hostname\n", argv[0]);
exit(1);
}
uname(&uts);
for(i=1;i<argc;i++) if(*argv[i] == '-') switch(argv[i][1]) {
case 'l':
login = 1;
break;
case 'd':
debug = 1;
break;
}
signal(SIGALRM, wakeup);
signal(SIGTERM, SIG_IGN);
if(configure(client, 3, getpid()) == -1) exit(1);
if((i = hostaddr(argv[argc - 1])) == -1) {
printf("Host '%s' not known\n", argv[argc - 1]);
exit(1);
}
else server[NODE] = i;
connect(server, sys);
return(0);
}
/*
* connect(addr): set up connection to ethernet address 'addr' (system 'sys')
*/
connect(addr, sys)
char *addr, *sys;
{
register struct request *r = &request;
char *shell, *user;
int n;
struct passwd *pw;
/*
* send off our login name and uid to remote host.
* also send timezone.
*/
if((user = getlogin()) == NULL)
pw = getpwuid(getuid());
else
pw = getpwnam(user);
if(pw == NULL) {
printf("Can't determine your user name!\n");
exit(1);
}
if(*pw->pw_name == 0) {
printf("Your user name is NULL! You seem to be %s\n",
user ? user : "unknown");
exit(1);
}
printf("Trying to connect to %s ... ", ipaddr(addr));
fflush(stdout);
sprintf(r->r_data, "%d %s TERM=%s",
pw->pw_uid, pw->pw_name, getenv("TERM"));
n = strlen(r->r_data);
send(r, n, REQUEST, addr);
recv(r);
if(r->r_type == TERMINATE) {
printf("rejected!\n%s: %s\n", sys, r->r_data);
exit(0);
}
memcpy(server, r->r_port.srcaddr, ETHERSIZE);
/*
* trap signals from here on, so that we can terminate the remote side.
*/
signal(SIGQUIT, toggle);
signal(SIGINT, sendsig);
signal(SIGHUP, die);
printf("OK\nStarting remote %s ... ", login ? "login" : "shell");
fflush(stdout);
if(login) n = sprintf(r->r_data, "login");
else {
shell = getenv("SHELL");
if(shell == 0) shell = "/bin/sh";
n = sprintf(r->r_data, "%s -i", shell);
}
send(r, n, REQUEST, server);
recv(r);
if(r->r_type == TERMINATE) {
printf("rejected!\n%s: %s\n", sys, r->r_data);
exit(0);
}
printf("OK\nConnection complete ... server is %s\n", ipaddr(server));
/*
* Set up the termio structures needed for mode swapping
*/
ioctl(fileno(stdin), TCGETA, &cooked);
ioctl(fileno(stdin), TCGETA, &raw);
raw.c_oflag &= ~OPOST;
raw.c_cc[VMIN] = 1;
raw.c_cc[VTIME] = 0;
raw.c_iflag = 0;
raw.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
screenmode = COOKED;
/*
* fork for reader and writer processes.
*/
reader = getpid();
if(writer = fork()) {
/*
* If we are starting a remote login via a ptty, then the remote host will
* echo, so set to raw mode. SIGQUIT will close the connection.
*/
if(login) {
screenmode = RAW;
ioctl(fileno(stdin), TCSETA, &raw);
signal(SIGQUIT, die);
signal(SIGINT, trap);
}
else {
/*
* Send the remote shell an initial newline, so that the user sees a prompt.
*/
r->r_data[0] = '\n';
send(r, 1, DATA, server);
}
while(n = read(fileno(stdin), r->r_data, sizeof r->r_data)) {
if(n == -1) {
if(errno == EINTR) continue;
else break;
}
if(debug) {
printf("client: sent [");
write(fileno(stdout), r->r_data, n);
printf("] to %s\n", ipaddr(server));
}
send(r, n, DATA, server);
}
send(r, 0, TERMINATE, server);
terminate(writer);
ioctl(fileno(stdout), TCSETA, &cooked);
exit(0);
}
else {
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
while(1) {
recv(r);
if(debug) {
printf("client: got [");
write(fileno(stdout), r->r_data, r->r_size);
printf("] from %s\n", ipaddr(r->r_port.srcaddr));
}
if(r->r_type == TERMINATE) {
printf("Lost remote connection [");
fflush(stdout);
write(fileno(stdout), r->r_data, r->r_size);
printf("]\n");
kill(reader, SIGTERM);
ioctl(fileno(stdout), TCSETA, &cooked);
exit(0);
}
write(fileno(stdout), r->r_data, r->r_size);
}
}
}
/*
* toggle: change screen mode from RAW <-> COOKED
*/
toggle(sig){
static int (*handler)();
signal(sig, toggle);
switch(screenmode) {
case COOKED:
handler = signal(SIGINT, trap);
ioctl(fileno(stdin), TCSETA, &raw);
putchar(07); /* beep */
fflush(stdout);
screenmode = RAW;
break;
case RAW:
if(handler) signal(SIGINT, handler);
ioctl(fileno(stdin), TCSETA, &cooked);
printf("[cooked]");
fflush(stdout);
screenmode = COOKED;
break;
}
}
/*
* trap interrupts in raw mode, substitute 'del' char
* We can't just ignore interrupts, otherwise we can't switch out of raw mode.
*/
trap(sig){
struct request r;
signal(sig, trap);
switch(sig) {
default:
case SIGINT:
r.r_data[0] = cooked.c_cc[VINTR];
break;
case SIGQUIT:
r.r_data[0] = cooked.c_cc[VQUIT];
break;
}
send(&r, 1, DATA, server);
}