Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / libexec / getty / 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  * @(#)from: subr.c     8.1 (Berkeley) 6/4/93
34  * $FreeBSD: src/libexec/getty/subr.c,v 1.16.2.1 2001/05/12 10:16:51 kris Exp $
35  * $DragonFly: src/libexec/getty/subr.c,v 1.2 2003/06/17 04:27:07 dillon Exp $
36  */
37
38 /*
39  * Melbourne getty.
40  */
41 #define COMPAT_43
42 #ifdef DEBUG
43 #include <stdio.h>
44 #endif
45 #include <stdlib.h>
46 #include <string.h>
47 #include <termios.h>
48 #include <unistd.h>
49 #include <sys/ioctl.h>
50 #include <sys/param.h>
51 #include <sys/time.h>
52 #include <syslog.h>
53
54 #include "gettytab.h"
55 #include "pathnames.h"
56 #include "extern.h"
57
58
59 #ifdef COMPAT_43
60 static void     compatflags __P((long));
61 #endif
62
63 /*
64  * Get a table entry.
65  */
66 void
67 gettable(name, buf)
68         const char *name;
69         char *buf;
70 {
71         register struct gettystrs *sp;
72         register struct gettynums *np;
73         register struct gettyflags *fp;
74         long n;
75         int l;
76         char *p;
77         char *msg = NULL;
78         const char *dba[2];
79
80         static int firsttime = 1;
81
82         dba[0] = _PATH_GETTYTAB;
83         dba[1] = 0;
84
85         if (firsttime) {
86                 /*
87                  * we need to strdup() anything in the strings array
88                  * initially in order to simplify things later
89                  */
90                 for (sp = gettystrs; sp->field; sp++)
91                         if (sp->value != NULL) {
92                                 /* handle these ones more carefully */
93                                 if (sp >= &gettystrs[4] && sp <= &gettystrs[6])
94                                         l = 2;
95                                 else
96                                         l = strlen(sp->value) + 1;
97                                 if ((p = malloc(l)) != NULL) {
98                                         strncpy(p, sp->value, l);
99                                         p[l-1] = '\0';
100                                 }
101                                 /*
102                                  * replace, even if NULL, else we'll
103                                  * have problems with free()ing static mem
104                                  */
105                                 sp->value = p;
106                         }
107                 firsttime = 0;
108         }
109
110         switch (cgetent(&buf, (char **)dba, (char *)name)) {
111         case 1:
112                 msg = "%s: couldn't resolve 'tc=' in gettytab '%s'";
113         case 0:
114                 break;
115         case -1:
116                 msg = "%s: unknown gettytab entry '%s'";
117                 break;
118         case -2:
119                 msg = "%s: retrieving gettytab entry '%s': %m";
120                 break;
121         case -3:
122                 msg = "%s: recursive 'tc=' reference gettytab entry '%s'";
123                 break;
124         default:
125                 msg = "%s: unexpected cgetent() error for entry '%s'";
126                 break;
127         }
128
129         if (msg != NULL) {
130                 syslog(LOG_ERR, msg, "getty", name);
131                 return;
132         }
133
134         for (sp = gettystrs; sp->field; sp++) {
135                 if ((l = cgetstr(buf, (char*)sp->field, &p)) >= 0) {
136                         if (sp->value) {
137                                 /* prefer existing value */
138                                 if (strcmp(p, sp->value) != 0)
139                                         free(sp->value);
140                                 else {
141                                         free(p);
142                                         p = sp->value;
143                                 }
144                         }
145                         sp->value = p;
146                 } else if (l == -1) {
147                         free(sp->value);
148                         sp->value = NULL;
149                 }
150         }
151
152         for (np = gettynums; np->field; np++) {
153                 if (cgetnum(buf, (char*)np->field, &n) == -1)
154                         np->set = 0;
155                 else {
156                         np->set = 1;
157                         np->value = n;
158                 }
159         }
160
161         for (fp = gettyflags; fp->field; fp++) {
162                 if (cgetcap(buf, (char *)fp->field, ':') == NULL)
163                         fp->set = 0;
164                 else {
165                         fp->set = 1;
166                         fp->value = 1 ^ fp->invrt;
167                 }
168         }
169
170 #ifdef DEBUG
171         printf("name=\"%s\", buf=\"%s\"\r\n", name, buf);
172         for (sp = gettystrs; sp->field; sp++)
173                 printf("cgetstr: %s=%s\r\n", sp->field, sp->value);
174         for (np = gettynums; np->field; np++)
175                 printf("cgetnum: %s=%d\r\n", np->field, np->value);
176         for (fp = gettyflags; fp->field; fp++)
177                 printf("cgetflags: %s='%c' set='%c'\r\n", fp->field, 
178                        fp->value + '0', fp->set + '0');
179 #endif /* DEBUG */
180 }
181
182 void
183 gendefaults()
184 {
185         register struct gettystrs *sp;
186         register struct gettynums *np;
187         register struct gettyflags *fp;
188
189         for (sp = gettystrs; sp->field; sp++)
190                 if (sp->value)
191                         sp->defalt = strdup(sp->value);
192         for (np = gettynums; np->field; np++)
193                 if (np->set)
194                         np->defalt = np->value;
195         for (fp = gettyflags; fp->field; fp++)
196                 if (fp->set)
197                         fp->defalt = fp->value;
198                 else
199                         fp->defalt = fp->invrt;
200 }
201
202 void
203 setdefaults()
204 {
205         register struct gettystrs *sp;
206         register struct gettynums *np;
207         register struct gettyflags *fp;
208
209         for (sp = gettystrs; sp->field; sp++)
210                 if (!sp->value)
211                         sp->value = !sp->defalt ? sp->defalt
212                                                 : strdup(sp->defalt);
213         for (np = gettynums; np->field; np++)
214                 if (!np->set)
215                         np->value = np->defalt;
216         for (fp = gettyflags; fp->field; fp++)
217                 if (!fp->set)
218                         fp->value = fp->defalt;
219 }
220
221 static char **
222 charnames[] = {
223         &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK,
224         &SU, &DS, &RP, &FL, &WE, &LN, 0
225 };
226
227 static char *
228 charvars[] = {
229         &tmode.c_cc[VERASE], &tmode.c_cc[VKILL], &tmode.c_cc[VINTR],
230         &tmode.c_cc[VQUIT], &tmode.c_cc[VSTART], &tmode.c_cc[VSTOP],
231         &tmode.c_cc[VEOF], &tmode.c_cc[VEOL], &tmode.c_cc[VSUSP],
232         &tmode.c_cc[VDSUSP], &tmode.c_cc[VREPRINT], &tmode.c_cc[VDISCARD],
233         &tmode.c_cc[VWERASE], &tmode.c_cc[VLNEXT], 0
234 };
235
236 void
237 setchars()
238 {
239         register int i;
240         register const char *p;
241
242         for (i = 0; charnames[i]; i++) {
243                 p = *charnames[i];
244                 if (p && *p)
245                         *charvars[i] = *p;
246                 else
247                         *charvars[i] = _POSIX_VDISABLE;
248         }
249 }
250
251 /* Macros to clear/set/test flags. */
252 #define SET(t, f)       (t) |= (f)
253 #define CLR(t, f)       (t) &= ~(f)
254 #define ISSET(t, f)     ((t) & (f))
255
256 void
257 set_flags(n)
258         int n;
259 {
260         register tcflag_t iflag, oflag, cflag, lflag;
261
262 #ifdef COMPAT_43
263         switch (n) {
264         case 0:
265                 if (F0set) {
266                         compatflags(F0);
267                         return;
268                 }
269                 break;
270         case 1:
271                 if (F1set) {
272                         compatflags(F1);
273                         return;
274                 }
275                 break;
276         default:
277                 if (F2set) {
278                         compatflags(F2);
279                         return;
280                 }
281                 break;
282         }
283 #endif
284
285         switch (n) {
286         case 0:
287                 if (C0set && I0set && L0set && O0set) {
288                         tmode.c_cflag = C0;
289                         tmode.c_iflag = I0;
290                         tmode.c_lflag = L0;
291                         tmode.c_oflag = O0;
292                         return;
293                 }
294                 break;
295         case 1:
296                 if (C1set && I1set && L1set && O1set) {
297                         tmode.c_cflag = C1;
298                         tmode.c_iflag = I1;
299                         tmode.c_lflag = L1;
300                         tmode.c_oflag = O1;
301                         return;
302                 }
303                 break;
304         default:
305                 if (C2set && I2set && L2set && O2set) {
306                         tmode.c_cflag = C2;
307                         tmode.c_iflag = I2;
308                         tmode.c_lflag = L2;
309                         tmode.c_oflag = O2;
310                         return;
311                 }
312                 break;
313         }
314
315         iflag = omode.c_iflag;
316         oflag = omode.c_oflag;
317         cflag = omode.c_cflag;
318         lflag = omode.c_lflag;
319
320         if (NP) {
321                 CLR(cflag, CSIZE|PARENB);
322                 SET(cflag, CS8);
323                 CLR(iflag, ISTRIP|INPCK|IGNPAR);
324         } else if (AP || EP || OP) {
325                 CLR(cflag, CSIZE);
326                 SET(cflag, CS7|PARENB);
327                 SET(iflag, ISTRIP);
328                 if (OP && !EP) {
329                         SET(iflag, INPCK|IGNPAR);
330                         SET(cflag, PARODD);
331                         if (AP)
332                                 CLR(iflag, INPCK);
333                 } else if (EP && !OP) {
334                         SET(iflag, INPCK|IGNPAR);
335                         CLR(cflag, PARODD);
336                         if (AP)
337                                 CLR(iflag, INPCK);
338                 } else if (AP || (EP && OP)) {
339                         CLR(iflag, INPCK|IGNPAR);
340                         CLR(cflag, PARODD);
341                 }
342         } /* else, leave as is */
343
344 #if 0
345         if (UC)
346                 f |= LCASE;
347 #endif
348
349         if (HC)
350                 SET(cflag, HUPCL);
351         else
352                 CLR(cflag, HUPCL);
353
354         if (MB)
355                 SET(cflag, MDMBUF);
356         else
357                 CLR(cflag, MDMBUF);
358
359         if (HW)
360                 SET(cflag, CRTSCTS);
361         else
362                 CLR(cflag, CRTSCTS);
363
364         if (NL) {
365                 SET(iflag, ICRNL);
366                 SET(oflag, ONLCR|OPOST);
367         } else {
368                 CLR(iflag, ICRNL);
369                 CLR(oflag, ONLCR);
370         }
371
372         if (!HT)
373                 SET(oflag, OXTABS|OPOST);
374         else
375                 CLR(oflag, OXTABS);
376
377 #ifdef XXX_DELAY
378         SET(f, delaybits());
379 #endif
380
381         if (n == 1) {           /* read mode flags */
382                 if (RW) {
383                         iflag = 0;
384                         CLR(oflag, OPOST);
385                         CLR(cflag, CSIZE|PARENB);
386                         SET(cflag, CS8);
387                         lflag = 0;
388                 } else {
389                         CLR(lflag, ICANON);
390                 }
391                 goto out;
392         }
393
394         if (n == 0)
395                 goto out;
396
397 #if 0
398         if (CB)
399                 SET(f, CRTBS);
400 #endif
401
402         if (CE)
403                 SET(lflag, ECHOE);
404         else
405                 CLR(lflag, ECHOE);
406
407         if (CK)
408                 SET(lflag, ECHOKE);
409         else
410                 CLR(lflag, ECHOKE);
411
412         if (PE)
413                 SET(lflag, ECHOPRT);
414         else
415                 CLR(lflag, ECHOPRT);
416
417         if (EC)
418                 SET(lflag, ECHO);
419         else
420                 CLR(lflag, ECHO);
421
422         if (XC)
423                 SET(lflag, ECHOCTL);
424         else
425                 CLR(lflag, ECHOCTL);
426
427         if (DX)
428                 SET(lflag, IXANY);
429         else
430                 CLR(lflag, IXANY);
431
432 out:
433         tmode.c_iflag = iflag;
434         tmode.c_oflag = oflag;
435         tmode.c_cflag = cflag;
436         tmode.c_lflag = lflag;
437 }
438
439 #ifdef COMPAT_43
440 /*
441  * Old TTY => termios, snatched from <sys/kern/tty_compat.c>
442  */
443 void
444 compatflags(flags)
445 register long flags;
446 {
447         register tcflag_t iflag, oflag, cflag, lflag;
448
449         iflag = BRKINT|ICRNL|IMAXBEL|IXON|IXANY;
450         oflag = OPOST|ONLCR|OXTABS;
451         cflag = CREAD;
452         lflag = ICANON|ISIG|IEXTEN;
453
454         if (ISSET(flags, TANDEM))
455                 SET(iflag, IXOFF);
456         else
457                 CLR(iflag, IXOFF);
458         if (ISSET(flags, ECHO))
459                 SET(lflag, ECHO);
460         else
461                 CLR(lflag, ECHO);
462         if (ISSET(flags, CRMOD)) {
463                 SET(iflag, ICRNL);
464                 SET(oflag, ONLCR);
465         } else {
466                 CLR(iflag, ICRNL);
467                 CLR(oflag, ONLCR);
468         }
469         if (ISSET(flags, XTABS))
470                 SET(oflag, OXTABS);
471         else
472                 CLR(oflag, OXTABS);
473
474
475         if (ISSET(flags, RAW)) {
476                 iflag &= IXOFF;
477                 CLR(lflag, ISIG|ICANON|IEXTEN);
478                 CLR(cflag, PARENB);
479         } else {
480                 SET(iflag, BRKINT|IXON|IMAXBEL);
481                 SET(lflag, ISIG|IEXTEN);
482                 if (ISSET(flags, CBREAK))
483                         CLR(lflag, ICANON);
484                 else
485                         SET(lflag, ICANON);
486                 switch (ISSET(flags, ANYP)) {
487                 case 0:
488                         CLR(cflag, PARENB);
489                         break;
490                 case ANYP:
491                         SET(cflag, PARENB);
492                         CLR(iflag, INPCK);
493                         break;
494                 case EVENP:
495                         SET(cflag, PARENB);
496                         SET(iflag, INPCK);
497                         CLR(cflag, PARODD);
498                         break;
499                 case ODDP:
500                         SET(cflag, PARENB);
501                         SET(iflag, INPCK);
502                         SET(cflag, PARODD);
503                         break;
504                 }
505         }
506
507         /* Nothing we can do with CRTBS. */
508         if (ISSET(flags, PRTERA))
509                 SET(lflag, ECHOPRT);
510         else
511                 CLR(lflag, ECHOPRT);
512         if (ISSET(flags, CRTERA))
513                 SET(lflag, ECHOE);
514         else
515                 CLR(lflag, ECHOE);
516         /* Nothing we can do with TILDE. */
517         if (ISSET(flags, MDMBUF))
518                 SET(cflag, MDMBUF);
519         else
520                 CLR(cflag, MDMBUF);
521         if (ISSET(flags, NOHANG))
522                 CLR(cflag, HUPCL);
523         else
524                 SET(cflag, HUPCL);
525         if (ISSET(flags, CRTKIL))
526                 SET(lflag, ECHOKE);
527         else
528                 CLR(lflag, ECHOKE);
529         if (ISSET(flags, CTLECH))
530                 SET(lflag, ECHOCTL);
531         else
532                 CLR(lflag, ECHOCTL);
533         if (!ISSET(flags, DECCTQ))
534                 SET(iflag, IXANY);
535         else
536                 CLR(iflag, IXANY);
537         CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH);
538         SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH));
539
540         if (ISSET(flags, RAW|LITOUT|PASS8)) {
541                 CLR(cflag, CSIZE);
542                 SET(cflag, CS8);
543                 if (!ISSET(flags, RAW|PASS8))
544                         SET(iflag, ISTRIP);
545                 else
546                         CLR(iflag, ISTRIP);
547                 if (!ISSET(flags, RAW|LITOUT))
548                         SET(oflag, OPOST);
549                 else
550                         CLR(oflag, OPOST);
551         } else {
552                 CLR(cflag, CSIZE);
553                 SET(cflag, CS7);
554                 SET(iflag, ISTRIP);
555                 SET(oflag, OPOST);
556         }
557
558         tmode.c_iflag = iflag;
559         tmode.c_oflag = oflag;
560         tmode.c_cflag = cflag;
561         tmode.c_lflag = lflag;
562 }
563 #endif
564
565 #ifdef XXX_DELAY
566 struct delayval {
567         unsigned        delay;          /* delay in ms */
568         int             bits;
569 };
570
571 /*
572  * below are random guesses, I can't be bothered checking
573  */
574
575 struct delayval crdelay[] = {
576         { 1,            CR1 },
577         { 2,            CR2 },
578         { 3,            CR3 },
579         { 83,           CR1 },
580         { 166,          CR2 },
581         { 0,            CR3 },
582 };
583
584 struct delayval nldelay[] = {
585         { 1,            NL1 },          /* special, calculated */
586         { 2,            NL2 },
587         { 3,            NL3 },
588         { 100,          NL2 },
589         { 0,            NL3 },
590 };
591
592 struct delayval bsdelay[] = {
593         { 1,            BS1 },
594         { 0,            0 },
595 };
596
597 struct delayval ffdelay[] = {
598         { 1,            FF1 },
599         { 1750,         FF1 },
600         { 0,            FF1 },
601 };
602
603 struct delayval tbdelay[] = {
604         { 1,            TAB1 },
605         { 2,            TAB2 },
606         { 3,            XTABS },        /* this is expand tabs */
607         { 100,          TAB1 },
608         { 0,            TAB2 },
609 };
610
611 int
612 delaybits()
613 {
614         register int f;
615
616         f  = adelay(CD, crdelay);
617         f |= adelay(ND, nldelay);
618         f |= adelay(FD, ffdelay);
619         f |= adelay(TD, tbdelay);
620         f |= adelay(BD, bsdelay);
621         return (f);
622 }
623
624 int
625 adelay(ms, dp)
626         register ms;
627         register struct delayval *dp;
628 {
629         if (ms == 0)
630                 return (0);
631         while (dp->delay && ms > dp->delay)
632                 dp++;
633         return (dp->bits);
634 }
635 #endif
636
637 char    editedhost[MAXHOSTNAMELEN];
638
639 void
640 edithost(pat)
641         register const char *pat;
642 {
643         register const char *host = HN;
644         register char *res = editedhost;
645
646         if (!pat)
647                 pat = "";
648         while (*pat) {
649                 switch (*pat) {
650
651                 case '#':
652                         if (*host)
653                                 host++;
654                         break;
655
656                 case '@':
657                         if (*host)
658                                 *res++ = *host++;
659                         break;
660
661                 default:
662                         *res++ = *pat;
663                         break;
664
665                 }
666                 if (res == &editedhost[sizeof editedhost - 1]) {
667                         *res = '\0';
668                         return;
669                 }
670                 pat++;
671         }
672         if (*host)
673                 strncpy(res, host, sizeof editedhost - (res - editedhost) - 1);
674         else
675                 *res = '\0';
676         editedhost[sizeof editedhost - 1] = '\0';
677 }
678
679 static struct speedtab {
680         int     speed;
681         int     uxname;
682 } speedtab[] = {
683         { 50,   B50 },
684         { 75,   B75 },
685         { 110,  B110 },
686         { 134,  B134 },
687         { 150,  B150 },
688         { 200,  B200 },
689         { 300,  B300 },
690         { 600,  B600 },
691         { 1200, B1200 },
692         { 1800, B1800 },
693         { 2400, B2400 },
694         { 4800, B4800 },
695         { 9600, B9600 },
696         { 19200, EXTA },
697         { 19,   EXTA },         /* for people who say 19.2K */
698         { 38400, EXTB },
699         { 38,   EXTB },
700         { 7200, EXTB },         /* alternative */
701         { 57600, B57600 },
702         { 115200, B115200 },
703         { 230400, B230400 },
704         { 0 }
705 };
706
707 int
708 speed(val)
709         int val;
710 {
711         register struct speedtab *sp;
712
713         if (val <= B230400)
714                 return (val);
715
716         for (sp = speedtab; sp->speed; sp++)
717                 if (sp->speed == val)
718                         return (sp->uxname);
719
720         return (B300);          /* default in impossible cases */
721 }
722
723 void
724 makeenv(env)
725         char *env[];
726 {
727         static char termbuf[128] = "TERM=";
728         register char *p, *q;
729         register char **ep;
730
731         ep = env;
732         if (TT && *TT) {
733                 strlcat(termbuf, TT, sizeof(termbuf));
734                 *ep++ = termbuf;
735         }
736         if ((p = EV)) {
737                 q = p;
738                 while ((q = strchr(q, ','))) {
739                         *q++ = '\0';
740                         *ep++ = p;
741                         p = q;
742                 }
743                 if (*p)
744                         *ep++ = p;
745         }
746         *ep = (char *)0;
747 }
748
749 /*
750  * This speed select mechanism is written for the Develcon DATASWITCH.
751  * The Develcon sends a string of the form "B{speed}\n" at a predefined
752  * baud rate. This string indicates the user's actual speed.
753  * The routine below returns the terminal type mapped from derived speed.
754  */
755 struct  portselect {
756         const char      *ps_baud;
757         const char      *ps_type;
758 } portspeeds[] = {
759         { "B110",       "std.110" },
760         { "B134",       "std.134" },
761         { "B150",       "std.150" },
762         { "B300",       "std.300" },
763         { "B600",       "std.600" },
764         { "B1200",      "std.1200" },
765         { "B2400",      "std.2400" },
766         { "B4800",      "std.4800" },
767         { "B9600",      "std.9600" },
768         { "B19200",     "std.19200" },
769         { 0 }
770 };
771
772 const char *
773 portselector()
774 {
775         char c, baud[20];
776         const char *type = "default";
777         register struct portselect *ps;
778         int len;
779
780         alarm(5*60);
781         for (len = 0; len < sizeof (baud) - 1; len++) {
782                 if (read(STDIN_FILENO, &c, 1) <= 0)
783                         break;
784                 c &= 0177;
785                 if (c == '\n' || c == '\r')
786                         break;
787                 if (c == 'B')
788                         len = 0;        /* in case of leading garbage */
789                 baud[len] = c;
790         }
791         baud[len] = '\0';
792         for (ps = portspeeds; ps->ps_baud; ps++)
793                 if (strcmp(ps->ps_baud, baud) == 0) {
794                         type = ps->ps_type;
795                         break;
796                 }
797         sleep(2);       /* wait for connection to complete */
798         return (type);
799 }
800
801 /*
802  * This auto-baud speed select mechanism is written for the Micom 600
803  * portselector. Selection is done by looking at how the character '\r'
804  * is garbled at the different speeds.
805  */
806 const char *
807 autobaud()
808 {
809         int rfds;
810         struct timeval timeout;
811         char c;
812         const char *type = "9600-baud";
813
814         (void)tcflush(0, TCIOFLUSH);
815         rfds = 1 << 0;
816         timeout.tv_sec = 5;
817         timeout.tv_usec = 0;
818         if (select(32, (fd_set *)&rfds, (fd_set *)NULL,
819             (fd_set *)NULL, &timeout) <= 0)
820                 return (type);
821         if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char))
822                 return (type);
823         timeout.tv_sec = 0;
824         timeout.tv_usec = 20;
825         (void) select(32, (fd_set *)NULL, (fd_set *)NULL,
826             (fd_set *)NULL, &timeout);
827         (void)tcflush(0, TCIOFLUSH);
828         switch (c & 0377) {
829
830         case 0200:              /* 300-baud */
831                 type = "300-baud";
832                 break;
833
834         case 0346:              /* 1200-baud */
835                 type = "1200-baud";
836                 break;
837
838         case  015:              /* 2400-baud */
839         case 0215:
840                 type = "2400-baud";
841                 break;
842
843         default:                /* 4800-baud */
844                 type = "4800-baud";
845                 break;
846
847         case 0377:              /* 9600-baud */
848                 type = "9600-baud";
849                 break;
850         }
851         return (type);
852 }