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