]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/string_utils.c
lxcmntent: coding rules
[mirror_lxc.git] / src / lxc / string_utils.c
CommitLineData
37ef15bb
CB
1/* liblxcapi
2 *
3 * Copyright © 2018 Christian Brauner <christian.brauner@ubuntu.com>.
4 * Copyright © 2018 Canonical Ltd.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
d38dd64a
CB
20#ifndef _GNU_SOURCE
21#define _GNU_SOURCE 1
22#endif
37ef15bb
CB
23#define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
24#include <ctype.h>
25#include <dirent.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <grp.h>
29#include <inttypes.h>
30#include <libgen.h>
31#include <pthread.h>
32#include <stddef.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <string.h>
37ef15bb
CB
36#include <sys/mman.h>
37#include <sys/mount.h>
38#include <sys/param.h>
39#include <sys/prctl.h>
40#include <sys/stat.h>
41#include <sys/types.h>
42#include <sys/wait.h>
d38dd64a 43#include <unistd.h>
37ef15bb 44
d38dd64a 45#include "config.h"
37ef15bb
CB
46#include "log.h"
47#include "lxclock.h"
f1eacafb 48#include "macro.h"
37ef15bb
CB
49#include "namespace.h"
50#include "parse.h"
51#include "string_utils.h"
37ef15bb
CB
52
53#ifndef HAVE_STRLCPY
54#include "include/strlcpy.h"
55#endif
56
57#ifndef HAVE_STRLCAT
58#include "include/strlcat.h"
59#endif
60
37ef15bb 61lxc_log_define(string_utils, lxc);
37ef15bb
CB
62
63char **lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup)
64{
65 va_list ap2;
66 size_t count = 1 + skip;
67 char **result;
68
69 /* first determine size of argument list, we don't want to reallocate
70 * constantly...
71 */
72 va_copy(ap2, ap);
73 while (1) {
74 char *arg = va_arg(ap2, char *);
75 if (!arg)
76 break;
77 count++;
78 }
79 va_end(ap2);
80
81 result = calloc(count, sizeof(char *));
82 if (!result)
83 return NULL;
84
85 count = skip;
86 while (1) {
87 char *arg = va_arg(ap, char *);
88 if (!arg)
89 break;
90 arg = do_strdup ? strdup(arg) : arg;
91 if (!arg)
92 goto oom;
93 result[count++] = arg;
94 }
95
96 /* calloc has already set last element to NULL*/
97 return result;
98
99oom:
100 free(result);
101 return NULL;
102}
103
104const char **lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
105{
106 return (const char **)lxc_va_arg_list_to_argv(ap, skip, 0);
107}
108
109char *lxc_string_replace(const char *needle, const char *replacement,
110 const char *haystack)
111{
112 ssize_t len = -1, saved_len = -1;
113 char *result = NULL;
114 size_t replacement_len = strlen(replacement);
115 size_t needle_len = strlen(needle);
116
117 /* should be executed exactly twice */
118 while (len == -1 || result == NULL) {
119 char *p;
120 char *last_p;
121 ssize_t part_len;
122
123 if (len != -1) {
124 result = calloc(1, len + 1);
125 if (!result)
126 return NULL;
127
128 saved_len = len;
129 }
130
131 len = 0;
132
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);
138
139 len += part_len;
140
141 if (result && replacement_len > 0)
142 memcpy(&result[len], replacement,
143 replacement_len);
144
145 len += replacement_len;
146 p += needle_len;
147 }
148
149 part_len = strlen(last_p);
150 if (result && part_len > 0)
151 memcpy(&result[len], last_p, part_len);
152
153 len += part_len;
154 }
155
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) {
160 free(result);
161 return NULL;
162 }
163
164 /* make sure we didn't overwrite any buffer,
165 * due to calloc the string should be 0-terminated */
166 if (result[len] != '\0') {
167 free(result);
168 return NULL;
169 }
170
171 return result;
172}
173
174bool lxc_string_in_array(const char *needle, const char **haystack)
175{
176 for (; haystack && *haystack; haystack++)
177 if (!strcmp(needle, *haystack))
178 return true;
179
180 return false;
181}
182
183char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix)
184{
185 char *result;
186 char **p;
187 size_t sep_len = strlen(sep);
188 size_t result_len = use_as_prefix * sep_len;
189 size_t buf_len;
190
191 /* calculate new string length */
192 for (p = (char **)parts; *p; p++)
193 result_len += (p > (char **)parts) * sep_len + strlen(*p);
194
195 buf_len = result_len + 1;
196 result = calloc(buf_len, 1);
197 if (!result)
198 return NULL;
199
200 if (use_as_prefix)
201 (void)strlcpy(result, sep, buf_len);
202
203 for (p = (char **)parts; *p; p++) {
204 if (p > (char **)parts)
205 (void)strlcat(result, sep, buf_len);
206
207 (void)strlcat(result, *p, buf_len);
208 }
209
210 return result;
211}
212
213char **lxc_normalize_path(const char *path)
214{
215 char **components;
216 char **p;
217 size_t components_len = 0;
218 size_t pos = 0;
219
220 components = lxc_string_split(path, '/');
221 if (!components)
222 return NULL;
223
224 for (p = components; *p; p++)
225 components_len++;
226
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));
235 components_len--;
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));
242 components_len -= 2;
243 pos--;
244 } else {
245 pos++;
246 }
247 }
248
249 return components;
250}
251
252char *lxc_deslashify(const char *path)
253{
254 char *dup, *p;
255 char **parts = NULL;
256 size_t n, len;
257
258 dup = strdup(path);
259 if (!dup)
260 return NULL;
261
262 parts = lxc_normalize_path(dup);
263 if (!parts) {
264 free(dup);
265 return NULL;
266 }
267
268 /* We'll end up here if path == "///" or path == "". */
269 if (!*parts) {
270 len = strlen(dup);
271 if (!len) {
272 lxc_free_array((void **)parts, free);
273 return dup;
274 }
275
276 n = strcspn(dup, "/");
277 if (n == len) {
278 free(dup);
279 lxc_free_array((void **)parts, free);
280
281 p = strdup("/");
282 if (!p)
283 return NULL;
284
285 return p;
286 }
287 }
288
289 p = lxc_string_join("/", (const char **)parts, *dup == '/');
290 free(dup);
291 lxc_free_array((void **)parts, free);
292 return p;
293}
294
295char *lxc_append_paths(const char *first, const char *second)
296{
297 int ret;
298 size_t len;
299 char *result = NULL;
300 const char *pattern = "%s%s";
301
302 len = strlen(first) + strlen(second) + 1;
303 if (second[0] != '/') {
304 len += 1;
305 pattern = "%s/%s";
306 }
307
308 result = calloc(1, len);
309 if (!result)
310 return NULL;
311
312 ret = snprintf(result, len, pattern, first, second);
313 if (ret < 0 || (size_t)ret >= len) {
314 free(result);
315 return NULL;
316 }
317
318 return result;
319}
320
321bool lxc_string_in_list(const char *needle, const char *haystack, char _sep)
322{
323 char *token, *str;
324 char sep[2] = { _sep, '\0' };
325 size_t len;
326
327 if (!haystack || !needle)
328 return 0;
329
330 len = strlen(haystack);
331 str = alloca(len + 1);
332 (void)strlcpy(str, haystack, len + 1);
333
334 lxc_iterate_parts(token, str, sep)
335 if (strcmp(needle, token) == 0)
336 return 1;
337
338 return 0;
339}
340
341char **lxc_string_split(const char *string, char _sep)
342{
343 char *token, *str;
344 char sep[2] = {_sep, '\0'};
345 char **tmp = NULL, **result = NULL;
346 size_t result_capacity = 0;
347 size_t result_count = 0;
348 int r, saved_errno;
349 size_t len;
350
351 if (!string)
352 return calloc(1, sizeof(char *));
353
354 len = strlen(string);
355 str = alloca(len + 1);
356 (void)strlcpy(str, string, len + 1);
357
358 lxc_iterate_parts(token, str, sep) {
359 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
360 if (r < 0)
361 goto error_out;
362
363 result[result_count] = strdup(token);
364 if (!result[result_count])
365 goto error_out;
366
367 result_count++;
368 }
369
370 /* if we allocated too much, reduce it */
371 tmp = realloc(result, (result_count + 1) * sizeof(char *));
372 if (!tmp)
373 goto error_out;
374
375 result = tmp;
376
377 /* Make sure we don't return uninitialized memory. */
378 if (result_count == 0)
379 *result = NULL;
380
381 return result;
382
383error_out:
384 saved_errno = errno;
385 lxc_free_array((void **)result, free);
386 errno = saved_errno;
387 return NULL;
388}
389
390static bool complete_word(char ***result, char *start, char *end, size_t *cap,
391 size_t *cnt)
392{
393 int r;
394
395 r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16);
396 if (r < 0)
397 return false;
398
399 (*result)[*cnt] = strndup(start, end - start);
400 if (!(*result)[*cnt])
401 return false;
402
403 (*cnt)++;
404
405 return true;
406}
407
408/*
409 * Given a a string 'one two "three four"', split into three words,
410 * one, two, and "three four"
411 */
412char **lxc_string_split_quoted(char *string)
413{
414 char *nextword = string, *p, state;
415 char **result = NULL;
416 size_t result_capacity = 0;
417 size_t result_count = 0;
418
419 if (!string || !*string)
420 return calloc(1, sizeof(char *));
421
422 // TODO I'm *not* handling escaped quote
423 state = ' ';
424 for (p = string; *p; p++) {
425 switch(state) {
426 case ' ':
427 if (isspace(*p))
428 continue;
429 else if (*p == '"' || *p == '\'') {
430 nextword = p;
431 state = *p;
432 continue;
433 }
434 nextword = p;
435 state = 'a';
436 continue;
437 case 'a':
438 if (isspace(*p)) {
439 complete_word(&result, nextword, p, &result_capacity, &result_count);
440 state = ' ';
441 continue;
442 }
443 continue;
444 case '"':
445 case '\'':
446 if (*p == state) {
447 complete_word(&result, nextword+1, p, &result_capacity, &result_count);
448 state = ' ';
449 continue;
450 }
451 continue;
452 }
453 }
454
455 if (state == 'a')
456 complete_word(&result, nextword, p, &result_capacity, &result_count);
457
458 return realloc(result, (result_count + 1) * sizeof(char *));
459}
460
461char **lxc_string_split_and_trim(const char *string, char _sep)
462{
463 char *token, *str;
464 char sep[2] = { _sep, '\0' };
465 char **result = NULL;
466 size_t result_capacity = 0;
467 size_t result_count = 0;
468 int r, saved_errno;
469 size_t i = 0;
470 size_t len;
471
472 if (!string)
473 return calloc(1, sizeof(char *));
474
475 len = strlen(string);
476 str = alloca(len + 1);
477 (void)strlcpy(str, string, len + 1);
478
479 lxc_iterate_parts(token, str, sep) {
480 while (token[0] == ' ' || token[0] == '\t')
481 token++;
482
483 i = strlen(token);
484 while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
485 token[i - 1] = '\0';
486 i--;
487 }
488
489 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
490 if (r < 0)
491 goto error_out;
492
493 result[result_count] = strdup(token);
494 if (!result[result_count])
495 goto error_out;
496
497 result_count++;
498 }
499
500 /* if we allocated too much, reduce it */
501 return realloc(result, (result_count + 1) * sizeof(char *));
502
503error_out:
504 saved_errno = errno;
505 lxc_free_array((void **)result, free);
506 errno = saved_errno;
507 return NULL;
508}
509
510void lxc_free_array(void **array, lxc_free_fn element_free_fn)
511{
512 void **p;
513
514 for (p = array; p && *p; p++)
515 element_free_fn(*p);
516
517 free((void*)array);
518}
519
520int lxc_grow_array(void ***array, size_t *capacity, size_t new_size, size_t capacity_increment)
521{
522 size_t new_capacity;
523 void **new_array;
524
525 /* first time around, catch some trivial mistakes of the user
526 * only initializing one of these */
527 if (!*array || !*capacity) {
528 *array = NULL;
529 *capacity = 0;
530 }
531
532 new_capacity = *capacity;
533 while (new_size + 1 > new_capacity)
534 new_capacity += capacity_increment;
535
536 if (new_capacity != *capacity) {
537 /* we have to reallocate */
538 new_array = realloc(*array, new_capacity * sizeof(void *));
539 if (!new_array)
540 return -1;
541
542 memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * sizeof(void *));
543 *array = new_array;
544 *capacity = new_capacity;
545 }
546
547 /* array has sufficient elements */
548 return 0;
549}
550
551size_t lxc_array_len(void **array)
552{
553 void **p;
554 size_t result = 0;
555
556 for (p = array; p && *p; p++)
557 result++;
558
559 return result;
560}
561
562void **lxc_append_null_to_array(void **array, size_t count)
563{
564 void **temp;
565
566 /* Append NULL to the array */
567 if (count) {
568 temp = realloc(array, (count + 1) * sizeof(*array));
569 if (!temp) {
570 size_t i;
571 for (i = 0; i < count; i++)
572 free(array[i]);
573 free(array);
574 return NULL;
575 }
576
577 array = temp;
578 array[count] = NULL;
579 }
580
581 return array;
582}
583
584static int lxc_append_null_to_list(void ***list)
585{
586 int newentry = 0;
587 void **tmp;
588
589 if (*list)
590 for (; (*list)[newentry]; newentry++) {
591 ;
592 }
593
594 tmp = realloc(*list, (newentry + 2) * sizeof(void **));
595 if (!tmp)
596 return -1;
597
598 *list = tmp;
599 (*list)[newentry + 1] = NULL;
600
601 return newentry;
602}
603
604int lxc_append_string(char ***list, char *entry)
605{
606 char *copy;
607 int newentry;
608
609 newentry = lxc_append_null_to_list((void ***)list);
610 if (newentry < 0)
611 return -1;
612
613 copy = strdup(entry);
614 if (!copy)
615 return -1;
616
617 (*list)[newentry] = copy;
618
619 return 0;
620}
621
622int lxc_safe_uint(const char *numstr, unsigned int *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 if (uli > UINT_MAX)
642 return -ERANGE;
643
644 *converted = (unsigned int)uli;
645 return 0;
646}
647
648int lxc_safe_ulong(const char *numstr, unsigned long *converted)
649{
650 char *err = NULL;
651 unsigned long int uli;
652
653 while (isspace(*numstr))
654 numstr++;
655
656 if (*numstr == '-')
657 return -EINVAL;
658
659 errno = 0;
660 uli = strtoul(numstr, &err, 0);
661 if (errno == ERANGE && uli == ULONG_MAX)
662 return -ERANGE;
663
664 if (err == numstr || *err != '\0')
665 return -EINVAL;
666
667 *converted = uli;
668 return 0;
669}
670
671int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base)
672{
673 char *err = NULL;
674 uint64_t u;
675
676 while (isspace(*numstr))
677 numstr++;
678
679 if (*numstr == '-')
680 return -EINVAL;
681
682 errno = 0;
683 u = strtoull(numstr, &err, base);
62fc8403 684 if (errno == ERANGE && u == UINT64_MAX)
37ef15bb
CB
685 return -ERANGE;
686
687 if (err == numstr || *err != '\0')
688 return -EINVAL;
689
690 *converted = u;
691 return 0;
692}
693
694int lxc_safe_int(const char *numstr, int *converted)
695{
696 char *err = NULL;
697 signed long int sli;
698
699 errno = 0;
700 sli = strtol(numstr, &err, 0);
701 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
702 return -ERANGE;
703
704 if (errno != 0 && sli == 0)
705 return -EINVAL;
706
707 if (err == numstr || *err != '\0')
708 return -EINVAL;
709
710 if (sli > INT_MAX || sli < INT_MIN)
711 return -ERANGE;
712
713 *converted = (int)sli;
714 return 0;
715}
716
717int lxc_safe_long(const char *numstr, long int *converted)
718{
719 char *err = NULL;
720 signed long int sli;
721
722 errno = 0;
723 sli = strtol(numstr, &err, 0);
724 if (errno == ERANGE && (sli == LONG_MAX || sli == LONG_MIN))
725 return -ERANGE;
726
727 if (errno != 0 && sli == 0)
728 return -EINVAL;
729
730 if (err == numstr || *err != '\0')
731 return -EINVAL;
732
733 *converted = sli;
734 return 0;
735}
736
737int lxc_safe_long_long(const char *numstr, long long int *converted)
738{
739 char *err = NULL;
740 signed long long int sli;
741
742 errno = 0;
743 sli = strtoll(numstr, &err, 0);
744 if (errno == ERANGE && (sli == LLONG_MAX || sli == LLONG_MIN))
745 return -ERANGE;
746
747 if (errno != 0 && sli == 0)
748 return -EINVAL;
749
750 if (err == numstr || *err != '\0')
751 return -EINVAL;
752
753 *converted = sli;
754 return 0;
755}
756
757char *must_concat(const char *first, ...)
758{
759 va_list args;
760 char *cur, *dest;
761 size_t cur_len, it_len;
762
763 dest = must_copy_string(first);
764 cur_len = it_len = strlen(first);
765
766 va_start(args, first);
767 while ((cur = va_arg(args, char *)) != NULL) {
768 it_len = strlen(cur);
769
770 dest = must_realloc(dest, cur_len + it_len + 1);
771
772 (void)memcpy(dest + cur_len, cur, it_len);
773 cur_len += it_len;
774 }
775 va_end(args);
776
777 dest[cur_len] = 0;
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);
795
796 full_len += buf_len;
37ef15bb
CB
797 if (cur[0] != '/')
798 full_len++;
799
7cfde20f 800 dest = must_realloc(dest, full_len + 1);
37ef15bb 801
7cfde20f 802 if (cur[0] != '/') {
803 memcpy(dest + cur_len, "/", 1);
804 cur_len++;
805 }
806
807 memcpy(dest + cur_len, cur, buf_len);
808 cur_len += buf_len;
37ef15bb
CB
809 }
810 va_end(args);
811
7cfde20f 812 dest[cur_len] = '\0';
37ef15bb
CB
813 return dest;
814}
815
816char *must_append_path(char *first, ...)
817{
818 char *cur;
819 size_t full_len;
820 va_list args;
821 char *dest = first;
822 size_t buf_len;
7cfde20f 823 size_t cur_len;
37ef15bb
CB
824
825 full_len = strlen(first);
7cfde20f 826 cur_len = full_len;
827
37ef15bb
CB
828 va_start(args, first);
829 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 830 buf_len = strlen(cur);
831
832 full_len += buf_len;
37ef15bb
CB
833 if (cur[0] != '/')
834 full_len++;
835
7cfde20f 836 dest = must_realloc(dest, full_len + 1);
37ef15bb 837
7cfde20f 838 if (cur[0] != '/') {
839 memcpy(dest + cur_len, "/", 1);
840 cur_len++;
841 }
842
843 memcpy(dest + cur_len, cur, buf_len);
844 cur_len += buf_len;
37ef15bb
CB
845 }
846 va_end(args);
847
7cfde20f 848 dest[cur_len] = '\0';
37ef15bb
CB
849 return dest;
850}
851
852char *must_copy_string(const char *entry)
853{
854 char *ret;
855
856 if (!entry)
857 return NULL;
858
859 do {
860 ret = strdup(entry);
861 } while (!ret);
862
863 return ret;
864}
865
866void *must_realloc(void *orig, size_t sz)
867{
868 void *ret;
869
870 do {
871 ret = realloc(orig, sz);
872 } while (!ret);
873
874 return ret;
875}
876
877int parse_byte_size_string(const char *s, int64_t *converted)
878{
879 int ret, suffix_len;
880 long long int conv;
881 int64_t mltpl, overflow;
882 char *end;
f1eacafb 883 char dup[INTTYPE_TO_STRLEN(int64_t)];
37ef15bb
CB
884 char suffix[3] = {0};
885
886 if (!s || !strcmp(s, ""))
887 return -EINVAL;
888
889 end = stpncpy(dup, s, sizeof(dup) - 1);
890 if (*end != '\0')
891 return -EINVAL;
892
893 if (isdigit(*(end - 1)))
894 suffix_len = 0;
895 else if (isalpha(*(end - 1)))
896 suffix_len = 1;
897 else
898 return -EINVAL;
899
900 if (suffix_len > 0 && (end - 2) == dup && !isdigit(*(end - 2)))
901 return -EINVAL;
902
903 if (suffix_len > 0 && isalpha(*(end - 2)))
904 suffix_len++;
905
906 if (suffix_len > 0) {
907 memcpy(suffix, end - suffix_len, suffix_len);
908 *(suffix + suffix_len) = '\0';
909 *(end - suffix_len) = '\0';
910 }
911 dup[lxc_char_right_gc(dup, strlen(dup))] = '\0';
912
913 ret = lxc_safe_long_long(dup, &conv);
914 if (ret < 0)
915 return -ret;
916
917 if (suffix_len != 2) {
918 *converted = conv;
919 return 0;
920 }
921
922 if (strcasecmp(suffix, "KB") == 0)
923 mltpl = 1024;
924 else if (strcasecmp(suffix, "MB") == 0)
925 mltpl = 1024 * 1024;
926 else if (strcasecmp(suffix, "GB") == 0)
927 mltpl = 1024 * 1024 * 1024;
928 else
929 return -EINVAL;
930
931 overflow = conv * mltpl;
932 if (conv != 0 && (overflow / conv) != mltpl)
933 return -ERANGE;
934
935 *converted = overflow;
936 return 0;
937}
938
939void remove_trailing_newlines(char *l)
940{
941 char *p = l;
942
943 while (*p)
944 p++;
945
946 while (--p >= l && *p == '\n')
947 *p = '\0';
948}
949
950int lxc_char_left_gc(const char *buffer, size_t len)
951{
952 size_t i;
953
954 for (i = 0; i < len; i++) {
955 if (buffer[i] == ' ' ||
956 buffer[i] == '\t')
957 continue;
958
959 return i;
960 }
961
962 return 0;
963}
964
965int lxc_char_right_gc(const char *buffer, size_t len)
966{
967 int i;
968
969 for (i = len - 1; i >= 0; i--) {
970 if (buffer[i] == ' ' ||
971 buffer[i] == '\t' ||
972 buffer[i] == '\n' ||
973 buffer[i] == '\0')
974 continue;
975
976 return i + 1;
977 }
978
979 return 0;
980}
981
982char *lxc_trim_whitespace_in_place(char *buffer)
983{
984 buffer += lxc_char_left_gc(buffer, strlen(buffer));
985 buffer[lxc_char_right_gc(buffer, strlen(buffer))] = '\0';
986 return buffer;
987}
988
989int lxc_is_line_empty(const char *line)
990{
991 int i;
992 size_t len = strlen(line);
993
994 for (i = 0; i < len; i++)
995 if (line[i] != ' ' && line[i] != '\t' &&
996 line[i] != '\n' && line[i] != '\r' &&
997 line[i] != '\f' && line[i] != '\0')
998 return 0;
999 return 1;
1000}
dca12ddf
CB
1001
1002void remove_trailing_slashes(char *p)
1003{
1004 int l = strlen(p);
1005 while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
1006 p[l] = '\0';
1007}