xref: /illumos-gate/usr/src/cmd/sort/utility.c (revision 101e15b5f8a77d9433805e541996abaabc9ca8c1)
1*101e15b5SRichard Lowe /*
2*101e15b5SRichard Lowe  * CDDL HEADER START
3*101e15b5SRichard Lowe  *
4*101e15b5SRichard Lowe  * The contents of this file are subject to the terms of the
5*101e15b5SRichard Lowe  * Common Development and Distribution License, Version 1.0 only
6*101e15b5SRichard Lowe  * (the "License").  You may not use this file except in compliance
7*101e15b5SRichard Lowe  * with the License.
8*101e15b5SRichard Lowe  *
9*101e15b5SRichard Lowe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*101e15b5SRichard Lowe  * or http://www.opensolaris.org/os/licensing.
11*101e15b5SRichard Lowe  * See the License for the specific language governing permissions
12*101e15b5SRichard Lowe  * and limitations under the License.
13*101e15b5SRichard Lowe  *
14*101e15b5SRichard Lowe  * When distributing Covered Code, include this CDDL HEADER in each
15*101e15b5SRichard Lowe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*101e15b5SRichard Lowe  * If applicable, add the following below this CDDL HEADER, with the
17*101e15b5SRichard Lowe  * fields enclosed by brackets "[]" replaced with your own identifying
18*101e15b5SRichard Lowe  * information: Portions Copyright [yyyy] [name of copyright owner]
19*101e15b5SRichard Lowe  *
20*101e15b5SRichard Lowe  * CDDL HEADER END
21*101e15b5SRichard Lowe  */
22*101e15b5SRichard Lowe /*
23*101e15b5SRichard Lowe  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*101e15b5SRichard Lowe  * Use is subject to license terms.
25*101e15b5SRichard Lowe  */
26*101e15b5SRichard Lowe 
27*101e15b5SRichard Lowe #include "utility.h"
28*101e15b5SRichard Lowe 
29*101e15b5SRichard Lowe #include "initialize.h"
30*101e15b5SRichard Lowe #include "statistics.h"
31*101e15b5SRichard Lowe #include "streams_common.h"
32*101e15b5SRichard Lowe #include "streams.h"
33*101e15b5SRichard Lowe 
34*101e15b5SRichard Lowe /*
35*101e15b5SRichard Lowe  * utility
36*101e15b5SRichard Lowe  *
37*101e15b5SRichard Lowe  * Overview
38*101e15b5SRichard Lowe  *   utility.c contains the general purpose routines used in various locations
39*101e15b5SRichard Lowe  *   throughout sort.  It provides a number of interfaces that maintain local
40*101e15b5SRichard Lowe  *   state relevant to this instance of sort.  We discuss the more significant
41*101e15b5SRichard Lowe  *   of these interfaces below.
42*101e15b5SRichard Lowe  *
43*101e15b5SRichard Lowe  * Output guard
44*101e15b5SRichard Lowe  *   sort is one of the few Unix utilities that is capable of working "in
45*101e15b5SRichard Lowe  *   place"; that is, sort can manipulate an input file and place its output in
46*101e15b5SRichard Lowe  *   a file of the same name safely.  This is handled in this implementation by
47*101e15b5SRichard Lowe  *   the output guard facility.  In the case of an interrupt or other fatal
48*101e15b5SRichard Lowe  *   signal, sort essays to restore the original input file.
49*101e15b5SRichard Lowe  *
50*101e15b5SRichard Lowe  * Temporary file cleanup
51*101e15b5SRichard Lowe  *   Similar to the output guard facility, sort cleans up its temporary files in
52*101e15b5SRichard Lowe  *   the case of interruption (or normal exit, for that matter); this is handled
53*101e15b5SRichard Lowe  *   by registering a list of file pointers for later use by the atexit handler.
54*101e15b5SRichard Lowe  *
55*101e15b5SRichard Lowe  * Temporary filename security
56*101e15b5SRichard Lowe  *   sort protects against "open-through-link" security attacks by verifying
57*101e15b5SRichard Lowe  *   that the selected temporary file name is unused.  If the file name is in
58*101e15b5SRichard Lowe  *   use, the pattern is readjusted until an available name pattern is
59*101e15b5SRichard Lowe  *   discovered.
60*101e15b5SRichard Lowe  *
61*101e15b5SRichard Lowe  * Buffered I/O
62*101e15b5SRichard Lowe  *   sort has a simple buffered I/O facility of its own, to facilitate writing
63*101e15b5SRichard Lowe  *   data in large quantities (particularly for multibyte locales).  cxwrite()
64*101e15b5SRichard Lowe  *   is the base routine, while wxwrite(), which handles multibyte buffers, is
65*101e15b5SRichard Lowe  *   built on top of cxwrite().
66*101e15b5SRichard Lowe  */
67*101e15b5SRichard Lowe 
68*101e15b5SRichard Lowe #define	XBUFFER_SIZE	(32 * KILOBYTE)
69*101e15b5SRichard Lowe 
70*101e15b5SRichard Lowe #define	EXIT_OK		0
71*101e15b5SRichard Lowe #define	EXIT_FAILURE	1
72*101e15b5SRichard Lowe #define	EXIT_ERROR	2
73*101e15b5SRichard Lowe #define	EXIT_INTERNAL	3
74*101e15b5SRichard Lowe 
75*101e15b5SRichard Lowe static int held_fd = -1;
76*101e15b5SRichard Lowe 
77*101e15b5SRichard Lowe static stream_t	**cleanup_chain = NULL;
78*101e15b5SRichard Lowe 
79*101e15b5SRichard Lowe static char *output_guard_tempname = NULL;
80*101e15b5SRichard Lowe static ssize_t output_guard_size = 0;
81*101e15b5SRichard Lowe static char *output_guard_filename = NULL;
82*101e15b5SRichard Lowe static int output_guard_copy_complete = 0;
83*101e15b5SRichard Lowe 
84*101e15b5SRichard Lowe static const char *default_tmpdir = "/var/tmp";
85*101e15b5SRichard Lowe static const char *default_template = "/stmAAAXXXXXX";
86*101e15b5SRichard Lowe static const char *default_template_count = ".00000000";
87*101e15b5SRichard Lowe static char *current_tmpdir;
88*101e15b5SRichard Lowe static char *current_template;
89*101e15b5SRichard Lowe 
90*101e15b5SRichard Lowe static const char PNAME_FMT[] = "%s: ";
91*101e15b5SRichard Lowe static const char ERRNO_FMT[] = ": %s\n";
92*101e15b5SRichard Lowe static const char *pname = "sort";
93*101e15b5SRichard Lowe 
94*101e15b5SRichard Lowe void
swap(void ** a,void ** b)95*101e15b5SRichard Lowe swap(void **a, void **b)
96*101e15b5SRichard Lowe {
97*101e15b5SRichard Lowe 	void *t;
98*101e15b5SRichard Lowe 
99*101e15b5SRichard Lowe 	t = *a;
100*101e15b5SRichard Lowe 	*a = *b;
101*101e15b5SRichard Lowe 	*b = t;
102*101e15b5SRichard Lowe 
103*101e15b5SRichard Lowe 	__S(stats_incr_swaps());
104*101e15b5SRichard Lowe }
105*101e15b5SRichard Lowe 
106*101e15b5SRichard Lowe /*
107*101e15b5SRichard Lowe  * Temporary file name template handling.
108*101e15b5SRichard Lowe  */
109*101e15b5SRichard Lowe static void
reset_file_template()110*101e15b5SRichard Lowe reset_file_template()
111*101e15b5SRichard Lowe {
112*101e15b5SRichard Lowe 	struct stat s;
113*101e15b5SRichard Lowe 
114*101e15b5SRichard Lowe 	do {
115*101e15b5SRichard Lowe 		(void) strcpy(current_template, current_tmpdir);
116*101e15b5SRichard Lowe 		(void) strcat(current_template, default_template);
117*101e15b5SRichard Lowe 		(void) mktemp(current_template);
118*101e15b5SRichard Lowe 		(void) strcat(current_template, default_template_count);
119*101e15b5SRichard Lowe 	} while (lstat(current_template, &s) != -1);
120*101e15b5SRichard Lowe }
121*101e15b5SRichard Lowe 
122*101e15b5SRichard Lowe int
bump_file_template()123*101e15b5SRichard Lowe bump_file_template()
124*101e15b5SRichard Lowe {
125*101e15b5SRichard Lowe 	struct stat s;
126*101e15b5SRichard Lowe 	int n = strlen(current_template);
127*101e15b5SRichard Lowe 	int i;
128*101e15b5SRichard Lowe 
129*101e15b5SRichard Lowe 	for (i = n - 1; isdigit((uchar_t)current_template[i]); i--) {
130*101e15b5SRichard Lowe 		current_template[i]++;
131*101e15b5SRichard Lowe 		if (current_template[i] > '9')
132*101e15b5SRichard Lowe 			current_template[i] = '0';
133*101e15b5SRichard Lowe 		else
134*101e15b5SRichard Lowe 			break;
135*101e15b5SRichard Lowe 	}
136*101e15b5SRichard Lowe 
137*101e15b5SRichard Lowe 	if (!isdigit((uchar_t)current_template[i])) {
138*101e15b5SRichard Lowe 		/*
139*101e15b5SRichard Lowe 		 * Template has been exhausted, so reset.
140*101e15b5SRichard Lowe 		 */
141*101e15b5SRichard Lowe 		reset_file_template();
142*101e15b5SRichard Lowe 	}
143*101e15b5SRichard Lowe 
144*101e15b5SRichard Lowe 	if (lstat(current_template, &s) == 0) {
145*101e15b5SRichard Lowe 		/*
146*101e15b5SRichard Lowe 		 * Our newly bumped template has been anticipated; reset to
147*101e15b5SRichard Lowe 		 * avoid possible "link-through" attack.
148*101e15b5SRichard Lowe 		 */
149*101e15b5SRichard Lowe 		reset_file_template();
150*101e15b5SRichard Lowe 	}
151*101e15b5SRichard Lowe 
152*101e15b5SRichard Lowe 	return (0);
153*101e15b5SRichard Lowe }
154*101e15b5SRichard Lowe 
155*101e15b5SRichard Lowe void
set_file_template(char ** T)156*101e15b5SRichard Lowe set_file_template(char **T)
157*101e15b5SRichard Lowe {
158*101e15b5SRichard Lowe 	struct stat s;
159*101e15b5SRichard Lowe 	int check_tmpdir = 0;
160*101e15b5SRichard Lowe 
161*101e15b5SRichard Lowe 	if (*T != NULL) {
162*101e15b5SRichard Lowe 		current_tmpdir = strdup(*T);
163*101e15b5SRichard Lowe 		check_tmpdir = 1;
164*101e15b5SRichard Lowe 	} else if ((current_tmpdir = getenv("TMPDIR")) != NULL) {
165*101e15b5SRichard Lowe 		check_tmpdir = 1;
166*101e15b5SRichard Lowe 	} else {
167*101e15b5SRichard Lowe 		current_tmpdir = (char *)default_tmpdir;
168*101e15b5SRichard Lowe 	}
169*101e15b5SRichard Lowe 
170*101e15b5SRichard Lowe 	/*
171*101e15b5SRichard Lowe 	 * Check that the temporary directory given exists, and is a directory.
172*101e15b5SRichard Lowe 	 */
173*101e15b5SRichard Lowe 	if (check_tmpdir) {
174*101e15b5SRichard Lowe 		if (stat(current_tmpdir, &s) != 0) {
175*101e15b5SRichard Lowe 			warn(gettext("cannot stat temporary directory %s"),
176*101e15b5SRichard Lowe 			    current_tmpdir);
177*101e15b5SRichard Lowe 
178*101e15b5SRichard Lowe 			current_tmpdir = (char *)default_tmpdir;
179*101e15b5SRichard Lowe 		} else if (!S_ISDIR(s.st_mode)) {
180*101e15b5SRichard Lowe 			warn(gettext("%s is not a directory; "
181*101e15b5SRichard Lowe 			    "using default temporary directory"),
182*101e15b5SRichard Lowe 			    current_tmpdir);
183*101e15b5SRichard Lowe 
184*101e15b5SRichard Lowe 			current_tmpdir = (char *)default_tmpdir;
185*101e15b5SRichard Lowe 		}
186*101e15b5SRichard Lowe 	}
187*101e15b5SRichard Lowe 
188*101e15b5SRichard Lowe 	ASSERT(current_tmpdir != NULL);
189*101e15b5SRichard Lowe 
190*101e15b5SRichard Lowe 	current_template = safe_realloc(NULL, strlen(current_tmpdir)
191*101e15b5SRichard Lowe 	    + strlen(default_template) + strlen(default_template_count) + 1);
192*101e15b5SRichard Lowe 
193*101e15b5SRichard Lowe 	reset_file_template();
194*101e15b5SRichard Lowe }
195*101e15b5SRichard Lowe 
196*101e15b5SRichard Lowe char *
get_file_template()197*101e15b5SRichard Lowe get_file_template()
198*101e15b5SRichard Lowe {
199*101e15b5SRichard Lowe 	return (current_template);
200*101e15b5SRichard Lowe }
201*101e15b5SRichard Lowe 
202*101e15b5SRichard Lowe /*
203*101e15b5SRichard Lowe  * Output guard routines.
204*101e15b5SRichard Lowe  */
205*101e15b5SRichard Lowe void
establish_output_guard(sort_t * S)206*101e15b5SRichard Lowe establish_output_guard(sort_t *S)
207*101e15b5SRichard Lowe {
208*101e15b5SRichard Lowe 	struct stat output_stat;
209*101e15b5SRichard Lowe 
210*101e15b5SRichard Lowe 	if (S->m_output_to_stdout)
211*101e15b5SRichard Lowe 		return;
212*101e15b5SRichard Lowe 
213*101e15b5SRichard Lowe 	if (stat(S->m_output_filename, &output_stat) == 0) {
214*101e15b5SRichard Lowe 		stream_t *strp = S->m_input_streams;
215*101e15b5SRichard Lowe 
216*101e15b5SRichard Lowe 		while (strp != NULL) {
217*101e15b5SRichard Lowe 			/*
218*101e15b5SRichard Lowe 			 * We needn't protect an empty file.
219*101e15b5SRichard Lowe 			 */
220*101e15b5SRichard Lowe 			if (!(strp->s_status & STREAM_NOTFILE) &&
221*101e15b5SRichard Lowe 			    strp->s_dev == output_stat.st_dev &&
222*101e15b5SRichard Lowe 			    strp->s_ino == output_stat.st_ino &&
223*101e15b5SRichard Lowe 			    strp->s_filesize > 0) {
224*101e15b5SRichard Lowe 				output_guard_filename = S->m_output_filename;
225*101e15b5SRichard Lowe 				output_guard_size = strp->s_filesize;
226*101e15b5SRichard Lowe 
227*101e15b5SRichard Lowe 				ASSERT(output_guard_filename != NULL);
228*101e15b5SRichard Lowe 
229*101e15b5SRichard Lowe 				if (bump_file_template() < 0)
230*101e15b5SRichard Lowe 					die(EMSG_TEMPORARY);
231*101e15b5SRichard Lowe 
232*101e15b5SRichard Lowe 				if ((strp->s_filename = output_guard_tempname =
233*101e15b5SRichard Lowe 				    strdup(get_file_template())) == NULL)
234*101e15b5SRichard Lowe 					die(EMSG_ALLOC);
235*101e15b5SRichard Lowe 
236*101e15b5SRichard Lowe 				xcp(output_guard_tempname,
237*101e15b5SRichard Lowe 				    output_guard_filename, output_guard_size);
238*101e15b5SRichard Lowe 
239*101e15b5SRichard Lowe 				output_guard_copy_complete = 1;
240*101e15b5SRichard Lowe 
241*101e15b5SRichard Lowe 				return;
242*101e15b5SRichard Lowe 			}
243*101e15b5SRichard Lowe 			strp = strp->s_next;
244*101e15b5SRichard Lowe 		}
245*101e15b5SRichard Lowe 	}
246*101e15b5SRichard Lowe }
247*101e15b5SRichard Lowe 
248*101e15b5SRichard Lowe void
remove_output_guard()249*101e15b5SRichard Lowe remove_output_guard()
250*101e15b5SRichard Lowe {
251*101e15b5SRichard Lowe 	if (output_guard_tempname && unlink(output_guard_tempname) == -1)
252*101e15b5SRichard Lowe 		warn(gettext("unable to unlink %s"), output_guard_tempname);
253*101e15b5SRichard Lowe 
254*101e15b5SRichard Lowe 	output_guard_tempname = NULL;
255*101e15b5SRichard Lowe }
256*101e15b5SRichard Lowe 
257*101e15b5SRichard Lowe void
set_cleanup_chain(stream_t ** strp)258*101e15b5SRichard Lowe set_cleanup_chain(stream_t **strp)
259*101e15b5SRichard Lowe {
260*101e15b5SRichard Lowe 	ASSERT(strp != NULL);
261*101e15b5SRichard Lowe 
262*101e15b5SRichard Lowe 	cleanup_chain = strp;
263*101e15b5SRichard Lowe }
264*101e15b5SRichard Lowe 
265*101e15b5SRichard Lowe /*
266*101e15b5SRichard Lowe  * atexit_handler() cleans up any temporary files outstanding after a fatal
267*101e15b5SRichard Lowe  * signal, a call to die() or at exit().  To preserve the input file under low
268*101e15b5SRichard Lowe  * storage conditions (and both the output file and the temporary files are
269*101e15b5SRichard Lowe  * directed at the same filesystem), we remove all temporary files but the
270*101e15b5SRichard Lowe  * output guard first, and then restore the original file.  Of course, this is
271*101e15b5SRichard Lowe  * not foolproof, as another writer may have exhausted storage.
272*101e15b5SRichard Lowe  */
273*101e15b5SRichard Lowe void
atexit_handler()274*101e15b5SRichard Lowe atexit_handler()
275*101e15b5SRichard Lowe {
276*101e15b5SRichard Lowe 	stream_t *strp;
277*101e15b5SRichard Lowe 
278*101e15b5SRichard Lowe 	if (cleanup_chain && *cleanup_chain)
279*101e15b5SRichard Lowe 		for (strp = *cleanup_chain; strp != NULL; strp = strp->s_next)
280*101e15b5SRichard Lowe 			stream_unlink_temporary(strp);
281*101e15b5SRichard Lowe 
282*101e15b5SRichard Lowe 	if (output_guard_tempname) {
283*101e15b5SRichard Lowe 		if (output_guard_copy_complete)
284*101e15b5SRichard Lowe 			xcp(output_guard_filename, output_guard_tempname,
285*101e15b5SRichard Lowe 			    output_guard_size);
286*101e15b5SRichard Lowe 
287*101e15b5SRichard Lowe 		remove_output_guard();
288*101e15b5SRichard Lowe 	}
289*101e15b5SRichard Lowe 
290*101e15b5SRichard Lowe 	__S(stats_display());
291*101e15b5SRichard Lowe }
292*101e15b5SRichard Lowe 
293*101e15b5SRichard Lowe size_t
strtomem(char * S)294*101e15b5SRichard Lowe strtomem(char *S)
295*101e15b5SRichard Lowe {
296*101e15b5SRichard Lowe 	const char *format_str = "%lf%c";
297*101e15b5SRichard Lowe 	double val = 0.0;
298*101e15b5SRichard Lowe 	size_t retval;
299*101e15b5SRichard Lowe 	char units = 'k';
300*101e15b5SRichard Lowe 	size_t phys_total = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGESIZE);
301*101e15b5SRichard Lowe 
302*101e15b5SRichard Lowe 	if (sscanf(S, format_str, &val, &units) < 1 || val < 0)
303*101e15b5SRichard Lowe 		return (0);
304*101e15b5SRichard Lowe 
305*101e15b5SRichard Lowe 	if (units == '%') {
306*101e15b5SRichard Lowe 		if (val < 0 || val > 100)
307*101e15b5SRichard Lowe 			return (0);
308*101e15b5SRichard Lowe 		val *= phys_total / 100;
309*101e15b5SRichard Lowe 	} else
310*101e15b5SRichard Lowe 		switch (units) {
311*101e15b5SRichard Lowe 			case 't' : /* terabytes */
312*101e15b5SRichard Lowe 			case 'T' :
313*101e15b5SRichard Lowe 				val *= 1024;
314*101e15b5SRichard Lowe 				/*FALLTHROUGH*/
315*101e15b5SRichard Lowe 			case 'g' : /* gigabytes */
316*101e15b5SRichard Lowe 			case 'G' :
317*101e15b5SRichard Lowe 				val *= 1024;
318*101e15b5SRichard Lowe 				/*FALLTHROUGH*/
319*101e15b5SRichard Lowe 			case 'm' : /* megabytes */
320*101e15b5SRichard Lowe 			case 'M' :
321*101e15b5SRichard Lowe 				val *= 1024;
322*101e15b5SRichard Lowe 				/*FALLTHROUGH*/
323*101e15b5SRichard Lowe 			case 'k' : /* kilobytes */
324*101e15b5SRichard Lowe 			case 'K' :
325*101e15b5SRichard Lowe 				val *= 1024;
326*101e15b5SRichard Lowe 				/*FALLTHROUGH*/
327*101e15b5SRichard Lowe 			case 'b' : /* bytes */
328*101e15b5SRichard Lowe 			case 'B' :
329*101e15b5SRichard Lowe 				break;
330*101e15b5SRichard Lowe 			default :
331*101e15b5SRichard Lowe 				/*
332*101e15b5SRichard Lowe 				 * default is kilobytes
333*101e15b5SRichard Lowe 				 */
334*101e15b5SRichard Lowe 				val *= 1024;
335*101e15b5SRichard Lowe 				break;
336*101e15b5SRichard Lowe 		}
337*101e15b5SRichard Lowe 
338*101e15b5SRichard Lowe 	if (val > SIZE_MAX)
339*101e15b5SRichard Lowe 		return (0);
340*101e15b5SRichard Lowe 
341*101e15b5SRichard Lowe 	retval = (size_t)val;
342*101e15b5SRichard Lowe 
343*101e15b5SRichard Lowe 	return (retval);
344*101e15b5SRichard Lowe }
345*101e15b5SRichard Lowe 
346*101e15b5SRichard Lowe size_t
available_memory(size_t mem_limit)347*101e15b5SRichard Lowe available_memory(size_t mem_limit)
348*101e15b5SRichard Lowe {
349*101e15b5SRichard Lowe 	size_t phys_avail = sysconf(_SC_AVPHYS_PAGES) * sysconf(_SC_PAGESIZE);
350*101e15b5SRichard Lowe 	size_t avail;
351*101e15b5SRichard Lowe 
352*101e15b5SRichard Lowe 	if (mem_limit != 0) {
353*101e15b5SRichard Lowe #ifdef DEBUG
354*101e15b5SRichard Lowe 		/*
355*101e15b5SRichard Lowe 		 * In the debug case, we want to test the temporary files
356*101e15b5SRichard Lowe 		 * handling, so no lower bound on the memory limit is imposed.
357*101e15b5SRichard Lowe 		 */
358*101e15b5SRichard Lowe 		avail = mem_limit;
359*101e15b5SRichard Lowe #else
360*101e15b5SRichard Lowe 		avail = MAX(64 * KILOBYTE, mem_limit);
361*101e15b5SRichard Lowe #endif /* DEBUG */
362*101e15b5SRichard Lowe 	} else {
363*101e15b5SRichard Lowe 		avail = MAX(64 * KILOBYTE, MIN(AV_MEM_MULTIPLIER * phys_avail /
364*101e15b5SRichard Lowe 		    AV_MEM_DIVISOR, 16 * MEGABYTE));
365*101e15b5SRichard Lowe 	}
366*101e15b5SRichard Lowe 
367*101e15b5SRichard Lowe 	__S(stats_set_available_memory(avail));
368*101e15b5SRichard Lowe 
369*101e15b5SRichard Lowe 	return (avail);
370*101e15b5SRichard Lowe }
371*101e15b5SRichard Lowe 
372*101e15b5SRichard Lowe void
set_memory_ratio(sort_t * S,int * numerator,int * denominator)373*101e15b5SRichard Lowe set_memory_ratio(sort_t *S, int *numerator, int *denominator)
374*101e15b5SRichard Lowe {
375*101e15b5SRichard Lowe 	if (S->m_c_locale) {
376*101e15b5SRichard Lowe 		*numerator = CHAR_AVG_LINE;
377*101e15b5SRichard Lowe 		*denominator = sizeof (line_rec_t) + sizeof (line_rec_t *) +
378*101e15b5SRichard Lowe 		    CHAR_AVG_LINE + CHAR_AVG_LINE;
379*101e15b5SRichard Lowe 		return;
380*101e15b5SRichard Lowe 	}
381*101e15b5SRichard Lowe 
382*101e15b5SRichard Lowe 	if (S->m_single_byte_locale) {
383*101e15b5SRichard Lowe 		*numerator = CHAR_AVG_LINE;
384*101e15b5SRichard Lowe 		*denominator = sizeof (line_rec_t) + sizeof (line_rec_t *) +
385*101e15b5SRichard Lowe 		    CHAR_AVG_LINE + XFRM_MULTIPLIER * CHAR_AVG_LINE;
386*101e15b5SRichard Lowe 		return;
387*101e15b5SRichard Lowe 	}
388*101e15b5SRichard Lowe 
389*101e15b5SRichard Lowe 	*numerator = WCHAR_AVG_LINE;
390*101e15b5SRichard Lowe 	*denominator = sizeof (line_rec_t) + sizeof (line_rec_t *) +
391*101e15b5SRichard Lowe 	    WCHAR_AVG_LINE + WCHAR_AVG_LINE;
392*101e15b5SRichard Lowe }
393*101e15b5SRichard Lowe 
394*101e15b5SRichard Lowe void *
safe_realloc(void * ptr,size_t sz)395*101e15b5SRichard Lowe safe_realloc(void *ptr, size_t sz)
396*101e15b5SRichard Lowe {
397*101e15b5SRichard Lowe 	/*
398*101e15b5SRichard Lowe 	 * safe_realloc() is not meant as an alternative free() mechanism--we
399*101e15b5SRichard Lowe 	 * disallow reallocations to size zero.
400*101e15b5SRichard Lowe 	 */
401*101e15b5SRichard Lowe 	ASSERT(sz != 0);
402*101e15b5SRichard Lowe 
403*101e15b5SRichard Lowe 	if ((ptr = realloc(ptr, sz)) != NULL)
404*101e15b5SRichard Lowe 		return (ptr);
405*101e15b5SRichard Lowe 
406*101e15b5SRichard Lowe 	die(gettext("unable to reallocate buffer"));
407*101e15b5SRichard Lowe 	/*NOTREACHED*/
408*101e15b5SRichard Lowe 	return (NULL);	/* keep gcc happy */
409*101e15b5SRichard Lowe }
410*101e15b5SRichard Lowe 
411*101e15b5SRichard Lowe void
safe_free(void * ptr)412*101e15b5SRichard Lowe safe_free(void *ptr)
413*101e15b5SRichard Lowe {
414*101e15b5SRichard Lowe 	if (ptr)
415*101e15b5SRichard Lowe 		free(ptr);
416*101e15b5SRichard Lowe }
417*101e15b5SRichard Lowe 
418*101e15b5SRichard Lowe void *
xzmap(void * addr,size_t len,int prot,int flags,off_t off)419*101e15b5SRichard Lowe xzmap(void *addr, size_t len, int prot, int flags, off_t off)
420*101e15b5SRichard Lowe {
421*101e15b5SRichard Lowe 	void *pa;
422*101e15b5SRichard Lowe 
423*101e15b5SRichard Lowe 	pa = mmap(addr, len, prot, flags | MAP_ANON, -1, off);
424*101e15b5SRichard Lowe 	if (pa == MAP_FAILED)
425*101e15b5SRichard Lowe 		die(gettext("can't mmap anonymous memory"));
426*101e15b5SRichard Lowe 
427*101e15b5SRichard Lowe 	return (pa);
428*101e15b5SRichard Lowe }
429*101e15b5SRichard Lowe 
430*101e15b5SRichard Lowe void
usage()431*101e15b5SRichard Lowe usage()
432*101e15b5SRichard Lowe {
433*101e15b5SRichard Lowe 	(void) fprintf(stderr,
434*101e15b5SRichard Lowe 	    gettext("usage: %s [-cmu] [-o output] [-T directory] [-S mem]"
435*101e15b5SRichard Lowe 	    " [-z recsz]\n\t[-dfiMnr] [-b] [-t char] [-k keydef]"
436*101e15b5SRichard Lowe 	    " [+pos1 [-pos2]] files...\n"), CMDNAME);
437*101e15b5SRichard Lowe 	exit(E_USAGE);
438*101e15b5SRichard Lowe }
439*101e15b5SRichard Lowe 
440*101e15b5SRichard Lowe /*
441*101e15b5SRichard Lowe  * hold_file_descriptor() and release_file_descriptor() reserve a single file
442*101e15b5SRichard Lowe  * descriptor entry for later use.  We issue the hold prior to any loop that has
443*101e15b5SRichard Lowe  * an exit condition based on the receipt of EMFILE from an open() call; once we
444*101e15b5SRichard Lowe  * have exited, we can release, typically prior to opening a file for output.
445*101e15b5SRichard Lowe  */
446*101e15b5SRichard Lowe void
hold_file_descriptor()447*101e15b5SRichard Lowe hold_file_descriptor()
448*101e15b5SRichard Lowe {
449*101e15b5SRichard Lowe 	ASSERT(held_fd == -1);
450*101e15b5SRichard Lowe 
451*101e15b5SRichard Lowe 	if ((held_fd = open("/dev/null", O_RDONLY)) == -1)
452*101e15b5SRichard Lowe 		die(gettext("insufficient available file descriptors\n"));
453*101e15b5SRichard Lowe }
454*101e15b5SRichard Lowe 
455*101e15b5SRichard Lowe void
release_file_descriptor()456*101e15b5SRichard Lowe release_file_descriptor()
457*101e15b5SRichard Lowe {
458*101e15b5SRichard Lowe 	ASSERT(held_fd != -1);
459*101e15b5SRichard Lowe 
460*101e15b5SRichard Lowe 	(void) close(held_fd);
461*101e15b5SRichard Lowe 	held_fd = -1;
462*101e15b5SRichard Lowe }
463*101e15b5SRichard Lowe 
464*101e15b5SRichard Lowe void
copy_line_rec(const line_rec_t * a,line_rec_t * b)465*101e15b5SRichard Lowe copy_line_rec(const line_rec_t *a, line_rec_t *b)
466*101e15b5SRichard Lowe {
467*101e15b5SRichard Lowe 	(void) memcpy(b, a, sizeof (line_rec_t));
468*101e15b5SRichard Lowe }
469*101e15b5SRichard Lowe 
470*101e15b5SRichard Lowe void
trip_eof(FILE * f)471*101e15b5SRichard Lowe trip_eof(FILE *f)
472*101e15b5SRichard Lowe {
473*101e15b5SRichard Lowe 	if (feof(f))
474*101e15b5SRichard Lowe 		return;
475*101e15b5SRichard Lowe 
476*101e15b5SRichard Lowe 	(void) ungetc(fgetc(f), f);
477*101e15b5SRichard Lowe }
478*101e15b5SRichard Lowe 
479*101e15b5SRichard Lowe /*
480*101e15b5SRichard Lowe  * int cxwrite(int, char *, size_t)
481*101e15b5SRichard Lowe  *
482*101e15b5SRichard Lowe  * Overview
483*101e15b5SRichard Lowe  *   cxwrite() implements a buffered version of fwrite(ptr, nbytes, 1, .) on
484*101e15b5SRichard Lowe  *   file descriptors.  It returns -1 in the case that the write() fails to
485*101e15b5SRichard Lowe  *   write the current buffer contents.  cxwrite() must be flushed before being
486*101e15b5SRichard Lowe  *   applied to a new file descriptor.
487*101e15b5SRichard Lowe  *
488*101e15b5SRichard Lowe  * Return values
489*101e15b5SRichard Lowe  *   0 on success, -1 on error.
490*101e15b5SRichard Lowe  */
491*101e15b5SRichard Lowe int
cxwrite(int fd,char * ptr,size_t nbytes)492*101e15b5SRichard Lowe cxwrite(int fd, char *ptr, size_t nbytes)
493*101e15b5SRichard Lowe {
494*101e15b5SRichard Lowe 	static char buffer[XBUFFER_SIZE];
495*101e15b5SRichard Lowe 	static size_t offset = 0;
496*101e15b5SRichard Lowe 	size_t mbytes;
497*101e15b5SRichard Lowe 
498*101e15b5SRichard Lowe 	if (ptr == NULL) {
499*101e15b5SRichard Lowe 		errno = 0;
500*101e15b5SRichard Lowe 		while (offset -= write(fd, buffer, offset)) {
501*101e15b5SRichard Lowe 			if (errno)
502*101e15b5SRichard Lowe 				break;
503*101e15b5SRichard Lowe 		}
504*101e15b5SRichard Lowe 
505*101e15b5SRichard Lowe 		if (offset)
506*101e15b5SRichard Lowe 			return (-1);
507*101e15b5SRichard Lowe 
508*101e15b5SRichard Lowe 		return (0);
509*101e15b5SRichard Lowe 	}
510*101e15b5SRichard Lowe 
511*101e15b5SRichard Lowe 	while (nbytes != 0) {
512*101e15b5SRichard Lowe 		if (offset + nbytes > XBUFFER_SIZE)
513*101e15b5SRichard Lowe 			mbytes = XBUFFER_SIZE - offset;
514*101e15b5SRichard Lowe 		else
515*101e15b5SRichard Lowe 			mbytes = nbytes;
516*101e15b5SRichard Lowe 
517*101e15b5SRichard Lowe 		(void) memcpy(buffer + offset, ptr, mbytes);
518*101e15b5SRichard Lowe 		nbytes -= mbytes;
519*101e15b5SRichard Lowe 		offset += mbytes;
520*101e15b5SRichard Lowe 		ptr += mbytes;
521*101e15b5SRichard Lowe 
522*101e15b5SRichard Lowe 		if (nbytes) {
523*101e15b5SRichard Lowe 			errno = 0;
524*101e15b5SRichard Lowe 			while (offset -= write(fd, buffer, offset)) {
525*101e15b5SRichard Lowe 				if (errno)
526*101e15b5SRichard Lowe 					break;
527*101e15b5SRichard Lowe 			}
528*101e15b5SRichard Lowe 
529*101e15b5SRichard Lowe 			if (offset)
530*101e15b5SRichard Lowe 				return (-1);
531*101e15b5SRichard Lowe 		}
532*101e15b5SRichard Lowe 	}
533*101e15b5SRichard Lowe 
534*101e15b5SRichard Lowe 	return (0);
535*101e15b5SRichard Lowe }
536*101e15b5SRichard Lowe 
537*101e15b5SRichard Lowe /*
538*101e15b5SRichard Lowe  * int wxwrite(int, wchar_t *)
539*101e15b5SRichard Lowe  *
540*101e15b5SRichard Lowe  * Overview
541*101e15b5SRichard Lowe  *   wxwrite() implements a buffered write() function for null-terminated wide
542*101e15b5SRichard Lowe  *   character buffers with similar calling semantics to cxwrite().  It returns
543*101e15b5SRichard Lowe  *   -1 in the case that it fails to write the current buffer contents.
544*101e15b5SRichard Lowe  *   wxwrite() must be flushed before being applied to a new file descriptor.
545*101e15b5SRichard Lowe  *
546*101e15b5SRichard Lowe  * Return values
547*101e15b5SRichard Lowe  *   0 on success, -1 on error.
548*101e15b5SRichard Lowe  */
549*101e15b5SRichard Lowe int
wxwrite(int fd,wchar_t * ptr)550*101e15b5SRichard Lowe wxwrite(int fd, wchar_t *ptr)
551*101e15b5SRichard Lowe {
552*101e15b5SRichard Lowe 	static char *convert_buffer;
553*101e15b5SRichard Lowe 	static size_t convert_bufsize = 1024;
554*101e15b5SRichard Lowe 	size_t req_bufsize;
555*101e15b5SRichard Lowe 
556*101e15b5SRichard Lowe 	if (ptr == NULL)
557*101e15b5SRichard Lowe 		return (cxwrite(fd, NULL, 0));
558*101e15b5SRichard Lowe 
559*101e15b5SRichard Lowe 	if (convert_buffer == NULL)
560*101e15b5SRichard Lowe 		convert_buffer = safe_realloc(NULL, convert_bufsize);
561*101e15b5SRichard Lowe 	/*
562*101e15b5SRichard Lowe 	 * We use wcstombs(NULL, ., .) to verify that we have an adequate
563*101e15b5SRichard Lowe 	 * buffer size for the conversion.  Since this buffer was converted into
564*101e15b5SRichard Lowe 	 * wide character format earlier, we can safely assume that the buffer
565*101e15b5SRichard Lowe 	 * can be converted back to the external multibyte form.
566*101e15b5SRichard Lowe 	 */
567*101e15b5SRichard Lowe 	req_bufsize = wcstombs(NULL, ptr, convert_bufsize);
568*101e15b5SRichard Lowe 	if (req_bufsize > convert_bufsize) {
569*101e15b5SRichard Lowe 		convert_bufsize = req_bufsize + 1;
570*101e15b5SRichard Lowe 		convert_buffer = safe_realloc(convert_buffer, convert_bufsize);
571*101e15b5SRichard Lowe 	}
572*101e15b5SRichard Lowe 
573*101e15b5SRichard Lowe 	(void) wcstombs(convert_buffer, ptr, convert_bufsize);
574*101e15b5SRichard Lowe 
575*101e15b5SRichard Lowe 	return (cxwrite(fd, convert_buffer, req_bufsize));
576*101e15b5SRichard Lowe }
577*101e15b5SRichard Lowe 
578*101e15b5SRichard Lowe int
xstreql(const char * a,const char * b)579*101e15b5SRichard Lowe xstreql(const char *a, const char *b)
580*101e15b5SRichard Lowe {
581*101e15b5SRichard Lowe 	return (strcmp(a, b) == 0);
582*101e15b5SRichard Lowe }
583*101e15b5SRichard Lowe 
584*101e15b5SRichard Lowe int
xstrneql(const char * a,const char * b,const size_t l)585*101e15b5SRichard Lowe xstrneql(const char *a, const char *b, const size_t l)
586*101e15b5SRichard Lowe {
587*101e15b5SRichard Lowe 	return (strncmp(a, b, l) == 0);
588*101e15b5SRichard Lowe }
589*101e15b5SRichard Lowe 
590*101e15b5SRichard Lowe char *
xstrnchr(const char * S,const int c,const size_t n)591*101e15b5SRichard Lowe xstrnchr(const char *S, const int c, const size_t n)
592*101e15b5SRichard Lowe {
593*101e15b5SRichard Lowe 	const char	*eS = S + n;
594*101e15b5SRichard Lowe 
595*101e15b5SRichard Lowe 	do {
596*101e15b5SRichard Lowe 		if (*S == (char)c)
597*101e15b5SRichard Lowe 			return ((char *)S);
598*101e15b5SRichard Lowe 	} while (++S < eS);
599*101e15b5SRichard Lowe 
600*101e15b5SRichard Lowe 	return (NULL);
601*101e15b5SRichard Lowe }
602*101e15b5SRichard Lowe 
603*101e15b5SRichard Lowe void
xstrninv(char * s,ssize_t start,ssize_t length)604*101e15b5SRichard Lowe xstrninv(char *s, ssize_t start, ssize_t length)
605*101e15b5SRichard Lowe {
606*101e15b5SRichard Lowe 	ssize_t i;
607*101e15b5SRichard Lowe 
608*101e15b5SRichard Lowe 	for (i = start; i < start + length; i++)
609*101e15b5SRichard Lowe 		s[i] = UCHAR_MAX - s[i];
610*101e15b5SRichard Lowe }
611*101e15b5SRichard Lowe 
612*101e15b5SRichard Lowe int
xwcsneql(const wchar_t * a,const wchar_t * b,const size_t length)613*101e15b5SRichard Lowe xwcsneql(const wchar_t *a, const wchar_t *b, const size_t length)
614*101e15b5SRichard Lowe {
615*101e15b5SRichard Lowe 	return (wcsncmp(a, b, length) == 0);
616*101e15b5SRichard Lowe }
617*101e15b5SRichard Lowe 
618*101e15b5SRichard Lowe wchar_t *
xwsnchr(const wchar_t * ws,const wint_t wc,const size_t n)619*101e15b5SRichard Lowe xwsnchr(const wchar_t *ws, const wint_t wc, const size_t n)
620*101e15b5SRichard Lowe {
621*101e15b5SRichard Lowe 	const wchar_t	*ews = ws + n;
622*101e15b5SRichard Lowe 
623*101e15b5SRichard Lowe 	do {
624*101e15b5SRichard Lowe 		if (*ws == (wchar_t)wc)
625*101e15b5SRichard Lowe 			return ((wchar_t *)ws);
626*101e15b5SRichard Lowe 	} while (++ws < ews);
627*101e15b5SRichard Lowe 
628*101e15b5SRichard Lowe 	return (NULL);
629*101e15b5SRichard Lowe }
630*101e15b5SRichard Lowe 
631*101e15b5SRichard Lowe void
xwcsninv(wchar_t * s,ssize_t start,ssize_t length)632*101e15b5SRichard Lowe xwcsninv(wchar_t *s, ssize_t start, ssize_t length)
633*101e15b5SRichard Lowe {
634*101e15b5SRichard Lowe 	ssize_t	i;
635*101e15b5SRichard Lowe 
636*101e15b5SRichard Lowe 	for (i = start; i < start + length; i++)
637*101e15b5SRichard Lowe 		s[i] = WCHAR_MAX - s[i];
638*101e15b5SRichard Lowe }
639*101e15b5SRichard Lowe 
640*101e15b5SRichard Lowe #ifdef _LITTLE_ENDIAN
641*101e15b5SRichard Lowe void
xwcsntomsb(wchar_t * s,ssize_t length)642*101e15b5SRichard Lowe xwcsntomsb(wchar_t *s, ssize_t length)
643*101e15b5SRichard Lowe {
644*101e15b5SRichard Lowe 	ssize_t i;
645*101e15b5SRichard Lowe 
646*101e15b5SRichard Lowe 	ASSERT(sizeof (wchar_t) == sizeof (uint32_t));
647*101e15b5SRichard Lowe 
648*101e15b5SRichard Lowe 	for (i = 0; i < length; i++, s++) {
649*101e15b5SRichard Lowe 		char *t = (char *)s;
650*101e15b5SRichard Lowe 		char u;
651*101e15b5SRichard Lowe 
652*101e15b5SRichard Lowe 		u = *t;
653*101e15b5SRichard Lowe 		*t = *(t + 3);
654*101e15b5SRichard Lowe 		*(t + 3) = u;
655*101e15b5SRichard Lowe 
656*101e15b5SRichard Lowe 		u = *(t + 1);
657*101e15b5SRichard Lowe 		*(t + 1) = *(t + 2);
658*101e15b5SRichard Lowe 		*(t + 2) = u;
659*101e15b5SRichard Lowe 	}
660*101e15b5SRichard Lowe }
661*101e15b5SRichard Lowe #endif /* _LITTLE_ENDIAN */
662*101e15b5SRichard Lowe 
663*101e15b5SRichard Lowe wchar_t *
xmemwchar(wchar_t * s,wchar_t w,ssize_t length)664*101e15b5SRichard Lowe xmemwchar(wchar_t *s, wchar_t w, ssize_t length)
665*101e15b5SRichard Lowe {
666*101e15b5SRichard Lowe 	ssize_t i = length;
667*101e15b5SRichard Lowe 
668*101e15b5SRichard Lowe 	while (--i > 0) {
669*101e15b5SRichard Lowe 		if (*s == w)
670*101e15b5SRichard Lowe 			return (s);
671*101e15b5SRichard Lowe 		s++;
672*101e15b5SRichard Lowe 	}
673*101e15b5SRichard Lowe 
674*101e15b5SRichard Lowe 	return (NULL);
675*101e15b5SRichard Lowe }
676*101e15b5SRichard Lowe 
677*101e15b5SRichard Lowe void
xcp(char * dst,char * src,off_t size)678*101e15b5SRichard Lowe xcp(char *dst, char *src, off_t size)
679*101e15b5SRichard Lowe {
680*101e15b5SRichard Lowe 	int fd_in, fd_out;
681*101e15b5SRichard Lowe 	void *mm_in;
682*101e15b5SRichard Lowe 	size_t chunksize = 2 * MEGABYTE;
683*101e15b5SRichard Lowe 	int i;
684*101e15b5SRichard Lowe 	ssize_t nchunks = size / chunksize;
685*101e15b5SRichard Lowe 	ssize_t lastchunk = size % chunksize;
686*101e15b5SRichard Lowe 
687*101e15b5SRichard Lowe 	if (dst == NULL || src == NULL)
688*101e15b5SRichard Lowe 		return;
689*101e15b5SRichard Lowe 
690*101e15b5SRichard Lowe 	if ((fd_in = open(src, O_RDONLY)) < 0)
691*101e15b5SRichard Lowe 		die(EMSG_OPEN, src);
692*101e15b5SRichard Lowe 	if ((fd_out = open(dst, O_RDWR | O_CREAT | O_TRUNC, OUTPUT_MODE)) < 0)
693*101e15b5SRichard Lowe 		die(EMSG_OPEN, dst);
694*101e15b5SRichard Lowe 
695*101e15b5SRichard Lowe 	for (i = 0; i < nchunks; i++) {
696*101e15b5SRichard Lowe 		if ((mm_in = mmap(0, chunksize, PROT_READ, MAP_SHARED, fd_in,
697*101e15b5SRichard Lowe 		    i * chunksize)) == MAP_FAILED)
698*101e15b5SRichard Lowe 			die(EMSG_MMAP, src);
699*101e15b5SRichard Lowe 
700*101e15b5SRichard Lowe 		if (write(fd_out, mm_in, chunksize) != chunksize)
701*101e15b5SRichard Lowe 			die(EMSG_WRITE, dst);
702*101e15b5SRichard Lowe 
703*101e15b5SRichard Lowe 		(void) munmap(mm_in, chunksize);
704*101e15b5SRichard Lowe 	}
705*101e15b5SRichard Lowe 
706*101e15b5SRichard Lowe 	if (lastchunk) {
707*101e15b5SRichard Lowe 		if ((mm_in = mmap(0, lastchunk, PROT_READ, MAP_SHARED, fd_in,
708*101e15b5SRichard Lowe 		    nchunks * chunksize)) == MAP_FAILED)
709*101e15b5SRichard Lowe 			die(EMSG_MMAP, src);
710*101e15b5SRichard Lowe 
711*101e15b5SRichard Lowe 		if (write(fd_out, mm_in, lastchunk) != lastchunk)
712*101e15b5SRichard Lowe 			die(EMSG_WRITE, dst);
713*101e15b5SRichard Lowe 
714*101e15b5SRichard Lowe 		(void) munmap(mm_in, lastchunk);
715*101e15b5SRichard Lowe 	}
716*101e15b5SRichard Lowe 
717*101e15b5SRichard Lowe 	(void) close(fd_in);
718*101e15b5SRichard Lowe 
719*101e15b5SRichard Lowe 	if (close(fd_out) == -1)
720*101e15b5SRichard Lowe 		die(EMSG_CLOSE, dst);
721*101e15b5SRichard Lowe }
722*101e15b5SRichard Lowe 
723*101e15b5SRichard Lowe /*PRINTFLIKE1*/
724*101e15b5SRichard Lowe void
warn(const char * format,...)725*101e15b5SRichard Lowe warn(const char *format, ...)
726*101e15b5SRichard Lowe {
727*101e15b5SRichard Lowe 	int err = errno;
728*101e15b5SRichard Lowe 	va_list alist;
729*101e15b5SRichard Lowe 
730*101e15b5SRichard Lowe 	if (pname != NULL)
731*101e15b5SRichard Lowe 		(void) fprintf(stderr, gettext(PNAME_FMT), pname);
732*101e15b5SRichard Lowe 
733*101e15b5SRichard Lowe 	va_start(alist, format);
734*101e15b5SRichard Lowe 	(void) vfprintf(stderr, format, alist);
735*101e15b5SRichard Lowe 	va_end(alist);
736*101e15b5SRichard Lowe 
737*101e15b5SRichard Lowe 	if (strrchr(format, '\n') == NULL)
738*101e15b5SRichard Lowe 		(void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err));
739*101e15b5SRichard Lowe }
740*101e15b5SRichard Lowe 
741*101e15b5SRichard Lowe /*PRINTFLIKE1*/
742*101e15b5SRichard Lowe void
die(const char * format,...)743*101e15b5SRichard Lowe die(const char *format, ...)
744*101e15b5SRichard Lowe {
745*101e15b5SRichard Lowe 	int err = errno;
746*101e15b5SRichard Lowe 	va_list alist;
747*101e15b5SRichard Lowe 
748*101e15b5SRichard Lowe 	if (pname != NULL)
749*101e15b5SRichard Lowe 		(void) fprintf(stderr, gettext(PNAME_FMT), pname);
750*101e15b5SRichard Lowe 
751*101e15b5SRichard Lowe 	va_start(alist, format);
752*101e15b5SRichard Lowe 	(void) vfprintf(stderr, format, alist);
753*101e15b5SRichard Lowe 	va_end(alist);
754*101e15b5SRichard Lowe 
755*101e15b5SRichard Lowe 	if (strrchr(format, '\n') == NULL)
756*101e15b5SRichard Lowe 		(void) fprintf(stderr, gettext(ERRNO_FMT), strerror(err));
757*101e15b5SRichard Lowe 
758*101e15b5SRichard Lowe 	exit(E_ERROR);
759*101e15b5SRichard Lowe }
760*101e15b5SRichard Lowe 
761*101e15b5SRichard Lowe #ifdef DEBUG
762*101e15b5SRichard Lowe /*
763*101e15b5SRichard Lowe  * pprintc() is called only by xdump().
764*101e15b5SRichard Lowe  */
765*101e15b5SRichard Lowe #define	BYTES_PER_LINE	16
766*101e15b5SRichard Lowe static void
pprintc(FILE * fp,char c)767*101e15b5SRichard Lowe pprintc(FILE *fp, char c)
768*101e15b5SRichard Lowe {
769*101e15b5SRichard Lowe 	if (isspace((uchar_t)c))
770*101e15b5SRichard Lowe 		(void) fprintf(fp, " ");
771*101e15b5SRichard Lowe 	else if (isprint((uchar_t)c))
772*101e15b5SRichard Lowe 		(void) fprintf(fp, "%c", c);
773*101e15b5SRichard Lowe 	else
774*101e15b5SRichard Lowe 		(void) fprintf(fp, ".");
775*101e15b5SRichard Lowe }
776*101e15b5SRichard Lowe 
777*101e15b5SRichard Lowe static void
pprintwc(FILE * fp,wchar_t c)778*101e15b5SRichard Lowe pprintwc(FILE *fp, wchar_t c)
779*101e15b5SRichard Lowe {
780*101e15b5SRichard Lowe 	if (iswspace(c))
781*101e15b5SRichard Lowe 		(void) fprintf(fp, " ");
782*101e15b5SRichard Lowe 	else if (iswprint(c))
783*101e15b5SRichard Lowe 		(void) fprintf(fp, "%wc", c);
784*101e15b5SRichard Lowe 	else
785*101e15b5SRichard Lowe 		(void) fprintf(fp, ".");
786*101e15b5SRichard Lowe }
787*101e15b5SRichard Lowe 
788*101e15b5SRichard Lowe /*
789*101e15b5SRichard Lowe  * xdump() is used only for debugging purposes.
790*101e15b5SRichard Lowe  */
791*101e15b5SRichard Lowe void
xdump(FILE * fp,uchar_t * buf,size_t bufsize,int wide)792*101e15b5SRichard Lowe xdump(FILE *fp, uchar_t *buf, size_t bufsize, int wide)
793*101e15b5SRichard Lowe {
794*101e15b5SRichard Lowe 	int i;
795*101e15b5SRichard Lowe 	size_t nc = 0;
796*101e15b5SRichard Lowe 	uchar_t d[BYTES_PER_LINE];
797*101e15b5SRichard Lowe 
798*101e15b5SRichard Lowe 	for (; nc < bufsize; buf++) {
799*101e15b5SRichard Lowe 		d[nc % BYTES_PER_LINE] = *buf;
800*101e15b5SRichard Lowe 		if (nc % BYTES_PER_LINE == 0) {
801*101e15b5SRichard Lowe 			(void) fprintf(fp, "%08x:", nc);
802*101e15b5SRichard Lowe 		}
803*101e15b5SRichard Lowe 		(void) fprintf(fp, " %02x", *buf);
804*101e15b5SRichard Lowe 		nc++;
805*101e15b5SRichard Lowe 		if (nc % BYTES_PER_LINE == 0) {
806*101e15b5SRichard Lowe 			(void) fprintf(fp, "  ");
807*101e15b5SRichard Lowe 			if (wide) {
808*101e15b5SRichard Lowe 				for (i = 0; i < BYTES_PER_LINE;
809*101e15b5SRichard Lowe 				    i += sizeof (wchar_t))
810*101e15b5SRichard Lowe 					pprintwc(fp, *(wchar_t *)(d + i));
811*101e15b5SRichard Lowe 			} else {
812*101e15b5SRichard Lowe 				for (i = 0; i < BYTES_PER_LINE; i++)
813*101e15b5SRichard Lowe 					pprintc(fp, d[i]);
814*101e15b5SRichard Lowe 			}
815*101e15b5SRichard Lowe 			(void) fprintf(fp, "\n");
816*101e15b5SRichard Lowe 		}
817*101e15b5SRichard Lowe 	}
818*101e15b5SRichard Lowe 
819*101e15b5SRichard Lowe 	for (i = nc % BYTES_PER_LINE; i < BYTES_PER_LINE; i++)
820*101e15b5SRichard Lowe 		(void) fprintf(fp, "   ");
821*101e15b5SRichard Lowe 
822*101e15b5SRichard Lowe 	(void) fprintf(fp, "  ");
823*101e15b5SRichard Lowe 
824*101e15b5SRichard Lowe 	if (wide) {
825*101e15b5SRichard Lowe 		for (i = 0; i < nc % BYTES_PER_LINE; i += sizeof (wchar_t))
826*101e15b5SRichard Lowe 			pprintwc(fp, *(wchar_t *)(d + i));
827*101e15b5SRichard Lowe 	} else {
828*101e15b5SRichard Lowe 		for (i = 0; i < nc % BYTES_PER_LINE; i++)
829*101e15b5SRichard Lowe 			pprintc(fp, d[i]);
830*101e15b5SRichard Lowe 	}
831*101e15b5SRichard Lowe 
832*101e15b5SRichard Lowe 	(void) fprintf(fp, "\n");
833*101e15b5SRichard Lowe }
834*101e15b5SRichard Lowe #endif /* DEBUG */
835