main.c revision 1.25 1 /* $NetBSD: main.c,v 1.25 1998/03/30 01:52:02 mrg 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.25 1998/03/30 01:52:02 mrg 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((const char *));
173 static void putpad __P((const char *));
174 static void xputs __P((const 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 int i;
339
340 oflush();
341 alarm(0);
342 signal(SIGALRM, SIG_DFL);
343 if (name[0] == '-') {
344 xputs("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 int c;
389 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 xputs("\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 xputs(
446 " \r");
447 prompt();
448 np = name;
449 continue;
450 } else if (isdigit(c))
451 digit++;
452 if (IG && (c <= ' ' || c > 0176))
453 continue;
454 *np++ = c;
455 putchr(cs);
456 }
457 signal(SIGINT, SIG_IGN);
458 *np = 0;
459 if (c == '\r')
460 crmod = 1;
461 if ((upper && !lower && !LC) || UC)
462 for (np = name; *np; np++)
463 if (isupper(*np))
464 *np = tolower(*np);
465 return (1);
466 }
467
468 static void
469 putpad(s)
470 const char *s;
471 {
472 int pad = 0;
473 speed_t ospeed = cfgetospeed(&tmode);
474
475 if (isdigit(*s)) {
476 while (isdigit(*s)) {
477 pad *= 10;
478 pad += *s++ - '0';
479 }
480 pad *= 10;
481 if (*s == '.' && isdigit(s[1])) {
482 pad += s[1] - '0';
483 s += 2;
484 }
485 }
486
487 xputs(s);
488 /*
489 * If no delay needed, or output speed is
490 * not comprehensible, then don't try to delay.
491 */
492 if (pad == 0 || ospeed <= 0)
493 return;
494
495 /*
496 * Round up by a half a character frame, and then do the delay.
497 * Too bad there are no user program accessible programmed delays.
498 * Transmitting pad characters slows many terminals down and also
499 * loads the system.
500 */
501 pad = (pad * ospeed + 50000) / 100000;
502 while (pad--)
503 putchr(*PC);
504 }
505
506 static void
507 xputs(s)
508 const char *s;
509 {
510 while (*s)
511 putchr(*s++);
512 }
513
514 char outbuf[OBUFSIZ];
515 int obufcnt = 0;
516
517 static void
518 putchr(cc)
519 int cc;
520 {
521 char c;
522
523 c = cc;
524 if (!NP) {
525 c |= partab[c&0177] & 0200;
526 if (OP)
527 c ^= 0200;
528 }
529 if (!UB) {
530 outbuf[obufcnt++] = c;
531 if (obufcnt >= OBUFSIZ)
532 oflush();
533 } else
534 write(STDOUT_FILENO, &c, 1);
535 }
536
537 static void
538 oflush()
539 {
540 if (obufcnt)
541 write(STDOUT_FILENO, outbuf, obufcnt);
542 obufcnt = 0;
543 }
544
545 static void
546 prompt()
547 {
548
549 putf(LM);
550 if (CO)
551 putchr('\n');
552 }
553
554 static void
555 putf(cp)
556 const char *cp;
557 {
558 extern char editedhost[];
559 time_t t;
560 char *slash, db[100];
561
562 while (*cp) {
563 if (*cp != '%') {
564 putchr(*cp++);
565 continue;
566 }
567 switch (*++cp) {
568
569 case 't':
570 slash = strrchr(ttyn, '/');
571 if (slash == (char *) 0)
572 xputs(ttyn);
573 else
574 xputs(&slash[1]);
575 break;
576
577 case 'h':
578 xputs(editedhost);
579 break;
580
581 case 'd': {
582 static char fmt[] = "%l:% %p on %A, %d %B %Y";
583
584 fmt[4] = 'M'; /* I *hate* SCCS... */
585 (void)time(&t);
586 (void)strftime(db, sizeof(db), fmt, localtime(&t));
587 xputs(db);
588 break;
589
590 case 's':
591 xputs(kerninfo.sysname);
592 break;
593
594 case 'm':
595 xputs(kerninfo.machine);
596 break;
597
598 case 'r':
599 xputs(kerninfo.release);
600 break;
601
602 case 'v':
603 xputs(kerninfo.version);
604 break;
605 }
606
607 case '%':
608 putchr('%');
609 break;
610 }
611 cp++;
612 }
613 }
614