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