main.c revision 1.20 1 /* $NetBSD: main.c,v 1.20 1997/04/29 21:01:54 tls Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #ifndef lint
37 static char copyright[] =
38 "@(#) Copyright (c) 1980, 1993\n\
39 The Regents of the University of California. All rights reserved.\n";
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "from: @(#)main.c 8.1 (Berkeley) 6/20/93";
45 #else
46 static char rcsid[] = "$NetBSD: main.c,v 1.20 1997/04/29 21:01:54 tls Exp $";
47 #endif
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <termios.h>
53 #include <sys/ioctl.h>
54 #include <sys/resource.h>
55 #include <sys/utsname.h>
56 #include <errno.h>
57 #include <signal.h>
58 #include <fcntl.h>
59 #include <time.h>
60 #include <ctype.h>
61 #include <fcntl.h>
62 #include <setjmp.h>
63 #include <signal.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <syslog.h>
67 #include <time.h>
68 #include <unistd.h>
69 #include <util.h>
70
71 #include "gettytab.h"
72 #include "pathnames.h"
73 #include "extern.h"
74
75 /*
76 * Set the amount of running time that getty should accumulate
77 * before deciding that something is wrong and exit.
78 */
79 #define GETTY_TIMEOUT 60 /* seconds */
80
81 struct termios tmode, omode;
82
83 int crmod, digit, lower, upper;
84
85 char hostname[MAXHOSTNAMELEN];
86 struct utsname kerninfo;
87 char name[16];
88 char dev[] = _PATH_DEV;
89 char ttyn[32];
90 char *portselector();
91 char *ttyname();
92
93 #define OBUFSIZ 128
94 #define TABBUFSIZ 512
95
96 char defent[TABBUFSIZ];
97 char tabent[TABBUFSIZ];
98
99 char *env[128];
100
101 char partab[] = {
102 0001,0201,0201,0001,0201,0001,0001,0201,
103 0202,0004,0003,0205,0005,0206,0201,0001,
104 0201,0001,0001,0201,0001,0201,0201,0001,
105 0001,0201,0201,0001,0201,0001,0001,0201,
106 0200,0000,0000,0200,0000,0200,0200,0000,
107 0000,0200,0200,0000,0200,0000,0000,0200,
108 0000,0200,0200,0000,0200,0000,0000,0200,
109 0200,0000,0000,0200,0000,0200,0200,0000,
110 0200,0000,0000,0200,0000,0200,0200,0000,
111 0000,0200,0200,0000,0200,0000,0000,0200,
112 0000,0200,0200,0000,0200,0000,0000,0200,
113 0200,0000,0000,0200,0000,0200,0200,0000,
114 0000,0200,0200,0000,0200,0000,0000,0200,
115 0200,0000,0000,0200,0000,0200,0200,0000,
116 0200,0000,0000,0200,0000,0200,0200,0000,
117 0000,0200,0200,0000,0200,0000,0000,0201
118 };
119
120 #define ERASE tmode.c_cc[VERASE]
121 #define KILL tmode.c_cc[VKILL]
122 #define EOT tmode.c_cc[VEOF]
123
124 jmp_buf timeout;
125
126 static void
127 dingdong()
128 {
129
130 alarm(0);
131 signal(SIGALRM, SIG_DFL);
132 longjmp(timeout, 1);
133 }
134
135 jmp_buf intrupt;
136
137 static void
138 interrupt()
139 {
140
141 signal(SIGINT, interrupt);
142 longjmp(intrupt, 1);
143 }
144
145 /*
146 * Action to take when getty is running too long.
147 */
148 void
149 timeoverrun(signo)
150 int signo;
151 {
152
153 syslog(LOG_ERR, "getty exiting due to excessive running time\n");
154 exit(1);
155 }
156
157 static int getname __P((void));
158 static void oflush __P((void));
159 static void prompt __P((void));
160 static void putchr __P((int));
161 static void putf __P((char *));
162 static void putpad __P((char *));
163 static void puts __P((char *));
164
165 int
166 main(argc, argv)
167 int argc;
168 char *argv[];
169 {
170 extern char **environ;
171 char *tname;
172 long allflags;
173 int repcnt = 0, failopenlogged = 0;
174 struct rlimit limit;
175
176 signal(SIGINT, SIG_IGN);
177 /*
178 signal(SIGQUIT, SIG_DFL);
179 */
180 openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
181 gethostname(hostname, sizeof(hostname));
182 if (hostname[0] == '\0')
183 strcpy(hostname, "Amnesiac");
184 uname(&kerninfo);
185
186 /*
187 * Limit running time to deal with broken or dead lines.
188 */
189 (void)signal(SIGXCPU, timeoverrun);
190 limit.rlim_max = RLIM_INFINITY;
191 limit.rlim_cur = GETTY_TIMEOUT;
192 (void)setrlimit(RLIMIT_CPU, &limit);
193
194 /*
195 * The following is a work around for vhangup interactions
196 * which cause great problems getting window systems started.
197 * If the tty line is "-", we do the old style getty presuming
198 * that the file descriptors are already set up for us.
199 * J. Gettys - MIT Project Athena.
200 */
201 if (argc <= 2 || strcmp(argv[2], "-") == 0) {
202 strncpy(ttyn, ttyname(0), 32);
203 ttyn[31] = (char)NULL;
204 }
205 else {
206 int i;
207
208 strcpy(ttyn, dev);
209 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
210 if (strcmp(argv[0], "+") != 0) {
211 chown(ttyn, 0, 0);
212 chmod(ttyn, 0600);
213 revoke(ttyn);
214 if (ttyaction(ttyn, "getty", "root"))
215 syslog(LOG_ERR,"%s: ttyaction failed", ttyn);
216 /*
217 * Delay the open so DTR stays down long enough to be detected.
218 */
219 sleep(2);
220 while ((i = open(ttyn, O_RDWR)) == -1) {
221 if ((repcnt % 10 == 0) &&
222 (errno != ENXIO || !failopenlogged)) {
223 syslog(LOG_ERR, "%s: %m", ttyn);
224 closelog();
225 failopenlogged = 1;
226 }
227 repcnt++;
228 sleep(60);
229 }
230 login_tty(i);
231 }
232 }
233
234 /* Start with default tty settings */
235 if (tcgetattr(0, &tmode) < 0) {
236 syslog(LOG_ERR, "%s: %m", ttyn);
237 exit(1);
238 }
239 omode = tmode;
240
241 gettable("default", defent);
242 gendefaults();
243 tname = "default";
244 if (argc > 1)
245 tname = argv[1];
246 for (;;) {
247 int off;
248
249 gettable(tname, tabent);
250 if (OPset || EPset || APset)
251 APset++, OPset++, EPset++;
252 setdefaults();
253 off = 0;
254 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */
255 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */
256 ioctl(0, FIOASYNC, &off); /* ditto for async mode */
257
258 if (IS)
259 cfsetispeed(&tmode, IS);
260 else if (SP)
261 cfsetispeed(&tmode, SP);
262 if (OS)
263 cfsetospeed(&tmode, OS);
264 else if (SP)
265 cfsetospeed(&tmode, SP);
266 setflags(0);
267 setchars();
268 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
269 syslog(LOG_ERR, "%s: %m", ttyn);
270 exit(1);
271 }
272 if (AB) {
273 extern char *autobaud();
274
275 tname = autobaud();
276 continue;
277 }
278 if (PS) {
279 tname = portselector();
280 continue;
281 }
282 if (CL && *CL)
283 putpad(CL);
284 edithost(HE);
285 if (IM && *IM)
286 putf(IM);
287 if (setjmp(timeout)) {
288 tmode.c_ispeed = tmode.c_ospeed = 0;
289 (void)tcsetattr(0, TCSANOW, &tmode);
290 exit(1);
291 }
292 if (TO) {
293 signal(SIGALRM, dingdong);
294 alarm(TO);
295 }
296 if (getname()) {
297 register int i;
298
299 oflush();
300 alarm(0);
301 signal(SIGALRM, SIG_DFL);
302 if (name[0] == '-') {
303 puts("user names may not start with '-'.");
304 continue;
305 }
306 if (!(upper || lower || digit))
307 continue;
308 setflags(2);
309 if (crmod) {
310 tmode.c_iflag |= ICRNL;
311 tmode.c_oflag |= ONLCR;
312 }
313 #if XXX
314 if (upper || UC)
315 tmode.sg_flags |= LCASE;
316 if (lower || LC)
317 tmode.sg_flags &= ~LCASE;
318 #endif
319 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
320 syslog(LOG_ERR, "%s: %m", ttyn);
321 exit(1);
322 }
323 signal(SIGINT, SIG_DFL);
324 for (i = 0; environ[i] != (char *)0; i++)
325 env[i] = environ[i];
326 makeenv(&env[i]);
327
328 limit.rlim_max = RLIM_INFINITY;
329 limit.rlim_cur = RLIM_INFINITY;
330 (void)setrlimit(RLIMIT_CPU, &limit);
331 execle(LO, "login", "-p", "--", name, (char *)0, env);
332 syslog(LOG_ERR, "%s: %m", LO);
333 exit(1);
334 }
335 alarm(0);
336 signal(SIGALRM, SIG_DFL);
337 signal(SIGINT, SIG_IGN);
338 if (NX && *NX)
339 tname = NX;
340 }
341 }
342
343 static int
344 getname()
345 {
346 register int c;
347 register char *np;
348 char cs;
349
350 /*
351 * Interrupt may happen if we use CBREAK mode
352 */
353 if (setjmp(intrupt)) {
354 signal(SIGINT, SIG_IGN);
355 return (0);
356 }
357 signal(SIGINT, interrupt);
358 setflags(1);
359 prompt();
360 if (PF > 0) {
361 oflush();
362 sleep(PF);
363 PF = 0;
364 }
365 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
366 syslog(LOG_ERR, "%s: %m", ttyn);
367 exit(1);
368 }
369 crmod = digit = lower = upper = 0;
370 np = name;
371 for (;;) {
372 oflush();
373 if (read(STDIN_FILENO, &cs, 1) <= 0)
374 exit(0);
375 if ((c = cs&0177) == 0)
376 return (0);
377 if (c == EOT)
378 exit(1);
379 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
380 putf("\r\n");
381 break;
382 }
383 if (islower(c))
384 lower = 1;
385 else if (isupper(c))
386 upper = 1;
387 else if (c == ERASE || c == '#' || c == '\b') {
388 if (np > name) {
389 np--;
390 if (cfgetospeed(&tmode) >= 1200)
391 puts("\b \b");
392 else
393 putchr(cs);
394 }
395 continue;
396 } else if (c == KILL || c == '@') {
397 putchr(cs);
398 putchr('\r');
399 if (cfgetospeed(&tmode) < 1200)
400 putchr('\n');
401 /* this is the way they do it down under ... */
402 else if (np > name)
403 puts(" \r");
404 prompt();
405 np = name;
406 continue;
407 } else if (isdigit(c))
408 digit++;
409 if (IG && (c <= ' ' || c > 0176))
410 continue;
411 *np++ = c;
412 putchr(cs);
413 }
414 signal(SIGINT, SIG_IGN);
415 *np = 0;
416 if (c == '\r')
417 crmod = 1;
418 if (upper && !lower && !LC || UC)
419 for (np = name; *np; np++)
420 if (isupper(*np))
421 *np = tolower(*np);
422 return (1);
423 }
424
425 static void
426 putpad(s)
427 register char *s;
428 {
429 register pad = 0;
430 speed_t ospeed = cfgetospeed(&tmode);
431
432 if (isdigit(*s)) {
433 while (isdigit(*s)) {
434 pad *= 10;
435 pad += *s++ - '0';
436 }
437 pad *= 10;
438 if (*s == '.' && isdigit(s[1])) {
439 pad += s[1] - '0';
440 s += 2;
441 }
442 }
443
444 puts(s);
445 /*
446 * If no delay needed, or output speed is
447 * not comprehensible, then don't try to delay.
448 */
449 if (pad == 0 || ospeed <= 0)
450 return;
451
452 /*
453 * Round up by a half a character frame, and then do the delay.
454 * Too bad there are no user program accessible programmed delays.
455 * Transmitting pad characters slows many terminals down and also
456 * loads the system.
457 */
458 pad = (pad * ospeed + 50000) / 100000;
459 while (pad--)
460 putchr(*PC);
461 }
462
463 static void
464 puts(s)
465 register char *s;
466 {
467 while (*s)
468 putchr(*s++);
469 }
470
471 char outbuf[OBUFSIZ];
472 int obufcnt = 0;
473
474 static void
475 putchr(cc)
476 int cc;
477 {
478 char c;
479
480 c = cc;
481 if (!NP) {
482 c |= partab[c&0177] & 0200;
483 if (OP)
484 c ^= 0200;
485 }
486 if (!UB) {
487 outbuf[obufcnt++] = c;
488 if (obufcnt >= OBUFSIZ)
489 oflush();
490 } else
491 write(STDOUT_FILENO, &c, 1);
492 }
493
494 static void
495 oflush()
496 {
497 if (obufcnt)
498 write(STDOUT_FILENO, outbuf, obufcnt);
499 obufcnt = 0;
500 }
501
502 static void
503 prompt()
504 {
505
506 putf(LM);
507 if (CO)
508 putchr('\n');
509 }
510
511 static void
512 putf(cp)
513 register char *cp;
514 {
515 extern char editedhost[];
516 time_t t;
517 char *slash, db[100];
518
519 while (*cp) {
520 if (*cp != '%') {
521 putchr(*cp++);
522 continue;
523 }
524 switch (*++cp) {
525
526 case 't':
527 slash = strrchr(ttyn, '/');
528 if (slash == (char *) 0)
529 puts(ttyn);
530 else
531 puts(&slash[1]);
532 break;
533
534 case 'h':
535 puts(editedhost);
536 break;
537
538 case 'd': {
539 static char fmt[] = "%l:% %p on %A, %d %B %Y";
540
541 fmt[4] = 'M'; /* I *hate* SCCS... */
542 (void)time(&t);
543 (void)strftime(db, sizeof(db), fmt, localtime(&t));
544 puts(db);
545 break;
546
547 case 's':
548 puts(kerninfo.sysname);
549 break;
550
551 case 'm':
552 puts(kerninfo.machine);
553 break;
554
555 case 'r':
556 puts(kerninfo.release);
557 break;
558
559 case 'v':
560 puts(kerninfo.version);
561 break;
562 }
563
564 case '%':
565 putchr('%');
566 break;
567 }
568 cp++;
569 }
570 }
571