• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2008 Kristian Høgsberg
3  * Copyright © 2013-2015 Red Hat, Inc.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22  * DEALINGS IN THE SOFTWARE.
23  */
24 
25 #pragma once
26 
27 #include "config.h"
28 
29 #include <assert.h>
30 #include <ctype.h>
31 #include <errno.h>
32 #include <limits.h>
33 #include <math.h>
34 #include <string.h>
35 #include <stdio.h>
36 #include <stdbool.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #ifdef HAVE_LOCALE_H
40 #include <locale.h>
41 #endif
42 #ifdef HAVE_XLOCALE_H
43 #include <xlocale.h>
44 #endif
45 
46 #include "util-macros.h"
47 
48 static inline bool
streq(const char * str1,const char * str2)49 streq(const char *str1, const char *str2)
50 {
51 	/* one NULL, one not NULL is always false */
52 	if (str1 && str2)
53 		return strcmp(str1, str2) == 0;
54 	return str1 == str2;
55 }
56 
57 static inline bool
strneq(const char * str1,const char * str2,int n)58 strneq(const char *str1, const char *str2, int n)
59 {
60 	/* one NULL, one not NULL is always false */
61 	if (str1 && str2)
62 		return strncmp(str1, str2, n) == 0;
63 	return str1 == str2;
64 }
65 
66 static inline void *
zalloc(size_t size)67 zalloc(size_t size)
68 {
69 	void *p;
70 
71 	/* We never need to alloc anything more than 1,5 MB so we can assume
72 	 * if we ever get above that something's going wrong */
73 	if (size > 1536 * 1024)
74 		assert(!"bug: internal malloc size limit exceeded");
75 
76 	p = calloc(1, size);
77 	if (!p)
78 		abort();
79 
80 	return p;
81 }
82 
83 /**
84  * strdup guaranteed to succeed. If the input string is NULL, the output
85  * string is NULL. If the input string is a string pointer, we strdup or
86  * abort on failure.
87  */
88 static inline char*
safe_strdup(const char * str)89 safe_strdup(const char *str)
90 {
91 	char *s;
92 
93 	if (!str)
94 		return NULL;
95 
96 	s = strdup(str);
97 	if (!s)
98 		abort();
99 	return s;
100 }
101 
102 /**
103  * Simple wrapper for asprintf that ensures the passed in-pointer is set
104  * to NULL upon error.
105  * The standard asprintf() call does not guarantee the passed in pointer
106  * will be NULL'ed upon failure, whereas this wrapper does.
107  *
108  * @param strp pointer to set to newly allocated string.
109  * This pointer should be passed to free() to release when done.
110  * @param fmt the format string to use for printing.
111  * @return The number of bytes printed (excluding the null byte terminator)
112  * upon success or -1 upon failure. In the case of failure the pointer is set
113  * to NULL.
114  */
115 __attribute__ ((format (printf, 2, 3)))
116 static inline int
xasprintf(char ** strp,const char * fmt,...)117 xasprintf(char **strp, const char *fmt, ...)
118 {
119 	int rc = 0;
120 	va_list args;
121 
122 	va_start(args, fmt);
123 	rc = vasprintf(strp, fmt, args);
124 	va_end(args);
125 	if ((rc == -1) && strp)
126 		*strp = NULL;
127 
128 	return rc;
129 }
130 
131 __attribute__ ((format (printf, 2, 0)))
132 static inline int
xvasprintf(char ** strp,const char * fmt,va_list args)133 xvasprintf(char **strp, const char *fmt, va_list args)
134 {
135 	int rc = 0;
136 	rc = vasprintf(strp, fmt, args);
137 	if ((rc == -1) && strp)
138 		*strp = NULL;
139 
140 	return rc;
141 }
142 
143 static inline bool
safe_atoi_base(const char * str,int * val,int base)144 safe_atoi_base(const char *str, int *val, int base)
145 {
146 	char *endptr;
147 	long v;
148 
149 	assert(base == 10 || base == 16 || base == 8);
150 
151 	errno = 0;
152 	v = strtol(str, &endptr, base);
153 	if (errno > 0)
154 		return false;
155 	if (str == endptr)
156 		return false;
157 	if (*str != '\0' && *endptr != '\0')
158 		return false;
159 
160 	if (v > INT_MAX || v < INT_MIN)
161 		return false;
162 
163 	*val = v;
164 	return true;
165 }
166 
167 static inline bool
safe_atoi(const char * str,int * val)168 safe_atoi(const char *str, int *val)
169 {
170 	return safe_atoi_base(str, val, 10);
171 }
172 
173 static inline bool
safe_atou_base(const char * str,unsigned int * val,int base)174 safe_atou_base(const char *str, unsigned int *val, int base)
175 {
176 	char *endptr;
177 	unsigned long v;
178 
179 	assert(base == 10 || base == 16 || base == 8);
180 
181 	errno = 0;
182 	v = strtoul(str, &endptr, base);
183 	if (errno > 0)
184 		return false;
185 	if (str == endptr)
186 		return false;
187 	if (*str != '\0' && *endptr != '\0')
188 		return false;
189 
190 	if ((long)v < 0)
191 		return false;
192 
193 	*val = v;
194 	return true;
195 }
196 
197 static inline bool
safe_atou(const char * str,unsigned int * val)198 safe_atou(const char *str, unsigned int *val)
199 {
200 	return safe_atou_base(str, val, 10);
201 }
202 
203 static inline bool
safe_atod(const char * str,double * val)204 safe_atod(const char *str, double *val)
205 {
206 	char *endptr;
207 	double v;
208 #ifdef HAVE_LOCALE_H
209 	locale_t c_locale;
210 #endif
211 	size_t slen = strlen(str);
212 
213 	/* We don't have a use-case where we want to accept hex for a double
214 	 * or any of the other values strtod can parse */
215 	for (size_t i = 0; i < slen; i++) {
216 		char c = str[i];
217 
218 		if (isdigit(c))
219 		       continue;
220 		switch(c) {
221 		case '+':
222 		case '-':
223 		case '.':
224 			break;
225 		default:
226 			return false;
227 		}
228 	}
229 
230 #ifdef HAVE_LOCALE_H
231 	/* Create a "C" locale to force strtod to use '.' as separator */
232 	c_locale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0);
233 	if (c_locale == (locale_t)0)
234 		return false;
235 
236 	errno = 0;
237 	v = strtod_l(str, &endptr, c_locale);
238 	freelocale(c_locale);
239 #else
240 	/* No locale support in provided libc, assume it already uses '.' */
241 	errno = 0;
242 	v = strtod(str, &endptr);
243 #endif
244 	if (errno > 0)
245 		return false;
246 	if (str == endptr)
247 		return false;
248 	if (*str != '\0' && *endptr != '\0')
249 		return false;
250 	if (v != 0.0 && !isnormal(v))
251 		return false;
252 
253 	*val = v;
254 	return true;
255 }
256 
257 char **strv_from_argv(int argc, char **argv);
258 char **strv_from_string(const char *in, const char *separator);
259 char *strv_join(char **strv, const char *joiner);
260 
261 static inline void
strv_free(char ** strv)262 strv_free(char **strv) {
263 	char **s = strv;
264 
265 	if (!strv)
266 		return;
267 
268 	while (*s != NULL) {
269 		free(*s);
270 		*s = (char*)0x1; /* detect use-after-free */
271 		s++;
272 	}
273 
274 	free (strv);
275 }
276 
277 struct key_value_str{
278 	char *key;
279 	char *value;
280 };
281 
282 struct key_value_double {
283 	double key;
284 	double value;
285 };
286 
287 static inline ssize_t
kv_double_from_string(const char * string,const char * pair_separator,const char * kv_separator,struct key_value_double ** result_out)288 kv_double_from_string(const char *string,
289 		      const char *pair_separator,
290 		      const char *kv_separator,
291 		      struct key_value_double **result_out)
292 
293 {
294 	char **pairs;
295 	char **pair;
296 	struct key_value_double *result = NULL;
297 	ssize_t npairs = 0;
298 	unsigned int idx = 0;
299 
300 	if (!pair_separator || pair_separator[0] == '\0' ||
301 	    !kv_separator || kv_separator[0] == '\0')
302 		return -1;
303 
304 	pairs = strv_from_string(string, pair_separator);
305 	if (!pairs)
306 		return -1;
307 
308 	for (pair = pairs; *pair; pair++)
309 		npairs++;
310 
311 	if (npairs == 0)
312 		goto error;
313 
314 	result = zalloc(npairs * sizeof *result);
315 
316 	for (pair = pairs; *pair; pair++) {
317 		char **kv = strv_from_string(*pair, kv_separator);
318 		double k, v;
319 
320 		if (!kv || !kv[0] || !kv[1] || kv[2] ||
321 		    !safe_atod(kv[0], &k) ||
322 		    !safe_atod(kv[1], &v)) {
323 			strv_free(kv);
324 			goto error;
325 		}
326 
327 		result[idx].key = k;
328 		result[idx].value = v;
329 		idx++;
330 
331 		strv_free(kv);
332 	}
333 
334 	strv_free(pairs);
335 
336 	*result_out = result;
337 
338 	return npairs;
339 
340 error:
341 	strv_free(pairs);
342 	free(result);
343 	return -1;
344 }
345 
346 /**
347  * Strip any of the characters in what from the beginning and end of the
348  * input string.
349  *
350  * @return a newly allocated string with none of "what" at the beginning or
351  * end of string
352  */
353 static inline char *
strstrip(const char * input,const char * what)354 strstrip(const char *input, const char *what)
355 {
356 	char *str, *last;
357 
358 	str = safe_strdup(&input[strspn(input, what)]);
359 
360 	last = str;
361 
362 	for (char *c = str; *c != '\0'; c++) {
363 		if (!strchr(what, *c))
364 			last = c + 1;
365 	}
366 
367 	*last = '\0';
368 
369 	return str;
370 }
371 
372 /**
373  * Return true if str ends in suffix, false otherwise. If the suffix is the
374  * empty string, strendswith() always returns false.
375  */
376 static inline bool
strendswith(const char * str,const char * suffix)377 strendswith(const char *str, const char *suffix)
378 {
379 	size_t slen = strlen(str);
380 	size_t suffixlen = strlen(suffix);
381 	size_t offset;
382 
383 	if (slen == 0 || suffixlen == 0 || suffixlen > slen)
384 		return false;
385 
386 	offset = slen - suffixlen;
387 	return strneq(&str[offset], suffix, suffixlen);
388 }
389 
390 static inline bool
strstartswith(const char * str,const char * prefix)391 strstartswith(const char *str, const char *prefix)
392 {
393 	size_t prefixlen = strlen(prefix);
394 
395 	return prefixlen > 0 ? strneq(str, prefix, strlen(prefix)) : false;
396 }
397 
398 const char *
399 safe_basename(const char *filename);
400 
401 char *
402 trunkname(const char *filename);
403 
404 /**
405  * Return a copy of str with all % converted to %% to make the string
406  * acceptable as printf format.
407  */
408 static inline char *
str_sanitize(const char * str)409 str_sanitize(const char *str)
410 {
411 	if (!str)
412 		return NULL;
413 
414 	if (!strchr(str, '%'))
415 		return strdup(str);
416 
417 	size_t slen = min(strlen(str), 512);
418 	char *sanitized = zalloc(2 * slen + 1);
419 	const char *src = str;
420 	char *dst = sanitized;
421 
422 	for (size_t i = 0; i < slen; i++) {
423 		if (*src == '%')
424 			*dst++ = '%';
425 		*dst++ = *src++;
426 	}
427 	*dst = '\0';
428 
429 	return sanitized;
430 }
431