Annotation of researchv10dc/cmd/uucp/unused/uugetty.c, revision 1.1.1.1

1.1       root        1: /*     /sccs/src/cmd/uucp/s.uugetty.c
                      2:        uugetty.c       1.3     8/30/84 17:38:06
                      3: */
                      4: #include       "uucp.h"
                      5: VERSION(@(#)uugetty.c  1.3);
                      6: 
                      7: /*     @(#)getty.c     1.5     */
                      8: /*     This program, uugetty, is the standard getty modified           */
                      9: /*     to allow a tty line to be used by uucp/cu or a dial in.         */
                     10: /*     For it to work with 801/212 dialers,                            */
                     11: /*     put an entry into inittab like                                  */
                     12: /*        30:2:respawn:/usr/lib/uucp/uugetty -t 60 cul04 1200          */
                     13: /*     For direct lines, or intelligent modems use                     */
                     14: /*        30:2:respawn:/usr/lib/uucp/uugetty -r -t 60 cul04 1200       */
                     15: /*        When this line is used, the Systems file that is             */
                     16: /*        used to call into it must have the following script          */
                     17: /*         "" \r\d\r\d\r\d\r in:--in: ...                              */
                     18: /*        This is because the uugetty expects to read a character      */
                     19: /*        before the login message is output.                          */
                     20: 
                     21: /*     It will only work on USG systems at least 5.0 or systems        */
                     22: /*     that permit kill(0, pid).                                       */
                     23: /*     This scheme was proposed by Larry Wehr and works as follows:    */
                     24: /*          The fopen of the line hangs until carrier is detected.     */
                     25: /*     At this point, uugetty attempts to create a LCK..line file      */
                     26: /*     If if fails, that means that uucico or cu are using the line.   */
                     27: /*       In this case, just do a busy wait, periodically checking      */
                     28: /*       for the LCK..line file.  When it goes away, then exit and     */
                     29: /*       a new uugetty will be spawned.                                */
                     30: /*     If it succeeds, then this is someone logging in--do normal      */
                     31: /*       getty processing.                                             */
                     32: /*     NOTE:                                                           */
                     33: /*       When the person hangs up (login case) the LCK..line file      */
                     34: /*     will remain, but this is ok because the ulockf() function       */
                     35: /*     used by uucico and uugetty and cu check the pid in the LCK      */
                     36: /*     file and if it doesn't exist, the LCK file is removed when      */
                     37: /*     it is needed.                                                   */
                     38: /*       Also, uugetty always sets the owner of the line to uucp.      */
                     39: /*     This is so that uucico/cu can get at the line.  (The new        */
                     40: /*     cu will run setuid uucp--or this will not work.)                */
                     41: /*                                                                     */
                     42: /*     There is an additional option for direct lines and lines        */
                     43: /*     that have intelligent modems (ones that return on open          */
                     44: /*     immediately.  The -r option means wait for one character        */
                     45: /*     before putting out the login message.  If the character         */
                     46: /*     comes in, then check the LCK file and proceed as above.         */
                     47: 
                     48: 
                     49: /*     getty - sets up speed, various terminal flags, line discipline, */
                     50: /*     and waits for new prospective user to enter name, before        */
                     51: /*     calling "login".                                                */
                     52: /*                                                                     */
                     53: /*     Usage:  getty  [-r] [-h] [-t time] line speed_label terminal            */
                     54: /*                 line_disc                                           */
                     55: /*                                                                     */
                     56: /*     -h says don't hangup by dropping carrier during the             */
                     57: /*             initialization phase.  Normally carrier is dropped to   */
                     58: /*             make the dataswitch release the line.                   */
                     59: /*     -t says timeout after the number of seconds in "time" have      */
                     60: /*             elapsed even if nothing is typed.  This is useful       */
                     61: /*             for making sure dialup lines release if someone calls   */
                     62: /*             in and then doesn't actually login in.                  */
                     63: /*     -r says wait for a character before putting out login message   */
                     64: /*             (This is for uugetty.c with intelligent modems          */
                     65: /*     "line" is the device in "/dev".                                 */
                     66: /*     "speed_label" is a pointer into the "/etc/getty_defs"           */
                     67: /*                     where the definition for the speeds and         */
                     68: /*                     other associated flags are to be found.         */
                     69: /*     "terminal" is the name of the terminal type.                    */
                     70: /*     "line_disc" is the name of the line discipline.                 */
                     71: /*                                                                     */
                     72: /*     Usage:  getty -c gettydefs_like_file                            */
                     73: /*                                                                     */
                     74: /*     The "-c" flag is used to have "getty" check a gettydefs file.   */
                     75: /*     "getty" parses the entire file and prints out its findings so   */
                     76: /*     that the user can make sure that the file contains the proper   */
                     77: /*     information.                                                    */
                     78: /*                                                                     */
                     79: 
                     80: /* dummies for using uucp .o routines */
                     81: void assert(){}
                     82: cleanup(){}
                     83: void logent(){}                /* so we can load ulockf() */
                     84: 
                     85: /* undefine DEBUG - it is defined in uucp.h */
                     86: #undef DEBUG
                     87: 
                     88: #include       <utmp.h>
                     89: #include       <sys/crtctl.h>
                     90: 
                     91: #define                TRUE            1
                     92: #define                FALSE           0
                     93: #define                FAILURE         -1
                     94: 
                     95: #define                SUCCESS         0
                     96: #define                ID              1
                     97: #define                IFLAGS          2
                     98: #define                FFLAGS          3
                     99: #define                MESSAGE         4
                    100: #define                NEXTID          5
                    101: 
                    102: #define                ACTIVE          1
                    103: #define                FINISHED        0
                    104: 
                    105: #define                ABORT           0177            /* Delete */
                    106: #define                QUIT            ('\\'&037)      /* ^\ */
                    107: #define                ERASE           '#'
                    108: #define                BACKSPACE       '\b'
                    109: #define                KILL            '@'
                    110: 
                    111: #ifdef OSS
                    112: /*     The following three characters are the standard OSS erase,      */
                    113: /*     kill, and abort characters.                                     */
                    114: 
                    115: #define                STDERASE        '_'
                    116: #define                STDKILL         '$'
                    117: #define                STDABORT        '&'
                    118: #endif
                    119: 
                    120: #define                control(x)      (x&037)
                    121: 
                    122: #define                GOODNAME        1
                    123: #define                NONAME          0
                    124: #define                BADSPEED        -1
                    125: 
                    126: #ifndef                fioctl
                    127: #define                fioctl(x,y,z)   ioctl(fileno(x),y,z)
                    128: #endif
                    129: 
                    130: struct Gdef {
                    131:        char    *g_id;  /* identification for modes & speeds */
                    132:        struct termio   g_iflags;       /* initial terminal flags */
                    133:        struct termio   g_fflags;       /* final terminal flags */
                    134:        char    *g_message;     /* login message */
                    135:        char    *g_nextid;      /* next id if this speed is wrong */
                    136: };
                    137: 
                    138: #define        MAXIDLENGTH     15      /* Maximum length the "g_id" and "g_nextid" \
                    139:                                 * strings can take.  Longer ones will be \
                    140:                                 * truncated. \
                    141:                                 */
                    142: #define MAXMESSAGE     79      /* Maximum length the "g_message" string \
                    143:                                 * can be.  Longer ones are truncated. \
                    144:                                 */
                    145: 
                    146: /*     Maximum length of line in /etc/gettydefs file and the maximum   */
                    147: /*     length of the user response to the "login" message.             */
                    148: 
                    149: #define        MAXLINE         255
                    150: #define        MAXARGS         64      /* Maximum number of arguments that can be \
                    151:                                 * passed to "login" \
                    152:                                 */
                    153: 
                    154: struct Symbols {
                    155:        char            *s_symbol;      /* Name of symbol */
                    156:        unsigned        s_value ;       /* Value of symbol */
                    157: };
                    158: 
                    159: /*     The following four symbols define the "SANE" state.             */
                    160: 
                    161: #define        ISANE   (BRKINT|IGNPAR|ISTRIP|ICRNL|IXON)
                    162: #define        OSANE   (OPOST|ONLCR)
                    163: #define        CSANE   (CS7|PARENB|CREAD)
                    164: #define        LSANE   (ISIG|ICANON|ECHO|ECHOK)
                    165: 
                    166: /*     Modes set with the TCSETAW ioctl command.                       */
                    167: 
                    168: struct Symbols imodes[] = {
                    169:        "IGNBRK",       IGNBRK,
                    170:        "BRKINT",       BRKINT,
                    171:        "IGNPAR",       IGNPAR,
                    172:        "PARMRK",       PARMRK,
                    173:        "INPCK",        INPCK,
                    174:        "ISTRIP",       ISTRIP,
                    175:        "INLCR",        INLCR,
                    176:        "IGNCR",        IGNCR,
                    177:        "ICRNL",        ICRNL,
                    178:        "IUCLC",        IUCLC,
                    179:        "IXON", IXON,
                    180:        "IXANY",        IXANY,
                    181:        "IXOFF",        IXOFF,
                    182:        NULL,   0
                    183: };
                    184: 
                    185: struct Symbols omodes[] = {
                    186:        "OPOST",        OPOST,
                    187:        "OLCUC",        OLCUC,
                    188:        "ONLCR",        ONLCR,
                    189:        "OCRNL",        OCRNL,
                    190:        "ONOCR",        ONOCR,
                    191:        "ONLRET",       ONLRET,
                    192:        "OFILL",        OFILL,
                    193:        "OFDEL",        OFDEL,
                    194:        "NLDLY",        NLDLY,
                    195:        "NL0",  NL0,
                    196:        "NL1",  NL1,
                    197:        "CRDLY",        CRDLY,
                    198:        "CR0",  CR0,
                    199:        "CR1",  CR1,
                    200:        "CR2",  CR2,
                    201:        "CR3",  CR3,
                    202:        "TABDLY",       TABDLY,
                    203:        "TAB0", TAB0,
                    204:        "TAB1", TAB1,
                    205:        "TAB2", TAB2,
                    206:        "TAB3", TAB3,
                    207:        "BSDLY",        BSDLY,
                    208:        "BS0",  BS0,
                    209:        "BS1",  BS1,
                    210:        "VTDLY",        VTDLY,
                    211:        "VT0",  VT0,
                    212:        "VT1",  VT1,
                    213:        "FFDLY",        FFDLY,
                    214:        "FF0",  FF0,
                    215:        "FF1",  FF1,
                    216:        NULL,   0
                    217: };
                    218: 
                    219: struct Symbols cmodes[] = {
                    220:        "B0",           B0,
                    221:        "B50",  B50,
                    222:        "B75",  B75,
                    223:        "B110", B110,
                    224:        "B134", B134,
                    225:        "B150", B150,
                    226:        "B200", B200,
                    227:        "B300", B300,
                    228:        "B600", B600,
                    229:        "B1200",        B1200,
                    230:        "B1800",        B1800,
                    231:        "B2400",        B2400,
                    232:        "B4800",        B4800,
                    233:        "B9600",        B9600,
                    234: #ifdef EXTA
                    235:        "EXTA",         EXTA,
                    236: #endif
                    237: #ifdef EXTB
                    238:        "EXTB",         EXTB,
                    239: #endif
                    240: #ifdef B19200
                    241:        "B19200",       B19200,
                    242: #endif
                    243: #ifdef B38400
                    244:        "B38400",       B38400,
                    245: #endif
                    246:        "CS5",  CS5,
                    247:        "CS6",  CS6,
                    248:        "CS7",  CS7,
                    249:        "CS8",  CS8,
                    250:        "CSTOPB",       CSTOPB,
                    251:        "CREAD",        CREAD,
                    252:        "PARENB",       PARENB,
                    253:        "PARODD",       PARODD,
                    254:        "HUPCL",        HUPCL,
                    255:        "CLOCAL",       CLOCAL,
                    256:        NULL,   0
                    257: };
                    258: 
                    259: struct Symbols lmodes[] = {
                    260:        "ISIG", ISIG,
                    261:        "ICANON",       ICANON,
                    262:        "XCASE",        XCASE,
                    263:        "ECHO", ECHO,
                    264:        "ECHOE",        ECHOE,
                    265:        "ECHOK",        ECHOK,
                    266:        "ECHONL",       ECHONL,
                    267:        "NOFLSH",       NOFLSH,
                    268:        NULL,   0
                    269: };
                    270: 
                    271: /*     Terminal types set with the LDSETT ioctl command.               */
                    272: 
                    273: struct Symbols terminals[] = {
                    274:        "none",         TERM_NONE,
                    275: #ifdef TERM_V10
                    276:        "vt100",                TERM_V10,
                    277: #endif
                    278: #ifdef TERM_H45
                    279:        "hp45",         TERM_H45,
                    280: #endif
                    281: #ifdef TERM_C10
                    282:        "c100",         TERM_C100,
                    283: #endif
                    284: #ifdef TERM_TEX
                    285:        "tektronix",    TERM_TEX,
                    286:        "tek",          TERM_TEX,
                    287: #endif
                    288: #ifdef TERM_D40
                    289:        "ds40-1",               TERM_D40,
                    290: #endif
                    291: #ifdef TERM_V61
                    292:        "vt61",         TERM_V61,
                    293: #endif
                    294: #ifdef TERM_TEC
                    295:        "tec",          TERM_TEC,
                    296: #endif
                    297:        NULL,           0
                    298: };
                    299: 
                    300: /*     Line disciplines set by the TIOCSETD ioctl command.             */
                    301: 
                    302: #ifndef        LDISC0
                    303: #define        LDISC0  0
                    304: #endif
                    305: 
                    306: struct Symbols linedisc[] = {
                    307:        "LDISC0",               LDISC0,
                    308:        NULL,           0
                    309: };
                    310: 
                    311: /*     If the /etc/gettydefs file can't be opened, the following       */
                    312: /*     default is used.                                                */
                    313: 
                    314: struct Gdef DEFAULT = {
                    315:        "default",
                    316:        ICRNL,0,B300+CREAD+HUPCL,0,
                    317:        LDISC0,ABORT,QUIT,ERASE,KILL,'\0','\0','\0','\0',
                    318:        ICRNL,OPOST+ONLCR+NLDLY+TAB3,B300+CS7+CREAD+HUPCL,
                    319:        ISIG+ICANON+ECHO+ECHOE+ECHOK,
                    320:        LDISC0,ABORT,QUIT,ERASE,KILL,'\0','\0','\0','\0',
                    321:        "LOGIN: ",
                    322:        "default"
                    323: };
                    324: 
                    325: #ifndef        DEBUG
                    326: char   *CTTY           =       "/dev/syscon";
                    327: #else
                    328: char   *CTTY           =       "/dev/sysconx";
                    329: #endif
                    330: 
                    331: char   *ISSUE_FILE     =       "/etc/issue";
                    332: char   *GETTY_DEFS     =       "/etc/gettydefs";
                    333: 
                    334: int    check = {
                    335:        FALSE
                    336: };
                    337: char   *checkgdfile;           /* Name of gettydefs file during
                    338:                                 * check mode.
                    339:                                 */
                    340: 
                    341: main(argc,argv)
                    342: int argc;
                    343: char **argv;
                    344: {
                    345:        char *line;
                    346:        register struct Gdef *speedef;
                    347:        char oldspeed[MAXIDLENGTH+1],newspeed[MAXIDLENGTH+1];
                    348:        extern struct Gdef *find_def();
                    349:        int termtype,lined;
                    350:        extern char *ISSUE_FILE,*GETTY_DEFS;
                    351:        extern int check;
                    352:        int hangup,timeout;
                    353:        extern char *checkgdfile;
                    354:        extern struct Symbols *search(),terminals[],linedisc[];
                    355:        extern int timedout();
                    356:        register struct Symbols *answer;
                    357:        char user[MAXLINE],*largs[MAXARGS],*ptr,buffer[MAXLINE];
                    358:        int wait_read = FALSE;  /* wait for read before output "login" */
                    359:        FILE *fp;
                    360:        FILE *fdup();
                    361:        struct utsname utsname;
                    362:        struct termcb termcb;
                    363:        struct termio termio;
                    364:        static char clrscreen[2] = {
                    365:                ESC,CS
                    366:        };
                    367:        struct stat statb;
                    368:        char lckname[MAXNAMESIZE];      /* lock file name LCK..line */
                    369: 
                    370:        signal(SIGINT,SIG_IGN);
                    371:        signal(SIGQUIT,SIG_DFL);
                    372: 
                    373:        hangup = TRUE;
                    374:        timeout = 0;
                    375:        while(--argc && **++argv == '-') {
                    376:                for(ptr = *argv + 1; *ptr;ptr++) switch(*ptr) {
                    377:                case 'h':
                    378:                        hangup = FALSE;
                    379:                        break;
                    380:                case 'r':
                    381:                        wait_read = TRUE;
                    382:                        break;
                    383:                case 't':
                    384:                        if(isdigit(*++ptr)) {
                    385:                                sscanf(ptr,"%d",&timeout);
                    386: 
                    387: /* Advance "ptr" so that it is pointing to the last digit of the */
                    388: /* timeout argument. */
                    389:                                while(isdigit(*++ptr));
                    390:                                ptr--;
                    391:                        } else if(--argc) {
                    392:                                if(isdigit(*(ptr = *++argv)))
                    393:                                        sscanf(ptr,"%d",&timeout);
                    394:                                else error("getty: timeout argument invalid. \"%s\"\n", *argv);
                    395:                        }
                    396:                        break;
                    397: 
                    398: /* Check a "gettydefs" file mode. */
                    399:                case 'c':
                    400:                        signal(SIGINT,SIG_DFL);
                    401:                        if(--argc == 0) {
                    402:                                fprintf(stderr,
                    403:                                    "Check Mode Usage: getty -c gettydefs-like-file\n");
                    404:                                exit(1);
                    405:                        }
                    406:                        check = TRUE;
                    407:                        checkgdfile = *++argv;
                    408: 
                    409: /* Attempt to open the check gettydefs file. */
                    410:                        if((fp = fopen(checkgdfile,"r")) == NULL) {
                    411:                                fprintf(stderr,"Cannot open %s\n",checkgdfile);
                    412:                                exit(1);
                    413:                        }
                    414:                        fclose(fp);
                    415: 
                    416: /* Call "find_def" to check the check file.  With the "check" flag */
                    417: /* set, it will parse the entire file, printing out the results. */
                    418:                        find_def(NULL);
                    419:                        exit(0);
                    420:                default:
                    421:                        break;
                    422:                }
                    423:        }
                    424: 
                    425: /* There must be at least one argument.  If there isn't, complain */
                    426: /* and then die after 20 seconds.  The 20 second sleep is to keep */
                    427: /* "init" from working too hard. */
                    428:        if(argc < 1) {
                    429:                error("getty: no terminal line specified.\n");
                    430:                sleep(20);
                    431:                exit(1);
                    432:        } else line = *argv;
                    433: 
                    434: /* If a "speed_label" was provided, search for it in the */
                    435: /* "getty_defs" file.  If none was provided, take the first entry */
                    436: /* of the "getty_defs" file as the initial settings. */
                    437:        if(--argc > 0 ) {
                    438:                if((speedef = find_def(*++argv)) == NULL) {
                    439:                        error("getty: unable to find %s in \"%s\".\n",
                    440:                            *argv,GETTY_DEFS);
                    441: 
                    442: /* Use the default value instead. */
                    443:                        speedef = find_def(NULL);
                    444:                }
                    445:        } else speedef = find_def(NULL);
                    446: 
                    447: /* If a terminal type was supplied, try to find it in list. */
                    448:        if(--argc > 0) {
                    449:                if((answer = search(*++argv,terminals)) == NULL) {
                    450:                        error("getty: %s is an undefined terminal type.\n",
                    451:                            *argv);
                    452:                        termtype = TERM_NONE;
                    453:                } else termtype = answer->s_value;
                    454:        } else termtype = TERM_NONE;
                    455: 
                    456: /* If a line discipline was supplied, try to find it in list. */
                    457:        if(--argc > 0) {
                    458:                if((answer = search(*++argv,linedisc)) == NULL) {
                    459:                        error("getty: %s is an undefined line discipline.\n",
                    460:                            *argv);
                    461:                        lined = LDISC0;
                    462:                } else lined = answer->s_value;
                    463:        } else lined = LDISC0;
                    464: 
                    465: /* Perform "utmp" accounting. */
                    466:        account(line);
                    467: 
                    468: /* Attempt to open standard input, output, and error on specified */
                    469: /* line. */
                    470:        chdir("/dev");
                    471: 
                    472: /* Code added for shared line - input/output           */
                    473: /* For use by uucico/cu/ct                             */
                    474: /* Method: -- wait for open                            */
                    475: /*     When success, check to see if LCK..line exists  */
                    476: /*       If it does, that means that uucico/cu/ct is   */
                    477: /*       using the line, so busy wait and exit when    */
                    478: /*       the LCK..line file goes away                  */
                    479: /*       If no LCK..line file, normal processing--     */
                    480: /*         close the line and use openline() as usual  */
                    481: /* If the -r option, wait for first character also.    */
                    482: 
                    483: /* Change the ownership of the terminal line to uucp and set */
                    484: /* the protections to only allow uucp to read the line. */
                    485:        stat(line,&statb);
                    486:        chown(line,UUCPUID,statb.st_gid); /* for uugetty use uucp uid */
                    487:        chmod(line,0622);
                    488: 
                    489:        (void) close(0);
                    490:        (void)fclose(stdin);
                    491:        (void) close(1);
                    492:        (void) close(2);
                    493:        (void) fclose(stdout);
                    494:        (void) fclose(stderr);
                    495:        if ( (fopen(line, "r+")) == NULL) { /* this opens stdin */
                    496:                error("getty: cannot open \"%s\". errno: %d\n",line,errno);
                    497:                sleep(20);
                    498:                exit(1);
                    499:        }
                    500:        if (wait_read) {          /* wait to read the first character */
                    501:                /* Set the terminal type and line discipline. */
                    502:                setupline(speedef,termtype,lined);
                    503:                /*
                    504:                 * Check for read failure or and EOT sent
                    505:                 * (EOT may come from a cu on the other side.)
                    506:                 * This code is to prevent the situation of
                    507:                 * "login" program getting started here while
                    508:                 * a uugetty is running on the other end of the
                    509:                 * line.
                    510:                 * NOTE: Cu on a direct line when ~. is encountered will
                    511:                 * send EOTs to the other side.  EOT=\004
                    512:                 */
                    513:                if ( read(0, buffer, 1) < 0
                    514:                  || *buffer == '\004') {
                    515:                        (void) fclose(stdin);
                    516:                        sleep(10);
                    517:                        exit(0);
                    518:                }
                    519:        }
                    520: 
                    521:        if (mlock(line)) { /*  There is a lock file already */
                    522:            /* some process is using the line for output */
                    523:            (void) fclose(stdin);
                    524:            (void) sprintf(lckname, "%s.%s", LOCKPRE, line);
                    525:            for (;;) {  /* busy wait for LCK..line to go away */
                    526:                sleep(60);
                    527:                if (checkLock(lckname) == 0) /* LCK..line gone */
                    528:                    break;
                    529:            }
                    530:            exit(0);
                    531:        }
                    532:            
                    533:        openline(line,speedef,termtype,lined,hangup);
                    534: 
                    535: /* Loop until user is successful in requesting login. */
                    536:        for(;;) {
                    537: 
                    538: /* If there is no terminal type, just advance a line. */
                    539:                if(termtype == TERM_NONE) {
                    540: 
                    541: /* A bug in the stdio package requires that the first output on */
                    542: /* the newly reopened stderr stream be a putc rather than an */
                    543: /* fprintf. */
                    544:                        putc('\r',stderr);
                    545:                        putc('\n',stderr);
                    546: 
                    547: /* If there is a terminal type, clear the screen with the common */
                    548: /* crt language.  Note that the characters have to be written in */
                    549: /* one write, and hence can't go through standard io, which is */
                    550: /* currently unbuffered. */
                    551:                } else write(fileno(stderr),clrscreen,sizeof(clrscreen));
                    552: 
                    553: /* If getty is supposed to die if no one logs in after a */
                    554: /* predetermined amount of time, set the timer. */
                    555:                if(timeout) {
                    556:                        signal(SIGALRM,timedout);
                    557:                        alarm(timeout);
                    558:                }
                    559: 
                    560: #ifdef SYS_NAME
                    561: /* Generate a message with the system identification in it. */
                    562:                if (uname(&utsname) != FAILURE) {
                    563:                        sprintf(buffer,"%.9s\r\n", utsname.nodename);
                    564: 
                    565: #ifdef UPPERCASE_ONLY
                    566: /* Make all the alphabetics upper case. */
                    567:                        for (ptr= buffer; *ptr;ptr++) *ptr = tolower(*ptr);
                    568: #endif
                    569:                        fputs(buffer,stderr);
                    570:                }
                    571: 
                    572: /* Print out the issue file. */
                    573:                if ((fp = fopen(ISSUE_FILE,"r")) != NULL) {
                    574:                        while ((ptr = fgets(buffer,sizeof(buffer),fp)) != NULL) {
                    575:                                fputs(ptr,stderr);
                    576: 
                    577: /* In "raw" mode, a carriage return must be supplied at the end of */
                    578: /* each line. */
                    579:                                putc('\r',stderr);
                    580:                        }
                    581:                        fclose(fp);
                    582:                }
                    583: #endif
                    584: 
                    585: /* Print the login message. */
                    586:                fprintf(stderr,"%s",speedef->g_message);
                    587: 
                    588: /* Get the user's typed response and respond appropriately. */
                    589:                switch(getname(user,&termio)) {
                    590:                case GOODNAME:
                    591:                        if (timeout) alarm(0);
                    592: 
                    593: /* If a terminal type was specified, keep only those parts of */
                    594: /* the gettydef final settings which were not explicitely turned */
                    595: /* on when the terminal type was set. */
                    596:                        if (termtype != TERM_NONE) {
                    597:                                termio.c_iflag |= (ISTRIP|ICRNL|IXON|IXANY)
                    598:                                        | (speedef->g_fflags.c_iflag
                    599:                                                & ~(ISTRIP|ICRNL|IXON|IXANY));
                    600:                                termio.c_oflag |= (OPOST|ONLCR)
                    601:                                        | (speedef->g_fflags.c_oflag
                    602:                                                & ~(OPOST|ONLCR));
                    603:                                termio.c_cflag = speedef->g_fflags.c_cflag;
                    604:                                termio.c_lflag = (ISIG|ICANON|ECHO|ECHOE|ECHOK)
                    605:                                        | (speedef->g_fflags.c_lflag
                    606:                                                & ~(ISIG|ICANON|ECHO|ECHOE|ECHOK));
                    607:                        } else {
                    608:                                termio.c_iflag |= speedef->g_fflags.c_iflag;
                    609:                                termio.c_oflag |= speedef->g_fflags.c_oflag;
                    610:                                termio.c_cflag |= speedef->g_fflags.c_cflag;
                    611:                                termio.c_lflag |= speedef->g_fflags.c_lflag;
                    612:                        }
                    613:                        termio.c_line = lined;
                    614:                        fioctl(stdin,TCSETAW,&termio);
                    615: 
                    616: /* Parse the input line from the user, breaking it at white */
                    617: /* spaces. */
                    618:                        largs[0] = "login";
                    619:                        parse(user,&largs[1],MAXARGS-1);
                    620: 
                    621: /* Exec "login". */
                    622: 
                    623: #ifndef        DEBUG
                    624:                        execv("/bin/login",largs);
                    625:                        exit(1);
                    626: #else
                    627:                        exit(0);
                    628: #endif
                    629: 
                    630: /* If the speed supplied was bad, try the next speed in the list. */
                    631:                case BADSPEED:
                    632: 
                    633: /* Save the name of the old speed definition incase new one is */
                    634: /* bad.  Copy the new speed out of the static so that "find_def" */
                    635: /* won't overwrite it in the process of looking for new entry. */
                    636:                        strcpy(oldspeed,speedef->g_id);
                    637:                        strcpy(newspeed,speedef->g_nextid);
                    638:                        if ((speedef = find_def(newspeed)) == NULL) {
                    639:                                error("getty: pointer to next speed in entry %s is bad.\n",
                    640:                                oldspeed);
                    641: 
                    642: /* In case of error, go back to the original entry. */
                    643:                                if((speedef = find_def(oldspeed)) == NULL) {
                    644: 
                    645: /* If the old entry has disappeared, then quit and let next "getty" try. */
                    646:                                        error("getty: unable to find %s again.\n",
                    647:                                                oldspeed);
                    648:                                        exit(1);
                    649:                                }
                    650:                        }
                    651: 
                    652: /* Setup the terminal for the new information. */
                    653:                        setupline(speedef,termtype,lined);
                    654:                        break;
                    655: 
                    656: /* If no name was supplied, not nothing, but try again. */
                    657:                case NONAME:
                    658:                        break;
                    659:                }
                    660:        }
                    661: }
                    662: 
                    663: account(line)
                    664: char *line;
                    665: {
                    666:        register int ownpid;
                    667:        register struct utmp *u;
                    668:        extern struct utmp *getutent(), *pututline();
                    669:        register FILE *fp;
                    670: 
                    671: /* Look in "utmp" file for our own entry and change it to LOGIN. */
                    672:        ownpid = getpid();
                    673: 
                    674:        while ((u = getutent()) != NULL) {
                    675: 
                    676: /* Is this our own entry? */
                    677:                if (u->ut_type == INIT_PROCESS && u->ut_pid == ownpid) {
                    678:                        strncpy(u->ut_line,line,sizeof(u->ut_line));
                    679:                        strncpy(u->ut_user,"LOGIN",sizeof(u->ut_user));
                    680:                        u->ut_type = LOGIN_PROCESS;
                    681: 
                    682: /* Write out the updated entry. */
                    683:                        pututline(u);
                    684:                        break;
                    685:                }
                    686:        }
                    687: 
                    688: /* If we were successful in finding an entry for ourself in the */
                    689: /* utmp file, then attempt to append to the end of the wtmp file. */
                    690:        if (u != NULL && (fp = fopen(WTMP_FILE,"r+")) != NULL) {
                    691:                fseek(fp,0L,2); /* Seek to end of file */
                    692:                fwrite(u,sizeof(*u),1,fp);
                    693:                fclose(fp);
                    694:        }
                    695: 
                    696: /* Close the utmp file. */
                    697:        endutent();
                    698: }
                    699: 
                    700: /*     "search" scans through a table of Symbols trying to find a      */
                    701: /*     match for the supplied string.  If it does, it returns the      */
                    702: /*     pointer to the Symbols structure, otherwise it returns NULL.    */
                    703: 
                    704: struct Symbols *search(target,symbols)
                    705: register char *target;
                    706: register struct Symbols *symbols;
                    707: {
                    708: 
                    709: /* Each symbol array terminates with a null pointer for an */
                    710: /* "s_symbol".  Scan until a match is found, or the null pointer */
                    711: /* is reached. */
                    712:        for (;symbols->s_symbol != NULL; symbols++)
                    713:                if (strcmp(target,symbols->s_symbol) == 0) return(symbols);
                    714:        return(NULL);
                    715: }
                    716: 
                    717: error(format,arg1,arg2,arg3,arg4)
                    718: char *format;
                    719: int arg1,arg2,arg3,arg4;
                    720: {
                    721:        register FILE *fp;
                    722: 
                    723:        if ((fp = fopen(CTTY,"w")) == NULL) return;
                    724:        else {
                    725:                fprintf(fp,format,arg1,arg2,arg3,arg4);
                    726:                fclose(fp);
                    727:        }
                    728: }
                    729: 
                    730: openline(line,speedef,termtype,lined,hangup)
                    731: register char *line;
                    732: register struct Gdef *speedef;
                    733: int termtype,lined,hangup;
                    734: {
                    735:        register FILE *fpin,*fp;
                    736:        extern int errno;
                    737: 
                    738:        close(1);
                    739:        close(2);
                    740:        fclose(stdout);
                    741:        fclose(stderr);
                    742: 
                    743:        fdup(stdin);
                    744:        fdup(stdin);
                    745:        setbuf(stdin,NULL);
                    746:        setbuf(stdout,NULL);
                    747:        setbuf(stderr,NULL);
                    748: 
                    749: /* Unless getty is being invoked by ct, make sure that DTR has been */
                    750: /* dropped and reasserted */
                    751:        if (hangup) hang_up_line();
                    752: 
                    753: /* Set the terminal type and line discipline. */
                    754:        setupline(speedef,termtype,lined);
                    755: }
                    756: 
                    757: #ifdef HANGUP
                    758: 
                    759: hang_up_line()
                    760: {
                    761:        struct termio termio;
                    762: 
                    763:        fioctl(stdin,TCGETA,&termio);
                    764:        termio.c_cflag &= ~CBAUD;
                    765:        termio.c_cflag |= B0;
                    766:        fioctl(stdin,TCSETAF,&termio);
                    767:        sleep(1);
                    768: }
                    769: #else
                    770: hang_up_line()
                    771: {
                    772: }
                    773: #endif
                    774: 
                    775: timedout()
                    776: {
                    777:        exit(1);
                    778: }
                    779: 
                    780: setupline(speedef,termtype,lined)
                    781: register struct Gdef *speedef;
                    782: int termtype,lined;
                    783: {
                    784:        struct termio termio;
                    785:        struct termcb termcb;
                    786:        unsigned short timer;
                    787: 
                    788: /* Set the terminal type to "none", which will clear all old */
                    789: /* special flags, if a terminal type was set from before. */
                    790:        termcb.st_flgs = 0;
                    791:        termcb.st_termt = TERM_NONE;
                    792:        termcb.st_vrow = 0;
                    793:        fioctl(stdin,LDSETT,&termcb);
                    794:        termcb.st_termt = termtype;
                    795:        fioctl(stdin,LDSETT,&termcb);
                    796: 
                    797: /* Get the current state of the modes and such for the terminal. */
                    798:        fioctl(stdin,TCGETA,&termio);
                    799:        if (termtype != TERM_NONE) {
                    800: 
                    801: /* If there is a terminal type, take away settings so that */
                    802: /* terminal is "raw" and "no echo".  Also take away the orginal */
                    803: /* speed setting. */
                    804:                termio.c_iflag = 0;
                    805:                termio.c_cflag &= ~(CSIZE|PARENB|CBAUD);
                    806:                termio.c_cflag |= CS8|CREAD|HUPCL;
                    807:                termio.c_lflag &= ~(ISIG|ICANON|ECHO|ECHOE|ECHOK);
                    808: 
                    809: /* Add in the speed. */
                    810:                termio.c_cflag |= (speedef->g_iflags.c_cflag & CBAUD);
                    811:        } else {
                    812:                termio.c_iflag = speedef->g_iflags.c_iflag;
                    813:                termio.c_oflag = speedef->g_iflags.c_oflag;
                    814:                termio.c_cflag = speedef->g_iflags.c_cflag;
                    815:                termio.c_lflag = speedef->g_iflags.c_lflag;
                    816:        }
                    817: 
                    818: /* Make sure that raw reads are 1 character at a time with no */
                    819: /* timeout. */
                    820:        termio.c_cc[VMIN] = 1;
                    821:        termio.c_cc[VTIME] = 0;
                    822: 
                    823: /* Add the line discipline. */
                    824:        termio.c_line = lined;
                    825:        fioctl(stdin,TCSETAF,&termio);
                    826: 
                    827: /* Pause briefly while terminal settles. */
                    828:        for(timer=0; ++timer != 0;);
                    829: }
                    830: 
                    831: /*     "getname" picks up the user's name from the standard input.     */
                    832: /*     It makes certain                                                */
                    833: /*     determinations about the modes that should be set up for the    */
                    834: /*     terminal depending upon what it sees.  If it sees all UPPER     */
                    835: /*     case characters, it sets the IUCLC & OLCUC flags.  If it sees   */
                    836: /*     a line terminated with a <linefeed>, it sets ICRNL.  If it sees */
                    837: /*     the user using the "standard" OSS erase, kill, abort, or line   */
                    838: /*     termination characters ( '_','$','&','/','!' respectively)      */
                    839: /*     it resets the erase, kill, and end of line characters.          */
                    840: 
                    841: int getname(user,termio)
                    842: char *user;
                    843: struct termio *termio;
                    844: {
                    845:        register char *ptr,c;
                    846:        register int rawc;
                    847:        int upper,lower;
                    848: 
                    849: /* Get the previous modes, erase, and kill characters and speeds. */
                    850:        fioctl(stdin,TCGETA,termio);
                    851: 
                    852: /* Set the flags to 0 and the erase and kill to the standard */
                    853: /* characters. */
                    854:        termio->c_iflag &= ICRNL;
                    855:        termio->c_oflag = 0;
                    856:        termio->c_cflag = 0;
                    857:        termio->c_lflag &= ECHO;
                    858:        for (ptr= (char*)termio->c_cc; ptr < (char*)&termio->c_cc[NCC];)
                    859:                *ptr++ = NULL;
                    860:        termio->c_cc[VINTR] = ABORT;
                    861:        termio->c_cc[VQUIT] = QUIT;
                    862:        termio->c_cc[VERASE] = ERASE;
                    863:        termio->c_cc[VKILL] = KILL;
                    864:        termio->c_cc[VEOF] = ('D'&037);
                    865:        ptr = user;
                    866:        upper = 0;
                    867:        lower = 0;
                    868:        do {
                    869: 
                    870: /* If it isn't possible to read line, exit. */
                    871:                if ((rawc = getc(stdin)) == EOF) exit(0);
                    872: 
                    873: /* If a null character was typed, return 0. */
                    874:                if ((c = (rawc & 0177)) == '\0') return(BADSPEED);
                    875: 
                    876: /* Echo the character if ECHO is off. */
                    877:                if( (termio->c_lflag&ECHO) == 0 )
                    878:                        putc(rawc,stdout);
                    879: #ifdef OSS
                    880:                if (c == ERASE || c == BACKSPACE) {
                    881: 
                    882: /* Store this character as the "erase" character. */
                    883:                        termio->c_cc[VERASE] = c;
                    884: #else
                    885:                if (c == ERASE) {
                    886: #endif
                    887: 
                    888: /* If there is anything to erase, erase a character. */
                    889:                        if (ptr > user) --ptr;
                    890:                }
                    891: 
                    892: #ifdef OSS
                    893:                else if (c == STDERASE) {
                    894:                        if (ptr > user) --ptr;
                    895: 
                    896: /* Set up the "standard OSS" erase, kill, etc. characters. */
                    897:                        termio->c_cc[VINTR] = STDABORT;
                    898:                        termio->c_cc[VERASE] = STDERASE;
                    899:                        termio->c_cc[VKILL] = STDKILL;
                    900:                        termio->c_cc[VEOL] = '/';
                    901:                        termio->c_cc[VEOL2] = '!';
                    902:                }
                    903: #endif
                    904: 
                    905: /* If the character is a kill line or abort character, reset the */
                    906: /* line. */
                    907:                else if (c == KILL || c == ABORT || c == control('U')) {
                    908:                        ptr = user;
                    909:                        fputs("\r\n",stdout);
                    910: 
                    911: /* Make sure the erase, kill, etc. are set to the UNIX standard. */
                    912:                        termio->c_cc[VINTR] = ABORT;
                    913:                        termio->c_cc[VERASE] = ERASE;
                    914:                        termio->c_cc[VKILL] = KILL;
                    915:                        termio->c_cc[VEOL] = '\0';
                    916:                        termio->c_cc[VEOL2] = '\0';
                    917:                }
                    918: 
                    919: #ifdef OSS
                    920:                else if (c == STDKILL || c == STDABORT) {
                    921:                        ptr = user;
                    922: 
                    923: /* Set up the "standard OSS" erase, kill, etc. characters. */
                    924:                        termio->c_cc[VINTR] = STDABORT;
                    925:                        termio->c_cc[VERASE] = STDERASE;
                    926:                        termio->c_cc[VKILL] = STDKILL;
                    927:                        termio->c_cc[VEOL] = '/';
                    928:                        termio->c_cc[VEOL2] = '!';
                    929:                }
                    930: #endif
                    931: 
                    932: /* If the character is lower case, increment the flag for lower case. */
                    933:                else if (islower(c)) {
                    934:                        lower++;
                    935:                        *ptr++ = c;
                    936:                }
                    937: 
                    938: /* If the character is upper case, increment the flag. */
                    939:                else if (isupper(c)) {
                    940:                        upper++;
                    941:                        *ptr++ = c;
                    942:                }
                    943: 
                    944: /* Just store all other characters. */
                    945:                else *ptr++ = c;
                    946:        }
                    947: 
                    948: /* Continue the above loop until a line terminator is found or */
                    949: /* until user name array is full. */
                    950: 
                    951: #ifdef OSS
                    952:        while (c != '\n' && c != '\r' && c != '/' && c != '!' &&
                    953:            ptr < (user + MAXLINE));
                    954: #else
                    955:        while (c != '\n' && c != '\r'
                    956:            && ptr < (user + MAXLINE));
                    957: #endif
                    958: 
                    959: /* Remove the last character from name. */
                    960:        *--ptr = '\0';
                    961:        if (ptr == user) return(NONAME);
                    962: 
                    963: #ifdef OSS
                    964: /* If the line was terminated with one of the printing OSS line */
                    965: /* termination characters or is a <cr>, add a <newline>. */
                    966:        if (c == '/' || c == '!') {
                    967:                putc('\n',stdout);
                    968: 
                    969: /* Set up the "standard OSS" erase, kill, etc. characters. */
                    970:                termio->c_cc[VINTR] = STDABORT;
                    971:                termio->c_cc[VERASE] = STDERASE;
                    972:                termio->c_cc[VKILL] = STDKILL;
                    973:                termio->c_cc[VEOL] = '/';
                    974:                termio->c_cc[VEOL2] = '!';
                    975:        } else
                    976: #endif
                    977:                if (c == '\r') putc('\n',stdout);
                    978: 
                    979: /* If the line terminated with a <lf>, put ICRNL and ONLCR into */
                    980: /* into the modes. */
                    981:        if (c == '\r') {
                    982:                termio->c_iflag |= ICRNL;
                    983:                termio->c_oflag |= ONLCR;
                    984: 
                    985: /* When line ends with a <lf>, then add the <cr>. */
                    986:        } else putc('\r',stdout);
                    987: 
                    988: /* Set the upper-lower case conversion switchs if only upper */
                    989: /* case characters were seen in the login and no lower case. */
                    990: /* Also convert all the upper case characters to lower case. */
                    991: 
                    992:        if (upper > 0 && lower == 0) {
                    993:                termio->c_iflag |= IUCLC;
                    994:                termio->c_oflag |= OLCUC;
                    995:                termio->c_lflag |= XCASE;
                    996:                for (ptr=user; *ptr; ptr++)
                    997:                        if (*ptr >= 'A' && *ptr <= 'Z' ) *ptr += ('a' - 'A');
                    998:        }
                    999:        return(GOODNAME);
                   1000: }
                   1001: 
                   1002: /*     "find_def" scans "/etc/gettydefs" for a string with the         */
                   1003: /*     requested "id".  If the "id" is NULL, then the first entry is   */
                   1004: /*     taken, hence the first entry must be the default entry.         */
                   1005: /*     If a match for the "id" is found, then the line is parsed and   */
                   1006: /*     the Gdef structure filled.  Errors in parsing generate error    */
                   1007: /*     messages on the system console.                                 */
                   1008: 
                   1009: struct Gdef *find_def(id)
                   1010: char *id;
                   1011: {
                   1012:        register struct Gdef *gptr;
                   1013:        register char *ptr,c;
                   1014:        FILE *fp;
                   1015:        int i,input,state,size,rawc,field;
                   1016:        char oldc,*optr,quoted(),*gdfile;
                   1017:        char line[MAXLINE+1];
                   1018:        static struct Gdef def;
                   1019:        extern struct Gdef DEFAULT;
                   1020:        static char d_id[MAXIDLENGTH+1],d_nextid[MAXIDLENGTH+1];
                   1021:        static char d_message[MAXMESSAGE+1];
                   1022:        extern char *GETTY_DEFS;
                   1023:        extern char *getword(),*fields(),*speed();
                   1024:        extern int check;
                   1025:        extern char *checkgdfile;
                   1026:        static char *states[] = {
                   1027:                "","id","initial flags","final flags","message","next id"
                   1028:        };
                   1029: 
                   1030: /* Decide whether to read the real /etc/gettydefs or the supplied */
                   1031: /* check file. */
                   1032:        if (check) gdfile = checkgdfile;
                   1033:        else gdfile = GETTY_DEFS;
                   1034: 
                   1035: /* Open the "/etc/gettydefs" file.  Be persistent. */
                   1036:        for (i=0; i < 3;i++) {
                   1037:                if ((fp = fopen(gdfile,"r")) != NULL) break;
                   1038:                else sleep(3);  /* Wait a little and then try again. */
                   1039:        }
                   1040: 
                   1041: /* If unable to open, complain and then use the built in default. */
                   1042:        if (fp == NULL) {
                   1043:                error("getty: can't open \"%s\".\n",gdfile);
                   1044:                return(&DEFAULT);
                   1045:        }
                   1046: 
                   1047: /* Start searching for the line with the proper "id". */
                   1048:        input = ACTIVE;
                   1049:        do {
                   1050:                for(ptr= line,oldc='\0'; ptr < &line[sizeof(line)] &&
                   1051:                    (rawc = getc(fp)) != EOF; ptr++,oldc = c) {
                   1052:                        c = *ptr = rawc;
                   1053: 
                   1054: /* Search for two \n's in a row. */
                   1055:                        if (c == '\n' && oldc == '\n') break;
                   1056:                }
                   1057: 
                   1058: /* If we didn't end with a '\n' or EOF, then the line is too long. */
                   1059: /* Skip over the remainder of the stuff in the line so that we */
                   1060: /* start correctly on next line. */
                   1061:                if (rawc != EOF && c != '\n') {
                   1062:                        for (oldc='\0'; (rawc = getc(fp)) != EOF;oldc=c) {
                   1063:                                c = rawc;
                   1064:                                if (c == '\n' && oldc != '\n') break;
                   1065:                        }
                   1066:                        if (check) fprintf(stdout,"Entry too long.\n");
                   1067:                }
                   1068: 
                   1069: /* If we ended at the end of the file, then if there is no */
                   1070: /* input, break out immediately otherwise set the "input" */
                   1071: /* flag to FINISHED so that the "do" loop will terminate. */
                   1072:                if (rawc == EOF) {
                   1073:                        if (ptr == line) break;
                   1074:                        else input = FINISHED;
                   1075:                }
                   1076: 
                   1077: /* If the last character stored was an EOF or '\n', replace it */
                   1078: /* with a '\0'. */
                   1079:                if (*ptr == (EOF & 0377) || *ptr == '\n') *ptr = '\0';
                   1080: 
                   1081: /* If the buffer is full, then make sure there is a null after the */
                   1082: /* last character stored. */
                   1083:                else *++ptr == '\0';
                   1084:                if (check) fprintf(stdout,"\n**** Next Entry ****\n%s\n",line);
                   1085: 
                   1086: /* If line starts with #, treat as comment */
                   1087:                if(line[0] == '#') continue;
                   1088: 
                   1089: /* Initialize "def" and "gptr". */
                   1090:                gptr = &def;
                   1091:                gptr->g_id = (char*)NULL;
                   1092:                gptr->g_iflags.c_iflag = 0;
                   1093:                gptr->g_iflags.c_oflag = 0;
                   1094:                gptr->g_iflags.c_cflag = 0;
                   1095:                gptr->g_iflags.c_lflag = 0;
                   1096:                gptr->g_fflags.c_iflag = 0;
                   1097:                gptr->g_fflags.c_oflag = 0;
                   1098:                gptr->g_fflags.c_cflag = 0;
                   1099:                gptr->g_fflags.c_lflag = 0;
                   1100:                gptr->g_message = (char*)NULL;
                   1101:                gptr->g_nextid = (char*)NULL;
                   1102: 
                   1103: /* Now that we have the complete line, scan if for the various */
                   1104: /* fields.  Advance to new field at each unquoted '#'. */
                   1105:                for (state=ID,ptr= line; state != FAILURE && state != SUCCESS;) {
                   1106:                        switch(state) {
                   1107:                        case ID:
                   1108: 
                   1109: /* Find word in ID field and move it to "d_id" array. */
                   1110:                                strncpy(d_id,getword(ptr,&size),MAXIDLENGTH);
                   1111:                                gptr->g_id = d_id;
                   1112: 
                   1113: /* Move to the next field.  If there is anything but white space */
                   1114: /* following the id up until the '#', then set state to FAILURE. */
                   1115:                                ptr += size;
                   1116:                                while (isspace(*ptr)) ptr++;
                   1117:                                if (*ptr != '#') {
                   1118:                                        field = state;
                   1119:                                        state = FAILURE;
                   1120:                                } else {
                   1121:                                        ptr++;  /* Skip the '#' */
                   1122:                                        state = IFLAGS;
                   1123:                                }
                   1124:                                break;
                   1125: 
                   1126: /* Extract the "g_iflags" */
                   1127:                        case IFLAGS:
                   1128:                                if ((ptr = fields(ptr,&gptr->g_iflags)) == NULL) {
                   1129:                                        field = state;
                   1130:                                        state = FAILURE;
                   1131:                                } else {
                   1132:                                        gptr->g_iflags.c_iflag &= ICRNL;
                   1133:                                        if((gptr->g_iflags.c_cflag & CSIZE) == 0)
                   1134:                                                gptr->g_iflags.c_cflag |= CS8;
                   1135:                                        gptr->g_iflags.c_cflag |= CREAD|HUPCL;
                   1136:                                        gptr->g_iflags.c_lflag &= ~(ISIG|ICANON
                   1137:                                                |XCASE|ECHOE|ECHOK);
                   1138:                                        ptr++;
                   1139:                                        state = FFLAGS;
                   1140:                                }
                   1141:                                break;
                   1142: 
                   1143: /* Extract the "g_fflags". */
                   1144:                        case FFLAGS:
                   1145:                                if ((ptr = fields(ptr,&gptr->g_fflags)) == NULL) {
                   1146:                                        field = state;
                   1147:                                        state = FAILURE;
                   1148:                                } else {
                   1149: 
                   1150: /* Force the CREAD mode in regardless of what the user specified. */
                   1151:                                        gptr->g_fflags.c_cflag |= CREAD;
                   1152:                                        ptr++;
                   1153:                                        state = MESSAGE;
                   1154:                                }
                   1155:                                break;
                   1156: 
                   1157: /* Take the entire next field as the "login" message. */
                   1158: /* Follow usual quoting procedures for control characters. */
                   1159:                        case MESSAGE:
                   1160:                                for (optr= d_message; (c = *ptr) != '\0'
                   1161:                                    && c != '#';ptr++) {
                   1162: 
                   1163: /* If the next character is a backslash, then get the quoted */
                   1164: /* character as one item. */
                   1165:                                        if (c == '\\') {
                   1166:                                                c = quoted(ptr,&size);
                   1167: /* -1 accounts for ++ that takes place later. */
                   1168:                                                ptr += size - 1;
                   1169:                                        }
                   1170: 
                   1171: /* If there is room, store the next character in d_message. */
                   1172:                                        if (optr < &d_message[MAXMESSAGE])
                   1173:                                                *optr++ = c;
                   1174:                                }
                   1175: 
                   1176: /* If we ended on a '#', then all is okay.  Move state to NEXTID. */
                   1177: /* If we didn't, then set state to FAILURE. */
                   1178:                                if (c == '#') {
                   1179:                                        gptr->g_message = d_message;
                   1180:                                        state = NEXTID;
                   1181: 
                   1182: /* Make sure message is null terminated. */
                   1183:                                        *optr++ = '\0';
                   1184:                                        ptr++;
                   1185:                                } else {
                   1186:                                        field = state;
                   1187:                                        state = FAILURE;
                   1188:                                }
                   1189:                                break;
                   1190: 
                   1191: /* Finally get the "g_nextid" field.  If this is successful, then */
                   1192: /* the line parsed okay. */
                   1193:                        case NEXTID:
                   1194: 
                   1195: /* Find the first word in the field and save it as the next id. */
                   1196:                                strncpy(d_nextid,getword(ptr,&size),MAXIDLENGTH);
                   1197:                                gptr->g_nextid = d_nextid;
                   1198: 
                   1199: /* There should be nothing else on the line.  Starting after the */
                   1200: /* word found, scan to end of line.  If anything beside white */
                   1201: /* space, set state to FAILURE. */
                   1202:                                ptr += size;
                   1203:                                while (isspace(*ptr)) ptr++;
                   1204:                                if (*ptr != '\0') {
                   1205:                                        field = state;
                   1206:                                        state = FAILURE;
                   1207:                                } else state = SUCCESS;
                   1208:                                break;
                   1209:                        }
                   1210:                }
                   1211: 
                   1212: /* If a line was successfully picked up and parsed, compare the */
                   1213: /* "g_id" field with the "id" we are looking for. */
                   1214:                if (state == SUCCESS) {
                   1215: 
                   1216: /* If there is an "id", compare them. */
                   1217:                        if (id != NULL) {
                   1218:                                if (strcmp(id,gptr->g_id) == 0) {
                   1219:                                        fclose(fp);
                   1220:                                        return(gptr);
                   1221:                                }
                   1222: 
                   1223: /* If there is no "id", then return this first successfully */
                   1224: /* parsed line outright. */
                   1225:                        } else if (check == FALSE) {
                   1226:                                fclose(fp);
                   1227:                                return(gptr);
                   1228: 
                   1229: /* In check mode print out the results of the parsing. */
                   1230:                        } else {
                   1231:                                fprintf(stdout,"id: %s\n",gptr->g_id);
                   1232:                                fprintf(stdout,"initial flags:\niflag- %o oflag- %o cflag- %o lflag- %o\n",
                   1233:                                        gptr->g_iflags.c_iflag,
                   1234:                                        gptr->g_iflags.c_oflag,
                   1235:                                        gptr->g_iflags.c_cflag,
                   1236:                                        gptr->g_iflags.c_lflag);
                   1237:                                fprintf(stdout,"final flags:\niflag- %o oflag- %o cflag- %o lflag- %o\n",
                   1238:                                        gptr->g_fflags.c_iflag,
                   1239:                                        gptr->g_fflags.c_oflag,
                   1240:                                        gptr->g_fflags.c_cflag,
                   1241:                                        gptr->g_fflags.c_lflag);
                   1242:                                fprintf(stdout,"message: %s\n",gptr->g_message);
                   1243:                                fprintf(stdout,"next id: %s\n",gptr->g_nextid);
                   1244:                        }
                   1245: 
                   1246: /* If parsing failed in check mode, complain, otherwise ignore */
                   1247: /* the bad line. */
                   1248:                } else if (check) {
                   1249:                        *++ptr = '\0';
                   1250:                        fprintf(stdout,"Parsing failure in the \"%s\" field\n\
                   1251: %s<--error detected here\n",
                   1252:                                states[field],line);
                   1253:                }
                   1254:        } while (input == ACTIVE);
                   1255: 
                   1256: /* If no match was found, then return NULL. */
                   1257:        fclose(fp);
                   1258:        return(NULL);
                   1259: }
                   1260: 
                   1261: char *getword(ptr,size)
                   1262: register char *ptr;
                   1263: int *size;
                   1264: {
                   1265:        register char *optr,c;
                   1266:        char quoted();
                   1267:        static char word[MAXIDLENGTH+1];
                   1268:        int qsize;
                   1269: 
                   1270: /* Skip over all white spaces including quoted spaces and tabs. */
                   1271:        for (*size=0; isspace(*ptr) || *ptr == '\\';) {
                   1272:                if (*ptr == '\\') {
                   1273:                        c = quoted(ptr,&qsize);
                   1274:                        (*size) += qsize;
                   1275:                        ptr += qsize+1;
                   1276: 
                   1277: /* If this quoted character is not a space or a tab or a newline */
                   1278: /* then break. */
                   1279:                        if (isspace(c) == 0) break;
                   1280:                } else {
                   1281:                        (*size)++;
                   1282:                        ptr++;
                   1283:                }
                   1284:        }
                   1285: 
                   1286: /* Put all characters from here to next white space or '#' or '\0' */
                   1287: /* into the word, up to the size of the word. */
                   1288:        for (optr= word,*optr='\0'; isspace(*ptr) == 0 &&
                   1289:            *ptr != '\0' && *ptr != '#'; ptr++,(*size)++) {
                   1290: 
                   1291: /* If the character is quoted, analyze it. */
                   1292:                if (*ptr == '\\') {
                   1293:                        c = quoted(ptr,&qsize);
                   1294:                        (*size) += qsize;
                   1295:                        ptr += qsize;
                   1296:                } else c = *ptr;
                   1297: 
                   1298: /* If there is room, add this character to the word. */
                   1299:                if (optr < &word[MAXIDLENGTH+1] ) *optr++ = c;
                   1300:        }
                   1301: 
                   1302: /* Make sure the line is null terminated. */
                   1303:        *optr++ = '\0';
                   1304:        return(word);
                   1305: }
                   1306: 
                   1307: /*     "quoted" takes a quoted character, starting at the quote        */
                   1308: /*     character, and returns a single character plus the size of      */
                   1309: /*     the quote string.  "quoted" recognizes the following as         */
                   1310: /*     special, \n,\r,\v,\t,\b,\f as well as the \nnn notation.        */
                   1311: 
                   1312: char quoted(ptr,qsize)
                   1313: char *ptr;
                   1314: int *qsize;
                   1315: {
                   1316:        register char c,*rptr;
                   1317:        register int i;
                   1318: 
                   1319:        rptr = ptr;
                   1320:        switch(*++rptr) {
                   1321:        case 'n':
                   1322:                c = '\n';
                   1323:                break;
                   1324:        case 'r':
                   1325:                c = '\r';
                   1326:                break;
                   1327:        case 'v':
                   1328:                c = '\013';
                   1329:                break;
                   1330:        case 'b':
                   1331:                c = '\b';
                   1332:                break;
                   1333:        case 't':
                   1334:                c = '\t';
                   1335:                break;
                   1336:        case 'f':
                   1337:                c = '\f';
                   1338:                break;
                   1339:        default:
                   1340: 
                   1341: /* If this is a numeric string, take up to three characters of */
                   1342: /* it as the value of the quoted character. */
                   1343:                if (*rptr >= '0' && *rptr <= '7') {
                   1344:                        for (i=0,c=0; i < 3;i++) {
                   1345:                                c = c*8 + (*rptr - '0');
                   1346:                                if (*++rptr < '0' || *rptr > '7') break;
                   1347:                        }
                   1348:                        rptr--;
                   1349: 
                   1350: /* If the character following the '\\' is a NULL, back up the */
                   1351: /* ptr so that the NULL won't be missed.  The sequence */
                   1352: /* backslash null is essentually illegal. */
                   1353:                } else if (*rptr == '\0') {
                   1354:                        c = '\0';
                   1355:                        rptr--;
                   1356: 
                   1357: /* In all other cases the quoting does nothing. */
                   1358:                } else c = *rptr;
                   1359:                break;
                   1360:        }
                   1361: 
                   1362: /* Compute the size of the quoted character. */
                   1363:        (*qsize) = rptr - ptr + 1;
                   1364:        return(c);
                   1365: }
                   1366: 
                   1367: /*     "fields" picks up the words in the next field and converts all  */
                   1368: /*     recognized words into the proper mask and puts it in the target */
                   1369: /*     field.                                                          */
                   1370: 
                   1371: char *fields(ptr,termio)
                   1372: register char *ptr;
                   1373: struct termio *termio;
                   1374: {
                   1375:        extern struct Symbols imodes[],omodes[],cmodes[],lmodes[];
                   1376:        extern struct Symbols *search();
                   1377:        register struct Symbols *symbol;
                   1378:        char *word,*getword();
                   1379:        int size;
                   1380:        extern int check;
                   1381: 
                   1382:        termio->c_iflag = 0;
                   1383:        termio->c_oflag = 0;
                   1384:        termio->c_cflag = 0;
                   1385:        termio->c_lflag = 0;
                   1386:        while (*ptr != '#' && *ptr != '\0') {
                   1387: 
                   1388: /* Pick up the next word in the sequence. */
                   1389:                word = getword(ptr,&size);
                   1390: 
                   1391: /* If there is a word, scan the two mode tables for it. */
                   1392:                if (*word != '\0') {
                   1393: 
                   1394: /* If the word is the special word "SANE", put in all the flags */
                   1395: /* that are needed for SANE tty behavior. */
                   1396:                        if (strcmp(word,"SANE") == 0) {
                   1397:                                termio->c_iflag |= ISANE;
                   1398:                                termio->c_oflag |= OSANE;
                   1399:                                termio->c_cflag |= CSANE;
                   1400:                                termio->c_lflag |= LSANE;
                   1401:                        } else if ((symbol = search(word,imodes)) != NULL)
                   1402:                                termio->c_iflag |= symbol->s_value;
                   1403:                        else if ((symbol = search(word,omodes)) != NULL)
                   1404:                                termio->c_oflag |= symbol->s_value;
                   1405:                        else if ((symbol = search(word,cmodes)) != NULL)
                   1406:                                termio->c_cflag |= symbol->s_value;
                   1407:                        else if ((symbol = search(word,lmodes)) != NULL)
                   1408:                                termio->c_lflag |= symbol->s_value;
                   1409:                        else if (check) fprintf(stdout,"Undefined: %s\n",word);
                   1410:                }
                   1411: 
                   1412: /* Advance pointer to after the word. */
                   1413:                ptr += size;
                   1414:        }
                   1415: 
                   1416: /* If we didn't end on a '#', return NULL, otherwise return the */
                   1417: /* updated pointer. */
                   1418:        return(*ptr != '#' ? NULL : ptr);
                   1419: }
                   1420: 
                   1421: /*     "parse" breaks up the user's response into seperate arguments   */
                   1422: /*     and fills the supplied array with those arguments.  Quoting     */
                   1423: /*     with the backspace is allowed.                                  */
                   1424: 
                   1425: parse(string,args,cnt)
                   1426: char *string,**args;
                   1427: int cnt;
                   1428: {
                   1429:        register char *ptrin,*ptrout;
                   1430:        register int i;
                   1431:        extern char quoted();
                   1432:        int qsize;
                   1433: 
                   1434:        for (i=0; i < cnt; i++) args[i] = (char *)NULL;
                   1435:        for (ptrin = ptrout = string,i=0; *ptrin != '\0' && i < cnt; i++) {
                   1436: 
                   1437: /* Skip excess white spaces between arguments. */
                   1438:                while(*ptrin == ' ' || *ptrin == '\t') {
                   1439:                        ptrin++;
                   1440:                        ptrout++;
                   1441:                }
                   1442: 
                   1443: /* Save the address of the argument if there is something there. */
                   1444:                if (*ptrin == '\0') break;
                   1445:                else args[i] = ptrout;
                   1446: 
                   1447: /* Span the argument itself.  The '\' character causes quoting */
                   1448: /* of the next character to take place (except for '\0'). */
                   1449:                while (*ptrin != '\0') {
                   1450: 
                   1451: /* Is this the quote character? */
                   1452:                        if (*ptrin == '\\') {
                   1453:                                *ptrout++ = quoted(ptrin,&qsize);
                   1454:                                ptrin += qsize;
                   1455: 
                   1456: /* Is this the end of the argument?  If so quit loop. */
                   1457:                        } else if (*ptrin == ' ' || *ptrin == '\t') {
                   1458:                                ptrin++;
                   1459:                                break;
                   1460: 
                   1461: /* If this is a normal letter of the argument, save it, advancing */
                   1462: /* the pointers at the same time. */
                   1463:                        } else *ptrout++ = *ptrin++;
                   1464:                }
                   1465: 
                   1466: /* Null terminate the string. */
                   1467:                *ptrout++ = '\0';
                   1468:        }
                   1469: }
                   1470: 
                   1471: FILE *fdup(fp)
                   1472: register FILE *fp;
                   1473: {
                   1474:        register int newfd;
                   1475:        register char *mode;
                   1476: 
                   1477: /* Dup the file descriptor for the specified stream and then */
                   1478: /* convert it to a stream pointer with the modes of the original */
                   1479: /* stream pointer. */
                   1480:        if ((newfd = dup(fileno(fp))) != FAILURE) {
                   1481: 
                   1482: /* Determine the proper mode.  If the old file was _IORW, then */
                   1483: /* use the "r+" option, if _IOREAD, the "r" option, or if _IOWRT */
                   1484: /* the "w" option.  Note that since none of these force an lseek */
                   1485: /* by "fdopen", the dupped file pointer will be at the same spot */
                   1486: /* as the original. */
                   1487:                if (fp->_flag & _IORW) mode = "r+";
                   1488:                else if (fp->_flag & _IOREAD) mode = "r";
                   1489:                else if (fp->_flag & _IOWRT) mode = "w";
                   1490: 
                   1491: /* Something is wrong, close dupped descriptor and return NULL. */
                   1492:                else {
                   1493:                        close(newfd);
                   1494:                        return(NULL);
                   1495:                }
                   1496: 
                   1497: /* Now have fdopen finish the job of establishing a new file pointer. */
                   1498:                return(fdopen(newfd,mode));
                   1499:        } else return(NULL);
                   1500: }
                   1501: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.