1: # 2: /* 3: * @(#)getty.c 1.5 -- adapt to terminal speed on dialup, and call login 4: */ 5: #include <whoami.h> 6: #include <sgtty.h> 7: #include <signal.h> 8: #include <sys/types.h> 9: #include <sys/file.h> 10: 11: #define IDENT "/etc/ident" /* contains login banner for sys */ 12: 13: #define SP_SESS /* "special session"-- root logins only */ 14: #define DO_CRTBS /* allow backspace as erase; stty erase if >2400 baud */ 15: 16: #define ERASE '#' 17: #define KILL '@' 18: #define CNTL(x) ('x'&037) 19: #define DEL '\177' 20: #define UNDEF '\377' 21: 22: struct sgttyb tmode; 23: struct tchars tchars = 24: { DEL, CNTL(\\), CNTL(Q), CNTL(S), CNTL(D), UNDEF 25: }; 26: #ifdef UCB_NTTY 27: struct ltchars ltc = 28: { CNTL(z), CNTL(y), CNTL(r), CNTL(o), CNTL(w), CNTL(v) 29: }; 30: #endif 31: 32: struct tab { 33: char tname; /* this table name */ 34: char nname; /* successor table name */ 35: int iflags; /* initial flags */ 36: int fflags; /* final flags */ 37: int ispeed; /* input speed */ 38: int ospeed; /* output speed */ 39: char *message; /* login message */ 40: } itab[] = { 41: 42: /* table '0'-1-2-3 300,1200,150,110 */ 43: 44: '0', 1, 45: ANYP+RAW+NL1+CR1, ANYP+ECHO+CR1, 46: B300, B300, 47: "\n\r\033;\007login: ", 48: 49: 1, 2, 50: ANYP+RAW+NL1+CR1, ANYP+XTABS+ECHO+CRMOD+FF1, 51: B1200, B1200, 52: "\n\r\033;login: ", 53: 54: 2, 3, 55: ANYP+RAW+NL1+CR1, EVENP+ECHO+FF1+CR2+TAB1+NL1, 56: B150, B150, 57: "\n\r\033:\006\006\017login: ", 58: 59: 3, '0', 60: ANYP+RAW+NL1+CR1, ANYP+ECHO+CRMOD+XTABS+LCASE+CR1, 61: B110, B110, 62: "\n\r:login: ", 63: 64: /* table '-' -- Console TTY 110 */ 65: '-', '-', 66: ANYP+RAW+NL1+CR1, ANYP+ECHO+CRMOD+XTABS+LCASE+CR1, 67: B110, B110, 68: "\n\r:login: ", 69: 70: /* table '1' -- 150 */ 71: '1', '1', 72: ANYP+RAW+NL1+CR1, EVENP+ECHO+FF1+CR2+TAB1+NL1, 73: B150, B150, 74: "\n\r\033:\006\006\017login: ", 75: 76: /* table '2' -- 9600 */ 77: '2', '2', 78: ANYP+RAW+NL1+CR1, ANYP+XTABS+ECHO+CRMOD, 79: B9600, B9600, 80: "\n\r;login: ", 81: 82: /* table '3'-'5' -- 1200,300 */ 83: '3', '5', 84: ANYP+RAW+NL1+CR1, ANYP+XTABS+ECHO+CRMOD+FF1, 85: B1200, B1200, 86: "\n\r:login: ", 87: 88: /* table '5'-'3' -- 300,1200 */ 89: '5', '3', 90: ANYP+RAW+NL1+CR1, ANYP+ECHO+CR1+XTABS, 91: B300, B300, 92: "\n\r:login: ", 93: 94: /* table '4' -- Console Decwriter */ 95: '4', '4', 96: ANYP+RAW+NL1+CR2, ANYP+ECHO+CRMOD+XTABS+CR2, 97: B300, B300, 98: "\n\r:login: ", 99: 100: /* table '6' -- 1200 */ 101: '6', '6', 102: ANYP+RAW+NL1+CR1, ANYP+XTABS+ECHO+CRMOD, 103: B1200, B1200, 104: "\n\r;login: ", 105: 106: /* table '7' -- 2400 */ 107: '7', '7', 108: ANYP+RAW+NL1+CR1, ANYP+XTABS+ECHO+CRMOD, 109: B2400, B2400, 110: "\n\r;login: ", 111: 112: /* table '8' -- 4800 */ 113: '8', '8', 114: ANYP+RAW+NL1+CR1, ANYP+XTABS+ECHO+CRMOD, 115: B4800, B4800, 116: "\n\r;login: ", 117: 118: /* table '9' -- 9600 */ 119: '9', '9', 120: ANYP+RAW+NL1+CR1, ANYP+XTABS+ECHO+CRMOD, 121: B9600, B9600, 122: "\n\r;login: ", 123: 124: /* table 'i' -- Interdata Console */ 125: 'i', 'i', 126: RAW+CRMOD, CRMOD+ECHO+LCASE, 127: 0, 0, 128: "\n\r:login: ", 129: 130: #ifdef TEXAS_AUTOBAUD 131: /* table 'B' -- Do autobauding */ 132: 133: #define NTRIES 5 134: #define WAITSEC 60 135: #define TB_AUTOBAUD 'B' 136: TB_AUTOBAUD, TB_AUTOBAUD, 137: ANYP+RAW, ANYP+XTABS+ECHO+CRMOD, 138: B9600, B9600, 139: "\n\r;login: ", 140: #endif 141: 142: /* table 'T' -- 9600 tektronix 4014 */ 143: 'T', 'T', 144: ANYP+RAW+NL1+CR1, ANYP+XTABS+ECHO+CRMOD+FF1, 145: B9600, B9600, 146: "\n\r\033;login: ", 147: }; 148: 149: #define NITAB sizeof itab/sizeof itab[0] 150: #define EOT 04 /* EOT char */ 151: 152: char name[16]; 153: int crmod; 154: int upper; 155: int lower; 156: #ifdef DO_CRTBS 157: int can_erase; 158: #endif 159: #ifdef SP_SESS 160: int sp_sess = { 0 }; /* flag special session */ 161: #endif 162: 163: char partab[] = { 164: 0001,0201,0201,0001,0201,0001,0001,0201, 165: 0202,0004,0003,0205,0005,0206,0201,0001, 166: 0201,0001,0001,0201,0001,0201,0201,0001, 167: 0001,0201,0201,0001,0201,0001,0001,0201, 168: 0200,0000,0000,0200,0000,0200,0200,0000, 169: 0000,0200,0200,0000,0200,0000,0000,0200, 170: 0000,0200,0200,0000,0200,0000,0000,0200, 171: 0200,0000,0000,0200,0000,0200,0200,0000, 172: 0200,0000,0000,0200,0000,0200,0200,0000, 173: 0000,0200,0200,0000,0200,0000,0000,0200, 174: 0000,0200,0200,0000,0200,0000,0000,0200, 175: 0200,0000,0000,0200,0000,0200,0200,0000, 176: 0000,0200,0200,0000,0200,0000,0000,0200, 177: 0200,0000,0000,0200,0000,0200,0200,0000, 178: 0200,0000,0000,0200,0000,0200,0200,0000, 179: 0000,0200,0200,0000,0200,0000,0000,0201 180: }; 181: 182: main(argc, argv) 183: char **argv; 184: { 185: register struct tab *tabp; 186: int tname; 187: int ldisc; 188: int bf; 189: #ifdef UCB_NTTY 190: int lmode = 0; 191: #endif 192: 193: ldisc = DFLT_LDISC; 194: ioctl(0, TIOCSETD, &ldisc); 195: #ifdef UCB_NTTY 196: ioctl(0, TIOCLSET, &lmode); 197: ioctl(0, TIOCSLTC, <c); 198: #endif 199: ioctl(0, TIOCSETC, &tchars); 200: 201: tname = '0'; 202: #ifdef SP_SESS 203: /* 204: * If we are called with a "+" name, flag special session. 205: */ 206: if(argv[0][0] == '+') 207: sp_sess++; 208: #endif 209: 210: if (argc > 1) 211: tname = argv[1][0]; 212: 213: 214: switch (tname) { 215: 216: /* 217: * If hardware has decoded high speed (or line is open), 218: * get the line speed. 219: */ 220: case '5': 221: ioctl(0,TIOCGETP, &tmode); 222: if (tmode.sg_ispeed == B1200) 223: tname = '3'; 224: break; 225: 226: #ifdef DO_CRTBS 227: /* 228: * Hard-wired crt ports (2400-9600 baud) 229: * allow use of backspace-erase. 230: */ 231: case '7': 232: case '8': 233: case '9': 234: can_erase++; 235: lmode = LCRTERA | LCRTBS; 236: ioctl(0, TIOCLSET, &lmode); 237: break; 238: #endif 239: } 240: for (;;) { 241: for(tabp = itab; tabp < &itab[NITAB]; tabp++) 242: if(tabp->tname == tname) 243: break; 244: if(tabp >= &itab[NITAB]) 245: tabp = itab; 246: tmode.sg_flags = tabp->iflags; 247: tmode.sg_ispeed = tabp->ispeed; 248: tmode.sg_ospeed = tabp->ospeed; 249: ioctl(0, TIOCSETP, &tmode); 250: ioctl(0, TIOCSETC, &tchars); 251: #ifdef TEXAS_AUTOBAUD 252: if ((tabp->tname == TB_AUTOBAUD) && set_baud_rate()) 253: { /* autobaud line */ 254: ioctl(0, TIOCGETP, &tmode); /* pick up baud rate */ 255: ioctl(0, TIOCSETP, &tmode); /* flush input */ 256: } 257: #endif 258: 259: if(tmode.sg_ospeed > B1200) 260: puts("\n\r"); 261: else 262: puts("\n\r\r\r\r\r\n\r\r\r\r\r"); 263: if ((bf = open(IDENT, FATT_RDONLY)) > 0) { 264: char buf[81]; 265: int i; 266: register char *s; 267: while ((i = read(bf, buf, sizeof (buf) - 1)) > 0) { 268: buf[i] = 0; 269: for (s = buf; *s; s++) { 270: if (*s == '\n') 271: putchr('\r'); 272: putchr(*s); 273: } 274: } 275: close(bf); 276: } 277: #ifdef SP_SESS 278: if(sp_sess) 279: puts("\n\r\r\r>>> Unix Maintenance Mode <<<"); 280: #endif 281: puts(tabp->message); 282: /* 283: * wait, then flush input to get rid 284: * of line noise 285: */ 286: sleep(1); 287: ioctl(0, TIOCSETP, &tmode); 288: if(getname()) { 289: if(upper==0 && lower==0) 290: continue; 291: #ifdef DO_CRTBS 292: tmode.sg_erase = can_erase? '\b': ERASE; 293: #else 294: tmode.sg_erase = ERASE; 295: #endif 296: tmode.sg_kill = KILL; 297: tmode.sg_flags = tabp->fflags; 298: if(crmod) 299: tmode.sg_flags |= CRMOD; 300: if(upper) 301: tmode.sg_flags |= LCASE; 302: if(lower) 303: tmode.sg_flags &= ~LCASE; 304: ioctl(0, TIOCSETP, &tmode); 305: putchr('\n'); 306: #ifdef SP_SESS 307: if(sp_sess) 308: execl("/bin/login", "slogin", name, 0); 309: #endif 310: execl("/bin/login", "login", name, 0); 311: exit(1); 312: } 313: tname = tabp->nname; 314: } 315: } 316: 317: getname() 318: { 319: register char *np; 320: register c; 321: char cs; 322: 323: crmod = 0; 324: upper = 0; 325: lower = 0; 326: np = name; 327: for (;;) { 328: if (read(0, &cs, 1) <= 0) 329: exit(0); 330: if ((c = cs&0177) == 0) 331: return(0); 332: if (c==EOT) 333: exit(1); 334: if (c=='\r' || c=='\n' || np >= &name[16]) 335: break; 336: #ifdef DO_CRTBS 337: if (c != '\b') 338: #endif 339: putchr(cs); 340: if (c>='a' && c <='z') 341: lower++; 342: else if (c>='A' && c<='Z') { 343: upper++; 344: c += 'a'-'A'; 345: #ifdef DO_CRTBS 346: } else if (c=='\b') { 347: if (np > name) { 348: np--; 349: puts("\b \b"); 350: } 351: continue; 352: #endif 353: } else if (c==ERASE) { 354: if (np > name) 355: np--; 356: continue; 357: } else if (c==KILL) { 358: putchr('\r'); 359: putchr('\n'); 360: np = name; 361: continue; 362: } else if(c == ' ') 363: c = '_'; 364: *np++ = c; 365: } 366: *np = 0; 367: if (c == '\r') 368: crmod++; 369: return(1); 370: } 371: 372: puts(as) 373: char *as; 374: { 375: register char *s; 376: 377: s = as; 378: while (*s) 379: putchr(*s++); 380: } 381: 382: putchr(cc) 383: { 384: char c; 385: c = cc; 386: c |= partab[c&0177] & 0200; 387: write(1, &c, 1); 388: } 389: 390: #ifdef TEXAS_AUTOBAUD 391: 392: /* Autobauding tables */ 393: struct match 394: { 395: char m_char; /* bit pattern to look for */ 396: char m_mask; /* bits to ignore in input character */ 397: short m_speed; /* what speed to set if matched */ 398: }; 399: 400: struct match match[] = { /* cr,int */ 401: { 0xfc, 0x03, B9600 }, /* 111111xx (cr,int) */ 402: { 0x0d, 0x80, B4800 }, /* x0001101 (cr) */ 403: { 0x03, 0x80, B4800 }, /* x0000011 (int) */ 404: { 0xe6, 0x00, B2400 }, /* 11100110 (cr) */ 405: { 0x1e, 0x00, B2400 }, /* 00011110 (int) */ 406: { 0x8c, 0x12, B1800 }, /* 100x11x0 (cr) */ 407: { 0x7c, 0x02, B1800 }, /* 011111x0 (int) */ 408: { 0x78, 0x80, B1200 }, /* x1111000 (cr,int) */ 409: { 0x80, 0x00, B600 }, /* 10000000 (cr,int) */ 410: { 0x00, 0x00, B300 }, /* 00000000 (cr,int) */ 411: { 0, 0, 0 } 412: }; 413: 414: /* Determine baud rate of terminal line 415: * Rich Wales (UCLA), June 1982 416: * 417: * Determine the baud rate of a terminal from a single 418: * carriage-return or ^C. It can identify 300, 600, 1200, 1800, 2400, 419: * 4800, and 9600 baud. 420: * 421: * If the new speed is below 2400 baud, it is advisable to do a "sleep" 422: * before the "ioctl". This allows any extra garbage from the input to 423: * make it from the multiplexer (DH or DZ) to the kernel input queue, 424: * where the speed change will cause it to be flushed. 425: */ 426: timeout() 427: { 428: puts("\7Connection timed out.\n\r"); 429: exit(1); 430: }; 431: 432: set_baud_rate() 433: { 434: register struct match *m; 435: register int i; 436: int lmode; 437: struct sgttyb sv, st; 438: char c; 439: 440: /* save current TTY mode, set new mode */ 441: ioctl(0, TIOCGETP, &sv); 442: st = sv; 443: st.sg_flags = RAW | ANYP; 444: ioctl(0, TIOCLGET, &lmode); 445: st.sg_ispeed = st.sg_ospeed = B4800; 446: ioctl(0, TIOCSETP, &st); 447: ioctl(0, TIOCLSET, &lmode); 448: if (ioctl(0, TIOCSIMG, 0) < 0) 449: return(0); 450: alarm(0); 451: for (i=0; i < NTRIES; i++) { 452: /* read a character and try to match it */ 453: signal(14,timeout); 454: alarm(WAITSEC); 455: read(0,&c,1); 456: alarm(0); 457: c &= 0377; 458: for (m = match; m->m_speed != 0; m++) { 459: if ((c &~ m->m_mask) == m->m_char) { 460: /* success -- restore old modes, but with new speed */ 461: sv.sg_ispeed = sv.sg_ospeed = m->m_speed; 462: if (sv.sg_ispeed < B2400) 463: sleep(1); 464: ioctl(0, TIOCCIMG, 0); 465: ioctl(0, TIOCSETP, &sv); 466: ioctl(0, TIOCLSET, &lmode); 467: return(1); 468: } 469: } 470: } 471: /* no match -- restore old modes */ 472: sleep(1); 473: ioctl(0, TIOCCIMG, 0); 474: ioctl(0, TIOCSETP, &sv); 475: ioctl(0, TIOCLSET, &lmode); 476: return(0); 477: } 478: #endif