home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
unix
/
volume15
/
ultrix-modem
/
modem.c
< prev
next >
Wrap
C/C++ Source or Header
|
1988-05-24
|
10KB
|
411 lines
/*
* Copyright (c) Dave Settle 1987
* All rights reserved.
* Permission is granted to do anything with this program, except remove
* this copyright notice, or sell it for profit.
*
* Problems, suggestions, bug fixes etc, to:
*
* Dave Settle, SMB Business Software, Thorn EMI Datasolve
*
* UUCP:
* dave@smb.co.uk
* ...!mcvax!ukc!nott-cs!smb!dave
*
* SMAIL: Voice:
* SMB Business Software +44 623 651651
* High Street
* Mansfield Telex:
* Nottingham NG18 1ES 37392 TECSMG
* England
* Fax:
* +44 623 659947
*
* modem.c: a bi-directional "getty" to allow incoming calls AND outgoing
* uucico's
*
* Modified by Rick Richardson for HDB uucp and AT&T Aztec protocol
*
* Modified by Jack Bonn for state logic (allows autoanswer on/off at
* a given time for each day of the week)
*
* Modified by Dave Settle:
*
* Code fixes:
* hangup routine added, to make sure phone is down before script, and
* after user disconnects.
* Parameterised send-expect routines.
* Minor bug fix to dread()
* Re-enable SIGALRM in wakeup()
* Catch all signals, to enable crashes to be detected.
* Chmod device back to 666, so that we can use it afterwards.
* Oct 87: fixup modem control with CLOCAL, so that remote disconnect
* can be detected and dealt with.
* Oct 87: fix autologout to send series of signals, not just SIGHUP
* Oct 87: Clean up code, and distribute to other source files.
* Nov 87: Fix lurking bug in 'expect'. Clean code for 'lint'.
* Nov 87: Ignore SIHGUP's generated by 'hangup'.
* Dec 87: Force getty NOT to hangup the line before login.
* Jan 87: Open stdio file descriptors.
*
*
*/
#include <sys/types.h>
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <termio.h>
#include <sys/stat.h>
#include <time.h>
#ifdef WATCHIT
#include <pwd.h>
struct passwd *getpwuid();
#endif
#define MAINDEF
#include "modem.h" /* variable definitions */
/*
* wakeup gets called when the alarm goes off
*/
wakeup(){
signal(SIGALRM, wakeup);
}
fault(sig){
printf("Crashed with signal %d\n", sig);
closedown(sig);
}
closedown(sig){
time_t now;
now = time((long *) 0);
/*
* [Nov 87]: Since we're about to hang up the phone,
* ignore the signal that this is going to generate.
*/
signal(SIGHUP, SIG_IGN);
if(sig) printf("Caught signal %d\n", sig);
printf("Closedown at %s", asctime(localtime(&now)));
/*
* Oct 87: new addition for SIGHUP. We receive this signal when the line
* is disconnected by a remote caller. Since the line is dead, so should
* the shell be (it got SIGHUP same as us); log it out anyway, even if it's
* trying to ignore it.
*/
if((sig == SIGHUP) && shell) autologout(shell);
/*
* change the value in utmp back to our pid.
*/
if(shell) uchange(shell, getpid()); /* back to normal */
/*
* clear modem line, which should also hangup the phone (if it wasn't already).
*/
hangup(dev);
close(dev);
/*
* chmod the device back to 666, so that uucico and cu can access it.
* NOTE: I prefer this to chown(uucp), which does not allow "cu" access.
*/
chmod(dname,0666); /* uucp access */
unlink(lockf);
if(status) printf("Logout status 0x%x\n", status);
fclose(stdout);
exit(0);
}
main(argc, argv, envp)
char **argv, **envp;
{
long t;
char *arg[5], *speed;
int baud, i;
struct conv *p;
struct stat sbuf;
time_t now, mtime;
#ifdef WATCHIT
FILE *procs;
struct passwd *pw;
char psbuff[128];
#endif
#ifdef SPEEDCONFIG
char c, buff[8];
#endif
#ifdef STATES
time_t delta, suicide;
int state;
#endif
FILE *lock;
/*
* catch and report all signals, but apply special treatment to legal signals
* Any program bugs get reported this way. You can get a core dump by sending
* it SIGFPE.
*/
for(i=1;i<SIGUSR1;i++) signal(i, fault);
signal(SIGHUP, SIG_IGN);
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGFPE, SIG_DFL); /* you can get a core dump here */
signal(SIGALRM, wakeup);
signal(SIGTERM, closedown);
/*
* Open the standard I/O file descriptors, if not already open.
* Running from init, we don't have a terminal, so output to LOGFILE.
*/
if((i = open("/dev/null", 0)) == 0) {
open("/dev/null", 1);
open("/dev/null", 1);
}
else close(i);
freopen(LOGFILE, "a", stdout);
#ifdef SETBUF
setbuf(stdout, NULL); /* if setvbuf broken */
#else
setvbuf(stdout, NULL, _IOLBF, 0);
#endif
if (argc < 2)
{
printf("Usage: %s <tty> [<speed>]\n", argv[0]);
sleep(5);
exit(5);
}
sprintf(dname, "/dev/%s", argv[1]);
#if defined(OL3B2)
sprintf(lockf, "/usr/spool/locks/LCK..%s", argv[1]);
#else
#if defined(HDB)
sprintf(lockf, "/usr/spool/locks/LCK.L.%s", argv[1]);
#else
sprintf(lockf, "/usr/spool/uucp/LCK..%s", argv[1]);
#endif
#endif
/*
* do not start while device is locked
*/
while(locked()) sleep(30);
if((dev = open(dname, O_RDWR | O_NDELAY)) == -1) {
perror(dname);
sleep(5); /* don't go crazy with respawns */
exit(4);
}
/*
* setup correct time zone
*/
putenv(TIMEZONE);
/*
* set terminal parameters
* Additional argument (if present) can be used to force an initial speed
* (Thanks rick)
*/
if(argc > 2) speed = argv[2];
else speed = DEFSPEED;
baud = findspeed(speed);
init_term(dev, baud);
/*
* send-expect strings - at the end, someone has connected to the modem
*/
#ifdef STATES
/*
* find out when the next state change is due to occur. At this point, we exit.
* The next initiation will set the modem up differently.
*/
delta = duration(&state);
suicide = time((long *) 0) + delta;
#endif
for(p = ring; p->c_send; p++) {
#ifdef STATES
if(!applicable(p, state)) continue;
#endif
send(p->c_send, mywrite);
#ifdef STATES
if(expect(p->c_expect, (int)(p->c_wait ? min(p->c_wait, delta) : delta), myread)) {
#else
if(expect(p->c_expect, p->c_wait, myread)) {
#endif
t = time((long *) 0);
#ifdef STATES
if(t >= suicide) {
printf("Exit due to state change\n");
exit(0);
}
#endif
printf("Incoming call failed to connect on %s", asctime(localtime(&t)));
/*
* we don't have to do anything special here, since no locks have been setup.
* However, since the main problems appear to be non-responding modems, send
* it some sort of 'un-wedging' sequence
*/
send(RESET, mywrite);
sleep(3);
hangup(dev);
sleep(10);
ioctl(dev, TCFLSH, 2); /* Flush both queues */
exit(3);
/*NOTREACHED*/
}
}
signal(SIGALRM, wakeup);
/*
* OK - incoming call connected. Find speed (if possible), create lock file,
* then spawn getty.
* At this point, we also trap hangups, so that we can clean up after
* any incoming calls. (Hangups are now detected by the hardware).
*/
signal(SIGHUP, closedown);
#ifdef SPEEDCONFIG
dread(dev, &c, 1);
if(c == '\r') speed = "300";
else {
dread(dev, buff, 4);
if(!strcmp(buff, "1200")) speed = "1200";
if(!strcmp(buff, "2400")) speed = "2400";
if(!strcmp(buff, "1275")) speed = "1200";
if(!strcmp(buff, "7512")) speed = "1200";
}
baud = findspeed(speed);
#endif
t = time((long *)0);
printf("Call connected at %s on %s", speed, asctime(localtime(&t)));
/*
* Someone has rung in - lock the device.
*/
lock = fopen(lockf, "w");
/*
* hand over to "getty"
*/
arg[0] = "getty";
arg[1] = "-h";
arg[2] = argv[1];
arg[3] = speed;
arg[4] = NULL;
if(shell = fork()) {
/*
* change the utmp pid to the "getty" process, so that it can login
*/
uchange(getpid(), shell); /* change utmp entry */
#if defined(OL3B2)
fprintf(lock," %d\n", shell);
#else
#if defined(HDB)
fprintf(lock,"%d\n", shell);
#else
fwrite((char *) &shell, sizeof shell, 1, lock);
#endif
#endif
fclose(lock);
/*
* wait for logout from shell.
* if terminal is idle for IDLETIME, force a logout anyway
*/
alarm(SPYTIME);
while((wait(&status) == -1) && (errno == EINTR)) {
if(stat(dname, &sbuf) == -1) {
perror(dname);
continue;
}
now = time((long *)0);
mtime = max(sbuf.st_atime, sbuf.st_mtime);
if((now - mtime) >= IDLETIME) {
write(dev, "autologout\r\n", 12);
printf("Device idle - autologout at %s\n",
asctime(localtime(&now)));
uchange(shell, getpid());
autologout(shell);
break;
}
#ifdef WATCHIT
t = time((long *) 0);
pw = getpwuid((int) sbuf.st_uid);
printf("Logon user is %s on %s", pw->pw_name,
asctime(localtime(&t)));
procs = popen("ps -ef", "r");
while(fgets(psbuff, sizeof psbuff, procs))
if(partof(psbuff, argv[1]) && partof(psbuff, pw->pw_name))
printf("%s", psbuff);
pclose(procs);
#endif
alarm(SPYTIME);
}
t = time((long *) 0);
printf("Call disconnected on %s", asctime(localtime(&t)));
closedown(0); /* remove locks etc */
/*NOTREACHED*/
}
else {
sleep(1); /* allow changes to utmp */
/*
* Re-do the termio settings, so that we can login.
* CLOCAL is removed at this point, so that a hangup will generate SIGHUP.
* Close all the files which we have open - getty expects none.
*/
login_term(dev, baud);
for(i=0;i<20;i++) close(i);
#ifdef DEBUG
printf("%d: /etc/getty %s %s\n", getpid(), arg[1], arg[2]);
#endif
execve("/etc/getty", arg, envp);
printf("can't exec getty\n");
exit(1);
/* NOTREACHED */
}
}
/*
* check for presence of lock file
* return 1 if locked.
*/
locked(){
struct stat sb;
if(stat(lockf, &sb) == -1) return(0);
#ifdef DEBUG
printf("%s locked\n", lockf);
#endif
return(1);
}
#ifdef WATCHIT
/*
* partof: look for str in text. Has a bug if you look for ...xxx...
*/
partof(text, str)
char *text, *str;
{
char *needle, *p;
for(p = text, needle = str; *p ; p++) {
if(*p != *needle) needle = str;
if(*p == *needle) needle++;
if(*needle == '\0') return(1);
}
return(0);
}
#endif
/*
* autologout: log out the child shell. Sends SIGHUP, SIGTERM, SIGKILL
* until the child exits.
*/
autologout(child)
{
kill(child, SIGHUP);
alarm(GRACETIME);
if(wait(&status) == -1) {
kill(child, SIGTERM);
alarm(GRACETIME);
if(wait(&status) == -1) {
kill(child, SIGKILL);
alarm(GRACETIME);
if(wait(&status) == -1) {
printf("Cannot kill child pid %d\n", child);
status = 0;
}
}
}
alarm(0);
}