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