]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/string_utils.c
pam_cgfs: remove dependency from cap & log
[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>
c4a090be 32#include <stdarg.h>
37ef15bb
CB
33#include <stddef.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37ef15bb
CB
37#include <sys/mman.h>
38#include <sys/mount.h>
39#include <sys/param.h>
40#include <sys/prctl.h>
41#include <sys/stat.h>
42#include <sys/types.h>
43#include <sys/wait.h>
d38dd64a 44#include <unistd.h>
37ef15bb 45
d38dd64a 46#include "config.h"
37ef15bb 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
CB
61char **lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup)
62{
63 va_list ap2;
64 size_t count = 1 + skip;
65 char **result;
66
67 /* first determine size of argument list, we don't want to reallocate
68 * constantly...
69 */
70 va_copy(ap2, ap);
71 while (1) {
72 char *arg = va_arg(ap2, char *);
73 if (!arg)
74 break;
75 count++;
76 }
77 va_end(ap2);
78
79 result = calloc(count, sizeof(char *));
80 if (!result)
81 return NULL;
82
83 count = skip;
84 while (1) {
85 char *arg = va_arg(ap, char *);
86 if (!arg)
87 break;
88 arg = do_strdup ? strdup(arg) : arg;
89 if (!arg)
90 goto oom;
91 result[count++] = arg;
92 }
93
94 /* calloc has already set last element to NULL*/
95 return result;
96
97oom:
98 free(result);
99 return NULL;
100}
101
102const char **lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
103{
104 return (const char **)lxc_va_arg_list_to_argv(ap, skip, 0);
105}
106
107char *lxc_string_replace(const char *needle, const char *replacement,
108 const char *haystack)
109{
110 ssize_t len = -1, saved_len = -1;
111 char *result = NULL;
112 size_t replacement_len = strlen(replacement);
113 size_t needle_len = strlen(needle);
114
115 /* should be executed exactly twice */
116 while (len == -1 || result == NULL) {
117 char *p;
118 char *last_p;
119 ssize_t part_len;
120
121 if (len != -1) {
122 result = calloc(1, len + 1);
123 if (!result)
124 return NULL;
125
126 saved_len = len;
127 }
128
129 len = 0;
130
131 for (last_p = (char *)haystack, p = strstr(last_p, needle); p;
132 last_p = p, p = strstr(last_p, needle)) {
133 part_len = (ssize_t)(p - last_p);
134 if (result && part_len > 0)
135 memcpy(&result[len], last_p, part_len);
136
137 len += part_len;
138
139 if (result && replacement_len > 0)
140 memcpy(&result[len], replacement,
141 replacement_len);
142
143 len += replacement_len;
144 p += needle_len;
145 }
146
147 part_len = strlen(last_p);
148 if (result && part_len > 0)
149 memcpy(&result[len], last_p, part_len);
150
151 len += part_len;
152 }
153
154 /* make sure we did the same thing twice,
155 * once for calculating length, the other
156 * time for copying data */
157 if (saved_len != len) {
158 free(result);
159 return NULL;
160 }
161
162 /* make sure we didn't overwrite any buffer,
163 * due to calloc the string should be 0-terminated */
164 if (result[len] != '\0') {
165 free(result);
166 return NULL;
167 }
168
169 return result;
170}
171
172bool lxc_string_in_array(const char *needle, const char **haystack)
173{
174 for (; haystack && *haystack; haystack++)
175 if (!strcmp(needle, *haystack))
176 return true;
177
178 return false;
179}
180
181char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix)
182{
183 char *result;
184 char **p;
185 size_t sep_len = strlen(sep);
186 size_t result_len = use_as_prefix * sep_len;
187 size_t buf_len;
188
189 /* calculate new string length */
190 for (p = (char **)parts; *p; p++)
191 result_len += (p > (char **)parts) * sep_len + strlen(*p);
192
193 buf_len = result_len + 1;
194 result = calloc(buf_len, 1);
195 if (!result)
196 return NULL;
197
198 if (use_as_prefix)
199 (void)strlcpy(result, sep, buf_len);
200
201 for (p = (char **)parts; *p; p++) {
202 if (p > (char **)parts)
203 (void)strlcat(result, sep, buf_len);
204
205 (void)strlcat(result, *p, buf_len);
206 }
207
208 return result;
209}
210
211char **lxc_normalize_path(const char *path)
212{
213 char **components;
214 char **p;
215 size_t components_len = 0;
216 size_t pos = 0;
217
218 components = lxc_string_split(path, '/');
219 if (!components)
220 return NULL;
221
222 for (p = components; *p; p++)
223 components_len++;
224
225 /* resolve '.' and '..' */
226 for (pos = 0; pos < components_len;) {
227 if (!strcmp(components[pos], ".") ||
228 (!strcmp(components[pos], "..") && pos == 0)) {
229 /* eat this element */
230 free(components[pos]);
231 memmove(&components[pos], &components[pos + 1],
232 sizeof(char *) * (components_len - pos));
233 components_len--;
234 } else if (!strcmp(components[pos], "..")) {
235 /* eat this and the previous element */
236 free(components[pos - 1]);
237 free(components[pos]);
238 memmove(&components[pos - 1], &components[pos + 1],
239 sizeof(char *) * (components_len - pos));
240 components_len -= 2;
241 pos--;
242 } else {
243 pos++;
244 }
245 }
246
247 return components;
248}
249
250char *lxc_deslashify(const char *path)
251{
252 char *dup, *p;
253 char **parts = NULL;
254 size_t n, len;
255
256 dup = strdup(path);
257 if (!dup)
258 return NULL;
259
260 parts = lxc_normalize_path(dup);
261 if (!parts) {
262 free(dup);
263 return NULL;
264 }
265
266 /* We'll end up here if path == "///" or path == "". */
267 if (!*parts) {
268 len = strlen(dup);
269 if (!len) {
270 lxc_free_array((void **)parts, free);
271 return dup;
272 }
273
274 n = strcspn(dup, "/");
275 if (n == len) {
276 free(dup);
277 lxc_free_array((void **)parts, free);
278
279 p = strdup("/");
280 if (!p)
281 return NULL;
282
283 return p;
284 }
285 }
286
287 p = lxc_string_join("/", (const char **)parts, *dup == '/');
288 free(dup);
289 lxc_free_array((void **)parts, free);
290 return p;
291}
292
293char *lxc_append_paths(const char *first, const char *second)
294{
295 int ret;
296 size_t len;
297 char *result = NULL;
298 const char *pattern = "%s%s";
299
300 len = strlen(first) + strlen(second) + 1;
301 if (second[0] != '/') {
302 len += 1;
303 pattern = "%s/%s";
304 }
305
306 result = calloc(1, len);
307 if (!result)
308 return NULL;
309
310 ret = snprintf(result, len, pattern, first, second);
311 if (ret < 0 || (size_t)ret >= len) {
312 free(result);
313 return NULL;
314 }
315
316 return result;
317}
318
319bool lxc_string_in_list(const char *needle, const char *haystack, char _sep)
320{
321 char *token, *str;
322 char sep[2] = { _sep, '\0' };
323 size_t len;
324
325 if (!haystack || !needle)
326 return 0;
327
328 len = strlen(haystack);
329 str = alloca(len + 1);
330 (void)strlcpy(str, haystack, len + 1);
331
332 lxc_iterate_parts(token, str, sep)
333 if (strcmp(needle, token) == 0)
334 return 1;
335
336 return 0;
337}
338
339char **lxc_string_split(const char *string, char _sep)
340{
341 char *token, *str;
342 char sep[2] = {_sep, '\0'};
343 char **tmp = NULL, **result = NULL;
344 size_t result_capacity = 0;
345 size_t result_count = 0;
346 int r, saved_errno;
347 size_t len;
348
349 if (!string)
350 return calloc(1, sizeof(char *));
351
352 len = strlen(string);
353 str = alloca(len + 1);
354 (void)strlcpy(str, string, len + 1);
355
356 lxc_iterate_parts(token, str, sep) {
357 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
358 if (r < 0)
359 goto error_out;
360
361 result[result_count] = strdup(token);
362 if (!result[result_count])
363 goto error_out;
364
365 result_count++;
366 }
367
368 /* if we allocated too much, reduce it */
369 tmp = realloc(result, (result_count + 1) * sizeof(char *));
370 if (!tmp)
371 goto error_out;
372
373 result = tmp;
374
375 /* Make sure we don't return uninitialized memory. */
376 if (result_count == 0)
377 *result = NULL;
378
379 return result;
380
381error_out:
382 saved_errno = errno;
383 lxc_free_array((void **)result, free);
384 errno = saved_errno;
385 return NULL;
386}
387
388static bool complete_word(char ***result, char *start, char *end, size_t *cap,
389 size_t *cnt)
390{
391 int r;
392
393 r = lxc_grow_array((void ***)result, cap, 2 + *cnt, 16);
394 if (r < 0)
395 return false;
396
397 (*result)[*cnt] = strndup(start, end - start);
398 if (!(*result)[*cnt])
399 return false;
400
401 (*cnt)++;
402
403 return true;
404}
405
406/*
407 * Given a a string 'one two "three four"', split into three words,
408 * one, two, and "three four"
409 */
410char **lxc_string_split_quoted(char *string)
411{
412 char *nextword = string, *p, state;
413 char **result = NULL;
414 size_t result_capacity = 0;
415 size_t result_count = 0;
416
417 if (!string || !*string)
418 return calloc(1, sizeof(char *));
419
420 // TODO I'm *not* handling escaped quote
421 state = ' ';
422 for (p = string; *p; p++) {
423 switch(state) {
424 case ' ':
425 if (isspace(*p))
426 continue;
427 else if (*p == '"' || *p == '\'') {
428 nextword = p;
429 state = *p;
430 continue;
431 }
432 nextword = p;
433 state = 'a';
434 continue;
435 case 'a':
436 if (isspace(*p)) {
437 complete_word(&result, nextword, p, &result_capacity, &result_count);
438 state = ' ';
439 continue;
440 }
441 continue;
442 case '"':
443 case '\'':
444 if (*p == state) {
445 complete_word(&result, nextword+1, p, &result_capacity, &result_count);
446 state = ' ';
447 continue;
448 }
449 continue;
450 }
451 }
452
453 if (state == 'a')
454 complete_word(&result, nextword, p, &result_capacity, &result_count);
455
456 return realloc(result, (result_count + 1) * sizeof(char *));
457}
458
459char **lxc_string_split_and_trim(const char *string, char _sep)
460{
461 char *token, *str;
462 char sep[2] = { _sep, '\0' };
463 char **result = NULL;
464 size_t result_capacity = 0;
465 size_t result_count = 0;
466 int r, saved_errno;
467 size_t i = 0;
468 size_t len;
469
470 if (!string)
471 return calloc(1, sizeof(char *));
472
473 len = strlen(string);
474 str = alloca(len + 1);
475 (void)strlcpy(str, string, len + 1);
476
477 lxc_iterate_parts(token, str, sep) {
478 while (token[0] == ' ' || token[0] == '\t')
479 token++;
480
481 i = strlen(token);
482 while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
483 token[i - 1] = '\0';
484 i--;
485 }
486
487 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
488 if (r < 0)
489 goto error_out;
490
491 result[result_count] = strdup(token);
492 if (!result[result_count])
493 goto error_out;
494
495 result_count++;
496 }
497
498 /* if we allocated too much, reduce it */
499 return realloc(result, (result_count + 1) * sizeof(char *));
500
501error_out:
502 saved_errno = errno;
503 lxc_free_array((void **)result, free);
504 errno = saved_errno;
505 return NULL;
506}
507
508void lxc_free_array(void **array, lxc_free_fn element_free_fn)
509{
510 void **p;
511
512 for (p = array; p && *p; p++)
513 element_free_fn(*p);
514
515 free((void*)array);
516}
517
518int lxc_grow_array(void ***array, size_t *capacity, size_t new_size, size_t capacity_increment)
519{
520 size_t new_capacity;
521 void **new_array;
522
523 /* first time around, catch some trivial mistakes of the user
524 * only initializing one of these */
525 if (!*array || !*capacity) {
526 *array = NULL;
527 *capacity = 0;
528 }
529
530 new_capacity = *capacity;
531 while (new_size + 1 > new_capacity)
532 new_capacity += capacity_increment;
533
534 if (new_capacity != *capacity) {
535 /* we have to reallocate */
536 new_array = realloc(*array, new_capacity * sizeof(void *));
537 if (!new_array)
538 return -1;
539
540 memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * sizeof(void *));
541 *array = new_array;
542 *capacity = new_capacity;
543 }
544
545 /* array has sufficient elements */
546 return 0;
547}
548
549size_t lxc_array_len(void **array)
550{
551 void **p;
552 size_t result = 0;
553
554 for (p = array; p && *p; p++)
555 result++;
556
557 return result;
558}
559
560void **lxc_append_null_to_array(void **array, size_t count)
561{
562 void **temp;
563
564 /* Append NULL to the array */
565 if (count) {
566 temp = realloc(array, (count + 1) * sizeof(*array));
567 if (!temp) {
568 size_t i;
569 for (i = 0; i < count; i++)
570 free(array[i]);
571 free(array);
572 return NULL;
573 }
574
575 array = temp;
576 array[count] = NULL;
577 }
578
579 return array;
580}
581
582static int lxc_append_null_to_list(void ***list)
583{
584 int newentry = 0;
585 void **tmp;
586
587 if (*list)
588 for (; (*list)[newentry]; newentry++) {
589 ;
590 }
591
592 tmp = realloc(*list, (newentry + 2) * sizeof(void **));
593 if (!tmp)
594 return -1;
595
596 *list = tmp;
597 (*list)[newentry + 1] = NULL;
598
599 return newentry;
600}
601
602int lxc_append_string(char ***list, char *entry)
603{
604 char *copy;
605 int newentry;
606
607 newentry = lxc_append_null_to_list((void ***)list);
608 if (newentry < 0)
609 return -1;
610
611 copy = strdup(entry);
612 if (!copy)
613 return -1;
614
615 (*list)[newentry] = copy;
616
617 return 0;
618}
619
620int lxc_safe_uint(const char *numstr, unsigned int *converted)
621{
622 char *err = NULL;
623 unsigned long int uli;
624
625 while (isspace(*numstr))
626 numstr++;
627
628 if (*numstr == '-')
629 return -EINVAL;
630
631 errno = 0;
632 uli = strtoul(numstr, &err, 0);
633 if (errno == ERANGE && uli == ULONG_MAX)
634 return -ERANGE;
635
636 if (err == numstr || *err != '\0')
637 return -EINVAL;
638
639 if (uli > UINT_MAX)
640 return -ERANGE;
641
642 *converted = (unsigned int)uli;
643 return 0;
644}
645
646int lxc_safe_ulong(const char *numstr, unsigned long *converted)
647{
648 char *err = NULL;
649 unsigned long int uli;
650
651 while (isspace(*numstr))
652 numstr++;
653
654 if (*numstr == '-')
655 return -EINVAL;
656
657 errno = 0;
658 uli = strtoul(numstr, &err, 0);
659 if (errno == ERANGE && uli == ULONG_MAX)
660 return -ERANGE;
661
662 if (err == numstr || *err != '\0')
663 return -EINVAL;
664
665 *converted = uli;
666 return 0;
667}
668
669int lxc_safe_uint64(const char *numstr, uint64_t *converted, int base)
670{
671 char *err = NULL;
672 uint64_t u;
673
674 while (isspace(*numstr))
675 numstr++;
676
677 if (*numstr == '-')
678 return -EINVAL;
679
680 errno = 0;
681 u = strtoull(numstr, &err, base);
62fc8403 682 if (errno == ERANGE && u == UINT64_MAX)
37ef15bb
CB
683 return -ERANGE;
684
685 if (err == numstr || *err != '\0')
686 return -EINVAL;
687
688 *converted = u;
689 return 0;
690}
691
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
755char *must_concat(const char *first, ...)
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';
37ef15bb
CB
776 return dest;
777}
778
779char *must_make_path(const char *first, ...)
780{
781 va_list args;
782 char *cur, *dest;
783 size_t full_len = strlen(first);
784 size_t buf_len;
7cfde20f 785 size_t cur_len;
37ef15bb
CB
786
787 dest = must_copy_string(first);
7cfde20f 788 cur_len = full_len;
37ef15bb
CB
789
790 va_start(args, first);
791 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 792 buf_len = strlen(cur);
793
794 full_len += buf_len;
37ef15bb
CB
795 if (cur[0] != '/')
796 full_len++;
797
7cfde20f 798 dest = must_realloc(dest, full_len + 1);
37ef15bb 799
7cfde20f 800 if (cur[0] != '/') {
801 memcpy(dest + cur_len, "/", 1);
802 cur_len++;
803 }
804
805 memcpy(dest + cur_len, cur, buf_len);
806 cur_len += buf_len;
37ef15bb
CB
807 }
808 va_end(args);
809
7cfde20f 810 dest[cur_len] = '\0';
37ef15bb
CB
811 return dest;
812}
813
814char *must_append_path(char *first, ...)
815{
816 char *cur;
817 size_t full_len;
818 va_list args;
819 char *dest = first;
820 size_t buf_len;
7cfde20f 821 size_t cur_len;
37ef15bb
CB
822
823 full_len = strlen(first);
7cfde20f 824 cur_len = full_len;
825
37ef15bb
CB
826 va_start(args, first);
827 while ((cur = va_arg(args, char *)) != NULL) {
7cfde20f 828 buf_len = strlen(cur);
829
830 full_len += buf_len;
37ef15bb
CB
831 if (cur[0] != '/')
832 full_len++;
833
7cfde20f 834 dest = must_realloc(dest, full_len + 1);
37ef15bb 835
7cfde20f 836 if (cur[0] != '/') {
837 memcpy(dest + cur_len, "/", 1);
838 cur_len++;
839 }
840
841 memcpy(dest + cur_len, cur, buf_len);
842 cur_len += buf_len;
37ef15bb
CB
843 }
844 va_end(args);
845
7cfde20f 846 dest[cur_len] = '\0';
37ef15bb
CB
847 return dest;
848}
849
850char *must_copy_string(const char *entry)
851{
852 char *ret;
853
854 if (!entry)
855 return NULL;
856
857 do {
858 ret = strdup(entry);
859 } while (!ret);
860
861 return ret;
862}
863
864void *must_realloc(void *orig, size_t sz)
865{
866 void *ret;
867
868 do {
869 ret = realloc(orig, sz);
870 } while (!ret);
871
872 return ret;
873}
874
875int parse_byte_size_string(const char *s, int64_t *converted)
876{
877 int ret, suffix_len;
878 long long int conv;
879 int64_t mltpl, overflow;
880 char *end;
f1eacafb 881 char dup[INTTYPE_TO_STRLEN(int64_t)];
37ef15bb
CB
882 char suffix[3] = {0};
883
884 if (!s || !strcmp(s, ""))
885 return -EINVAL;
886
887 end = stpncpy(dup, s, sizeof(dup) - 1);
888 if (*end != '\0')
889 return -EINVAL;
890
891 if (isdigit(*(end - 1)))
892 suffix_len = 0;
893 else if (isalpha(*(end - 1)))
894 suffix_len = 1;
895 else
896 return -EINVAL;
897
898 if (suffix_len > 0 && (end - 2) == dup && !isdigit(*(end - 2)))
899 return -EINVAL;
900
901 if (suffix_len > 0 && isalpha(*(end - 2)))
902 suffix_len++;
903
904 if (suffix_len > 0) {
905 memcpy(suffix, end - suffix_len, suffix_len);
906 *(suffix + suffix_len) = '\0';
907 *(end - suffix_len) = '\0';
908 }
909 dup[lxc_char_right_gc(dup, strlen(dup))] = '\0';
910
911 ret = lxc_safe_long_long(dup, &conv);
912 if (ret < 0)
913 return -ret;
914
915 if (suffix_len != 2) {
916 *converted = conv;
917 return 0;
918 }
919
920 if (strcasecmp(suffix, "KB") == 0)
921 mltpl = 1024;
922 else if (strcasecmp(suffix, "MB") == 0)
923 mltpl = 1024 * 1024;
924 else if (strcasecmp(suffix, "GB") == 0)
925 mltpl = 1024 * 1024 * 1024;
926 else
927 return -EINVAL;
928
929 overflow = conv * mltpl;
930 if (conv != 0 && (overflow / conv) != mltpl)
931 return -ERANGE;
932
933 *converted = overflow;
934 return 0;
935}
936
937void remove_trailing_newlines(char *l)
938{
939 char *p = l;
940
941 while (*p)
942 p++;
943
944 while (--p >= l && *p == '\n')
945 *p = '\0';
946}
947
948int lxc_char_left_gc(const char *buffer, size_t len)
949{
950 size_t i;
951
952 for (i = 0; i < len; i++) {
953 if (buffer[i] == ' ' ||
954 buffer[i] == '\t')
955 continue;
956
957 return i;
958 }
959
960 return 0;
961}
962
963int lxc_char_right_gc(const char *buffer, size_t len)
964{
965 int i;
966
967 for (i = len - 1; i >= 0; i--) {
968 if (buffer[i] == ' ' ||
969 buffer[i] == '\t' ||
970 buffer[i] == '\n' ||
971 buffer[i] == '\0')
972 continue;
973
974 return i + 1;
975 }
976
977 return 0;
978}
979
980char *lxc_trim_whitespace_in_place(char *buffer)
981{
982 buffer += lxc_char_left_gc(buffer, strlen(buffer));
983 buffer[lxc_char_right_gc(buffer, strlen(buffer))] = '\0';
984 return buffer;
985}
986
987int lxc_is_line_empty(const char *line)
988{
989 int i;
990 size_t len = strlen(line);
991
992 for (i = 0; i < len; i++)
993 if (line[i] != ' ' && line[i] != '\t' &&
994 line[i] != '\n' && line[i] != '\r' &&
995 line[i] != '\f' && line[i] != '\0')
996 return 0;
997 return 1;
998}
dca12ddf
CB
999
1000void remove_trailing_slashes(char *p)
1001{
1002 int l = strlen(p);
1003 while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
1004 p[l] = '\0';
1005}