3 * Copyright © 2019 Christian Brauner <christian.brauner@ubuntu.com>.
4 * Copyright © 2019 Canonical Ltd.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this library; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
39 #include <sys/mount.h>
40 #include <sys/param.h>
41 #include <sys/prctl.h>
43 #include <sys/types.h>
50 #include "memory_utils.h"
51 #include "namespace.h"
53 #include "string_utils.h"
56 #include "include/strlcpy.h"
60 #include "include/strlcat.h"
63 char **lxc_va_arg_list_to_argv(va_list ap
, size_t skip
, int do_strdup
)
66 size_t count
= 1 + skip
;
69 /* first determine size of argument list, we don't want to reallocate
74 char *arg
= va_arg(ap2
, char *);
81 result
= calloc(count
, sizeof(char *));
87 char *arg
= va_arg(ap
, char *);
90 arg
= do_strdup
? strdup(arg
) : arg
;
93 result
[count
++] = arg
;
96 /* calloc has already set last element to NULL*/
104 const char **lxc_va_arg_list_to_argv_const(va_list ap
, size_t skip
)
106 return (const char **)lxc_va_arg_list_to_argv(ap
, skip
, 0);
109 char *lxc_string_replace(const char *needle
, const char *replacement
,
110 const char *haystack
)
112 ssize_t len
= -1, saved_len
= -1;
114 size_t replacement_len
= strlen(replacement
);
115 size_t needle_len
= strlen(needle
);
117 /* should be executed exactly twice */
118 while (len
== -1 || result
== NULL
) {
124 result
= calloc(1, len
+ 1);
133 for (last_p
= (char *)haystack
, p
= strstr(last_p
, needle
); p
;
134 last_p
= p
, p
= strstr(last_p
, needle
)) {
135 part_len
= (ssize_t
)(p
- last_p
);
136 if (result
&& part_len
> 0)
137 memcpy(&result
[len
], last_p
, part_len
);
141 if (result
&& replacement_len
> 0)
142 memcpy(&result
[len
], replacement
,
145 len
+= replacement_len
;
149 part_len
= strlen(last_p
);
150 if (result
&& part_len
> 0)
151 memcpy(&result
[len
], last_p
, part_len
);
156 /* make sure we did the same thing twice,
157 * once for calculating length, the other
158 * time for copying data */
159 if (saved_len
!= len
) {
164 /* make sure we didn't overwrite any buffer,
165 * due to calloc the string should be 0-terminated */
166 if (result
[len
] != '\0') {
174 bool lxc_string_in_array(const char *needle
, const char **haystack
)
176 for (; haystack
&& *haystack
; haystack
++)
177 if (!strcmp(needle
, *haystack
))
183 char *lxc_string_join(const char *sep
, const char **parts
, bool use_as_prefix
)
187 size_t sep_len
= strlen(sep
);
188 size_t result_len
= use_as_prefix
* sep_len
;
191 /* calculate new string length */
192 for (p
= (char **)parts
; *p
; p
++)
193 result_len
+= (p
> (char **)parts
) * sep_len
+ strlen(*p
);
195 buf_len
= result_len
+ 1;
196 result
= calloc(buf_len
, 1);
201 (void)strlcpy(result
, sep
, buf_len
);
203 for (p
= (char **)parts
; *p
; p
++) {
204 if (p
> (char **)parts
)
205 (void)strlcat(result
, sep
, buf_len
);
207 (void)strlcat(result
, *p
, buf_len
);
213 char **lxc_normalize_path(const char *path
)
217 size_t components_len
= 0;
220 components
= lxc_string_split(path
, '/');
224 for (p
= components
; *p
; p
++)
227 /* resolve '.' and '..' */
228 for (pos
= 0; pos
< components_len
;) {
229 if (!strcmp(components
[pos
], ".") ||
230 (!strcmp(components
[pos
], "..") && pos
== 0)) {
231 /* eat this element */
232 free(components
[pos
]);
233 memmove(&components
[pos
], &components
[pos
+ 1],
234 sizeof(char *) * (components_len
- pos
));
236 } else if (!strcmp(components
[pos
], "..")) {
237 /* eat this and the previous element */
238 free(components
[pos
- 1]);
239 free(components
[pos
]);
240 memmove(&components
[pos
- 1], &components
[pos
+ 1],
241 sizeof(char *) * (components_len
- pos
));
252 char *lxc_deslashify(const char *path
)
262 parts
= lxc_normalize_path(dup
);
268 /* We'll end up here if path == "///" or path == "". */
272 lxc_free_array((void **)parts
, free
);
276 n
= strcspn(dup
, "/");
279 lxc_free_array((void **)parts
, free
);
289 p
= lxc_string_join("/", (const char **)parts
, *dup
== '/');
291 lxc_free_array((void **)parts
, free
);
295 char *lxc_append_paths(const char *first
, const char *second
)
300 int pattern_type
= 0;
302 len
= strlen(first
) + strlen(second
) + 1;
303 if (second
[0] != '/') {
308 result
= calloc(1, len
);
312 if (pattern_type
== 0)
313 ret
= snprintf(result
, len
, "%s%s", first
, second
);
315 ret
= snprintf(result
, len
, "%s/%s", first
, second
);
316 if (ret
< 0 || (size_t)ret
>= len
) {
324 bool lxc_string_in_list(const char *needle
, const char *haystack
, char _sep
)
326 __do_free
char *str
= NULL
;
328 char sep
[2] = { _sep
, '\0' };
330 if (!haystack
|| !needle
)
333 str
= must_copy_string(haystack
);
334 lxc_iterate_parts(token
, str
, sep
)
335 if (strcmp(needle
, token
) == 0)
341 char **lxc_string_split(const char *string
, char _sep
)
343 __do_free
char *str
= NULL
;
345 char sep
[2] = {_sep
, '\0'};
346 char **tmp
= NULL
, **result
= NULL
;
347 size_t result_capacity
= 0;
348 size_t result_count
= 0;
352 return calloc(1, sizeof(char *));
354 str
= must_copy_string(string
);
355 lxc_iterate_parts(token
, str
, sep
) {
356 r
= lxc_grow_array((void ***)&result
, &result_capacity
, result_count
+ 1, 16);
360 result
[result_count
] = strdup(token
);
361 if (!result
[result_count
])
367 /* if we allocated too much, reduce it */
368 tmp
= realloc(result
, (result_count
+ 1) * sizeof(char *));
374 /* Make sure we don't return uninitialized memory. */
375 if (result_count
== 0)
382 lxc_free_array((void **)result
, free
);
387 static bool complete_word(char ***result
, char *start
, char *end
, size_t *cap
,
392 r
= lxc_grow_array((void ***)result
, cap
, 2 + *cnt
, 16);
396 (*result
)[*cnt
] = strndup(start
, end
- start
);
397 if (!(*result
)[*cnt
])
406 * Given a a string 'one two "three four"', split into three words,
407 * one, two, and "three four"
409 char **lxc_string_split_quoted(char *string
)
411 char *nextword
= string
, *p
, state
;
412 char **result
= NULL
;
413 size_t result_capacity
= 0;
414 size_t result_count
= 0;
416 if (!string
|| !*string
)
417 return calloc(1, sizeof(char *));
419 // TODO I'm *not* handling escaped quote
421 for (p
= string
; *p
; p
++) {
426 else if (*p
== '"' || *p
== '\'') {
436 complete_word(&result
, nextword
, p
, &result_capacity
, &result_count
);
444 complete_word(&result
, nextword
+1, p
, &result_capacity
, &result_count
);
453 complete_word(&result
, nextword
, p
, &result_capacity
, &result_count
);
455 return realloc(result
, (result_count
+ 1) * sizeof(char *));
458 char **lxc_string_split_and_trim(const char *string
, char _sep
)
460 __do_free
char *str
= NULL
;
462 char sep
[2] = { _sep
, '\0' };
463 char **result
= NULL
;
464 size_t result_capacity
= 0;
465 size_t result_count
= 0;
470 return calloc(1, sizeof(char *));
472 str
= must_copy_string(string
);
473 lxc_iterate_parts(token
, str
, sep
) {
474 while (token
[0] == ' ' || token
[0] == '\t')
478 while (i
> 0 && (token
[i
- 1] == ' ' || token
[i
- 1] == '\t')) {
483 r
= lxc_grow_array((void ***)&result
, &result_capacity
, result_count
+ 1, 16);
487 result
[result_count
] = strdup(token
);
488 if (!result
[result_count
])
494 /* if we allocated too much, reduce it */
495 return realloc(result
, (result_count
+ 1) * sizeof(char *));
499 lxc_free_array((void **)result
, free
);
504 void lxc_free_array(void **array
, lxc_free_fn element_free_fn
)
508 for (p
= array
; p
&& *p
; p
++)
514 int lxc_grow_array(void ***array
, size_t *capacity
, size_t new_size
, size_t capacity_increment
)
519 /* first time around, catch some trivial mistakes of the user
520 * only initializing one of these */
521 if (!*array
|| !*capacity
) {
526 new_capacity
= *capacity
;
527 while (new_size
+ 1 > new_capacity
)
528 new_capacity
+= capacity_increment
;
530 if (new_capacity
!= *capacity
) {
531 /* we have to reallocate */
532 new_array
= realloc(*array
, new_capacity
* sizeof(void *));
536 memset(&new_array
[*capacity
], 0, (new_capacity
- (*capacity
)) * sizeof(void *));
538 *capacity
= new_capacity
;
541 /* array has sufficient elements */
545 size_t lxc_array_len(void **array
)
550 for (p
= array
; p
&& *p
; p
++)
556 void **lxc_append_null_to_array(void **array
, size_t count
)
560 /* Append NULL to the array */
562 temp
= realloc(array
, (count
+ 1) * sizeof(*array
));
565 for (i
= 0; i
< count
; i
++)
578 static int lxc_append_null_to_list(void ***list
)
584 for (; (*list
)[newentry
]; newentry
++) {
588 tmp
= realloc(*list
, (newentry
+ 2) * sizeof(void **));
593 (*list
)[newentry
+ 1] = NULL
;
598 int lxc_append_string(char ***list
, char *entry
)
603 newentry
= lxc_append_null_to_list((void ***)list
);
607 copy
= strdup(entry
);
611 (*list
)[newentry
] = copy
;
616 int lxc_safe_uint(const char *numstr
, unsigned int *converted
)
619 unsigned long int uli
;
621 while (isspace(*numstr
))
628 uli
= strtoul(numstr
, &err
, 0);
629 if (errno
== ERANGE
&& uli
== ULONG_MAX
)
632 if (err
== numstr
|| *err
!= '\0')
638 *converted
= (unsigned int)uli
;
642 int lxc_safe_ulong(const char *numstr
, unsigned long *converted
)
645 unsigned long int uli
;
647 while (isspace(*numstr
))
654 uli
= strtoul(numstr
, &err
, 0);
655 if (errno
== ERANGE
&& uli
== ULONG_MAX
)
658 if (err
== numstr
|| *err
!= '\0')
665 int lxc_safe_uint64(const char *numstr
, uint64_t *converted
, int base
)
670 while (isspace(*numstr
))
677 u
= strtoull(numstr
, &err
, base
);
678 if (errno
== ERANGE
&& u
== UINT64_MAX
)
681 if (err
== numstr
|| *err
!= '\0')
688 int lxc_safe_int(const char *numstr
, int *converted
)
694 sli
= strtol(numstr
, &err
, 0);
695 if (errno
== ERANGE
&& (sli
== LONG_MAX
|| sli
== LONG_MIN
))
698 if (errno
!= 0 && sli
== 0)
701 if (err
== numstr
|| *err
!= '\0')
704 if (sli
> INT_MAX
|| sli
< INT_MIN
)
707 *converted
= (int)sli
;
711 int lxc_safe_long(const char *numstr
, long int *converted
)
717 sli
= strtol(numstr
, &err
, 0);
718 if (errno
== ERANGE
&& (sli
== LONG_MAX
|| sli
== LONG_MIN
))
721 if (errno
!= 0 && sli
== 0)
724 if (err
== numstr
|| *err
!= '\0')
731 int lxc_safe_long_long(const char *numstr
, long long int *converted
)
734 signed long long int sli
;
737 sli
= strtoll(numstr
, &err
, 0);
738 if (errno
== ERANGE
&& (sli
== LLONG_MAX
|| sli
== LLONG_MIN
))
741 if (errno
!= 0 && sli
== 0)
744 if (err
== numstr
|| *err
!= '\0')
751 char *must_concat(const char *first
, ...)
755 size_t cur_len
, it_len
;
757 dest
= must_copy_string(first
);
758 cur_len
= it_len
= strlen(first
);
760 va_start(args
, first
);
761 while ((cur
= va_arg(args
, char *)) != NULL
) {
762 it_len
= strlen(cur
);
764 dest
= must_realloc(dest
, cur_len
+ it_len
+ 1);
766 (void)memcpy(dest
+ cur_len
, cur
, it_len
);
771 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
);
794 dest
= must_realloc(dest
, full_len
+ 1);
797 memcpy(dest
+ cur_len
, "/", 1);
801 memcpy(dest
+ cur_len
, cur
, buf_len
);
806 dest
[cur_len
] = '\0';
810 char *must_append_path(char *first
, ...)
819 full_len
= strlen(first
);
822 va_start(args
, first
);
823 while ((cur
= va_arg(args
, char *)) != NULL
) {
824 buf_len
= strlen(cur
);
830 dest
= must_realloc(dest
, full_len
+ 1);
833 memcpy(dest
+ cur_len
, "/", 1);
837 memcpy(dest
+ cur_len
, cur
, buf_len
);
842 dest
[cur_len
] = '\0';
846 char *must_copy_string(const char *entry
)
860 void *must_realloc(void *orig
, size_t sz
)
865 ret
= realloc(orig
, sz
);
871 int parse_byte_size_string(const char *s
, int64_t *converted
)
875 int64_t mltpl
, overflow
;
877 char dup
[INTTYPE_TO_STRLEN(int64_t)];
878 char suffix
[3] = {0};
880 if (!s
|| !strcmp(s
, ""))
883 end
= stpncpy(dup
, s
, sizeof(dup
) - 1);
887 if (isdigit(*(end
- 1)))
889 else if (isalpha(*(end
- 1)))
894 if (suffix_len
> 0 && (end
- 2) == dup
&& !isdigit(*(end
- 2)))
897 if (suffix_len
> 0 && isalpha(*(end
- 2)))
900 if (suffix_len
> 0) {
901 memcpy(suffix
, end
- suffix_len
, suffix_len
);
902 *(suffix
+ suffix_len
) = '\0';
903 *(end
- suffix_len
) = '\0';
905 dup
[lxc_char_right_gc(dup
, strlen(dup
))] = '\0';
907 ret
= lxc_safe_long_long(dup
, &conv
);
911 if (suffix_len
!= 2) {
916 if (strcasecmp(suffix
, "KB") == 0)
918 else if (strcasecmp(suffix
, "MB") == 0)
920 else if (strcasecmp(suffix
, "GB") == 0)
921 mltpl
= 1024 * 1024 * 1024;
925 overflow
= conv
* mltpl
;
926 if (conv
!= 0 && (overflow
/ conv
) != mltpl
)
929 *converted
= overflow
;
933 void remove_trailing_newlines(char *l
)
940 while (--p
>= l
&& *p
== '\n')
944 int lxc_char_left_gc(const char *buffer
, size_t len
)
948 for (i
= 0; i
< len
; i
++) {
949 if (buffer
[i
] == ' ' ||
959 int lxc_char_right_gc(const char *buffer
, size_t len
)
963 for (i
= len
- 1; i
>= 0; i
--) {
964 if (buffer
[i
] == ' ' ||
976 char *lxc_trim_whitespace_in_place(char *buffer
)
978 buffer
+= lxc_char_left_gc(buffer
, strlen(buffer
));
979 buffer
[lxc_char_right_gc(buffer
, strlen(buffer
))] = '\0';
983 int lxc_is_line_empty(const char *line
)
986 size_t len
= strlen(line
);
988 for (i
= 0; i
< len
; i
++)
989 if (line
[i
] != ' ' && line
[i
] != '\t' &&
990 line
[i
] != '\n' && line
[i
] != '\r' &&
991 line
[i
] != '\f' && line
[i
] != '\0')
996 void remove_trailing_slashes(char *p
)
999 while (--l
>= 0 && (p
[l
] == '/' || p
[l
] == '\n'))