xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.bin/telnet/utilities.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 1994-2002 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate 
6*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
7*0Sstevel@tonic-gate 
8*0Sstevel@tonic-gate /*
9*0Sstevel@tonic-gate  * usr/src/cmd/cmd-inet/usr.bin/telnet/utilities.c
10*0Sstevel@tonic-gate  */
11*0Sstevel@tonic-gate 
12*0Sstevel@tonic-gate /*
13*0Sstevel@tonic-gate  * Copyright (c) 1988, 1993
14*0Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
15*0Sstevel@tonic-gate  *
16*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
17*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
18*0Sstevel@tonic-gate  * are met:
19*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
20*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
21*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
22*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
23*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
24*0Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
25*0Sstevel@tonic-gate  *    must display the following acknowledgement:
26*0Sstevel@tonic-gate  *	This product includes software developed by the University of
27*0Sstevel@tonic-gate  *	California, Berkeley and its contributors.
28*0Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
29*0Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
30*0Sstevel@tonic-gate  *    without specific prior written permission.
31*0Sstevel@tonic-gate  *
32*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
33*0Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
34*0Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
35*0Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
36*0Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37*0Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38*0Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39*0Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
40*0Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
41*0Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
42*0Sstevel@tonic-gate  * SUCH DAMAGE.
43*0Sstevel@tonic-gate  */
44*0Sstevel@tonic-gate 
45*0Sstevel@tonic-gate #ifndef lint
46*0Sstevel@tonic-gate static char sccsid[] = "@(#)utilities.c	8.1 (Berkeley) 6/6/93";
47*0Sstevel@tonic-gate #endif /* not lint */
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate #define	TELOPTS
50*0Sstevel@tonic-gate #ifdef	lint
51*0Sstevel@tonic-gate static char *telcmds[] = {0};
52*0Sstevel@tonic-gate static char *slc_names[] = {0};
53*0Sstevel@tonic-gate static char *encrypt_names[] = {0};
54*0Sstevel@tonic-gate static char *enctype_names[] = {0};
55*0Sstevel@tonic-gate #else	/* lint */
56*0Sstevel@tonic-gate #define	TELCMDS
57*0Sstevel@tonic-gate #define	SLC_NAMES
58*0Sstevel@tonic-gate #endif	/* lint */
59*0Sstevel@tonic-gate #include <arpa/telnet.h>
60*0Sstevel@tonic-gate #include <sys/types.h>
61*0Sstevel@tonic-gate #include <sys/time.h>
62*0Sstevel@tonic-gate #include <sys/param.h>
63*0Sstevel@tonic-gate #include <sys/socket.h>
64*0Sstevel@tonic-gate #include <errno.h>
65*0Sstevel@tonic-gate 
66*0Sstevel@tonic-gate #include <ctype.h>
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate #include "general.h"
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate #include "ring.h"
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate #include "defines.h"
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate #include "externs.h"
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate FILE	*NetTrace = 0;		/* Not in bss, since needs to stay */
77*0Sstevel@tonic-gate int	prettydump;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate /*
80*0Sstevel@tonic-gate  * upcase()
81*0Sstevel@tonic-gate  *
82*0Sstevel@tonic-gate  *	Upcase (in place) the argument.
83*0Sstevel@tonic-gate  */
84*0Sstevel@tonic-gate 
85*0Sstevel@tonic-gate     void
upcase(argument)86*0Sstevel@tonic-gate upcase(argument)
87*0Sstevel@tonic-gate 	register char *argument;
88*0Sstevel@tonic-gate {
89*0Sstevel@tonic-gate 	register int c;
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate 	while ((c = *argument) != 0) {
92*0Sstevel@tonic-gate 		if (islower(c)) {
93*0Sstevel@tonic-gate 			*argument = toupper(c);
94*0Sstevel@tonic-gate 		}
95*0Sstevel@tonic-gate 	argument++;
96*0Sstevel@tonic-gate 	}
97*0Sstevel@tonic-gate }
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate /*
100*0Sstevel@tonic-gate  * SetSockOpt()
101*0Sstevel@tonic-gate  *
102*0Sstevel@tonic-gate  * Compensate for differences in 4.2 and 4.3 systems.
103*0Sstevel@tonic-gate  */
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate     int
SetSockOpt(fd,level,option,yesno)106*0Sstevel@tonic-gate SetSockOpt(fd, level, option, yesno)
107*0Sstevel@tonic-gate     int fd, level, option, yesno;
108*0Sstevel@tonic-gate {
109*0Sstevel@tonic-gate 	return (setsockopt(fd, level, option, &yesno, sizeof (yesno)));
110*0Sstevel@tonic-gate }
111*0Sstevel@tonic-gate 
112*0Sstevel@tonic-gate /*
113*0Sstevel@tonic-gate  * The following are routines used to print out debugging information.
114*0Sstevel@tonic-gate  */
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate unsigned char NetTraceFile[MAXPATHLEN] = "(standard output)";
117*0Sstevel@tonic-gate 
118*0Sstevel@tonic-gate     void
SetNetTrace(file)119*0Sstevel@tonic-gate SetNetTrace(file)
120*0Sstevel@tonic-gate     register char *file;
121*0Sstevel@tonic-gate {
122*0Sstevel@tonic-gate 	if (NetTrace && NetTrace != stdout)
123*0Sstevel@tonic-gate 		(void) fclose(NetTrace);
124*0Sstevel@tonic-gate 	if (file && (strcmp(file, "-") != 0)) {
125*0Sstevel@tonic-gate 		NetTrace = fopen(file, "w");
126*0Sstevel@tonic-gate 		if (NetTrace) {
127*0Sstevel@tonic-gate 			(void) strcpy((char *)NetTraceFile, file);
128*0Sstevel@tonic-gate 			return;
129*0Sstevel@tonic-gate 		}
130*0Sstevel@tonic-gate 		(void) fprintf(stderr, "Cannot open %s.\n", file);
131*0Sstevel@tonic-gate 	}
132*0Sstevel@tonic-gate 	NetTrace = stdout;
133*0Sstevel@tonic-gate 	(void) strcpy((char *)NetTraceFile, "(standard output)");
134*0Sstevel@tonic-gate }
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate     void
Dump(direction,buffer,length)137*0Sstevel@tonic-gate Dump(direction, buffer, length)
138*0Sstevel@tonic-gate     char direction;
139*0Sstevel@tonic-gate     unsigned char *buffer;
140*0Sstevel@tonic-gate     int length;
141*0Sstevel@tonic-gate {
142*0Sstevel@tonic-gate #define	BYTES_PER_LINE	32
143*0Sstevel@tonic-gate #define	min(x, y)	((x < y) ? x:y)
144*0Sstevel@tonic-gate 	unsigned char *pThis;
145*0Sstevel@tonic-gate 	int offset;
146*0Sstevel@tonic-gate 
147*0Sstevel@tonic-gate 	offset = 0;
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate 	while (length) {
150*0Sstevel@tonic-gate 		/* print one line */
151*0Sstevel@tonic-gate 		(void) fprintf(NetTrace, "%c 0x%x\t", direction, offset);
152*0Sstevel@tonic-gate 		pThis = buffer;
153*0Sstevel@tonic-gate 		if (prettydump) {
154*0Sstevel@tonic-gate 			buffer = buffer + min(length, BYTES_PER_LINE/2);
155*0Sstevel@tonic-gate 			while (pThis < buffer) {
156*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "%c%.2x",
157*0Sstevel@tonic-gate 				    (((*pThis)&0xff) == 0xff) ? '*' : ' ',
158*0Sstevel@tonic-gate 				    (*pThis)&0xff);
159*0Sstevel@tonic-gate 				pThis++;
160*0Sstevel@tonic-gate 			}
161*0Sstevel@tonic-gate 			length -= BYTES_PER_LINE/2;
162*0Sstevel@tonic-gate 			offset += BYTES_PER_LINE/2;
163*0Sstevel@tonic-gate 		} else {
164*0Sstevel@tonic-gate 			buffer = buffer + min(length, BYTES_PER_LINE);
165*0Sstevel@tonic-gate 			while (pThis < buffer) {
166*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "%.2x", (*pThis)&0xff);
167*0Sstevel@tonic-gate 				pThis++;
168*0Sstevel@tonic-gate 			}
169*0Sstevel@tonic-gate 			length -= BYTES_PER_LINE;
170*0Sstevel@tonic-gate 			offset += BYTES_PER_LINE;
171*0Sstevel@tonic-gate 		}
172*0Sstevel@tonic-gate 		if (NetTrace == stdout) {
173*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "\r\n");
174*0Sstevel@tonic-gate 		} else {
175*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "\n");
176*0Sstevel@tonic-gate 		}
177*0Sstevel@tonic-gate 		if (length < 0) {
178*0Sstevel@tonic-gate 			(void) fflush(NetTrace);
179*0Sstevel@tonic-gate 			return;
180*0Sstevel@tonic-gate 		}
181*0Sstevel@tonic-gate 		/* find next unique line */
182*0Sstevel@tonic-gate 	}
183*0Sstevel@tonic-gate 	(void) fflush(NetTrace);
184*0Sstevel@tonic-gate }
185*0Sstevel@tonic-gate 
186*0Sstevel@tonic-gate 
187*0Sstevel@tonic-gate 	void
printoption(direction,cmd,option)188*0Sstevel@tonic-gate printoption(direction, cmd, option)
189*0Sstevel@tonic-gate 	char *direction;
190*0Sstevel@tonic-gate 	int cmd, option;
191*0Sstevel@tonic-gate {
192*0Sstevel@tonic-gate 	if (!showoptions)
193*0Sstevel@tonic-gate 		return;
194*0Sstevel@tonic-gate 	if (cmd == IAC) {
195*0Sstevel@tonic-gate 		if (TELCMD_OK(option))
196*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "%s IAC %s", direction,
197*0Sstevel@tonic-gate 			    TELCMD(option));
198*0Sstevel@tonic-gate 		else
199*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "%s IAC %d", direction,
200*0Sstevel@tonic-gate 				option);
201*0Sstevel@tonic-gate 	} else {
202*0Sstevel@tonic-gate 		register char *fmt;
203*0Sstevel@tonic-gate 		fmt = (cmd == WILL) ? "WILL" : (cmd == WONT) ? "WONT" :
204*0Sstevel@tonic-gate 			(cmd == DO) ? "DO" : (cmd == DONT) ? "DONT" : 0;
205*0Sstevel@tonic-gate 		if (fmt) {
206*0Sstevel@tonic-gate 		    (void) fprintf(NetTrace, "%s %s ", direction, fmt);
207*0Sstevel@tonic-gate 		    if (TELOPT_OK(option))
208*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "%s", TELOPT(option));
209*0Sstevel@tonic-gate 		    else if (option == TELOPT_EXOPL)
210*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "EXOPL");
211*0Sstevel@tonic-gate 		    else
212*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "%d", option);
213*0Sstevel@tonic-gate 		} else
214*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "%s %d %d", direction, cmd,
215*0Sstevel@tonic-gate 			    option);
216*0Sstevel@tonic-gate 	}
217*0Sstevel@tonic-gate 	if (NetTrace == stdout) {
218*0Sstevel@tonic-gate 	    (void) fprintf(NetTrace, "\r\n");
219*0Sstevel@tonic-gate 	    (void) fflush(NetTrace);
220*0Sstevel@tonic-gate 	} else {
221*0Sstevel@tonic-gate 	    (void) fprintf(NetTrace, "\n");
222*0Sstevel@tonic-gate 	}
223*0Sstevel@tonic-gate }
224*0Sstevel@tonic-gate 
225*0Sstevel@tonic-gate     void
optionstatus()226*0Sstevel@tonic-gate optionstatus()
227*0Sstevel@tonic-gate {
228*0Sstevel@tonic-gate 	register int i;
229*0Sstevel@tonic-gate 	extern char will_wont_resp[], do_dont_resp[];
230*0Sstevel@tonic-gate 
231*0Sstevel@tonic-gate 	for (i = 0; i < SUBBUFSIZE; i++) {
232*0Sstevel@tonic-gate 		if (do_dont_resp[i]) {
233*0Sstevel@tonic-gate 			if (TELOPT_OK(i))
234*0Sstevel@tonic-gate 				(void) printf("resp DO_DONT %s: %d\n",
235*0Sstevel@tonic-gate 				    TELOPT(i), do_dont_resp[i]);
236*0Sstevel@tonic-gate 			else if (TELCMD_OK(i))
237*0Sstevel@tonic-gate 				(void) printf("resp DO_DONT %s: %d\n",
238*0Sstevel@tonic-gate 				    TELCMD(i), do_dont_resp[i]);
239*0Sstevel@tonic-gate 			else
240*0Sstevel@tonic-gate 				(void) printf("resp DO_DONT %d: %d\n", i,
241*0Sstevel@tonic-gate 				    do_dont_resp[i]);
242*0Sstevel@tonic-gate 			if (my_want_state_is_do(i)) {
243*0Sstevel@tonic-gate 				if (TELOPT_OK(i))
244*0Sstevel@tonic-gate 					(void) printf("want DO   %s\n",
245*0Sstevel@tonic-gate 					    TELOPT(i));
246*0Sstevel@tonic-gate 				else if (TELCMD_OK(i))
247*0Sstevel@tonic-gate 					(void) printf("want DO   %s\n",
248*0Sstevel@tonic-gate 						TELCMD(i));
249*0Sstevel@tonic-gate 				else
250*0Sstevel@tonic-gate 					(void) printf("want DO   %d\n", i);
251*0Sstevel@tonic-gate 			} else {
252*0Sstevel@tonic-gate 				if (TELOPT_OK(i))
253*0Sstevel@tonic-gate 					(void) printf("want DONT %s\n",
254*0Sstevel@tonic-gate 					    TELOPT(i));
255*0Sstevel@tonic-gate 				else if (TELCMD_OK(i))
256*0Sstevel@tonic-gate 					(void) printf("want DONT %s\n",
257*0Sstevel@tonic-gate 					    TELCMD(i));
258*0Sstevel@tonic-gate 				else
259*0Sstevel@tonic-gate 					(void) printf("want DONT %d\n", i);
260*0Sstevel@tonic-gate 			}
261*0Sstevel@tonic-gate 		} else {
262*0Sstevel@tonic-gate 			if (my_state_is_do(i)) {
263*0Sstevel@tonic-gate 				if (TELOPT_OK(i))
264*0Sstevel@tonic-gate 					(void) printf("     DO   %s\n",
265*0Sstevel@tonic-gate 					    TELOPT(i));
266*0Sstevel@tonic-gate 				else if (TELCMD_OK(i))
267*0Sstevel@tonic-gate 					(void) printf("     DO   %s\n",
268*0Sstevel@tonic-gate 					    TELCMD(i));
269*0Sstevel@tonic-gate 				else
270*0Sstevel@tonic-gate 					(void) printf("     DO   %d\n", i);
271*0Sstevel@tonic-gate 			}
272*0Sstevel@tonic-gate 		}
273*0Sstevel@tonic-gate 		if (will_wont_resp[i]) {
274*0Sstevel@tonic-gate 			if (TELOPT_OK(i))
275*0Sstevel@tonic-gate 				(void) printf("resp WILL_WONT %s: %d\n",
276*0Sstevel@tonic-gate 				    TELOPT(i), will_wont_resp[i]);
277*0Sstevel@tonic-gate 			else if (TELCMD_OK(i))
278*0Sstevel@tonic-gate 				(void) printf("resp WILL_WONT %s: %d\n",
279*0Sstevel@tonic-gate 				    TELCMD(i), will_wont_resp[i]);
280*0Sstevel@tonic-gate 			else
281*0Sstevel@tonic-gate 				(void) printf("resp WILL_WONT %d: %d\n",
282*0Sstevel@tonic-gate 				    i, will_wont_resp[i]);
283*0Sstevel@tonic-gate 			if (my_want_state_is_will(i)) {
284*0Sstevel@tonic-gate 				if (TELOPT_OK(i))
285*0Sstevel@tonic-gate 					(void) printf("want WILL %s\n",
286*0Sstevel@tonic-gate 					    TELOPT(i));
287*0Sstevel@tonic-gate 				else if (TELCMD_OK(i))
288*0Sstevel@tonic-gate 					(void) printf("want WILL %s\n",
289*0Sstevel@tonic-gate 					    TELCMD(i));
290*0Sstevel@tonic-gate 				else
291*0Sstevel@tonic-gate 					(void) printf("want WILL %d\n", i);
292*0Sstevel@tonic-gate 			} else {
293*0Sstevel@tonic-gate 				if (TELOPT_OK(i))
294*0Sstevel@tonic-gate 					(void) printf("want WONT %s\n",
295*0Sstevel@tonic-gate 					    TELOPT(i));
296*0Sstevel@tonic-gate 				else if (TELCMD_OK(i))
297*0Sstevel@tonic-gate 					(void) printf("want WONT %s\n",
298*0Sstevel@tonic-gate 					    TELCMD(i));
299*0Sstevel@tonic-gate 				else
300*0Sstevel@tonic-gate 					(void) printf("want WONT %d\n", i);
301*0Sstevel@tonic-gate 			}
302*0Sstevel@tonic-gate 		} else {
303*0Sstevel@tonic-gate 			if (my_state_is_will(i)) {
304*0Sstevel@tonic-gate 				if (TELOPT_OK(i))
305*0Sstevel@tonic-gate 					(void) printf("     WILL %s\n",
306*0Sstevel@tonic-gate 					    TELOPT(i));
307*0Sstevel@tonic-gate 				else if (TELCMD_OK(i))
308*0Sstevel@tonic-gate 					(void) printf("     WILL %s\n",
309*0Sstevel@tonic-gate 					    TELCMD(i));
310*0Sstevel@tonic-gate 				else
311*0Sstevel@tonic-gate 					(void) printf("     WILL %d\n", i);
312*0Sstevel@tonic-gate 			}
313*0Sstevel@tonic-gate 		}
314*0Sstevel@tonic-gate 	}
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate }
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate     void
printsub(direction,pointer,length)319*0Sstevel@tonic-gate printsub(direction, pointer, length)
320*0Sstevel@tonic-gate 	char direction;	/* '<' or '>' */
321*0Sstevel@tonic-gate 	unsigned char *pointer;	/* where suboption data sits */
322*0Sstevel@tonic-gate 	int	  length;	/* length of suboption data */
323*0Sstevel@tonic-gate {
324*0Sstevel@tonic-gate 	register int i;
325*0Sstevel@tonic-gate 	char buf[512];
326*0Sstevel@tonic-gate 	extern int want_status_response;
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 	if (showoptions || direction == 0 ||
329*0Sstevel@tonic-gate 	    (want_status_response && (pointer[0] == TELOPT_STATUS))) {
330*0Sstevel@tonic-gate 		if (direction) {
331*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "%s IAC SB ",
332*0Sstevel@tonic-gate 				(direction == '<')? "RCVD":"SENT");
333*0Sstevel@tonic-gate 			if (length >= 3) {
334*0Sstevel@tonic-gate 				register int j;
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 				i = pointer[length-2];
337*0Sstevel@tonic-gate 				j = pointer[length-1];
338*0Sstevel@tonic-gate 
339*0Sstevel@tonic-gate 				if (i != IAC || j != SE) {
340*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
341*0Sstevel@tonic-gate 					    "(terminated by ");
342*0Sstevel@tonic-gate 					if (TELOPT_OK(i))
343*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, "%s ",
344*0Sstevel@tonic-gate 						    TELOPT(i));
345*0Sstevel@tonic-gate 					else if (TELCMD_OK(i))
346*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, "%s ",
347*0Sstevel@tonic-gate 						    TELCMD(i));
348*0Sstevel@tonic-gate 					else
349*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, "%d ",
350*0Sstevel@tonic-gate 						    i);
351*0Sstevel@tonic-gate 					if (TELOPT_OK(j))
352*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, "%s",
353*0Sstevel@tonic-gate 						    TELOPT(j));
354*0Sstevel@tonic-gate 					else if (TELCMD_OK(j))
355*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, "%s",
356*0Sstevel@tonic-gate 						    TELCMD(j));
357*0Sstevel@tonic-gate 					else
358*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, "%d",
359*0Sstevel@tonic-gate 						    j);
360*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
361*0Sstevel@tonic-gate 					    ", not IAC SE!) ");
362*0Sstevel@tonic-gate 				}
363*0Sstevel@tonic-gate 			}
364*0Sstevel@tonic-gate 			length -= 2;
365*0Sstevel@tonic-gate 		}
366*0Sstevel@tonic-gate 		if (length < 1) {
367*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "(Empty suboption??\?)");
368*0Sstevel@tonic-gate 			if (NetTrace == stdout)
369*0Sstevel@tonic-gate 				(void) fflush(NetTrace);
370*0Sstevel@tonic-gate 			return;
371*0Sstevel@tonic-gate 		}
372*0Sstevel@tonic-gate 		switch (pointer[0]) {
373*0Sstevel@tonic-gate 		case TELOPT_TTYPE:
374*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "TERMINAL-TYPE ");
375*0Sstevel@tonic-gate 			switch (pointer[1]) {
376*0Sstevel@tonic-gate 			case TELQUAL_IS:
377*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "IS \"%.*s\"",
378*0Sstevel@tonic-gate 				    length-2,
379*0Sstevel@tonic-gate 				    (char *)pointer+2);
380*0Sstevel@tonic-gate 				break;
381*0Sstevel@tonic-gate 			case TELQUAL_SEND:
382*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "SEND");
383*0Sstevel@tonic-gate 				break;
384*0Sstevel@tonic-gate 			default:
385*0Sstevel@tonic-gate 				(void) fprintf(NetTrace,
386*0Sstevel@tonic-gate 				    "- unknown qualifier %d (0x%x).",
387*0Sstevel@tonic-gate 				    pointer[1], pointer[1]);
388*0Sstevel@tonic-gate 			}
389*0Sstevel@tonic-gate 			break;
390*0Sstevel@tonic-gate 		case TELOPT_TSPEED:
391*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "TERMINAL-SPEED");
392*0Sstevel@tonic-gate 			if (length < 2) {
393*0Sstevel@tonic-gate 				(void) fprintf(NetTrace,
394*0Sstevel@tonic-gate 				    " (empty suboption??\?)");
395*0Sstevel@tonic-gate 				break;
396*0Sstevel@tonic-gate 			}
397*0Sstevel@tonic-gate 			switch (pointer[1]) {
398*0Sstevel@tonic-gate 			case TELQUAL_IS:
399*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " IS ");
400*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "%.*s", length-2,
401*0Sstevel@tonic-gate 				    (char *)pointer+2);
402*0Sstevel@tonic-gate 				break;
403*0Sstevel@tonic-gate 			default:
404*0Sstevel@tonic-gate 				if (pointer[1] == 1)
405*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, " SEND");
406*0Sstevel@tonic-gate 				else
407*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
408*0Sstevel@tonic-gate 					    " %d (unknown)", pointer[1]);
409*0Sstevel@tonic-gate 				for (i = 2; i < length; i++)
410*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, " ?%d?",
411*0Sstevel@tonic-gate 					    pointer[i]);
412*0Sstevel@tonic-gate 				break;
413*0Sstevel@tonic-gate 			}
414*0Sstevel@tonic-gate 			break;
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate 		case TELOPT_LFLOW:
417*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "TOGGLE-FLOW-CONTROL");
418*0Sstevel@tonic-gate 			if (length < 2) {
419*0Sstevel@tonic-gate 				(void) fprintf(NetTrace,
420*0Sstevel@tonic-gate 				    " (empty suboption??\?)");
421*0Sstevel@tonic-gate 				break;
422*0Sstevel@tonic-gate 			}
423*0Sstevel@tonic-gate 			switch (pointer[1]) {
424*0Sstevel@tonic-gate 			case LFLOW_OFF:
425*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " OFF");
426*0Sstevel@tonic-gate 				break;
427*0Sstevel@tonic-gate 			case LFLOW_ON:
428*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " ON");
429*0Sstevel@tonic-gate 				break;
430*0Sstevel@tonic-gate 			case LFLOW_RESTART_ANY:
431*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " RESTART-ANY");
432*0Sstevel@tonic-gate 				break;
433*0Sstevel@tonic-gate 			case LFLOW_RESTART_XON:
434*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " RESTART-XON");
435*0Sstevel@tonic-gate 				break;
436*0Sstevel@tonic-gate 			default:
437*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " %d (unknown)",
438*0Sstevel@tonic-gate 				    pointer[1]);
439*0Sstevel@tonic-gate 			}
440*0Sstevel@tonic-gate 			for (i = 2; i < length; i++)
441*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " ?%d?",
442*0Sstevel@tonic-gate 				    pointer[i]);
443*0Sstevel@tonic-gate 			break;
444*0Sstevel@tonic-gate 
445*0Sstevel@tonic-gate 		case TELOPT_NAWS:
446*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "NAWS");
447*0Sstevel@tonic-gate 			if (length < 2) {
448*0Sstevel@tonic-gate 				(void) fprintf(NetTrace,
449*0Sstevel@tonic-gate 				    " (empty suboption??\?)");
450*0Sstevel@tonic-gate 				break;
451*0Sstevel@tonic-gate 			}
452*0Sstevel@tonic-gate 			if (length == 2) {
453*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " ?%d?", pointer[1]);
454*0Sstevel@tonic-gate 				break;
455*0Sstevel@tonic-gate 			}
456*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, " %d %d (%d)",
457*0Sstevel@tonic-gate 			    pointer[1], pointer[2],
458*0Sstevel@tonic-gate 			    (int)((((unsigned int)pointer[1])<<8)|
459*0Sstevel@tonic-gate 			    ((unsigned int)pointer[2])));
460*0Sstevel@tonic-gate 			if (length == 4) {
461*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " ?%d?", pointer[3]);
462*0Sstevel@tonic-gate 				break;
463*0Sstevel@tonic-gate 			}
464*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, " %d %d (%d)",
465*0Sstevel@tonic-gate 			    pointer[3], pointer[4],
466*0Sstevel@tonic-gate 			    (int)((((unsigned int)pointer[3])<<8)|
467*0Sstevel@tonic-gate 			    ((unsigned int)pointer[4])));
468*0Sstevel@tonic-gate 			for (i = 5; i < length; i++)
469*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " ?%d?", pointer[i]);
470*0Sstevel@tonic-gate 			break;
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate 		case TELOPT_AUTHENTICATION:
473*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "AUTHENTICATION");
474*0Sstevel@tonic-gate 			if (length < 2) {
475*0Sstevel@tonic-gate 				(void) fprintf(NetTrace,
476*0Sstevel@tonic-gate 					" (empty suboption??\?)");
477*0Sstevel@tonic-gate 				break;
478*0Sstevel@tonic-gate 			}
479*0Sstevel@tonic-gate 			switch (pointer[1]) {
480*0Sstevel@tonic-gate 			case TELQUAL_REPLY:
481*0Sstevel@tonic-gate 			case TELQUAL_IS:
482*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " %s ",
483*0Sstevel@tonic-gate 				    (pointer[1] == TELQUAL_IS) ?
484*0Sstevel@tonic-gate 				    "IS" : "REPLY");
485*0Sstevel@tonic-gate 				if (AUTHTYPE_NAME_OK(pointer[2]))
486*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, "%s ",
487*0Sstevel@tonic-gate 					    AUTHTYPE_NAME(pointer[2]));
488*0Sstevel@tonic-gate 				else
489*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, "%d ",
490*0Sstevel@tonic-gate 						pointer[2]);
491*0Sstevel@tonic-gate 				if (length < 3) {
492*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
493*0Sstevel@tonic-gate 					    "(partial suboption??\?)");
494*0Sstevel@tonic-gate 					break;
495*0Sstevel@tonic-gate 				}
496*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "%s|%s",
497*0Sstevel@tonic-gate 				    ((pointer[3] & AUTH_WHO_MASK) ==
498*0Sstevel@tonic-gate 				    AUTH_WHO_CLIENT) ? "CLIENT" : "SERVER",
499*0Sstevel@tonic-gate 				    ((pointer[3] & AUTH_HOW_MASK) ==
500*0Sstevel@tonic-gate 				    AUTH_HOW_MUTUAL) ? "MUTUAL" : "ONE-WAY");
501*0Sstevel@tonic-gate 
502*0Sstevel@tonic-gate 				auth_printsub(&pointer[1], length - 1,
503*0Sstevel@tonic-gate 				    (uchar_t *)buf, sizeof (buf));
504*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "%s", buf);
505*0Sstevel@tonic-gate 				break;
506*0Sstevel@tonic-gate 
507*0Sstevel@tonic-gate 			case TELQUAL_SEND:
508*0Sstevel@tonic-gate 				i = 2;
509*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " SEND ");
510*0Sstevel@tonic-gate 				while (i < length) {
511*0Sstevel@tonic-gate 					if (AUTHTYPE_NAME_OK(pointer[i]))
512*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, "%s ",
513*0Sstevel@tonic-gate 						    AUTHTYPE_NAME(pointer[i]));
514*0Sstevel@tonic-gate 					else
515*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, "%d ",
516*0Sstevel@tonic-gate 						    pointer[i]);
517*0Sstevel@tonic-gate 					if (++i >= length) {
518*0Sstevel@tonic-gate 						(void) fprintf(NetTrace,
519*0Sstevel@tonic-gate 						    "(partial "
520*0Sstevel@tonic-gate 						    "suboption??\?)");
521*0Sstevel@tonic-gate 						break;
522*0Sstevel@tonic-gate 					}
523*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, "%s|%s ",
524*0Sstevel@tonic-gate 					    ((pointer[i] & AUTH_WHO_MASK) ==
525*0Sstevel@tonic-gate 					    AUTH_WHO_CLIENT) ?
526*0Sstevel@tonic-gate 					    "CLIENT" : "SERVER",
527*0Sstevel@tonic-gate 					    ((pointer[i] & AUTH_HOW_MASK) ==
528*0Sstevel@tonic-gate 					    AUTH_HOW_MUTUAL) ?
529*0Sstevel@tonic-gate 					    "MUTUAL" : "ONE-WAY");
530*0Sstevel@tonic-gate 					++i;
531*0Sstevel@tonic-gate 				}
532*0Sstevel@tonic-gate 				break;
533*0Sstevel@tonic-gate 
534*0Sstevel@tonic-gate 			case TELQUAL_NAME:
535*0Sstevel@tonic-gate 				i = 2;
536*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " NAME \"");
537*0Sstevel@tonic-gate 				while (i < length)
538*0Sstevel@tonic-gate 					(void) putc(pointer[i++], NetTrace);
539*0Sstevel@tonic-gate 				(void) putc('"', NetTrace);
540*0Sstevel@tonic-gate 				break;
541*0Sstevel@tonic-gate 
542*0Sstevel@tonic-gate 			default:
543*0Sstevel@tonic-gate 				for (i = 2; i < length; i++)
544*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " ?%d?", pointer[i]);
545*0Sstevel@tonic-gate 				break;
546*0Sstevel@tonic-gate 			}
547*0Sstevel@tonic-gate 			break;
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 		case TELOPT_ENCRYPT:
550*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "ENCRYPT");
551*0Sstevel@tonic-gate 			if (length < 2) {
552*0Sstevel@tonic-gate 				(void) fprintf(NetTrace,
553*0Sstevel@tonic-gate 				    " (empty suboption??\?)");
554*0Sstevel@tonic-gate 				break;
555*0Sstevel@tonic-gate 			}
556*0Sstevel@tonic-gate 			switch (pointer[1]) {
557*0Sstevel@tonic-gate 			case ENCRYPT_START:
558*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " START");
559*0Sstevel@tonic-gate 				break;
560*0Sstevel@tonic-gate 
561*0Sstevel@tonic-gate 			case ENCRYPT_END:
562*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " END");
563*0Sstevel@tonic-gate 				break;
564*0Sstevel@tonic-gate 
565*0Sstevel@tonic-gate 			case ENCRYPT_REQSTART:
566*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " REQUEST-START");
567*0Sstevel@tonic-gate 				break;
568*0Sstevel@tonic-gate 
569*0Sstevel@tonic-gate 			case ENCRYPT_REQEND:
570*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " REQUEST-END");
571*0Sstevel@tonic-gate 				break;
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 			case ENCRYPT_IS:
574*0Sstevel@tonic-gate 			case ENCRYPT_REPLY:
575*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " %s ",
576*0Sstevel@tonic-gate 				    (pointer[1] == ENCRYPT_IS) ?
577*0Sstevel@tonic-gate 				    "IS" : "REPLY");
578*0Sstevel@tonic-gate 				if (length < 3) {
579*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, " (partial "
580*0Sstevel@tonic-gate 					    "suboption??\?)");
581*0Sstevel@tonic-gate 					break;
582*0Sstevel@tonic-gate 				}
583*0Sstevel@tonic-gate 				if (ENCTYPE_NAME_OK(pointer[2]))
584*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, "%s ",
585*0Sstevel@tonic-gate 					    ENCTYPE_NAME(pointer[2]));
586*0Sstevel@tonic-gate 				else
587*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
588*0Sstevel@tonic-gate 					    " %d (unknown)", pointer[2]);
589*0Sstevel@tonic-gate 
590*0Sstevel@tonic-gate 				encrypt_printsub(&pointer[1], length - 1,
591*0Sstevel@tonic-gate 				    (uchar_t *)buf, sizeof (buf));
592*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "%s", buf);
593*0Sstevel@tonic-gate 				break;
594*0Sstevel@tonic-gate 
595*0Sstevel@tonic-gate 			case ENCRYPT_SUPPORT:
596*0Sstevel@tonic-gate 				i = 2;
597*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " SUPPORT ");
598*0Sstevel@tonic-gate 				while (i < length) {
599*0Sstevel@tonic-gate 					if (ENCTYPE_NAME_OK(pointer[i]))
600*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, "%s ",
601*0Sstevel@tonic-gate 						    ENCTYPE_NAME(pointer[i]));
602*0Sstevel@tonic-gate 					else
603*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, "%d ",
604*0Sstevel@tonic-gate 						    pointer[i]);
605*0Sstevel@tonic-gate 					i++;
606*0Sstevel@tonic-gate 				}
607*0Sstevel@tonic-gate 				break;
608*0Sstevel@tonic-gate 
609*0Sstevel@tonic-gate 			case ENCRYPT_ENC_KEYID:
610*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " ENC_KEYID ");
611*0Sstevel@tonic-gate 				goto encommon;
612*0Sstevel@tonic-gate 
613*0Sstevel@tonic-gate 			case ENCRYPT_DEC_KEYID:
614*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " DEC_KEYID ");
615*0Sstevel@tonic-gate 				goto encommon;
616*0Sstevel@tonic-gate 
617*0Sstevel@tonic-gate 			default:
618*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, " %d (unknown)",
619*0Sstevel@tonic-gate 				    pointer[1]);
620*0Sstevel@tonic-gate 			encommon:
621*0Sstevel@tonic-gate 				for (i = 2; i < length; i++)
622*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, " %d",
623*0Sstevel@tonic-gate 					    pointer[i]);
624*0Sstevel@tonic-gate 				break;
625*0Sstevel@tonic-gate 			}
626*0Sstevel@tonic-gate 			break;
627*0Sstevel@tonic-gate 
628*0Sstevel@tonic-gate 		case TELOPT_LINEMODE:
629*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "LINEMODE ");
630*0Sstevel@tonic-gate 			if (length < 2) {
631*0Sstevel@tonic-gate 				(void) fprintf(NetTrace,
632*0Sstevel@tonic-gate 				    " (empty suboption??\?)");
633*0Sstevel@tonic-gate 				break;
634*0Sstevel@tonic-gate 			}
635*0Sstevel@tonic-gate 			switch (pointer[1]) {
636*0Sstevel@tonic-gate 			case WILL:
637*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "WILL ");
638*0Sstevel@tonic-gate 				goto common;
639*0Sstevel@tonic-gate 			case WONT:
640*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "WONT ");
641*0Sstevel@tonic-gate 				goto common;
642*0Sstevel@tonic-gate 			case DO:
643*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "DO ");
644*0Sstevel@tonic-gate 				goto common;
645*0Sstevel@tonic-gate 			case DONT:
646*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "DONT ");
647*0Sstevel@tonic-gate common:
648*0Sstevel@tonic-gate 				if (length < 3) {
649*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
650*0Sstevel@tonic-gate 						"(no option??\?)");
651*0Sstevel@tonic-gate 					break;
652*0Sstevel@tonic-gate 				}
653*0Sstevel@tonic-gate 				switch (pointer[2]) {
654*0Sstevel@tonic-gate 				case LM_FORWARDMASK:
655*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
656*0Sstevel@tonic-gate 					    "Forward Mask");
657*0Sstevel@tonic-gate 					for (i = 3; i < length; i++)
658*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, " %x",
659*0Sstevel@tonic-gate 						    pointer[i]);
660*0Sstevel@tonic-gate 					break;
661*0Sstevel@tonic-gate 				default:
662*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, "%d (unknown)",
663*0Sstevel@tonic-gate 					    pointer[2]);
664*0Sstevel@tonic-gate 					for (i = 3; i < length; i++)
665*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
666*0Sstevel@tonic-gate 					    " %d", pointer[i]);
667*0Sstevel@tonic-gate 					break;
668*0Sstevel@tonic-gate 				}
669*0Sstevel@tonic-gate 				break;
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate 			case LM_SLC:
672*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "SLC");
673*0Sstevel@tonic-gate 				for (i = 2; i < length - 2; i += 3) {
674*0Sstevel@tonic-gate 					if (SLC_NAME_OK(pointer[i+SLC_FUNC]))
675*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, " %s",
676*0Sstevel@tonic-gate 						    SLC_NAME(pointer[
677*0Sstevel@tonic-gate 						    i+SLC_FUNC]));
678*0Sstevel@tonic-gate 					else
679*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, " %d",
680*0Sstevel@tonic-gate 						    pointer[i+SLC_FUNC]);
681*0Sstevel@tonic-gate 					switch (pointer[i+SLC_FLAGS] &
682*0Sstevel@tonic-gate 					    SLC_LEVELBITS) {
683*0Sstevel@tonic-gate 					case SLC_NOSUPPORT:
684*0Sstevel@tonic-gate 						(void) fprintf(NetTrace,
685*0Sstevel@tonic-gate 						    " NOSUPPORT");
686*0Sstevel@tonic-gate 						break;
687*0Sstevel@tonic-gate 					case SLC_CANTCHANGE:
688*0Sstevel@tonic-gate 						(void) fprintf(NetTrace,
689*0Sstevel@tonic-gate 						    " CANTCHANGE");
690*0Sstevel@tonic-gate 						break;
691*0Sstevel@tonic-gate 					case SLC_VARIABLE:
692*0Sstevel@tonic-gate 						(void) fprintf(NetTrace,
693*0Sstevel@tonic-gate 						    " VARIABLE");
694*0Sstevel@tonic-gate 						break;
695*0Sstevel@tonic-gate 					case SLC_DEFAULT:
696*0Sstevel@tonic-gate 						(void) fprintf(NetTrace,
697*0Sstevel@tonic-gate 						    " DEFAULT");
698*0Sstevel@tonic-gate 						break;
699*0Sstevel@tonic-gate 					}
700*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, "%s%s%s",
701*0Sstevel@tonic-gate 					    pointer[i+SLC_FLAGS]&SLC_ACK ?
702*0Sstevel@tonic-gate 						"|ACK" : "",
703*0Sstevel@tonic-gate 					    pointer[i+SLC_FLAGS]&SLC_FLUSHIN ?
704*0Sstevel@tonic-gate 						"|FLUSHIN" : "",
705*0Sstevel@tonic-gate 					    pointer[i+SLC_FLAGS]&SLC_FLUSHOUT ?
706*0Sstevel@tonic-gate 						"|FLUSHOUT" : "");
707*0Sstevel@tonic-gate 					if (pointer[i+SLC_FLAGS] &
708*0Sstevel@tonic-gate 					    ~(SLC_ACK|SLC_FLUSHIN|
709*0Sstevel@tonic-gate 					    SLC_FLUSHOUT| SLC_LEVELBITS))
710*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, "(0x%x)",
711*0Sstevel@tonic-gate 					    pointer[i+SLC_FLAGS]);
712*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, " %d;",
713*0Sstevel@tonic-gate 					    pointer[i+SLC_VALUE]);
714*0Sstevel@tonic-gate 					if ((pointer[i+SLC_VALUE] == IAC) &&
715*0Sstevel@tonic-gate 					    (pointer[i+SLC_VALUE+1] == IAC))
716*0Sstevel@tonic-gate 						i++;
717*0Sstevel@tonic-gate 				}
718*0Sstevel@tonic-gate 				for (; i < length; i++)
719*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, " ?%d?",
720*0Sstevel@tonic-gate 					    pointer[i]);
721*0Sstevel@tonic-gate 				break;
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 			case LM_MODE:
724*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "MODE ");
725*0Sstevel@tonic-gate 				if (length < 3) {
726*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
727*0Sstevel@tonic-gate 					    "(no mode??\?)");
728*0Sstevel@tonic-gate 					break;
729*0Sstevel@tonic-gate 				}
730*0Sstevel@tonic-gate 				{
731*0Sstevel@tonic-gate 					char tbuf[64];
732*0Sstevel@tonic-gate 					(void) sprintf(tbuf, "%s%s%s%s%s",
733*0Sstevel@tonic-gate 					    pointer[2]&MODE_EDIT ? "|EDIT" : "",
734*0Sstevel@tonic-gate 					    pointer[2]&MODE_TRAPSIG ?
735*0Sstevel@tonic-gate 					    "|TRAPSIG" : "",
736*0Sstevel@tonic-gate 					    pointer[2]&MODE_SOFT_TAB ?
737*0Sstevel@tonic-gate 					    "|SOFT_TAB" : "",
738*0Sstevel@tonic-gate 					    pointer[2]&MODE_LIT_ECHO ?
739*0Sstevel@tonic-gate 					    "|LIT_ECHO" : "",
740*0Sstevel@tonic-gate 					    pointer[2]&MODE_ACK ? "|ACK" : "");
741*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, "%s", tbuf[1] ?
742*0Sstevel@tonic-gate 					    &tbuf[1] : "0");
743*0Sstevel@tonic-gate 				}
744*0Sstevel@tonic-gate 				if (pointer[2]&~(MODE_MASK))
745*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, " (0x%x)",
746*0Sstevel@tonic-gate 					    pointer[2]);
747*0Sstevel@tonic-gate 				for (i = 3; i < length; i++)
748*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, " ?0x%x?",
749*0Sstevel@tonic-gate 					    pointer[i]);
750*0Sstevel@tonic-gate 				break;
751*0Sstevel@tonic-gate 			default:
752*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "%d (unknown)",
753*0Sstevel@tonic-gate 				    pointer[1]);
754*0Sstevel@tonic-gate 				for (i = 2; i < length; i++)
755*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, " %d",
756*0Sstevel@tonic-gate 					    pointer[i]);
757*0Sstevel@tonic-gate 				}
758*0Sstevel@tonic-gate 				break;
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 		case TELOPT_STATUS: {
761*0Sstevel@tonic-gate 				register char *cp;
762*0Sstevel@tonic-gate 				register int j, k;
763*0Sstevel@tonic-gate 
764*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "STATUS");
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate 				switch (pointer[1]) {
767*0Sstevel@tonic-gate 				default:
768*0Sstevel@tonic-gate 					if (pointer[1] == TELQUAL_SEND)
769*0Sstevel@tonic-gate 						(void) fprintf(NetTrace,
770*0Sstevel@tonic-gate 						    " SEND");
771*0Sstevel@tonic-gate 					else
772*0Sstevel@tonic-gate 						(void) fprintf(NetTrace,
773*0Sstevel@tonic-gate 						    " %d (unknown)",
774*0Sstevel@tonic-gate 						    pointer[1]);
775*0Sstevel@tonic-gate 					for (i = 2; i < length; i++)
776*0Sstevel@tonic-gate 					(void) fprintf(NetTrace, " ?%d?",
777*0Sstevel@tonic-gate 					    pointer[i]);
778*0Sstevel@tonic-gate 					break;
779*0Sstevel@tonic-gate 				case TELQUAL_IS:
780*0Sstevel@tonic-gate 					if (--want_status_response < 0)
781*0Sstevel@tonic-gate 						want_status_response = 0;
782*0Sstevel@tonic-gate 					if (NetTrace == stdout)
783*0Sstevel@tonic-gate 						(void) fprintf(NetTrace,
784*0Sstevel@tonic-gate 						    " IS\r\n");
785*0Sstevel@tonic-gate 					else
786*0Sstevel@tonic-gate 						(void) fprintf(NetTrace,
787*0Sstevel@tonic-gate 						    " IS\n");
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate 					for (i = 2; i < length; i++) {
790*0Sstevel@tonic-gate 						switch (pointer[i]) {
791*0Sstevel@tonic-gate 						case DO:
792*0Sstevel@tonic-gate 							cp = "DO";
793*0Sstevel@tonic-gate 							goto common2;
794*0Sstevel@tonic-gate 						case DONT:
795*0Sstevel@tonic-gate 							cp = "DONT";
796*0Sstevel@tonic-gate 							goto common2;
797*0Sstevel@tonic-gate 						case WILL:
798*0Sstevel@tonic-gate 							cp = "WILL";
799*0Sstevel@tonic-gate 							goto common2;
800*0Sstevel@tonic-gate 						case WONT:
801*0Sstevel@tonic-gate 							cp = "WONT";
802*0Sstevel@tonic-gate 							goto common2;
803*0Sstevel@tonic-gate common2:
804*0Sstevel@tonic-gate 							i++;
805*0Sstevel@tonic-gate 							if (TELOPT_OK(
806*0Sstevel@tonic-gate 							    (int)pointer[i]))
807*0Sstevel@tonic-gate 								(void) fprintf(
808*0Sstevel@tonic-gate 								    NetTrace,
809*0Sstevel@tonic-gate 								    " %s %s",
810*0Sstevel@tonic-gate 								    cp,
811*0Sstevel@tonic-gate 								    TELOPT(
812*0Sstevel@tonic-gate 								    pointer[
813*0Sstevel@tonic-gate 								    i]));
814*0Sstevel@tonic-gate 							else
815*0Sstevel@tonic-gate 								(void) fprintf(
816*0Sstevel@tonic-gate 								    NetTrace,
817*0Sstevel@tonic-gate 								    " %s %d",
818*0Sstevel@tonic-gate 								    cp,
819*0Sstevel@tonic-gate 								    pointer[i]);
820*0Sstevel@tonic-gate 
821*0Sstevel@tonic-gate 							if (NetTrace == stdout)
822*0Sstevel@tonic-gate 								(void) fprintf(
823*0Sstevel@tonic-gate 								    NetTrace,
824*0Sstevel@tonic-gate 								    "\r\n");
825*0Sstevel@tonic-gate 							else
826*0Sstevel@tonic-gate 								(void) fprintf(
827*0Sstevel@tonic-gate 								    NetTrace,
828*0Sstevel@tonic-gate 								    "\n");
829*0Sstevel@tonic-gate 							break;
830*0Sstevel@tonic-gate 
831*0Sstevel@tonic-gate 						case SB:
832*0Sstevel@tonic-gate 							(void) fprintf(NetTrace,
833*0Sstevel@tonic-gate 							    " SB ");
834*0Sstevel@tonic-gate 							i++;
835*0Sstevel@tonic-gate 							j = k = i;
836*0Sstevel@tonic-gate 							while (j < length) {
837*0Sstevel@tonic-gate 			if (pointer[j] == SE) {
838*0Sstevel@tonic-gate 				if (j+1 == length)
839*0Sstevel@tonic-gate 					break;
840*0Sstevel@tonic-gate 				if (pointer[j+1] == SE)
841*0Sstevel@tonic-gate 					j++;
842*0Sstevel@tonic-gate 				else
843*0Sstevel@tonic-gate 					break;
844*0Sstevel@tonic-gate 				}
845*0Sstevel@tonic-gate 				pointer[k++] = pointer[j++];
846*0Sstevel@tonic-gate 							}
847*0Sstevel@tonic-gate 							printsub(0,
848*0Sstevel@tonic-gate 							    &pointer[i], k - i);
849*0Sstevel@tonic-gate 							if (i < length) {
850*0Sstevel@tonic-gate 						(void) fprintf(NetTrace, " SE");
851*0Sstevel@tonic-gate 				i = j;
852*0Sstevel@tonic-gate 			} else
853*0Sstevel@tonic-gate 				i = j - 1;
854*0Sstevel@tonic-gate 
855*0Sstevel@tonic-gate 			if (NetTrace == stdout)
856*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "\r\n");
857*0Sstevel@tonic-gate 			else
858*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "\n");
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 							break;
861*0Sstevel@tonic-gate 
862*0Sstevel@tonic-gate 						default:
863*0Sstevel@tonic-gate 							(void) fprintf(NetTrace,
864*0Sstevel@tonic-gate 							    " %d", pointer[i]);
865*0Sstevel@tonic-gate 							break;
866*0Sstevel@tonic-gate 						}
867*0Sstevel@tonic-gate 					}
868*0Sstevel@tonic-gate 					break;
869*0Sstevel@tonic-gate 				}
870*0Sstevel@tonic-gate 				break;
871*0Sstevel@tonic-gate 			}
872*0Sstevel@tonic-gate 
873*0Sstevel@tonic-gate 		case TELOPT_XDISPLOC:
874*0Sstevel@tonic-gate 			(void) fprintf(NetTrace, "X-DISPLAY-LOCATION ");
875*0Sstevel@tonic-gate 			switch (pointer[1]) {
876*0Sstevel@tonic-gate 			case TELQUAL_IS:
877*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "IS \"%.*s\"",
878*0Sstevel@tonic-gate 				    length-2, (char *)pointer+2);
879*0Sstevel@tonic-gate 				break;
880*0Sstevel@tonic-gate 			case TELQUAL_SEND:
881*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "SEND");
882*0Sstevel@tonic-gate 				break;
883*0Sstevel@tonic-gate 			default:
884*0Sstevel@tonic-gate 				(void) fprintf(NetTrace,
885*0Sstevel@tonic-gate 				    "- unknown qualifier %d (0x%x).",
886*0Sstevel@tonic-gate 				    pointer[1], pointer[1]);
887*0Sstevel@tonic-gate 			}
888*0Sstevel@tonic-gate 			break;
889*0Sstevel@tonic-gate 
890*0Sstevel@tonic-gate 		case TELOPT_NEW_ENVIRON:
891*0Sstevel@tonic-gate 	    (void) fprintf(NetTrace, "NEW-ENVIRON ");
892*0Sstevel@tonic-gate #ifdef	OLD_ENVIRON
893*0Sstevel@tonic-gate 	    goto env_common1;
894*0Sstevel@tonic-gate 	case TELOPT_OLD_ENVIRON:
895*0Sstevel@tonic-gate 	    (void) fprintf(NetTrace, "OLD-ENVIRON ");
896*0Sstevel@tonic-gate 	env_common1:
897*0Sstevel@tonic-gate #endif
898*0Sstevel@tonic-gate 	    switch (pointer[1]) {
899*0Sstevel@tonic-gate 	    case TELQUAL_IS:
900*0Sstevel@tonic-gate 		(void) fprintf(NetTrace, "IS ");
901*0Sstevel@tonic-gate 		goto env_common;
902*0Sstevel@tonic-gate 	    case TELQUAL_SEND:
903*0Sstevel@tonic-gate 		(void) fprintf(NetTrace, "SEND ");
904*0Sstevel@tonic-gate 		goto env_common;
905*0Sstevel@tonic-gate 	    case TELQUAL_INFO:
906*0Sstevel@tonic-gate 		(void) fprintf(NetTrace, "INFO ");
907*0Sstevel@tonic-gate 	    env_common:
908*0Sstevel@tonic-gate 		{
909*0Sstevel@tonic-gate 		    register int noquote = 2;
910*0Sstevel@tonic-gate #if defined(ENV_HACK) && defined(OLD_ENVIRON)
911*0Sstevel@tonic-gate 		    extern int old_env_var, old_env_value;
912*0Sstevel@tonic-gate #endif
913*0Sstevel@tonic-gate 		    for (i = 2; i < length; i++) {
914*0Sstevel@tonic-gate 			switch (pointer[i]) {
915*0Sstevel@tonic-gate 			case NEW_ENV_VALUE:
916*0Sstevel@tonic-gate #ifdef OLD_ENVIRON
917*0Sstevel@tonic-gate 		    /*	case NEW_ENV_OVAR: */
918*0Sstevel@tonic-gate 			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
919*0Sstevel@tonic-gate #ifdef	ENV_HACK
920*0Sstevel@tonic-gate 				if (old_env_var == OLD_ENV_VALUE)
921*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
922*0Sstevel@tonic-gate 					    "\" (VALUE) " + noquote);
923*0Sstevel@tonic-gate 				else
924*0Sstevel@tonic-gate #endif
925*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
926*0Sstevel@tonic-gate 					    "\" VAR " + noquote);
927*0Sstevel@tonic-gate 			    } else
928*0Sstevel@tonic-gate #endif /* OLD_ENVIRON */
929*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "\" VALUE " + noquote);
930*0Sstevel@tonic-gate 			    noquote = 2;
931*0Sstevel@tonic-gate 			    break;
932*0Sstevel@tonic-gate 
933*0Sstevel@tonic-gate 			case NEW_ENV_VAR:
934*0Sstevel@tonic-gate #ifdef OLD_ENVIRON
935*0Sstevel@tonic-gate 		    /* case OLD_ENV_VALUE: */
936*0Sstevel@tonic-gate 			    if (pointer[0] == TELOPT_OLD_ENVIRON) {
937*0Sstevel@tonic-gate #ifdef	ENV_HACK
938*0Sstevel@tonic-gate 				if (old_env_value == OLD_ENV_VAR)
939*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
940*0Sstevel@tonic-gate 					    "\" (VAR) " + noquote);
941*0Sstevel@tonic-gate 				else
942*0Sstevel@tonic-gate #endif
943*0Sstevel@tonic-gate 					(void) fprintf(NetTrace,
944*0Sstevel@tonic-gate 					    "\" VALUE " + noquote);
945*0Sstevel@tonic-gate 			    } else
946*0Sstevel@tonic-gate #endif /* OLD_ENVIRON */
947*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "\" VAR " + noquote);
948*0Sstevel@tonic-gate 			    noquote = 2;
949*0Sstevel@tonic-gate 			    break;
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate 			case ENV_ESC:
952*0Sstevel@tonic-gate 			    (void) fprintf(NetTrace, "\" ESC " + noquote);
953*0Sstevel@tonic-gate 			    noquote = 2;
954*0Sstevel@tonic-gate 			    break;
955*0Sstevel@tonic-gate 
956*0Sstevel@tonic-gate 			case ENV_USERVAR:
957*0Sstevel@tonic-gate 			    (void) fprintf(NetTrace, "\" USERVAR " + noquote);
958*0Sstevel@tonic-gate 			    noquote = 2;
959*0Sstevel@tonic-gate 			    break;
960*0Sstevel@tonic-gate 
961*0Sstevel@tonic-gate 			default:
962*0Sstevel@tonic-gate 			def_case:
963*0Sstevel@tonic-gate 			    if (isprint(pointer[i]) && pointer[i] != '"') {
964*0Sstevel@tonic-gate 				if (noquote) {
965*0Sstevel@tonic-gate 				    (void) putc('"', NetTrace);
966*0Sstevel@tonic-gate 				    noquote = 0;
967*0Sstevel@tonic-gate 				}
968*0Sstevel@tonic-gate 				(void) putc(pointer[i], NetTrace);
969*0Sstevel@tonic-gate 			    } else {
970*0Sstevel@tonic-gate 				(void) fprintf(NetTrace, "\" %03o " + noquote,
971*0Sstevel@tonic-gate 							pointer[i]);
972*0Sstevel@tonic-gate 				noquote = 2;
973*0Sstevel@tonic-gate 			    }
974*0Sstevel@tonic-gate 			    break;
975*0Sstevel@tonic-gate 			}
976*0Sstevel@tonic-gate 		    }
977*0Sstevel@tonic-gate 		    if (!noquote)
978*0Sstevel@tonic-gate 			(void) putc('"', NetTrace);
979*0Sstevel@tonic-gate 		    break;
980*0Sstevel@tonic-gate 		}
981*0Sstevel@tonic-gate 	    }
982*0Sstevel@tonic-gate 	    break;
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 	default:
985*0Sstevel@tonic-gate 	    if (TELOPT_OK(pointer[0]))
986*0Sstevel@tonic-gate 		(void) fprintf(NetTrace, "%s (unknown)", TELOPT(pointer[0]));
987*0Sstevel@tonic-gate 	    else
988*0Sstevel@tonic-gate 		(void) fprintf(NetTrace, "%d (unknown)", pointer[0]);
989*0Sstevel@tonic-gate 	    for (i = 1; i < length; i++)
990*0Sstevel@tonic-gate 		(void) fprintf(NetTrace, " %d", pointer[i]);
991*0Sstevel@tonic-gate 	    break;
992*0Sstevel@tonic-gate 	}
993*0Sstevel@tonic-gate 	if (direction) {
994*0Sstevel@tonic-gate 	    if (NetTrace == stdout)
995*0Sstevel@tonic-gate 		(void) fprintf(NetTrace, "\r\n");
996*0Sstevel@tonic-gate 	    else
997*0Sstevel@tonic-gate 		(void) fprintf(NetTrace, "\n");
998*0Sstevel@tonic-gate 	}
999*0Sstevel@tonic-gate 	if (NetTrace == stdout)
1000*0Sstevel@tonic-gate 	    (void) fflush(NetTrace);
1001*0Sstevel@tonic-gate 	}
1002*0Sstevel@tonic-gate }
1003*0Sstevel@tonic-gate 
1004*0Sstevel@tonic-gate /*
1005*0Sstevel@tonic-gate  * EmptyTerminal - called to make sure that the terminal buffer is empty.
1006*0Sstevel@tonic-gate  *			Note that we consider the buffer to run all the
1007*0Sstevel@tonic-gate  *			way to the kernel (thus the select).
1008*0Sstevel@tonic-gate  */
1009*0Sstevel@tonic-gate 
1010*0Sstevel@tonic-gate static void
EmptyTerminal()1011*0Sstevel@tonic-gate EmptyTerminal()
1012*0Sstevel@tonic-gate {
1013*0Sstevel@tonic-gate 	fd_set	o;
1014*0Sstevel@tonic-gate 
1015*0Sstevel@tonic-gate 	FD_ZERO(&o);
1016*0Sstevel@tonic-gate 
1017*0Sstevel@tonic-gate 	if (TTYBYTES() == 0) {
1018*0Sstevel@tonic-gate 		FD_SET(tout, &o);
1019*0Sstevel@tonic-gate 		/* wait for TTLOWAT */
1020*0Sstevel@tonic-gate 		(void) select(tout+1, NULL, &o, NULL, NULL);
1021*0Sstevel@tonic-gate 	} else {
1022*0Sstevel@tonic-gate 		while (TTYBYTES()) {
1023*0Sstevel@tonic-gate 			if (ttyflush(0) == -2) {
1024*0Sstevel@tonic-gate 				/* This will not return. */
1025*0Sstevel@tonic-gate 				fatal_tty_error("write");
1026*0Sstevel@tonic-gate 			}
1027*0Sstevel@tonic-gate 			FD_SET(tout, &o);
1028*0Sstevel@tonic-gate 			/* wait for TTLOWAT */
1029*0Sstevel@tonic-gate 			(void) select(tout+1, NULL, &o, NULL, NULL);
1030*0Sstevel@tonic-gate 		}
1031*0Sstevel@tonic-gate 	}
1032*0Sstevel@tonic-gate }
1033*0Sstevel@tonic-gate 
1034*0Sstevel@tonic-gate static void
SetForExit()1035*0Sstevel@tonic-gate SetForExit()
1036*0Sstevel@tonic-gate {
1037*0Sstevel@tonic-gate 	setconnmode(0);
1038*0Sstevel@tonic-gate 	do {
1039*0Sstevel@tonic-gate 		(void) telrcv();		/* Process any incoming data */
1040*0Sstevel@tonic-gate 		EmptyTerminal();
1041*0Sstevel@tonic-gate 	} while (ring_full_count(&netiring));	/* While there is any */
1042*0Sstevel@tonic-gate 	setcommandmode();
1043*0Sstevel@tonic-gate 	(void) fflush(stdout);
1044*0Sstevel@tonic-gate 	(void) fflush(stderr);
1045*0Sstevel@tonic-gate 	setconnmode(0);
1046*0Sstevel@tonic-gate 	EmptyTerminal();			/* Flush the path to the tty */
1047*0Sstevel@tonic-gate 	setcommandmode();
1048*0Sstevel@tonic-gate }
1049*0Sstevel@tonic-gate 
1050*0Sstevel@tonic-gate void
Exit(returnCode)1051*0Sstevel@tonic-gate Exit(returnCode)
1052*0Sstevel@tonic-gate 	int returnCode;
1053*0Sstevel@tonic-gate {
1054*0Sstevel@tonic-gate 	SetForExit();
1055*0Sstevel@tonic-gate 	exit(returnCode);
1056*0Sstevel@tonic-gate }
1057*0Sstevel@tonic-gate 
1058*0Sstevel@tonic-gate void
ExitString(string,returnCode)1059*0Sstevel@tonic-gate ExitString(string, returnCode)
1060*0Sstevel@tonic-gate 	char *string;
1061*0Sstevel@tonic-gate 	int returnCode;
1062*0Sstevel@tonic-gate {
1063*0Sstevel@tonic-gate 	SetForExit();
1064*0Sstevel@tonic-gate 	(void) fwrite(string, 1, strlen(string), stderr);
1065*0Sstevel@tonic-gate 	exit(returnCode);
1066*0Sstevel@tonic-gate }
1067*0Sstevel@tonic-gate 
1068*0Sstevel@tonic-gate #define	BUFFER_CHUNK_SIZE 64
1069*0Sstevel@tonic-gate 
1070*0Sstevel@tonic-gate /* Round up to a multiple of BUFFER_CHUNK_SIZE */
1071*0Sstevel@tonic-gate #define	ROUND_CHUNK_SIZE(s) ((((s) + BUFFER_CHUNK_SIZE - 1) / \
1072*0Sstevel@tonic-gate 		BUFFER_CHUNK_SIZE) * BUFFER_CHUNK_SIZE)
1073*0Sstevel@tonic-gate 
1074*0Sstevel@tonic-gate /*
1075*0Sstevel@tonic-gate  * Optionally allocate a buffer, and optionally read a string from a stream
1076*0Sstevel@tonic-gate  * into the buffer, starting at the given offset.  If the buffer isn't
1077*0Sstevel@tonic-gate  * large enough for the given offset, or if buffer space is exhausted
1078*0Sstevel@tonic-gate  * when reading the string, the size of the buffer is increased.
1079*0Sstevel@tonic-gate  *
1080*0Sstevel@tonic-gate  * A buffer can be supplied when the function is called, passing the
1081*0Sstevel@tonic-gate  * buffer address via the first argument.  The buffer size can be
1082*0Sstevel@tonic-gate  * passed as well, in the second argument.  If the second argument is
1083*0Sstevel@tonic-gate  * NULL, the function makes no assumptions about the buffer size.
1084*0Sstevel@tonic-gate  * The address of the buffer is returned via the first argument, and the
1085*0Sstevel@tonic-gate  * buffer size via the second argument if this is not NULL.
1086*0Sstevel@tonic-gate  * These returned values may differ from the supplied values if the buffer
1087*0Sstevel@tonic-gate  * was reallocated.
1088*0Sstevel@tonic-gate  *
1089*0Sstevel@tonic-gate  * If no buffer is to be supplied, specify a buffer address of NULL, via
1090*0Sstevel@tonic-gate  * the first argument.
1091*0Sstevel@tonic-gate  *
1092*0Sstevel@tonic-gate  * If the pointer to the buffer address is NULL, the function just returns
1093*0Sstevel@tonic-gate  * NULL, and performs no other processing.
1094*0Sstevel@tonic-gate  *
1095*0Sstevel@tonic-gate  * If a NULL stream is passed, the function will just make sure the
1096*0Sstevel@tonic-gate  * supplied buffer is large enough to hold the supplied offset,
1097*0Sstevel@tonic-gate  * reallocating it if is too small or too large.
1098*0Sstevel@tonic-gate  *
1099*0Sstevel@tonic-gate  * The returned buffer will be a multiple of BUFFER_CHUNK_SIZE in size.
1100*0Sstevel@tonic-gate  *
1101*0Sstevel@tonic-gate  * The function stops reading from the stream when a newline is read,
1102*0Sstevel@tonic-gate  * end of file is reached, or an error occurs.  The newline is not
1103*0Sstevel@tonic-gate  * returned in the buffer.  The returned string will be NULL terminated.
1104*0Sstevel@tonic-gate  *
1105*0Sstevel@tonic-gate  * The function returns the address of the buffer if any characters
1106*0Sstevel@tonic-gate  * are read and no error occurred, otherwise it returns NULL.
1107*0Sstevel@tonic-gate  *
1108*0Sstevel@tonic-gate  * If the function returns NULL, a buffer may have been allocated.  The
1109*0Sstevel@tonic-gate  * buffer address will be returned via the first argument, together with
1110*0Sstevel@tonic-gate  * the buffer size if the second argument is not NULL.
1111*0Sstevel@tonic-gate  *
1112*0Sstevel@tonic-gate  */
1113*0Sstevel@tonic-gate static char *
GetStringAtOffset(bufp,cbufsiz,off,st)1114*0Sstevel@tonic-gate GetStringAtOffset(bufp, cbufsiz, off, st)
1115*0Sstevel@tonic-gate 	char **bufp;
1116*0Sstevel@tonic-gate 	unsigned int *cbufsiz;
1117*0Sstevel@tonic-gate 	unsigned int off;
1118*0Sstevel@tonic-gate 	FILE *st;
1119*0Sstevel@tonic-gate {
1120*0Sstevel@tonic-gate 	unsigned int bufsiz;
1121*0Sstevel@tonic-gate 	char *buf;
1122*0Sstevel@tonic-gate 	char *nbuf;
1123*0Sstevel@tonic-gate 	unsigned int idx = off;
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 	if (bufp == NULL)
1126*0Sstevel@tonic-gate 		return (NULL);
1127*0Sstevel@tonic-gate 
1128*0Sstevel@tonic-gate 	buf = *bufp;
1129*0Sstevel@tonic-gate 
1130*0Sstevel@tonic-gate 	bufsiz = ROUND_CHUNK_SIZE(off + 1);
1131*0Sstevel@tonic-gate 
1132*0Sstevel@tonic-gate 	if (buf == NULL || cbufsiz == NULL || *cbufsiz != bufsiz) {
1133*0Sstevel@tonic-gate 		if ((nbuf = realloc(buf, bufsiz)) == NULL)
1134*0Sstevel@tonic-gate 			return (NULL);
1135*0Sstevel@tonic-gate 
1136*0Sstevel@tonic-gate 		buf = nbuf;
1137*0Sstevel@tonic-gate 		*bufp = buf;
1138*0Sstevel@tonic-gate 		if (cbufsiz != NULL)
1139*0Sstevel@tonic-gate 			*cbufsiz = bufsiz;
1140*0Sstevel@tonic-gate 	}
1141*0Sstevel@tonic-gate 
1142*0Sstevel@tonic-gate 
1143*0Sstevel@tonic-gate 	if (st == NULL)
1144*0Sstevel@tonic-gate 		return (buf);
1145*0Sstevel@tonic-gate 
1146*0Sstevel@tonic-gate 	clearerr(st);
1147*0Sstevel@tonic-gate 	for (;;) {
1148*0Sstevel@tonic-gate 		int c = getc(st);
1149*0Sstevel@tonic-gate 
1150*0Sstevel@tonic-gate 		/* Expand the buffer as needed. */
1151*0Sstevel@tonic-gate 		if (idx == bufsiz) {
1152*0Sstevel@tonic-gate 			bufsiz += BUFFER_CHUNK_SIZE;
1153*0Sstevel@tonic-gate 			if ((nbuf = realloc(buf, bufsiz)) == NULL) {
1154*0Sstevel@tonic-gate 				/* Discard everything we read. */
1155*0Sstevel@tonic-gate 				buf[off] = 0;
1156*0Sstevel@tonic-gate 				buf = NULL;
1157*0Sstevel@tonic-gate 				break;
1158*0Sstevel@tonic-gate 			}
1159*0Sstevel@tonic-gate 			buf = nbuf;
1160*0Sstevel@tonic-gate 			*bufp = buf;
1161*0Sstevel@tonic-gate 			if (cbufsiz != NULL)
1162*0Sstevel@tonic-gate 				*cbufsiz = bufsiz;
1163*0Sstevel@tonic-gate 		}
1164*0Sstevel@tonic-gate 
1165*0Sstevel@tonic-gate 		if (c == EOF || c == '\n') {
1166*0Sstevel@tonic-gate 			buf[idx] = 0;
1167*0Sstevel@tonic-gate 			if (ferror(st) != 0) {
1168*0Sstevel@tonic-gate 				/* Retry if interrupted by a signal. */
1169*0Sstevel@tonic-gate 				if (errno == EINTR) {
1170*0Sstevel@tonic-gate 					clearerr(st);
1171*0Sstevel@tonic-gate 					continue;
1172*0Sstevel@tonic-gate 				}
1173*0Sstevel@tonic-gate 				buf = NULL;
1174*0Sstevel@tonic-gate 			} else if (feof(st) != 0) {
1175*0Sstevel@tonic-gate 				/* No characters transferred? */
1176*0Sstevel@tonic-gate 				if (off == idx)
1177*0Sstevel@tonic-gate 					buf = NULL;
1178*0Sstevel@tonic-gate 			}
1179*0Sstevel@tonic-gate 			break;
1180*0Sstevel@tonic-gate 		}
1181*0Sstevel@tonic-gate 		buf[idx++] = c;
1182*0Sstevel@tonic-gate 	}
1183*0Sstevel@tonic-gate 	return (buf);
1184*0Sstevel@tonic-gate }
1185*0Sstevel@tonic-gate 
1186*0Sstevel@tonic-gate /*
1187*0Sstevel@tonic-gate  * Read a string from the supplied stream.  Stop reading when a newline
1188*0Sstevel@tonic-gate  * is read, end of file reached, or an error occurs.
1189*0Sstevel@tonic-gate  *
1190*0Sstevel@tonic-gate  * A buffer can be supplied by specifying the buffer address via the
1191*0Sstevel@tonic-gate  * first argument. The buffer size can be passed via the second argument.
1192*0Sstevel@tonic-gate  * If the second argument is NULL, the function makes no assumptions
1193*0Sstevel@tonic-gate  * about the buffer size. The buffer will be reallocated if it is too
1194*0Sstevel@tonic-gate  * small or too large for the returned string.
1195*0Sstevel@tonic-gate  *
1196*0Sstevel@tonic-gate  * If no buffer is to be supplied, specify a buffer address of NULL,
1197*0Sstevel@tonic-gate  * via the first argument.
1198*0Sstevel@tonic-gate  *
1199*0Sstevel@tonic-gate  * If the first argument is NULL, the function just returns NULL, and
1200*0Sstevel@tonic-gate  * performs no other processing.
1201*0Sstevel@tonic-gate  *
1202*0Sstevel@tonic-gate  * The function returns the address of the buffer if any characters are
1203*0Sstevel@tonic-gate  * read and no error occurred.
1204*0Sstevel@tonic-gate  *
1205*0Sstevel@tonic-gate  * If the function returns NULL, a buffer may have been allocated.  The
1206*0Sstevel@tonic-gate  * buffer address and buffer size will be returned via the first argument,
1207*0Sstevel@tonic-gate  * and the buffer size via the second argument, if this isn't NULL.
1208*0Sstevel@tonic-gate  */
1209*0Sstevel@tonic-gate char *
GetString(bufp,bufsiz,st)1210*0Sstevel@tonic-gate GetString(bufp, bufsiz, st)
1211*0Sstevel@tonic-gate 	char **bufp;
1212*0Sstevel@tonic-gate 	unsigned int *bufsiz;
1213*0Sstevel@tonic-gate 	FILE *st;
1214*0Sstevel@tonic-gate {
1215*0Sstevel@tonic-gate 	return (GetStringAtOffset(bufp, bufsiz, 0, st));
1216*0Sstevel@tonic-gate }
1217*0Sstevel@tonic-gate 
1218*0Sstevel@tonic-gate /*
1219*0Sstevel@tonic-gate  * Allocate a buffer to hold a string of given length.
1220*0Sstevel@tonic-gate  *
1221*0Sstevel@tonic-gate  * An existing buffer can be reallocated by passing its address and via
1222*0Sstevel@tonic-gate  * the first argument.  The buffer size can be passed via the second
1223*0Sstevel@tonic-gate  * argument.  If the second argument is NULL, the function makes no
1224*0Sstevel@tonic-gate  * assumptions about the buffer size.
1225*0Sstevel@tonic-gate  *
1226*0Sstevel@tonic-gate  * If no existing buffer is to be supplied, pass a NULL buffer address via
1227*0Sstevel@tonic-gate  * the first argument.
1228*0Sstevel@tonic-gate  *
1229*0Sstevel@tonic-gate  * If the first argument is NULL, the function just returns NULL,
1230*0Sstevel@tonic-gate  * and performs no other processing.
1231*0Sstevel@tonic-gate  */
1232*0Sstevel@tonic-gate char *
AllocStringBuffer(bufp,bufsiz,size)1233*0Sstevel@tonic-gate AllocStringBuffer(bufp, bufsiz, size)
1234*0Sstevel@tonic-gate 	char **bufp;
1235*0Sstevel@tonic-gate 	unsigned int *bufsiz;
1236*0Sstevel@tonic-gate 	unsigned int size;
1237*0Sstevel@tonic-gate {
1238*0Sstevel@tonic-gate 	return (GetStringAtOffset(bufp, bufsiz, size, (FILE *)NULL));
1239*0Sstevel@tonic-gate }
1240*0Sstevel@tonic-gate 
1241*0Sstevel@tonic-gate /*
1242*0Sstevel@tonic-gate  * This function is similar to GetString(), except that the string read
1243*0Sstevel@tonic-gate  * from the stream is appended to the supplied string.
1244*0Sstevel@tonic-gate  */
1245*0Sstevel@tonic-gate char *
GetAndAppendString(bufp,bufsiz,str,st)1246*0Sstevel@tonic-gate GetAndAppendString(bufp, bufsiz, str, st)
1247*0Sstevel@tonic-gate 	char **bufp;
1248*0Sstevel@tonic-gate 	unsigned int *bufsiz;
1249*0Sstevel@tonic-gate 	char *str;
1250*0Sstevel@tonic-gate 	FILE *st;
1251*0Sstevel@tonic-gate {
1252*0Sstevel@tonic-gate 	unsigned int off = strlen(str);
1253*0Sstevel@tonic-gate 
1254*0Sstevel@tonic-gate 	if (GetStringAtOffset(bufp, bufsiz, off, st) == NULL)
1255*0Sstevel@tonic-gate 		return (NULL);
1256*0Sstevel@tonic-gate 
1257*0Sstevel@tonic-gate 	return (memcpy(*bufp, str, off));
1258*0Sstevel@tonic-gate }
1259