1 /* SPDX-License-Identifier: LGPL-2.1+ */
19 #include <sys/mount.h>
20 #include <sys/param.h>
21 #include <sys/prctl.h>
23 #include <sys/types.h>
27 #include "string_utils.h"
29 #include "memory_utils.h"
39 char **lxc_va_arg_list_to_argv(va_list ap
, size_t skip
, int do_strdup
)
42 size_t count
= 1 + skip
;
45 /* first determine size of argument list, we don't want to reallocate
50 char *arg
= va_arg(ap2
, char *);
57 result
= calloc(count
, sizeof(char *));
63 char *arg
= va_arg(ap
, char *);
66 arg
= do_strdup
? strdup(arg
) : arg
;
69 result
[count
++] = arg
;
72 /* calloc has already set last element to NULL*/
80 const char **lxc_va_arg_list_to_argv_const(va_list ap
, size_t skip
)
82 return (const char **)lxc_va_arg_list_to_argv(ap
, skip
, 0);
85 char *lxc_string_replace(const char *needle
, const char *replacement
,
88 ssize_t len
= -1, saved_len
= -1;
90 size_t replacement_len
= strlen(replacement
);
91 size_t needle_len
= strlen(needle
);
93 /* should be executed exactly twice */
94 while (len
== -1 || result
== NULL
) {
100 result
= calloc(1, len
+ 1);
109 for (last_p
= (char *)haystack
, p
= strstr(last_p
, needle
); p
;
110 last_p
= p
, p
= strstr(last_p
, needle
)) {
111 part_len
= (ssize_t
)(p
- last_p
);
112 if (result
&& part_len
> 0)
113 memcpy(&result
[len
], last_p
, part_len
);
117 if (result
&& replacement_len
> 0)
118 memcpy(&result
[len
], replacement
,
121 len
+= replacement_len
;
125 part_len
= strlen(last_p
);
126 if (result
&& part_len
> 0)
127 memcpy(&result
[len
], last_p
, part_len
);
132 /* make sure we did the same thing twice,
133 * once for calculating length, the other
134 * time for copying data */
135 if (saved_len
!= len
) {
140 /* make sure we didn't overwrite any buffer,
141 * due to calloc the string should be 0-terminated */
142 if (result
[len
] != '\0') {
150 bool lxc_string_in_array(const char *needle
, const char **haystack
)
152 for (; haystack
&& *haystack
; haystack
++)
153 if (strequal(needle
, *haystack
))
159 char *lxc_string_join(const char *sep
, const char **parts
, bool use_as_prefix
)
163 size_t sep_len
= strlen(sep
);
164 size_t result_len
= use_as_prefix
* sep_len
;
167 /* calculate new string length */
168 for (p
= (char **)parts
; *p
; p
++)
169 result_len
+= (p
> (char **)parts
) * sep_len
+ strlen(*p
);
171 buf_len
= result_len
+ 1;
172 result
= calloc(buf_len
, 1);
177 (void)strlcpy(result
, sep
, buf_len
);
179 for (p
= (char **)parts
; *p
; p
++) {
180 if (p
> (char **)parts
)
181 (void)strlcat(result
, sep
, buf_len
);
183 (void)strlcat(result
, *p
, buf_len
);
189 /* taken from systemd */
190 char *lxc_path_simplify(const char *path
)
192 __do_free
char *path_new
= NULL
;
194 bool slash
= false, ignore_slash
= false, absolute
;
196 path_new
= strdup(path
);
200 if (is_empty_string(path_new
))
201 return move_ptr(path_new
);
203 absolute
= abspath(path_new
);
206 if (*f
== '.' && (f
[1] == 0 || f
[1] == '/')) {
211 for (t
= path_new
; *f
; f
++) {
219 if (*f
== '.' && (f
[1] == 0 || f
[1] == '/'))
224 ignore_slash
= false;
240 return move_ptr(path_new
);
243 char *lxc_append_paths(const char *first
, const char *second
)
245 __do_free
char *result
= NULL
;
248 int pattern_type
= 0;
250 len
= strlen(first
) + strlen(second
) + 1;
251 if (second
[0] != '/') {
256 result
= zalloc(len
);
260 if (pattern_type
== 0)
261 ret
= strnprintf(result
, len
, "%s%s", first
, second
);
263 ret
= strnprintf(result
, len
, "%s/%s", first
, second
);
267 return move_ptr(result
);
270 bool lxc_string_in_list(const char *needle
, const char *haystack
, char _sep
)
272 __do_free
char *str
= NULL
;
274 char sep
[2] = { _sep
, '\0' };
276 if (!haystack
|| !needle
)
279 str
= must_copy_string(haystack
);
280 lxc_iterate_parts(token
, str
, sep
)
281 if (strequal(needle
, token
))
287 char **lxc_string_split(const char *string
, char _sep
)
289 __do_free
char *str
= NULL
;
291 char sep
[2] = {_sep
, '\0'};
292 char **tmp
= NULL
, **result
= NULL
;
293 size_t result_capacity
= 0;
294 size_t result_count
= 0;
298 return calloc(1, sizeof(char *));
300 str
= must_copy_string(string
);
301 lxc_iterate_parts(token
, str
, sep
) {
302 r
= lxc_grow_array((void ***)&result
, &result_capacity
, result_count
+ 1, 16);
306 result
[result_count
] = strdup(token
);
307 if (!result
[result_count
])
313 /* if we allocated too much, reduce it */
314 tmp
= realloc(result
, (result_count
+ 1) * sizeof(char *));
320 /* Make sure we don't return uninitialized memory. */
321 if (result_count
== 0)
328 lxc_free_array((void **)result
, free
);
333 static bool complete_word(char ***result
, char *start
, char *end
, size_t *cap
,
338 r
= lxc_grow_array((void ***)result
, cap
, 2 + *cnt
, 16);
342 (*result
)[*cnt
] = strndup(start
, end
- start
);
343 if (!(*result
)[*cnt
])
352 * Given a a string 'one two "three four"', split into three words,
353 * one, two, and "three four"
355 char **lxc_string_split_quoted(char *string
)
357 char *nextword
= string
, *p
, state
;
358 char **result
= NULL
;
359 size_t result_capacity
= 0;
360 size_t result_count
= 0;
362 if (!string
|| !*string
)
363 return calloc(1, sizeof(char *));
365 // TODO I'm *not* handling escaped quote
367 for (p
= string
; *p
; p
++) {
372 else if (*p
== '"' || *p
== '\'') {
382 complete_word(&result
, nextword
, p
, &result_capacity
, &result_count
);
390 complete_word(&result
, nextword
+1, p
, &result_capacity
, &result_count
);
399 complete_word(&result
, nextword
, p
, &result_capacity
, &result_count
);
402 return calloc(1, sizeof(char *));
404 return realloc(result
, (result_count
+ 1) * sizeof(char *));
407 char **lxc_string_split_and_trim(const char *string
, char _sep
)
409 __do_free
char *str
= NULL
;
411 char sep
[2] = { _sep
, '\0' };
412 char **result
= NULL
;
413 size_t result_capacity
= 0;
414 size_t result_count
= 0;
419 return calloc(1, sizeof(char *));
421 str
= must_copy_string(string
);
422 lxc_iterate_parts(token
, str
, sep
) {
423 while (token
[0] == ' ' || token
[0] == '\t')
427 while (i
> 0 && (token
[i
- 1] == ' ' || token
[i
- 1] == '\t')) {
432 r
= lxc_grow_array((void ***)&result
, &result_capacity
, result_count
+ 1, 16);
436 result
[result_count
] = strdup(token
);
437 if (!result
[result_count
])
444 return calloc(1, sizeof(char *));
446 /* if we allocated too much, reduce it */
447 return realloc(result
, (result_count
+ 1) * sizeof(char *));
451 lxc_free_array((void **)result
, free
);
456 void lxc_free_array(void **array
, lxc_free_fn element_free_fn
)
460 for (p
= array
; p
&& *p
; p
++)
466 int lxc_grow_array(void ***array
, size_t *capacity
, size_t new_size
, size_t capacity_increment
)
471 /* first time around, catch some trivial mistakes of the user
472 * only initializing one of these */
473 if (!*array
|| !*capacity
) {
478 new_capacity
= *capacity
;
479 while (new_size
+ 1 > new_capacity
)
480 new_capacity
+= capacity_increment
;
482 if (new_capacity
!= *capacity
) {
483 /* we have to reallocate */
484 new_array
= realloc(*array
, new_capacity
* sizeof(void *));
488 memset(&new_array
[*capacity
], 0, (new_capacity
- (*capacity
)) * sizeof(void *));
490 *capacity
= new_capacity
;
493 /* array has sufficient elements */
497 size_t lxc_array_len(void **array
)
502 for (p
= array
; p
&& *p
; p
++)
508 void **lxc_append_null_to_array(void **array
, size_t count
)
512 /* Append NULL to the array */
514 temp
= realloc(array
, (count
+ 1) * sizeof(*array
));
517 for (i
= 0; i
< count
; i
++)
530 static int lxc_append_null_to_list(void ***list
)
536 for (; (*list
)[newentry
]; newentry
++) {
540 tmp
= realloc(*list
, (newentry
+ 2) * sizeof(void **));
545 (*list
)[newentry
+ 1] = NULL
;
550 int lxc_append_string(char ***list
, char *entry
)
555 newentry
= lxc_append_null_to_list((void ***)list
);
559 copy
= strdup(entry
);
563 (*list
)[newentry
] = copy
;
568 int lxc_safe_uint(const char *numstr
, unsigned int *converted
)
571 unsigned long int uli
;
573 while (isspace(*numstr
))
580 uli
= strtoul(numstr
, &err
, 0);
581 if (errno
== ERANGE
&& uli
== ULONG_MAX
)
584 if (err
== numstr
|| *err
!= '\0')
590 *converted
= (unsigned int)uli
;
594 int lxc_safe_ulong(const char *numstr
, unsigned long *converted
)
597 unsigned long int uli
;
599 while (isspace(*numstr
))
606 uli
= strtoul(numstr
, &err
, 0);
607 if (errno
== ERANGE
&& uli
== ULONG_MAX
)
610 if (err
== numstr
|| *err
!= '\0')
617 int lxc_safe_uint64(const char *numstr
, uint64_t *converted
, int base
)
622 while (isspace(*numstr
))
629 u
= strtoull(numstr
, &err
, base
);
630 if (errno
== ERANGE
&& u
== UINT64_MAX
)
633 if (err
== numstr
|| *err
!= '\0')
640 int lxc_safe_int64_residual(const char *restrict numstr
,
641 int64_t *restrict converted
, int base
,
642 char *restrict residual
, size_t residual_len
)
644 char *remaining
= NULL
;
647 if (residual
&& residual_len
== 0)
648 return ret_errno(EINVAL
);
650 if (!residual
&& residual_len
!= 0)
651 return ret_errno(EINVAL
);
653 memset(residual
, 0, residual_len
);
655 while (isspace(*numstr
))
659 u
= strtoll(numstr
, &remaining
, base
);
660 if (errno
== ERANGE
&& u
== INT64_MAX
)
661 return ret_errno(ERANGE
);
663 if (remaining
== numstr
)
669 if (*remaining
== '\0')
672 len
= strlen(remaining
);
673 if (len
>= residual_len
)
674 return ret_errno(EINVAL
);
676 memcpy(residual
, remaining
, len
);
677 } else if (*remaining
!= '\0') {
678 return ret_errno(EINVAL
);
686 int lxc_safe_int(const char *numstr
, int *converted
)
692 sli
= strtol(numstr
, &err
, 0);
693 if (errno
== ERANGE
&& (sli
== LONG_MAX
|| sli
== LONG_MIN
))
696 if (errno
!= 0 && sli
== 0)
699 if (err
== numstr
|| *err
!= '\0')
702 if (sli
> INT_MAX
|| sli
< INT_MIN
)
705 *converted
= (int)sli
;
709 int lxc_safe_long(const char *numstr
, long int *converted
)
715 sli
= strtol(numstr
, &err
, 0);
716 if (errno
== ERANGE
&& (sli
== LONG_MAX
|| sli
== LONG_MIN
))
719 if (errno
!= 0 && sli
== 0)
722 if (err
== numstr
|| *err
!= '\0')
729 int lxc_safe_long_long(const char *numstr
, long long int *converted
)
732 signed long long int sli
;
735 sli
= strtoll(numstr
, &err
, 0);
736 if (errno
== ERANGE
&& (sli
== LLONG_MAX
|| sli
== LLONG_MIN
))
739 if (errno
!= 0 && sli
== 0)
742 if (err
== numstr
|| *err
!= '\0')
749 char *must_concat(size_t *len
, const char *first
, ...)
753 size_t cur_len
, it_len
;
755 dest
= must_copy_string(first
);
756 cur_len
= it_len
= strlen(first
);
758 va_start(args
, first
);
759 while ((cur
= va_arg(args
, char *)) != NULL
) {
760 it_len
= strlen(cur
);
762 dest
= must_realloc(dest
, cur_len
+ it_len
+ 1);
764 (void)memcpy(dest
+ cur_len
, cur
, it_len
);
769 dest
[cur_len
] = '\0';
775 char *must_make_path(const char *first
, ...)
779 size_t full_len
= strlen(first
);
783 dest
= must_copy_string(first
);
786 va_start(args
, first
);
787 while ((cur
= va_arg(args
, char *)) != NULL
) {
788 buf_len
= strlen(cur
);
796 dest
= must_realloc(dest
, full_len
+ 1);
799 memcpy(dest
+ cur_len
, "/", 1);
803 memcpy(dest
+ cur_len
, cur
, buf_len
);
808 dest
[cur_len
] = '\0';
812 char *must_append_path(char *first
, ...)
821 full_len
= strlen(first
);
824 va_start(args
, first
);
825 while ((cur
= va_arg(args
, char *)) != NULL
) {
826 buf_len
= strlen(cur
);
832 dest
= must_realloc(dest
, full_len
+ 1);
835 memcpy(dest
+ cur_len
, "/", 1);
839 memcpy(dest
+ cur_len
, cur
, buf_len
);
844 dest
[cur_len
] = '\0';
848 char *must_copy_string(const char *entry
)
862 void *must_realloc(void *orig
, size_t sz
)
867 ret
= realloc(orig
, sz
);
873 int parse_byte_size_string(const char *s
, long long int *converted
)
876 long long int conv
, mltpl
;
878 char dup
[INTTYPE_TO_STRLEN(long long int)] = {0};
879 char suffix
[3] = {0};
883 return ret_errno(EINVAL
);
886 if (len
== 0 || len
> sizeof(dup
) - 1)
887 return ret_errno(EINVAL
);
892 if (isdigit(*(end
- 1)))
894 else if (isalpha(*(end
- 1)))
897 return ret_errno(EINVAL
);
899 if (suffix_len
> 0) {
900 if ((end
- 1) == dup
)
901 return ret_errno(EINVAL
);
903 if ((end
- 2) == dup
) {
904 if (isalpha(*(end
- 2)))
905 return ret_errno(EINVAL
);
908 if (isalpha(*(end
- 2))) /* 12MB */
914 memcpy(suffix
, end
- suffix_len
, suffix_len
);
915 *(suffix
+ suffix_len
) = '\0';
916 *(end
- suffix_len
) = '\0';
919 dup
[lxc_char_right_gc(dup
, strlen(dup
))] = '\0';
921 ret
= lxc_safe_long_long(dup
, &conv
);
925 if (suffix_len
!= 2) {
930 if (strcasecmp(suffix
, "KB") == 0)
932 else if (strcasecmp(suffix
, "MB") == 0)
934 else if (strcasecmp(suffix
, "GB") == 0)
935 mltpl
= 1024 * 1024 * 1024;
937 return ret_errno(EINVAL
);
939 if (check_mul_overflow(conv
, mltpl
, converted
))
940 return ret_errno(ERANGE
);
945 void remove_trailing_newlines(char *l
)
952 while (--p
>= l
&& *p
== '\n')
956 int lxc_char_left_gc(const char *buffer
, size_t len
)
960 for (i
= 0; i
< len
; i
++) {
961 if (buffer
[i
] == ' ' ||
971 int lxc_char_right_gc(const char *buffer
, size_t len
)
975 for (i
= len
- 1; i
>= 0; i
--) {
976 if (buffer
[i
] == ' ' ||
988 char *lxc_trim_whitespace_in_place(char *buffer
)
990 buffer
+= lxc_char_left_gc(buffer
, strlen(buffer
));
991 buffer
[lxc_char_right_gc(buffer
, strlen(buffer
))] = '\0';
995 int lxc_is_line_empty(const char *line
)
997 size_t len
= strlen(line
);
999 for (size_t i
= 0; i
< len
; i
++)
1000 if (line
[i
] != ' ' && line
[i
] != '\t' &&
1001 line
[i
] != '\n' && line
[i
] != '\r' &&
1002 line
[i
] != '\f' && line
[i
] != '\0')
1007 void remove_trailing_slashes(char *p
)
1010 while (--l
>= 0 && (p
[l
] == '/' || p
[l
] == '\n'))