]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - libexec/getty/subr.c
Don't cast away the const, it's not been needed since r92925.
[FreeBSD/FreeBSD.git] / libexec / getty / subr.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1983, 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 #if 0
34 static char sccsid[] = "@(#)from: subr.c        8.1 (Berkeley) 6/4/93";
35 #endif
36 static const char rcsid[] =
37   "$FreeBSD$";
38 #endif /* not lint */
39
40 /*
41  * Melbourne getty.
42  */
43 #include <sys/ioctl.h>
44 #include <sys/param.h>
45 #include <sys/time.h>
46
47 #include <poll.h>
48 #include <regex.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <syslog.h>
52 #include <termios.h>
53 #include <unistd.h>
54
55 #include "gettytab.h"
56 #include "pathnames.h"
57 #include "extern.h"
58
59 /*
60  * Get a table entry.
61  */
62 void
63 gettable(const char *name, char *buf)
64 {
65         struct gettystrs *sp;
66         struct gettynums *np;
67         struct gettyflags *fp;
68         long n;
69         int l;
70         char *p;
71         char *msg = NULL;
72         const char *dba[2];
73
74         static int firsttime = 1;
75
76         dba[0] = _PATH_GETTYTAB;
77         dba[1] = NULL;
78
79         if (firsttime) {
80                 /*
81                  * we need to strdup() anything in the strings array
82                  * initially in order to simplify things later
83                  */
84                 for (sp = gettystrs; sp->field; sp++)
85                         if (sp->value != NULL) {
86                                 /* handle these ones more carefully */
87                                 if (sp >= &gettystrs[4] && sp <= &gettystrs[6])
88                                         l = 2;
89                                 else
90                                         l = strlen(sp->value) + 1;
91                                 if ((p = malloc(l)) != NULL) {
92                                         strncpy(p, sp->value, l);
93                                         p[l-1] = '\0';
94                                 }
95                                 /*
96                                  * replace, even if NULL, else we'll
97                                  * have problems with free()ing static mem
98                                  */
99                                 sp->value = p;
100                         }
101                 firsttime = 0;
102         }
103
104         switch (cgetent(&buf, (char **)dba, name)) {
105         case 1:
106                 msg = "%s: couldn't resolve 'tc=' in gettytab '%s'";
107         case 0:
108                 break;
109         case -1:
110                 msg = "%s: unknown gettytab entry '%s'";
111                 break;
112         case -2:
113                 msg = "%s: retrieving gettytab entry '%s': %m";
114                 break;
115         case -3:
116                 msg = "%s: recursive 'tc=' reference gettytab entry '%s'";
117                 break;
118         default:
119                 msg = "%s: unexpected cgetent() error for entry '%s'";
120                 break;
121         }
122
123         if (msg != NULL) {
124                 syslog(LOG_ERR, msg, "getty", name);
125                 return;
126         }
127
128         for (sp = gettystrs; sp->field; sp++) {
129                 if ((l = cgetstr(buf, sp->field, &p)) >= 0) {
130                         if (sp->value) {
131                                 /* prefer existing value */
132                                 if (strcmp(p, sp->value) != 0)
133                                         free(sp->value);
134                                 else {
135                                         free(p);
136                                         p = sp->value;
137                                 }
138                         }
139                         sp->value = p;
140                 } else if (l == -1) {
141                         free(sp->value);
142                         sp->value = NULL;
143                 }
144         }
145
146         for (np = gettynums; np->field; np++) {
147                 if (cgetnum(buf, np->field, &n) == -1)
148                         np->set = 0;
149                 else {
150                         np->set = 1;
151                         np->value = n;
152                 }
153         }
154
155         for (fp = gettyflags; fp->field; fp++) {
156                 if (cgetcap(buf, fp->field, ':') == NULL)
157                         fp->set = 0;
158                 else {
159                         fp->set = 1;
160                         fp->value = 1 ^ fp->invrt;
161                 }
162         }
163 }
164
165 void
166 gendefaults(void)
167 {
168         struct gettystrs *sp;
169         struct gettynums *np;
170         struct gettyflags *fp;
171
172         for (sp = gettystrs; sp->field; sp++)
173                 if (sp->value)
174                         sp->defalt = strdup(sp->value);
175         for (np = gettynums; np->field; np++)
176                 if (np->set)
177                         np->defalt = np->value;
178         for (fp = gettyflags; fp->field; fp++)
179                 if (fp->set)
180                         fp->defalt = fp->value;
181                 else
182                         fp->defalt = fp->invrt;
183 }
184
185 void
186 setdefaults(void)
187 {
188         struct gettystrs *sp;
189         struct gettynums *np;
190         struct gettyflags *fp;
191
192         for (sp = gettystrs; sp->field; sp++)
193                 if (!sp->value)
194                         sp->value = !sp->defalt ? sp->defalt
195                                                 : strdup(sp->defalt);
196         for (np = gettynums; np->field; np++)
197                 if (!np->set)
198                         np->value = np->defalt;
199         for (fp = gettyflags; fp->field; fp++)
200                 if (!fp->set)
201                         fp->value = fp->defalt;
202 }
203
204 static char **
205 charnames[] = {
206         &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
207         &SU, &DS, &RP, &FL, &WE, &LN, 0
208 };
209
210 static char *
211 charvars[] = {
212         &tmode.c_cc[VERASE], &tmode.c_cc[VKILL], &tmode.c_cc[VINTR],
213         &tmode.c_cc[VQUIT], &tmode.c_cc[VSTART], &tmode.c_cc[VSTOP],
214         &tmode.c_cc[VEOF], &tmode.c_cc[VEOL], &tmode.c_cc[VSUSP],
215         &tmode.c_cc[VDSUSP], &tmode.c_cc[VREPRINT], &tmode.c_cc[VDISCARD],
216         &tmode.c_cc[VWERASE], &tmode.c_cc[VLNEXT], 0
217 };
218
219 void
220 setchars(void)
221 {
222         int i;
223         const char *p;
224
225         for (i = 0; charnames[i]; i++) {
226                 p = *charnames[i];
227                 if (p && *p)
228                         *charvars[i] = *p;
229                 else
230                         *charvars[i] = _POSIX_VDISABLE;
231         }
232 }
233
234 /* Macros to clear/set/test flags. */
235 #define SET(t, f)       (t) |= (f)
236 #define CLR(t, f)       (t) &= ~(f)
237 #define ISSET(t, f)     ((t) & (f))
238
239 void
240 set_flags(int n)
241 {
242         tcflag_t iflag, oflag, cflag, lflag;
243
244
245         switch (n) {
246         case 0:
247                 if (C0set && I0set && L0set && O0set) {
248                         tmode.c_cflag = C0;
249                         tmode.c_iflag = I0;
250                         tmode.c_lflag = L0;
251                         tmode.c_oflag = O0;
252                         return;
253                 }
254                 break;
255         case 1:
256                 if (C1set && I1set && L1set && O1set) {
257                         tmode.c_cflag = C1;
258                         tmode.c_iflag = I1;
259                         tmode.c_lflag = L1;
260                         tmode.c_oflag = O1;
261                         return;
262                 }
263                 break;
264         default:
265                 if (C2set && I2set && L2set && O2set) {
266                         tmode.c_cflag = C2;
267                         tmode.c_iflag = I2;
268                         tmode.c_lflag = L2;
269                         tmode.c_oflag = O2;
270                         return;
271                 }
272                 break;
273         }
274
275         iflag = omode.c_iflag;
276         oflag = omode.c_oflag;
277         cflag = omode.c_cflag;
278         lflag = omode.c_lflag;
279
280         if (NP) {
281                 CLR(cflag, CSIZE|PARENB);
282                 SET(cflag, CS8);
283                 CLR(iflag, ISTRIP|INPCK|IGNPAR);
284         } else if (AP || EP || OP) {
285                 CLR(cflag, CSIZE);
286                 SET(cflag, CS7|PARENB);
287                 SET(iflag, ISTRIP);
288                 if (OP && !EP) {
289                         SET(iflag, INPCK|IGNPAR);
290                         SET(cflag, PARODD);
291                         if (AP)
292                                 CLR(iflag, INPCK);
293                 } else if (EP && !OP) {
294                         SET(iflag, INPCK|IGNPAR);
295                         CLR(cflag, PARODD);
296                         if (AP)
297                                 CLR(iflag, INPCK);
298                 } else if (AP || (EP && OP)) {
299                         CLR(iflag, INPCK|IGNPAR);
300                         CLR(cflag, PARODD);
301                 }
302         } /* else, leave as is */
303
304 #if 0
305         if (UC)
306                 f |= LCASE;
307 #endif
308
309         if (HC)
310                 SET(cflag, HUPCL);
311         else
312                 CLR(cflag, HUPCL);
313
314         if (MB)
315                 SET(cflag, MDMBUF);
316         else
317                 CLR(cflag, MDMBUF);
318
319         if (HW)
320                 SET(cflag, CRTSCTS);
321         else
322                 CLR(cflag, CRTSCTS);
323
324         if (NL) {
325                 SET(iflag, ICRNL);
326                 SET(oflag, ONLCR|OPOST);
327         } else {
328                 CLR(iflag, ICRNL);
329                 CLR(oflag, ONLCR);
330         }
331
332         if (!HT)
333                 SET(oflag, OXTABS|OPOST);
334         else
335                 CLR(oflag, OXTABS);
336
337 #ifdef XXX_DELAY
338         SET(f, delaybits());
339 #endif
340
341         if (n == 1) {           /* read mode flags */
342                 if (RW) {
343                         iflag = 0;
344                         CLR(oflag, OPOST);
345                         CLR(cflag, CSIZE|PARENB);
346                         SET(cflag, CS8);
347                         lflag = 0;
348                 } else {
349                         CLR(lflag, ICANON);
350                 }
351                 goto out;
352         }
353
354         if (n == 0)
355                 goto out;
356
357 #if 0
358         if (CB)
359                 SET(f, CRTBS);
360 #endif
361
362         if (CE)
363                 SET(lflag, ECHOE);
364         else
365                 CLR(lflag, ECHOE);
366
367         if (CK)
368                 SET(lflag, ECHOKE);
369         else
370                 CLR(lflag, ECHOKE);
371
372         if (PE)
373                 SET(lflag, ECHOPRT);
374         else
375                 CLR(lflag, ECHOPRT);
376
377         if (EC)
378                 SET(lflag, ECHO);
379         else
380                 CLR(lflag, ECHO);
381
382         if (XC)
383                 SET(lflag, ECHOCTL);
384         else
385                 CLR(lflag, ECHOCTL);
386
387         if (DX)
388                 SET(lflag, IXANY);
389         else
390                 CLR(lflag, IXANY);
391
392 out:
393         tmode.c_iflag = iflag;
394         tmode.c_oflag = oflag;
395         tmode.c_cflag = cflag;
396         tmode.c_lflag = lflag;
397 }
398
399
400 #ifdef XXX_DELAY
401 struct delayval {
402         unsigned        delay;          /* delay in ms */
403         int             bits;
404 };
405
406 /*
407  * below are random guesses, I can't be bothered checking
408  */
409
410 struct delayval crdelay[] = {
411         { 1,            CR1 },
412         { 2,            CR2 },
413         { 3,            CR3 },
414         { 83,           CR1 },
415         { 166,          CR2 },
416         { 0,            CR3 },
417 };
418
419 struct delayval nldelay[] = {
420         { 1,            NL1 },          /* special, calculated */
421         { 2,            NL2 },
422         { 3,            NL3 },
423         { 100,          NL2 },
424         { 0,            NL3 },
425 };
426
427 struct delayval bsdelay[] = {
428         { 1,            BS1 },
429         { 0,            0 },
430 };
431
432 struct delayval ffdelay[] = {
433         { 1,            FF1 },
434         { 1750,         FF1 },
435         { 0,            FF1 },
436 };
437
438 struct delayval tbdelay[] = {
439         { 1,            TAB1 },
440         { 2,            TAB2 },
441         { 3,            XTABS },        /* this is expand tabs */
442         { 100,          TAB1 },
443         { 0,            TAB2 },
444 };
445
446 int
447 delaybits(void)
448 {
449         int f;
450
451         f  = adelay(CD, crdelay);
452         f |= adelay(ND, nldelay);
453         f |= adelay(FD, ffdelay);
454         f |= adelay(TD, tbdelay);
455         f |= adelay(BD, bsdelay);
456         return (f);
457 }
458
459 int
460 adelay(int ms, struct delayval *dp)
461 {
462         if (ms == 0)
463                 return (0);
464         while (dp->delay && ms > dp->delay)
465                 dp++;
466         return (dp->bits);
467 }
468 #endif
469
470 char    editedhost[MAXHOSTNAMELEN];
471
472 void
473 edithost(const char *pattern)
474 {
475         regex_t regex;
476         regmatch_t *match;
477         int found;
478
479         if (pattern == NULL || *pattern == '\0')
480                 goto copyasis;
481         if (regcomp(&regex, pattern, REG_EXTENDED) != 0)
482                 goto copyasis;
483
484         match = calloc(regex.re_nsub + 1, sizeof(*match));
485         if (match == NULL) {
486                 regfree(&regex);
487                 goto copyasis;
488         }
489
490         found = !regexec(&regex, HN, regex.re_nsub + 1, match, 0);
491         if (found) {
492                 size_t subex, totalsize;
493
494                 /*
495                  * We found a match.  If there were no parenthesized
496                  * subexpressions in the pattern, use entire matched
497                  * string as ``editedhost''; otherwise use the first
498                  * matched subexpression.
499                  */
500                 subex = !!regex.re_nsub;
501                 totalsize = match[subex].rm_eo - match[subex].rm_so + 1;
502                 strlcpy(editedhost, HN + match[subex].rm_so, totalsize >
503                     sizeof(editedhost) ? sizeof(editedhost) : totalsize);
504         }
505         free(match);
506         regfree(&regex);
507         if (found)
508                 return;
509         /*
510          * In case of any errors, or if the pattern did not match, pass
511          * the original hostname as is.
512          */
513  copyasis:
514         strlcpy(editedhost, HN, sizeof(editedhost));
515 }
516
517 static struct speedtab {
518         int     speed;
519         int     uxname;
520 } speedtab[] = {
521         { 50,   B50 },
522         { 75,   B75 },
523         { 110,  B110 },
524         { 134,  B134 },
525         { 150,  B150 },
526         { 200,  B200 },
527         { 300,  B300 },
528         { 600,  B600 },
529         { 1200, B1200 },
530         { 1800, B1800 },
531         { 2400, B2400 },
532         { 4800, B4800 },
533         { 9600, B9600 },
534         { 19200, EXTA },
535         { 19,   EXTA },         /* for people who say 19.2K */
536         { 38400, EXTB },
537         { 38,   EXTB },
538         { 7200, EXTB },         /* alternative */
539         { 57600, B57600 },
540         { 115200, B115200 },
541         { 230400, B230400 },
542         { 0 }
543 };
544
545 int
546 speed(int val)
547 {
548         struct speedtab *sp;
549
550         if (val <= B230400)
551                 return (val);
552
553         for (sp = speedtab; sp->speed; sp++)
554                 if (sp->speed == val)
555                         return (sp->uxname);
556
557         return (B300);          /* default in impossible cases */
558 }
559
560 void
561 makeenv(char *env[])
562 {
563         static char termbuf[128] = "TERM=";
564         char *p, *q;
565         char **ep;
566
567         ep = env;
568         if (TT && *TT) {
569                 strlcat(termbuf, TT, sizeof(termbuf));
570                 *ep++ = termbuf;
571         }
572         if ((p = EV)) {
573                 q = p;
574                 while ((q = strchr(q, ','))) {
575                         *q++ = '\0';
576                         *ep++ = p;
577                         p = q;
578                 }
579                 if (*p)
580                         *ep++ = p;
581         }
582         *ep = (char *)0;
583 }
584
585 /*
586  * This speed select mechanism is written for the Develcon DATASWITCH.
587  * The Develcon sends a string of the form "B{speed}\n" at a predefined
588  * baud rate. This string indicates the user's actual speed.
589  * The routine below returns the terminal type mapped from derived speed.
590  */
591 struct  portselect {
592         const char      *ps_baud;
593         const char      *ps_type;
594 } portspeeds[] = {
595         { "B110",       "std.110" },
596         { "B134",       "std.134" },
597         { "B150",       "std.150" },
598         { "B300",       "std.300" },
599         { "B600",       "std.600" },
600         { "B1200",      "std.1200" },
601         { "B2400",      "std.2400" },
602         { "B4800",      "std.4800" },
603         { "B9600",      "std.9600" },
604         { "B19200",     "std.19200" },
605         { NULL, NULL }
606 };
607
608 const char *
609 portselector(void)
610 {
611         char c, baud[20];
612         const char *type = "default";
613         struct portselect *ps;
614         size_t len;
615
616         alarm(5*60);
617         for (len = 0; len < sizeof (baud) - 1; len++) {
618                 if (read(STDIN_FILENO, &c, 1) <= 0)
619                         break;
620                 c &= 0177;
621                 if (c == '\n' || c == '\r')
622                         break;
623                 if (c == 'B')
624                         len = 0;        /* in case of leading garbage */
625                 baud[len] = c;
626         }
627         baud[len] = '\0';
628         for (ps = portspeeds; ps->ps_baud; ps++)
629                 if (strcmp(ps->ps_baud, baud) == 0) {
630                         type = ps->ps_type;
631                         break;
632                 }
633         sleep(2);       /* wait for connection to complete */
634         return (type);
635 }
636
637 /*
638  * This auto-baud speed select mechanism is written for the Micom 600
639  * portselector. Selection is done by looking at how the character '\r'
640  * is garbled at the different speeds.
641  */
642 const char *
643 autobaud(void)
644 {
645         struct pollfd set[1];
646         struct timespec timeout;
647         char c;
648         const char *type = "9600-baud";
649
650         (void)tcflush(0, TCIOFLUSH);
651         set[0].fd = STDIN_FILENO;
652         set[0].events = POLLIN;
653         if (poll(set, 1, 5000) <= 0)
654                 return (type);
655         if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
656                 return (type);
657         timeout.tv_sec = 0;
658         timeout.tv_nsec = 20000;
659         (void)nanosleep(&timeout, NULL);
660         (void)tcflush(0, TCIOFLUSH);
661         switch (c & 0377) {
662
663         case 0200:              /* 300-baud */
664                 type = "300-baud";
665                 break;
666
667         case 0346:              /* 1200-baud */
668                 type = "1200-baud";
669                 break;
670
671         case  015:              /* 2400-baud */
672         case 0215:
673                 type = "2400-baud";
674                 break;
675
676         default:                /* 4800-baud */
677                 type = "4800-baud";
678                 break;
679
680         case 0377:              /* 9600-baud */
681                 type = "9600-baud";
682                 break;
683         }
684         return (type);
685 }