]> git.cameronkatri.com Git - apple_cmds.git/blob - system_cmds/getty.tproj/main.c
Merge branch 'apple'
[apple_cmds.git] / system_cmds / getty.tproj / main.c
1 /*-
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Portions copyright (c) 2007 Apple Inc. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __unused static const 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 #endif
46 __unused static const char rcsid[] =
47 "$FreeBSD: src/libexec/getty/main.c,v 1.47 2005/04/06 17:42:24 stefanf Exp $";
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #include <sys/ioctl.h>
52 #include <sys/time.h>
53 #include <sys/resource.h>
54 #include <sys/stat.h>
55 #include <sys/ttydefaults.h>
56 #include <sys/utsname.h>
57
58 #include <ctype.h>
59 #include <errno.h>
60 #include <fcntl.h>
61 #include <locale.h>
62 #ifdef __APPLE__
63 #include <util.h>
64 #else
65 #include <libutil.h>
66 #endif
67 #include <setjmp.h>
68 #include <signal.h>
69 #include <stdlib.h>
70 #include <string.h>
71 #include <syslog.h>
72 #include <termios.h>
73 #include <time.h>
74 #include <unistd.h>
75
76 #ifdef __APPLE__
77 #include <TargetConditionals.h>
78 #endif
79
80 #include <libiosexec.h>
81
82 #include "gettytab.h"
83 #include "extern.h"
84 #include "pathnames.h"
85
86 /*
87 * Set the amount of running time that getty should accumulate
88 * before deciding that something is wrong and exit.
89 */
90 #define GETTY_TIMEOUT 60 /* seconds */
91
92 #undef CTRL
93 #define CTRL(x) (x&037)
94
95 /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */
96
97 #define PPP_FRAME 0x7e /* PPP Framing character */
98 #define PPP_STATION 0xff /* "All Station" character */
99 #define PPP_ESCAPE 0x7d /* Escape Character */
100 #define PPP_CONTROL 0x03 /* PPP Control Field */
101 #define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */
102 #define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */
103 #define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */
104
105 /* original mode; flags've been reset using values from <sys/ttydefaults.h> */
106 struct termios omode;
107 /* current mode */
108 struct termios tmode;
109
110 int crmod, digit, lower, upper;
111
112 char hostname[MAXHOSTNAMELEN];
113 char name[MAXLOGNAME*3];
114 char dev[] = _PATH_DEV;
115 char ttyn[32];
116
117 #define OBUFSIZ 128
118 #define TABBUFSIZ 512
119
120 const char *tname;
121
122 char *env[128];
123
124 char partab[] = {
125 0001,0201,0201,0001,0201,0001,0001,0201,
126 0202,0004,0003,0205,0005,0206,0201,0001,
127 0201,0001,0001,0201,0001,0201,0201,0001,
128 0001,0201,0201,0001,0201,0001,0001,0201,
129 0200,0000,0000,0200,0000,0200,0200,0000,
130 0000,0200,0200,0000,0200,0000,0000,0200,
131 0000,0200,0200,0000,0200,0000,0000,0200,
132 0200,0000,0000,0200,0000,0200,0200,0000,
133 0200,0000,0000,0200,0000,0200,0200,0000,
134 0000,0200,0200,0000,0200,0000,0000,0200,
135 0000,0200,0200,0000,0200,0000,0000,0200,
136 0200,0000,0000,0200,0000,0200,0200,0000,
137 0000,0200,0200,0000,0200,0000,0000,0200,
138 0200,0000,0000,0200,0000,0200,0200,0000,
139 0200,0000,0000,0200,0000,0200,0200,0000,
140 0000,0200,0200,0000,0200,0000,0000,0201
141 };
142
143 #define ERASE tmode.c_cc[VERASE]
144 #define KILL tmode.c_cc[VKILL]
145 #define EOT tmode.c_cc[VEOF]
146
147 #define puts Gputs
148
149 static void defttymode(void);
150 static void dingdong(int);
151 static void dogettytab(void);
152 static int getname(void);
153 static void interrupt(int);
154 static void oflush(void);
155 static void prompt(void);
156 static void putchr(int);
157 static void putf(const char *);
158 static void putpad(const char *);
159 static void puts(const char *);
160 static void timeoverrun(int);
161 static char *getty_getline(int);
162 static void setttymode(int);
163 static int opentty(const char *, int);
164
165 jmp_buf timeout;
166
167 static void
168 dingdong(int signo __unused)
169 {
170 alarm(0);
171 longjmp(timeout, 1);
172 }
173
174 jmp_buf intrupt;
175
176 static void
177 interrupt(int signo __unused)
178 {
179 longjmp(intrupt, 1);
180 }
181
182 /*
183 * Action to take when getty is running too long.
184 */
185 static void
186 timeoverrun(int signo __unused)
187 {
188
189 syslog(LOG_ERR, "getty exiting due to excessive running time");
190 exit(1);
191 }
192
193 int
194 main(int argc, char *argv[])
195 {
196 extern char **environ;
197 int first_sleep = 1, first_time = 1;
198 struct rlimit limit;
199 int rval;
200 #ifdef __APPLE__
201 int ttyopenmode = O_RDWR;
202 #endif
203
204 signal(SIGINT, SIG_IGN);
205 signal(SIGQUIT, SIG_IGN);
206
207 openlog("getty", LOG_ODELAY|LOG_CONS|LOG_PID, LOG_AUTH);
208 gethostname(hostname, sizeof(hostname) - 1);
209 hostname[sizeof(hostname) - 1] = '\0';
210 if (hostname[0] == '\0')
211 strcpy(hostname, "Amnesiac");
212
213 /*
214 * Limit running time to deal with broken or dead lines.
215 */
216 (void)signal(SIGXCPU, timeoverrun);
217 limit.rlim_max = RLIM_INFINITY;
218 limit.rlim_cur = GETTY_TIMEOUT;
219 (void)setrlimit(RLIMIT_CPU, &limit);
220
221 gettable("default");
222 gendefaults();
223 tname = "default";
224 if (argc > 1)
225 tname = argv[1];
226
227 /*
228 * The following is a work around for vhangup interactions
229 * which cause great problems getting window systems started.
230 * If the tty line is "-", we do the old style getty presuming
231 * that the file descriptors are already set up for us.
232 * J. Gettys - MIT Project Athena.
233 */
234 if (argc <= 2 || strcmp(argv[2], "-") == 0)
235 #ifdef __APPLE__
236 {
237 // <rdar://problem/5178373>
238 char* n = ttyname(STDIN_FILENO);
239 if (n) {
240 strlcpy(ttyn, n, sizeof(ttyn));
241 } else {
242 syslog(LOG_ERR, "ttyname %m");
243 exit(1);
244 }
245 }
246 #else
247 strcpy(ttyn, ttyname(STDIN_FILENO));
248 #endif
249 else {
250 strcpy(ttyn, dev);
251 strncat(ttyn, argv[2], sizeof(ttyn)-sizeof(dev));
252 if (strcmp(argv[0], "+") != 0) {
253 chown(ttyn, 0, 0);
254 chmod(ttyn, 0600);
255 revoke(ttyn);
256
257 /*
258 * Do the first scan through gettytab.
259 * Terminal mode parameters will be wrong until
260 * defttymode() called, but they're irrelevant for
261 * the initial setup of the terminal device.
262 */
263 dogettytab();
264
265 #if defined(__APPLE__) && !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR)
266 if (strncmp(ttyn, _PATH_CONSOLE, sizeof(ttyn)) == 0)
267 ttyopenmode |= O_POPUP;
268 #endif
269 /*
270 * Init or answer modem sequence has been specified.
271 */
272 if (IC || AC) {
273 #ifdef __APPLE__
274 if (!opentty(ttyn, ttyopenmode))
275 #else
276 if (!opentty(ttyn, O_RDWR|O_NONBLOCK))
277 #endif
278 exit(1);
279 defttymode();
280 setttymode(1);
281 }
282
283 if (IC) {
284 if (getty_chat(IC, CT, DC) > 0) {
285 syslog(LOG_ERR, "modem init problem on %s", ttyn);
286 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
287 exit(1);
288 }
289 }
290
291 if (AC) {
292 int i, rfds;
293 struct timeval to;
294
295 rfds = 1 << 0; /* FD_SET */
296 to.tv_sec = RT;
297 to.tv_usec = 0;
298 i = select(32, (fd_set*)&rfds, (fd_set*)NULL,
299 (fd_set*)NULL, RT ? &to : NULL);
300 if (i < 0) {
301 syslog(LOG_ERR, "select %s: %m", ttyn);
302 } else if (i == 0) {
303 syslog(LOG_NOTICE, "recycle tty %s", ttyn);
304 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
305 exit(0); /* recycle for init */
306 }
307 i = getty_chat(AC, CT, DC);
308 if (i > 0) {
309 syslog(LOG_ERR, "modem answer problem on %s", ttyn);
310 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
311 exit(1);
312 }
313 } else { /* maybe blocking open */
314 #ifdef __APPLE__
315 if (!opentty(ttyn, ttyopenmode | (NC ? O_NONBLOCK : 0 )))
316 #else
317 if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 )))
318 #endif
319 exit(1);
320 }
321 }
322 }
323
324 defttymode();
325 for (;;) {
326
327 /*
328 * if a delay was specified then sleep for that
329 * number of seconds before writing the initial prompt
330 */
331 if (first_sleep && DE) {
332 sleep(DE);
333 /* remove any noise */
334 (void)tcflush(STDIN_FILENO, TCIOFLUSH);
335 }
336 first_sleep = 0;
337
338 setttymode(0);
339 if (AB) {
340 tname = autobaud();
341 dogettytab();
342 continue;
343 }
344 if (PS) {
345 tname = portselector();
346 dogettytab();
347 continue;
348 }
349 if (CL && *CL)
350 putpad(CL);
351 edithost(HE);
352
353 /* if this is the first time through this, and an
354 issue file has been given, then send it */
355 if (first_time && IF) {
356 int fd;
357
358 if ((fd = open(IF, O_RDONLY)) != -1) {
359 char * cp;
360
361 while ((cp = getty_getline(fd)) != NULL) {
362 putf(cp);
363 }
364 close(fd);
365 }
366 }
367 first_time = 0;
368
369 if (IM && *IM && !(PL && PP))
370 putf(IM);
371 if (setjmp(timeout)) {
372 cfsetispeed(&tmode, B0);
373 cfsetospeed(&tmode, B0);
374 (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode);
375 exit(1);
376 }
377 if (TO) {
378 signal(SIGALRM, dingdong);
379 alarm(TO);
380 }
381
382 rval = 0;
383 if (AL) {
384 const char *p = AL;
385 char *q = name;
386
387 while (*p && q < &name[sizeof name - 1]) {
388 if (isupper(*p))
389 upper = 1;
390 else if (islower(*p))
391 lower = 1;
392 else if (isdigit(*p))
393 digit = 1;
394 *q++ = *p++;
395 }
396 } else if (!(PL && PP))
397 rval = getname();
398 if (rval == 2 || (PL && PP)) {
399 oflush();
400 alarm(0);
401 limit.rlim_max = RLIM_INFINITY;
402 limit.rlim_cur = RLIM_INFINITY;
403 (void)setrlimit(RLIMIT_CPU, &limit);
404 execle(PP, "ppplogin", ttyn, (char *) 0, env);
405 syslog(LOG_ERR, "%s: %m", PP);
406 exit(1);
407 } else if (rval || AL) {
408 int i;
409
410 oflush();
411 alarm(0);
412 signal(SIGALRM, SIG_DFL);
413 if (name[0] == '\0')
414 continue;
415 if (name[0] == '-') {
416 puts("user names may not start with '-'.");
417 continue;
418 }
419 if (!(upper || lower || digit)) {
420 if (AL) {
421 syslog(LOG_ERR,
422 "invalid auto-login name: %s", AL);
423 exit(1);
424 } else
425 continue;
426 }
427 set_flags(2);
428 if (crmod) {
429 tmode.c_iflag |= ICRNL;
430 tmode.c_oflag |= ONLCR;
431 }
432 #if REALLY_OLD_TTYS
433 if (upper || UC)
434 tmode.sg_flags |= LCASE;
435 if (lower || LC)
436 tmode.sg_flags &= ~LCASE;
437 #endif
438 if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
439 syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
440 exit(1);
441 }
442 signal(SIGINT, SIG_DFL);
443 for (i = 0; environ[i] != (char *)0; i++)
444 env[i] = environ[i];
445 makeenv(&env[i]);
446
447 limit.rlim_max = RLIM_INFINITY;
448 limit.rlim_cur = RLIM_INFINITY;
449 (void)setrlimit(RLIMIT_CPU, &limit);
450 #ifdef __APPLE__
451 // <rdar://problem/3205179>
452 execle(LO, "login", AL ? "-fp1" : "-p1", name,
453 #else
454 execle(LO, "login", AL ? "-fp" : "-p", name,
455 #endif
456 (char *) 0, env);
457 syslog(LOG_ERR, "%s: %m", LO);
458 exit(1);
459 }
460 alarm(0);
461 signal(SIGALRM, SIG_DFL);
462 signal(SIGINT, SIG_IGN);
463 if (NX && *NX) {
464 tname = NX;
465 dogettytab();
466 }
467 }
468 }
469
470 static int
471 opentty(const char *tty, int flags)
472 {
473 int i;
474 int failopenlogged = 0;
475
476 while ((i = open(tty, flags)) == -1)
477 {
478 if (!failopenlogged) {
479 syslog(LOG_ERR, "open %s: %m", tty);
480 failopenlogged = 1;
481 }
482 sleep(60);
483 }
484 if (login_tty(i) < 0) {
485 #ifndef __APPLE__
486 if (daemon(0,0) < 0) {
487 syslog(LOG_ERR,"daemon: %m");
488 close(i);
489 return 0;
490 }
491 #endif
492 if (login_tty(i) < 0) {
493 syslog(LOG_ERR, "login_tty %s: %m", tty);
494 close(i);
495 return 0;
496 }
497 }
498 return 1;
499 }
500
501 static void
502 defttymode(void)
503 {
504
505 /* Start with default tty settings. */
506 if (tcgetattr(STDIN_FILENO, &tmode) < 0) {
507 syslog(LOG_ERR, "tcgetattr %s: %m", ttyn);
508 exit(1);
509 }
510 omode = tmode; /* fill c_cc for dogettytab() */
511 dogettytab();
512 /*
513 * Don't rely on the driver too much, and initialize crucial
514 * things according to <sys/ttydefaults.h>. Avoid clobbering
515 * the c_cc[] settings however, the console drivers might wish
516 * to leave their idea of the preferred VERASE key value
517 * there.
518 */
519 tmode.c_iflag = TTYDEF_IFLAG;
520 tmode.c_oflag = TTYDEF_OFLAG;
521 tmode.c_lflag = TTYDEF_LFLAG;
522 tmode.c_cflag = TTYDEF_CFLAG;
523 if (NC)
524 tmode.c_cflag |= CLOCAL;
525 omode = tmode;
526 }
527
528 static void
529 setttymode(int raw)
530 {
531 int off = 0;
532
533 (void)tcflush(STDIN_FILENO, TCIOFLUSH); /* clear out the crap */
534 ioctl(STDIN_FILENO, FIONBIO, &off); /* turn off non-blocking mode */
535 ioctl(STDIN_FILENO, FIOASYNC, &off); /* ditto for async mode */
536
537 if (IS)
538 cfsetispeed(&tmode, speed(IS));
539 else if (SP)
540 cfsetispeed(&tmode, speed(SP));
541 if (OS)
542 cfsetospeed(&tmode, speed(OS));
543 else if (SP)
544 cfsetospeed(&tmode, speed(SP));
545 set_flags(0);
546 setchars();
547 if (raw)
548 cfmakeraw(&tmode);
549 if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
550 syslog(LOG_ERR, "tcsetattr %s: %m", ttyn);
551 exit(1);
552 }
553 }
554
555
556 static int
557 getname(void)
558 {
559 int c;
560 char *np;
561 unsigned char cs;
562 int ppp_state = 0;
563 int ppp_connection = 0;
564
565 /*
566 * Interrupt may happen if we use CBREAK mode
567 */
568 if (setjmp(intrupt)) {
569 signal(SIGINT, SIG_IGN);
570 return (0);
571 }
572 signal(SIGINT, interrupt);
573 set_flags(1);
574 prompt();
575 oflush();
576 if (PF > 0) {
577 sleep(PF);
578 PF = 0;
579 }
580 if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) {
581 syslog(LOG_ERR, "%s: %m", ttyn);
582 exit(1);
583 }
584 crmod = digit = lower = upper = 0;
585 np = name;
586 for (;;) {
587 oflush();
588 if (read(STDIN_FILENO, &cs, 1) <= 0)
589 exit(0);
590 if ((c = cs&0177) == 0)
591 return (0);
592
593 /* PPP detection state machine..
594 Look for sequences:
595 PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or
596 PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
597 See RFC1662.
598 Derived from code from Michael Hancock, <michaelh@cet.co.jp>
599 and Erik 'PPP' Olson, <eriko@wrq.com>
600 */
601
602 if (PP && (cs == PPP_FRAME)) {
603 ppp_state = 1;
604 } else if (ppp_state == 1 && cs == PPP_STATION) {
605 ppp_state = 2;
606 } else if (ppp_state == 2 && cs == PPP_ESCAPE) {
607 ppp_state = 3;
608 } else if ((ppp_state == 2 && cs == PPP_CONTROL)
609 || (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) {
610 ppp_state = 4;
611 } else if (ppp_state == 4 && cs == PPP_LCP_HI) {
612 ppp_state = 5;
613 } else if (ppp_state == 5 && cs == PPP_LCP_LOW) {
614 ppp_connection = 1;
615 break;
616 } else {
617 ppp_state = 0;
618 }
619
620 if (c == EOT || c == CTRL('d'))
621 exit(0);
622 if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) {
623 putf("\r\n");
624 break;
625 }
626 if (islower(c))
627 lower = 1;
628 else if (isupper(c))
629 upper = 1;
630 else if (c == ERASE || c == '\b' || c == 0177) {
631 if (np > name) {
632 np--;
633 if (cfgetospeed(&tmode) >= 1200)
634 puts("\b \b");
635 else
636 putchr(cs);
637 }
638 continue;
639 } else if (c == KILL || c == CTRL('u')) {
640 putchr('\r');
641 if (cfgetospeed(&tmode) < 1200)
642 putchr('\n');
643 /* this is the way they do it down under ... */
644 else if (np > name)
645 puts(" \r");
646 prompt();
647 digit = lower = upper = 0;
648 np = name;
649 continue;
650 } else if (isdigit(c))
651 digit = 1;
652 if (IG && (c <= ' ' || c > 0176))
653 continue;
654 *np++ = c;
655 putchr(cs);
656 }
657 signal(SIGINT, SIG_IGN);
658 *np = 0;
659 if (c == '\r')
660 crmod = 1;
661 if ((upper && !lower && !LC) || UC)
662 for (np = name; *np; np++)
663 if (isupper(*np))
664 *np = tolower(*np);
665 return (1 + ppp_connection);
666 }
667
668 static void
669 putpad(const char *s)
670 {
671 int pad = 0;
672 speed_t ospeed = cfgetospeed(&tmode);
673
674 if (isdigit(*s)) {
675 while (isdigit(*s)) {
676 pad *= 10;
677 pad += *s++ - '0';
678 }
679 pad *= 10;
680 if (*s == '.' && isdigit(s[1])) {
681 pad += s[1] - '0';
682 s += 2;
683 }
684 }
685
686 puts(s);
687 /*
688 * If no delay needed, or output speed is
689 * not comprehensible, then don't try to delay.
690 */
691 if (pad == 0 || ospeed <= 0)
692 return;
693
694 /*
695 * Round up by a half a character frame, and then do the delay.
696 * Too bad there are no user program accessible programmed delays.
697 * Transmitting pad characters slows many terminals down and also
698 * loads the system.
699 */
700 pad = (pad * ospeed + 50000) / 100000;
701 while (pad--)
702 putchr(*PC);
703 }
704
705 static void
706 puts(const char *s)
707 {
708 while (*s)
709 putchr(*s++);
710 }
711
712 char outbuf[OBUFSIZ];
713 int obufcnt = 0;
714
715 static void
716 putchr(int cc)
717 {
718 char c;
719
720 c = cc;
721 if (!NP) {
722 c |= partab[c&0177] & 0200;
723 if (OP)
724 c ^= 0200;
725 }
726 if (!UB) {
727 outbuf[obufcnt++] = c;
728 if (obufcnt >= OBUFSIZ)
729 oflush();
730 } else
731 write(STDOUT_FILENO, &c, 1);
732 }
733
734 static void
735 oflush(void)
736 {
737 if (obufcnt)
738 write(STDOUT_FILENO, outbuf, obufcnt);
739 obufcnt = 0;
740 }
741
742 static void
743 prompt(void)
744 {
745
746 putf(LM);
747 if (CO)
748 putchr('\n');
749 }
750
751
752 static char *
753 getty_getline(int fd)
754 {
755 int i = 0;
756 static char linebuf[512];
757
758 /*
759 * This is certainly slow, but it avoids having to include
760 * stdio.h unnecessarily. Issue files should be small anyway.
761 */
762 while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) {
763 if (linebuf[i] == '\n') {
764 /* Don't rely on newline mode, assume raw */
765 linebuf[i++] = '\r';
766 linebuf[i++] = '\n';
767 linebuf[i] = '\0';
768 return linebuf;
769 }
770 ++i;
771 }
772 linebuf[i] = '\0';
773 return i ? linebuf : 0;
774 }
775
776 static void
777 putf(const char *cp)
778 {
779 extern char editedhost[];
780 time_t t;
781 char *slash, db[100];
782
783 static struct utsname kerninfo;
784
785 if (!*kerninfo.sysname)
786 uname(&kerninfo);
787
788 while (*cp) {
789 if (*cp != '%') {
790 putchr(*cp++);
791 continue;
792 }
793 switch (*++cp) {
794
795 case 't':
796 slash = strrchr(ttyn, '/');
797 if (slash == (char *) 0)
798 puts(ttyn);
799 else
800 puts(&slash[1]);
801 break;
802
803 case 'h':
804 puts(editedhost);
805 break;
806
807 case 'd': {
808 t = (time_t)0;
809 (void)time(&t);
810 if (Lo)
811 (void)setlocale(LC_TIME, Lo);
812 (void)strftime(db, sizeof(db), DF, localtime(&t));
813 puts(db);
814 break;
815
816 case 's':
817 puts(kerninfo.sysname);
818 break;
819
820 case 'm':
821 puts(kerninfo.machine);
822 break;
823
824 case 'r':
825 puts(kerninfo.release);
826 break;
827
828 case 'v':
829 puts(kerninfo.version);
830 break;
831 }
832
833 case '%':
834 putchr('%');
835 break;
836 }
837 cp++;
838 }
839 }
840
841 /*
842 * Read a gettytab database entry and perform necessary quirks.
843 */
844 static void
845 dogettytab()
846 {
847 /* Read the database entry. */
848 gettable(tname);
849
850 /*
851 * Avoid inheriting the parity values from the default entry
852 * if any of them is set in the current entry.
853 * Mixing different parity settings is unreasonable.
854 */
855 if (OPset || EPset || APset || NPset)
856 OPset = EPset = APset = NPset = 1;
857
858 /* Fill in default values for unset capabilities. */
859 setdefaults();
860 }