home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1992 March / Source_Code_CD-ROM_Walnut_Creek_March_1992.iso / usenet / altsrcs / 2 / 2592 / autouu.c
Encoding:
C/C++ Source or Header  |  1991-01-22  |  19.4 KB  |  677 lines

  1. /*
  2.  *    Copyright 1990 MCS & Karl Denninger.  All rights reserved.
  3.  *
  4.  *    Public use is permitted under the following conditions:
  5.  *
  6.  *    1) You do not remove my name from the package, or claim you wrote it.
  7.  *    2) You distribute ORIGINAL source code with all distributions made,
  8.  *       modified or not, binary or source.
  9.  *    3) You do not attempt to sell the package, or use it to enhance the
  10.  *       commercial value of any product or service.  
  11.  *    4) This package is distributed with ABSOLUTELY NO WARRANTY OF ANY
  12.  *       KIND.  If it melts your system to slag YOU are responsible, not
  13.  *       MCS or myself.  The burden rests with you to perform adaquate
  14.  *       testing before turning this loose on unsuspecting users.
  15.  *
  16.  *    Commercial distribution rights reserved; contact MCS at (708) 808-7200
  17.  *    for details on commercial distribution licensing.
  18.  *
  19.  *    Compile with:  cc -s -o autouu autouu.c -lc_s -lx
  20.  *
  21.  */
  22. /*    Autobaud program 
  23.  
  24.     Run in place of 'getty', this will prompt for a name
  25.     and call login just like the old one used to do... Only
  26.     difference is that it is rather interesting in it's interpretation
  27.     of what a 'gettydefs' file is; that is, there isn't one.
  28.     
  29.     We use modem return messages to determine the baud rate.  Locks are
  30.     respected as well, allowing the uucp system to share the ports.
  31.  
  32.     You invoke this with:
  33.         /etc/autonew ttyA2 [code] [file]
  34.     
  35.     from /etc/inittab.  "[code]" is the numeric code for the baud rate
  36.     to send the initialization string at -- most of the time  you want
  37.     this to be the highest baud rate your modem will support.
  38.  
  39.     Notes:
  40.         1) The device name does not have a prefix.  It is prepended
  41.            automatically (/dev/ is added).
  42.         2) For ISC, use the MODEM CONTROL PORTS.  This program can
  43.            interlock with UUCP; see their DEVICES file for the
  44.            proper flags to set in the DEVICES and DIALERS files.
  45.            Use the "new" definitions which have ",M" added (see your
  46.            documentation for details).
  47.         3) While a port is being used for dialout, it will show
  48.            up in a "who" command as "_Dialout" once data
  49.            transmission begins.
  50.         4) Modes and owners will be changed on ports to prevent 
  51.            random users from using the ports for "cu"s and other 
  52.            communications uses.  This can be easily changed if 
  53.            desired (look for the "chmod" call in the source).
  54.         5) The file /etc/autobaud.parm must be present if the "file"
  55.            argument is missing.  If the "file" argument is present,
  56.            it points to the control file to be used.  The format
  57.            is as follows:
  58.             First line -- initialization string for ports
  59.             Second line -- response to initialization string
  60.             Third line -- Generic "connected" message
  61.             Up to first "#" alone -- baud codes, rates (text), and
  62.                      response strings expected.
  63.             Next line -- Login prompt
  64.             Remainder of file -- Issue file
  65.  
  66.             Baud codes are the speed codes from termio.h; 
  67.             11, for example, is 2400 baud.
  68.  
  69.             An example /etc/autobaud.parm file:
  70.                 
  71.             AAATE0Q0V1
  72.             OK
  73.             CONNECTED
  74.             7 300 CONNECT
  75.             9 1200 CONNECT 1200
  76.             11 2400 CONNECT 2400
  77.             13 9600 CONNECT 9600
  78.             14 19200 CONNECT FAST
  79.             #
  80.             Login:
  81.  
  82.             Welcome to the system
  83.             <EOF>
  84.         
  85.             This is a typical file for a system containing both
  86.             Telebit and low-speed modems (300-2400 baud).  Note
  87.             that the "AAA" is doubled to allow the Telebit to
  88.             autosync.  If you have hardware flow control then
  89.             enable it -- otherwise, set the modem up for
  90.             Xon/Xoff flow control, BREAK is sent and flushes,
  91.             Telebit S66=0 and S58=254 (Autobaud and prefer 
  92.             19200).  This permits full functionality with the 
  93.             exception of low-speed UUCP inbound calls through 
  94.             Telebits; if you have hardware flow control then no
  95.             restrictions apply.
  96.             
  97.         6) Your I/O board and/or drivers MUST correctly support the
  98.            notion of O_NDELAY.  In addition, you have to be able to
  99.            turn on and off the NDELAY flag with fcntl.  LOTS of
  100.            intelligent boards broke this; if it's broken this
  101.            program will NOT work.  ONE HACK:  If your NDELAY
  102.            interpretation returns non-blocking if CD is down (with
  103.            CLOCAL set and NDELAY cleared) this program will function
  104.            correctly, although it will eat a small portion of CPU
  105.            time to do so.
  106.         
  107.         7) Autobaud will wait for a carriage return and use it 
  108.            to determine the parity of the caller's terminal (either
  109.            8/N/1 or 7/E/1 only).  If the user doesn't press anything
  110.            within a reasonable time frame, 8/N/1 is assumed.  The
  111.            message "CONNECTED" is output to the user terminal
  112.            immediately after autobaud senses the user's baud rate.
  113.  
  114.         8) All modems served by a configuration must use the same 
  115.             response sequences, although subsets are permitted (ie: the
  116.            example file above would work for a USR Courier 2400 and
  117.            a Telebit Trailblazer Plus equally well).
  118.  
  119.     CHECK THE FUNCTIONS "checklock()" and "makelock()" -- they may need 
  120.     to be modified for your system!  In particular, some systems use 
  121.     binary PIDs and/or store the lock file in a different place.  We 
  122.     currently are set up for HDB UUCP on ISC 2.0.2/2.2.
  123.  
  124.     Note that this program can share a port with a modem dialing out on
  125.     the same line!  It will perform with uucp on the same port without
  126.     trouble, so long as the locking is done correctly by uucp and other
  127.     programs which expect lock files.
  128.  
  129.     Autobaud removes any stale lock files it finds automatically.
  130.  
  131. */
  132.  
  133. #define        MAXISSUE    100        /* Lines in /etc/issue file */
  134. #define        MAXSECONDS    60            /* Timeout at start */
  135. #define        LOGSECONDS    90            /* Timeout at login */
  136. #define        UUCICO        "/usr/lib/uucp/uucico"    /* Where's uucico? */
  137. #define        BELL        7            /* Makes a "beep" */
  138.  
  139. extern    char    *malloc();
  140.  
  141. #include    <stdio.h>
  142. #include    <fcntl.h>
  143. #include    <sys/types.h>
  144. #include    <sys/tty.h>
  145. #include    <utmp.h>
  146. #include    <signal.h>
  147. #include    <errno.h>
  148. #include    <termio.h>
  149. #include    <sys/stat.h>
  150.  
  151. /*    Globals        */
  152.  
  153. int    maschan = -1;        /* Nothing initially; master channel */
  154. int    timeout = 0;        /* Timer value for keeping track of time */
  155. FILE    *ferr;            /* Error channel */
  156.  
  157. slowwrite(chan, str, len)    /* Write a string slowly to the port */
  158. int    chan, len;
  159. char    *str;
  160. {    
  161.     int     x;
  162.     char    *ptr;
  163.     char    ch[2];
  164.  
  165.     ptr = str;
  166.     for (x = 0; x < len; x++) {
  167.         ch[0] = *ptr;
  168.         write(chan, ch, 1);
  169.         nap(10);
  170.         ptr++;
  171.     }
  172.     return;
  173. }
  174.  
  175. checkmatch(matches, mcount, bfr, speed)        /* Any matches in array? */
  176. struct    {
  177.     char    string[40];
  178.     int    baud;
  179.     char    speed[20];
  180. } matches[];
  181. int    mcount;
  182. char    bfr[];
  183. char    speed[];
  184. {
  185.     int    x = 0;
  186.  
  187.     for (x = 0; x < mcount; x++) {
  188.         if (!strcmp(bfr, matches[x].string)) {
  189.             strcpy(speed, matches[x].speed);
  190.             return(matches[x].baud);
  191.         }
  192.     }
  193.     return(0);
  194. }
  195.  
  196. /*     External declarations    */
  197. extern    struct    utmp    *getutent(), *pututline();
  198.  
  199.  
  200. /*    Makelock / Checklock - makes / checks for lock files
  201.     line        - the line to check for a lock
  202.     lockflag    - if non-zero, checklock will sleep until it sees the
  203.               lock is gone, otherwise it returns status
  204.               (checklock only)
  205.  
  206. Returns not zero (-1) if line is locked
  207.  
  208. */
  209.  
  210. int    makelock(line)
  211. char    *line;
  212. {
  213.  
  214. char    tmp[80];
  215. char    tmp2[80];
  216. char    tbfr[20];
  217. int    id;
  218. FILE    *id2;
  219. int    pid;
  220. struct    stat    st;
  221.  
  222.     sprintf(tmp, "/usr/spool/locks/LTMP..%d", getpid());
  223.     sprintf(tmp2, "/usr/spool/locks/LCK..%s", line);
  224.     if ((id = open(tmp, O_WRONLY|O_CREAT, 0660)) < 0) {
  225.         exit(1);
  226.     }
  227.     sprintf(tbfr, "%10d\n", getpid());
  228.     tbfr[11] = 0;
  229.     write(id, tbfr, 11);
  230.     close(id);
  231.     if (!stat(UUCICO, &st)) {            /* Find ownership */
  232.         chown(tmp, st.st_uid, st.st_gid);    /* Set owner/group */
  233.     }
  234.     while (link(tmp, tmp2)) {
  235.         if ((id2 = fopen(tmp2, "r")) == (FILE *) NULL) {
  236.             sleep(1);            /* Slow down.. */
  237.             continue;
  238.         }
  239.         fscanf(id2, "%d", &pid);        /* Read PID from file */
  240.         fclose(id2);                /* Be nice.. */
  241.         if (!kill(pid, 0)) {            /* Oh oh, a process! */
  242.             return(-1);
  243.         }
  244.         unlink(tmp2);
  245.     }
  246.     unlink(tmp);
  247.     return(0);
  248. }
  249.  
  250. int    checklock(line, lockflag)
  251. char    *line;
  252. int    lockflag;        /* If non-zero, wait for open line */
  253. {
  254.  
  255. char    ltmp[10];
  256. char    tmp[80];
  257. int    pid;
  258. FILE    *id;
  259.     
  260.     strcpy(ltmp, line);
  261.     sprintf(tmp, "/usr/spool/locks/LCK..%s", ltmp);    /* Where are locks? */
  262.     while (!access(tmp, 0)) {            /* If file is there */
  263.         if ((id = fopen(tmp, "r")) != (FILE *) NULL) {    /* opened? */
  264.             fscanf(id, " %d", &pid);    /* Get pid from bfr */
  265.             fclose(id);            /* Clean up */
  266.             if (kill(pid, 0)) {    /* See if process is alive */
  267.                 if (errno == ESRCH) {    /* Nope; it died */
  268.                     unlink(tmp);    /* Clear lock */
  269.                     continue;    /* Look again */
  270.                 }
  271.             }
  272.             if (lockflag) {            /* IF waiting */
  273.                 sleep(1);        /* Wait/keep going */
  274.             } else {
  275.                 return(-1);        /* Else return locked */
  276.             }
  277.         }
  278.     }
  279.     return(0);                    /* Line is clear */
  280. }
  281.  
  282. settogetty(line)            /* Mark process in Getty */
  283. char    *line;
  284. {
  285.     int    pid;
  286.     struct    utmp    *u;
  287.     FILE    *fid;
  288.  
  289.     pid = getpid();        /* Get our pid */
  290.     while ((u = getutent()) != NULL) {    /* While there are more lines */
  291.         if (((u->ut_type == INIT_PROCESS) || (u->ut_type == USER_PROCESS)) && (u->ut_pid == pid)) {
  292.             strcpy(u->ut_line, line);    /* Set line name */
  293.             strcpy(u->ut_user, "_Idle");    /* And name */
  294.             u->ut_pid = getpid();        /* And pid */
  295.             u->ut_type = LOGIN_PROCESS;    /* And type */
  296.             pututline(u);            /* Do it */
  297.             if ((fid = fopen(WTMP_FILE, "a+")) != NULL) {
  298.                 fseek(fid, 0L, 2);    /* Seek end */
  299.                 fwrite((char *) u, sizeof(*u), 1, fid);
  300.                 fclose(fid);        /* Wrote wtmp */
  301.             }
  302.             break;
  303.         }
  304.     }
  305.     endutent();
  306.     return;
  307. }
  308.  
  309. settologin(line)        /* Tell the system we're at login state */
  310. char    *line;
  311. {
  312.     int    pid;
  313.     struct    utmp    *u;
  314.  
  315.     pid = getpid();        /* Get our pid */
  316.     while ((u = getutent()) != NULL) {    /* While there are more lines */
  317.         if ((u->ut_type == LOGIN_PROCESS) && (u->ut_pid == pid)) {
  318.             strcpy(u->ut_line, line);
  319.             strcpy(u->ut_user, "LOGIN");    /* Change name.. */
  320.             pututline(u);
  321.         }
  322.     }
  323.     endutent();
  324.     return;
  325. }
  326.  
  327. setlocked(line)        /* Fake a utmp entry for dialout lines (flagging) */
  328. char    *line;
  329. {
  330.     int    pid;
  331.     struct    utmp    *u;
  332.  
  333.     pid = getpid();        /* Get our pid */
  334.     while ((u = getutent()) != NULL) {    /* While there are more lines */
  335.         if ((u->ut_type == INIT_PROCESS) && (u->ut_pid == pid)) {
  336.             strcpy(u->ut_line, line);    /* Set line name */
  337.             strncpy(u->ut_user, "_Dialout", 8);    /* "User" */
  338. /*            u->ut_type = LOGIN_PROCESS;    *//* If invisible */
  339.             u->ut_type = USER_PROCESS;    /* It's visible */
  340.             pututline(u);
  341.         }
  342.     }
  343.     endutent();
  344.     return;
  345. }
  346.  
  347. /*    Catch alarm signals    
  348.     Does two things -- catches the alarms, and also adds one to the
  349.     seconds counter.  If the user takes too long call 'hangup()' before
  350.     returning        */
  351.  
  352. catch()
  353. {
  354.     signal(SIGALRM, catch);        /* Re-enable signal catcher */
  355.     if (timeout++ >= MAXSECONDS)
  356.         hangup();        /* Kill the user if he just sat */
  357.     return;                /* Do nothing else, just exit */
  358. }
  359.  
  360. /*    Make upper case into lower case    */
  361.  
  362. tlc(ptr)
  363. char    *ptr;
  364. {
  365.     char    *pt;
  366.     int     qm = 0;
  367.  
  368.     pt = ptr;
  369.     while (*pt != 0) {
  370.         if ((*pt >= 'A') && (*pt <= 'Z')) {
  371.             *pt = *pt + 32;
  372.             qm++;
  373.         }
  374.         pt++;
  375.     }
  376.     if (qm) 
  377.         printf("%c\nWarning: Please use *lower* case on this system%c\n", BELL, BELL);
  378.     return;
  379. }
  380.  
  381.  
  382. hangup()     /*    Make sure the phone gets hung up when we exit    */
  383. {
  384.     struct    termio    tt_array;
  385.     
  386.     if (maschan < 0)
  387.         exit(1);                /* Just exit */
  388.     if (ioctl(maschan, TCGETA, &tt_array)) {    /* No delay */
  389.         perror("Get parameter error");
  390.         exit(1);
  391.     }
  392.     tt_array.c_cflag &= ~(CBAUD|CLOCAL);        /* Set baud to 0 */
  393.     tt_array.c_cflag |= HUPCL|CREAD|CS8;        /* Set hangup */
  394.  
  395.     if (ioctl(maschan, TCSETA, &tt_array)) {    /* No delay */
  396.         perror("Hang up error");
  397.         exit(1);
  398.     }
  399.     exit(0);
  400. }
  401.  
  402. /*    Here is where all the fun begins; the main program     */
  403.  
  404. main(argc, argv)
  405. int    argc;
  406. char    *argv[];
  407. {
  408.     int    debug = 0;
  409.     int    x, ch, sw, status;
  410.     struct    termio    tt_array;
  411.     FILE    *fid, *fid2;
  412.     static    char    tmp[133], loginp[132];
  413.     extern    struct utmp *getutent(), *pututline();
  414.     char    baud[132];
  415.     char    connected[512];
  416.     int    fbaud = 0;
  417.     int    sbaud = 0;
  418.     char    line[80];
  419.     struct    stat    st;
  420.     char    init[80];
  421.     char    iresp[80];
  422.     int    initbaud;
  423.     char    speed[20];
  424.     struct    {
  425.         char    string[40];
  426.         int    baud;
  427.         char    speed[20];
  428.     } matches[20];
  429.     char    *istring[MAXISSUE];
  430.     int    mcount = 0;
  431.     int    bcount = 0;
  432.     int    icount = 0;
  433.     int    lcount = 0;
  434.     char    bc[2];
  435.     char    bfr[20];
  436.     int    satisfied = 0;
  437.     int    hoseline;
  438.     int    quit = 0;
  439.     int    stop = 0;
  440.  
  441.     signal(SIGALRM, catch);            /* Catch alarms */
  442.     signal(SIGINT, SIG_IGN);        /* Ignore interrupts */
  443.     if (argc > 4)
  444.         debug++;
  445.     initbaud = atoi(argv[2]);        /* Initial baud rate */
  446.     strcpy(init, "ATZ\r");            /* Send this to init */
  447.     if (argc > 3) 
  448.         fid = fopen(argv[3], "r");    /* Try to open it */
  449.     else
  450.         fid = fopen("/etc/autobaud.parm", "r");    /* Try to open it */
  451.     if (fid != (FILE *) NULL) {
  452.         fgets(init, 80, fid);        /* Init string */
  453.         init[strlen(init) - 1] = '\r';    /* Make last a return */
  454.         fgets(tmp, 80, fid);
  455.         sscanf(tmp, " %s", iresp);
  456.         fgets(connected, 511, fid);    /* Connected string */
  457.         stop = 0;
  458.         while ((!stop) && (fgets(tmp, 80, fid) != (char *) NULL)) {
  459.             if ((tmp[0] == '#') && (strlen(tmp) <= 2)) {
  460.                 stop++;
  461.                 continue;
  462.             }
  463.             sscanf(tmp, "%d %[!-z] %[!-z ]", &matches[mcount].baud, matches[mcount].speed, matches[mcount].string);
  464.             mcount++;
  465.         }
  466.         lcount = MAXISSUE;
  467.         icount = 0;
  468.         fgets(loginp, 80, fid);            /* Get login prompt */
  469.         if (strlen(loginp))
  470.             loginp[strlen(loginp) - 1] = 0;    /* Chop off L/F */
  471.         while ((lcount) && (fgets(tmp, 132, fid) != (char *) NULL)) {    /* Get line */
  472.             istring[icount] = malloc(strlen(tmp) + 2);
  473.             strcpy(istring[icount++], tmp);
  474.             lcount--;
  475.         }
  476.         fclose(fid);
  477.     }
  478.     strcpy(line, argv[1]);            /* Look on this line */
  479.     setlocked(argv[1]);            /* Set port id to locked */
  480.     sprintf(tmp, "/dev/%s", line);        /* Check the line */
  481.     if (!stat(UUCICO, &st)) {        /* Who owns uucp? */
  482.         chown(tmp, st.st_uid, st.st_gid);/* Set line owner & group */
  483.         chmod(tmp, 0660);
  484.     }
  485.     checklock(line, 1);            /* Wait for no locks */
  486.     settogetty(argv[1]);            /* Mark us as in 'getty' */
  487. #ifndef    DEBUG
  488.     close(0);                /* Close stdin,stdout,stderr */
  489.     close(1);
  490.     close(2);
  491.     (void) setpgrp();            /* Make sure we have our own
  492.                               control terminal */
  493. #endif
  494.     sprintf(tmp, "/dev/%s", argv[1]);
  495.     if ((x = open(tmp, O_RDWR|O_NDELAY)) < 0) {/* BECOMES CONTROL TERM */
  496.         exit(1);            /* Exit; error! */
  497.     }                    /* End of line.. */
  498.     maschan = x;                /* Master I/O channel */
  499.     tt_array.c_cflag = (HUPCL|CLOCAL|CS8|CREAD);
  500.     tt_array.c_cc[VMIN] = 1;
  501.     tt_array.c_cc[VTIME] = 1;        /* Set parameters */
  502.     ioctl(maschan, TCFLSH, 2);        /* Flush channel */
  503.     if (ioctl(maschan, TCSETAW, &tt_array) == -1) {/* Set DTR down */
  504.         exit(1);
  505.     }
  506.     sleep(1);
  507.     tt_array.c_cflag |= initbaud;        /* Set initial baud rate */
  508.     checklock(line, 0);            /* Exit if locked */
  509.     if (ioctl(maschan, TCSETAW, &tt_array) == -1) {/* Set parameters */
  510.         exit(1);
  511.     }
  512.     ioctl(maschan, TCFLSH, 2);        /* Flush channel */
  513.     sleep(1);
  514.     if ((status = fcntl(x, F_GETFL, 0)) != -1) {
  515.         status &= (~O_NDELAY);
  516.         if (fcntl(x, F_SETFL, status)) {    /* Clear O_NDELAY */
  517.             exit(0);
  518.         }
  519.     }
  520.     status = fcntl(maschan, F_GETFL, 0);    /* Read it again to be sure */
  521.     sleep(1);                /* Allow modem to settle */
  522.     checklock(line, 0);            /* Exit if locked */
  523.     timeout = 0;                /* No timeout yet */
  524.     slowwrite(maschan, init, strlen(init));/* Write initialization */
  525.     if (debug)
  526.         fprintf(ferr, "%x\n", status);
  527.     signal(SIGALRM, hangup);        /* Quit on timeout */
  528.     bcount = 0;
  529.     alarm(5);                /* Wait 5 seconds tops */
  530.     while (!quit) {                /* Check return from init */
  531.         if (!read(maschan, bc, 1)) {    /* Look for a character */
  532.             sleep(1);
  533.             continue;
  534.         }
  535.         if (debug)
  536.             fprintf(ferr, " %d\n", bc[0]);
  537.         if ((bc[0] == 10) || (bc[0] == 13)) {
  538.             if (strcmp(bfr, iresp)) {/* If not correct response */
  539.                 bcount = 0;    /* Then drop it */
  540.                 continue;    /* Keep looking */
  541.             } else {
  542.                 quit++;        /* Else done */
  543.             }
  544.         } else {
  545.             bfr[bcount++] = bc[0];    /* Save character */
  546.             bfr[bcount] = 0;    /* Null terminate */
  547.         }
  548.     }
  549.     dup(maschan);
  550.     dup(maschan);    
  551.     ioctl(maschan, TCFLSH, 2);
  552.     ioctl((maschan + 1), TCFLSH, 2);
  553.     ioctl((maschan + 2), TCFLSH, 2);
  554.     ferr = fopen("/dev/console", "w");    /* Write to console for errs */
  555.     alarm(0);                /* Turn off timeout */
  556.     strcpy(line, argv[1]);            /* Look on this line */
  557.     if (checklock(line, 0))            /* Check lock status again */
  558.         exit(0);            /* Exit if line is locked */
  559.     satisfied = 0;
  560.     bcount = 0;                /* Nothing in buffer */
  561.     signal(SIGALRM, hangup);
  562.     alarm(1800);                /* 30 minutes idle time */
  563.     while (!satisfied) {            /* Read result codes */
  564.         if (!read(maschan, bc, 1)) {    /* Look for a character */
  565.             sleep(2);
  566.             continue;
  567.         }
  568.         if (checklock(line, 0))        /* Locked by someone else? */
  569.             exit(0);        /* Quit if so */
  570.         if ((bc[0] == 10) || (bc[0] == 13)) {    /* New line? */
  571.             satisfied = checkmatch(matches, mcount, bfr, speed);
  572.             if (!satisfied) {
  573.                 bcount = 0;
  574.             }
  575.         } else {
  576.             bfr[bcount++] = bc[0];        /* Store character */
  577.             bfr[bcount] = 0;        /* Null terminate */
  578.         }
  579.     }
  580.     alarm(0);
  581.     if (makelock(line)) {            /* This is VERY bad! */
  582.         exit(0);            /* Quit right now! */
  583.     }
  584.     ioctl(maschan, TCGETA, &tt_array);
  585.     tt_array.c_cflag &= (~CBAUD);    /* Clear baud rate bits */
  586.     tt_array.c_cflag |= satisfied;    /* Set new baud rate */
  587.     ioctl(maschan, TCSETAW, &tt_array);
  588.     sprintf(baud, "%s @ %s bps", line, speed);
  589.     fid2 = fdopen(maschan, "a+");    /* Give us a stream channel please */
  590.     ioctl(maschan, TCFLSH, 2);    /* Flush input & output */
  591.     sleep(1);            /* Wait a second for settling... */
  592.     fprintf(fid2, "%s\r\n", connected);
  593.     fflush(fid2);
  594.     signal(SIGALRM, catch);
  595.     timeout = 0;
  596.     alarm(10);
  597.     if (read(maschan, bc, 1) > 0) {
  598.         switch(bc[0]) {
  599.             case 13:
  600.             case 10:
  601.                 strcat(baud, ", 8/N/1");
  602.                 goto aexit;        /* Do nothing */
  603.                 break;
  604.             case -115:        /* If signed... */
  605.             case 141:        /* 7/E/1, but otherwise ok */
  606.                 tt_array.c_cflag &= (~CS8);
  607.                 tt_array.c_cflag |= (CS7|PARENB);
  608.                 ioctl(maschan, TCSETAW, &tt_array);
  609.                 ioctl((maschan + 1), TCSETAW, &tt_array);
  610.                 ioctl((maschan + 2), TCSETAW, &tt_array);
  611.                 strcat(baud, ", 7/E/1");
  612.                 goto aexit;
  613.                 break;
  614.             default:
  615.                 break;
  616.         }
  617.     }
  618. aexit:;
  619.     tt_array.c_cflag &= (~(CBAUD|CLOCAL));
  620.     tt_array.c_cflag |= (satisfied|HUPCL);    /* New baud rate */
  621.     tt_array.c_oflag |= OPOST|ONLCR;
  622.  
  623. /*    If available, enable CTS flow control.  This is necessary for
  624.     Telebit Trailblazers and others of the general type.  Unfortunately,
  625.     only SCO has these things... (grr)  
  626. */
  627.  
  628. #ifdef    HARDWARE_FLOW
  629.     tt_array.c_iflag |= BRKINT|IGNPAR|INPCK|ICRNL;
  630.     tt_array.c_cflag |= HUPCL|CTSFLOW|RTSFLOW;
  631. #else
  632.     tt_array.c_iflag |= BRKINT|IGNPAR|INPCK|ICRNL|IXON|IXANY;
  633.     tt_array.c_cflag |= HUPCL;
  634. #endif
  635.     tt_array.c_lflag |= ISIG|ICANON|ECHO|ECHOE|ECHOK;
  636.     tt_array.c_cc[VINTR] = 177;
  637.     tt_array.c_cc[VQUIT] = 0;
  638.     tt_array.c_cc[VERASE] = 8;
  639.     tt_array.c_cc[VKILL] = 21;
  640.     tt_array.c_cc[VEOF] = 4;
  641.     tt_array.c_cc[VEOL] = 0;
  642.     ioctl(maschan, TCSETAW, &tt_array);    /* Set parameters */
  643.     ioctl((maschan + 1), TCSETAW, &tt_array);
  644.     ioctl((maschan + 2), TCSETAW, &tt_array);
  645.     signal(SIGALRM, hangup);    /* If we time out, hang up the line */
  646.     alarm(LOGSECONDS);        /* LOGSECONDS to read/reply, then out */
  647.     fprintf(fid2, "\n[%s]\n", baud);/* Display parameters we found */
  648.     for (x = 0; x < icount; x++) {
  649.         fputs(istring[x], fid2);
  650.     }
  651.     fputs("\r\n", fid2);        /* End with another <return> */
  652. bg1:;
  653.     fputs(loginp, fid2);        /* Prompt for login name */
  654.     fgets(tmp, 80, fid2);        /* Read it, but don't allow overrun */
  655.     if (*tmp == 10)            /* If nothing, ask again */
  656.         goto bg1;
  657.     tmp[strlen(tmp)-1] = 0;        /* Make sure null terminated */
  658.     tlc(tmp);            /* Lower case the name */
  659.     signal(SIGINT, SIG_DFL);    /* Reset signal handling */
  660.     signal(SIGALRM, SIG_DFL);
  661.     alarm(0);            /* Clear alarm */
  662.     fclose(ferr);            /* Close error channel */
  663. /*
  664.  * Take two shots at where login is.  If we can't find it in either of these
  665.  * places you're screwed; dump the caller.  Try to tell the user if this
  666.  * happens, but no guarantees....
  667.  */
  668.  
  669.     execlp("/etc/login", "login", tmp, (char *) NULL);
  670.     execlp("/bin/login", "login", tmp, (char *) NULL);
  671.     fputs("Login not executable; contact administrator\n", fid2);
  672.     fflush(fid2);            /* Make sure it's printed */
  673.     sleep(3);            /* Wait for output to drain */
  674.     exit(1);            /* And quit with error (ignored) */
  675. }
  676.  
  677.