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