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