Annotation of researchv10no/cmd/uucp/unused/uugetty.c, revision 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.