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