Update post installation article url
[minix3.git] / libexec / getty / main.c
blobdf5750327537449b8d4c09b593688e786f4a9d2e
1 /* $NetBSD: main.c,v 1.64 2013/08/12 13:54:33 joerg Exp $ */
3 /*-
4 * Copyright (c) 1980, 1993
5 * The Regents of the University of California. All rights reserved.
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. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
32 #include <sys/cdefs.h>
34 #ifndef lint
35 __COPYRIGHT("@(#) Copyright (c) 1980, 1993\
36 The Regents of the University of California. All rights reserved.");
37 #endif /* not lint */
39 #ifndef lint
40 #if 0
41 static char sccsid[] = "from: @(#)main.c 8.1 (Berkeley) 6/20/93";
42 #else
43 __RCSID("$NetBSD: main.c,v 1.64 2013/08/12 13:54:33 joerg Exp $");
44 #endif
45 #endif /* not lint */
47 #include <sys/param.h>
48 #include <sys/ioctl.h>
49 #include <sys/resource.h>
50 #include <sys/utsname.h>
52 #include <ctype.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <limits.h>
56 #include <pwd.h>
57 #include <setjmp.h>
58 #include <signal.h>
59 #include <stdio.h>
60 #include <stdlib.h>
61 #include <string.h>
62 #include <syslog.h>
63 #include <term.h>
64 #include <termios.h>
65 #include <time.h>
66 #include <ttyent.h>
67 #include <unistd.h>
68 #include <util.h>
70 #include "gettytab.h"
71 #include "pathnames.h"
72 #include "extern.h"
74 extern char editedhost[];
77 * Set the amount of running time that getty should accumulate
78 * before deciding that something is wrong and exit.
80 #define GETTY_TIMEOUT 60 /* seconds */
82 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
84 #define PPP_FRAME 0x7e /* PPP Framing character */
85 #define PPP_STATION 0xff /* "All Station" character */
86 #define PPP_ESCAPE 0x7d /* Escape Character */
87 #define PPP_CONTROL 0x03 /* PPP Control Field */
88 #define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */
89 #define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */
90 #define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */
92 struct termios tmode, omode;
94 int crmod, digit_or_punc, lower, upper;
96 char hostname[MAXHOSTNAMELEN + 1];
97 struct utsname kerninfo;
98 char name[LOGIN_NAME_MAX];
99 char dev[] = _PATH_DEV;
100 char ttyn[32];
101 char lockfile[512];
102 uid_t ttyowner;
103 char *rawttyn;
105 #define OBUFSIZ 128
106 #define TABBUFSIZ 512
108 char defent[TABBUFSIZ];
109 char tabent[TABBUFSIZ];
111 char *env[128];
113 const unsigned char partab[] = {
114 0001,0201,0201,0001,0201,0001,0001,0201,
115 0202,0004,0003,0205,0005,0206,0201,0001,
116 0201,0001,0001,0201,0001,0201,0201,0001,
117 0001,0201,0201,0001,0201,0001,0001,0201,
118 0200,0000,0000,0200,0000,0200,0200,0000,
119 0000,0200,0200,0000,0200,0000,0000,0200,
120 0000,0200,0200,0000,0200,0000,0000,0200,
121 0200,0000,0000,0200,0000,0200,0200,0000,
122 0200,0000,0000,0200,0000,0200,0200,0000,
123 0000,0200,0200,0000,0200,0000,0000,0200,
124 0000,0200,0200,0000,0200,0000,0000,0200,
125 0200,0000,0000,0200,0000,0200,0200,0000,
126 0000,0200,0200,0000,0200,0000,0000,0200,
127 0200,0000,0000,0200,0000,0200,0200,0000,
128 0200,0000,0000,0200,0000,0200,0200,0000,
129 0000,0200,0200,0000,0200,0000,0000,0201
132 #define ERASE tmode.c_cc[VERASE]
133 #define KILL tmode.c_cc[VKILL]
134 #define EOT tmode.c_cc[VEOF]
136 static void clearscreen(void);
138 sigjmp_buf timeout;
140 __dead static void
141 /*ARGSUSED*/
142 dingdong(int signo)
145 (void)alarm(0);
146 (void)signal(SIGALRM, SIG_DFL);
147 siglongjmp(timeout, 1);
150 sigjmp_buf intrupt;
152 __dead static void
153 /*ARGSUSED*/
154 interrupt(int signo)
157 (void)signal(SIGINT, interrupt);
158 siglongjmp(intrupt, 1);
161 #if !defined(__minix)
163 * Action to take when getty is running too long.
165 __dead static void
166 /*ARGSUSED*/
167 timeoverrun(int signo)
170 syslog(LOG_ERR, "getty exiting due to excessive running time");
171 exit(1);
173 #endif /* !defined(__minix) */
175 static int getname(void);
176 static void oflush(void);
177 static void prompt(void);
178 static int putchr(int);
179 static void putf(const char *);
180 static void xputs(const char *);
182 #define putpad(s) tputs(s, 1, putchr)
185 main(int argc, char *argv[], char *envp[])
187 const char *progname;
188 int repcnt = 0, failopenlogged = 0, first_time = 1;
189 struct rlimit limit;
190 struct passwd *pw;
191 int rval;
192 /* this is used past the siglongjmp, so make sure it is not cached
193 in registers that might become invalid. */
194 volatile int uugetty = 0;
195 const char * volatile tname = "default";
197 (void)signal(SIGINT, SIG_IGN);
198 openlog("getty", LOG_PID, LOG_AUTH);
199 (void)gethostname(hostname, sizeof(hostname));
200 hostname[sizeof(hostname) - 1] = '\0';
201 if (hostname[0] == '\0')
202 (void)strlcpy(hostname, "Amnesiac", sizeof(hostname));
203 (void)uname(&kerninfo);
205 progname = getprogname();
206 if (progname[0] == 'u' && progname[1] == 'u')
207 uugetty = 1;
210 * Find id of uucp login (if present) so we can chown tty properly.
212 if (uugetty && (pw = getpwnam("uucp")))
213 ttyowner = pw->pw_uid;
214 else
215 ttyowner = 0;
218 * Limit running time to deal with broken or dead lines.
220 #if !defined(__minix)
221 (void)signal(SIGXCPU, timeoverrun);
222 #endif /* !defined(__minix) */
223 limit.rlim_max = RLIM_INFINITY;
224 limit.rlim_cur = GETTY_TIMEOUT;
225 (void)setrlimit(RLIMIT_CPU, &limit);
228 * The following is a work around for vhangup interactions
229 * which cause great problems getting window systems started.
230 * If the tty line is "-", we do the old style getty presuming
231 * that the file descriptors are already set up for us.
232 * J. Gettys - MIT Project Athena.
234 if (argc <= 2 || strcmp(argv[2], "-") == 0) {
235 (void)strlcpy(ttyn, ttyname(0), sizeof(ttyn));
237 else {
238 int i;
240 rawttyn = argv[2];
241 (void)strlcpy(ttyn, dev, sizeof(ttyn));
242 (void)strlcat(ttyn, argv[2], sizeof(ttyn));
243 if (uugetty) {
244 (void)chown(ttyn, ttyowner, 0);
245 (void)strlcpy(lockfile, _PATH_LOCK,
246 sizeof(lockfile));
247 (void)strlcat(lockfile, argv[2],
248 sizeof(lockfile));
250 * wait for lockfiles to go away before we try
251 * to open
253 if (pidlock(lockfile, 0, 0, 0) != 0) {
254 syslog(LOG_ERR,
255 "%s: can't create lockfile", ttyn);
256 exit(1);
258 (void)unlink(lockfile);
260 if (strcmp(argv[0], "+") != 0) {
261 (void)chown(ttyn, ttyowner, 0);
262 (void)chmod(ttyn, 0600);
263 #if !defined(__minix)
264 (void)revoke(ttyn);
265 #endif /* !defined(__minix) */
266 if (ttyaction(ttyn, "getty", "root"))
267 syslog(LOG_WARNING, "%s: ttyaction failed",
268 ttyn);
270 * Delay the open so DTR stays down long enough
271 * to be detected.
273 (void)sleep(2);
274 while ((i = open(ttyn, O_RDWR)) == -1) {
275 if ((repcnt % 10 == 0) &&
276 (errno != ENXIO || !failopenlogged)) {
277 syslog(LOG_WARNING, "%s: %m", ttyn);
278 closelog();
279 failopenlogged = 1;
281 repcnt++;
282 (void)sleep(60);
284 if (uugetty && pidlock(lockfile, 0, 0, 0) != 0) {
285 syslog(LOG_ERR, "%s: can't create lockfile",
286 ttyn);
287 exit(1);
289 if (uugetty)
290 (void)chown(lockfile, ttyowner, 0);
291 (void)login_tty(i);
295 /* Start with default tty settings */
296 if (tcgetattr(0, &tmode) < 0) {
297 syslog(LOG_ERR, "%s: %m", ttyn);
298 exit(1);
300 omode = tmode;
302 gettable("default", defent);
303 gendefaults();
304 if (argc > 1)
305 tname = argv[1];
306 for (;;) {
307 #if !defined(__minix)
308 int off;
309 #endif /* !defined(__minix) */
311 rval = 0;
312 gettable(tname, tabent);
313 if (OPset || EPset || APset)
314 APset++, OPset++, EPset++;
315 setdefaults();
316 #if !defined(__minix)
317 off = 0;
318 #endif /* !defined(__minix) */
319 (void)tcflush(0, TCIOFLUSH); /* clear out the crap */
320 #if !defined(__minix)
321 (void)ioctl(0, FIONBIO, &off); /* turn off non-blocking mode */
322 (void)ioctl(0, FIOASYNC, &off); /* ditto for async mode */
323 #endif /* !defined(__minix) */
325 if (IS)
326 (void)cfsetispeed(&tmode, (speed_t)IS);
327 else if (SP)
328 (void)cfsetispeed(&tmode, (speed_t)SP);
329 if (OS)
330 (void)cfsetospeed(&tmode, (speed_t)OS);
331 else if (SP)
332 (void)cfsetospeed(&tmode, (speed_t)SP);
333 setflags(0);
334 setchars();
335 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
336 syslog(LOG_ERR, "%s: %m", ttyn);
337 exit(1);
339 if (AB) {
340 tname = autobaud();
341 continue;
343 if (PS) {
344 tname = portselector();
345 continue;
347 if (CS)
348 clearscreen();
349 if (CL && *CL)
350 putpad(CL);
351 edithost(HE);
354 * If this is the first time through this, and an
355 * issue file has been given, then send it.
357 if (first_time != 0 && IF != NULL) {
358 char buf[_POSIX2_LINE_MAX];
359 FILE *fp;
361 if ((fp = fopen(IF, "r")) != NULL) {
362 while (fgets(buf, sizeof(buf) - 1, fp) != NULL)
363 putf(buf);
364 (void)fclose(fp);
367 first_time = 0;
369 if (IM && *IM)
370 putf(IM);
371 oflush();
372 if (sigsetjmp(timeout, 1)) {
373 tmode.c_ispeed = tmode.c_ospeed = 0;
374 (void)tcsetattr(0, TCSANOW, &tmode);
375 exit(1);
377 if (TO) {
378 (void)signal(SIGALRM, dingdong);
379 (void)alarm((unsigned int)TO);
381 if (NN) {
382 name[0] = '\0';
383 lower = 1;
384 upper = digit_or_punc = 0;
385 } else if (AL) {
386 const char *p = AL;
387 char *q = name;
389 while (*p && q < &name[sizeof name - 1]) {
390 if (isupper((unsigned char)*p))
391 upper = 1;
392 else if (islower((unsigned char)*p))
393 lower = 1;
394 else if (isdigit((unsigned char)*p))
395 digit_or_punc = 1;
396 *q++ = *p++;
398 } else if ((rval = getname()) == 2) {
399 setflags(2);
400 (void)execle(PP, "ppplogin", ttyn, (char *) 0, env);
401 syslog(LOG_ERR, "%s: %m", PP);
402 exit(1);
405 if (rval || AL || NN) {
406 int i;
408 oflush();
409 (void)alarm(0);
410 (void)signal(SIGALRM, SIG_DFL);
411 if (name[0] == '-') {
412 xputs("user names may not start with '-'.");
413 continue;
415 if (!(upper || lower || digit_or_punc))
416 continue;
417 setflags(2);
418 if (crmod) {
419 tmode.c_iflag |= ICRNL;
420 tmode.c_oflag |= ONLCR;
422 #if XXX
423 if (upper || UC)
424 tmode.sg_flags |= LCASE;
425 if (lower || LC)
426 tmode.sg_flags &= ~LCASE;
427 #endif
428 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
429 syslog(LOG_ERR, "%s: %m", ttyn);
430 exit(1);
432 (void)signal(SIGINT, SIG_DFL);
433 for (i = 0; envp[i] != NULL; i++)
434 env[i] = envp[i];
435 makeenv(&env[i]);
437 limit.rlim_max = RLIM_INFINITY;
438 limit.rlim_cur = RLIM_INFINITY;
439 (void)setrlimit(RLIMIT_CPU, &limit);
440 if (NN)
441 (void)execle(LO, "login", AL ? "-fp" : "-p",
442 NULL, env);
443 else
444 (void)execle(LO, "login", AL ? "-fp" : "-p",
445 "--", name, NULL, env);
446 syslog(LOG_ERR, "%s: %m", LO);
447 exit(1);
449 (void)alarm(0);
450 (void)signal(SIGALRM, SIG_DFL);
451 (void)signal(SIGINT, SIG_IGN);
452 if (NX && *NX)
453 tname = NX;
454 if (uugetty)
455 (void)unlink(lockfile);
459 static int
460 getname(void)
462 int c;
463 char *np;
464 unsigned char cs;
465 int ppp_state, ppp_connection;
468 * Interrupt may happen if we use CBREAK mode
470 if (sigsetjmp(intrupt, 1)) {
471 (void)signal(SIGINT, SIG_IGN);
472 return (0);
474 (void)signal(SIGINT, interrupt);
475 setflags(1);
476 prompt();
477 if (PF > 0) {
478 oflush();
479 (void)sleep((unsigned int)PF);
480 PF = 0;
482 if (tcsetattr(0, TCSANOW, &tmode) < 0) {
483 syslog(LOG_ERR, "%s: %m", ttyn);
484 exit(1);
486 crmod = digit_or_punc = lower = upper = 0;
487 ppp_state = ppp_connection = 0;
488 np = name;
489 for (;;) {
490 oflush();
491 if (read(STDIN_FILENO, &cs, 1) <= 0)
492 exit(0);
493 if ((c = cs&0177) == 0)
494 return (0);
497 * PPP detection state machine..
498 * Look for sequences:
499 * PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
500 * PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
501 * See RFC1662.
502 * Derived from code from Michael Hancock <michaelh@cet.co.jp>
503 * and Erik 'PPP' Olson <eriko@wrq.com>
505 if (PP && cs == PPP_FRAME) {
506 ppp_state = 1;
507 } else if (ppp_state == 1 && cs == PPP_STATION) {
508 ppp_state = 2;
509 } else if (ppp_state == 2 && cs == PPP_ESCAPE) {
510 ppp_state = 3;
511 } else if ((ppp_state == 2 && cs == PPP_CONTROL) ||
512 (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
513 ppp_state = 4;
514 } else if (ppp_state == 4 && cs == PPP_LCP_HI) {
515 ppp_state = 5;
516 } else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
517 ppp_connection = 1;
518 break;
519 } else {
520 ppp_state = 0;
523 if (c == EOT)
524 exit(1);
525 if (c == '\r' || c == '\n' ||
526 np >= &name[LOGIN_NAME_MAX - 1]) {
527 *np = '\0';
528 putf("\r\n");
529 break;
531 if (islower(c))
532 lower = 1;
533 else if (isupper(c))
534 upper = 1;
535 else if (c == ERASE || c == '#' || c == '\b') {
536 if (np > name) {
537 np--;
538 if (cfgetospeed(&tmode) >= 1200)
539 xputs("\b \b");
540 else
541 putchr(cs);
543 continue;
544 } else if (c == KILL || c == '@') {
545 putchr(cs);
546 putchr('\r');
547 if (cfgetospeed(&tmode) < 1200)
548 putchr('\n');
549 /* this is the way they do it down under ... */
550 else if (np > name)
551 xputs(
552 " \r");
553 prompt();
554 np = name;
555 continue;
556 } else if (isdigit(c) || c == '_')
557 digit_or_punc = 1;
558 if (IG && (c <= ' ' || c > 0176))
559 continue;
560 *np++ = c;
561 putchr(cs);
564 * An MS-Windows direct connect PPP "client" won't send its
565 * first PPP packet until we respond to its "CLIENT" poll
566 * with a CRLF sequence. We cater to yet another broken
567 * implementation of a previously-standard protocol...
569 *np = '\0';
570 if (strstr(name, "CLIENT"))
571 putf("\r\n");
573 (void)signal(SIGINT, SIG_IGN);
574 *np = 0;
575 if (c == '\r')
576 crmod = 1;
577 if ((upper && !lower && !LC) || UC)
578 for (np = name; *np; np++)
579 *np = tolower((unsigned char)*np);
580 return (1 + ppp_connection);
583 static void
584 xputs(const char *s)
586 while (*s)
587 putchr(*s++);
590 char outbuf[OBUFSIZ];
591 size_t obufcnt = 0;
593 static int
594 putchr(int cc)
596 unsigned char c;
598 c = cc;
599 if (!NP) {
600 c |= partab[c&0177] & 0200;
601 if (OP)
602 c ^= 0200;
604 if (!UB) {
605 outbuf[obufcnt++] = c;
606 if (obufcnt >= OBUFSIZ)
607 oflush();
608 return 1;
610 return write(STDOUT_FILENO, &c, 1);
613 static void
614 oflush(void)
616 if (obufcnt)
617 (void)write(STDOUT_FILENO, outbuf, obufcnt);
618 obufcnt = 0;
621 static void
622 prompt(void)
625 putf(LM);
626 if (CO)
627 putchr('\n');
630 static void
631 putf(const char *cp)
633 time_t t;
634 char *slash, db[100];
636 while (*cp) {
637 if (*cp != '%') {
638 putchr(*cp++);
639 continue;
641 switch (*++cp) {
643 case 't':
644 if ((slash = strstr(ttyn, "/pts/")) == NULL)
645 slash = strrchr(ttyn, '/');
646 if (slash == NULL)
647 xputs(ttyn);
648 else
649 xputs(&slash[1]);
650 break;
652 case 'h':
653 xputs(editedhost);
654 break;
656 case 'd':
657 (void)time(&t);
658 (void)strftime(db, sizeof(db),
659 "%l:%M%p on %A, %d %B %Y", localtime(&t));
660 xputs(db);
661 break;
663 case 's':
664 xputs(kerninfo.sysname);
665 break;
667 case 'm':
668 xputs(kerninfo.machine);
669 break;
671 case 'r':
672 xputs(kerninfo.release);
673 break;
675 case 'v':
676 xputs(kerninfo.version);
677 break;
679 case '%':
680 putchr('%');
681 break;
683 if (*cp)
684 cp++;
688 static void
689 clearscreen(void)
691 struct ttyent *typ;
692 int err;
694 if (rawttyn == NULL)
695 return;
697 typ = getttynam(rawttyn);
699 if ((typ == NULL) || (typ->ty_type == NULL) ||
700 (typ->ty_type[0] == 0))
701 return;
703 if (setupterm(typ->ty_type, 0, &err) == ERR)
704 return;
706 if (clear_screen)
707 putpad(clear_screen);
709 del_curterm(cur_term);
710 cur_term = NULL;