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