xref: /aosp_15_r20/external/selinux/libsepol/src/util.c (revision 2d543d20722ada2425b5bdab9d0d1d29470e7bba)
1*2d543d20SAndroid Build Coastguard Worker /* Authors: Joshua Brindle <[email protected]>
2*2d543d20SAndroid Build Coastguard Worker  * 	    Jason Tang <[email protected]>
3*2d543d20SAndroid Build Coastguard Worker  *
4*2d543d20SAndroid Build Coastguard Worker  * Copyright (C) 2005-2006 Tresys Technology, LLC
5*2d543d20SAndroid Build Coastguard Worker  *
6*2d543d20SAndroid Build Coastguard Worker  *  This library is free software; you can redistribute it and/or
7*2d543d20SAndroid Build Coastguard Worker  *  modify it under the terms of the GNU Lesser General Public
8*2d543d20SAndroid Build Coastguard Worker  *  License as published by the Free Software Foundation; either
9*2d543d20SAndroid Build Coastguard Worker  *  version 2.1 of the License, or (at your option) any later version.
10*2d543d20SAndroid Build Coastguard Worker  *
11*2d543d20SAndroid Build Coastguard Worker  *  This library is distributed in the hope that it will be useful,
12*2d543d20SAndroid Build Coastguard Worker  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13*2d543d20SAndroid Build Coastguard Worker  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*2d543d20SAndroid Build Coastguard Worker  *  Lesser General Public License for more details.
15*2d543d20SAndroid Build Coastguard Worker  *
16*2d543d20SAndroid Build Coastguard Worker  *  You should have received a copy of the GNU Lesser General Public
17*2d543d20SAndroid Build Coastguard Worker  *  License along with this library; if not, write to the Free Software
18*2d543d20SAndroid Build Coastguard Worker  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19*2d543d20SAndroid Build Coastguard Worker  */
20*2d543d20SAndroid Build Coastguard Worker 
21*2d543d20SAndroid Build Coastguard Worker #include <assert.h>
22*2d543d20SAndroid Build Coastguard Worker #include <ctype.h>
23*2d543d20SAndroid Build Coastguard Worker #include <stdarg.h>
24*2d543d20SAndroid Build Coastguard Worker #include <stdio.h>
25*2d543d20SAndroid Build Coastguard Worker #include <stdlib.h>
26*2d543d20SAndroid Build Coastguard Worker 
27*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/flask_types.h>
28*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/policydb.h>
29*2d543d20SAndroid Build Coastguard Worker #include <sepol/policydb/util.h>
30*2d543d20SAndroid Build Coastguard Worker 
31*2d543d20SAndroid Build Coastguard Worker #include "private.h"
32*2d543d20SAndroid Build Coastguard Worker 
33*2d543d20SAndroid Build Coastguard Worker struct val_to_name {
34*2d543d20SAndroid Build Coastguard Worker 	unsigned int val;
35*2d543d20SAndroid Build Coastguard Worker 	const char *name;
36*2d543d20SAndroid Build Coastguard Worker };
37*2d543d20SAndroid Build Coastguard Worker 
38*2d543d20SAndroid Build Coastguard Worker /* Add an unsigned integer to a dynamically reallocated array.  *cnt
39*2d543d20SAndroid Build Coastguard Worker  * is a reference pointer to the number of values already within array
40*2d543d20SAndroid Build Coastguard Worker  * *a; it will be incremented upon successfully appending i.  If *a is
41*2d543d20SAndroid Build Coastguard Worker  * NULL then this function will create a new array (*cnt is reset to
42*2d543d20SAndroid Build Coastguard Worker  * 0).  Return 0 on success, -1 on out of memory. */
add_i_to_a(uint32_t i,uint32_t * cnt,uint32_t ** a)43*2d543d20SAndroid Build Coastguard Worker int add_i_to_a(uint32_t i, uint32_t * cnt, uint32_t ** a)
44*2d543d20SAndroid Build Coastguard Worker {
45*2d543d20SAndroid Build Coastguard Worker 	uint32_t *new;
46*2d543d20SAndroid Build Coastguard Worker 
47*2d543d20SAndroid Build Coastguard Worker 	if (cnt == NULL || *cnt == UINT32_MAX || a == NULL)
48*2d543d20SAndroid Build Coastguard Worker 		return -1;
49*2d543d20SAndroid Build Coastguard Worker 
50*2d543d20SAndroid Build Coastguard Worker 	/* FIX ME: This is not very elegant! We use an array that we
51*2d543d20SAndroid Build Coastguard Worker 	 * grow as new uint32_t are added to an array.  But rather
52*2d543d20SAndroid Build Coastguard Worker 	 * than be smart about it, for now we realloc() the array each
53*2d543d20SAndroid Build Coastguard Worker 	 * time a new uint32_t is added! */
54*2d543d20SAndroid Build Coastguard Worker 	if (*a != NULL)
55*2d543d20SAndroid Build Coastguard Worker 		new = (uint32_t *) reallocarray(*a, *cnt + 1, sizeof(uint32_t));
56*2d543d20SAndroid Build Coastguard Worker 	else {			/* empty list */
57*2d543d20SAndroid Build Coastguard Worker 
58*2d543d20SAndroid Build Coastguard Worker 		*cnt = 0;
59*2d543d20SAndroid Build Coastguard Worker 		new = (uint32_t *) malloc(sizeof(uint32_t));
60*2d543d20SAndroid Build Coastguard Worker 	}
61*2d543d20SAndroid Build Coastguard Worker 	if (new == NULL) {
62*2d543d20SAndroid Build Coastguard Worker 		return -1;
63*2d543d20SAndroid Build Coastguard Worker 	}
64*2d543d20SAndroid Build Coastguard Worker 	new[*cnt] = i;
65*2d543d20SAndroid Build Coastguard Worker 	(*cnt)++;
66*2d543d20SAndroid Build Coastguard Worker 	*a = new;
67*2d543d20SAndroid Build Coastguard Worker 	return 0;
68*2d543d20SAndroid Build Coastguard Worker }
69*2d543d20SAndroid Build Coastguard Worker 
perm_name(hashtab_key_t key,hashtab_datum_t datum,void * data)70*2d543d20SAndroid Build Coastguard Worker static int perm_name(hashtab_key_t key, hashtab_datum_t datum, void *data)
71*2d543d20SAndroid Build Coastguard Worker {
72*2d543d20SAndroid Build Coastguard Worker 	struct val_to_name *v = data;
73*2d543d20SAndroid Build Coastguard Worker 	perm_datum_t *perdatum;
74*2d543d20SAndroid Build Coastguard Worker 
75*2d543d20SAndroid Build Coastguard Worker 	perdatum = (perm_datum_t *) datum;
76*2d543d20SAndroid Build Coastguard Worker 
77*2d543d20SAndroid Build Coastguard Worker 	if (v->val == perdatum->s.value) {
78*2d543d20SAndroid Build Coastguard Worker 		v->name = key;
79*2d543d20SAndroid Build Coastguard Worker 		return 1;
80*2d543d20SAndroid Build Coastguard Worker 	}
81*2d543d20SAndroid Build Coastguard Worker 
82*2d543d20SAndroid Build Coastguard Worker 	return 0;
83*2d543d20SAndroid Build Coastguard Worker }
84*2d543d20SAndroid Build Coastguard Worker 
sepol_av_to_string(const policydb_t * policydbp,sepol_security_class_t tclass,sepol_access_vector_t av)85*2d543d20SAndroid Build Coastguard Worker char *sepol_av_to_string(const policydb_t *policydbp, sepol_security_class_t tclass,
86*2d543d20SAndroid Build Coastguard Worker 			 sepol_access_vector_t av)
87*2d543d20SAndroid Build Coastguard Worker {
88*2d543d20SAndroid Build Coastguard Worker 	struct val_to_name v;
89*2d543d20SAndroid Build Coastguard Worker 	const class_datum_t *cladatum = policydbp->class_val_to_struct[tclass - 1];
90*2d543d20SAndroid Build Coastguard Worker 	uint32_t i;
91*2d543d20SAndroid Build Coastguard Worker 	int rc;
92*2d543d20SAndroid Build Coastguard Worker 	char *buffer = NULL, *p;
93*2d543d20SAndroid Build Coastguard Worker 	int len;
94*2d543d20SAndroid Build Coastguard Worker 	size_t remaining, size = 64;
95*2d543d20SAndroid Build Coastguard Worker 
96*2d543d20SAndroid Build Coastguard Worker retry:
97*2d543d20SAndroid Build Coastguard Worker 	if (__builtin_mul_overflow(size, 2, &size))
98*2d543d20SAndroid Build Coastguard Worker 		goto err;
99*2d543d20SAndroid Build Coastguard Worker 	p = realloc(buffer, size);
100*2d543d20SAndroid Build Coastguard Worker 	if (!p)
101*2d543d20SAndroid Build Coastguard Worker 		goto err;
102*2d543d20SAndroid Build Coastguard Worker 	*p = '\0'; /* Just in case there are no permissions */
103*2d543d20SAndroid Build Coastguard Worker 	buffer = p;
104*2d543d20SAndroid Build Coastguard Worker 	remaining = size;
105*2d543d20SAndroid Build Coastguard Worker 
106*2d543d20SAndroid Build Coastguard Worker 	for (i = 0; i < cladatum->permissions.nprim; i++) {
107*2d543d20SAndroid Build Coastguard Worker 		if (av & (UINT32_C(1) << i)) {
108*2d543d20SAndroid Build Coastguard Worker 			v.val = i + 1;
109*2d543d20SAndroid Build Coastguard Worker 			rc = hashtab_map(cladatum->permissions.table,
110*2d543d20SAndroid Build Coastguard Worker 					 perm_name, &v);
111*2d543d20SAndroid Build Coastguard Worker 			if (!rc && cladatum->comdatum) {
112*2d543d20SAndroid Build Coastguard Worker 				rc = hashtab_map(cladatum->comdatum->
113*2d543d20SAndroid Build Coastguard Worker 						 permissions.table, perm_name,
114*2d543d20SAndroid Build Coastguard Worker 						 &v);
115*2d543d20SAndroid Build Coastguard Worker 			}
116*2d543d20SAndroid Build Coastguard Worker 			if (rc == 1) {
117*2d543d20SAndroid Build Coastguard Worker 				len = snprintf(p, remaining, " %s", v.name);
118*2d543d20SAndroid Build Coastguard Worker 				if (len < 0)
119*2d543d20SAndroid Build Coastguard Worker 					goto err;
120*2d543d20SAndroid Build Coastguard Worker 				if ((size_t) len >= remaining)
121*2d543d20SAndroid Build Coastguard Worker 					goto retry;
122*2d543d20SAndroid Build Coastguard Worker 				p += len;
123*2d543d20SAndroid Build Coastguard Worker 				remaining -= len;
124*2d543d20SAndroid Build Coastguard Worker 			}
125*2d543d20SAndroid Build Coastguard Worker 		}
126*2d543d20SAndroid Build Coastguard Worker 	}
127*2d543d20SAndroid Build Coastguard Worker 
128*2d543d20SAndroid Build Coastguard Worker 	return buffer;
129*2d543d20SAndroid Build Coastguard Worker 
130*2d543d20SAndroid Build Coastguard Worker err:
131*2d543d20SAndroid Build Coastguard Worker 	free(buffer);
132*2d543d20SAndroid Build Coastguard Worker 	return NULL;
133*2d543d20SAndroid Build Coastguard Worker }
134*2d543d20SAndroid Build Coastguard Worker 
135*2d543d20SAndroid Build Coastguard Worker #define next_bit_in_range(i, p) (((i) + 1 < sizeof(p)*8) && xperm_test(((i) + 1), p))
136*2d543d20SAndroid Build Coastguard Worker 
sepol_extended_perms_to_string(const avtab_extended_perms_t * xperms)137*2d543d20SAndroid Build Coastguard Worker char *sepol_extended_perms_to_string(const avtab_extended_perms_t *xperms)
138*2d543d20SAndroid Build Coastguard Worker {
139*2d543d20SAndroid Build Coastguard Worker 	uint16_t value;
140*2d543d20SAndroid Build Coastguard Worker 	uint16_t low_bit;
141*2d543d20SAndroid Build Coastguard Worker 	uint16_t low_value;
142*2d543d20SAndroid Build Coastguard Worker 	unsigned int bit;
143*2d543d20SAndroid Build Coastguard Worker 	unsigned int in_range;
144*2d543d20SAndroid Build Coastguard Worker 	char *buffer = NULL, *p;
145*2d543d20SAndroid Build Coastguard Worker 	int len;
146*2d543d20SAndroid Build Coastguard Worker 	size_t remaining, size = 128;
147*2d543d20SAndroid Build Coastguard Worker 
148*2d543d20SAndroid Build Coastguard Worker 	if ((xperms->specified != AVTAB_XPERMS_IOCTLFUNCTION)
149*2d543d20SAndroid Build Coastguard Worker 		&& (xperms->specified != AVTAB_XPERMS_IOCTLDRIVER)
150*2d543d20SAndroid Build Coastguard Worker 		&& (xperms->specified != AVTAB_XPERMS_NLMSG))
151*2d543d20SAndroid Build Coastguard Worker 		return NULL;
152*2d543d20SAndroid Build Coastguard Worker 
153*2d543d20SAndroid Build Coastguard Worker retry:
154*2d543d20SAndroid Build Coastguard Worker 	if (__builtin_mul_overflow(size, 2, &size))
155*2d543d20SAndroid Build Coastguard Worker 		goto err;
156*2d543d20SAndroid Build Coastguard Worker 	p = realloc(buffer, size);
157*2d543d20SAndroid Build Coastguard Worker 	if (!p)
158*2d543d20SAndroid Build Coastguard Worker 		goto err;
159*2d543d20SAndroid Build Coastguard Worker 	buffer = p;
160*2d543d20SAndroid Build Coastguard Worker 	remaining = size;
161*2d543d20SAndroid Build Coastguard Worker 
162*2d543d20SAndroid Build Coastguard Worker 	if ((xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION)
163*2d543d20SAndroid Build Coastguard Worker 		|| (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER)) {
164*2d543d20SAndroid Build Coastguard Worker 		len = snprintf(p, remaining, "ioctl { ");
165*2d543d20SAndroid Build Coastguard Worker 	} else {
166*2d543d20SAndroid Build Coastguard Worker 		len = snprintf(p, remaining, "nlmsg { ");
167*2d543d20SAndroid Build Coastguard Worker 	}
168*2d543d20SAndroid Build Coastguard Worker 	if (len < 0 || (size_t)len >= remaining)
169*2d543d20SAndroid Build Coastguard Worker 		goto err;
170*2d543d20SAndroid Build Coastguard Worker 	p += len;
171*2d543d20SAndroid Build Coastguard Worker 	remaining -= len;
172*2d543d20SAndroid Build Coastguard Worker 
173*2d543d20SAndroid Build Coastguard Worker 	in_range = 0;
174*2d543d20SAndroid Build Coastguard Worker 	for (bit = 0; bit < sizeof(xperms->perms)*8; bit++) {
175*2d543d20SAndroid Build Coastguard Worker 		if (!xperm_test(bit, xperms->perms))
176*2d543d20SAndroid Build Coastguard Worker 			continue;
177*2d543d20SAndroid Build Coastguard Worker 
178*2d543d20SAndroid Build Coastguard Worker 		if (in_range && next_bit_in_range(bit, xperms->perms)) {
179*2d543d20SAndroid Build Coastguard Worker 			/* continue until high value found */
180*2d543d20SAndroid Build Coastguard Worker 			continue;
181*2d543d20SAndroid Build Coastguard Worker 		} else if (next_bit_in_range(bit, xperms->perms)) {
182*2d543d20SAndroid Build Coastguard Worker 			/* low value */
183*2d543d20SAndroid Build Coastguard Worker 			low_bit = bit;
184*2d543d20SAndroid Build Coastguard Worker 			in_range = 1;
185*2d543d20SAndroid Build Coastguard Worker 			continue;
186*2d543d20SAndroid Build Coastguard Worker 		}
187*2d543d20SAndroid Build Coastguard Worker 
188*2d543d20SAndroid Build Coastguard Worker 		if (xperms->specified == AVTAB_XPERMS_IOCTLFUNCTION || xperms->specified == AVTAB_XPERMS_NLMSG) {
189*2d543d20SAndroid Build Coastguard Worker 			value = xperms->driver<<8 | bit;
190*2d543d20SAndroid Build Coastguard Worker 			if (in_range) {
191*2d543d20SAndroid Build Coastguard Worker 				low_value = xperms->driver<<8 | low_bit;
192*2d543d20SAndroid Build Coastguard Worker 				len = snprintf(p, remaining, "0x%hx-0x%hx ", low_value, value);
193*2d543d20SAndroid Build Coastguard Worker 			} else {
194*2d543d20SAndroid Build Coastguard Worker 				len = snprintf(p, remaining, "0x%hx ", value);
195*2d543d20SAndroid Build Coastguard Worker 			}
196*2d543d20SAndroid Build Coastguard Worker 		} else if (xperms->specified == AVTAB_XPERMS_IOCTLDRIVER) {
197*2d543d20SAndroid Build Coastguard Worker 			value = bit << 8;
198*2d543d20SAndroid Build Coastguard Worker 			if (in_range) {
199*2d543d20SAndroid Build Coastguard Worker 				low_value = low_bit << 8;
200*2d543d20SAndroid Build Coastguard Worker 				len = snprintf(p, remaining, "0x%hx-0x%hx ", low_value, (uint16_t) (value|0xff));
201*2d543d20SAndroid Build Coastguard Worker 			} else {
202*2d543d20SAndroid Build Coastguard Worker 				len = snprintf(p, remaining, "0x%hx-0x%hx ", value, (uint16_t) (value|0xff));
203*2d543d20SAndroid Build Coastguard Worker 			}
204*2d543d20SAndroid Build Coastguard Worker 
205*2d543d20SAndroid Build Coastguard Worker 		}
206*2d543d20SAndroid Build Coastguard Worker 
207*2d543d20SAndroid Build Coastguard Worker 		if (len < 0)
208*2d543d20SAndroid Build Coastguard Worker 			goto err;
209*2d543d20SAndroid Build Coastguard Worker 		if ((size_t) len >= remaining)
210*2d543d20SAndroid Build Coastguard Worker 			goto retry;
211*2d543d20SAndroid Build Coastguard Worker 
212*2d543d20SAndroid Build Coastguard Worker 		p += len;
213*2d543d20SAndroid Build Coastguard Worker 		remaining -= len;
214*2d543d20SAndroid Build Coastguard Worker 		if (in_range)
215*2d543d20SAndroid Build Coastguard Worker 			in_range = 0;
216*2d543d20SAndroid Build Coastguard Worker 	}
217*2d543d20SAndroid Build Coastguard Worker 
218*2d543d20SAndroid Build Coastguard Worker 	len = snprintf(p, remaining, "}");
219*2d543d20SAndroid Build Coastguard Worker 	if (len < 0)
220*2d543d20SAndroid Build Coastguard Worker 		goto err;
221*2d543d20SAndroid Build Coastguard Worker 	if ((size_t) len >= remaining)
222*2d543d20SAndroid Build Coastguard Worker 		goto retry;
223*2d543d20SAndroid Build Coastguard Worker 
224*2d543d20SAndroid Build Coastguard Worker 	return buffer;
225*2d543d20SAndroid Build Coastguard Worker 
226*2d543d20SAndroid Build Coastguard Worker err:
227*2d543d20SAndroid Build Coastguard Worker 	free(buffer);
228*2d543d20SAndroid Build Coastguard Worker 	return NULL;
229*2d543d20SAndroid Build Coastguard Worker }
230*2d543d20SAndroid Build Coastguard Worker 
231*2d543d20SAndroid Build Coastguard Worker /*
232*2d543d20SAndroid Build Coastguard Worker  * The tokenize and tokenize_str functions may be used to
233*2d543d20SAndroid Build Coastguard Worker  * replace sscanf to read tokens from buffers.
234*2d543d20SAndroid Build Coastguard Worker  */
235*2d543d20SAndroid Build Coastguard Worker 
236*2d543d20SAndroid Build Coastguard Worker /* Read a token from a buffer */
tokenize_str(char delim,char ** str,const char ** ptr,size_t * len)237*2d543d20SAndroid Build Coastguard Worker static inline int tokenize_str(char delim, char **str, const char **ptr, size_t *len)
238*2d543d20SAndroid Build Coastguard Worker {
239*2d543d20SAndroid Build Coastguard Worker 	const char *tmp_buf = *ptr;
240*2d543d20SAndroid Build Coastguard Worker 	*str = NULL;
241*2d543d20SAndroid Build Coastguard Worker 
242*2d543d20SAndroid Build Coastguard Worker 	while (**ptr != '\0') {
243*2d543d20SAndroid Build Coastguard Worker 		if (isspace(delim) && isspace(**ptr)) {
244*2d543d20SAndroid Build Coastguard Worker 			(*ptr)++;
245*2d543d20SAndroid Build Coastguard Worker 			break;
246*2d543d20SAndroid Build Coastguard Worker 		} else if (!isspace(delim) && **ptr == delim) {
247*2d543d20SAndroid Build Coastguard Worker 			(*ptr)++;
248*2d543d20SAndroid Build Coastguard Worker 			break;
249*2d543d20SAndroid Build Coastguard Worker 		}
250*2d543d20SAndroid Build Coastguard Worker 
251*2d543d20SAndroid Build Coastguard Worker 		(*ptr)++;
252*2d543d20SAndroid Build Coastguard Worker 	}
253*2d543d20SAndroid Build Coastguard Worker 
254*2d543d20SAndroid Build Coastguard Worker 	*len = *ptr - tmp_buf;
255*2d543d20SAndroid Build Coastguard Worker 	/* If the end of the string has not been reached, this will ensure the
256*2d543d20SAndroid Build Coastguard Worker 	 * delimiter is not included when returning the token.
257*2d543d20SAndroid Build Coastguard Worker 	 */
258*2d543d20SAndroid Build Coastguard Worker 	if (**ptr != '\0') {
259*2d543d20SAndroid Build Coastguard Worker 		(*len)--;
260*2d543d20SAndroid Build Coastguard Worker 	}
261*2d543d20SAndroid Build Coastguard Worker 
262*2d543d20SAndroid Build Coastguard Worker 	*str = strndup(tmp_buf, *len);
263*2d543d20SAndroid Build Coastguard Worker 	if (!*str) {
264*2d543d20SAndroid Build Coastguard Worker 		return -1;
265*2d543d20SAndroid Build Coastguard Worker 	}
266*2d543d20SAndroid Build Coastguard Worker 
267*2d543d20SAndroid Build Coastguard Worker 	/* Squash spaces if the delimiter is a whitespace character */
268*2d543d20SAndroid Build Coastguard Worker 	while (**ptr != '\0' && isspace(delim) && isspace(**ptr)) {
269*2d543d20SAndroid Build Coastguard Worker 		(*ptr)++;
270*2d543d20SAndroid Build Coastguard Worker 	}
271*2d543d20SAndroid Build Coastguard Worker 
272*2d543d20SAndroid Build Coastguard Worker 	return 0;
273*2d543d20SAndroid Build Coastguard Worker }
274*2d543d20SAndroid Build Coastguard Worker 
275*2d543d20SAndroid Build Coastguard Worker /*
276*2d543d20SAndroid Build Coastguard Worker  * line_buf - Buffer containing string to tokenize.
277*2d543d20SAndroid Build Coastguard Worker  * delim - The delimiter used to tokenize line_buf. A whitespace delimiter will
278*2d543d20SAndroid Build Coastguard Worker  *	    be tokenized using isspace().
279*2d543d20SAndroid Build Coastguard Worker  * num_args - The number of parameter entries to process.
280*2d543d20SAndroid Build Coastguard Worker  * ...      - A 'char **' for each parameter.
281*2d543d20SAndroid Build Coastguard Worker  * returns  - The number of items processed.
282*2d543d20SAndroid Build Coastguard Worker  *
283*2d543d20SAndroid Build Coastguard Worker  * This function calls tokenize_str() to do the actual string processing. The
284*2d543d20SAndroid Build Coastguard Worker  * caller is responsible for calling free() on each additional argument. The
285*2d543d20SAndroid Build Coastguard Worker  * function will not tokenize more than num_args and the last argument will
286*2d543d20SAndroid Build Coastguard Worker  * contain the remaining content of line_buf. If the delimiter is any whitespace
287*2d543d20SAndroid Build Coastguard Worker  * character, then all whitespace will be squashed.
288*2d543d20SAndroid Build Coastguard Worker  */
tokenize(const char * line_buf,char delim,int num_args,...)289*2d543d20SAndroid Build Coastguard Worker int tokenize(const char *line_buf, char delim, int num_args, ...)
290*2d543d20SAndroid Build Coastguard Worker {
291*2d543d20SAndroid Build Coastguard Worker 	char **arg;
292*2d543d20SAndroid Build Coastguard Worker 	const char *buf_p;
293*2d543d20SAndroid Build Coastguard Worker 	int rc, items;
294*2d543d20SAndroid Build Coastguard Worker 	size_t arg_len = 0;
295*2d543d20SAndroid Build Coastguard Worker 	va_list ap;
296*2d543d20SAndroid Build Coastguard Worker 
297*2d543d20SAndroid Build Coastguard Worker 	buf_p = line_buf;
298*2d543d20SAndroid Build Coastguard Worker 
299*2d543d20SAndroid Build Coastguard Worker 	/* Process the arguments */
300*2d543d20SAndroid Build Coastguard Worker 	va_start(ap, num_args);
301*2d543d20SAndroid Build Coastguard Worker 
302*2d543d20SAndroid Build Coastguard Worker 	for (items = 0; items < num_args && *buf_p != '\0'; items++) {
303*2d543d20SAndroid Build Coastguard Worker 		arg = va_arg(ap, char **);
304*2d543d20SAndroid Build Coastguard Worker 
305*2d543d20SAndroid Build Coastguard Worker 		/* Save the remainder of the string in arg */
306*2d543d20SAndroid Build Coastguard Worker 		if (items == num_args - 1) {
307*2d543d20SAndroid Build Coastguard Worker 			*arg = strdup(buf_p);
308*2d543d20SAndroid Build Coastguard Worker 			if (*arg == NULL) {
309*2d543d20SAndroid Build Coastguard Worker 				goto exit;
310*2d543d20SAndroid Build Coastguard Worker 			}
311*2d543d20SAndroid Build Coastguard Worker 
312*2d543d20SAndroid Build Coastguard Worker 			continue;
313*2d543d20SAndroid Build Coastguard Worker 		}
314*2d543d20SAndroid Build Coastguard Worker 
315*2d543d20SAndroid Build Coastguard Worker 		rc = tokenize_str(delim, arg, &buf_p, &arg_len);
316*2d543d20SAndroid Build Coastguard Worker 		if (rc < 0) {
317*2d543d20SAndroid Build Coastguard Worker 			goto exit;
318*2d543d20SAndroid Build Coastguard Worker 		}
319*2d543d20SAndroid Build Coastguard Worker 	}
320*2d543d20SAndroid Build Coastguard Worker 
321*2d543d20SAndroid Build Coastguard Worker exit:
322*2d543d20SAndroid Build Coastguard Worker 	va_end(ap);
323*2d543d20SAndroid Build Coastguard Worker 	return items;
324*2d543d20SAndroid Build Coastguard Worker }
325