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