diff --git a/libexec/getty/chat.c b/libexec/getty/chat.c index 980a144cdb1d..0a348d6b2ebb 100644 --- a/libexec/getty/chat.c +++ b/libexec/getty/chat.c @@ -1,488 +1,488 @@ /*- * Copyright (c) 1997 * David L Nugent . * All rights reserved. * * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice immediately at the beginning of the file, without modification, * this list of conditions, and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. This work was done expressly for inclusion into FreeBSD. Other use * is permitted provided this notation is included. * 4. Absolutely no warranty of function or purpose is made by the authors. * 5. Modifications may be freely made to this file providing the above * conditions are met. * * Modem chat module - send/expect style functions for getty * For semi-intelligent modem handling. */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include "gettytab.h" #include "extern.h" #define PAUSE_CH (unsigned char)'\xff' /* pause kludge */ #define CHATDEBUG_RECEIVE 0x01 #define CHATDEBUG_SEND 0x02 #define CHATDEBUG_EXPECT 0x04 #define CHATDEBUG_MISC 0x08 #define CHATDEBUG_DEFAULT 0 #define CHAT_DEFAULT_TIMEOUT 10 static int chat_debug = CHATDEBUG_DEFAULT; static int chat_alarm = CHAT_DEFAULT_TIMEOUT; /* Default */ static volatile int alarmed = 0; static void chat_alrm(int); static int chat_unalarm(void); static int getdigit(char **, int, int); static char **read_chat(char **); static char *cleanchr(char **, unsigned char); static const char *cleanstr(const char *, int); static const char *result(int); static int chat_expect(const char *); static int chat_send(char const *); /* * alarm signal handler * handle timeouts in read/write * change stdin to non-blocking mode to prevent * possible hang in read(). */ static void chat_alrm(int signo __unused) { int on = 1; alarm(1); alarmed = 1; signal(SIGALRM, chat_alrm); ioctl(STDIN_FILENO, FIONBIO, &on); } /* * Turn back on blocking mode reset by chat_alrm() */ static int chat_unalarm(void) { int off = 0; return ioctl(STDIN_FILENO, FIONBIO, &off); } /* * convert a string of a given base (octal/hex) to binary */ static int getdigit(char **ptr, int base, int max) { int i, val = 0; char * q; static const char xdigits[] = "0123456789abcdef"; for (i = 0, q = *ptr; i++ < max; ++q) { int sval; const char * s = strchr(xdigits, tolower(*q)); if (s == NULL || (sval = s - xdigits) >= base) break; val = (val * base) + sval; } *ptr = q; return val; } /* * read_chat() * Convert a whitespace delimtied string into an array * of strings, being expect/send pairs */ static char ** read_chat(char **chatstr) { char *str = *chatstr; char **res = NULL; if (str != NULL) { char *tmp = NULL; int l; if ((l=strlen(str)) > 0 && (tmp=malloc(l + 1)) != NULL && (res=malloc(((l + 1) / 2 + 1) * sizeof(char *))) != NULL) { static char ws[] = " \t"; char * p; for (l = 0, p = strtok(strcpy(tmp, str), ws); p != NULL; p = strtok(NULL, ws)) { char *q, *r; /* Read escapes */ for (q = r = p; *r; ++q) { if (*q == '\\') { /* handle special escapes */ switch (*++q) { case 'a': /* bell */ *r++ = '\a'; break; case 'r': /* cr */ *r++ = '\r'; break; case 'n': /* nl */ *r++ = '\n'; break; case 'f': /* ff */ *r++ = '\f'; break; case 'b': /* bs */ *r++ = '\b'; break; case 'e': /* esc */ *r++ = 27; break; case 't': /* tab */ *r++ = '\t'; break; case 'p': /* pause */ *r++ = PAUSE_CH; break; case 's': case 'S': /* space */ *r++ = ' '; break; case 'x': /* hexdigit */ ++q; *r++ = getdigit(&q, 16, 2); --q; break; case '0': /* octal */ ++q; *r++ = getdigit(&q, 8, 3); --q; break; default: /* literal */ *r++ = *q; break; case 0: /* not past eos */ --q; break; } } else { /* copy standard character */ *r++ = *q; } } /* Remove surrounding quotes, if any */ if (*p == '"' || *p == '\'') { q = strrchr(p+1, *p); if (q != NULL && *q == *p && q[1] == '\0') { *q = '\0'; p++; } } res[l++] = p; } res[l] = NULL; *chatstr = tmp; return res; } free(tmp); } return res; } /* * clean a character for display (ctrl/meta character) */ static char * cleanchr(char **buf, unsigned char ch) { int l; static char tmpbuf[5]; char * tmp = buf ? *buf : tmpbuf; if (ch & 0x80) { strcpy(tmp, "M-"); l = 2; ch &= 0x7f; } else - l = 0; + l = 0; if (ch < 32) { tmp[l++] = '^'; tmp[l++] = ch + '@'; } else if (ch == 127) { tmp[l++] = '^'; tmp[l++] = '?'; } else tmp[l++] = ch; tmp[l] = '\0'; if (buf) *buf = tmp + l; return tmp; } /* * clean a string for display (ctrl/meta characters) */ static const char * cleanstr(const char *s, int l) { static char * tmp = NULL; static int tmplen = 0; if (tmplen < l * 4 + 1) tmp = realloc(tmp, tmplen = l * 4 + 1); if (tmp == NULL) { tmplen = 0; return "(mem alloc error)"; } else { int i = 0; char * p = tmp; while (i < l) cleanchr(&p, s[i++]); *p = '\0'; } return tmp; } /* * return result as a pseudo-english word */ static const char * result(int r) { static const char * results[] = { "OK", "MEMERROR", "IOERROR", "TIMEOUT" }; return results[r & 3]; } /* * chat_expect() * scan input for an expected string */ static int chat_expect(const char *str) { int len, r = 0; if (chat_debug & CHATDEBUG_EXPECT) syslog(LOG_DEBUG, "chat_expect '%s'", cleanstr(str, strlen(str))); if ((len = strlen(str)) > 0) { int i = 0; char * got; if ((got = malloc(len + 1)) == NULL) r = 1; else { memset(got, 0, len+1); alarm(chat_alarm); alarmed = 0; while (r == 0 && i < len) { if (alarmed) r = 3; else { unsigned char ch; if (read(STDIN_FILENO, &ch, 1) == 1) { if (chat_debug & CHATDEBUG_RECEIVE) syslog(LOG_DEBUG, "chat_recv '%s' m=%d", - cleanchr(NULL, ch), i); + cleanchr(NULL, ch), i); if (ch == str[i]) got[i++] = ch; else if (i > 0) { int j = 1; /* See if we can resync on a * partial match in our buffer */ while (j < i && memcmp(got + j, str, i - j) != 0) j++; if (j < i) memcpy(got, got + j, i - j); i -= j; } } else r = alarmed ? 3 : 2; } } alarm(0); - chat_unalarm(); - alarmed = 0; - free(got); + chat_unalarm(); + alarmed = 0; + free(got); } } if (chat_debug & CHATDEBUG_EXPECT) syslog(LOG_DEBUG, "chat_expect %s", result(r)); return r; } /* * chat_send() * send a chat string */ static int chat_send(char const *str) { int r = 0; if (chat_debug & CHATDEBUG_SEND) syslog(LOG_DEBUG, "chat_send '%s'", cleanstr(str, strlen(str))); if (*str) { alarm(chat_alarm); alarmed = 0; while (r == 0 && *str) { unsigned char ch = (unsigned char)*str++; if (alarmed) - r = 3; + r = 3; else if (ch == PAUSE_CH) usleep(500000); /* 1/2 second */ else { usleep(10000); /* be kind to modem */ if (write(STDOUT_FILENO, &ch, 1) != 1) - r = alarmed ? 3 : 2; + r = alarmed ? 3 : 2; } } alarm(0); chat_unalarm(); alarmed = 0; } if (chat_debug & CHATDEBUG_SEND) - syslog(LOG_DEBUG, "chat_send %s", result(r)); + syslog(LOG_DEBUG, "chat_send %s", result(r)); return r; } /* * getty_chat() * * Termination codes: * -1 - no script supplied * 0 - script terminated correctly * 1 - invalid argument, expect string too large, etc. * 2 - error on an I/O operation or fatal error condition * 3 - timeout waiting for a simple string * * Parameters: * char *scrstr - unparsed chat script * timeout - seconds timeout * debug - debug value (bitmask) */ int getty_chat(char *scrstr, int timeout, int debug) { int r = -1; chat_alarm = timeout ? timeout : CHAT_DEFAULT_TIMEOUT; chat_debug = debug; if (scrstr != NULL) { char **script; if (chat_debug & CHATDEBUG_MISC) syslog(LOG_DEBUG, "getty_chat script='%s'", scrstr); if ((script = read_chat(&scrstr)) != NULL) { int i = r = 0; int off = 0; sig_t old_alarm; /* * We need to be in raw mode for all this * Rely on caller... */ old_alarm = signal(SIGALRM, chat_alrm); chat_unalarm(); /* Force blocking mode at start */ /* * This is the send/expect loop */ while (r == 0 && script[i] != NULL) if ((r = chat_expect(script[i++])) == 0 && script[i] != NULL) r = chat_send(script[i++]); signal(SIGALRM, old_alarm); free(script); free(scrstr); /* * Ensure stdin is in blocking mode */ ioctl(STDIN_FILENO, FIONBIO, &off); } if (chat_debug & CHATDEBUG_MISC) - syslog(LOG_DEBUG, "getty_chat %s", result(r)); + syslog(LOG_DEBUG, "getty_chat %s", result(r)); } return r; } diff --git a/libexec/getty/init.c b/libexec/getty/init.c index 4ff0291c6f46..79b9601a2be1 100644 --- a/libexec/getty/init.c +++ b/libexec/getty/init.c @@ -1,156 +1,156 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)from: init.c 8.1 (Berkeley) 6/4/93"; #endif static const char rcsid[] = - "$FreeBSD$"; + "$FreeBSD$"; #endif /* not lint */ /* * Getty table initializations. * * Melbourne getty. */ #include #include #include "gettytab.h" #include "extern.h" #include "pathnames.h" static char loginmsg[] = "login: "; static char nullstr[] = ""; static char loginprg[] = _PATH_LOGIN; static char datefmt[] = "%+"; #define M(a) (char *)(&omode.c_cc[a]) struct gettystrs gettystrs[] = { { "nx", NULL, NULL }, /* next table */ { "cl", NULL, NULL }, /* screen clear characters */ { "im", NULL, NULL }, /* initial message */ { "lm", loginmsg, NULL }, /* login message */ { "er", M(VERASE), NULL }, /* erase character */ { "kl", M(VKILL), NULL }, /* kill character */ { "et", M(VEOF), NULL }, /* eof chatacter (eot) */ { "pc", nullstr, NULL }, /* pad character */ { "tt", NULL, NULL }, /* terminal type */ { "ev", NULL, NULL }, /* environment */ { "lo", loginprg, NULL }, /* login program */ { "hn", hostname, NULL }, /* host name */ { "he", NULL, NULL }, /* host name edit */ { "in", M(VINTR), NULL }, /* interrupt char */ { "qu", M(VQUIT), NULL }, /* quit char */ { "xn", M(VSTART), NULL }, /* XON (start) char */ { "xf", M(VSTOP), NULL }, /* XOFF (stop) char */ { "bk", M(VEOL), NULL }, /* brk char (alt \n) */ { "su", M(VSUSP), NULL }, /* suspend char */ { "ds", M(VDSUSP), NULL }, /* delayed suspend */ { "rp", M(VREPRINT), NULL }, /* reprint char */ { "fl", M(VDISCARD), NULL }, /* flush output */ { "we", M(VWERASE), NULL }, /* word erase */ { "ln", M(VLNEXT), NULL }, /* literal next */ { "Lo", NULL, NULL }, /* locale for strftime() */ { "pp", NULL, NULL }, /* ppp login program */ { "if", NULL, NULL }, /* sysv-like 'issue' filename */ { "ic", NULL, NULL }, /* modem init-chat */ { "ac", NULL, NULL }, /* modem answer-chat */ { "al", NULL, NULL }, /* user to auto-login */ { "df", datefmt, NULL }, /* format for strftime() */ { "iM" , NULL, NULL }, /* initial message program */ { NULL, NULL, NULL } }; struct gettynums gettynums[] = { { "is", 0, 0, 0 }, /* input speed */ { "os", 0, 0, 0 }, /* output speed */ { "sp", 0, 0, 0 }, /* both speeds */ { "nd", 0, 0, 0 }, /* newline delay */ { "cd", 0, 0, 0 }, /* carriage-return delay */ { "td", 0, 0, 0 }, /* tab delay */ { "fd", 0, 0, 0 }, /* form-feed delay */ { "bd", 0, 0, 0 }, /* backspace delay */ { "to", 0, 0, 0 }, /* timeout */ { "f0", 0, 0, 0 }, /* output flags */ { "f1", 0, 0, 0 }, /* input flags */ { "f2", 0, 0, 0 }, /* user mode flags */ { "pf", 0, 0, 0 }, /* delay before flush at 1st prompt */ { "c0", 0, 0, 0 }, /* output c_flags */ { "c1", 0, 0, 0 }, /* input c_flags */ { "c2", 0, 0, 0 }, /* user mode c_flags */ { "i0", 0, 0, 0 }, /* output i_flags */ { "i1", 0, 0, 0 }, /* input i_flags */ { "i2", 0, 0, 0 }, /* user mode i_flags */ { "l0", 0, 0, 0 }, /* output l_flags */ { "l1", 0, 0, 0 }, /* input l_flags */ { "l2", 0, 0, 0 }, /* user mode l_flags */ { "o0", 0, 0, 0 }, /* output o_flags */ { "o1", 0, 0, 0 }, /* input o_flags */ { "o2", 0, 0, 0 }, /* user mode o_flags */ { "de", 0, 0, 0 }, /* delay before sending 1st prompt */ { "rt", 0, 0, 0 }, /* reset timeout */ { "ct", 0, 0, 0 }, /* chat script timeout */ { "dc", 0, 0, 0 }, /* debug chat script value */ { NULL, 0, 0, 0 } }; - + struct gettyflags gettyflags[] = { { "ht", 0, 0, 0, 0 }, /* has tabs */ { "nl", 1, 0, 0, 0 }, /* has newline char */ { "ep", 0, 0, 0, 0 }, /* even parity */ { "op", 0, 0, 0, 0 }, /* odd parity */ { "ap", 0, 0, 0, 0 }, /* any parity */ { "ec", 1, 0, 0, 0 }, /* no echo */ { "co", 0, 0, 0, 0 }, /* console special */ { "cb", 0, 0, 0, 0 }, /* crt backspace */ { "ck", 0, 0, 0, 0 }, /* crt kill */ { "ce", 0, 0, 0, 0 }, /* crt erase */ { "pe", 0, 0, 0, 0 }, /* printer erase */ { "rw", 1, 0, 0, 0 }, /* don't use raw */ { "xc", 1, 0, 0, 0 }, /* don't ^X ctl chars */ { "lc", 0, 0, 0, 0 }, /* terminal las lower case */ { "uc", 0, 0, 0, 0 }, /* terminal has no lower case */ { "ig", 0, 0, 0, 0 }, /* ignore garbage */ { "ps", 0, 0, 0, 0 }, /* do port selector speed select */ { "hc", 1, 0, 0, 0 }, /* don't set hangup on close */ { "ub", 0, 0, 0, 0 }, /* unbuffered output */ { "ab", 0, 0, 0, 0 }, /* auto-baud detect with '\r' */ { "dx", 0, 0, 0, 0 }, /* set decctlq */ { "np", 0, 0, 0, 0 }, /* no parity at all (8bit chars) */ { "mb", 0, 0, 0, 0 }, /* do MDMBUF flow control */ { "hw", 0, 0, 0, 0 }, /* do CTSRTS flow control */ { "nc", 0, 0, 0, 0 }, /* set clocal (no carrier) */ { "pl", 0, 0, 0, 0 }, /* use PPP instead of login(1) */ { NULL, 0, 0, 0, 0 } }; diff --git a/libexec/getty/main.c b/libexec/getty/main.c index 605be6c9bd56..bc01ab83b8b2 100644 --- a/libexec/getty/main.c +++ b/libexec/getty/main.c @@ -1,815 +1,815 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1980, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1980, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)from: main.c 8.1 (Berkeley) 6/20/93"; #endif #endif /* not lint */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gettytab.h" #include "extern.h" #include "pathnames.h" /* * Set the amount of running time that getty should accumulate * before deciding that something is wrong and exit. */ #define GETTY_TIMEOUT 60 /* seconds */ #undef CTRL #define CTRL(x) (x&037) /* defines for auto detection of incoming PPP calls (->PAP/CHAP) */ #define PPP_FRAME 0x7e /* PPP Framing character */ #define PPP_STATION 0xff /* "All Station" character */ #define PPP_ESCAPE 0x7d /* Escape Character */ #define PPP_CONTROL 0x03 /* PPP Control Field */ #define PPP_CONTROL_ESCAPED 0x23 /* PPP Control Field, escaped */ #define PPP_LCP_HI 0xc0 /* LCP protocol - high byte */ #define PPP_LCP_LOW 0x21 /* LCP protocol - low byte */ /* original mode; flags've been reset using values from */ struct termios omode; /* current mode */ struct termios tmode; static int crmod, digit, lower, upper; char hostname[MAXHOSTNAMELEN]; static char name[MAXLOGNAME*3]; static char ttyn[32]; #define OBUFSIZ 128 static const char *tname; static char *env[128]; static char partab[] = { 0001,0201,0201,0001,0201,0001,0001,0201, 0202,0004,0003,0205,0005,0206,0201,0001, 0201,0001,0001,0201,0001,0201,0201,0001, 0001,0201,0201,0001,0201,0001,0001,0201, 0200,0000,0000,0200,0000,0200,0200,0000, 0000,0200,0200,0000,0200,0000,0000,0200, 0000,0200,0200,0000,0200,0000,0000,0200, 0200,0000,0000,0200,0000,0200,0200,0000, 0200,0000,0000,0200,0000,0200,0200,0000, 0000,0200,0200,0000,0200,0000,0000,0200, 0000,0200,0200,0000,0200,0000,0000,0200, 0200,0000,0000,0200,0000,0200,0200,0000, 0000,0200,0200,0000,0200,0000,0000,0200, 0200,0000,0000,0200,0000,0200,0200,0000, 0200,0000,0000,0200,0000,0200,0200,0000, 0000,0200,0200,0000,0200,0000,0000,0201 }; #define ERASE tmode.c_cc[VERASE] #define KILL tmode.c_cc[VKILL] #define EOT tmode.c_cc[VEOF] #define puts Gputs static void defttymode(void); static void dingdong(int); static void dogettytab(void); static int getname(void); static void interrupt(int); static void oflush(void); static void prompt(void); static void putchr(int); static void putf(const char *); static void putpad(const char *); static void puts(const char *); static void timeoverrun(int); static char *get_line(int); static void setttymode(int); static int opentty(const char *, int); static jmp_buf timeout; static void dingdong(int signo __unused) { alarm(0); longjmp(timeout, 1); } static jmp_buf intrupt; static void interrupt(int signo __unused) { longjmp(intrupt, 1); } /* * Action to take when getty is running too long. */ static void timeoverrun(int signo __unused) { syslog(LOG_ERR, "getty exiting due to excessive running time"); exit(1); } int main(int argc, char *argv[]) { int first_sleep = 1, first_time = 1; struct rlimit limit; int rval; signal(SIGINT, SIG_IGN); signal(SIGQUIT, SIG_IGN); openlog("getty", LOG_CONS|LOG_PID, LOG_AUTH); gethostname(hostname, sizeof(hostname) - 1); hostname[sizeof(hostname) - 1] = '\0'; if (hostname[0] == '\0') snprintf(hostname, sizeof(hostname), "Amnesiac"); /* * Limit running time to deal with broken or dead lines. */ (void)signal(SIGXCPU, timeoverrun); limit.rlim_max = RLIM_INFINITY; limit.rlim_cur = GETTY_TIMEOUT; (void)setrlimit(RLIMIT_CPU, &limit); gettable("default"); gendefaults(); tname = "default"; if (argc > 1) tname = argv[1]; /* * The following is a work around for vhangup interactions * which cause great problems getting window systems started. * If the tty line is "-", we do the old style getty presuming * that the file descriptors are already set up for us. * J. Gettys - MIT Project Athena. */ if (argc <= 2 || strcmp(argv[2], "-") == 0) - snprintf(ttyn, sizeof(ttyn), "%s", ttyname(STDIN_FILENO)); + snprintf(ttyn, sizeof(ttyn), "%s", ttyname(STDIN_FILENO)); else { - snprintf(ttyn, sizeof(ttyn), "%s%s", _PATH_DEV, argv[2]); - if (strcmp(argv[0], "+") != 0) { - chown(ttyn, 0, 0); - chmod(ttyn, 0600); - revoke(ttyn); - - /* - * Do the first scan through gettytab. - * Terminal mode parameters will be wrong until - * defttymode() called, but they're irrelevant for - * the initial setup of the terminal device. - */ - dogettytab(); - - /* - * Init or answer modem sequence has been specified. - */ - if (IC || AC) { - if (!opentty(ttyn, O_RDWR|O_NONBLOCK)) - exit(1); - defttymode(); - setttymode(1); - } + snprintf(ttyn, sizeof(ttyn), "%s%s", _PATH_DEV, argv[2]); + if (strcmp(argv[0], "+") != 0) { + chown(ttyn, 0, 0); + chmod(ttyn, 0600); + revoke(ttyn); + + /* + * Do the first scan through gettytab. + * Terminal mode parameters will be wrong until + * defttymode() called, but they're irrelevant for + * the initial setup of the terminal device. + */ + dogettytab(); - if (IC) { - if (getty_chat(IC, CT, DC) > 0) { - syslog(LOG_ERR, "modem init problem on %s", ttyn); - (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); - exit(1); + /* + * Init or answer modem sequence has been specified. + */ + if (IC || AC) { + if (!opentty(ttyn, O_RDWR|O_NONBLOCK)) + exit(1); + defttymode(); + setttymode(1); } - } - if (AC) { - fd_set rfds; - struct timeval to; - int i; - - FD_ZERO(&rfds); - FD_SET(0, &rfds); - to.tv_sec = RT; - to.tv_usec = 0; - i = select(32, &rfds, NULL, NULL, RT ? &to : NULL); - if (i < 0) { - syslog(LOG_ERR, "select %s: %m", ttyn); - } else if (i == 0) { - syslog(LOG_NOTICE, "recycle tty %s", ttyn); - (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); - exit(0); /* recycle for init */ + if (IC) { + if (getty_chat(IC, CT, DC) > 0) { + syslog(LOG_ERR, "modem init problem on %s", ttyn); + (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); + exit(1); + } } - i = getty_chat(AC, CT, DC); - if (i > 0) { - syslog(LOG_ERR, "modem answer problem on %s", ttyn); - (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); - exit(1); + + if (AC) { + fd_set rfds; + struct timeval to; + int i; + + FD_ZERO(&rfds); + FD_SET(0, &rfds); + to.tv_sec = RT; + to.tv_usec = 0; + i = select(32, &rfds, NULL, NULL, RT ? &to : NULL); + if (i < 0) { + syslog(LOG_ERR, "select %s: %m", ttyn); + } else if (i == 0) { + syslog(LOG_NOTICE, "recycle tty %s", ttyn); + (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); + exit(0); /* recycle for init */ + } + i = getty_chat(AC, CT, DC); + if (i > 0) { + syslog(LOG_ERR, "modem answer problem on %s", ttyn); + (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); + exit(1); + } + } else { /* maybe blocking open */ + if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 ))) + exit(1); } - } else { /* maybe blocking open */ - if (!opentty(ttyn, O_RDWR | (NC ? O_NONBLOCK : 0 ))) - exit(1); } - } } defttymode(); for (;;) { /* - * if a delay was specified then sleep for that + * if a delay was specified then sleep for that * number of seconds before writing the initial prompt */ if (first_sleep && DE) { - sleep(DE); - /* remove any noise */ - (void)tcflush(STDIN_FILENO, TCIOFLUSH); + sleep(DE); + /* remove any noise */ + (void)tcflush(STDIN_FILENO, TCIOFLUSH); } first_sleep = 0; setttymode(0); if (AB) { tname = autobaud(); dogettytab(); continue; } if (PS) { tname = portselector(); dogettytab(); continue; } if (CL && *CL) putpad(CL); edithost(HE); /* if this is the first time through this, and an issue file has been given, then send it */ if (first_time && IF) { int fd; if ((fd = open(IF, O_RDONLY)) != -1) { char * cp; while ((cp = get_line(fd)) != NULL) { - putf(cp); + putf(cp); } close(fd); } } first_time = 0; if (IMP && *IMP && !(PL && PP)) system(IMP); if (IM && *IM && !(PL && PP)) putf(IM); if (setjmp(timeout)) { cfsetispeed(&tmode, B0); cfsetospeed(&tmode, B0); (void)tcsetattr(STDIN_FILENO, TCSANOW, &tmode); exit(1); } if (TO) { signal(SIGALRM, dingdong); alarm(TO); } rval = 0; if (AL) { const char *p = AL; char *q = name; while (*p && q < &name[sizeof name - 1]) { if (isupper(*p)) upper = 1; else if (islower(*p)) lower = 1; else if (isdigit(*p)) digit = 1; *q++ = *p++; } } else if (!(PL && PP)) rval = getname(); if (rval == 2 || (PL && PP)) { oflush(); alarm(0); limit.rlim_max = RLIM_INFINITY; limit.rlim_cur = RLIM_INFINITY; (void)setrlimit(RLIMIT_CPU, &limit); execle(PP, "ppplogin", ttyn, (char *) 0, env); syslog(LOG_ERR, "%s: %m", PP); exit(1); } else if (rval || AL) { int i; oflush(); alarm(0); signal(SIGALRM, SIG_DFL); if (name[0] == '\0') continue; if (name[0] == '-') { puts("user names may not start with '-'."); continue; } if (!(upper || lower || digit)) { if (AL) { syslog(LOG_ERR, "invalid auto-login name: %s", AL); exit(1); } else continue; } set_flags(2); if (crmod) { tmode.c_iflag |= ICRNL; tmode.c_oflag |= ONLCR; } #if REALLY_OLD_TTYS if (upper || UC) tmode.sg_flags |= LCASE; if (lower || LC) tmode.sg_flags &= ~LCASE; #endif if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { syslog(LOG_ERR, "tcsetattr %s: %m", ttyn); exit(1); } signal(SIGINT, SIG_DFL); for (i = 0; environ[i] != (char *)0; i++) env[i] = environ[i]; makeenv(&env[i]); limit.rlim_max = RLIM_INFINITY; limit.rlim_cur = RLIM_INFINITY; (void)setrlimit(RLIMIT_CPU, &limit); execle(LO, "login", AL ? "-fp" : "-p", name, (char *) 0, env); syslog(LOG_ERR, "%s: %m", LO); exit(1); } alarm(0); signal(SIGALRM, SIG_DFL); signal(SIGINT, SIG_IGN); if (NX && *NX) { tname = NX; dogettytab(); } } } static int opentty(const char *tty, int flags) { int failopenlogged = 0, i, saved_errno; while ((i = open(tty, flags)) == -1) { saved_errno = errno; if (!failopenlogged) { syslog(LOG_ERR, "open %s: %m", tty); failopenlogged = 1; } if (saved_errno == ENOENT) return 0; sleep(60); } - if (login_tty(i) < 0) { + if (login_tty(i) < 0) { if (daemon(0,0) < 0) { syslog(LOG_ERR,"daemon: %m"); close(i); return 0; } if (login_tty(i) < 0) { syslog(LOG_ERR, "login_tty %s: %m", tty); close(i); return 0; } } return 1; } static void defttymode(void) { struct termios def; /* Start with default tty settings. */ if (tcgetattr(STDIN_FILENO, &tmode) < 0) { syslog(LOG_ERR, "tcgetattr %s: %m", ttyn); exit(1); } omode = tmode; /* fill c_cc for dogettytab() */ dogettytab(); /* * Don't rely on the driver too much, and initialize crucial * things according to . Avoid clobbering * the c_cc[] settings however, the console drivers might wish * to leave their idea of the preferred VERASE key value * there. */ cfmakesane(&def); tmode.c_iflag = def.c_iflag; tmode.c_oflag = def.c_oflag; tmode.c_lflag = def.c_lflag; tmode.c_cflag = def.c_cflag; if (NC) tmode.c_cflag |= CLOCAL; omode = tmode; } static void setttymode(int raw) { int off = 0; (void)tcflush(STDIN_FILENO, TCIOFLUSH); /* clear out the crap */ ioctl(STDIN_FILENO, FIONBIO, &off); /* turn off non-blocking mode */ ioctl(STDIN_FILENO, FIOASYNC, &off); /* ditto for async mode */ if (IS) cfsetispeed(&tmode, speed(IS)); else if (SP) cfsetispeed(&tmode, speed(SP)); if (OS) cfsetospeed(&tmode, speed(OS)); else if (SP) cfsetospeed(&tmode, speed(SP)); set_flags(0); setchars(); if (raw) cfmakeraw(&tmode); if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { syslog(LOG_ERR, "tcsetattr %s: %m", ttyn); exit(1); } } static int getname(void) { int c; char *np; unsigned char cs; int ppp_state = 0; int ppp_connection = 0; /* * Interrupt may happen if we use CBREAK mode */ if (setjmp(intrupt)) { signal(SIGINT, SIG_IGN); return (0); } signal(SIGINT, interrupt); set_flags(1); prompt(); oflush(); if (PF > 0) { sleep(PF); PF = 0; } if (tcsetattr(STDIN_FILENO, TCSANOW, &tmode) < 0) { syslog(LOG_ERR, "%s: %m", ttyn); exit(1); } crmod = digit = lower = upper = 0; np = name; for (;;) { oflush(); if (read(STDIN_FILENO, &cs, 1) <= 0) exit(0); if ((c = cs&0177) == 0) return (0); /* PPP detection state machine.. Look for sequences: PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED or PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC) See RFC1662. Derived from code from Michael Hancock, and Erik 'PPP' Olson, - */ + */ if (PP && (cs == PPP_FRAME)) { ppp_state = 1; } else if (ppp_state == 1 && cs == PPP_STATION) { ppp_state = 2; } else if (ppp_state == 2 && cs == PPP_ESCAPE) { ppp_state = 3; } else if ((ppp_state == 2 && cs == PPP_CONTROL) - || (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) { + || (ppp_state == 3 && cs == PPP_CONTROL_ESCAPED)) { ppp_state = 4; } else if (ppp_state == 4 && cs == PPP_LCP_HI) { ppp_state = 5; } else if (ppp_state == 5 && cs == PPP_LCP_LOW) { ppp_connection = 1; break; } else { ppp_state = 0; } if (c == EOT || c == CTRL('d')) exit(0); if (c == '\r' || c == '\n' || np >= &name[sizeof name-1]) { putf("\r\n"); break; } if (islower(c)) lower = 1; else if (isupper(c)) upper = 1; else if (c == ERASE || c == '\b' || c == 0177) { if (np > name) { np--; if (cfgetospeed(&tmode) >= 1200) puts("\b \b"); else putchr(cs); } continue; } else if (c == KILL || c == CTRL('u')) { putchr('\r'); if (cfgetospeed(&tmode) < 1200) putchr('\n'); /* this is the way they do it down under ... */ else if (np > name) puts(" \r"); prompt(); digit = lower = upper = 0; np = name; continue; } else if (isdigit(c)) digit = 1; if (IG && (c <= ' ' || c > 0176)) continue; *np++ = c; putchr(cs); } signal(SIGINT, SIG_IGN); *np = 0; if (c == '\r') crmod = 1; if ((upper && !lower && !LC) || UC) for (np = name; *np; np++) if (isupper(*np)) *np = tolower(*np); return (1 + ppp_connection); } static void putpad(const char *s) { int pad = 0; speed_t ospeed = cfgetospeed(&tmode); if (isdigit(*s)) { while (isdigit(*s)) { pad *= 10; pad += *s++ - '0'; } pad *= 10; if (*s == '.' && isdigit(s[1])) { pad += s[1] - '0'; s += 2; } } puts(s); /* * If no delay needed, or output speed is * not comprehensible, then don't try to delay. */ if (pad == 0 || ospeed <= 0) return; /* * Round up by a half a character frame, and then do the delay. * Too bad there are no user program accessible programmed delays. * Transmitting pad characters slows many terminals down and also * loads the system. */ pad = (pad * ospeed + 50000) / 100000; while (pad--) putchr(*PC); } static void puts(const char *s) { while (*s) putchr(*s++); } static char outbuf[OBUFSIZ]; static int obufcnt = 0; static void putchr(int cc) { char c; c = cc; if (!NP) { c |= partab[c&0177] & 0200; if (OP) c ^= 0200; } if (!UB) { outbuf[obufcnt++] = c; if (obufcnt >= OBUFSIZ) oflush(); } else write(STDOUT_FILENO, &c, 1); } static void oflush(void) { if (obufcnt) write(STDOUT_FILENO, outbuf, obufcnt); obufcnt = 0; } static void prompt(void) { putf(LM); if (CO) putchr('\n'); } static char * get_line(int fd) { size_t i = 0; static char linebuf[512]; /* * This is certainly slow, but it avoids having to include * stdio.h unnecessarily. Issue files should be small anyway. */ while (i < (sizeof linebuf - 3) && read(fd, linebuf+i, 1)==1) { if (linebuf[i] == '\n') { /* Don't rely on newline mode, assume raw */ linebuf[i++] = '\r'; linebuf[i++] = '\n'; linebuf[i] = '\0'; return linebuf; } ++i; } linebuf[i] = '\0'; return i ? linebuf : 0; } static void putf(const char *cp) { time_t t; char db[100]; const char *slash; static struct utsname kerninfo; if (!*kerninfo.sysname) uname(&kerninfo); while (*cp) { if (*cp != '%') { putchr(*cp++); continue; } switch (*++cp) { case 't': slash = strrchr(ttyn, '/'); if (slash == (char *) 0) puts(ttyn); else puts(&slash[1]); break; case 'h': puts(editedhost); break; case 'd': t = (time_t)0; (void)time(&t); if (Lo) (void)setlocale(LC_TIME, Lo); (void)strftime(db, sizeof(db), DF, localtime(&t)); puts(db); break; case 's': puts(kerninfo.sysname); break; case 'm': puts(kerninfo.machine); break; case 'r': puts(kerninfo.release); break; case 'v': puts(kerninfo.version); break; case '%': putchr('%'); break; } cp++; } } /* * Read a gettytab database entry and perform necessary quirks. */ static void dogettytab(void) { - + /* Read the database entry. */ gettable(tname); /* * Avoid inheriting the parity values from the default entry * if any of them is set in the current entry. * Mixing different parity settings is unreasonable. */ if (OPset || EPset || APset || NPset) OPset = EPset = APset = NPset = 1; /* Fill in default values for unset capabilities. */ setdefaults(); } diff --git a/libexec/getty/subr.c b/libexec/getty/subr.c index f8637211d424..68682df6d5bd 100644 --- a/libexec/getty/subr.c +++ b/libexec/getty/subr.c @@ -1,684 +1,684 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1983, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)from: subr.c 8.1 (Berkeley) 6/4/93"; #endif static const char rcsid[] = - "$FreeBSD$"; + "$FreeBSD$"; #endif /* not lint */ /* * Melbourne getty. */ #include #include #include #include #include #include #include #include #include #include #include "gettytab.h" #include "pathnames.h" #include "extern.h" /* * Get a table entry. */ void gettable(const char *name) { char *buf = NULL; struct gettystrs *sp; struct gettynums *np; struct gettyflags *fp; long n; int l; char *p; static char path_gettytab[PATH_MAX]; char *dba[2]; static int firsttime = 1; strlcpy(path_gettytab, _PATH_GETTYTAB, sizeof(path_gettytab)); dba[0] = path_gettytab; dba[1] = NULL; if (firsttime) { /* * we need to strdup() anything in the strings array * initially in order to simplify things later */ for (sp = gettystrs; sp->field; sp++) if (sp->value != NULL) { /* handle these ones more carefully */ if (sp >= &gettystrs[4] && sp <= &gettystrs[6]) l = 2; else l = strlen(sp->value) + 1; if ((p = malloc(l)) != NULL) strlcpy(p, sp->value, l); /* * replace, even if NULL, else we'll * have problems with free()ing static mem */ sp->value = p; } firsttime = 0; } switch (cgetent(&buf, dba, name)) { case 1: syslog(LOG_ERR, "getty: couldn't resolve 'tc=' in gettytab '%s'", name); return; case 0: break; case -1: syslog(LOG_ERR, "getty: unknown gettytab entry '%s'", name); return; case -2: syslog(LOG_ERR, "getty: retrieving gettytab entry '%s': %m", name); return; case -3: syslog(LOG_ERR, "getty: recursive 'tc=' reference gettytab entry '%s'", name); return; default: syslog(LOG_ERR, "getty: unexpected cgetent() error for entry '%s'", name); return; } for (sp = gettystrs; sp->field; sp++) { if ((l = cgetstr(buf, sp->field, &p)) >= 0) { if (sp->value) { /* prefer existing value */ if (strcmp(p, sp->value) != 0) free(sp->value); else { free(p); p = sp->value; } } sp->value = p; } else if (l == -1) { free(sp->value); sp->value = NULL; } } for (np = gettynums; np->field; np++) { if (cgetnum(buf, np->field, &n) == -1) np->set = 0; else { np->set = 1; np->value = n; } } for (fp = gettyflags; fp->field; fp++) { if (cgetcap(buf, fp->field, ':') == NULL) fp->set = 0; else { fp->set = 1; fp->value = 1 ^ fp->invrt; } } free(buf); } void gendefaults(void) { struct gettystrs *sp; struct gettynums *np; struct gettyflags *fp; for (sp = gettystrs; sp->field; sp++) if (sp->value) sp->defalt = strdup(sp->value); for (np = gettynums; np->field; np++) if (np->set) np->defalt = np->value; for (fp = gettyflags; fp->field; fp++) if (fp->set) fp->defalt = fp->value; else fp->defalt = fp->invrt; } void setdefaults(void) { struct gettystrs *sp; struct gettynums *np; struct gettyflags *fp; for (sp = gettystrs; sp->field; sp++) if (!sp->value) - sp->value = !sp->defalt ? sp->defalt - : strdup(sp->defalt); + sp->value = !sp->defalt ? + sp->defalt : strdup(sp->defalt); for (np = gettynums; np->field; np++) if (!np->set) np->value = np->defalt; for (fp = gettyflags; fp->field; fp++) if (!fp->set) fp->value = fp->defalt; } static char ** charnames[] = { &ER, &KL, &IN, &QU, &XN, &XF, &ET, &BK, &SU, &DS, &RP, &FL, &WE, &LN, 0 }; #define CV(a) (char *)(&tmode.c_cc[a]) static char * charvars[] = { CV(VERASE), CV(VKILL), CV(VINTR), CV(VQUIT), CV(VSTART), CV(VSTOP), CV(VEOF), CV(VEOL), CV(VSUSP), CV(VDSUSP), CV(VREPRINT), CV(VDISCARD), CV(VWERASE), CV(VLNEXT), 0 }; void setchars(void) { int i; const char *p; for (i = 0; charnames[i]; i++) { p = *charnames[i]; if (p && *p) *charvars[i] = *p; else *charvars[i] = _POSIX_VDISABLE; } } /* Macros to clear/set/test flags. */ #define SET(t, f) (t) |= (f) #define CLR(t, f) (t) &= ~(f) #define ISSET(t, f) ((t) & (f)) void set_flags(int n) { tcflag_t iflag, oflag, cflag, lflag; switch (n) { case 0: if (C0set && I0set && L0set && O0set) { tmode.c_cflag = C0; tmode.c_iflag = I0; tmode.c_lflag = L0; tmode.c_oflag = O0; return; } break; case 1: if (C1set && I1set && L1set && O1set) { tmode.c_cflag = C1; tmode.c_iflag = I1; tmode.c_lflag = L1; tmode.c_oflag = O1; return; } break; default: if (C2set && I2set && L2set && O2set) { tmode.c_cflag = C2; tmode.c_iflag = I2; tmode.c_lflag = L2; tmode.c_oflag = O2; return; } break; } iflag = omode.c_iflag; oflag = omode.c_oflag; cflag = omode.c_cflag; lflag = omode.c_lflag; if (NP) { CLR(cflag, CSIZE|PARENB); SET(cflag, CS8); CLR(iflag, ISTRIP|INPCK|IGNPAR); } else if (AP || EP || OP) { CLR(cflag, CSIZE); SET(cflag, CS7|PARENB); SET(iflag, ISTRIP); if (OP && !EP) { SET(iflag, INPCK|IGNPAR); SET(cflag, PARODD); if (AP) CLR(iflag, INPCK); } else if (EP && !OP) { SET(iflag, INPCK|IGNPAR); CLR(cflag, PARODD); if (AP) CLR(iflag, INPCK); } else if (AP || (EP && OP)) { CLR(iflag, INPCK|IGNPAR); CLR(cflag, PARODD); } } /* else, leave as is */ #if 0 if (UC) f |= LCASE; #endif if (HC) SET(cflag, HUPCL); else CLR(cflag, HUPCL); if (MB) SET(cflag, MDMBUF); else CLR(cflag, MDMBUF); if (HW) SET(cflag, CRTSCTS); else CLR(cflag, CRTSCTS); if (NL) { SET(iflag, ICRNL); SET(oflag, ONLCR|OPOST); } else { CLR(iflag, ICRNL); CLR(oflag, ONLCR); } if (!HT) SET(oflag, OXTABS|OPOST); else CLR(oflag, OXTABS); #ifdef XXX_DELAY SET(f, delaybits()); #endif if (n == 1) { /* read mode flags */ if (RW) { iflag = 0; CLR(oflag, OPOST); CLR(cflag, CSIZE|PARENB); SET(cflag, CS8); lflag = 0; } else { CLR(lflag, ICANON); } goto out; } if (n == 0) goto out; #if 0 if (CB) SET(f, CRTBS); #endif if (CE) SET(lflag, ECHOE); else CLR(lflag, ECHOE); if (CK) SET(lflag, ECHOKE); else CLR(lflag, ECHOKE); if (PE) SET(lflag, ECHOPRT); else CLR(lflag, ECHOPRT); if (EC) SET(lflag, ECHO); else CLR(lflag, ECHO); if (XC) SET(lflag, ECHOCTL); else CLR(lflag, ECHOCTL); if (DX) SET(lflag, IXANY); else CLR(lflag, IXANY); out: tmode.c_iflag = iflag; tmode.c_oflag = oflag; tmode.c_cflag = cflag; tmode.c_lflag = lflag; } #ifdef XXX_DELAY struct delayval { unsigned delay; /* delay in ms */ int bits; }; /* * below are random guesses, I can't be bothered checking */ struct delayval crdelay[] = { { 1, CR1 }, { 2, CR2 }, { 3, CR3 }, { 83, CR1 }, { 166, CR2 }, { 0, CR3 }, }; struct delayval nldelay[] = { { 1, NL1 }, /* special, calculated */ { 2, NL2 }, { 3, NL3 }, { 100, NL2 }, { 0, NL3 }, }; struct delayval bsdelay[] = { { 1, BS1 }, { 0, 0 }, }; struct delayval ffdelay[] = { { 1, FF1 }, { 1750, FF1 }, { 0, FF1 }, }; struct delayval tbdelay[] = { { 1, TAB1 }, { 2, TAB2 }, { 3, XTABS }, /* this is expand tabs */ { 100, TAB1 }, { 0, TAB2 }, }; int delaybits(void) { int f; f = adelay(CD, crdelay); f |= adelay(ND, nldelay); f |= adelay(FD, ffdelay); f |= adelay(TD, tbdelay); f |= adelay(BD, bsdelay); return (f); } int adelay(int ms, struct delayval *dp) { if (ms == 0) return (0); while (dp->delay && ms > dp->delay) dp++; return (dp->bits); } #endif char editedhost[MAXHOSTNAMELEN]; void edithost(const char *pattern) { regex_t regex; regmatch_t *match; int found; if (pattern == NULL || *pattern == '\0') goto copyasis; if (regcomp(®ex, pattern, REG_EXTENDED) != 0) goto copyasis; match = calloc(regex.re_nsub + 1, sizeof(*match)); if (match == NULL) { regfree(®ex); goto copyasis; } found = !regexec(®ex, HN, regex.re_nsub + 1, match, 0); if (found) { size_t subex, totalsize; /* * We found a match. If there were no parenthesized * subexpressions in the pattern, use entire matched * string as ``editedhost''; otherwise use the first * matched subexpression. */ subex = !!regex.re_nsub; totalsize = match[subex].rm_eo - match[subex].rm_so + 1; strlcpy(editedhost, HN + match[subex].rm_so, totalsize > sizeof(editedhost) ? sizeof(editedhost) : totalsize); } free(match); regfree(®ex); if (found) return; /* * In case of any errors, or if the pattern did not match, pass * the original hostname as is. */ - copyasis: +copyasis: strlcpy(editedhost, HN, sizeof(editedhost)); } static struct speedtab { int speed; int uxname; } speedtab[] = { { 50, B50 }, { 75, B75 }, { 110, B110 }, { 134, B134 }, { 150, B150 }, { 200, B200 }, { 300, B300 }, { 600, B600 }, { 1200, B1200 }, { 1800, B1800 }, { 2400, B2400 }, { 4800, B4800 }, { 9600, B9600 }, { 19200, EXTA }, { 19, EXTA }, /* for people who say 19.2K */ { 38400, EXTB }, { 38, EXTB }, { 7200, EXTB }, /* alternative */ { 57600, B57600 }, { 115200, B115200 }, { 230400, B230400 }, { 0, 0 } }; int speed(int val) { struct speedtab *sp; if (val <= B230400) return (val); for (sp = speedtab; sp->speed; sp++) if (sp->speed == val) return (sp->uxname); return (B300); /* default in impossible cases */ } void makeenv(char *env[]) { static char termbuf[128] = "TERM="; char *p, *q; char **ep; ep = env; if (TT && *TT) { strlcat(termbuf, TT, sizeof(termbuf)); *ep++ = termbuf; } if ((p = EV)) { q = p; while ((q = strchr(q, ','))) { *q++ = '\0'; *ep++ = p; p = q; } if (*p) *ep++ = p; } *ep = (char *)0; } /* * This speed select mechanism is written for the Develcon DATASWITCH. * The Develcon sends a string of the form "B{speed}\n" at a predefined * baud rate. This string indicates the user's actual speed. * The routine below returns the terminal type mapped from derived speed. */ static struct portselect { const char *ps_baud; const char *ps_type; } portspeeds[] = { { "B110", "std.110" }, { "B134", "std.134" }, { "B150", "std.150" }, { "B300", "std.300" }, { "B600", "std.600" }, { "B1200", "std.1200" }, { "B2400", "std.2400" }, { "B4800", "std.4800" }, { "B9600", "std.9600" }, { "B19200", "std.19200" }, { NULL, NULL } }; const char * portselector(void) { char c, baud[20]; const char *type = "default"; struct portselect *ps; size_t len; alarm(5*60); for (len = 0; len < sizeof (baud) - 1; len++) { if (read(STDIN_FILENO, &c, 1) <= 0) break; c &= 0177; if (c == '\n' || c == '\r') break; if (c == 'B') len = 0; /* in case of leading garbage */ baud[len] = c; } baud[len] = '\0'; for (ps = portspeeds; ps->ps_baud; ps++) if (strcmp(ps->ps_baud, baud) == 0) { type = ps->ps_type; break; } sleep(2); /* wait for connection to complete */ return (type); } /* * This auto-baud speed select mechanism is written for the Micom 600 * portselector. Selection is done by looking at how the character '\r' * is garbled at the different speeds. */ const char * autobaud(void) { struct pollfd set[1]; struct timespec timeout; char c; const char *type = "9600-baud"; (void)tcflush(0, TCIOFLUSH); set[0].fd = STDIN_FILENO; set[0].events = POLLIN; if (poll(set, 1, 5000) <= 0) return (type); if (read(STDIN_FILENO, &c, sizeof(char)) != sizeof(char)) return (type); timeout.tv_sec = 0; timeout.tv_nsec = 20000; (void)nanosleep(&timeout, NULL); (void)tcflush(0, TCIOFLUSH); switch (c & 0377) { case 0200: /* 300-baud */ type = "300-baud"; break; case 0346: /* 1200-baud */ type = "1200-baud"; break; case 015: /* 2400-baud */ case 0215: type = "2400-baud"; break; default: /* 4800-baud */ type = "4800-baud"; break; case 0377: /* 9600-baud */ type = "9600-baud"; break; } return (type); }