main.c revision 1.26 1 /* $NetBSD: main.c,v 1.26 1998/07/06 06:48:19 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.26 1998/07/06 06:48:19 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 + 1];
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_PID, LOG_AUTH);
196 gethostname(hostname, sizeof(hostname));
197 hostname[sizeof(hostname) - 1] = '\0';
198 if (hostname[0] == '\0')
199 strcpy(hostname, "Amnesiac");
200 uname(&kerninfo);
201
202 if (__progname[0] == 'u' && __progname[1] == 'u')
203 uugetty = 1;
204
205 /*
206 * Find id of uucp login (if present) so we can chown tty properly.
207 */
208 if (uugetty && (pw = getpwnam("uucp")))
209 ttyowner = pw->pw_uid;
210 else
211 ttyowner = 0;
212
213 /*
214 * Limit running time to deal with broken or dead lines.
215 */
216 (void)signal(SIGXCPU, timeoverrun);
217 limit.rlim_max = RLIM_INFINITY;
218 limit.rlim_cur = GETTY_TIMEOUT;
219 (void)setrlimit(RLIMIT_CPU, &limit);
220
221 /*
222 * The following is a work around for vhangup interactions
223 * which cause great problems getting window systems started.
224 * If the tty line is "-", we do the old style getty presuming
225 * that the file descriptors are already set up for us.
226 * J. Gettys - MIT Project Athena.
227 */
228 if (argc <= 2 || strcmp(argv[2], "-") == 0) {
229 strncpy(ttyn, ttyname(0), 32);
230 ttyn[31] = (char)NULL;
231 }
232 else {
233 int i;
234
235 strcpy(ttyn, dev);
236 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
237
238 if (uugetty) {
239 chown(ttyn, ttyowner, 0);
240 strcpy(lockfile, _PATH_LOCK);
241 strncat(lockfile, argv[2], sizeof(lockfile)-sizeof(_PATH_LOCK));
242 /* wait for lockfiles to go away before we try to open */
243 if ( pidlock(lockfile, 0, 0, 0) != 0 ) {
244 syslog(LOG_ERR, "%s: can't create lockfile", ttyn);
245 exit(1);
246 }
247 unlink(lockfile);
248 }
249 if (strcmp(argv[0], "+") != 0) {
250 chown(ttyn, ttyowner, 0);
251 chmod(ttyn, 0600);
252 revoke(ttyn);
253 if (ttyaction(ttyn, "getty", "root"))
254 syslog(LOG_ERR,"%s: ttyaction failed", ttyn);
255 /*
256 * Delay the open so DTR stays down long enough to be detected.
257 */
258 sleep(2);
259 while ((i = open(ttyn, O_RDWR)) == -1) {
260 if ((repcnt % 10 == 0) &&
261 (errno != ENXIO || !failopenlogged)) {
262 syslog(LOG_ERR, "%s: %m", ttyn);
263 closelog();
264 failopenlogged = 1;
265 }
266 repcnt++;
267 sleep(60);
268 }
269 if (uugetty && pidlock(lockfile, 0, 0, 0) != 0) {
270 syslog(LOG_ERR, "%s: can't create lockfile", ttyn);
271 exit(1);
272 }
273 (void) chown(lockfile, ttyowner, 0);
274 login_tty(i);
275 }
276 }
277
278 /* Start with default tty settings */
279 if (tcgetattr(0, &tmode) < 0) {
280 syslog(LOG_ERR, "%s: %m", ttyn);
281 exit(1);
282 }
283 omode = tmode;
284
285 gettable("default", defent);
286 gendefaults();
287 tname = "default";
288 if (argc > 1)
289 tname = argv[1];
290 for (;;) {
291 int off;
292
293 gettable(tname, tabent);
294 if (OPset || EPset || APset)
295 APset++, OPset++, EPset++;
296 setdefaults();
297 off = 0;
298 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */
299 ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */
300 ioctl(0, FIOASYNC, &off); /* ditto for async mode */
301
302 if (IS)
303 cfsetispeed(&tmode, IS);
304 else if (SP)
305 cfsetispeed(&tmode, SP);
306 if (OS)
307 cfsetospeed(&tmode, OS);
308 else if (SP)
309 cfsetospeed(&tmode, SP);
310 setflags(0);
311 setchars();
312 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
313 syslog(LOG_ERR, "%s: %m", ttyn);
314 exit(1);
315 }
316 if (AB) {
317 tname = autobaud();
318 continue;
319 }
320 if (PS) {
321 tname = portselector();
322 continue;
323 }
324 if (CL && *CL)
325 putpad(CL);
326 edithost(HE);
327 if (IM && *IM)
328 putf(IM);
329 if (setjmp(timeout)) {
330 tmode.c_ispeed = tmode.c_ospeed = 0;
331 (void)tcsetattr(0, TCSANOW, &tmode);
332 exit(1);
333 }
334 if (TO) {
335 signal(SIGALRM, dingdong);
336 alarm(TO);
337 }
338 if (getname()) {
339 int i;
340
341 oflush();
342 alarm(0);
343 signal(SIGALRM, SIG_DFL);
344 if (name[0] == '-') {
345 xputs("user names may not start with '-'.");
346 continue;
347 }
348 if (!(upper || lower || digit))
349 continue;
350 setflags(2);
351 if (crmod) {
352 tmode.c_iflag |= ICRNL;
353 tmode.c_oflag |= ONLCR;
354 }
355 #if XXX
356 if (upper || UC)
357 tmode.sg_flags |= LCASE;
358 if (lower || LC)
359 tmode.sg_flags &= ~LCASE;
360 #endif
361 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
362 syslog(LOG_ERR, "%s: %m", ttyn);
363 exit(1);
364 }
365 signal(SIGINT, SIG_DFL);
366 for (i = 0; environ[i] != (char *)0; i++)
367 env[i] = environ[i];
368 makeenv(&env[i]);
369
370 limit.rlim_max = RLIM_INFINITY;
371 limit.rlim_cur = RLIM_INFINITY;
372 (void)setrlimit(RLIMIT_CPU, &limit);
373 execle(LO, "login", "-p", "--", name, (char *)0, env);
374 syslog(LOG_ERR, "%s: %m", LO);
375 exit(1);
376 }
377 alarm(0);
378 signal(SIGALRM, SIG_DFL);
379 signal(SIGINT, SIG_IGN);
380 if (NX && *NX)
381 tname = NX;
382 unlink(lockfile);
383 }
384 }
385
386 static int
387 getname()
388 {
389 int c;
390 char *np;
391 char cs;
392
393 /*
394 * Interrupt may happen if we use CBREAK mode
395 */
396 if (setjmp(intrupt)) {
397 signal(SIGINT, SIG_IGN);
398 return (0);
399 }
400 signal(SIGINT, interrupt);
401 setflags(1);
402 prompt();
403 if (PF > 0) {
404 oflush();
405 sleep(PF);
406 PF = 0;
407 }
408 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
409 syslog(LOG_ERR, "%s: %m", ttyn);
410 exit(1);
411 }
412 crmod = digit = lower = upper = 0;
413 np = name;
414 for (;;) {
415 oflush();
416 if (read(STDIN_FILENO, &cs, 1) <= 0)
417 exit(0);
418 if ((c = cs&0177) == 0)
419 return (0);
420 if (c == EOT)
421 exit(1);
422 if (c == '\r' || c == '\n' || np >= &name[sizeof name]) {
423 putf("\r\n");
424 break;
425 }
426 if (islower(c))
427 lower = 1;
428 else if (isupper(c))
429 upper = 1;
430 else if (c == ERASE || c == '#' || c == '\b') {
431 if (np > name) {
432 np--;
433 if (cfgetospeed(&tmode) >= 1200)
434 xputs("\b \b");
435 else
436 putchr(cs);
437 }
438 continue;
439 } else if (c == KILL || c == '@') {
440 putchr(cs);
441 putchr('\r');
442 if (cfgetospeed(&tmode) < 1200)
443 putchr('\n');
444 /* this is the way they do it down under ... */
445 else if (np > name)
446 xputs(
447 " \r");
448 prompt();
449 np = name;
450 continue;
451 } else if (isdigit(c))
452 digit++;
453 if (IG && (c <= ' ' || c > 0176))
454 continue;
455 *np++ = c;
456 putchr(cs);
457 }
458 signal(SIGINT, SIG_IGN);
459 *np = 0;
460 if (c == '\r')
461 crmod = 1;
462 if ((upper && !lower && !LC) || UC)
463 for (np = name; *np; np++)
464 if (isupper(*np))
465 *np = tolower(*np);
466 return (1);
467 }
468
469 static void
470 putpad(s)
471 const char *s;
472 {
473 int pad = 0;
474 speed_t ospeed = cfgetospeed(&tmode);
475
476 if (isdigit(*s)) {
477 while (isdigit(*s)) {
478 pad *= 10;
479 pad += *s++ - '0';
480 }
481 pad *= 10;
482 if (*s == '.' && isdigit(s[1])) {
483 pad += s[1] - '0';
484 s += 2;
485 }
486 }
487
488 xputs(s);
489 /*
490 * If no delay needed, or output speed is
491 * not comprehensible, then don't try to delay.
492 */
493 if (pad == 0 || ospeed <= 0)
494 return;
495
496 /*
497 * Round up by a half a character frame, and then do the delay.
498 * Too bad there are no user program accessible programmed delays.
499 * Transmitting pad characters slows many terminals down and also
500 * loads the system.
501 */
502 pad = (pad * ospeed + 50000) / 100000;
503 while (pad--)
504 putchr(*PC);
505 }
506
507 static void
508 xputs(s)
509 const char *s;
510 {
511 while (*s)
512 putchr(*s++);
513 }
514
515 char outbuf[OBUFSIZ];
516 int obufcnt = 0;
517
518 static void
519 putchr(cc)
520 int cc;
521 {
522 char c;
523
524 c = cc;
525 if (!NP) {
526 c |= partab[c&0177] & 0200;
527 if (OP)
528 c ^= 0200;
529 }
530 if (!UB) {
531 outbuf[obufcnt++] = c;
532 if (obufcnt >= OBUFSIZ)
533 oflush();
534 } else
535 write(STDOUT_FILENO, &c, 1);
536 }
537
538 static void
539 oflush()
540 {
541 if (obufcnt)
542 write(STDOUT_FILENO, outbuf, obufcnt);
543 obufcnt = 0;
544 }
545
546 static void
547 prompt()
548 {
549
550 putf(LM);
551 if (CO)
552 putchr('\n');
553 }
554
555 static void
556 putf(cp)
557 const char *cp;
558 {
559 extern char editedhost[];
560 time_t t;
561 char *slash, db[100];
562
563 while (*cp) {
564 if (*cp != '%') {
565 putchr(*cp++);
566 continue;
567 }
568 switch (*++cp) {
569
570 case 't':
571 slash = strrchr(ttyn, '/');
572 if (slash == (char *) 0)
573 xputs(ttyn);
574 else
575 xputs(&slash[1]);
576 break;
577
578 case 'h':
579 xputs(editedhost);
580 break;
581
582 case 'd': {
583 static char fmt[] = "%l:% %p on %A, %d %B %Y";
584
585 fmt[4] = 'M'; /* I *hate* SCCS... */
586 (void)time(&t);
587 (void)strftime(db, sizeof(db), fmt, localtime(&t));
588 xputs(db);
589 break;
590
591 case 's':
592 xputs(kerninfo.sysname);
593 break;
594
595 case 'm':
596 xputs(kerninfo.machine);
597 break;
598
599 case 'r':
600 xputs(kerninfo.release);
601 break;
602
603 case 'v':
604 xputs(kerninfo.version);
605 break;
606 }
607
608 case '%':
609 putchr('%');
610 break;
611 }
612 cp++;
613 }
614 }
615