PD uugetty for Interactives 386/ix?
Karl Denninger
karl at ddsw1.MCS.COM
Mon Sep 3 16:05:02 AEST 1990
In article <9009011253.AA13674 at esegue.segue.boston.ma.us> johnl at esegue.segue.boston.ma.us (John R. Levine) writes:
>In article <90243.123640RREED at ucf1vm.cc.ucf.edu> you write:
>>A friend of mine without net access (now, but if you can help, that will
>>change!) asked me to see if I could find a PD uugetty replacement for his
>>386/ix system.
>
>Rather than using uugetty, use either the async driver on the X5 or X6
>update disks, or else the public FAS driver posted here. Both of them
>provide separate /dev entries for dialin and dialout, so you can run a
>modem both ways without uugetty. I have used both, and they both work.
>
>FAS is somewhat faster, X5/X6 supports VP/ix. Both take advantage of
>the extra buffering in a 16550 ASYNC chip.
That does NOT solve one problem:
o You dial out on the non-modem control port. The call completes, then
drops. How do you detect it? The answer? You don't!
The fix? Below is a shar archive. Unpack, read the comments, compile and
go. This will work on ISC 2.2, 2.0.2, and should work on SCO Unix V/386
(but it has NOT been tested there). There is one hack in the code right now:
ISC does not correctly support CLOCAL on modem control lines. If
you open a port with O_NDELAY, then set CLOCAL and clear O_NDELAY
with fcntl, you should get BLOCKING reads with the CD signal
ignored. Instead you get non-blocking reads if CD is low, and
blocking reads if CD is high (idiots!). Thus, there's a timer-read
routine in here; it'll work if and when ISC fixes their driver, and
works ok as is now (but does consume a couple seconds of runtime per
hour when the port is idle).
Unfortunately, Equinox and a few other board makers have mimiced the
broken code instead of fixing it (double idiots!) Thus this hack.
Note: This code is NOT PD; it's Copyrighted. It can be used
non-commercially, but if you want to sell it or enhance the value of
a commercial poduct you have to get a distribution license. Flame
if you must, use the code if it helps you.
This program is still a little messy, but it certainly functions.
We run all our modems at "ddsw1" with this and have no trouble with
it at all.
#! /bin/sh
# This is a shell archive. Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file". To overwrite existing
# files, type "sh file -c". You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g.. If this archive is complete, you
# will see the following message at the end:
# "End of shell archive."
# Contents: autonew.c
# Wrapped by karl at ddsw1 on Mon Sep 3 01:03:03 1990
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'autonew.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'autonew.c'\"
else
echo shar: Extracting \"'autonew.c'\" \(18668 characters\)
sed "s/^X//" >'autonew.c' <<'END_OF_FILE'
X/*
X * Copyright 1990 MCS & Karl Denninger. All rights reserved.
X *
X * Public use is permitted under the following conditions:
X *
X * 1) You do not remove my name from the package, or claim you wrote it.
X * 2) You distribute ORIGINAL source code with all distributions made,
X * modified or not, binary or source.
X * 3) You do not attempt to sell the package, or use it to enhance the
X * commercial value of any product or service.
X * 4) This package is distributed with ABSOLUTELY NO WARRANTY OF ANY
X * KIND. If it melts your system to slag YOU are responsible, not
X * MCS or myself. The burden rests with you to perform adaquate
X * testing before turning this loose on unsuspecting users.
X *
X * Commercial distribution rights reserved; contact MCS at (708) 808-7200
X * for details on commercial distribution licensing.
X *
X * Compile with: cc -s -o autonew autonew.c -lc_s -lx
X *
X */
X/* Autobaud program
X
X Run in place of 'getty', this will prompt for a name
X and call login just like the old one used to do... Only
X difference is that it is rather interesting in it's interpretation
X of what a 'gettydefs' file is; that is, there isn't one.
X
X We use modem return messages to determine the baud rate. Locks are
X respected as well, allowing the uucp system to share the ports.
X
X The issue file is in /etc/issue.new. The first line of this file
X contains the login prompt. The remainder is the banner message.
X
X You invoke this with:
X /etc/autonew ttyA2 [code]
X
X from /etc/inittab. "[code]" is the numeric code for the baud rate
X to send the initialization string at -- most of the time you want
X this to be the highest baud rate your modem will support.
X
X Notes:
X 1) The device name does not have a prefix. It is prepended
X automatically (/dev/ is added).
X 2) For ISC, use the MODEM CONTROL PORTS. This program can
X interlock with UUCP; see their DEVICES file for the
X proper flags to set in the DEVICES and DIALERS files.
X Use the "new" definitions which have ",M" added (see your
X documentation for details).
X 3) While a port is being used for dialout, it will show
X up in a "who" command as "_Dialout".
X 4) Modes will be changed on ports to prevent random users
X from using the ports for "cu"s and other communications
X uses. This can be easily changed if desired (look for
X the "chmod" call in the source).
X 5) The file /etc/autobaud.parm must be present. The format
X is as follows:
X First line -- initialization string for ports
X Second line -- response to initialization string
X Rest of lines -- baud codes, rates (text), and
X response strings expected.
X
X Baud codes are the speed codes from termio.h;
X 11, for example, is 2400 baud.
X
X An example /etc/autobaud.parm file:
X
X AAAAATE0Q0V1
X OK
X 7 300 CONNECT
X 9 1200 CONNECT 1200
X 11 2400 CONNECT 2400
X 14 19200 CONNECT FAST
X
X
X 6) Your I/O board and/or drivers MUST correctly support the
X notion of O_NDELAY. In addition, you have to be able to
X turn on and off the NDELAY flag with fcntl. LOTS of
X intelligent boards broke this; if it's broken this
X program will NOT work. ONE HACK: If your NDELAY
X interpretation returns non-blocking if CD is down (with
X CLOCAL set and NDELAY cleared) this program will function
X correctly, although it will eat a small portion of CPU
X time to do so.
X
X 7) Autobaud will wait for a carriage return and use it
X to determine the parity of the caller's terminal (either
X 8/N/1 or 7/E/1 only). If the user doesn't press anything
X within a reasonable time frame, 8/N/1 is assumed. The
X message "CONNECTED" is output to the user terminal
X immediately after autobaud senses the user's baud rate.
X
X 8) All modems served by this have must use the same response
X sequences, although subsets are permitted (ie: the
X example file above would work for a USR Courier 2400 and
X a Telebit Trailblazer Plus equally well).
X
X CHECK THE FUNCTIONS "checklock()" and "makelock()" -- they may need
X to be modified for your system! In particular, some systems use
X binary PIDs and/or store the lock file in a different place. We
X currently are set up for HDB UUCP on ISC 2.0.2/2.2.
X
X Note that this program can share a port with a modem dialing out on
X the same line! It will perform with uucp on the same port without
X trouble, so long as the locking is done correctly by uucp and other
X programs which expect lock files.
X
X Autobaud removes any stale lock files it finds automatically.
X
X*/
X
X#define MAXSECONDS 60 /* Timeout at start */
X#define LOGSECONDS 90 /* Timeout at login */
X#define UUCICO "/usr/lib/uucp/uucico" /* Where's uucico? */
X#define BELL 7 /* Makes a "beep" */
X
X#include <stdio.h>
X#include <fcntl.h>
X#include <sys/types.h>
X#include <sys/tty.h>
X#include <utmp.h>
X#include <signal.h>
X#include <errno.h>
X#include <termio.h>
X#include <sys/stat.h>
X
X/* Globals */
X
int maschan = -1; /* Nothing initially; master channel */
int timeout = 0; /* Timer value for keeping track of time */
XFILE *ferr; /* Error channel */
X
slowwrite(chan, str, len) /* Write a string slowly to the port */
int chan, len;
char *str;
X{
X int x;
X char *ptr;
X char ch[2];
X
X ptr = str;
X for (x = 0; x < len; x++) {
X ch[0] = *ptr;
X write(chan, ch, 1);
X nap(10);
X ptr++;
X }
X return;
X}
X
checkmatch(matches, mcount, bfr, speed) /* Any matches in array? */
struct {
X char string[40];
X int baud;
X char speed[20];
X} matches[];
int mcount;
char bfr[];
char speed[];
X{
X int x = 0;
X
X for (x = 0; x < mcount; x++) {
X if (!strcmp(bfr, matches[x].string)) {
X strcpy(speed, matches[x].speed);
X return(matches[x].baud);
X }
X }
X return(0);
X}
X
X/* External declarations */
extern struct utmp *getutent(), *pututline();
X
X
X/* Makelock / Checklock - makes / checks for lock files
X line - the line to check for a lock
X lockflag - if non-zero, checklock will sleep until it sees the
X lock is gone, otherwise it returns status
X (checklock only)
X
Returns not zero (-1) if line is locked
X
X*/
X
int makelock(line)
char *line;
X{
X
char tmp[80];
char tmp2[80];
char tbfr[20];
int id;
XFILE *id2;
int pid;
struct stat st;
X
X sprintf(tmp, "/usr/spool/locks/LTMP..%d", getpid());
X sprintf(tmp2, "/usr/spool/locks/LCK..%s", line);
X if ((id = open(tmp, O_WRONLY|O_CREAT, 0660)) < 0) {
X exit(1);
X }
X sprintf(tbfr, "%10d\n", getpid());
X tbfr[11] = 0;
X write(id, tbfr, 11);
X close(id);
X if (!stat(UUCICO, &st)) { /* Find ownership */
X chown(tmp, st.st_uid, st.st_gid); /* Set owner/group */
X }
X while (link(tmp, tmp2)) {
X if ((id2 = fopen(tmp2, "r")) == (FILE *) NULL) {
X sleep(1); /* Slow down.. */
X continue;
X }
X fscanf(id2, "%d", &pid); /* Read PID from file */
X fclose(id2); /* Be nice.. */
X if (!kill(pid, 0)) { /* Oh oh, a process! */
X return(-1);
X }
X unlink(tmp2);
X }
X unlink(tmp);
X return(0);
X}
X
int checklock(line, lockflag)
char *line;
int lockflag; /* If non-zero, wait for open line */
X{
X
char ltmp[10];
char tmp[80];
int pid;
XFILE *id;
X
X strcpy(ltmp, line);
X sprintf(tmp, "/usr/spool/locks/LCK..%s", ltmp); /* Where are locks? */
X while (!access(tmp, 0)) { /* If file is there */
X if ((id = fopen(tmp, "r")) != (FILE *) NULL) { /* opened? */
X fscanf(id, " %d", &pid); /* Get pid from bfr */
X fclose(id); /* Clean up */
X if (kill(pid, 0)) { /* See if process is alive */
X if (errno == ESRCH) { /* Nope; it died */
X unlink(tmp); /* Clear lock */
X continue; /* Look again */
X }
X }
X if (lockflag) { /* IF waiting */
X sleep(1); /* Wait/keep going */
X } else {
X return(-1); /* Else return locked */
X }
X }
X }
X if (ltmp[4] <= 'Z') /* Did idiot use lowercase port name? */
X ltmp[4] = ltmp[4] + 32; /* Oh yeah, check it too... */
X sprintf(tmp, "/usr/spool/locks/LCK..%s", ltmp); /* Where are locks? */
X while (!access(tmp, 0)) { /* If file is there */
X if ((id = fopen(tmp, "r")) != (FILE *) NULL) { /* opened? */
X fscanf(id, " %d", &pid); /* Get pid from bfr */
X fclose(id); /* Clean up */
X if (kill(pid, 0)) { /* See if process is alive */
X if (errno == ESRCH) { /* Nope; it died */
X unlink(tmp); /* Clear lock */
X continue; /* Look again */
X }
X }
X if (lockflag) { /* IF waiting */
X sleep(1); /* Wait/keep going */
X } else {
X return(-1); /* Else return locked */
X }
X }
X }
X return(0); /* Line is clear */
X}
X
settogetty(line) /* Mark process in Getty */
char *line;
X{
X int pid;
X struct utmp *u;
X FILE *fid;
X
X pid = getpid(); /* Get our pid */
X while ((u = getutent()) != NULL) { /* While there are more lines */
X if (((u->ut_type == INIT_PROCESS) || (u->ut_type == USER_PROCESS)) && (u->ut_pid == pid)) {
X strcpy(u->ut_line, line); /* Set line name */
X strcpy(u->ut_user, "_Idle"); /* And name */
X u->ut_pid = getpid(); /* And pid */
X u->ut_type = LOGIN_PROCESS; /* And type */
X pututline(u); /* Do it */
X if ((fid = fopen(WTMP_FILE, "a+")) != NULL) {
X fseek(fid, 0L, 2); /* Seek end */
X fwrite((char *) u, sizeof(*u), 1, fid);
X fclose(fid); /* Wrote wtmp */
X }
X break;
X }
X }
X endutent();
X return;
X}
X
settologin(line) /* Tell the system we're at login state */
char *line;
X{
X int pid;
X struct utmp *u;
X
X pid = getpid(); /* Get our pid */
X while ((u = getutent()) != NULL) { /* While there are more lines */
X if ((u->ut_type == LOGIN_PROCESS) && (u->ut_pid == pid)) {
X strcpy(u->ut_line, line);
X strcpy(u->ut_user, "LOGIN"); /* Change name.. */
X pututline(u);
X }
X }
X endutent();
X return;
X}
X
setlocked(line) /* Fake a utmp entry for dialout lines (flagging) */
char *line;
X{
X int pid;
X struct utmp *u;
X
X pid = getpid(); /* Get our pid */
X while ((u = getutent()) != NULL) { /* While there are more lines */
X if ((u->ut_type == INIT_PROCESS) && (u->ut_pid == pid)) {
X strcpy(u->ut_line, line); /* Set line name */
X strncpy(u->ut_user, "_Dialout", 8); /* "User" */
X/* u->ut_type = LOGIN_PROCESS; *//* If invisible */
X u->ut_type = USER_PROCESS; /* It's visible */
X pututline(u);
X }
X }
X endutent();
X return;
X}
X
X/* Catch alarm signals
X Does two things -- catches the alarms, and also adds one to the
X seconds counter. If the user takes too long call 'hangup()' before
X returning */
X
catch()
X{
X signal(SIGALRM, catch); /* Re-enable signal catcher */
X if (timeout++ >= MAXSECONDS)
X hangup(); /* Kill the user if he just sat */
X return; /* Do nothing else, just exit */
X}
X
X/* Make upper case into lower case */
X
tlc(ptr)
char *ptr;
X{
X char *pt;
X int qm = 0;
X
X pt = ptr;
X while (*pt != 0) {
X if ((*pt >= 'A') && (*pt <= 'Z')) {
X *pt = *pt + 32;
X qm++;
X }
X pt++;
X }
X if (qm)
X printf("%c\nWarning: Please use *lower* case on this system%c\n", BELL, BELL);
X return;
X}
X
X
hangup() /* Make sure the phone gets hung up when we exit */
X{
X struct termio tt_array;
X
X if (maschan < 0)
X exit(1); /* Just exit */
X if (ioctl(maschan, TCGETA, &tt_array)) { /* No delay */
X perror("Get parameter error");
X exit(1);
X }
X tt_array.c_cflag &= ~(CBAUD|CLOCAL); /* Set baud to 0 */
X tt_array.c_cflag |= HUPCL|CREAD|CS8; /* Set hangup */
X
X if (ioctl(maschan, TCSETA, &tt_array)) { /* No delay */
X perror("Hang up error");
X exit(1);
X }
X exit(0);
X}
X
X/* Here is where all the fun begins; the main program */
X
main(argc, argv)
int argc;
char *argv[];
X{
X int debug = 0;
X int x, ch, sw, status;
X struct termio tt_array;
X FILE *fid, *fid2;
X static char tmp[80], loginp[80];
X extern struct utmp *getutent(), *pututline();
X char baud[132];
X int fbaud = 0;
X int sbaud = 0;
X char line[80];
X struct stat st;
X char init[80];
X char iresp[80];
X int initbaud;
X char speed[20];
X struct {
X char string[40];
X int baud;
X char speed[20];
X } matches[20];
X int mcount = 0;
X int bcount = 0;
X char bc[2];
X char bfr[20];
X int satisfied = 0;
X int hoseline;
X int quit = 0;
X
X signal(SIGALRM, catch); /* Catch alarms */
X signal(SIGINT, SIG_IGN); /* Ignore interrupts */
X if (argc > 3)
X debug++;
X initbaud = atoi(argv[2]); /* Initial baud rate */
X strcpy(init, "ATZ\r"); /* Send this to init */
X fid = fopen("/etc/autobaud.parm", "r"); /* Try to open it */
X if (fid != (FILE *) NULL) {
X fgets(init, 80, fid); /* Init string */
X fscanf(fid, " %s", iresp);
X while (fgets(tmp, 80, fid) != (char *) NULL) {
X sscanf(tmp, "%d %[!-z] %[!-z ]", &matches[mcount].baud, matches[mcount].speed, matches[mcount].string);
X mcount++;
X }
X fclose(fid);
X init[strlen(init) - 1] = '\r'; /* Make last a return */
X }
X strcpy(line, argv[1]); /* Look on this line */
X setlocked(argv[1]); /* Set port id to locked */
X sprintf(tmp, "/dev/%s", line); /* Check the line */
X if (!stat(UUCICO, &st)) { /* Who owns uucp? */
X chown(tmp, st.st_uid, st.st_gid);/* Set line owner & group */
X chmod(tmp, 0660);
X }
X checklock(line, 1); /* Wait for no locks */
X settogetty(argv[1]); /* Mark us as in 'getty' */
X#ifndef DEBUG
X close(0); /* Close stdin,stdout,stderr */
X close(1);
X close(2);
X (void) setpgrp(); /* Make sure we have our own
X control terminal */
X#endif
X sprintf(tmp, "/dev/%s", argv[1]);
X if ((x = open(tmp, O_RDWR|O_NDELAY)) < 0) {/* BECOMES CONTROL TERM */
X exit(1); /* Exit; error! */
X } /* End of line.. */
X maschan = x; /* Master I/O channel */
X tt_array.c_cflag = (HUPCL|CLOCAL|CS8|CREAD);
X tt_array.c_cc[VMIN] = 1;
X tt_array.c_cc[VTIME] = 1; /* Set parameters */
X if (ioctl(maschan, TCSETAW, &tt_array) == -1) {/* Set DTR down */
X exit(1);
X }
X sleep(1);
X tt_array.c_cflag |= initbaud; /* Set initial baud rate */
X checklock(line, 0); /* Exit if locked */
X if (ioctl(maschan, TCSETAW, &tt_array) == -1) {/* Set parameters */
X exit(1);
X }
X sleep(1);
X if ((status = fcntl(x, F_GETFL, 0)) != -1) {
X status &= (~O_NDELAY);
X if (fcntl(x, F_SETFL, status)) { /* Clear O_NDELAY */
X exit(0);
X }
X }
X status = fcntl(maschan, F_GETFL, 0); /* Read it again to be sure */
X sleep(1); /* Allow modem to settle */
X checklock(line, 0); /* Exit if locked */
X timeout = 0; /* No timeout yet */
X slowwrite(maschan, init, strlen(init));/* Write initialization */
X if (debug)
X fprintf(ferr, "%x\n", status);
X signal(SIGALRM, hangup); /* Quit on timeout */
X bcount = 0;
X alarm(5); /* Wait 5 seconds tops */
X while (!quit) { /* Check return from init */
X if (!read(maschan, bc, 1)) { /* Look for a character */
X sleep(1);
X continue;
X }
X if (debug)
X fprintf(ferr, " %d\n", bc[0]);
X if ((bc[0] == 10) || (bc[0] == 13)) {
X if (strcmp(bfr, iresp)) {/* If not correct response */
X bcount = 0; /* Then drop it */
X continue; /* Keep looking */
X } else {
X quit++; /* Else done */
X }
X } else {
X bfr[bcount++] = bc[0]; /* Save character */
X bfr[bcount] = 0; /* Null terminate */
X }
X }
X dup(maschan);
X dup(maschan);
X ferr = fopen("/dev/console", "w"); /* Write to console for errs */
X alarm(0); /* Turn off timeout */
X strcpy(line, argv[1]); /* Look on this line */
X if (checklock(line, 0)) /* Check lock status again */
X exit(0); /* Exit if line is locked */
X satisfied = 0;
X bcount = 0; /* Nothing in buffer */
X while (!satisfied) { /* Read result codes */
X if (!read(maschan, bc, 1)) { /* Look for a character */
X sleep(2);
X continue;
X }
X if (checklock(line, 0)) /* Locked by someone else? */
X exit(0); /* Quit if so */
X if ((bc[0] == 10) || (bc[0] == 13)) { /* New line? */
X satisfied = checkmatch(matches, mcount, bfr, speed);
X if (!satisfied) {
X bcount = 0;
X }
X } else {
X bfr[bcount++] = bc[0]; /* Store character */
X bfr[bcount] = 0; /* Null terminate */
X }
X }
X if (makelock(line)) { /* This is VERY bad! */
X exit(0); /* Quit right now! */
X }
X sprintf(baud, "%s @ %s bps", line, speed);
X fid2 = fdopen(maschan, "a+"); /* Give us a stream channel please */
X ioctl(maschan, TCFLSH, 2); /* Flush input & output */
X sleep(1); /* Wait a second for settling... */
X fprintf(fid2, "CONNECTED\r\n");
X fflush(fid2);
X signal(SIGALRM, catch);
X timeout = 0;
X alarm(10);
X if (read(maschan, bc, 1) > 0) {
X switch(bc[0]) {
X case 13:
X case 10:
X strcat(baud, ", 8/N/1");
X goto aexit; /* Do nothing */
X break;
X case -115: /* If signed... */
X case 141: /* 7/E/1, but otherwise ok */
X tt_array.c_cflag &= (~CS8);
X tt_array.c_cflag |= (CS7|PARENB);
X ioctl(maschan, TCSETAW, &tt_array);
X ioctl((maschan + 1), TCSETAW, &tt_array);
X ioctl((maschan + 2), TCSETAW, &tt_array);
X strcat(baud, ", 7/E/1");
X goto aexit;
X break;
X }
X }
aexit:;
X tt_array.c_cflag &= (~(CBAUD|CLOCAL));
X tt_array.c_cflag |= (satisfied|HUPCL); /* New baud rate */
X tt_array.c_oflag |= OPOST|ONLCR;
X
X/* If available, enable CTS flow control. This is necessary for
X Telebit Trailblazers and others of the general type. Unfortunately,
X only SCO has these things... (grr)
X*/
X
X#ifdef HARDWARE_FLOW
X tt_array.c_iflag |= BRKINT|IGNPAR|INPCK|ICRNL;
X tt_array.c_cflag |= HUPCL|CTSFLOW|RTSFLOW;
X#else
X tt_array.c_iflag |= BRKINT|IGNPAR|INPCK|ICRNL|IXON|IXANY;
X tt_array.c_cflag |= HUPCL;
X#endif
X tt_array.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHOK;
X tt_array.c_cc[VINTR] = 177;
X tt_array.c_cc[VQUIT] = 0;
X tt_array.c_cc[VERASE] = 8;
X tt_array.c_cc[VKILL] = 21;
X tt_array.c_cc[VEOF] = 4;
X tt_array.c_cc[VEOL] = 0;
X ioctl(maschan, TCSETAW, &tt_array); /* Set parameters */
X ioctl((maschan + 1), TCSETAW, &tt_array);
X ioctl((maschan + 2), TCSETAW, &tt_array);
X signal(SIGALRM, hangup); /* If we time out, hang up the line */
X alarm(LOGSECONDS); /* LOGSECONDS to read/reply, then out */
X fprintf(fid2, "\n[%s]\n", baud);/* Display parameters we found */
X if ((fid = fopen("/etc/issue.new", "r")) != NULL) {
X fgets(loginp, 80, fid); /* Get login prompt */
X loginp[strlen(loginp)-1] = 0;
X while (fgets(tmp, 80, fid) != NULL) { /* Display issue file */
X fputs(tmp, fid2);
X }
X fclose(fid);
X }
X fputs("\r\n", fid2); /* End with another <return> */
bg1:;
X fputs(loginp, fid2); /* Prompt for login name */
X fgets(tmp, 80, fid2); /* Read it, but don't allow overrun */
X if (*tmp == 10) /* If nothing, ask again */
X goto bg1;
X tmp[strlen(tmp)-1] = 0; /* Make sure null terminated */
X tlc(tmp); /* Lower case the name */
X signal(SIGINT, SIG_DFL); /* Reset signal handling */
X signal(SIGALRM, SIG_DFL);
X alarm(0); /* Clear alarm */
X fclose(ferr); /* Close error channel */
X/*
X * Take two shots at where login is. If we can't find it in either of these
X * places you're screwed; dump the caller. Try to tell the user if this
X * happens, but no guarantees....
X */
X
X execlp("/etc/login", "login", tmp, (char *) NULL);
X execlp("/bin/login", "login", tmp, (char *) NULL);
X fputs("Login not executable; contact administrator\n", fid2);
X fflush(fid2); /* Make sure it's printed */
X sleep(3); /* Wait for output to drain */
X exit(1); /* And quit with error (ignored) */
X}
X
END_OF_FILE
if test 18668 -ne `wc -c <'autonew.c'`; then
echo shar: \"'autonew.c'\" unpacked with wrong size!
fi
# end of 'autonew.c'
fi
echo shar: End of shell archive.
exit 0
More information about the Comp.unix.sysv386
mailing list