]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/string_utils.c
string_utils: ensure that errno is set on return
[mirror_lxc.git] / src / lxc / string_utils.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
37ef15bb 2
d38dd64a
CB
3#ifndef _GNU_SOURCE
4#define _GNU_SOURCE 1
5#endif
37ef15bb
CB
6#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
7#include <ctype.h>
8#include <dirent.h>
9#include <errno.h>
10#include <fcntl.h>
11#include <grp.h>
12#include <inttypes.h>
13#include <libgen.h>
14#include <pthread.h>
c4a090be 15#include <stdarg.h>
37ef15bb
CB
16#include <stddef.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
37ef15bb
CB
20#include <sys/mman.h>
21#include <sys/mount.h>
22#include <sys/param.h>
23#include <sys/prctl.h>
24#include <sys/stat.h>
25#include <sys/types.h>
26#include <sys/wait.h>
d38dd64a 27#include <unistd.h>
37ef15bb 28
d38dd64a 29#include "config.h"
37ef15bb 30#include "lxclock.h"
f1eacafb 31#include "macro.h"
97f35ce6 32#include "memory_utils.h"
37ef15bb
CB
33#include "namespace.h"
34#include "parse.h"
35#include "string_utils.h"
37ef15bb
CB
36
37#ifndef HAVE_STRLCPY
38#include "include/strlcpy.h"
39#endif
40
41#ifndef HAVE_STRLCAT
42#include "include/strlcat.h"
43#endif
44
37ef15bb
CB
45char **lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup)
46{
47 va_list ap2;
48 size_t count = 1 + skip;
49 char **result;
50
51 /* first determine size of argument list, we don't want to reallocate
52 * constantly...
53 */
54 va_copy(ap2, ap);
51a8a74c 55 for (;;) {
37ef15bb
CB
56 char *arg = va_arg(ap2, char *);
57 if (!arg)
58 break;
59 count++;
60 }
61 va_end(ap2);
62
63 result = calloc(count, sizeof(char *));
64 if (!result)
65 return NULL;
66
67 count = skip;
51a8a74c 68 for (;;) {
37ef15bb
CB
69 char *arg = va_arg(ap, char *);
70 if (!arg)
71 break;
72 arg = do_strdup ? strdup(arg) : arg;
73 if (!arg)
74 goto oom;
75 result[count++] = arg;
76 }
77
78 /* calloc has already set last element to NULL*/
79 return result;
80
81oom:
82 free(result);
83 return NULL;
84}
85
86const char **lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
87{
88 return (const char **)lxc_va_arg_list_to_argv(ap, skip, 0);
89}
90
91char *lxc_string_replace(const char *needle, const char *replacement,
92 const char *haystack)
93{
94 ssize_t len = -1, saved_len = -1;
95 char *result = NULL;
96 size_t replacement_len = strlen(replacement);
97 size_t needle_len = strlen(needle);
98
99 /* should be executed exactly twice */
100 while (len == -1 || result == NULL) {
101 char *p;
102 char *last_p;
103 ssize_t part_len;
104
105 if (len != -1) {
106 result = calloc(1, len + 1);
107 if (!result)
108 return NULL;
109
110 saved_len = len;
111 }
112
113 len = 0;
114
115 for (last_p = (char *)haystack, p = strstr(last_p, needle); p;
116 last_p = p, p = strstr(last_p, needle)) {
117 part_len = (ssize_t)(p - last_p);
118 if (result && part_len > 0)
119 memcpy(&result[len], last_p, part_len);
120
121 len += part_len;
122
123 if (result && replacement_len > 0)
124 memcpy(&result[len], replacement,
125 replacement_len);
126
127 len += replacement_len;
128 p += needle_len;
129 }
130
131 part_len = strlen(last_p);
132 if (result && part_len > 0)
133 memcpy(&result[len], last_p, part_len);
134
135 len += part_len;
136 }
137
138 /* make sure we did the same thing twice,
139 * once for calculating length, the other
140 * time for copying data */
141 if (saved_len != len) {
142 free(result);
143 return NULL;
144 }
145
146 /* make sure we didn't overwrite any buffer,
147 * due to calloc the string should be 0-terminated */
148 if (result[len] != '\0') {
149 free(result);
150 return NULL;
151 }
152
153 return result;
154}
155
156bool lxc_string_in_array(const char *needle, const char **haystack)
157{
158 for (; haystack && *haystack; haystack++)
7ba62a5e 159 if (strequal(needle, *haystack))
37ef15bb
CB
160 return true;
161
162 return false;
163}
164
165char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix)
166{
167 char *result;
168 char **p;
169 size_t sep_len = strlen(sep);
170 size_t result_len = use_as_prefix * sep_len;
171 size_t buf_len;
172
173 /* calculate new string length */
174 for (p = (char **)parts; *p; p++)
175 result_len += (p > (char **)parts) * sep_len + strlen(*p);
176
177 buf_len = result_len + 1;
178 result = calloc(buf_len, 1);
179 if (!result)
180 return NULL;
181
182 if (use_as_prefix)
183 (void)strlcpy(result, sep, buf_len);
184
185 for (p = (char **)parts; *p; p++) {
186 if (p > (char **)parts)
187 (void)strlcat(result, sep, buf_len);
188
189 (void)strlcat(result, *p, buf_len);
190 }
191
192 return result;
193}
194
28e54be1
CB
195/* taken from systemd */
196char *path_simplify(const char *path)
37ef15bb 197{
28e54be1
CB
198 __do_free char *path_new = NULL;
199 char *f, *t;
200 bool slash = false, ignore_slash = false, absolute;
37ef15bb 201
28e54be1
CB
202 path_new = strdup(path);
203 if (!path_new)
37ef15bb
CB
204 return NULL;
205
28e54be1
CB
206 if (is_empty_string(path_new))
207 return move_ptr(path_new);
208
209 absolute = abspath(path_new);
210
211 f = path_new;
212 if (*f == '.' && IN_SET(f[1], 0, '/')) {
213 ignore_slash = true;
214 f++;
37ef15bb
CB
215 }
216
28e54be1 217 for (t = path_new; *f; f++) {
37ef15bb 218
28e54be1
CB
219 if (*f == '/') {
220 slash = true;
221 continue;
222 }
37ef15bb 223
28e54be1
CB
224 if (slash) {
225 if (*f == '.' && IN_SET(f[1], 0, '/'))
226 continue;
37ef15bb 227
28e54be1
CB
228 slash = false;
229 if (ignore_slash)
230 ignore_slash = false;
231 else
232 *(t++) = '/';
37ef15bb 233 }
28e54be1
CB
234
235 *(t++) = *f;
236 }
237
238 if (t == path_new) {
239 if (absolute)
240 *(t++) = '/';
241 else
242 *(t++) = '.';
37ef15bb
CB
243 }
244
28e54be1
CB
245 *t = 0;
246 return move_ptr(path_new);
37ef15bb
CB
247}
248
249char *lxc_append_paths(const char *first, const char *second)
250{
4af24cb7 251 __do_free char *result = NULL;
37ef15bb
CB
252 int ret;
253 size_t len;
d07545c7 254 int pattern_type = 0;
37ef15bb
CB
255
256 len = strlen(first) + strlen(second) + 1;
257 if (second[0] != '/') {
258 len += 1;
d07545c7 259 pattern_type = 1;
37ef15bb
CB
260 }
261
4af24cb7 262 result = zalloc(len);
37ef15bb
CB
263 if (!result)
264 return NULL;
265
d07545c7 266 if (pattern_type == 0)
4af24cb7 267 ret = strnprintf(result, len, "%s%s", first, second);
d07545c7 268 else
4af24cb7
CB
269 ret = strnprintf(result, len, "%s/%s", first, second);
270 if (ret < 0)
37ef15bb 271 return NULL;
37ef15bb 272
4af24cb7 273 return move_ptr(result);
37ef15bb
CB
274}
275
276bool lxc_string_in_list(const char *needle, const char *haystack, char _sep)
277{
97f35ce6
CB
278 __do_free char *str = NULL;
279 char *token;
37ef15bb 280 char sep[2] = { _sep, '\0' };
37ef15bb
CB
281
282 if (!haystack || !needle)
283 return 0;
284
97f35ce6 285 str = must_copy_string(haystack);
37ef15bb 286 lxc_iterate_parts(token, str, sep)
7ba62a5e 287 if (strequal(needle, token))
37ef15bb
CB
288 return 1;
289
290 return 0;
291}
292
293char **lxc_string_split(const char *string, char _sep)
294{
97f35ce6
CB
295 __do_free char *str = NULL;
296 char *token;
37ef15bb
CB
297 char sep[2] = {_sep, '\0'};
298 char **tmp = NULL, **result = NULL;
299 size_t result_capacity = 0;
300 size_t result_count = 0;
301 int r, saved_errno;
37ef15bb
CB
302
303 if (!string)
304 return calloc(1, sizeof(char *));
305
97f35ce6 306 str = must_copy_string(string);
37ef15bb
CB
307 lxc_iterate_parts(token, str, sep) {
308 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
309 if (r < 0)
310 goto error_out;
311
312 result[result_count] = strdup(token);
313 if (!result[result_count])
314 goto error_out;
315
316 result_count++;
317 }
318
319 /* if we allocated too much, reduce it */
320 tmp = realloc(result, (result_count + 1) * sizeof(char *));
321 if (!tmp)
322 goto error_out;
323
324 result = tmp;
325
326 /* Make sure we don't return uninitialized memory. */
327 if (result_count == 0)
328 *result = NULL;
329
330 return result;
331
332error_out:
333 saved_errno = errno;
334 lxc_free_array((void **)result, free);
335 errno = saved_errno;
336 return NULL;
337}
338
339static bool complete_word(char ***result, char *start, char *end, size_t *cap,
340 size_t *cnt)
341{
342 int r;
343
344 r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16);
345 if (r < 0)
346 return false;
347
348 (*result)[*cnt] = strndup(start, end - start);
349 if (!(*result)[*cnt])
350 return false;
351
352 (*cnt)++;
353
354 return true;
355}
356
357/*
358 * Given a a string 'one two "three four"', split into three words,
359 * one, two, and "three four"
360 */
361char **lxc_string_split_quoted(char *string)
362{
363 char *nextword = string, *p, state;
364 char **result = NULL;
365 size_t result_capacity = 0;
366 size_t result_count = 0;
367
368 if (!string || !*string)
369 return calloc(1, sizeof(char *));
370
371 // TODO I'm *not* handling escaped quote
372 state = ' ';
373 for (p = string; *p; p++) {
374 switch(state) {
375 case ' ':
376 if (isspace(*p))
377 continue;
378 else if (*p == '"' || *p == '\'') {
379 nextword = p;
380 state = *p;
381 continue;
382 }
383 nextword = p;
384 state = 'a';
385 continue;
386 case 'a':
387 if (isspace(*p)) {
388 complete_word(&result, nextword, p, &result_capacity, &result_count);
389 state = ' ';
390 continue;
391 }
392 continue;
393 case '"':
394 case '\'':
395 if (*p == state) {
396 complete_word(&result, nextword+1, p, &result_capacity, &result_count);
397 state = ' ';
398 continue;
399 }
400 continue;
401 }
402 }
403
404 if (state == 'a')
405 complete_word(&result, nextword, p, &result_capacity, &result_count);
406
407 return realloc(result, (result_count + 1) * sizeof(char *));
408}
409
410char **lxc_string_split_and_trim(const char *string, char _sep)
411{
97f35ce6
CB
412 __do_free char *str = NULL;
413 char *token;
37ef15bb
CB
414 char sep[2] = { _sep, '\0' };
415 char **result = NULL;
416 size_t result_capacity = 0;
417 size_t result_count = 0;
418 int r, saved_errno;
419 size_t i = 0;
37ef15bb
CB
420
421 if (!string)
422 return calloc(1, sizeof(char *));
423
97f35ce6 424 str = must_copy_string(string);
37ef15bb
CB
425 lxc_iterate_parts(token, str, sep) {
426 while (token[0] == ' ' || token[0] == '\t')
427 token++;
428
429 i = strlen(token);
430 while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
431 token[i - 1] = '\0';
432 i--;
433 }
434
435 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
436 if (r < 0)
437 goto error_out;
438
439 result[result_count] = strdup(token);
440 if (!result[result_count])
441 goto error_out;
442
443 result_count++;
444 }
445
446 /* if we allocated too much, reduce it */
447 return realloc(result, (result_count + 1) * sizeof(char *));
448
449error_out:
450 saved_errno = errno;
451 lxc_free_array((void **)result, free);
452 errno = saved_errno;
453 return NULL;
454}
455
456void lxc_free_array(void **array, lxc_free_fn element_free_fn)
457{
458 void **p;
459
460 for (p = array; p && *p; p++)
461 element_free_fn(*p);
462
463 free((void*)array);
464}
465
466int lxc_grow_array(void ***array, size_t *capacity, size_t new_size, size_t capacity_increment)
467{
468 size_t new_capacity;
469 void **new_array;
470
471 /* first time around, catch some trivial mistakes of the user
472 * only initializing one of these */
473 if (!*array || !*capacity) {
474 *array = NULL;
475 *capacity = 0;
476 }
477
478 new_capacity = *capacity;
479 while (new_size + 1 > new_capacity)
480 new_capacity += capacity_increment;
481
482 if (new_capacity != *capacity) {
483 /* we have to reallocate */
484 new_array = realloc(*array, new_capacity * sizeof(void *));
485 if (!new_array)
486 return -1;
487
488 memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * sizeof(void *));
489 *array = new_array;
490 *capacity = new_capacity;
491 }
492
493 /* array has sufficient elements */
494 return 0;
495}
496
497size_t lxc_array_len(void **array)
498{
499 void **p;
500 size_t result = 0;
501
502 for (p = array; p && *p; p++)
503 result++;
504
505 return result;
506}
507
508void **lxc_append_null_to_array(void **array, size_t count)
509{
510 void **temp;
511
512 /* Append NULL to the array */
513 if (count) {
514 temp = realloc(array, (count + 1) * sizeof(*array));
515 if (!temp) {
516 size_t i;
517 for (i = 0; i < count; i++)
518 free(array[i]);
519 free(array);
520 return NULL;
521 }
522
523 array = temp;
524 array[count] = NULL;
525 }
526
527 return array;
528}
529
530static int lxc_append_null_to_list(void ***list)
531{
532 int newentry = 0;
533 void **tmp;
534
535 if (*list)
536 for (; (*list)[newentry]; newentry++) {
537 ;
538 }
539
540 tmp = realloc(*list, (newentry + 2) * sizeof(void **));
541 if (!tmp)
542 return -1;
543
544 *list = tmp;
545 (*list)[newentry + 1] = NULL;
546
547 return newentry;
548}
549
550int lxc_append_string(char ***list, char *entry)
551{
552 char *copy;
553 int newentry;
554
555 newentry = lxc_append_null_to_list((void ***)list);
556 if (newentry < 0)
557 return -1;
558
559 copy = strdup(entry);
560 if (!copy)
561 return -1;
562
563 (*list)[newentry] = copy;
564
565 return 0;
566}
567
568int lxc_safe_uint(const char *numstr, unsigned int *converted)
569{
570 char *err = NULL;
571 unsigned long int uli;
572
573 while (isspace(*numstr))
574 numstr++;
575
576 if (*numstr == '-')
577 return -EINVAL;
578
579 errno = 0;
580 uli = strtoul(numstr, &err, 0);
581 if (errno == ERANGE && uli == ULONG_MAX)
582 return -ERANGE;
583
584 if (err == numstr || *err != '\0')
585 return -EINVAL;
586
587 if (uli > UINT_MAX)
588 return -ERANGE;
589
590 *converted = (unsigned int)uli;
591 return 0;
592}
593
594int lxc_safe_ulong(const char *numstr, unsigned long *converted)
595{
596 char *err = NULL;
597 unsigned long int uli;
598
599 while (isspace(*numstr))
600 numstr++;
601
602 if (*numstr == '-')
603 return -EINVAL;
604
605 errno = 0;
606 uli = strtoul(numstr, &err, 0);
607 if (errno == ERANGE && uli == ULONG_MAX)
608 return -ERANGE;
609
610 if (err == numstr || *err != '\0')
611 return -EINVAL;
612
613 *converted = uli;
614 return 0;
615}
616
617int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base)
618{
619 char *err = NULL;
620 uint64_t u;
621
622 while (isspace(*numstr))
623 numstr++;
624
625 if (*numstr == '-')
626 return -EINVAL;
627
628 errno = 0;
629 u = strtoull(numstr, &err, base);
62fc8403 630 if (errno == ERANGE && u == UINT64_MAX)
37ef15bb
CB
631 return -ERANGE;
632
633 if (err == numstr || *err != '\0')
634 return -EINVAL;
635
636 *converted = u;
637 return 0;
638}
639
70fd7fc9
CB
640int lxc_safe_int64_residual(const char *numstr, int64_t *converted, int base, char *residual,
641 size_t residual_len)
642{
643 char *remaining = NULL;
644 int64_t u;
645
646 if (residual && residual_len == 0)
647 return ret_errno(EINVAL);
648
649 if (!residual && residual_len != 0)
650 return ret_errno(EINVAL);
651
c45833e3
CB
652 memset(residual, 0, residual_len);
653
70fd7fc9
CB
654 while (isspace(*numstr))
655 numstr++;
656
657 errno = 0;
658 u = strtoll(numstr, &remaining, base);
659 if (errno == ERANGE && u == INT64_MAX)
90e69d71 660 return ret_errno(ERANGE);
70fd7fc9
CB
661
662 if (remaining == numstr)
663 return -EINVAL;
664
665 if (residual) {
666 size_t len = 0;
667
c45833e3 668 if (*remaining == '\0')
70fd7fc9 669 goto out;
70fd7fc9
CB
670
671 len = strlen(remaining);
672 if (len >= residual_len)
90e69d71 673 return ret_errno(EINVAL);
70fd7fc9
CB
674
675 memcpy(residual, remaining, len);
676 } else if (*remaining != '\0') {
90e69d71 677 return ret_errno(EINVAL);
70fd7fc9
CB
678 }
679
680out:
681 *converted = u;
682 return 0;
683}
684
37ef15bb
CB
685int lxc_safe_int(const char *numstr, int *converted)
686{
687 char *err = NULL;
688 signed long int sli;
689
690 errno = 0;
691 sli = strtol(numstr, &err, 0);
692 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
693 return -ERANGE;
694
695 if (errno != 0 && sli == 0)
696 return -EINVAL;
697
698 if (err == numstr || *err != '\0')
699 return -EINVAL;
700
701 if (sli > INT_MAX || sli < INT_MIN)
702 return -ERANGE;
703
704 *converted = (int)sli;
705 return 0;
706}
707
708int lxc_safe_long(const char *numstr, long int *converted)
709{
710 char *err = NULL;
711 signed long int sli;
712
713 errno = 0;
714 sli = strtol(numstr, &err, 0);
715 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
716 return -ERANGE;
717
718 if (errno != 0 && sli == 0)
719 return -EINVAL;
720
721 if (err == numstr || *err != '\0')
722 return -EINVAL;
723
724 *converted = sli;
725 return 0;
726}
727
728int lxc_safe_long_long(const char *numstr, long long int *converted)
729{
730 char *err = NULL;
731 signed long long int sli;
732
733 errno = 0;
734 sli = strtoll(numstr, &err, 0);
735 if (errno == ERANGE && (sli == LLONG_MAX || sli == LLONG_MIN))
736 return -ERANGE;
737
738 if (errno != 0 && sli == 0)
739 return -EINVAL;
740
741 if (err == numstr || *err != '\0')
742 return -EINVAL;
743
744 *converted = sli;
745 return 0;
746}
747
fe70edee 748char *must_concat(size_t *len, const char *first, ...)
37ef15bb
CB
749{
750 va_list args;
751 char *cur, *dest;
752 size_t cur_len, it_len;
753
754 dest = must_copy_string(first);
755 cur_len = it_len = strlen(first);
756
757 va_start(args, first);
758 while ((cur = va_arg(args, char *)) != NULL) {
759 it_len = strlen(cur);
760
761 dest = must_realloc(dest, cur_len + it_len + 1);
762
763 (void)memcpy(dest + cur_len, cur, it_len);
764 cur_len += it_len;
765 }
766 va_end(args);
767
b9bb8bbb 768 dest[cur_len] = '\0';
fe70edee
CB
769 if (len)
770 *len = cur_len;
37ef15bb
CB
771 return dest;
772}
773
774char *must_make_path(const char *first, ...)
775{
776 va_list args;
777 char *cur, *dest;
778 size_t full_len = strlen(first);
779 size_t buf_len;
7cfde20f 780 size_t cur_len;
37ef15bb
CB
781
782 dest = must_copy_string(first);
7cfde20f 783 cur_len = full_len;
37ef15bb
CB
784
785 va_start(args, first);
786 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 787 buf_len = strlen(cur);
19281251
CB
788 if (buf_len == 0)
789 continue;
7cfde20f 790
791 full_len += buf_len;
37ef15bb
CB
792 if (cur[0] != '/')
793 full_len++;
794
7cfde20f 795 dest = must_realloc(dest, full_len + 1);
37ef15bb 796
7cfde20f 797 if (cur[0] != '/') {
798 memcpy(dest + cur_len, "/", 1);
799 cur_len++;
800 }
801
802 memcpy(dest + cur_len, cur, buf_len);
803 cur_len += buf_len;
37ef15bb
CB
804 }
805 va_end(args);
806
7cfde20f 807 dest[cur_len] = '\0';
37ef15bb
CB
808 return dest;
809}
810
811char *must_append_path(char *first, ...)
812{
813 char *cur;
814 size_t full_len;
815 va_list args;
816 char *dest = first;
817 size_t buf_len;
7cfde20f 818 size_t cur_len;
37ef15bb
CB
819
820 full_len = strlen(first);
7cfde20f 821 cur_len = full_len;
822
37ef15bb
CB
823 va_start(args, first);
824 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 825 buf_len = strlen(cur);
826
827 full_len += buf_len;
37ef15bb
CB
828 if (cur[0] != '/')
829 full_len++;
830
7cfde20f 831 dest = must_realloc(dest, full_len + 1);
37ef15bb 832
7cfde20f 833 if (cur[0] != '/') {
834 memcpy(dest + cur_len, "/", 1);
835 cur_len++;
836 }
837
838 memcpy(dest + cur_len, cur, buf_len);
839 cur_len += buf_len;
37ef15bb
CB
840 }
841 va_end(args);
842
7cfde20f 843 dest[cur_len] = '\0';
37ef15bb
CB
844 return dest;
845}
846
847char *must_copy_string(const char *entry)
848{
849 char *ret;
850
851 if (!entry)
852 return NULL;
853
854 do {
855 ret = strdup(entry);
856 } while (!ret);
857
858 return ret;
859}
860
861void *must_realloc(void *orig, size_t sz)
862{
863 void *ret;
864
865 do {
866 ret = realloc(orig, sz);
867 } while (!ret);
868
869 return ret;
870}
871
4c5479d2 872int parse_byte_size_string(const char *s, long long int *converted)
37ef15bb
CB
873{
874 int ret, suffix_len;
4c5479d2 875 long long int conv, mltpl;
37ef15bb 876 char *end;
f6727edb 877 char dup[INTTYPE_TO_STRLEN(long long int)] = {0};
37ef15bb
CB
878 char suffix[3] = {0};
879
b2480b29 880 if (is_empty_string(s))
3f5c01db 881 return ret_errno(EINVAL);
37ef15bb
CB
882
883 end = stpncpy(dup, s, sizeof(dup) - 1);
884 if (*end != '\0')
3f5c01db 885 return ret_errno(EINVAL);
37ef15bb
CB
886
887 if (isdigit(*(end - 1)))
888 suffix_len = 0;
889 else if (isalpha(*(end - 1)))
890 suffix_len = 1;
891 else
3f5c01db 892 return ret_errno(EINVAL);
37ef15bb 893
b2480b29
CB
894 if (suffix_len > 0) {
895 if ((end - 1) == dup)
896 return ret_errno(EINVAL);
37ef15bb 897
b2480b29
CB
898 if ((end - 2) == dup) {
899 if (isalpha(*(end - 2)))
900 return ret_errno(EINVAL);
901 /* 1B */
902 } else {
903 if (isalpha(*(end - 2))) /* 12MB */
904 suffix_len++;
905
906 /* 12B */
907 }
37ef15bb 908
37ef15bb
CB
909 memcpy(suffix, end - suffix_len, suffix_len);
910 *(suffix + suffix_len) = '\0';
911 *(end - suffix_len) = '\0';
912 }
b2480b29 913
37ef15bb
CB
914 dup[lxc_char_right_gc(dup, strlen(dup))] = '\0';
915
916 ret = lxc_safe_long_long(dup, &conv);
3f5c01db
CB
917 if (ret)
918 return ret;
37ef15bb
CB
919
920 if (suffix_len != 2) {
921 *converted = conv;
922 return 0;
923 }
924
925 if (strcasecmp(suffix, "KB") == 0)
926 mltpl = 1024;
927 else if (strcasecmp(suffix, "MB") == 0)
928 mltpl = 1024 * 1024;
929 else if (strcasecmp(suffix, "GB") == 0)
930 mltpl = 1024 * 1024 * 1024;
931 else
3f5c01db 932 return ret_errno(EINVAL);
37ef15bb 933
4c5479d2 934 if (check_mul_overflow(conv, mltpl, converted))
3f5c01db 935 return ret_errno(ERANGE);
37ef15bb 936
37ef15bb
CB
937 return 0;
938}
939
940void remove_trailing_newlines(char *l)
941{
942 char *p = l;
943
944 while (*p)
945 p++;
946
947 while (--p >= l && *p == '\n')
948 *p = '\0';
949}
950
951int lxc_char_left_gc(const char *buffer, size_t len)
952{
953 size_t i;
954
955 for (i = 0; i < len; i++) {
956 if (buffer[i] == ' ' ||
957 buffer[i] == '\t')
958 continue;
959
960 return i;
961 }
962
963 return 0;
964}
965
966int lxc_char_right_gc(const char *buffer, size_t len)
967{
968 int i;
969
970 for (i = len - 1; i >= 0; i--) {
971 if (buffer[i] == ' ' ||
972 buffer[i] == '\t' ||
973 buffer[i] == '\n' ||
974 buffer[i] == '\0')
975 continue;
976
977 return i + 1;
978 }
979
980 return 0;
981}
982
983char *lxc_trim_whitespace_in_place(char *buffer)
984{
985 buffer += lxc_char_left_gc(buffer, strlen(buffer));
986 buffer[lxc_char_right_gc(buffer, strlen(buffer))] = '\0';
987 return buffer;
988}
989
990int lxc_is_line_empty(const char *line)
991{
992 int i;
993 size_t len = strlen(line);
994
995 for (i = 0; i < len; i++)
996 if (line[i] != ' ' && line[i] != '\t' &&
997 line[i] != '\n' && line[i] != '\r' &&
998 line[i] != '\f' && line[i] != '\0')
999 return 0;
1000 return 1;
1001}
dca12ddf
CB
1002
1003void remove_trailing_slashes(char *p)
1004{
1005 int l = strlen(p);
1006 while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
1007 p[l] = '\0';
1008}