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