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