]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/string_utils.c
string_utils: always memset buf in lxc_safe_int64_residual()
[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
195char **lxc_normalize_path(const char *path)
196{
197 char **components;
198 char **p;
199 size_t components_len = 0;
200 size_t pos = 0;
201
202 components = lxc_string_split(path, '/');
203 if (!components)
204 return NULL;
205
206 for (p = components; *p; p++)
207 components_len++;
208
209 /* resolve '.' and '..' */
210 for (pos = 0; pos < components_len;) {
7ba62a5e
CB
211 if (strequal(components[pos], ".") ||
212 (strequal(components[pos], "..") && pos == 0)) {
37ef15bb
CB
213 /* eat this element */
214 free(components[pos]);
215 memmove(&components[pos], &components[pos + 1],
216 sizeof(char *) * (components_len - pos));
217 components_len--;
7ba62a5e 218 } else if (strequal(components[pos], "..")) {
37ef15bb
CB
219 /* eat this and the previous element */
220 free(components[pos - 1]);
221 free(components[pos]);
222 memmove(&components[pos - 1], &components[pos + 1],
223 sizeof(char *) * (components_len - pos));
224 components_len -= 2;
225 pos--;
226 } else {
227 pos++;
228 }
229 }
230
231 return components;
232}
233
234char *lxc_deslashify(const char *path)
235{
236 char *dup, *p;
237 char **parts = NULL;
238 size_t n, len;
239
240 dup = strdup(path);
241 if (!dup)
242 return NULL;
243
244 parts = lxc_normalize_path(dup);
245 if (!parts) {
246 free(dup);
247 return NULL;
248 }
249
250 /* We'll end up here if path == "///" or path == "". */
251 if (!*parts) {
252 len = strlen(dup);
253 if (!len) {
254 lxc_free_array((void **)parts, free);
255 return dup;
256 }
257
258 n = strcspn(dup, "/");
259 if (n == len) {
260 free(dup);
261 lxc_free_array((void **)parts, free);
262
263 p = strdup("/");
264 if (!p)
265 return NULL;
266
267 return p;
268 }
269 }
270
271 p = lxc_string_join("/", (const char **)parts, *dup == '/');
272 free(dup);
273 lxc_free_array((void **)parts, free);
274 return p;
275}
276
277char *lxc_append_paths(const char *first, const char *second)
278{
4af24cb7 279 __do_free char *result = NULL;
37ef15bb
CB
280 int ret;
281 size_t len;
d07545c7 282 int pattern_type = 0;
37ef15bb
CB
283
284 len = strlen(first) + strlen(second) + 1;
285 if (second[0] != '/') {
286 len += 1;
d07545c7 287 pattern_type = 1;
37ef15bb
CB
288 }
289
4af24cb7 290 result = zalloc(len);
37ef15bb
CB
291 if (!result)
292 return NULL;
293
d07545c7 294 if (pattern_type == 0)
4af24cb7 295 ret = strnprintf(result, len, "%s%s", first, second);
d07545c7 296 else
4af24cb7
CB
297 ret = strnprintf(result, len, "%s/%s", first, second);
298 if (ret < 0)
37ef15bb 299 return NULL;
37ef15bb 300
4af24cb7 301 return move_ptr(result);
37ef15bb
CB
302}
303
304bool lxc_string_in_list(const char *needle, const char *haystack, char _sep)
305{
97f35ce6
CB
306 __do_free char *str = NULL;
307 char *token;
37ef15bb 308 char sep[2] = { _sep, '\0' };
37ef15bb
CB
309
310 if (!haystack || !needle)
311 return 0;
312
97f35ce6 313 str = must_copy_string(haystack);
37ef15bb 314 lxc_iterate_parts(token, str, sep)
7ba62a5e 315 if (strequal(needle, token))
37ef15bb
CB
316 return 1;
317
318 return 0;
319}
320
321char **lxc_string_split(const char *string, char _sep)
322{
97f35ce6
CB
323 __do_free char *str = NULL;
324 char *token;
37ef15bb
CB
325 char sep[2] = {_sep, '\0'};
326 char **tmp = NULL, **result = NULL;
327 size_t result_capacity = 0;
328 size_t result_count = 0;
329 int r, saved_errno;
37ef15bb
CB
330
331 if (!string)
332 return calloc(1, sizeof(char *));
333
97f35ce6 334 str = must_copy_string(string);
37ef15bb
CB
335 lxc_iterate_parts(token, str, sep) {
336 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
337 if (r < 0)
338 goto error_out;
339
340 result[result_count] = strdup(token);
341 if (!result[result_count])
342 goto error_out;
343
344 result_count++;
345 }
346
347 /* if we allocated too much, reduce it */
348 tmp = realloc(result, (result_count + 1) * sizeof(char *));
349 if (!tmp)
350 goto error_out;
351
352 result = tmp;
353
354 /* Make sure we don't return uninitialized memory. */
355 if (result_count == 0)
356 *result = NULL;
357
358 return result;
359
360error_out:
361 saved_errno = errno;
362 lxc_free_array((void **)result, free);
363 errno = saved_errno;
364 return NULL;
365}
366
367static bool complete_word(char ***result, char *start, char *end, size_t *cap,
368 size_t *cnt)
369{
370 int r;
371
372 r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16);
373 if (r < 0)
374 return false;
375
376 (*result)[*cnt] = strndup(start, end - start);
377 if (!(*result)[*cnt])
378 return false;
379
380 (*cnt)++;
381
382 return true;
383}
384
385/*
386 * Given a a string 'one two "three four"', split into three words,
387 * one, two, and "three four"
388 */
389char **lxc_string_split_quoted(char *string)
390{
391 char *nextword = string, *p, state;
392 char **result = NULL;
393 size_t result_capacity = 0;
394 size_t result_count = 0;
395
396 if (!string || !*string)
397 return calloc(1, sizeof(char *));
398
399 // TODO I'm *not* handling escaped quote
400 state = ' ';
401 for (p = string; *p; p++) {
402 switch(state) {
403 case ' ':
404 if (isspace(*p))
405 continue;
406 else if (*p == '"' || *p == '\'') {
407 nextword = p;
408 state = *p;
409 continue;
410 }
411 nextword = p;
412 state = 'a';
413 continue;
414 case 'a':
415 if (isspace(*p)) {
416 complete_word(&result, nextword, p, &result_capacity, &result_count);
417 state = ' ';
418 continue;
419 }
420 continue;
421 case '"':
422 case '\'':
423 if (*p == state) {
424 complete_word(&result, nextword+1, p, &result_capacity, &result_count);
425 state = ' ';
426 continue;
427 }
428 continue;
429 }
430 }
431
432 if (state == 'a')
433 complete_word(&result, nextword, p, &result_capacity, &result_count);
434
435 return realloc(result, (result_count + 1) * sizeof(char *));
436}
437
438char **lxc_string_split_and_trim(const char *string, char _sep)
439{
97f35ce6
CB
440 __do_free char *str = NULL;
441 char *token;
37ef15bb
CB
442 char sep[2] = { _sep, '\0' };
443 char **result = NULL;
444 size_t result_capacity = 0;
445 size_t result_count = 0;
446 int r, saved_errno;
447 size_t i = 0;
37ef15bb
CB
448
449 if (!string)
450 return calloc(1, sizeof(char *));
451
97f35ce6 452 str = must_copy_string(string);
37ef15bb
CB
453 lxc_iterate_parts(token, str, sep) {
454 while (token[0] == ' ' || token[0] == '\t')
455 token++;
456
457 i = strlen(token);
458 while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
459 token[i - 1] = '\0';
460 i--;
461 }
462
463 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
464 if (r < 0)
465 goto error_out;
466
467 result[result_count] = strdup(token);
468 if (!result[result_count])
469 goto error_out;
470
471 result_count++;
472 }
473
474 /* if we allocated too much, reduce it */
475 return realloc(result, (result_count + 1) * sizeof(char *));
476
477error_out:
478 saved_errno = errno;
479 lxc_free_array((void **)result, free);
480 errno = saved_errno;
481 return NULL;
482}
483
484void lxc_free_array(void **array, lxc_free_fn element_free_fn)
485{
486 void **p;
487
488 for (p = array; p && *p; p++)
489 element_free_fn(*p);
490
491 free((void*)array);
492}
493
494int lxc_grow_array(void ***array, size_t *capacity, size_t new_size, size_t capacity_increment)
495{
496 size_t new_capacity;
497 void **new_array;
498
499 /* first time around, catch some trivial mistakes of the user
500 * only initializing one of these */
501 if (!*array || !*capacity) {
502 *array = NULL;
503 *capacity = 0;
504 }
505
506 new_capacity = *capacity;
507 while (new_size + 1 > new_capacity)
508 new_capacity += capacity_increment;
509
510 if (new_capacity != *capacity) {
511 /* we have to reallocate */
512 new_array = realloc(*array, new_capacity * sizeof(void *));
513 if (!new_array)
514 return -1;
515
516 memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * sizeof(void *));
517 *array = new_array;
518 *capacity = new_capacity;
519 }
520
521 /* array has sufficient elements */
522 return 0;
523}
524
525size_t lxc_array_len(void **array)
526{
527 void **p;
528 size_t result = 0;
529
530 for (p = array; p && *p; p++)
531 result++;
532
533 return result;
534}
535
536void **lxc_append_null_to_array(void **array, size_t count)
537{
538 void **temp;
539
540 /* Append NULL to the array */
541 if (count) {
542 temp = realloc(array, (count + 1) * sizeof(*array));
543 if (!temp) {
544 size_t i;
545 for (i = 0; i < count; i++)
546 free(array[i]);
547 free(array);
548 return NULL;
549 }
550
551 array = temp;
552 array[count] = NULL;
553 }
554
555 return array;
556}
557
558static int lxc_append_null_to_list(void ***list)
559{
560 int newentry = 0;
561 void **tmp;
562
563 if (*list)
564 for (; (*list)[newentry]; newentry++) {
565 ;
566 }
567
568 tmp = realloc(*list, (newentry + 2) * sizeof(void **));
569 if (!tmp)
570 return -1;
571
572 *list = tmp;
573 (*list)[newentry + 1] = NULL;
574
575 return newentry;
576}
577
578int lxc_append_string(char ***list, char *entry)
579{
580 char *copy;
581 int newentry;
582
583 newentry = lxc_append_null_to_list((void ***)list);
584 if (newentry < 0)
585 return -1;
586
587 copy = strdup(entry);
588 if (!copy)
589 return -1;
590
591 (*list)[newentry] = copy;
592
593 return 0;
594}
595
596int lxc_safe_uint(const char *numstr, unsigned int *converted)
597{
598 char *err = NULL;
599 unsigned long int uli;
600
601 while (isspace(*numstr))
602 numstr++;
603
604 if (*numstr == '-')
605 return -EINVAL;
606
607 errno = 0;
608 uli = strtoul(numstr, &err, 0);
609 if (errno == ERANGE && uli == ULONG_MAX)
610 return -ERANGE;
611
612 if (err == numstr || *err != '\0')
613 return -EINVAL;
614
615 if (uli > UINT_MAX)
616 return -ERANGE;
617
618 *converted = (unsigned int)uli;
619 return 0;
620}
621
622int lxc_safe_ulong(const char *numstr, unsigned long *converted)
623{
624 char *err = NULL;
625 unsigned long int uli;
626
627 while (isspace(*numstr))
628 numstr++;
629
630 if (*numstr == '-')
631 return -EINVAL;
632
633 errno = 0;
634 uli = strtoul(numstr, &err, 0);
635 if (errno == ERANGE && uli == ULONG_MAX)
636 return -ERANGE;
637
638 if (err == numstr || *err != '\0')
639 return -EINVAL;
640
641 *converted = uli;
642 return 0;
643}
644
645int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base)
646{
647 char *err = NULL;
648 uint64_t u;
649
650 while (isspace(*numstr))
651 numstr++;
652
653 if (*numstr == '-')
654 return -EINVAL;
655
656 errno = 0;
657 u = strtoull(numstr, &err, base);
62fc8403 658 if (errno == ERANGE && u == UINT64_MAX)
37ef15bb
CB
659 return -ERANGE;
660
661 if (err == numstr || *err != '\0')
662 return -EINVAL;
663
664 *converted = u;
665 return 0;
666}
667
70fd7fc9
CB
668int lxc_safe_int64_residual(const char *numstr, int64_t *converted, int base, char *residual,
669 size_t residual_len)
670{
671 char *remaining = NULL;
672 int64_t u;
673
674 if (residual && residual_len == 0)
675 return ret_errno(EINVAL);
676
677 if (!residual && residual_len != 0)
678 return ret_errno(EINVAL);
679
c45833e3
CB
680 memset(residual, 0, residual_len);
681
70fd7fc9
CB
682 while (isspace(*numstr))
683 numstr++;
684
685 errno = 0;
686 u = strtoll(numstr, &remaining, base);
687 if (errno == ERANGE && u == INT64_MAX)
688 return -ERANGE;
689
690 if (remaining == numstr)
691 return -EINVAL;
692
693 if (residual) {
694 size_t len = 0;
695
c45833e3 696 if (*remaining == '\0')
70fd7fc9 697 goto out;
70fd7fc9
CB
698
699 len = strlen(remaining);
700 if (len >= residual_len)
701 return -EINVAL;
702
703 memcpy(residual, remaining, len);
704 } else if (*remaining != '\0') {
705 return -EINVAL;
706 }
707
708out:
709 *converted = u;
710 return 0;
711}
712
37ef15bb
CB
713int lxc_safe_int(const char *numstr, int *converted)
714{
715 char *err = NULL;
716 signed long int sli;
717
718 errno = 0;
719 sli = strtol(numstr, &err, 0);
720 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
721 return -ERANGE;
722
723 if (errno != 0 && sli == 0)
724 return -EINVAL;
725
726 if (err == numstr || *err != '\0')
727 return -EINVAL;
728
729 if (sli > INT_MAX || sli < INT_MIN)
730 return -ERANGE;
731
732 *converted = (int)sli;
733 return 0;
734}
735
736int lxc_safe_long(const char *numstr, long int *converted)
737{
738 char *err = NULL;
739 signed long int sli;
740
741 errno = 0;
742 sli = strtol(numstr, &err, 0);
743 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
744 return -ERANGE;
745
746 if (errno != 0 && sli == 0)
747 return -EINVAL;
748
749 if (err == numstr || *err != '\0')
750 return -EINVAL;
751
752 *converted = sli;
753 return 0;
754}
755
756int lxc_safe_long_long(const char *numstr, long long int *converted)
757{
758 char *err = NULL;
759 signed long long int sli;
760
761 errno = 0;
762 sli = strtoll(numstr, &err, 0);
763 if (errno == ERANGE && (sli == LLONG_MAX || sli == LLONG_MIN))
764 return -ERANGE;
765
766 if (errno != 0 && sli == 0)
767 return -EINVAL;
768
769 if (err == numstr || *err != '\0')
770 return -EINVAL;
771
772 *converted = sli;
773 return 0;
774}
775
fe70edee 776char *must_concat(size_t *len, const char *first, ...)
37ef15bb
CB
777{
778 va_list args;
779 char *cur, *dest;
780 size_t cur_len, it_len;
781
782 dest = must_copy_string(first);
783 cur_len = it_len = strlen(first);
784
785 va_start(args, first);
786 while ((cur = va_arg(args, char *)) != NULL) {
787 it_len = strlen(cur);
788
789 dest = must_realloc(dest, cur_len + it_len + 1);
790
791 (void)memcpy(dest + cur_len, cur, it_len);
792 cur_len += it_len;
793 }
794 va_end(args);
795
b9bb8bbb 796 dest[cur_len] = '\0';
fe70edee
CB
797 if (len)
798 *len = cur_len;
37ef15bb
CB
799 return dest;
800}
801
802char *must_make_path(const char *first, ...)
803{
804 va_list args;
805 char *cur, *dest;
806 size_t full_len = strlen(first);
807 size_t buf_len;
7cfde20f 808 size_t cur_len;
37ef15bb
CB
809
810 dest = must_copy_string(first);
7cfde20f 811 cur_len = full_len;
37ef15bb
CB
812
813 va_start(args, first);
814 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 815 buf_len = strlen(cur);
19281251
CB
816 if (buf_len == 0)
817 continue;
7cfde20f 818
819 full_len += buf_len;
37ef15bb
CB
820 if (cur[0] != '/')
821 full_len++;
822
7cfde20f 823 dest = must_realloc(dest, full_len + 1);
37ef15bb 824
7cfde20f 825 if (cur[0] != '/') {
826 memcpy(dest + cur_len, "/", 1);
827 cur_len++;
828 }
829
830 memcpy(dest + cur_len, cur, buf_len);
831 cur_len += buf_len;
37ef15bb
CB
832 }
833 va_end(args);
834
7cfde20f 835 dest[cur_len] = '\0';
37ef15bb
CB
836 return dest;
837}
838
839char *must_append_path(char *first, ...)
840{
841 char *cur;
842 size_t full_len;
843 va_list args;
844 char *dest = first;
845 size_t buf_len;
7cfde20f 846 size_t cur_len;
37ef15bb
CB
847
848 full_len = strlen(first);
7cfde20f 849 cur_len = full_len;
850
37ef15bb
CB
851 va_start(args, first);
852 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 853 buf_len = strlen(cur);
854
855 full_len += buf_len;
37ef15bb
CB
856 if (cur[0] != '/')
857 full_len++;
858
7cfde20f 859 dest = must_realloc(dest, full_len + 1);
37ef15bb 860
7cfde20f 861 if (cur[0] != '/') {
862 memcpy(dest + cur_len, "/", 1);
863 cur_len++;
864 }
865
866 memcpy(dest + cur_len, cur, buf_len);
867 cur_len += buf_len;
37ef15bb
CB
868 }
869 va_end(args);
870
7cfde20f 871 dest[cur_len] = '\0';
37ef15bb
CB
872 return dest;
873}
874
875char *must_copy_string(const char *entry)
876{
877 char *ret;
878
879 if (!entry)
880 return NULL;
881
882 do {
883 ret = strdup(entry);
884 } while (!ret);
885
886 return ret;
887}
888
889void *must_realloc(void *orig, size_t sz)
890{
891 void *ret;
892
893 do {
894 ret = realloc(orig, sz);
895 } while (!ret);
896
897 return ret;
898}
899
900int parse_byte_size_string(const char *s, int64_t *converted)
901{
902 int ret, suffix_len;
903 long long int conv;
904 int64_t mltpl, overflow;
905 char *end;
f1eacafb 906 char dup[INTTYPE_TO_STRLEN(int64_t)];
37ef15bb
CB
907 char suffix[3] = {0};
908
b2480b29 909 if (is_empty_string(s))
3f5c01db 910 return ret_errno(EINVAL);
37ef15bb
CB
911
912 end = stpncpy(dup, s, sizeof(dup) - 1);
913 if (*end != '\0')
3f5c01db 914 return ret_errno(EINVAL);
37ef15bb
CB
915
916 if (isdigit(*(end - 1)))
917 suffix_len = 0;
918 else if (isalpha(*(end - 1)))
919 suffix_len = 1;
920 else
3f5c01db 921 return ret_errno(EINVAL);
37ef15bb 922
b2480b29
CB
923 if (suffix_len > 0) {
924 if ((end - 1) == dup)
925 return ret_errno(EINVAL);
37ef15bb 926
b2480b29
CB
927 if ((end - 2) == dup) {
928 if (isalpha(*(end - 2)))
929 return ret_errno(EINVAL);
930 /* 1B */
931 } else {
932 if (isalpha(*(end - 2))) /* 12MB */
933 suffix_len++;
934
935 /* 12B */
936 }
37ef15bb 937
37ef15bb
CB
938 memcpy(suffix, end - suffix_len, suffix_len);
939 *(suffix + suffix_len) = '\0';
940 *(end - suffix_len) = '\0';
941 }
b2480b29 942
37ef15bb
CB
943 dup[lxc_char_right_gc(dup, strlen(dup))] = '\0';
944
945 ret = lxc_safe_long_long(dup, &conv);
3f5c01db
CB
946 if (ret)
947 return ret;
37ef15bb
CB
948
949 if (suffix_len != 2) {
950 *converted = conv;
951 return 0;
952 }
953
954 if (strcasecmp(suffix, "KB") == 0)
955 mltpl = 1024;
956 else if (strcasecmp(suffix, "MB") == 0)
957 mltpl = 1024 * 1024;
958 else if (strcasecmp(suffix, "GB") == 0)
959 mltpl = 1024 * 1024 * 1024;
960 else
3f5c01db 961 return ret_errno(EINVAL);
37ef15bb
CB
962
963 overflow = conv * mltpl;
964 if (conv != 0 && (overflow / conv) != mltpl)
3f5c01db 965 return ret_errno(ERANGE);
37ef15bb
CB
966
967 *converted = overflow;
968 return 0;
969}
970
971void remove_trailing_newlines(char *l)
972{
973 char *p = l;
974
975 while (*p)
976 p++;
977
978 while (--p >= l && *p == '\n')
979 *p = '\0';
980}
981
982int lxc_char_left_gc(const char *buffer, size_t len)
983{
984 size_t i;
985
986 for (i = 0; i < len; i++) {
987 if (buffer[i] == ' ' ||
988 buffer[i] == '\t')
989 continue;
990
991 return i;
992 }
993
994 return 0;
995}
996
997int lxc_char_right_gc(const char *buffer, size_t len)
998{
999 int i;
1000
1001 for (i = len - 1; i >= 0; i--) {
1002 if (buffer[i] == ' ' ||
1003 buffer[i] == '\t' ||
1004 buffer[i] == '\n' ||
1005 buffer[i] == '\0')
1006 continue;
1007
1008 return i + 1;
1009 }
1010
1011 return 0;
1012}
1013
1014char *lxc_trim_whitespace_in_place(char *buffer)
1015{
1016 buffer += lxc_char_left_gc(buffer, strlen(buffer));
1017 buffer[lxc_char_right_gc(buffer, strlen(buffer))] = '\0';
1018 return buffer;
1019}
1020
1021int lxc_is_line_empty(const char *line)
1022{
1023 int i;
1024 size_t len = strlen(line);
1025
1026 for (i = 0; i < len; i++)
1027 if (line[i] != ' ' && line[i] != '\t' &&
1028 line[i] != '\n' && line[i] != '\r' &&
1029 line[i] != '\f' && line[i] != '\0')
1030 return 0;
1031 return 1;
1032}
dca12ddf
CB
1033
1034void remove_trailing_slashes(char *p)
1035{
1036 int l = strlen(p);
1037 while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
1038 p[l] = '\0';
1039}