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