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