settle@cs.nott.ac.uk (Dave Settle SMB) (02/03/87)
A thousand and one appologies ... The original program "modem.c" did not work. This was due to about three separate bugs, two of them trivial and one of them MAJOR. The diagnostic about "no utmp entry" is the major one. This is a message from "login", complaining that it can't find its own process id in the file /etc/utmp. The reason it can't find it, is that the pid is actually the pid of "modem", which is hanging around waiting for it to finish. The fix is to change the pid value to the pid of the spawned shell (and change it back again afterwards). This fix is in "uchange.c". I have also had problems getting "login" to prompt for a password. This turns out to be a result of the non-default stty settings that you have to have to talk to the modem. This has been fixed to work on my machine, but may cause problems on others - check the termio ioctl before the "exec". I've also moved speed configuration to a place before the device is locked - otherwise it gives up thinking the device is locked by someone else! Since the changes have been reasonably extensive (and I've never been a big fan of "diff"), I'm re-posting the whole source (it's not very big). If you want the manpage again, mail me. Sorry about the bugs. Dave Settle, SMB Business Software, Thorn EMI Datasolve UUCP: ...!mcvax!ukc!nott-cs!smb!dave dave@smb.UUCP SMAIL: Voice: SMB Business Software +44 623 651651 High Street Mansfield Nottingham NG18 1ES Telex: England 37392 TECSMG #! /bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #! /bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create: # modem.c # uchange.c # Makefile # This archive created: Mon Feb 2 14:10:07 1987 export PATH; PATH=/bin:/usr/bin:$PATH echo shar: "extracting 'modem.c'" '(8689 characters)' if test -f 'modem.c' then echo shar: "will not over-write existing file 'modem.c'" else cat << \SHAR_EOF > 'modem.c' /* modem.c: a bi-directional "getty" to allow incoming calls AND outgoing * uucico's * * A script is defined to place the modem in a state where it will accept * incoming calls (i.e. auto-answer). If a call arrives, a getty is spawned * and a device lock created, thus preventing outgoing calls. * If uucp tries to use the line, the program notices the lock file, * and abandons the session. "init" then starts another version off, which * suspends itself until the device is not locked. * * For your local site, you have to do the following: * * Put this line in /etc/inittab * XX:2:respawn:/usr/lib/modem ttyXX where ttyXX is your modem line * * Make sure that your dialer script is prepared to: * a) sleep for > 1 sec BEFORE reading the first reply from the modem * b) accept that the first character sent by the modem will NOT get there * * e.g. Hayes dialer script is NORMALLY * * ... AT OK ATDP\T CONNECT * * but MUST be modified to * * ... AT\r\D OK ATDP\T CONNECT #( \D is a 2-sec pause ) * * * Modify the included dialer script to talk to YOUR modem * Modify the speed-detection routine, if your modem is not a hayes-compatible * * Modify "locked()" to read YOUR lock directory * */ #include <sys/types.h> #include <termio.h> #include <stdio.h> #include <signal.h> #include <sys/stat.h> #include <setjmp.h> #define PNUMBER 'T' /* \T is "insert tel no" */ #define WTIME 5 /* default wait time */ #define LOGFILE "/usr/lib/modem.log" /* log file */ #define max(a,b) (a) > (b) ? (a) : (b) #define DEBUG 0 /* if "1", you get told what's * going on */ #define OL3B2 1 /* my machine is a 3B2 */ #define IDLETIME 30*60 /* autologout time */ long time(); char *localtime(); struct conv { char *c_send; char *c_expect; int c_wait; /* time to wait for c_expect */ } ring[] = { {"AT\rAT", "OK", WTIME }, /* anyone there? */ {"ATX1V1", "OK", WTIME }, /* turn on responses */ {"ATS0=1", "OK", WTIME }, /* enable auto answer */ {"ATS9=10", "OK", WTIME}, /* 1 sec carrier before detect */ {"ATS10=14", "OK", WTIME}, /* 400 msec carrier loss is OK */ {"ATS24=3", "OK", WTIME}, /* step speed 3 seconds */ {"\\c", "RING", 0}, /* wait (indefinately) for RING in */ {"\\c", "CONNECT", 20}, /* wait for call to be connected */ {NULL, NULL, 0} /* finished */ }; char lockf[50]; /* argument lock file */ /* * We have 2 /dev files linked together, so it is also necessary to look * for a lock on the modem device */ #ifdef OL3B2 char *altlock = "/usr/spool/locks/LCK..modem"; #else char *altlock = "/usr/spool/uucp/LCK..modem"; #endif wakeup(){} /* gets called when the alarm goes off */ int shell, status; /* pid of shell, and exit status */ closedown(){ time_t t; if(shell) uchange(shell, getpid()); /* back to normal */ unlink(lockf); unlink(altlock); sleep(1); /* leave dev closed for a bit */ t = time((long *)0); if(status) printf("Logout status 0x%x\n", status); printf("Call disconnected on %s", asctime(localtime(&t))); fclose(stdout); exit(0); } main(argc, argv, envp) char **argv, **envp; { int dev; long t; char dname[20], *arg[4], c, buff[10], *speed; struct conv *p; struct termio term; struct stat sbuf; time_t otime, mtime; FILE *lock; /* * make ourselves immune from hangups */ signal(SIGHUP, SIG_IGN); signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); signal(SIGALRM, wakeup); signal(SIGTERM, closedown); /* * running from getty, we don't have a terminal, so output to LOGFILE */ freopen(LOGFILE, "a", stdout); setvbuf(stdout, NULL, _IOLBF, 0); sprintf(dname, "/dev/%s", argv[1]); #ifdef OL3B2 sprintf(lockf, "/usr/spool/locks/LCK..%s", argv[1]); #else sprintf(lockf, "/usr/spool/uucp/LCK..%s", argv[1]); #endif if((dev = open(dname, 2)) == -1) { perror(dname); sleep(5); /* don't go crazy with respawns */ exit(1); } /* * do not start while device is lockeed */ while(locked()) sleep(30); /* * setup correct time zone */ putenv("TZ=GMT0BST"); /* * set terminal parameters */ if(ioctl(dev, TCGETA, &term) == -1) perror("TCGETA"); term.c_lflag = ISIG | ECHOK; term.c_iflag = BRKINT; term.c_oflag &= ~OPOST; term.c_cflag = B1200 | CREAD | HUPCL | CS8; term.c_cc[VMIN] = 1; term.c_cc[VTIME] = 0; if(ioctl(dev, TCSETAW, &term) == -1) perror("TCSETA"); /* * send-expect strings - at the end, someone has connected to the modem */ for(p = ring; p->c_send; p++) { send(p->c_send, dev); if(expect(p->c_expect, p->c_wait, dev)) { t = time((long *) 0); printf("Incoming call failed to connect on %s", asctime(localtime(&t))); fclose(stdout); exit(1); } } /* * having reached here, we have to determine the speed of the connection */ dread(dev, &c, 1); speed = "1200"; /* default speed */ 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"; } 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"); close(creat(altlock, 0666)); /* and the other one */ /* * hand over to "getty" */ arg[0] = "getty"; arg[1] = argv[1]; arg[2] = speed; arg[3] = NULL; signal(SIGALRM, wakeup); /* reset the alarm call */ if(shell = fork()) { /* * change the utmp pid to the "getty" process, so that it can login */ uchange(getpid(), shell); /* change utmp entry */ #ifdef OL3B2 fprintf(lock," %d\n", shell); #else fwrite(&shell, sizeof shell, 1, lock); #endif fclose(lock); sleep(3); close(dev); /* * wait for logout from shell. * if terminal is idle for IDLETIME, force a logout anyway */ mtime = time((long *)0); while((alarm(IDLETIME) != -1) && (wait(&status) == -1)) { stat(dname, &sbuf); otime = mtime; mtime = max(sbuf.st_atime, sbuf.st_mtime); if((mtime - otime) >= IDLETIME) { kill(shell, SIGHUP); wait(&status); break; } } closedown(); /* remove locks etc */ /*NOTREACHED*/ } else { sleep(1); /* allow changes to utmp */ /* * We have to redo the termio settings, 'cos we can't close "dev" without * hanging up the phone. * Strange things have been known to happen during "login" with incorrect * settings - if it forgets to ask you for a password, check the settings below */ term.c_cc[VEOF] = 04; /* cntrl-D */ term.c_iflag = BRKINT | IGNPAR | ISTRIP | ICRNL; term.c_oflag = OPOST | ONLCR | TAB3; term.c_cflag &= ~CSIZE; /* keep the speed */ term.c_cflag |= CS7 | HUPCL | CREAD; term.c_lflag = ISIG | ICANON; ioctl(dev, TCSETAW, &term); #if 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(0); } /* * send: send the string to the modem */ send(s, dev) char *s; { int nocr = 0; #if DEBUG sshow("send("); #endif for(;*s;s++) { if(*s == '\\') switch(*++s) { case 'c': nocr = 1; continue; default: printf("%c: unknown escape char\n"); } dwrite(dev, s, 1); show(*s); } if(nocr == 0) { dwrite(dev, "\r", 1); sshow("\\r)\n"); } else sshow("<no cr>)\n"); sleep(1); } /* * expect: expect a string from the modem * chars are threaded on the needle as they match the expect string * if one fails to match, all chars are unthreaded. * expect succeeds if all chars on expect string are threaded. */ jmp_buf env; timeout(){ longjmp(env, 1); } expect(s, t, dev) char *s; { char *needle = s, c; signal(SIGALRM, timeout); if(setjmp(env)) { printf("modem: timeout expecting %s\n", s); return(1); /* fail - timeout */ } alarm(t); /* if zero, no timeout */ #if DEBUG printf("expect(%s)\n", s); #endif while(*needle) { dread(dev, &c, 1); show(c); if(*needle == c) needle++; else needle = s; } #if DEBUG printf("got it\n"); #endif return(0); } /* * sshow: show string */ sshow(s) char *s; { while(*s) show(*s++); } show(c) char c; { #if DEBUG if((c < 31) && (c != '\n')) printf("^%c", c + '@'); else putchar(c); fflush(stdout); #endif } /* * check for presence of lock file * return 1 if locked. */ locked(){ struct stat sb; if((stat(lockf, &sb) == -1) && (stat(altlock, &sb) == -1)) return(0); #if DEBUG printf("%s locked\n", lockf); #endif return(1); } dwrite(f, s, n) int f, n; char *s; { if(locked()) exit(0); return(write(f, s, n)); } dread(f, s, n) int f, n; char *s; { int i; for(i=0;i<n;i++) { if(locked()) exit(0); while(read(f, s, 1) < 1) if(locked()) exit(0); } } SHAR_EOF if test 8689 -ne "`wc -c < 'modem.c'`" then echo shar: "error transmitting 'modem.c'" '(should have been 8689 characters)' fi fi echo shar: "extracting 'uchange.c'" '(561 characters)' if test -f 'uchange.c' then echo shar: "will not over-write existing file 'uchange.c'" else cat << \SHAR_EOF > 'uchange.c' /* * change the ut_pid value from "old" to "new". * Attempts to do all the things that "getty" appears to do. */ #include <sys/types.h> #include <utmp.h> struct utmp *utmp, *getutent(), *getutid(); uchange(old, new) { setutent(); while(utmp = getutent()) { if(utmp->ut_pid == old) { utmp->ut_pid = new; if(strcmp(utmp->ut_user, "getty")) strcpy(utmp->ut_user, "modem"); else strcpy(utmp->ut_user, "getty"); pututline(utmp); endutent(); return(1); } } printf("modem: can't find utmp entry"); endutent(); return(1); } SHAR_EOF if test 561 -ne "`wc -c < 'uchange.c'`" then echo shar: "error transmitting 'uchange.c'" '(should have been 561 characters)' fi fi echo shar: "extracting 'Makefile'" '(94 characters)' if test -f 'Makefile' then echo shar: "will not over-write existing file 'Makefile'" else cat << \SHAR_EOF > 'Makefile' # # new makefile for modem. # PARTS = modem.o uchange.o modem: ${PARTS} cc ${PARTS} -o modem SHAR_EOF if test 94 -ne "`wc -c < 'Makefile'`" then echo shar: "error transmitting 'Makefile'" '(should have been 94 characters)' fi fi exit 0 # End of shell archive
wendt@arizona.UUCP (02/27/87)
In article <4552@robin.cs.nott.ac.uk>, settle@cs.nott.ac.uk (Dave Settle SMB) writes: > dread(f, s, n) > int f, n; > char *s; > { > int i; > for(i=0;i<n;i++) { > if(locked()) exit(0); > while(read(f, s, 1) < 1) if(locked()) exit(0); > } > } The character pointer, s, needs to be incremented in this loop. Now in order to comply with Federal law and comp.sources.d practice and traditions, here's my contribution to the discussion about port turnaround: "That's the sort of blinkard philistine pig-ignorance I've come to expect from you non-creative garbage. "Sitting all day long on your loathsome spotty behinds picking blackheads, not giving a tinkers cusp for the struggling artist. With your Tony Jacklin golf clubs and your secret Masonic handshakes... Well I wouldn't become a freemason now if you got on your lousy stinkin knees and begged me!" Alan Wendt U of AZ Computer Science