/* * Copyright 1994-2002 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * usr/src/cmd/cmd-inet/usr.bin/telnet/utilities.c */ /* * Copyright (c) 1988, 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. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. 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 char sccsid[] = "@(#)utilities.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #define TELOPTS #ifdef lint static char *telcmds[] = {0}; static char *slc_names[] = {0}; static char *encrypt_names[] = {0}; static char *enctype_names[] = {0}; #else /* lint */ #define TELCMDS #define SLC_NAMES #endif /* lint */ #include <arpa/telnet.h> #include <sys/types.h> #include <sys/time.h> #include <sys/param.h> #include <sys/socket.h> #include <errno.h> #include <ctype.h> #include "general.h" #include "ring.h" #include "defines.h" #include "externs.h" FILE *NetTrace = 0; /* Not in bss, since needs to stay */ int prettydump; /* * upcase() * * Upcase (in place) the argument. */ void upcase(argument) register char *argument; { register int c; while ((c = *argument) != 0) { if (islower(c)) { *argument = toupper(c); } argument++; } } /* * SetSockOpt() * * Compensate for differences in 4.2 and 4.3 systems. */ int SetSockOpt(fd, level, option, yesno) int fd, level, option, yesno; { return (setsockopt(fd, level, option, &yesno, sizeof (yesno))); } /* * The following are routines used to print out debugging information. */ unsigned char NetTraceFile[MAXPATHLEN] = "(standard output)"; void SetNetTrace(file) register char *file; { if (NetTrace && NetTrace != stdout) (void) fclose(NetTrace); if (file && (strcmp(file, "-") != 0)) { NetTrace = fopen(file, "w"); if (NetTrace) { (void) strcpy((char *)NetTraceFile, file); return; } (void) fprintf(stderr, "Cannot open %s.\n", file); } NetTrace = stdout; (void) strcpy((char *)NetTraceFile, "(standard output)"); } void Dump(direction, buffer, length) char direction; unsigned char *buffer; int length; { #define BYTES_PER_LINE 32 #define min(x, y) ((x < y) ? x:y) unsigned char *pThis; int offset; offset = 0; while (length) { /* print one line */ (void) fprintf(NetTrace, "%c 0x%x\t", direction, offset); pThis = buffer; if (prettydump) { buffer = buffer + min(length, BYTES_PER_LINE/2); while (pThis < buffer) { (void) fprintf(NetTrace, "%c%.2x", (((*pThis)&0xff) == 0xff) ? '*' : ' ', (*pThis)&0xff); pThis++; } length -= BYTES_PER_LINE/2; offset += BYTES_PER_LINE/2; } else { buffer = buffer + min(length, BYTES_PER_LINE); while (pThis < buffer) { (void) fprintf(NetTrace, "%.2x", (*pThis)&0xff); pThis++; } length -= BYTES_PER_LINE; offset += BYTES_PER_LINE; } if (NetTrace == stdout) { (void) fprintf(NetTrace, "\r\n"); } else { (void) fprintf(NetTrace, "\n"); } if (length < 0) { (void) fflush(NetTrace); return; } /* find next unique line */ } (void) fflush(NetTrace); } void printoption(direction, cmd, option) char *direction; int cmd, option; { if (!showoptions) return; if (cmd == IAC) { if (TELCMD_OK(option)) (void) fprintf(NetTrace, "%s IAC %s", direction, TELCMD(option)); else (void) fprintf(NetTrace, "%s IAC %d", direction, option); } else { register char *fmt; fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" : (cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0; if (fmt) { (void) fprintf(NetTrace, "%s %s ", direction, fmt); if (TELOPT_OK(option)) (void) fprintf(NetTrace, "%s", TELOPT(option)); else if (option == TELOPT_EXOPL) (void) fprintf(NetTrace, "EXOPL"); else (void) fprintf(NetTrace, "%d", option); } else (void) fprintf(NetTrace, "%s %d %d", direction, cmd, option); } if (NetTrace == stdout) { (void) fprintf(NetTrace, "\r\n"); (void) fflush(NetTrace); } else { (void) fprintf(NetTrace, "\n"); } } void optionstatus() { register int i; extern char will_wont_resp[], do_dont_resp[]; for (i = 0; i < SUBBUFSIZE; i++) { if (do_dont_resp[i]) { if (TELOPT_OK(i)) (void) printf("resp DO_DONT %s: %d\n", TELOPT(i), do_dont_resp[i]); else if (TELCMD_OK(i)) (void) printf("resp DO_DONT %s: %d\n", TELCMD(i), do_dont_resp[i]); else (void) printf("resp DO_DONT %d: %d\n", i, do_dont_resp[i]); if (my_want_state_is_do(i)) { if (TELOPT_OK(i)) (void) printf("want DO %s\n", TELOPT(i)); else if (TELCMD_OK(i)) (void) printf("want DO %s\n", TELCMD(i)); else (void) printf("want DO %d\n", i); } else { if (TELOPT_OK(i)) (void) printf("want DONT %s\n", TELOPT(i)); else if (TELCMD_OK(i)) (void) printf("want DONT %s\n", TELCMD(i)); else (void) printf("want DONT %d\n", i); } } else { if (my_state_is_do(i)) { if (TELOPT_OK(i)) (void) printf(" DO %s\n", TELOPT(i)); else if (TELCMD_OK(i)) (void) printf(" DO %s\n", TELCMD(i)); else (void) printf(" DO %d\n", i); } } if (will_wont_resp[i]) { if (TELOPT_OK(i)) (void) printf("resp WILL_WONT %s: %d\n", TELOPT(i), will_wont_resp[i]); else if (TELCMD_OK(i)) (void) printf("resp WILL_WONT %s: %d\n", TELCMD(i), will_wont_resp[i]); else (void) printf("resp WILL_WONT %d: %d\n", i, will_wont_resp[i]); if (my_want_state_is_will(i)) { if (TELOPT_OK(i)) (void) printf("want WILL %s\n", TELOPT(i)); else if (TELCMD_OK(i)) (void) printf("want WILL %s\n", TELCMD(i)); else (void) printf("want WILL %d\n", i); } else { if (TELOPT_OK(i)) (void) printf("want WONT %s\n", TELOPT(i)); else if (TELCMD_OK(i)) (void) printf("want WONT %s\n", TELCMD(i)); else (void) printf("want WONT %d\n", i); } } else { if (my_state_is_will(i)) { if (TELOPT_OK(i)) (void) printf(" WILL %s\n", TELOPT(i)); else if (TELCMD_OK(i)) (void) printf(" WILL %s\n", TELCMD(i)); else (void) printf(" WILL %d\n", i); } } } } void printsub(direction, pointer, length) char direction; /* '<' or '>' */ unsigned char *pointer; /* where suboption data sits */ int length; /* length of suboption data */ { register int i; char buf[512]; extern int want_status_response; if (showoptions || direction == 0 || (want_status_response && (pointer[0] == TELOPT_STATUS))) { if (direction) { (void) fprintf(NetTrace, "%s IAC SB ", (direction == '<')? "RCVD":"SENT"); if (length >= 3) { register int j; i = pointer[length-2]; j = pointer[length-1]; if (i != IAC || j != SE) { (void) fprintf(NetTrace, "(terminated by "); if (TELOPT_OK(i)) (void) fprintf(NetTrace, "%s ", TELOPT(i)); else if (TELCMD_OK(i)) (void) fprintf(NetTrace, "%s ", TELCMD(i)); else (void) fprintf(NetTrace, "%d ", i); if (TELOPT_OK(j)) (void) fprintf(NetTrace, "%s", TELOPT(j)); else if (TELCMD_OK(j)) (void) fprintf(NetTrace, "%s", TELCMD(j)); else (void) fprintf(NetTrace, "%d", j); (void) fprintf(NetTrace, ", not IAC SE!) "); } } length -= 2; } if (length < 1) { (void) fprintf(NetTrace, "(Empty suboption??\?)"); if (NetTrace == stdout) (void) fflush(NetTrace); return; } switch (pointer[0]) { case TELOPT_TTYPE: (void) fprintf(NetTrace, "TERMINAL-TYPE "); switch (pointer[1]) { case TELQUAL_IS: (void) fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); break; case TELQUAL_SEND: (void) fprintf(NetTrace, "SEND"); break; default: (void) fprintf(NetTrace, "- unknown qualifier %d (0x%x).", pointer[1], pointer[1]); } break; case TELOPT_TSPEED: (void) fprintf(NetTrace, "TERMINAL-SPEED"); if (length < 2) { (void) fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case TELQUAL_IS: (void) fprintf(NetTrace, " IS "); (void) fprintf(NetTrace, "%.*s", length-2, (char *)pointer+2); break; default: if (pointer[1] == 1) (void) fprintf(NetTrace, " SEND"); else (void) fprintf(NetTrace, " %d (unknown)", pointer[1]); for (i = 2; i < length; i++) (void) fprintf(NetTrace, " ?%d?", pointer[i]); break; } break; case TELOPT_LFLOW: (void) fprintf(NetTrace, "TOGGLE-FLOW-CONTROL"); if (length < 2) { (void) fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case LFLOW_OFF: (void) fprintf(NetTrace, " OFF"); break; case LFLOW_ON: (void) fprintf(NetTrace, " ON"); break; case LFLOW_RESTART_ANY: (void) fprintf(NetTrace, " RESTART-ANY"); break; case LFLOW_RESTART_XON: (void) fprintf(NetTrace, " RESTART-XON"); break; default: (void) fprintf(NetTrace, " %d (unknown)", pointer[1]); } for (i = 2; i < length; i++) (void) fprintf(NetTrace, " ?%d?", pointer[i]); break; case TELOPT_NAWS: (void) fprintf(NetTrace, "NAWS"); if (length < 2) { (void) fprintf(NetTrace, " (empty suboption??\?)"); break; } if (length == 2) { (void) fprintf(NetTrace, " ?%d?", pointer[1]); break; } (void) fprintf(NetTrace, " %d %d (%d)", pointer[1], pointer[2], (int)((((unsigned int)pointer[1])<<8)| ((unsigned int)pointer[2]))); if (length == 4) { (void) fprintf(NetTrace, " ?%d?", pointer[3]); break; } (void) fprintf(NetTrace, " %d %d (%d)", pointer[3], pointer[4], (int)((((unsigned int)pointer[3])<<8)| ((unsigned int)pointer[4]))); for (i = 5; i < length; i++) (void) fprintf(NetTrace, " ?%d?", pointer[i]); break; case TELOPT_AUTHENTICATION: (void) fprintf(NetTrace, "AUTHENTICATION"); if (length < 2) { (void) fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case TELQUAL_REPLY: case TELQUAL_IS: (void) fprintf(NetTrace, " %s ", (pointer[1] == TELQUAL_IS) ? "IS" : "REPLY"); if (AUTHTYPE_NAME_OK(pointer[2])) (void) fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[2])); else (void) fprintf(NetTrace, "%d ", pointer[2]); if (length < 3) { (void) fprintf(NetTrace, "(partial suboption??\?)"); break; } (void) fprintf(NetTrace, "%s|%s", ((pointer[3] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER", ((pointer[3] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY"); auth_printsub(&pointer[1], length - 1, (uchar_t *)buf, sizeof (buf)); (void) fprintf(NetTrace, "%s", buf); break; case TELQUAL_SEND: i = 2; (void) fprintf(NetTrace, " SEND "); while (i < length) { if (AUTHTYPE_NAME_OK(pointer[i])) (void) fprintf(NetTrace, "%s ", AUTHTYPE_NAME(pointer[i])); else (void) fprintf(NetTrace, "%d ", pointer[i]); if (++i >= length) { (void) fprintf(NetTrace, "(partial " "suboption??\?)"); break; } (void) fprintf(NetTrace, "%s|%s ", ((pointer[i] & AUTH_WHO_MASK) == AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER", ((pointer[i] & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY"); ++i; } break; case TELQUAL_NAME: i = 2; (void) fprintf(NetTrace, " NAME \""); while (i < length) (void) putc(pointer[i++], NetTrace); (void) putc('"', NetTrace); break; default: for (i = 2; i < length; i++) (void) fprintf(NetTrace, " ?%d?", pointer[i]); break; } break; case TELOPT_ENCRYPT: (void) fprintf(NetTrace, "ENCRYPT"); if (length < 2) { (void) fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case ENCRYPT_START: (void) fprintf(NetTrace, " START"); break; case ENCRYPT_END: (void) fprintf(NetTrace, " END"); break; case ENCRYPT_REQSTART: (void) fprintf(NetTrace, " REQUEST-START"); break; case ENCRYPT_REQEND: (void) fprintf(NetTrace, " REQUEST-END"); break; case ENCRYPT_IS: case ENCRYPT_REPLY: (void) fprintf(NetTrace, " %s ", (pointer[1] == ENCRYPT_IS) ? "IS" : "REPLY"); if (length < 3) { (void) fprintf(NetTrace, " (partial " "suboption??\?)"); break; } if (ENCTYPE_NAME_OK(pointer[2])) (void) fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[2])); else (void) fprintf(NetTrace, " %d (unknown)", pointer[2]); encrypt_printsub(&pointer[1], length - 1, (uchar_t *)buf, sizeof (buf)); (void) fprintf(NetTrace, "%s", buf); break; case ENCRYPT_SUPPORT: i = 2; (void) fprintf(NetTrace, " SUPPORT "); while (i < length) { if (ENCTYPE_NAME_OK(pointer[i])) (void) fprintf(NetTrace, "%s ", ENCTYPE_NAME(pointer[i])); else (void) fprintf(NetTrace, "%d ", pointer[i]); i++; } break; case ENCRYPT_ENC_KEYID: (void) fprintf(NetTrace, " ENC_KEYID "); goto encommon; case ENCRYPT_DEC_KEYID: (void) fprintf(NetTrace, " DEC_KEYID "); goto encommon; default: (void) fprintf(NetTrace, " %d (unknown)", pointer[1]); encommon: for (i = 2; i < length; i++) (void) fprintf(NetTrace, " %d", pointer[i]); break; } break; case TELOPT_LINEMODE: (void) fprintf(NetTrace, "LINEMODE "); if (length < 2) { (void) fprintf(NetTrace, " (empty suboption??\?)"); break; } switch (pointer[1]) { case WILL: (void) fprintf(NetTrace, "WILL "); goto common; case WONT: (void) fprintf(NetTrace, "WONT "); goto common; case DO: (void) fprintf(NetTrace, "DO "); goto common; case DONT: (void) fprintf(NetTrace, "DONT "); common: if (length < 3) { (void) fprintf(NetTrace, "(no option??\?)"); break; } switch (pointer[2]) { case LM_FORWARDMASK: (void) fprintf(NetTrace, "Forward Mask"); for (i = 3; i < length; i++) (void) fprintf(NetTrace, " %x", pointer[i]); break; default: (void) fprintf(NetTrace, "%d (unknown)", pointer[2]); for (i = 3; i < length; i++) (void) fprintf(NetTrace, " %d", pointer[i]); break; } break; case LM_SLC: (void) fprintf(NetTrace, "SLC"); for (i = 2; i < length - 2; i += 3) { if (SLC_NAME_OK(pointer[i+SLC_FUNC])) (void) fprintf(NetTrace, " %s", SLC_NAME(pointer[ i+SLC_FUNC])); else (void) fprintf(NetTrace, " %d", pointer[i+SLC_FUNC]); switch (pointer[i+SLC_FLAGS] & SLC_LEVELBITS) { case SLC_NOSUPPORT: (void) fprintf(NetTrace, " NOSUPPORT"); break; case SLC_CANTCHANGE: (void) fprintf(NetTrace, " CANTCHANGE"); break; case SLC_VARIABLE: (void) fprintf(NetTrace, " VARIABLE"); break; case SLC_DEFAULT: (void) fprintf(NetTrace, " DEFAULT"); break; } (void) fprintf(NetTrace, "%s%s%s", pointer[i+SLC_FLAGS]&SLC_ACK ? "|ACK" : "", pointer[i+SLC_FLAGS]&SLC_FLUSHIN ? "|FLUSHIN" : "", pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ? "|FLUSHOUT" : ""); if (pointer[i+SLC_FLAGS] & ~(SLC_ACK|SLC_FLUSHIN| SLC_FLUSHOUT| SLC_LEVELBITS)) (void) fprintf(NetTrace, "(0x%x)", pointer[i+SLC_FLAGS]); (void) fprintf(NetTrace, " %d;", pointer[i+SLC_VALUE]); if ((pointer[i+SLC_VALUE] == IAC) && (pointer[i+SLC_VALUE+1] == IAC)) i++; } for (; i < length; i++) (void) fprintf(NetTrace, " ?%d?", pointer[i]); break; case LM_MODE: (void) fprintf(NetTrace, "MODE "); if (length < 3) { (void) fprintf(NetTrace, "(no mode??\?)"); break; } { char tbuf[64]; (void) sprintf(tbuf, "%s%s%s%s%s", pointer[2]&MODE_EDIT ? "|EDIT" : "", pointer[2]&MODE_TRAPSIG ? "|TRAPSIG" : "", pointer[2]&MODE_SOFT_TAB ? "|SOFT_TAB" : "", pointer[2]&MODE_LIT_ECHO ? "|LIT_ECHO" : "", pointer[2]&MODE_ACK ? "|ACK" : ""); (void) fprintf(NetTrace, "%s", tbuf[1] ? &tbuf[1] : "0"); } if (pointer[2]&~(MODE_MASK)) (void) fprintf(NetTrace, " (0x%x)", pointer[2]); for (i = 3; i < length; i++) (void) fprintf(NetTrace, " ?0x%x?", pointer[i]); break; default: (void) fprintf(NetTrace, "%d (unknown)", pointer[1]); for (i = 2; i < length; i++) (void) fprintf(NetTrace, " %d", pointer[i]); } break; case TELOPT_STATUS: { register char *cp; register int j, k; (void) fprintf(NetTrace, "STATUS"); switch (pointer[1]) { default: if (pointer[1] == TELQUAL_SEND) (void) fprintf(NetTrace, " SEND"); else (void) fprintf(NetTrace, " %d (unknown)", pointer[1]); for (i = 2; i < length; i++) (void) fprintf(NetTrace, " ?%d?", pointer[i]); break; case TELQUAL_IS: if (--want_status_response < 0) want_status_response = 0; if (NetTrace == stdout) (void) fprintf(NetTrace, " IS\r\n"); else (void) fprintf(NetTrace, " IS\n"); for (i = 2; i < length; i++) { switch (pointer[i]) { case DO: cp = "DO"; goto common2; case DONT: cp = "DONT"; goto common2; case WILL: cp = "WILL"; goto common2; case WONT: cp = "WONT"; goto common2; common2: i++; if (TELOPT_OK( (int)pointer[i])) (void) fprintf( NetTrace, " %s %s", cp, TELOPT( pointer[ i])); else (void) fprintf( NetTrace, " %s %d", cp, pointer[i]); if (NetTrace == stdout) (void) fprintf( NetTrace, "\r\n"); else (void) fprintf( NetTrace, "\n"); break; case SB: (void) fprintf(NetTrace, " SB "); i++; j = k = i; while (j < length) { if (pointer[j] == SE) { if (j+1 == length) break; if (pointer[j+1] == SE) j++; else break; } pointer[k++] = pointer[j++]; } printsub(0, &pointer[i], k - i); if (i < length) { (void) fprintf(NetTrace, " SE"); i = j; } else i = j - 1; if (NetTrace == stdout) (void) fprintf(NetTrace, "\r\n"); else (void) fprintf(NetTrace, "\n"); break; default: (void) fprintf(NetTrace, " %d", pointer[i]); break; } } break; } break; } case TELOPT_XDISPLOC: (void) fprintf(NetTrace, "X-DISPLAY-LOCATION "); switch (pointer[1]) { case TELQUAL_IS: (void) fprintf(NetTrace, "IS \"%.*s\"", length-2, (char *)pointer+2); break; case TELQUAL_SEND: (void) fprintf(NetTrace, "SEND"); break; default: (void) fprintf(NetTrace, "- unknown qualifier %d (0x%x).", pointer[1], pointer[1]); } break; case TELOPT_NEW_ENVIRON: (void) fprintf(NetTrace, "NEW-ENVIRON "); #ifdef OLD_ENVIRON goto env_common1; case TELOPT_OLD_ENVIRON: (void) fprintf(NetTrace, "OLD-ENVIRON "); env_common1: #endif switch (pointer[1]) { case TELQUAL_IS: (void) fprintf(NetTrace, "IS "); goto env_common; case TELQUAL_SEND: (void) fprintf(NetTrace, "SEND "); goto env_common; case TELQUAL_INFO: (void) fprintf(NetTrace, "INFO "); env_common: { register int noquote = 2; #if defined(ENV_HACK) && defined(OLD_ENVIRON) extern int old_env_var, old_env_value; #endif for (i = 2; i < length; i++) { switch (pointer[i]) { case NEW_ENV_VALUE: #ifdef OLD_ENVIRON /* case NEW_ENV_OVAR: */ if (pointer[0] == TELOPT_OLD_ENVIRON) { #ifdef ENV_HACK if (old_env_var == OLD_ENV_VALUE) (void) fprintf(NetTrace, "\" (VALUE) " + noquote); else #endif (void) fprintf(NetTrace, "\" VAR " + noquote); } else #endif /* OLD_ENVIRON */ (void) fprintf(NetTrace, "\" VALUE " + noquote); noquote = 2; break; case NEW_ENV_VAR: #ifdef OLD_ENVIRON /* case OLD_ENV_VALUE: */ if (pointer[0] == TELOPT_OLD_ENVIRON) { #ifdef ENV_HACK if (old_env_value == OLD_ENV_VAR) (void) fprintf(NetTrace, "\" (VAR) " + noquote); else #endif (void) fprintf(NetTrace, "\" VALUE " + noquote); } else #endif /* OLD_ENVIRON */ (void) fprintf(NetTrace, "\" VAR " + noquote); noquote = 2; break; case ENV_ESC: (void) fprintf(NetTrace, "\" ESC " + noquote); noquote = 2; break; case ENV_USERVAR: (void) fprintf(NetTrace, "\" USERVAR " + noquote); noquote = 2; break; default: def_case: if (isprint(pointer[i]) && pointer[i] != '"') { if (noquote) { (void) putc('"', NetTrace); noquote = 0; } (void) putc(pointer[i], NetTrace); } else { (void) fprintf(NetTrace, "\" %03o " + noquote, pointer[i]); noquote = 2; } break; } } if (!noquote) (void) putc('"', NetTrace); break; } } break; default: if (TELOPT_OK(pointer[0])) (void) fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0])); else (void) fprintf(NetTrace, "%d (unknown)", pointer[0]); for (i = 1; i < length; i++) (void) fprintf(NetTrace, " %d", pointer[i]); break; } if (direction) { if (NetTrace == stdout) (void) fprintf(NetTrace, "\r\n"); else (void) fprintf(NetTrace, "\n"); } if (NetTrace == stdout) (void) fflush(NetTrace); } } /* * EmptyTerminal - called to make sure that the terminal buffer is empty. * Note that we consider the buffer to run all the * way to the kernel (thus the select). */ static void EmptyTerminal() { fd_set o; FD_ZERO(&o); if (TTYBYTES() == 0) { FD_SET(tout, &o); /* wait for TTLOWAT */ (void) select(tout+1, NULL, &o, NULL, NULL); } else { while (TTYBYTES()) { if (ttyflush(0) == -2) { /* This will not return. */ fatal_tty_error("write"); } FD_SET(tout, &o); /* wait for TTLOWAT */ (void) select(tout+1, NULL, &o, NULL, NULL); } } } static void SetForExit() { setconnmode(0); do { (void) telrcv(); /* Process any incoming data */ EmptyTerminal(); } while (ring_full_count(&netiring)); /* While there is any */ setcommandmode(); (void) fflush(stdout); (void) fflush(stderr); setconnmode(0); EmptyTerminal(); /* Flush the path to the tty */ setcommandmode(); } void Exit(returnCode) int returnCode; { SetForExit(); exit(returnCode); } void ExitString(string, returnCode) char *string; int returnCode; { SetForExit(); (void) fwrite(string, 1, strlen(string), stderr); exit(returnCode); } #define BUFFER_CHUNK_SIZE 64 /* Round up to a multiple of BUFFER_CHUNK_SIZE */ #define ROUND_CHUNK_SIZE(s) ((((s) + BUFFER_CHUNK_SIZE - 1) / \ BUFFER_CHUNK_SIZE) * BUFFER_CHUNK_SIZE) /* * Optionally allocate a buffer, and optionally read a string from a stream * into the buffer, starting at the given offset. If the buffer isn't * large enough for the given offset, or if buffer space is exhausted * when reading the string, the size of the buffer is increased. * * A buffer can be supplied when the function is called, passing the * buffer address via the first argument. The buffer size can be * passed as well, in the second argument. If the second argument is * NULL, the function makes no assumptions about the buffer size. * The address of the buffer is returned via the first argument, and the * buffer size via the second argument if this is not NULL. * These returned values may differ from the supplied values if the buffer * was reallocated. * * If no buffer is to be supplied, specify a buffer address of NULL, via * the first argument. * * If the pointer to the buffer address is NULL, the function just returns * NULL, and performs no other processing. * * If a NULL stream is passed, the function will just make sure the * supplied buffer is large enough to hold the supplied offset, * reallocating it if is too small or too large. * * The returned buffer will be a multiple of BUFFER_CHUNK_SIZE in size. * * The function stops reading from the stream when a newline is read, * end of file is reached, or an error occurs. The newline is not * returned in the buffer. The returned string will be NULL terminated. * * The function returns the address of the buffer if any characters * are read and no error occurred, otherwise it returns NULL. * * If the function returns NULL, a buffer may have been allocated. The * buffer address will be returned via the first argument, together with * the buffer size if the second argument is not NULL. * */ static char * GetStringAtOffset(bufp, cbufsiz, off, st) char **bufp; unsigned int *cbufsiz; unsigned int off; FILE *st; { unsigned int bufsiz; char *buf; char *nbuf; unsigned int idx = off; if (bufp == NULL) return (NULL); buf = *bufp; bufsiz = ROUND_CHUNK_SIZE(off + 1); if (buf == NULL || cbufsiz == NULL || *cbufsiz != bufsiz) { if ((nbuf = realloc(buf, bufsiz)) == NULL) return (NULL); buf = nbuf; *bufp = buf; if (cbufsiz != NULL) *cbufsiz = bufsiz; } if (st == NULL) return (buf); clearerr(st); for (;;) { int c = getc(st); /* Expand the buffer as needed. */ if (idx == bufsiz) { bufsiz += BUFFER_CHUNK_SIZE; if ((nbuf = realloc(buf, bufsiz)) == NULL) { /* Discard everything we read. */ buf[off] = 0; buf = NULL; break; } buf = nbuf; *bufp = buf; if (cbufsiz != NULL) *cbufsiz = bufsiz; } if (c == EOF || c == '\n') { buf[idx] = 0; if (ferror(st) != 0) { /* Retry if interrupted by a signal. */ if (errno == EINTR) { clearerr(st); continue; } buf = NULL; } else if (feof(st) != 0) { /* No characters transferred? */ if (off == idx) buf = NULL; } break; } buf[idx++] = c; } return (buf); } /* * Read a string from the supplied stream. Stop reading when a newline * is read, end of file reached, or an error occurs. * * A buffer can be supplied by specifying the buffer address via the * first argument. The buffer size can be passed via the second argument. * If the second argument is NULL, the function makes no assumptions * about the buffer size. The buffer will be reallocated if it is too * small or too large for the returned string. * * If no buffer is to be supplied, specify a buffer address of NULL, * via the first argument. * * If the first argument is NULL, the function just returns NULL, and * performs no other processing. * * The function returns the address of the buffer if any characters are * read and no error occurred. * * If the function returns NULL, a buffer may have been allocated. The * buffer address and buffer size will be returned via the first argument, * and the buffer size via the second argument, if this isn't NULL. */ char * GetString(bufp, bufsiz, st) char **bufp; unsigned int *bufsiz; FILE *st; { return (GetStringAtOffset(bufp, bufsiz, 0, st)); } /* * Allocate a buffer to hold a string of given length. * * An existing buffer can be reallocated by passing its address and via * the first argument. The buffer size can be passed via the second * argument. If the second argument is NULL, the function makes no * assumptions about the buffer size. * * If no existing buffer is to be supplied, pass a NULL buffer address via * the first argument. * * If the first argument is NULL, the function just returns NULL, * and performs no other processing. */ char * AllocStringBuffer(bufp, bufsiz, size) char **bufp; unsigned int *bufsiz; unsigned int size; { return (GetStringAtOffset(bufp, bufsiz, size, (FILE *)NULL)); } /* * This function is similar to GetString(), except that the string read * from the stream is appended to the supplied string. */ char * GetAndAppendString(bufp, bufsiz, str, st) char **bufp; unsigned int *bufsiz; char *str; FILE *st; { unsigned int off = strlen(str); if (GetStringAtOffset(bufp, bufsiz, off, st) == NULL) return (NULL); return (memcpy(*bufp, str, off)); }