]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/string_utils.c
github: Update for main branch
[mirror_lxc.git] / src / lxc / string_utils.c
CommitLineData
cc73685d 1/* SPDX-License-Identifier: LGPL-2.1+ */
37ef15bb 2
b4e5e90b
CB
3#include "config.h"
4
37ef15bb
CB
5#include <ctype.h>
6#include <dirent.h>
7#include <errno.h>
8#include <fcntl.h>
9#include <grp.h>
10#include <inttypes.h>
11#include <libgen.h>
12#include <pthread.h>
c4a090be 13#include <stdarg.h>
37ef15bb
CB
14#include <stddef.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
37ef15bb
CB
18#include <sys/mman.h>
19#include <sys/mount.h>
20#include <sys/param.h>
21#include <sys/prctl.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/wait.h>
d38dd64a 25#include <unistd.h>
37ef15bb 26
b4e5e90b 27#include "string_utils.h"
f1eacafb 28#include "macro.h"
97f35ce6 29#include "memory_utils.h"
37ef15bb 30
db4af8c5 31#if !HAVE_STRLCPY
58db1a61 32#include "strlcpy.h"
37ef15bb
CB
33#endif
34
db4af8c5 35#if !HAVE_STRLCAT
58db1a61 36#include "strlcat.h"
37ef15bb
CB
37#endif
38
37ef15bb
CB
39char **lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup)
40{
41 va_list ap2;
42 size_t count = 1 + skip;
43 char **result;
44
45 /* first determine size of argument list, we don't want to reallocate
46 * constantly...
47 */
48 va_copy(ap2, ap);
51a8a74c 49 for (;;) {
37ef15bb
CB
50 char *arg = va_arg(ap2, char *);
51 if (!arg)
52 break;
53 count++;
54 }
55 va_end(ap2);
56
57 result = calloc(count, sizeof(char *));
58 if (!result)
59 return NULL;
60
61 count = skip;
51a8a74c 62 for (;;) {
37ef15bb
CB
63 char *arg = va_arg(ap, char *);
64 if (!arg)
65 break;
66 arg = do_strdup ? strdup(arg) : arg;
67 if (!arg)
68 goto oom;
69 result[count++] = arg;
70 }
71
72 /* calloc has already set last element to NULL*/
73 return result;
74
75oom:
76 free(result);
77 return NULL;
78}
79
80const char **lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
81{
82 return (const char **)lxc_va_arg_list_to_argv(ap, skip, 0);
83}
84
85char *lxc_string_replace(const char *needle, const char *replacement,
86 const char *haystack)
87{
88 ssize_t len = -1, saved_len = -1;
89 char *result = NULL;
90 size_t replacement_len = strlen(replacement);
91 size_t needle_len = strlen(needle);
92
93 /* should be executed exactly twice */
94 while (len == -1 || result == NULL) {
95 char *p;
96 char *last_p;
97 ssize_t part_len;
98
99 if (len != -1) {
100 result = calloc(1, len + 1);
101 if (!result)
102 return NULL;
103
104 saved_len = len;
105 }
106
107 len = 0;
108
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);
114
115 len += part_len;
116
117 if (result && replacement_len > 0)
118 memcpy(&result[len], replacement,
119 replacement_len);
120
121 len += replacement_len;
122 p += needle_len;
123 }
124
125 part_len = strlen(last_p);
126 if (result && part_len > 0)
127 memcpy(&result[len], last_p, part_len);
128
129 len += part_len;
130 }
131
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) {
136 free(result);
137 return NULL;
138 }
139
140 /* make sure we didn't overwrite any buffer,
141 * due to calloc the string should be 0-terminated */
142 if (result[len] != '\0') {
143 free(result);
144 return NULL;
145 }
146
147 return result;
148}
149
150bool lxc_string_in_array(const char *needle, const char **haystack)
151{
152 for (; haystack && *haystack; haystack++)
7ba62a5e 153 if (strequal(needle, *haystack))
37ef15bb
CB
154 return true;
155
156 return false;
157}
158
159char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix)
160{
161 char *result;
162 char **p;
163 size_t sep_len = strlen(sep);
164 size_t result_len = use_as_prefix * sep_len;
165 size_t buf_len;
166
167 /* calculate new string length */
168 for (p = (char **)parts; *p; p++)
169 result_len += (p > (char **)parts) * sep_len + strlen(*p);
170
171 buf_len = result_len + 1;
172 result = calloc(buf_len, 1);
173 if (!result)
174 return NULL;
175
176 if (use_as_prefix)
177 (void)strlcpy(result, sep, buf_len);
178
179 for (p = (char **)parts; *p; p++) {
180 if (p > (char **)parts)
181 (void)strlcat(result, sep, buf_len);
182
183 (void)strlcat(result, *p, buf_len);
184 }
185
186 return result;
187}
188
28e54be1 189/* taken from systemd */
539c3977 190char *lxc_path_simplify(const char *path)
37ef15bb 191{
28e54be1
CB
192 __do_free char *path_new = NULL;
193 char *f, *t;
194 bool slash = false, ignore_slash = false, absolute;
37ef15bb 195
28e54be1
CB
196 path_new = strdup(path);
197 if (!path_new)
37ef15bb
CB
198 return NULL;
199
28e54be1
CB
200 if (is_empty_string(path_new))
201 return move_ptr(path_new);
202
203 absolute = abspath(path_new);
204
205 f = path_new;
4deaa28c 206 if (*f == '.' && (f[1] == 0 || f[1] == '/')) {
28e54be1
CB
207 ignore_slash = true;
208 f++;
37ef15bb
CB
209 }
210
28e54be1 211 for (t = path_new; *f; f++) {
37ef15bb 212
28e54be1
CB
213 if (*f == '/') {
214 slash = true;
215 continue;
216 }
37ef15bb 217
28e54be1 218 if (slash) {
4deaa28c 219 if (*f == '.' && (f[1] == 0 || f[1] == '/'))
28e54be1 220 continue;
37ef15bb 221
28e54be1
CB
222 slash = false;
223 if (ignore_slash)
224 ignore_slash = false;
225 else
226 *(t++) = '/';
37ef15bb 227 }
28e54be1
CB
228
229 *(t++) = *f;
230 }
231
232 if (t == path_new) {
233 if (absolute)
234 *(t++) = '/';
235 else
236 *(t++) = '.';
37ef15bb
CB
237 }
238
28e54be1
CB
239 *t = 0;
240 return move_ptr(path_new);
37ef15bb
CB
241}
242
243char *lxc_append_paths(const char *first, const char *second)
244{
4af24cb7 245 __do_free char *result = NULL;
37ef15bb
CB
246 int ret;
247 size_t len;
d07545c7 248 int pattern_type = 0;
37ef15bb
CB
249
250 len = strlen(first) + strlen(second) + 1;
251 if (second[0] != '/') {
252 len += 1;
d07545c7 253 pattern_type = 1;
37ef15bb
CB
254 }
255
4af24cb7 256 result = zalloc(len);
37ef15bb
CB
257 if (!result)
258 return NULL;
259
d07545c7 260 if (pattern_type == 0)
4af24cb7 261 ret = strnprintf(result, len, "%s%s", first, second);
d07545c7 262 else
4af24cb7
CB
263 ret = strnprintf(result, len, "%s/%s", first, second);
264 if (ret < 0)
37ef15bb 265 return NULL;
37ef15bb 266
4af24cb7 267 return move_ptr(result);
37ef15bb
CB
268}
269
270bool lxc_string_in_list(const char *needle, const char *haystack, char _sep)
271{
97f35ce6
CB
272 __do_free char *str = NULL;
273 char *token;
37ef15bb 274 char sep[2] = { _sep, '\0' };
37ef15bb
CB
275
276 if (!haystack || !needle)
277 return 0;
278
97f35ce6 279 str = must_copy_string(haystack);
37ef15bb 280 lxc_iterate_parts(token, str, sep)
7ba62a5e 281 if (strequal(needle, token))
37ef15bb
CB
282 return 1;
283
284 return 0;
285}
286
287char **lxc_string_split(const char *string, char _sep)
288{
97f35ce6
CB
289 __do_free char *str = NULL;
290 char *token;
37ef15bb
CB
291 char sep[2] = {_sep, '\0'};
292 char **tmp = NULL, **result = NULL;
293 size_t result_capacity = 0;
294 size_t result_count = 0;
295 int r, saved_errno;
37ef15bb
CB
296
297 if (!string)
298 return calloc(1, sizeof(char *));
299
97f35ce6 300 str = must_copy_string(string);
37ef15bb
CB
301 lxc_iterate_parts(token, str, sep) {
302 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
303 if (r < 0)
304 goto error_out;
305
306 result[result_count] = strdup(token);
307 if (!result[result_count])
308 goto error_out;
309
310 result_count++;
311 }
312
313 /* if we allocated too much, reduce it */
314 tmp = realloc(result, (result_count + 1) * sizeof(char *));
315 if (!tmp)
316 goto error_out;
317
318 result = tmp;
319
320 /* Make sure we don't return uninitialized memory. */
321 if (result_count == 0)
322 *result = NULL;
323
324 return result;
325
326error_out:
327 saved_errno = errno;
328 lxc_free_array((void **)result, free);
329 errno = saved_errno;
330 return NULL;
331}
332
333static bool complete_word(char ***result, char *start, char *end, size_t *cap,
334 size_t *cnt)
335{
336 int r;
337
338 r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16);
339 if (r < 0)
340 return false;
341
342 (*result)[*cnt] = strndup(start, end - start);
343 if (!(*result)[*cnt])
344 return false;
345
346 (*cnt)++;
347
348 return true;
349}
350
351/*
352 * Given a a string 'one two "three four"', split into three words,
353 * one, two, and "three four"
354 */
355char **lxc_string_split_quoted(char *string)
356{
357 char *nextword = string, *p, state;
358 char **result = NULL;
359 size_t result_capacity = 0;
360 size_t result_count = 0;
361
362 if (!string || !*string)
363 return calloc(1, sizeof(char *));
364
365 // TODO I'm *not* handling escaped quote
366 state = ' ';
367 for (p = string; *p; p++) {
368 switch(state) {
369 case ' ':
370 if (isspace(*p))
371 continue;
372 else if (*p == '"' || *p == '\'') {
373 nextword = p;
374 state = *p;
375 continue;
376 }
377 nextword = p;
378 state = 'a';
379 continue;
380 case 'a':
381 if (isspace(*p)) {
382 complete_word(&result, nextword, p, &result_capacity, &result_count);
383 state = ' ';
384 continue;
385 }
386 continue;
387 case '"':
388 case '\'':
389 if (*p == state) {
390 complete_word(&result, nextword+1, p, &result_capacity, &result_count);
391 state = ' ';
392 continue;
393 }
394 continue;
395 }
396 }
397
398 if (state == 'a')
399 complete_word(&result, nextword, p, &result_capacity, &result_count);
400
47f5be06
L
401 if (result == NULL)
402 return calloc(1, sizeof(char *));
403
37ef15bb
CB
404 return realloc(result, (result_count + 1) * sizeof(char *));
405}
406
407char **lxc_string_split_and_trim(const char *string, char _sep)
408{
97f35ce6
CB
409 __do_free char *str = NULL;
410 char *token;
37ef15bb
CB
411 char sep[2] = { _sep, '\0' };
412 char **result = NULL;
413 size_t result_capacity = 0;
414 size_t result_count = 0;
415 int r, saved_errno;
416 size_t i = 0;
37ef15bb
CB
417
418 if (!string)
419 return calloc(1, sizeof(char *));
420
97f35ce6 421 str = must_copy_string(string);
37ef15bb
CB
422 lxc_iterate_parts(token, str, sep) {
423 while (token[0] == ' ' || token[0] == '\t')
424 token++;
425
426 i = strlen(token);
427 while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
428 token[i - 1] = '\0';
429 i--;
430 }
431
432 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
433 if (r < 0)
434 goto error_out;
435
436 result[result_count] = strdup(token);
437 if (!result[result_count])
438 goto error_out;
439
440 result_count++;
441 }
442
47f5be06
L
443 if (result == NULL)
444 return calloc(1, sizeof(char *));
445
37ef15bb
CB
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
59f5a103
CB
640int lxc_safe_int64_residual(const char *restrict numstr,
641 int64_t *restrict converted, int base,
642 char *restrict residual, size_t residual_len)
70fd7fc9
CB
643{
644 char *remaining = NULL;
645 int64_t u;
646
647 if (residual && residual_len == 0)
648 return ret_errno(EINVAL);
649
650 if (!residual && residual_len != 0)
651 return ret_errno(EINVAL);
652
c45833e3
CB
653 memset(residual, 0, residual_len);
654
70fd7fc9
CB
655 while (isspace(*numstr))
656 numstr++;
657
658 errno = 0;
659 u = strtoll(numstr, &remaining, base);
660 if (errno == ERANGE && u == INT64_MAX)
90e69d71 661 return ret_errno(ERANGE);
70fd7fc9
CB
662
663 if (remaining == numstr)
664 return -EINVAL;
665
666 if (residual) {
667 size_t len = 0;
668
c45833e3 669 if (*remaining == '\0')
70fd7fc9 670 goto out;
70fd7fc9
CB
671
672 len = strlen(remaining);
673 if (len >= residual_len)
90e69d71 674 return ret_errno(EINVAL);
70fd7fc9
CB
675
676 memcpy(residual, remaining, len);
677 } else if (*remaining != '\0') {
90e69d71 678 return ret_errno(EINVAL);
70fd7fc9
CB
679 }
680
681out:
682 *converted = u;
683 return 0;
684}
685
37ef15bb
CB
686int lxc_safe_int(const char *numstr, int *converted)
687{
688 char *err = NULL;
689 signed long int sli;
690
691 errno = 0;
692 sli = strtol(numstr, &err, 0);
693 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
694 return -ERANGE;
695
696 if (errno != 0 && sli == 0)
697 return -EINVAL;
698
699 if (err == numstr || *err != '\0')
700 return -EINVAL;
701
702 if (sli > INT_MAX || sli < INT_MIN)
703 return -ERANGE;
704
705 *converted = (int)sli;
706 return 0;
707}
708
709int lxc_safe_long(const char *numstr, long int *converted)
710{
711 char *err = NULL;
712 signed long int sli;
713
714 errno = 0;
715 sli = strtol(numstr, &err, 0);
716 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
717 return -ERANGE;
718
719 if (errno != 0 && sli == 0)
720 return -EINVAL;
721
722 if (err == numstr || *err != '\0')
723 return -EINVAL;
724
725 *converted = sli;
726 return 0;
727}
728
729int lxc_safe_long_long(const char *numstr, long long int *converted)
730{
731 char *err = NULL;
732 signed long long int sli;
733
734 errno = 0;
735 sli = strtoll(numstr, &err, 0);
736 if (errno == ERANGE && (sli == LLONG_MAX || sli == LLONG_MIN))
737 return -ERANGE;
738
739 if (errno != 0 && sli == 0)
740 return -EINVAL;
741
742 if (err == numstr || *err != '\0')
743 return -EINVAL;
744
745 *converted = sli;
746 return 0;
747}
748
fe70edee 749char *must_concat(size_t *len, const char *first, ...)
37ef15bb
CB
750{
751 va_list args;
752 char *cur, *dest;
753 size_t cur_len, it_len;
754
755 dest = must_copy_string(first);
756 cur_len = it_len = strlen(first);
757
758 va_start(args, first);
759 while ((cur = va_arg(args, char *)) != NULL) {
760 it_len = strlen(cur);
761
762 dest = must_realloc(dest, cur_len + it_len + 1);
763
764 (void)memcpy(dest + cur_len, cur, it_len);
765 cur_len += it_len;
766 }
767 va_end(args);
768
b9bb8bbb 769 dest[cur_len] = '\0';
fe70edee
CB
770 if (len)
771 *len = cur_len;
37ef15bb
CB
772 return dest;
773}
774
775char *must_make_path(const char *first, ...)
776{
777 va_list args;
778 char *cur, *dest;
779 size_t full_len = strlen(first);
780 size_t buf_len;
7cfde20f 781 size_t cur_len;
37ef15bb
CB
782
783 dest = must_copy_string(first);
7cfde20f 784 cur_len = full_len;
37ef15bb
CB
785
786 va_start(args, first);
787 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 788 buf_len = strlen(cur);
19281251
CB
789 if (buf_len == 0)
790 continue;
7cfde20f 791
792 full_len += buf_len;
37ef15bb
CB
793 if (cur[0] != '/')
794 full_len++;
795
7cfde20f 796 dest = must_realloc(dest, full_len + 1);
37ef15bb 797
7cfde20f 798 if (cur[0] != '/') {
799 memcpy(dest + cur_len, "/", 1);
800 cur_len++;
801 }
802
803 memcpy(dest + cur_len, cur, buf_len);
804 cur_len += buf_len;
37ef15bb
CB
805 }
806 va_end(args);
807
7cfde20f 808 dest[cur_len] = '\0';
37ef15bb
CB
809 return dest;
810}
811
812char *must_append_path(char *first, ...)
813{
814 char *cur;
815 size_t full_len;
816 va_list args;
817 char *dest = first;
818 size_t buf_len;
7cfde20f 819 size_t cur_len;
37ef15bb
CB
820
821 full_len = strlen(first);
7cfde20f 822 cur_len = full_len;
823
37ef15bb
CB
824 va_start(args, first);
825 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 826 buf_len = strlen(cur);
827
828 full_len += buf_len;
37ef15bb
CB
829 if (cur[0] != '/')
830 full_len++;
831
7cfde20f 832 dest = must_realloc(dest, full_len + 1);
37ef15bb 833
7cfde20f 834 if (cur[0] != '/') {
835 memcpy(dest + cur_len, "/", 1);
836 cur_len++;
837 }
838
839 memcpy(dest + cur_len, cur, buf_len);
840 cur_len += buf_len;
37ef15bb
CB
841 }
842 va_end(args);
843
7cfde20f 844 dest[cur_len] = '\0';
37ef15bb
CB
845 return dest;
846}
847
848char *must_copy_string(const char *entry)
849{
850 char *ret;
851
852 if (!entry)
853 return NULL;
854
855 do {
856 ret = strdup(entry);
857 } while (!ret);
858
859 return ret;
860}
861
862void *must_realloc(void *orig, size_t sz)
863{
864 void *ret;
865
866 do {
867 ret = realloc(orig, sz);
868 } while (!ret);
869
870 return ret;
871}
872
4c5479d2 873int parse_byte_size_string(const char *s, long long int *converted)
37ef15bb
CB
874{
875 int ret, suffix_len;
4c5479d2 876 long long int conv, mltpl;
37ef15bb 877 char *end;
f6727edb 878 char dup[INTTYPE_TO_STRLEN(long long int)] = {0};
37ef15bb 879 char suffix[3] = {0};
6d345aa4 880 size_t len;
37ef15bb 881
6d345aa4 882 if (!s)
3f5c01db 883 return ret_errno(EINVAL);
37ef15bb 884
6d345aa4
EV
885 len = strlen(s);
886 if (len == 0 || len > sizeof(dup) - 1)
3f5c01db 887 return ret_errno(EINVAL);
37ef15bb 888
6d345aa4
EV
889 memcpy(dup, s, len);
890
891 end = dup + len;
37ef15bb
CB
892 if (isdigit(*(end - 1)))
893 suffix_len = 0;
894 else if (isalpha(*(end - 1)))
895 suffix_len = 1;
896 else
3f5c01db 897 return ret_errno(EINVAL);
37ef15bb 898
b2480b29
CB
899 if (suffix_len > 0) {
900 if ((end - 1) == dup)
901 return ret_errno(EINVAL);
37ef15bb 902
b2480b29
CB
903 if ((end - 2) == dup) {
904 if (isalpha(*(end - 2)))
905 return ret_errno(EINVAL);
906 /* 1B */
907 } else {
908 if (isalpha(*(end - 2))) /* 12MB */
909 suffix_len++;
910
911 /* 12B */
912 }
37ef15bb 913
37ef15bb
CB
914 memcpy(suffix, end - suffix_len, suffix_len);
915 *(suffix + suffix_len) = '\0';
916 *(end - suffix_len) = '\0';
917 }
b2480b29 918
37ef15bb
CB
919 dup[lxc_char_right_gc(dup, strlen(dup))] = '\0';
920
921 ret = lxc_safe_long_long(dup, &conv);
3f5c01db
CB
922 if (ret)
923 return ret;
37ef15bb
CB
924
925 if (suffix_len != 2) {
926 *converted = conv;
927 return 0;
928 }
929
930 if (strcasecmp(suffix, "KB") == 0)
931 mltpl = 1024;
932 else if (strcasecmp(suffix, "MB") == 0)
933 mltpl = 1024 * 1024;
934 else if (strcasecmp(suffix, "GB") == 0)
935 mltpl = 1024 * 1024 * 1024;
936 else
3f5c01db 937 return ret_errno(EINVAL);
37ef15bb 938
4c5479d2 939 if (check_mul_overflow(conv, mltpl, converted))
3f5c01db 940 return ret_errno(ERANGE);
37ef15bb 941
37ef15bb
CB
942 return 0;
943}
944
945void remove_trailing_newlines(char *l)
946{
947 char *p = l;
948
949 while (*p)
950 p++;
951
952 while (--p >= l && *p == '\n')
953 *p = '\0';
954}
955
956int lxc_char_left_gc(const char *buffer, size_t len)
957{
958 size_t i;
959
960 for (i = 0; i < len; i++) {
961 if (buffer[i] == ' ' ||
962 buffer[i] == '\t')
963 continue;
964
965 return i;
966 }
967
968 return 0;
969}
970
971int lxc_char_right_gc(const char *buffer, size_t len)
972{
973 int i;
974
975 for (i = len - 1; i >= 0; i--) {
976 if (buffer[i] == ' ' ||
977 buffer[i] == '\t' ||
978 buffer[i] == '\n' ||
979 buffer[i] == '\0')
980 continue;
981
982 return i + 1;
983 }
984
985 return 0;
986}
987
988char *lxc_trim_whitespace_in_place(char *buffer)
989{
990 buffer += lxc_char_left_gc(buffer, strlen(buffer));
991 buffer[lxc_char_right_gc(buffer, strlen(buffer))] = '\0';
992 return buffer;
993}
994
995int lxc_is_line_empty(const char *line)
996{
37ef15bb
CB
997 size_t len = strlen(line);
998
a5e92f5d 999 for (size_t i = 0; i < len; i++)
37ef15bb
CB
1000 if (line[i] != ' ' && line[i] != '\t' &&
1001 line[i] != '\n' && line[i] != '\r' &&
1002 line[i] != '\f' && line[i] != '\0')
1003 return 0;
1004 return 1;
1005}
dca12ddf
CB
1006
1007void remove_trailing_slashes(char *p)
1008{
1009 int l = strlen(p);
1010 while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
1011 p[l] = '\0';
1012}