]> git.cameronkatri.com Git - apple_cmds.git/blob - system_cmds/getty.tproj/subr.c
atrun: Install LaunchDaemon
[apple_cmds.git] / system_cmds / getty.tproj / subr.c
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 #include <sys/cdefs.h>
35
36 #ifndef lint
37 #if 0
38 static char sccsid[] = "@(#)from: subr.c 8.1 (Berkeley) 6/4/93";
39 #endif
40 __unused static const char rcsid[] =
41 "$FreeBSD: src/libexec/getty/subr.c,v 1.19 2004/06/25 10:11:28 phk Exp $";
42 #endif /* not lint */
43
44 /*
45 * Melbourne getty.
46 */
47 #ifdef DEBUG
48 #include <stdio.h>
49 #endif
50 #include <stdlib.h>
51 #include <string.h>
52 #include <termios.h>
53 #include <unistd.h>
54 #include <sys/ioctl.h>
55 #include <sys/param.h>
56 #include <sys/time.h>
57 #include <syslog.h>
58
59 #include "gettytab.h"
60 #include "pathnames.h"
61 #include "extern.h"
62
63 /*
64 * Get a table entry.
65 */
66 void
67 gettable(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 = (int)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
183 void
184 gendefaults(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
203 void
204 setdefaults(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
222 static char **
223 charnames[] = {
224 &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
225 &SU, &DS, &RP, &FL, &WE, &LN, 0
226 };
227
228 static char *
229 charvars[] = {
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
247 void
248 setchars(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
267 void
268 set_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
420 out:
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
429 struct 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
438 struct delayval crdelay[] = {
439 { 1, CR1 },
440 { 2, CR2 },
441 { 3, CR3 },
442 { 83, CR1 },
443 { 166, CR2 },
444 { 0, CR3 },
445 };
446
447 struct delayval nldelay[] = {
448 { 1, NL1 }, /* special, calculated */
449 { 2, NL2 },
450 { 3, NL3 },
451 { 100, NL2 },
452 { 0, NL3 },
453 };
454
455 struct delayval bsdelay[] = {
456 { 1, BS1 },
457 { 0, 0 },
458 };
459
460 struct delayval ffdelay[] = {
461 { 1, FF1 },
462 { 1750, FF1 },
463 { 0, FF1 },
464 };
465
466 struct delayval tbdelay[] = {
467 { 1, TAB1 },
468 { 2, TAB2 },
469 { 3, XTABS }, /* this is expand tabs */
470 { 100, TAB1 },
471 { 0, TAB2 },
472 };
473
474 int
475 delaybits(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
487 int
488 adelay(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
498 char editedhost[MAXHOSTNAMELEN];
499
500 void
501 edithost(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
539 static 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
567 int
568 speed(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
582 void
583 makeenv(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 */
613 struct 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
630 const char *
631 portselector(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 */
664 const char *
665 autobaud(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 }