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