]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/string_utils.c
build: add src/include to build and simplify header inclusions
[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
58db1a61 38#include "strlcpy.h"
37ef15bb
CB
39#endif
40
41#ifndef HAVE_STRLCAT
58db1a61 42#include "strlcat.h"
37ef15bb
CB
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
47f5be06
L
407 if (result == NULL)
408 return calloc(1, sizeof(char *));
409
37ef15bb
CB
410 return realloc(result, (result_count + 1) * sizeof(char *));
411}
412
413char **lxc_string_split_and_trim(const char *string, char _sep)
414{
97f35ce6
CB
415 __do_free char *str = NULL;
416 char *token;
37ef15bb
CB
417 char sep[2] = { _sep, '\0' };
418 char **result = NULL;
419 size_t result_capacity = 0;
420 size_t result_count = 0;
421 int r, saved_errno;
422 size_t i = 0;
37ef15bb
CB
423
424 if (!string)
425 return calloc(1, sizeof(char *));
426
97f35ce6 427 str = must_copy_string(string);
37ef15bb
CB
428 lxc_iterate_parts(token, str, sep) {
429 while (token[0] == ' ' || token[0] == '\t')
430 token++;
431
432 i = strlen(token);
433 while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
434 token[i - 1] = '\0';
435 i--;
436 }
437
438 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
439 if (r < 0)
440 goto error_out;
441
442 result[result_count] = strdup(token);
443 if (!result[result_count])
444 goto error_out;
445
446 result_count++;
447 }
448
47f5be06
L
449 if (result == NULL)
450 return calloc(1, sizeof(char *));
451
37ef15bb
CB
452 /* if we allocated too much, reduce it */
453 return realloc(result, (result_count + 1) * sizeof(char *));
454
455error_out:
456 saved_errno = errno;
457 lxc_free_array((void **)result, free);
458 errno = saved_errno;
459 return NULL;
460}
461
462void lxc_free_array(void **array, lxc_free_fn element_free_fn)
463{
464 void **p;
465
466 for (p = array; p && *p; p++)
467 element_free_fn(*p);
468
469 free((void*)array);
470}
471
472int lxc_grow_array(void ***array, size_t *capacity, size_t new_size, size_t capacity_increment)
473{
474 size_t new_capacity;
475 void **new_array;
476
477 /* first time around, catch some trivial mistakes of the user
478 * only initializing one of these */
479 if (!*array || !*capacity) {
480 *array = NULL;
481 *capacity = 0;
482 }
483
484 new_capacity = *capacity;
485 while (new_size + 1 > new_capacity)
486 new_capacity += capacity_increment;
487
488 if (new_capacity != *capacity) {
489 /* we have to reallocate */
490 new_array = realloc(*array, new_capacity * sizeof(void *));
491 if (!new_array)
492 return -1;
493
494 memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * sizeof(void *));
495 *array = new_array;
496 *capacity = new_capacity;
497 }
498
499 /* array has sufficient elements */
500 return 0;
501}
502
503size_t lxc_array_len(void **array)
504{
505 void **p;
506 size_t result = 0;
507
508 for (p = array; p && *p; p++)
509 result++;
510
511 return result;
512}
513
514void **lxc_append_null_to_array(void **array, size_t count)
515{
516 void **temp;
517
518 /* Append NULL to the array */
519 if (count) {
520 temp = realloc(array, (count + 1) * sizeof(*array));
521 if (!temp) {
522 size_t i;
523 for (i = 0; i < count; i++)
524 free(array[i]);
525 free(array);
526 return NULL;
527 }
528
529 array = temp;
530 array[count] = NULL;
531 }
532
533 return array;
534}
535
536static int lxc_append_null_to_list(void ***list)
537{
538 int newentry = 0;
539 void **tmp;
540
541 if (*list)
542 for (; (*list)[newentry]; newentry++) {
543 ;
544 }
545
546 tmp = realloc(*list, (newentry + 2) * sizeof(void **));
547 if (!tmp)
548 return -1;
549
550 *list = tmp;
551 (*list)[newentry + 1] = NULL;
552
553 return newentry;
554}
555
556int lxc_append_string(char ***list, char *entry)
557{
558 char *copy;
559 int newentry;
560
561 newentry = lxc_append_null_to_list((void ***)list);
562 if (newentry < 0)
563 return -1;
564
565 copy = strdup(entry);
566 if (!copy)
567 return -1;
568
569 (*list)[newentry] = copy;
570
571 return 0;
572}
573
574int lxc_safe_uint(const char *numstr, unsigned int *converted)
575{
576 char *err = NULL;
577 unsigned long int uli;
578
579 while (isspace(*numstr))
580 numstr++;
581
582 if (*numstr == '-')
583 return -EINVAL;
584
585 errno = 0;
586 uli = strtoul(numstr, &err, 0);
587 if (errno == ERANGE && uli == ULONG_MAX)
588 return -ERANGE;
589
590 if (err == numstr || *err != '\0')
591 return -EINVAL;
592
593 if (uli > UINT_MAX)
594 return -ERANGE;
595
596 *converted = (unsigned int)uli;
597 return 0;
598}
599
600int lxc_safe_ulong(const char *numstr, unsigned long *converted)
601{
602 char *err = NULL;
603 unsigned long int uli;
604
605 while (isspace(*numstr))
606 numstr++;
607
608 if (*numstr == '-')
609 return -EINVAL;
610
611 errno = 0;
612 uli = strtoul(numstr, &err, 0);
613 if (errno == ERANGE && uli == ULONG_MAX)
614 return -ERANGE;
615
616 if (err == numstr || *err != '\0')
617 return -EINVAL;
618
619 *converted = uli;
620 return 0;
621}
622
623int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base)
624{
625 char *err = NULL;
626 uint64_t u;
627
628 while (isspace(*numstr))
629 numstr++;
630
631 if (*numstr == '-')
632 return -EINVAL;
633
634 errno = 0;
635 u = strtoull(numstr, &err, base);
62fc8403 636 if (errno == ERANGE && u == UINT64_MAX)
37ef15bb
CB
637 return -ERANGE;
638
639 if (err == numstr || *err != '\0')
640 return -EINVAL;
641
642 *converted = u;
643 return 0;
644}
645
59f5a103
CB
646int lxc_safe_int64_residual(const char *restrict numstr,
647 int64_t *restrict converted, int base,
648 char *restrict residual, size_t residual_len)
70fd7fc9
CB
649{
650 char *remaining = NULL;
651 int64_t u;
652
653 if (residual && residual_len == 0)
654 return ret_errno(EINVAL);
655
656 if (!residual && residual_len != 0)
657 return ret_errno(EINVAL);
658
c45833e3
CB
659 memset(residual, 0, residual_len);
660
70fd7fc9
CB
661 while (isspace(*numstr))
662 numstr++;
663
664 errno = 0;
665 u = strtoll(numstr, &remaining, base);
666 if (errno == ERANGE && u == INT64_MAX)
90e69d71 667 return ret_errno(ERANGE);
70fd7fc9
CB
668
669 if (remaining == numstr)
670 return -EINVAL;
671
672 if (residual) {
673 size_t len = 0;
674
c45833e3 675 if (*remaining == '\0')
70fd7fc9 676 goto out;
70fd7fc9
CB
677
678 len = strlen(remaining);
679 if (len >= residual_len)
90e69d71 680 return ret_errno(EINVAL);
70fd7fc9
CB
681
682 memcpy(residual, remaining, len);
683 } else if (*remaining != '\0') {
90e69d71 684 return ret_errno(EINVAL);
70fd7fc9
CB
685 }
686
687out:
688 *converted = u;
689 return 0;
690}
691
37ef15bb
CB
692int lxc_safe_int(const char *numstr, int *converted)
693{
694 char *err = NULL;
695 signed long int sli;
696
697 errno = 0;
698 sli = strtol(numstr, &err, 0);
699 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
700 return -ERANGE;
701
702 if (errno != 0 && sli == 0)
703 return -EINVAL;
704
705 if (err == numstr || *err != '\0')
706 return -EINVAL;
707
708 if (sli > INT_MAX || sli < INT_MIN)
709 return -ERANGE;
710
711 *converted = (int)sli;
712 return 0;
713}
714
715int lxc_safe_long(const char *numstr, long int *converted)
716{
717 char *err = NULL;
718 signed long int sli;
719
720 errno = 0;
721 sli = strtol(numstr, &err, 0);
722 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
723 return -ERANGE;
724
725 if (errno != 0 && sli == 0)
726 return -EINVAL;
727
728 if (err == numstr || *err != '\0')
729 return -EINVAL;
730
731 *converted = sli;
732 return 0;
733}
734
735int lxc_safe_long_long(const char *numstr, long long int *converted)
736{
737 char *err = NULL;
738 signed long long int sli;
739
740 errno = 0;
741 sli = strtoll(numstr, &err, 0);
742 if (errno == ERANGE && (sli == LLONG_MAX || sli == LLONG_MIN))
743 return -ERANGE;
744
745 if (errno != 0 && sli == 0)
746 return -EINVAL;
747
748 if (err == numstr || *err != '\0')
749 return -EINVAL;
750
751 *converted = sli;
752 return 0;
753}
754
fe70edee 755char *must_concat(size_t *len, const char *first, ...)
37ef15bb
CB
756{
757 va_list args;
758 char *cur, *dest;
759 size_t cur_len, it_len;
760
761 dest = must_copy_string(first);
762 cur_len = it_len = strlen(first);
763
764 va_start(args, first);
765 while ((cur = va_arg(args, char *)) != NULL) {
766 it_len = strlen(cur);
767
768 dest = must_realloc(dest, cur_len + it_len + 1);
769
770 (void)memcpy(dest + cur_len, cur, it_len);
771 cur_len += it_len;
772 }
773 va_end(args);
774
b9bb8bbb 775 dest[cur_len] = '\0';
fe70edee
CB
776 if (len)
777 *len = cur_len;
37ef15bb
CB
778 return dest;
779}
780
781char *must_make_path(const char *first, ...)
782{
783 va_list args;
784 char *cur, *dest;
785 size_t full_len = strlen(first);
786 size_t buf_len;
7cfde20f 787 size_t cur_len;
37ef15bb
CB
788
789 dest = must_copy_string(first);
7cfde20f 790 cur_len = full_len;
37ef15bb
CB
791
792 va_start(args, first);
793 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 794 buf_len = strlen(cur);
19281251
CB
795 if (buf_len == 0)
796 continue;
7cfde20f 797
798 full_len += buf_len;
37ef15bb
CB
799 if (cur[0] != '/')
800 full_len++;
801
7cfde20f 802 dest = must_realloc(dest, full_len + 1);
37ef15bb 803
7cfde20f 804 if (cur[0] != '/') {
805 memcpy(dest + cur_len, "/", 1);
806 cur_len++;
807 }
808
809 memcpy(dest + cur_len, cur, buf_len);
810 cur_len += buf_len;
37ef15bb
CB
811 }
812 va_end(args);
813
7cfde20f 814 dest[cur_len] = '\0';
37ef15bb
CB
815 return dest;
816}
817
818char *must_append_path(char *first, ...)
819{
820 char *cur;
821 size_t full_len;
822 va_list args;
823 char *dest = first;
824 size_t buf_len;
7cfde20f 825 size_t cur_len;
37ef15bb
CB
826
827 full_len = strlen(first);
7cfde20f 828 cur_len = full_len;
829
37ef15bb
CB
830 va_start(args, first);
831 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 832 buf_len = strlen(cur);
833
834 full_len += buf_len;
37ef15bb
CB
835 if (cur[0] != '/')
836 full_len++;
837
7cfde20f 838 dest = must_realloc(dest, full_len + 1);
37ef15bb 839
7cfde20f 840 if (cur[0] != '/') {
841 memcpy(dest + cur_len, "/", 1);
842 cur_len++;
843 }
844
845 memcpy(dest + cur_len, cur, buf_len);
846 cur_len += buf_len;
37ef15bb
CB
847 }
848 va_end(args);
849
7cfde20f 850 dest[cur_len] = '\0';
37ef15bb
CB
851 return dest;
852}
853
854char *must_copy_string(const char *entry)
855{
856 char *ret;
857
858 if (!entry)
859 return NULL;
860
861 do {
862 ret = strdup(entry);
863 } while (!ret);
864
865 return ret;
866}
867
868void *must_realloc(void *orig, size_t sz)
869{
870 void *ret;
871
872 do {
873 ret = realloc(orig, sz);
874 } while (!ret);
875
876 return ret;
877}
878
4c5479d2 879int parse_byte_size_string(const char *s, long long int *converted)
37ef15bb
CB
880{
881 int ret, suffix_len;
4c5479d2 882 long long int conv, mltpl;
37ef15bb 883 char *end;
f6727edb 884 char dup[INTTYPE_TO_STRLEN(long long int)] = {0};
37ef15bb 885 char suffix[3] = {0};
6d345aa4 886 size_t len;
37ef15bb 887
6d345aa4 888 if (!s)
3f5c01db 889 return ret_errno(EINVAL);
37ef15bb 890
6d345aa4
EV
891 len = strlen(s);
892 if (len == 0 || len > sizeof(dup) - 1)
3f5c01db 893 return ret_errno(EINVAL);
37ef15bb 894
6d345aa4
EV
895 memcpy(dup, s, len);
896
897 end = dup + len;
37ef15bb
CB
898 if (isdigit(*(end - 1)))
899 suffix_len = 0;
900 else if (isalpha(*(end - 1)))
901 suffix_len = 1;
902 else
3f5c01db 903 return ret_errno(EINVAL);
37ef15bb 904
b2480b29
CB
905 if (suffix_len > 0) {
906 if ((end - 1) == dup)
907 return ret_errno(EINVAL);
37ef15bb 908
b2480b29
CB
909 if ((end - 2) == dup) {
910 if (isalpha(*(end - 2)))
911 return ret_errno(EINVAL);
912 /* 1B */
913 } else {
914 if (isalpha(*(end - 2))) /* 12MB */
915 suffix_len++;
916
917 /* 12B */
918 }
37ef15bb 919
37ef15bb
CB
920 memcpy(suffix, end - suffix_len, suffix_len);
921 *(suffix + suffix_len) = '\0';
922 *(end - suffix_len) = '\0';
923 }
b2480b29 924
37ef15bb
CB
925 dup[lxc_char_right_gc(dup, strlen(dup))] = '\0';
926
927 ret = lxc_safe_long_long(dup, &conv);
3f5c01db
CB
928 if (ret)
929 return ret;
37ef15bb
CB
930
931 if (suffix_len != 2) {
932 *converted = conv;
933 return 0;
934 }
935
936 if (strcasecmp(suffix, "KB") == 0)
937 mltpl = 1024;
938 else if (strcasecmp(suffix, "MB") == 0)
939 mltpl = 1024 * 1024;
940 else if (strcasecmp(suffix, "GB") == 0)
941 mltpl = 1024 * 1024 * 1024;
942 else
3f5c01db 943 return ret_errno(EINVAL);
37ef15bb 944
4c5479d2 945 if (check_mul_overflow(conv, mltpl, converted))
3f5c01db 946 return ret_errno(ERANGE);
37ef15bb 947
37ef15bb
CB
948 return 0;
949}
950
951void remove_trailing_newlines(char *l)
952{
953 char *p = l;
954
955 while (*p)
956 p++;
957
958 while (--p >= l && *p == '\n')
959 *p = '\0';
960}
961
962int lxc_char_left_gc(const char *buffer, size_t len)
963{
964 size_t i;
965
966 for (i = 0; i < len; i++) {
967 if (buffer[i] == ' ' ||
968 buffer[i] == '\t')
969 continue;
970
971 return i;
972 }
973
974 return 0;
975}
976
977int lxc_char_right_gc(const char *buffer, size_t len)
978{
979 int i;
980
981 for (i = len - 1; i >= 0; i--) {
982 if (buffer[i] == ' ' ||
983 buffer[i] == '\t' ||
984 buffer[i] == '\n' ||
985 buffer[i] == '\0')
986 continue;
987
988 return i + 1;
989 }
990
991 return 0;
992}
993
994char *lxc_trim_whitespace_in_place(char *buffer)
995{
996 buffer += lxc_char_left_gc(buffer, strlen(buffer));
997 buffer[lxc_char_right_gc(buffer, strlen(buffer))] = '\0';
998 return buffer;
999}
1000
1001int lxc_is_line_empty(const char *line)
1002{
1003 int i;
1004 size_t len = strlen(line);
1005
1006 for (i = 0; i < len; i++)
1007 if (line[i] != ' ' && line[i] != '\t' &&
1008 line[i] != '\n' && line[i] != '\r' &&
1009 line[i] != '\f' && line[i] != '\0')
1010 return 0;
1011 return 1;
1012}
dca12ddf
CB
1013
1014void remove_trailing_slashes(char *p)
1015{
1016 int l = strlen(p);
1017 while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
1018 p[l] = '\0';
1019}