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