xref: /onnv-gate/usr/src/cmd/lvm/metassist/common/volume_string.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include "volume_string.h"
30*0Sstevel@tonic-gate 
31*0Sstevel@tonic-gate #include <ctype.h>
32*0Sstevel@tonic-gate #include <errno.h>
33*0Sstevel@tonic-gate #include <libintl.h>
34*0Sstevel@tonic-gate #include <math.h>
35*0Sstevel@tonic-gate #include <stdarg.h>
36*0Sstevel@tonic-gate #include <stdio.h>
37*0Sstevel@tonic-gate #include <stdlib.h>
38*0Sstevel@tonic-gate #include <string.h>
39*0Sstevel@tonic-gate #include "volume_error.h"
40*0Sstevel@tonic-gate #include "volume_output.h"
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate /*
43*0Sstevel@tonic-gate  * ******************************************************************
44*0Sstevel@tonic-gate  *
45*0Sstevel@tonic-gate  * Function prototypes
46*0Sstevel@tonic-gate  *
47*0Sstevel@tonic-gate  * ******************************************************************
48*0Sstevel@tonic-gate  */
49*0Sstevel@tonic-gate 
50*0Sstevel@tonic-gate static void *append_to_pointer_array(void **array, void *pointer);
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate /*
53*0Sstevel@tonic-gate  * ******************************************************************
54*0Sstevel@tonic-gate  *
55*0Sstevel@tonic-gate  * Data
56*0Sstevel@tonic-gate  *
57*0Sstevel@tonic-gate  * ******************************************************************
58*0Sstevel@tonic-gate  */
59*0Sstevel@tonic-gate 
60*0Sstevel@tonic-gate /* All-inclusive valid size units */
61*0Sstevel@tonic-gate units_t universal_units[] = {
62*0Sstevel@tonic-gate 	{"BLOCKS", BYTES_PER_BLOCK},
63*0Sstevel@tonic-gate 	{"KB", BYTES_PER_KILOBYTE},
64*0Sstevel@tonic-gate 	{"MB", BYTES_PER_MEGABYTE},
65*0Sstevel@tonic-gate 	{"GB", BYTES_PER_GIGABYTE},
66*0Sstevel@tonic-gate 	{"TB", BYTES_PER_TERABYTE},
67*0Sstevel@tonic-gate 	{NULL, 0}
68*0Sstevel@tonic-gate };
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate /*
71*0Sstevel@tonic-gate  * ******************************************************************
72*0Sstevel@tonic-gate  *
73*0Sstevel@tonic-gate  * External functions
74*0Sstevel@tonic-gate  *
75*0Sstevel@tonic-gate  * ******************************************************************
76*0Sstevel@tonic-gate  */
77*0Sstevel@tonic-gate 
78*0Sstevel@tonic-gate /*
79*0Sstevel@tonic-gate  * Concatenates a list of strings.  The result must be free()d.
80*0Sstevel@tonic-gate  *
81*0Sstevel@tonic-gate  * @param       numargs
82*0Sstevel@tonic-gate  *              The number of strings to concatenate.
83*0Sstevel@tonic-gate  *
84*0Sstevel@tonic-gate  * @param       ...
85*0Sstevel@tonic-gate  *              The strings (type char *) to concatenate.
86*0Sstevel@tonic-gate  *
87*0Sstevel@tonic-gate  * @return      the concatenated string
88*0Sstevel@tonic-gate  *              if succesful
89*0Sstevel@tonic-gate  *
90*0Sstevel@tonic-gate  * @return      NULL
91*0Sstevel@tonic-gate  *              if memory could not be allocated
92*0Sstevel@tonic-gate  */
93*0Sstevel@tonic-gate char *
stralloccat(int numargs,...)94*0Sstevel@tonic-gate stralloccat(
95*0Sstevel@tonic-gate 	int numargs,
96*0Sstevel@tonic-gate 	...)
97*0Sstevel@tonic-gate {
98*0Sstevel@tonic-gate 	va_list vl;
99*0Sstevel@tonic-gate 	int i;
100*0Sstevel@tonic-gate 	int len = 1;
101*0Sstevel@tonic-gate 	char *cat;
102*0Sstevel@tonic-gate 
103*0Sstevel@tonic-gate 	/* Determine length of concatenated string */
104*0Sstevel@tonic-gate 	va_start(vl, numargs);
105*0Sstevel@tonic-gate 	for (i = 0; i < numargs; i++) {
106*0Sstevel@tonic-gate 	    char *str = va_arg(vl, char *);
107*0Sstevel@tonic-gate 	    if (str != NULL) {
108*0Sstevel@tonic-gate 		len += strlen(str);
109*0Sstevel@tonic-gate 	    }
110*0Sstevel@tonic-gate 	}
111*0Sstevel@tonic-gate 	va_end(vl);
112*0Sstevel@tonic-gate 
113*0Sstevel@tonic-gate 	/* Allocate memory for concatenation plus a trailing NULL */
114*0Sstevel@tonic-gate 	cat = (char *)calloc(1, len * sizeof (char));
115*0Sstevel@tonic-gate 
116*0Sstevel@tonic-gate 	if (cat == NULL) {
117*0Sstevel@tonic-gate 	    return (NULL);
118*0Sstevel@tonic-gate 	}
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	/* Concatenate strings */
121*0Sstevel@tonic-gate 	va_start(vl, numargs);
122*0Sstevel@tonic-gate 	for (i = 0; i < numargs; i++) {
123*0Sstevel@tonic-gate 	    char *str = va_arg(vl, char *);
124*0Sstevel@tonic-gate 	    if (str != NULL) {
125*0Sstevel@tonic-gate 		strcat(cat, str);
126*0Sstevel@tonic-gate 	    }
127*0Sstevel@tonic-gate 	}
128*0Sstevel@tonic-gate 	va_end(vl);
129*0Sstevel@tonic-gate 
130*0Sstevel@tonic-gate 	return (cat);
131*0Sstevel@tonic-gate }
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate /*
134*0Sstevel@tonic-gate  * Convert the given string to a uint16_t, verifying that the value
135*0Sstevel@tonic-gate  * does not exceed the lower or upper bounds of a uint16_t.
136*0Sstevel@tonic-gate  *
137*0Sstevel@tonic-gate  * @param       str
138*0Sstevel@tonic-gate  *              the string to convert
139*0Sstevel@tonic-gate  *
140*0Sstevel@tonic-gate  * @param       num
141*0Sstevel@tonic-gate  *              the addr of the uint16_t
142*0Sstevel@tonic-gate  *
143*0Sstevel@tonic-gate  * @return      0
144*0Sstevel@tonic-gate  *              if the given string was converted to a uint16_t
145*0Sstevel@tonic-gate  *
146*0Sstevel@tonic-gate  * @return      -1
147*0Sstevel@tonic-gate  *              if the string could could not be converted to a number
148*0Sstevel@tonic-gate  *
149*0Sstevel@tonic-gate  * @return      -2
150*0Sstevel@tonic-gate  *              if the converted number exceeds the lower or upper
151*0Sstevel@tonic-gate  *              bounds of a uint16_t
152*0Sstevel@tonic-gate  */
153*0Sstevel@tonic-gate int
str_to_uint16(char * str,uint16_t * num)154*0Sstevel@tonic-gate str_to_uint16(
155*0Sstevel@tonic-gate 	char *str,
156*0Sstevel@tonic-gate 	uint16_t *num)
157*0Sstevel@tonic-gate {
158*0Sstevel@tonic-gate 	long long lnum;
159*0Sstevel@tonic-gate 	int error = 0;
160*0Sstevel@tonic-gate 
161*0Sstevel@tonic-gate 	/* Convert string to long long */
162*0Sstevel@tonic-gate 	if (sscanf(str, "%lld", &lnum) != 1) {
163*0Sstevel@tonic-gate 	    error = -1;
164*0Sstevel@tonic-gate 	} else {
165*0Sstevel@tonic-gate 
166*0Sstevel@tonic-gate 		/*
167*0Sstevel@tonic-gate 		 * Verify that the long long value does not exceed the
168*0Sstevel@tonic-gate 		 * lower or upper bounds of a uint16_t
169*0Sstevel@tonic-gate 		 */
170*0Sstevel@tonic-gate 
171*0Sstevel@tonic-gate 	    /* Maximum value of uint16_t */
172*0Sstevel@tonic-gate 	    uint16_t max = (uint16_t)~0ULL;
173*0Sstevel@tonic-gate 
174*0Sstevel@tonic-gate 	    if (lnum < 0 || lnum > max) {
175*0Sstevel@tonic-gate 		error = -2;
176*0Sstevel@tonic-gate 	    } else {
177*0Sstevel@tonic-gate 		*num = lnum;
178*0Sstevel@tonic-gate 	    }
179*0Sstevel@tonic-gate 	}
180*0Sstevel@tonic-gate 
181*0Sstevel@tonic-gate 	return (error);
182*0Sstevel@tonic-gate }
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate /*
185*0Sstevel@tonic-gate  * Converts the given long long into a string.  This string must be
186*0Sstevel@tonic-gate  * freed.
187*0Sstevel@tonic-gate  *
188*0Sstevel@tonic-gate  * @param       num
189*0Sstevel@tonic-gate  *              the long long to convert
190*0Sstevel@tonic-gate  *
191*0Sstevel@tonic-gate  * @param       str
192*0Sstevel@tonic-gate  *              the addr of the string
193*0Sstevel@tonic-gate  *
194*0Sstevel@tonic-gate  * @return      0
195*0Sstevel@tonic-gate  *              if successful
196*0Sstevel@tonic-gate  *
197*0Sstevel@tonic-gate  * @return      ENOMEM
198*0Sstevel@tonic-gate  *              if the physical limits of the system are exceeded by
199*0Sstevel@tonic-gate  *              size bytes of memory which cannot be allocated
200*0Sstevel@tonic-gate  *
201*0Sstevel@tonic-gate  * @return      EAGAIN
202*0Sstevel@tonic-gate  *              if there is not enough memory available to allocate
203*0Sstevel@tonic-gate  *              size bytes of memory
204*0Sstevel@tonic-gate  */
205*0Sstevel@tonic-gate int
ll_to_str(long long num,char ** str)206*0Sstevel@tonic-gate ll_to_str(
207*0Sstevel@tonic-gate 	long long num,
208*0Sstevel@tonic-gate 	char **str)
209*0Sstevel@tonic-gate {
210*0Sstevel@tonic-gate 	int error = 0;
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate 	/* Allocate memory for the string */
213*0Sstevel@tonic-gate 	if ((*str = calloc(1, LONG_LONG_STR_SIZE * sizeof (char))) == NULL) {
214*0Sstevel@tonic-gate 	    error = errno;
215*0Sstevel@tonic-gate 	} else {
216*0Sstevel@tonic-gate 	    /* Convert the integer to a string */
217*0Sstevel@tonic-gate 	    snprintf(*str, LONG_LONG_STR_SIZE, "%lld", num);
218*0Sstevel@tonic-gate 	}
219*0Sstevel@tonic-gate 
220*0Sstevel@tonic-gate 	return (error);
221*0Sstevel@tonic-gate }
222*0Sstevel@tonic-gate 
223*0Sstevel@tonic-gate /*
224*0Sstevel@tonic-gate  * Convert a size specification to bytes.
225*0Sstevel@tonic-gate  *
226*0Sstevel@tonic-gate  * @param       str
227*0Sstevel@tonic-gate  *              a size specification strings of the form
228*0Sstevel@tonic-gate  *              <value><units>, where valid <units> are specified by
229*0Sstevel@tonic-gate  *              the units argument and <value> is the (floating-point)
230*0Sstevel@tonic-gate  *              multiplier of the units
231*0Sstevel@tonic-gate  *
232*0Sstevel@tonic-gate  * @param       bytes
233*0Sstevel@tonic-gate  *              RETURN: the result of converting the given size string
234*0Sstevel@tonic-gate  *              to bytes
235*0Sstevel@tonic-gate  *
236*0Sstevel@tonic-gate  * @return      0
237*0Sstevel@tonic-gate  *              if successful
238*0Sstevel@tonic-gate  *
239*0Sstevel@tonic-gate  * @return      non-zero
240*0Sstevel@tonic-gate  *              if an error occurred.  Use get_error_string() to
241*0Sstevel@tonic-gate  *              retrieve the associated error message.
242*0Sstevel@tonic-gate  */
243*0Sstevel@tonic-gate int
sizestr_to_bytes(char * str,uint64_t * bytes,units_t units[])244*0Sstevel@tonic-gate sizestr_to_bytes(
245*0Sstevel@tonic-gate 	char *str,
246*0Sstevel@tonic-gate 	uint64_t *bytes,
247*0Sstevel@tonic-gate 	units_t units[])
248*0Sstevel@tonic-gate {
249*0Sstevel@tonic-gate 	char *unit_str;
250*0Sstevel@tonic-gate 	long double d;
251*0Sstevel@tonic-gate 	int error = 0;
252*0Sstevel@tonic-gate 	int i;
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	/* Convert <value> string to double */
255*0Sstevel@tonic-gate 	if ((d = strtod(str, &unit_str)) == 0) {
256*0Sstevel@tonic-gate 	    volume_set_error(gettext("invalid size string: %s"), str);
257*0Sstevel@tonic-gate 	    error = -1;
258*0Sstevel@tonic-gate 	} else {
259*0Sstevel@tonic-gate 
260*0Sstevel@tonic-gate 	    /* Trim leading white space */
261*0Sstevel@tonic-gate 	    while (isspace(*unit_str) != 0) {
262*0Sstevel@tonic-gate 		++unit_str;
263*0Sstevel@tonic-gate 	    }
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 	    /* Convert to bytes based on <units> */
266*0Sstevel@tonic-gate 	    for (i = 0; units[i].unit_str != NULL; i++) {
267*0Sstevel@tonic-gate 		if (strcasecmp(unit_str, units[i].unit_str) == 0) {
268*0Sstevel@tonic-gate 		    d *= units[i].bytes_per_unit;
269*0Sstevel@tonic-gate 		    break;
270*0Sstevel@tonic-gate 		}
271*0Sstevel@tonic-gate 	    }
272*0Sstevel@tonic-gate 
273*0Sstevel@tonic-gate 	    /* Was a valid unit string found? */
274*0Sstevel@tonic-gate 	    if (units[i].unit_str == NULL) {
275*0Sstevel@tonic-gate 		volume_set_error(
276*0Sstevel@tonic-gate 		    gettext("missing or invalid units indicator in size: %s"),
277*0Sstevel@tonic-gate 		    str);
278*0Sstevel@tonic-gate 		error = -1;
279*0Sstevel@tonic-gate 	    }
280*0Sstevel@tonic-gate 	}
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate 	if (error) {
283*0Sstevel@tonic-gate 	    *bytes = 0;
284*0Sstevel@tonic-gate 	} else {
285*0Sstevel@tonic-gate 	    *bytes = (uint64_t)d;
286*0Sstevel@tonic-gate 	    oprintf(OUTPUT_DEBUG,
287*0Sstevel@tonic-gate 		gettext("converted \"%s\" to %llu bytes\n"), str, *bytes);
288*0Sstevel@tonic-gate 	}
289*0Sstevel@tonic-gate 
290*0Sstevel@tonic-gate 	return (error);
291*0Sstevel@tonic-gate }
292*0Sstevel@tonic-gate 
293*0Sstevel@tonic-gate /*
294*0Sstevel@tonic-gate  * Convert bytes to a size specification string.
295*0Sstevel@tonic-gate  *
296*0Sstevel@tonic-gate  * @param       bytes
297*0Sstevel@tonic-gate  *              the number of bytes
298*0Sstevel@tonic-gate  *
299*0Sstevel@tonic-gate  * @param       str
300*0Sstevel@tonic-gate  *              RETURN: a size specification strings of the form
301*0Sstevel@tonic-gate  *              <value><units>, where valid <units> are specified by
302*0Sstevel@tonic-gate  *              the units argument and <value> is the (floating-point)
303*0Sstevel@tonic-gate  *              multiplier of the units.  This string must be freed.
304*0Sstevel@tonic-gate  *
305*0Sstevel@tonic-gate  * @return      0
306*0Sstevel@tonic-gate  *              if successful
307*0Sstevel@tonic-gate  *
308*0Sstevel@tonic-gate  * @return      non-zero
309*0Sstevel@tonic-gate  *              if an error occurred.  Use get_error_string() to
310*0Sstevel@tonic-gate  *              retrieve the associated error message.
311*0Sstevel@tonic-gate  */
312*0Sstevel@tonic-gate int
bytes_to_sizestr(uint64_t bytes,char ** str,units_t units[],boolean_t round)313*0Sstevel@tonic-gate bytes_to_sizestr(
314*0Sstevel@tonic-gate 	uint64_t bytes,
315*0Sstevel@tonic-gate 	char **str,
316*0Sstevel@tonic-gate 	units_t units[],
317*0Sstevel@tonic-gate 	boolean_t round)
318*0Sstevel@tonic-gate {
319*0Sstevel@tonic-gate 	int i, len, error = 0;
320*0Sstevel@tonic-gate 	double value;
321*0Sstevel@tonic-gate 	const char *format;
322*0Sstevel@tonic-gate 	units_t use_units = units[0];
323*0Sstevel@tonic-gate 
324*0Sstevel@tonic-gate 	/* Determine the units to use */
325*0Sstevel@tonic-gate 	for (i = 0; units[i].unit_str != NULL; i++) {
326*0Sstevel@tonic-gate 	    if (bytes >= units[i].bytes_per_unit) {
327*0Sstevel@tonic-gate 		use_units = units[i];
328*0Sstevel@tonic-gate 	    }
329*0Sstevel@tonic-gate 	}
330*0Sstevel@tonic-gate 
331*0Sstevel@tonic-gate 	value = ((long double)bytes / use_units.bytes_per_unit);
332*0Sstevel@tonic-gate 
333*0Sstevel@tonic-gate 	/* Length of string plus trailing NULL */
334*0Sstevel@tonic-gate 	len = LONG_LONG_STR_SIZE + strlen(use_units.unit_str) + 1;
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	if (round) {
337*0Sstevel@tonic-gate 	    value = floor(value + 0.5F);
338*0Sstevel@tonic-gate 	    format = "%.0f%s";
339*0Sstevel@tonic-gate 	} else {
340*0Sstevel@tonic-gate 	    format = "%.2f%s";
341*0Sstevel@tonic-gate 	}
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	/* Append units to string */
344*0Sstevel@tonic-gate 	*str = calloc(1, len * sizeof (char));
345*0Sstevel@tonic-gate 	if (*str == NULL) {
346*0Sstevel@tonic-gate 	    error = errno;
347*0Sstevel@tonic-gate 	} else {
348*0Sstevel@tonic-gate 	    snprintf(*str, len, format, value, use_units.unit_str);
349*0Sstevel@tonic-gate 	}
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	return (error);
352*0Sstevel@tonic-gate }
353*0Sstevel@tonic-gate 
354*0Sstevel@tonic-gate /*
355*0Sstevel@tonic-gate  * Appends a copy of the given string to the given string array,
356*0Sstevel@tonic-gate  * ensuring that the last element in the array is NULL.  This array
357*0Sstevel@tonic-gate  * must be freed via free_string_array.
358*0Sstevel@tonic-gate  *
359*0Sstevel@tonic-gate  * Note when an error occurs and NULL is returned, array is not freed.
360*0Sstevel@tonic-gate  * Subsequently callers should save a pointer to the original array
361*0Sstevel@tonic-gate  * until success is verified.
362*0Sstevel@tonic-gate  *
363*0Sstevel@tonic-gate  * @param       array
364*0Sstevel@tonic-gate  *              the array to append to, or NULL to create a new array
365*0Sstevel@tonic-gate  *
366*0Sstevel@tonic-gate  * @param       str
367*0Sstevel@tonic-gate  *              the string to copy and add to the array
368*0Sstevel@tonic-gate  *
369*0Sstevel@tonic-gate  * @return      a pointer to the realloc'd (and possibly moved) array
370*0Sstevel@tonic-gate  *              if succesful
371*0Sstevel@tonic-gate  *
372*0Sstevel@tonic-gate  * @return      NULL
373*0Sstevel@tonic-gate  *              if unsuccesful
374*0Sstevel@tonic-gate  */
375*0Sstevel@tonic-gate char **
append_to_string_array(char ** array,char * str)376*0Sstevel@tonic-gate append_to_string_array(
377*0Sstevel@tonic-gate 	char **array,
378*0Sstevel@tonic-gate 	char *str)
379*0Sstevel@tonic-gate {
380*0Sstevel@tonic-gate 	char *copy = strdup(str);
381*0Sstevel@tonic-gate 
382*0Sstevel@tonic-gate 	if (copy == NULL) {
383*0Sstevel@tonic-gate 	    return (NULL);
384*0Sstevel@tonic-gate 	}
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate 	return ((char **)append_to_pointer_array((void **)array, copy));
387*0Sstevel@tonic-gate }
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate /*
390*0Sstevel@tonic-gate  * Frees each element of the given string array, then frees the array
391*0Sstevel@tonic-gate  * itself.
392*0Sstevel@tonic-gate  *
393*0Sstevel@tonic-gate  * @param       array
394*0Sstevel@tonic-gate  *              a NULL-terminated string array
395*0Sstevel@tonic-gate  */
396*0Sstevel@tonic-gate void
free_string_array(char ** array)397*0Sstevel@tonic-gate free_string_array(
398*0Sstevel@tonic-gate 	char **array)
399*0Sstevel@tonic-gate {
400*0Sstevel@tonic-gate 	int i;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	/* Free each available element */
403*0Sstevel@tonic-gate 	for (i = 0; array[i] != NULL; i++) {
404*0Sstevel@tonic-gate 	    free(array[i]);
405*0Sstevel@tonic-gate 	}
406*0Sstevel@tonic-gate 
407*0Sstevel@tonic-gate 	/* Free the array itself */
408*0Sstevel@tonic-gate 	free((void *)array);
409*0Sstevel@tonic-gate }
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate /*
412*0Sstevel@tonic-gate  * ******************************************************************
413*0Sstevel@tonic-gate  *
414*0Sstevel@tonic-gate  * Static functions
415*0Sstevel@tonic-gate  *
416*0Sstevel@tonic-gate  * ******************************************************************
417*0Sstevel@tonic-gate  */
418*0Sstevel@tonic-gate 
419*0Sstevel@tonic-gate /*
420*0Sstevel@tonic-gate  * Appends the given pointer to the given pointer array, ensuring that
421*0Sstevel@tonic-gate  * the last element in the array is NULL.
422*0Sstevel@tonic-gate  *
423*0Sstevel@tonic-gate  * Note when an error occurs and NULL is returned, array is not freed.
424*0Sstevel@tonic-gate  * Subsequently callers should save a pointer to the original array
425*0Sstevel@tonic-gate  * until success is verified.
426*0Sstevel@tonic-gate  *
427*0Sstevel@tonic-gate  * @param       array
428*0Sstevel@tonic-gate  *              the array to append to, or NULL to create a new array
429*0Sstevel@tonic-gate  *
430*0Sstevel@tonic-gate  * @param       pointer
431*0Sstevel@tonic-gate  *              the pointer to add to the array
432*0Sstevel@tonic-gate  *
433*0Sstevel@tonic-gate  * @return      a pointer to the realloc'd (and possibly moved) array
434*0Sstevel@tonic-gate  *              if succesful
435*0Sstevel@tonic-gate  *
436*0Sstevel@tonic-gate  * @return      NULL
437*0Sstevel@tonic-gate  *              if unsuccesful
438*0Sstevel@tonic-gate  */
439*0Sstevel@tonic-gate static void *
append_to_pointer_array(void ** array,void * pointer)440*0Sstevel@tonic-gate append_to_pointer_array(
441*0Sstevel@tonic-gate 	void **array,
442*0Sstevel@tonic-gate 	void *pointer)
443*0Sstevel@tonic-gate {
444*0Sstevel@tonic-gate 	void **newarray = NULL;
445*0Sstevel@tonic-gate 	int i = 0;
446*0Sstevel@tonic-gate 
447*0Sstevel@tonic-gate 	if (array != NULL) {
448*0Sstevel@tonic-gate 	    /* Count the elements currently in the array */
449*0Sstevel@tonic-gate 	    for (i = 0; array[i] != NULL; ++i);
450*0Sstevel@tonic-gate 	}
451*0Sstevel@tonic-gate 
452*0Sstevel@tonic-gate 	/* realloc, adding a slot for the new pointer */
453*0Sstevel@tonic-gate 	newarray = (void **)realloc(array, (i + 2) * sizeof (*array));
454*0Sstevel@tonic-gate 
455*0Sstevel@tonic-gate 	if (newarray != NULL) {
456*0Sstevel@tonic-gate 	    /* Append pointer and terminal NULL */
457*0Sstevel@tonic-gate 	    newarray[i] = pointer;
458*0Sstevel@tonic-gate 	    newarray[i+1] = NULL;
459*0Sstevel@tonic-gate 	}
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	return (newarray);
462*0Sstevel@tonic-gate }
463