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