1 /*-
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * %sccs.include.redist.c%
6 */
7
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1993\n\
11 The Regents of the University of California. All rights reserved.\n";
12 #endif /* not lint */
13
14 #ifndef lint
15 static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 06/20/93";
16 #endif /* not lint */
17
18 #define USE_OLD_TTY
19
20 #include <sys/param.h>
21 #include <sys/stat.h>
22 #include <sys/resource.h>
23
24 #include <ctype.h>
25 #include <ctype.h>
26 #include <fcntl.h>
27 #include <setjmp.h>
28 #include <sgtty.h>
29 #include <signal.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <syslog.h>
33 #include <time.h>
34 #include <unistd.h>
35
36 #include "gettytab.h"
37 #include "pathnames.h"
38 #include "extern.h"
39
40 /*
41 * Set the amount of running time that getty should accumulate
42 * before deciding that something is wrong and exit.
43 */
44 #define GETTY_TIMEOUT 60 /* seconds */
45
46 struct sgttyb tmode = {
47 0, 0, CERASE, CKILL, 0
48 };
49 struct tchars tc = {
50 CINTR, CQUIT, CSTART,
51 CSTOP, CEOF, CBRK,
52 };
53 struct ltchars ltc = {
54 CSUSP, CDSUSP, CRPRNT,
55 CFLUSH, CWERASE, CLNEXT
56 };
57
58 int crmod, digit, lower, upper;
59
60 char hostname[MAXHOSTNAMELEN];
61 char name[16];
62 char dev[] = _PATH_DEV;
63 char ttyn[32];
64 char *portselector();
65 char *ttyname();
66
67 #define OBUFSIZ 128
68 #define TABBUFSIZ 512
69
70 char defent[TABBUFSIZ];
71 char tabent[TABBUFSIZ];
72
73 char *env[128];
74
75 char partab[] = {
76 0001,0201,0201,0001,0201,0001,0001,0201,
77 0202,0004,0003,0205,0005,0206,0201,0001,
78 0201,0001,0001,0201,0001,0201,0201,0001,
79 0001,0201,0201,0001,0201,0001,0001,0201,
80 0200,0000,0000,0200,0000,0200,0200,0000,
81 0000,0200,0200,0000,0200,0000,0000,0200,
82 0000,0200,0200,0000,0200,0000,0000,0200,
83 0200,0000,0000,0200,0000,0200,0200,0000,
84 0200,0000,0000,0200,0000,0200,0200,0000,
85 0000,0200,0200,0000,0200,0000,0000,0200,
86 0000,0200,0200,0000,0200,0000,0000,0200,
87 0200,0000,0000,0200,0000,0200,0200,0000,
88 0000,0200,0200,0000,0200,0000,0000,0200,
89 0200,0000,0000,0200,0000,0200,0200,0000,
90 0200,0000,0000,0200,0000,0200,0200,0000,
91 0000,0200,0200,0000,0200,0000,0000,0201
92 };
93
94 #define ERASE tmode.sg_erase
95 #define KILL tmode.sg_kill
96 #define EOT tc.t_eofc
97
98 jmp_buf timeout;
99
100 static void
dingdong()101 dingdong()
102 {
103
104 alarm(0);
105 signal(SIGALRM, SIG_DFL);
106 longjmp(timeout, 1);
107 }
108
109 jmp_buf intrupt;
110
111 static void
interrupt()112 interrupt()
113 {
114
115 signal(SIGINT, interrupt);
116 longjmp(intrupt, 1);
117 }
118
119 /*
120 * Action to take when getty is running too long.
121 */
122 void
timeoverrun(signo)123 timeoverrun(signo)
124 int signo;
125 {
126
127 syslog(LOG_ERR, "getty exiting due to excessive running time\n");
128 exit(1);
129 }
130
131 static int getname __P((void));
132 static void oflush __P((void));
133 static void prompt __P((void));
134 static void putchr __P((int));
135 static void putf __P((char *));
136 static void putpad __P((char *));
137 static void puts __P((char *));
138
139 int
main(argc,argv)140 main(argc, argv)
141 int argc;
142 char *argv[];
143 {
144 extern char **environ;
145 char *tname;
146 long allflags;
147 int repcnt = 0;
148 struct rlimit limit;
149
150 signal(SIGINT, SIG_IGN);
151 /*
152 signal(SIGQUIT, SIG_DFL);
153 */
154 openlog("getty", LOG_ODELAY|LOG_CONS, LOG_AUTH);
155 gethostname(hostname, sizeof(hostname));
156 if (hostname[0] == '\0')
157 strcpy(hostname, "Amnesiac");
158
159 /*
160 * Limit running time to deal with broken or dead lines.
161 */
162 (void)signal(SIGXCPU, timeoverrun);
163 limit.rlim_max = RLIM_INFINITY;
164 limit.rlim_cur = GETTY_TIMEOUT;
165 (void)setrlimit(RLIMIT_CPU, &limit);
166
167 /*
168 * The following is a work around for vhangup interactions
169 * which cause great problems getting window systems started.
170 * If the tty line is "-", we do the old style getty presuming
171 * that the file descriptors are already set up for us.
172 * J. Gettys - MIT Project Athena.
173 */
174 if (argc <= 2 || strcmp(argv[2], "-") == 0)
175 strcpy(ttyn, ttyname(0));
176 else {
177 int i;
178
179 strcpy(ttyn, dev);
180 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
181 if (strcmp(argv[0], "+") != 0) {
182 chown(ttyn, 0, 0);
183 chmod(ttyn, 0600);
184 revoke(ttyn);
185 /*
186 * Delay the open so DTR stays down long enough to be detected.
187 */
188 sleep(2);
189 while ((i = open(ttyn, O_RDWR)) == -1) {
190 if (repcnt % 10 == 0) {
191 syslog(LOG_ERR, "%s: %m", ttyn);
192 closelog();
193 }
194 repcnt++;
195 sleep(60);
196 }
197 login_tty(i);
198 }
199 }
200
201 gettable("default", defent);
202 gendefaults();
203 tname = "default";
204 if (argc > 1)
205 tname = argv[1];
206 for (;;) {
207 int off;
208
209 gettable(tname, tabent);
210 if (OPset || EPset || APset)
211 APset++, OPset++, EPset++;
212 setdefaults();
213 off = 0;
214 ioctl(0, TIOCFLUSH, &off); /* clear out the crap */
215 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */
216 ioctl(0, FIOASYNC, &off); /* ditto for async mode */
217 if (IS)
218 tmode.sg_ispeed = speed(IS);
219 else if (SP)
220 tmode.sg_ispeed = speed(SP);
221 if (OS)
222 tmode.sg_ospeed = speed(OS);
223 else if (SP)
224 tmode.sg_ospeed = speed(SP);
225 tmode.sg_flags = setflags(0);
226 ioctl(0, TIOCSETP, &tmode);
227 setchars();
228 ioctl(0, TIOCSETC, &tc);
229 if (HC)
230 ioctl(0, TIOCHPCL, 0);
231 if (AB) {
232 extern char *autobaud();
233
234 tname = autobaud();
235 continue;
236 }
237 if (PS) {
238 tname = portselector();
239 continue;
240 }
241 if (CL && *CL)
242 putpad(CL);
243 edithost(HE);
244 if (IM && *IM)
245 putf(IM);
246 if (setjmp(timeout)) {
247 tmode.sg_ispeed = tmode.sg_ospeed = 0;
248 ioctl(0, TIOCSETP, &tmode);
249 exit(1);
250 }
251 if (TO) {
252 signal(SIGALRM, dingdong);
253 alarm(TO);
254 }
255 if (getname()) {
256 register int i;
257
258 oflush();
259 alarm(0);
260 signal(SIGALRM, SIG_DFL);
261 if (name[0] == '-') {
262 puts("user names may not start with '-'.");
263 continue;
264 }
265 if (!(upper || lower || digit))
266 continue;
267 allflags = setflags(2);
268 tmode.sg_flags = allflags & 0xffff;
269 allflags >>= 16;
270 if (crmod || NL)
271 tmode.sg_flags |= CRMOD;
272 if (upper || UC)
273 tmode.sg_flags |= LCASE;
274 if (lower || LC)
275 tmode.sg_flags &= ~LCASE;
276 ioctl(0, TIOCSETP, &tmode);
277 ioctl(0, TIOCSLTC, <c);
278 ioctl(0, TIOCLSET, &allflags);
279 signal(SIGINT, SIG_DFL);
280 for (i = 0; environ[i] != (char *)0; i++)
281 env[i] = environ[i];
282 makeenv(&env[i]);
283
284 /*
285 * this is what login was doing anyway.
286 * soon we rewrite getty completely.
287 */
288 set_ttydefaults(0);
289 limit.rlim_max = RLIM_INFINITY;
290 limit.rlim_cur = RLIM_INFINITY;
291 (void)setrlimit(RLIMIT_CPU, &limit);
292 execle(LO, "login", "-p", name, (char *) 0, env);
293 syslog(LOG_ERR, "%s: %m", LO);
294 exit(1);
295 }
296 alarm(0);
297 signal(SIGALRM, SIG_DFL);
298 signal(SIGINT, SIG_IGN);
299 if (NX && *NX)
300 tname = NX;
301 }
302 }
303
304 static int
getname()305 getname()
306 {
307 register int c;
308 register char *np;
309 char cs;
310
311 /*
312 * Interrupt may happen if we use CBREAK mode
313 */
314 if (setjmp(intrupt)) {
315 signal(SIGINT, SIG_IGN);
316 return (0);
317 }
318 signal(SIGINT, interrupt);
319 tmode.sg_flags = setflags(0);
320 ioctl(0, TIOCSETP, &tmode);
321 tmode.sg_flags = setflags(1);
322 prompt();
323 if (PF > 0) {
324 oflush();
325 sleep(PF);
326 PF = 0;
327 }
328 ioctl(0, TIOCSETP, &tmode);
329 crmod = digit = lower = upper = 0;
330 np = name;
331 for (;;) {
332 oflush();
333 if (read(STDIN_FILENO, &cs, 1) <= 0)
334 exit(0);
335 if ((c = cs&0177) == 0)
336 return (0);
337 if (c == EOT)
338 exit(1);
339 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
340 putf("\r\n");
341 break;
342 }
343 if (islower(c))
344 lower = 1;
345 else if (isupper(c))
346 upper = 1;
347 else if (c == ERASE || c == '#' || c == '\b') {
348 if (np > name) {
349 np--;
350 if (tmode.sg_ospeed >= B1200)
351 puts("\b \b");
352 else
353 putchr(cs);
354 }
355 continue;
356 } else if (c == KILL || c == '@') {
357 putchr(cs);
358 putchr('\r');
359 if (tmode.sg_ospeed < B1200)
360 putchr('\n');
361 /* this is the way they do it down under ... */
362 else if (np > name)
363 puts(" \r");
364 prompt();
365 np = name;
366 continue;
367 } else if (isdigit(c))
368 digit++;
369 if (IG && (c <= ' ' || c > 0176))
370 continue;
371 *np++ = c;
372 putchr(cs);
373 }
374 signal(SIGINT, SIG_IGN);
375 *np = 0;
376 if (c == '\r')
377 crmod = 1;
378 if (upper && !lower && !LC || UC)
379 for (np = name; *np; np++)
380 if (isupper(*np))
381 *np = tolower(*np);
382 return (1);
383 }
384
385 static
386 short tmspc10[] = {
387 0, 2000, 1333, 909, 743, 666, 500, 333, 166, 83, 55, 41, 20, 10, 5, 15
388 };
389
390 static void
putpad(s)391 putpad(s)
392 register char *s;
393 {
394 register pad = 0;
395 register mspc10;
396
397 if (isdigit(*s)) {
398 while (isdigit(*s)) {
399 pad *= 10;
400 pad += *s++ - '0';
401 }
402 pad *= 10;
403 if (*s == '.' && isdigit(s[1])) {
404 pad += s[1] - '0';
405 s += 2;
406 }
407 }
408
409 puts(s);
410 /*
411 * If no delay needed, or output speed is
412 * not comprehensible, then don't try to delay.
413 */
414 if (pad == 0)
415 return;
416 if (tmode.sg_ospeed <= 0 ||
417 tmode.sg_ospeed >= (sizeof tmspc10 / sizeof tmspc10[0]))
418 return;
419
420 /*
421 * Round up by a half a character frame, and then do the delay.
422 * Too bad there are no user program accessible programmed delays.
423 * Transmitting pad characters slows many terminals down and also
424 * loads the system.
425 */
426 mspc10 = tmspc10[tmode.sg_ospeed];
427 pad += mspc10 / 2;
428 for (pad /= mspc10; pad > 0; pad--)
429 putchr(*PC);
430 }
431
432 static void
puts(s)433 puts(s)
434 register char *s;
435 {
436 while (*s)
437 putchr(*s++);
438 }
439
440 char outbuf[OBUFSIZ];
441 int obufcnt = 0;
442
443 static void
putchr(cc)444 putchr(cc)
445 int cc;
446 {
447 char c;
448
449 c = cc;
450 if (!NP) {
451 c |= partab[c&0177] & 0200;
452 if (OP)
453 c ^= 0200;
454 }
455 if (!UB) {
456 outbuf[obufcnt++] = c;
457 if (obufcnt >= OBUFSIZ)
458 oflush();
459 } else
460 write(STDOUT_FILENO, &c, 1);
461 }
462
463 static void
oflush()464 oflush()
465 {
466 if (obufcnt)
467 write(STDOUT_FILENO, outbuf, obufcnt);
468 obufcnt = 0;
469 }
470
471 static void
prompt()472 prompt()
473 {
474
475 putf(LM);
476 if (CO)
477 putchr('\n');
478 }
479
480 static void
putf(cp)481 putf(cp)
482 register char *cp;
483 {
484 extern char editedhost[];
485 time_t t;
486 char *slash, db[100];
487
488 while (*cp) {
489 if (*cp != '%') {
490 putchr(*cp++);
491 continue;
492 }
493 switch (*++cp) {
494
495 case 't':
496 slash = strrchr(ttyn, '/');
497 if (slash == (char *) 0)
498 puts(ttyn);
499 else
500 puts(&slash[1]);
501 break;
502
503 case 'h':
504 puts(editedhost);
505 break;
506
507 case 'd': {
508 static char fmt[] = "%l:% %P on %A, %d %B %Y";
509
510 fmt[4] = 'M'; /* I *hate* SCCS... */
511 (void)time(&t);
512 (void)strftime(db, sizeof(db), fmt, localtime(&t));
513 puts(db);
514 break;
515 }
516
517 case '%':
518 putchr('%');
519 break;
520 }
521 cp++;
522 }
523 }
524