|
|
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:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.