Callback to terminals
Pete French
pcf at galadriel.bt.co.uk
Sat Sep 16 00:33:22 AEST 1989
Since so many of you out there have requested the source to my program
for redialing terminals (even though it dont work!) then rather than keep
answering mail every 5 minutes I will post it here. Its not very long, or
very well written (I wasnt very good at C then) and all the comments have
been added recently (i.e. the last few days) so I cant guarantee that they
accurately reflect the thinking behind the code when it was written.
But for what its worth ... here it is. feel free to play with it as you see fit.
If you get it going ... mail me back a copy :-)
-Pete.
---------------------------cut here--------------------------------
/* redial - redial a number. Used as "redial <number>". The program
immediately logs out the user running it and then attempts to
redial him on the given telephone number using a hayes modem.
The modem is expected to be 300 baud and connected to tty00. These
are - at the present time - hardwired into the program.
NOTE : Although this program appears to function correctly when
connected to a terminal instead of a modem (i.e. all the correct
sequences are sent) it has never been shown to work with an actual
modem. This program _DOES_NOT_WORK_ in its current state. Some
debugging is therefore necessary (but not much I hope :-) ).
It is suggested that this be done by using a terminal to
monitor the RS232 line and watch the exchange between the program and
the modem.
Adapt this code any way you want - you may give it to anyone you like
as well (you may eveny give it to anyone you diskile :-) ).
-Pete French. */
#include <stdio.h>
#include <termio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <utmp.h>
#include <string.h>
#include <signal.h>
extern struct utmp *getutline();
struct utmp *y;
struct termio cts;
int curpid;
char *banner;
/* werminate() terminates the program by correctly setting up
the utmp entry and then exiting */
werminate(val)
int val;
{
close(0);
close(1);
close(2);
strcpy(y->ut_name,"LOGIN");
strcpy(y->ut_line,"tty00");
strcpy(y->ut_id,"0");
y->ut_type=LOGIN_PROCESS;
y->ut_pid=getpid();
pututline(y);
exit(val);
}
main(argc,argv)
int argc;
char *argv[];
{
int rtty,wtty;
struct utmp x;
signal(SIGALRM,werminate);
/* check that we have one argument */
if(argc!=2)
{
fprintf(stderr,"redial: bad number of arguments\n");
exit(1);
}
/* fork redial process and kill parent - this logs out the user
who is running redial */
banner="Redial from uk.co.bt.kyns\n\r\r";
if(fork()!=0)
{
kill(getppid(),9);
werminate(0);
}
/* redial process - look for the terminal line in utmp */
strcpy(x.ut_line,ttyname(1)+5);
utmpname("/etc/utmp");
if((y=getutline(&x))==0)
{
fputs("Terminal not found\n",stderr);
werminate(1);
}
/* open the terminal line to the modem - hardwired as TTY0 */
rtty=open("/dev/tty00",O_RDONLY);
wtty=open("/dev/tty00",O_WRONLY);
/* duplicate onto stdin, stdout and stderr */
dup2(rtty,0);
dup2(wtty,1);
dup2(wtty,2);
/* and then close the originals . We are now connected to
/dev/tty00 rather that the original tty */
close(rtty);
close(wtty);
/* Wait for this process to be inherited by process 1 (since it is
now an orphan. Set an alkarm for 60 to terminate the process if
we are not inherited */
alarm(60);
while(getppid()!=1);
alarm(0);
/* Dial the number using outdial() and then fork a getty on the line. This
process waits for the getty forked process to die (when the
user loggs out) and then clears the call by sending ath to the modem */
outdial(argv[1]);
if(fork()==0) gettyrun();
wait(&curpid);
write(1,"\n\rCall clearing...\n\r",20);
close(1);
sleep(5);
wtty=open("/dev/tty00",O_WRONLY);
sleep(5);
write(wtty,"+++",3);
sleep(5);
write(wtty,"ath\n",4);
close(wtty);
werminate(0);
}
/* gettyrun() runs a getty process on the modem line to allow logins */
gettyrun()
{
/* set head of process group. This connects /dev/tty to what we have redirected
stdin, stdout and stderr to */
setpgrp();
write(1,banner,strlen(banner));
/* set up the utmp entry and exec a getty process - from here on the system
aacts exactly as if a getty had been placed on the line by init */
strcpy(y->ut_name,"LOGIN");
strcpy(y->ut_line,"tty00");
strcpy(y->ut_id,"0");
y->ut_type=LOGIN_PROCESS;
y->ut_pid=getpid();
pututline(y);
execl("/etc/getty","/etc/getty","tty00","co_300x",(char*)0);
}
/* outdial() dials the pone number on a hayes modem */
outdial(numb)
char *numb;
{
char expect;
int i;
/* set up the terminal line to the correct parameters */
cts.c_iflag=BRKINT | ICRNL | IGNCR | IXON;
cts.c_oflag=OPOST | ONLCR | TAB3;
cts.c_cflag=B300 | CS7 | HUPCL | CREAD | CLOCAL | PARENB;
cts.c_lflag=ISIG | ECHOE;
cts.c_line=(char)0;
cts.c_cc[4]=(char)1;
ioctl(1,TCSETA,&cts);
/* send the 'at' string and look for a returned AT (out modem returned all
strings in capitals ) */
write(1,"at",2);
read(0,&expect,1);
if(expect!='A') werminate(1);
read(0,&expect,1);
if(expect!='T') werminate(1);
/* All charcters now sent are checked to make sure they are echoed. The
string setn is atd<number>r . The r reverses the line when the connection
is made so that ORIGINATE can be used at the far end */
write(1,"d",1);
read(0,&expect,1);
if(expect!='d') werminate(1);
i=0;
alarm(60);
while(numb[i]!='\0')
{
write(1,&numb[i],1);
read(0,&expect,1);
if(expect!=numb[i++]) werminate(1);
}
alarm(0);
write(1,"r\n",2);
alarm(100);
/* wait for the connect message and return . If not then there is a timeout */
scanf("CONNECT");
alarm(0);
}
--
-Pete French. |
British Telecom Research Labs. | "The carefree days are distant now,
Martlesham Heath, East Anglia. | I wear my memories like a shroud..."
All my own thoughts (of course) | -SIOUXSIE
More information about the Comp.unix.wizards
mailing list