]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/utils.c
make heavier use of process_lock (v2)
[mirror_lxc.git] / src / lxc / utils.c
CommitLineData
e3642c43
DL
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
9afe19d6 7 * Daniel Lezcano <daniel.lezcano at free.fr>
e3642c43
DL
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
250b1eec 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
e3642c43
DL
22 */
23
d983b93c 24#define _GNU_SOURCE
e3642c43
DL
25#include <errno.h>
26#include <unistd.h>
d983b93c
MN
27#include <stdlib.h>
28#include <stddef.h>
61a1d519 29#include <string.h>
e3642c43
DL
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <sys/mman.h>
d983b93c 33#include <sys/param.h>
6e4bb2e0 34#include <sys/mount.h>
d983b93c
MN
35#include <dirent.h>
36#include <fcntl.h>
1b09f2c0 37#include <libgen.h>
9be53773
SH
38#include <sys/types.h>
39#include <sys/wait.h>
502657d5 40#include <assert.h>
e3642c43 41
0e95426b
CS
42#ifndef HAVE_GETLINE
43#ifdef HAVE_FGETLN
44#include <../include/getline.h>
45#endif
46#endif
47
3ce74686 48#include "utils.h"
e3642c43 49#include "log.h"
025ed0f3 50#include "lxclock.h"
e3642c43
DL
51
52lxc_log_define(lxc_utils, lxc);
53
60bf62d4
SH
54static int _recursive_rmdir_onedev(char *dirname, dev_t pdev)
55{
56 struct dirent dirent, *direntp;
57 DIR *dir;
58 int ret, failed=0;
59 char pathname[MAXPATHLEN];
60
025ed0f3 61 process_lock();
60bf62d4 62 dir = opendir(dirname);
025ed0f3 63 process_unlock();
60bf62d4
SH
64 if (!dir) {
65 ERROR("%s: failed to open %s", __func__, dirname);
66 return 0;
67 }
68
69 while (!readdir_r(dir, &dirent, &direntp)) {
70 struct stat mystat;
71 int rc;
72
73 if (!direntp)
74 break;
75
76 if (!strcmp(direntp->d_name, ".") ||
77 !strcmp(direntp->d_name, ".."))
78 continue;
79
80 rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name);
81 if (rc < 0 || rc >= MAXPATHLEN) {
82 ERROR("pathname too long");
83 failed=1;
84 continue;
85 }
86 ret = lstat(pathname, &mystat);
87 if (ret) {
88 ERROR("%s: failed to stat %s", __func__, pathname);
89 failed=1;
90 continue;
91 }
92 if (mystat.st_dev != pdev)
93 continue;
94 if (S_ISDIR(mystat.st_mode)) {
95 if (!_recursive_rmdir_onedev(pathname, pdev))
96 failed=1;
97 } else {
98 if (unlink(pathname) < 0) {
99 ERROR("%s: failed to delete %s", __func__, pathname);
100 failed=1;
101 }
102 }
103 }
104
105 if (rmdir(dirname) < 0) {
106 ERROR("%s: failed to delete %s", __func__, dirname);
107 failed=1;
108 }
109
025ed0f3
SH
110 process_lock();
111 ret = closedir(dir);
112 process_unlock();
113 if (ret) {
60bf62d4
SH
114 ERROR("%s: failed to close directory %s", __func__, dirname);
115 failed=1;
116 }
117
118 return !failed;
119}
120
121/* returns 1 on success, 0 if there were any failures */
122extern int lxc_rmdir_onedev(char *path)
123{
124 struct stat mystat;
125
126 if (lstat(path, &mystat) < 0) {
127 ERROR("%s: failed to stat %s", __func__, path);
128 return 0;
129 }
130
131 return _recursive_rmdir_onedev(path, mystat.st_dev);
132}
133
6e4bb2e0
MN
134static int mount_fs(const char *source, const char *target, const char *type)
135{
136 /* the umount may fail */
137 if (umount(target))
138 WARN("failed to unmount %s : %s", target, strerror(errno));
139
140 if (mount(source, target, type, 0, NULL)) {
141 ERROR("failed to mount %s : %s", target, strerror(errno));
142 return -1;
143 }
144
145 DEBUG("'%s' mounted on '%s'", source, target);
146
147 return 0;
148}
149
150extern int lxc_setup_fs(void)
151{
152 if (mount_fs("proc", "/proc", "proc"))
153 return -1;
154
721d262c 155 /* if we can't mount /dev/shm, continue anyway */
6e4bb2e0 156 if (mount_fs("shmfs", "/dev/shm", "tmpfs"))
3283db09 157 INFO("failed to mount /dev/shm");
6e4bb2e0
MN
158
159 /* If we were able to mount /dev/shm, then /dev exists */
b91b1cd7 160 /* Sure, but it's read-only per config :) */
6e4bb2e0 161 if (access("/dev/mqueue", F_OK) && mkdir("/dev/mqueue", 0666)) {
b91b1cd7
SH
162 DEBUG("failed to create '/dev/mqueue'");
163 return 0;
6e4bb2e0
MN
164 }
165
5d4d3ebb 166 /* continue even without posix message queue support */
6e4bb2e0 167 if (mount_fs("mqueue", "/dev/mqueue", "mqueue"))
5d4d3ebb 168 INFO("failed to mount /dev/mqueue");
6e4bb2e0
MN
169
170 return 0;
171}
9ddaf3bf
JHS
172
173/* borrowed from iproute2 */
7c11d57a 174extern int get_u16(unsigned short *val, const char *arg, int base)
9ddaf3bf
JHS
175{
176 unsigned long res;
177 char *ptr;
178
179 if (!arg || !*arg)
180 return -1;
181
182 res = strtoul(arg, &ptr, base);
183 if (!ptr || ptr == arg || *ptr || res > 0xFFFF)
184 return -1;
185
186 *val = res;
187
188 return 0;
189}
190
3ce74686 191extern int mkdir_p(const char *dir, mode_t mode)
1b09f2c0 192{
3ce74686
SH
193 const char *tmp = dir;
194 const char *orig = dir;
860fc865
RW
195 char *makeme;
196
197 do {
198 dir = tmp + strspn(tmp, "/");
199 tmp = dir + strcspn(dir, "/");
d74325c4 200 makeme = strndup(orig, dir - orig);
860fc865
RW
201 if (*makeme) {
202 if (mkdir(makeme, mode) && errno != EEXIST) {
203 SYSERROR("failed to create directory '%s'\n", makeme);
d74325c4 204 free(makeme);
860fc865
RW
205 return -1;
206 }
207 }
d74325c4 208 free(makeme);
860fc865 209 } while(tmp != dir);
1b09f2c0 210
98663823 211 return 0;
1b09f2c0 212}
2a59a681 213
d0386d66 214static char *copy_global_config_value(char *p)
2a59a681
SH
215{
216 int len = strlen(p);
217 char *retbuf;
218
219 if (len < 1)
220 return NULL;
221 if (p[len-1] == '\n') {
222 p[len-1] = '\0';
223 len--;
224 }
225 retbuf = malloc(len+1);
226 if (!retbuf)
227 return NULL;
228 strcpy(retbuf, p);
229 return retbuf;
230}
231
31a95fec 232#define DEFAULT_VG "lxc"
31a95fec 233#define DEFAULT_ZFSROOT "lxc"
67e571de 234
d0386d66 235const char *lxc_global_config_value(const char *option_name)
31a95fec 236{
d0386d66
CS
237 static const char *options[][2] = {
238 { "lvm_vg", DEFAULT_VG },
239 { "zfsroot", DEFAULT_ZFSROOT },
240 { "lxcpath", LXCPATH },
6e16552d 241 { "cgroup.pattern", DEFAULT_CGROUP_PATTERN },
33ad9f1a 242 { "cgroup.use", NULL },
d0386d66
CS
243 { NULL, NULL },
244 };
245 static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
246 const char *(*ptr)[2];
247 size_t i;
248 char buf[1024], *p, *p2;
249 FILE *fin = NULL;
250
251 for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
252 if (!strcmp(option_name, (*ptr)[0]))
253 break;
254 }
255 if (!(*ptr)[0]) {
256 errno = EINVAL;
257 return NULL;
258 }
259 if (values[i])
260 return values[i];
31a95fec 261
025ed0f3 262 process_lock();
db27c8d7 263 fin = fopen_cloexec(LXC_GLOBAL_CONF, "r");
025ed0f3 264 process_unlock();
31a95fec
SH
265 if (fin) {
266 while (fgets(buf, 1024, fin)) {
267 if (buf[0] == '#')
268 continue;
d0386d66 269 p = strstr(buf, option_name);
31a95fec
SH
270 if (!p)
271 continue;
d0386d66
CS
272 /* see if there was just white space in front
273 * of the option name
274 */
275 for (p2 = buf; p2 < p; p2++) {
276 if (*p2 != ' ' && *p2 != '\t')
277 break;
278 }
279 if (p2 < p)
280 continue;
31a95fec
SH
281 p = strchr(p, '=');
282 if (!p)
283 continue;
d0386d66
CS
284 /* see if there was just white space after
285 * the option name
286 */
287 for (p2 += strlen(option_name); p2 < p; p2++) {
288 if (*p2 != ' ' && *p2 != '\t')
289 break;
290 }
291 if (p2 < p)
292 continue;
31a95fec
SH
293 p++;
294 while (*p && (*p == ' ' || *p == '\t')) p++;
295 if (!*p)
296 continue;
d0386d66 297 values[i] = copy_global_config_value(p);
31a95fec
SH
298 goto out;
299 }
300 }
d0386d66
CS
301 /* could not find value, use default */
302 values[i] = (*ptr)[1];
303 /* special case: if default value is NULL,
304 * and there is no config, don't view that
305 * as an error... */
306 if (!values[i])
307 errno = 0;
31a95fec
SH
308
309out:
025ed0f3 310 process_lock();
31a95fec
SH
311 if (fin)
312 fclose(fin);
025ed0f3 313 process_unlock();
d0386d66 314 return values[i];
31a95fec
SH
315}
316
d0386d66 317const char *default_lvm_vg(void)
31a95fec 318{
d0386d66
CS
319 return lxc_global_config_value("lvm_vg");
320}
31a95fec 321
d0386d66
CS
322const char *default_zfs_root(void)
323{
324 return lxc_global_config_value("zfsroot");
31a95fec 325}
67e571de 326const char *default_lxc_path(void)
2a59a681 327{
d0386d66 328 return lxc_global_config_value("lxcpath");
2a59a681 329}
9be53773 330
9e60f51d
DE
331const char *get_rundir()
332{
333 const char *rundir;
334
335 rundir = getenv("XDG_RUNTIME_DIR");
336 if (geteuid() == 0 || rundir == NULL)
337 rundir = "/run";
338 return rundir;
339}
340
9be53773
SH
341int wait_for_pid(pid_t pid)
342{
343 int status, ret;
344
345again:
346 ret = waitpid(pid, &status, 0);
347 if (ret == -1) {
71b9b8ed 348 if (errno == EINTR)
9be53773
SH
349 goto again;
350 return -1;
351 }
352 if (ret != pid)
353 goto again;
354 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
355 return -1;
356 return 0;
357}
c797a220
CS
358
359int lxc_wait_for_pid_status(pid_t pid)
360{
361 int status, ret;
362
363again:
364 ret = waitpid(pid, &status, 0);
365 if (ret == -1) {
366 if (errno == EINTR)
367 goto again;
368 return -1;
369 }
370 if (ret != pid)
371 goto again;
372 return status;
373}
92f023dc 374
650468bb 375ssize_t lxc_write_nointr(int fd, const void* buf, size_t count)
92f023dc 376{
650468bb 377 ssize_t ret;
92f023dc
CS
378again:
379 ret = write(fd, buf, count);
380 if (ret < 0 && errno == EINTR)
381 goto again;
382 return ret;
383}
384
650468bb 385ssize_t lxc_read_nointr(int fd, void* buf, size_t count)
92f023dc 386{
650468bb 387 ssize_t ret;
92f023dc
CS
388again:
389 ret = read(fd, buf, count);
390 if (ret < 0 && errno == EINTR)
391 goto again;
392 return ret;
393}
394
650468bb 395ssize_t lxc_read_nointr_expect(int fd, void* buf, size_t count, const void* expected_buf)
92f023dc 396{
650468bb 397 ssize_t ret;
92f023dc
CS
398 ret = lxc_read_nointr(fd, buf, count);
399 if (ret <= 0)
400 return ret;
650468bb 401 if ((size_t)ret != count)
92f023dc
CS
402 return -1;
403 if (expected_buf && memcmp(buf, expected_buf, count) != 0) {
404 errno = EINVAL;
405 return -1;
406 }
407 return ret;
408}
3ce74686 409
025ed0f3
SH
410static inline int lock_fclose(FILE *f)
411{
412 int ret;
413 process_lock();
414 ret = fclose(f);
415 process_unlock();
416 return ret;
417}
418
3ce74686
SH
419#if HAVE_LIBGNUTLS
420#include <gnutls/gnutls.h>
421#include <gnutls/crypto.h>
422int sha1sum_file(char *fnam, unsigned char *digest)
423{
424 char *buf;
425 int ret;
426 FILE *f;
427 long flen;
428
429 if (!fnam)
430 return -1;
025ed0f3
SH
431 process_lock();
432 f = fopen_cloexec(fnam, "r");
433 process_unlock();
434 if (f < 0) {
3ce74686
SH
435 SYSERROR("Error opening template");
436 return -1;
437 }
438 if (fseek(f, 0, SEEK_END) < 0) {
439 SYSERROR("Error seeking to end of template");
025ed0f3 440 lock_fclose(f);
3ce74686
SH
441 return -1;
442 }
443 if ((flen = ftell(f)) < 0) {
444 SYSERROR("Error telling size of template");
025ed0f3 445 lock_fclose(f);
3ce74686
SH
446 return -1;
447 }
448 if (fseek(f, 0, SEEK_SET) < 0) {
449 SYSERROR("Error seeking to start of template");
025ed0f3 450 lock_fclose(f);
3ce74686
SH
451 return -1;
452 }
453 if ((buf = malloc(flen+1)) == NULL) {
454 SYSERROR("Out of memory");
025ed0f3 455 lock_fclose(f);
3ce74686
SH
456 return -1;
457 }
458 if (fread(buf, 1, flen, f) != flen) {
459 SYSERROR("Failure reading template");
460 free(buf);
025ed0f3 461 lock_fclose(f);
3ce74686
SH
462 return -1;
463 }
025ed0f3 464 if (lock_fclose(f) < 0) {
3ce74686
SH
465 SYSERROR("Failre closing template");
466 free(buf);
467 return -1;
468 }
469 buf[flen] = '\0';
470 ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, buf, flen, (void *)digest);
471 free(buf);
472 return ret;
473}
474#endif
61a1d519
CS
475
476char** lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup)
477{
478 va_list ap2;
479 size_t count = 1 + skip;
480 char **result;
481
482 /* first determine size of argument list, we don't want to reallocate
483 * constantly...
484 */
485 va_copy(ap2, ap);
486 while (1) {
487 char* arg = va_arg(ap2, char*);
488 if (!arg)
489 break;
490 count++;
491 }
492 va_end(ap2);
493
494 result = calloc(count, sizeof(char*));
495 if (!result)
496 return NULL;
497 count = skip;
498 while (1) {
499 char* arg = va_arg(ap, char*);
500 if (!arg)
501 break;
502 arg = do_strdup ? strdup(arg) : arg;
503 if (!arg)
504 goto oom;
505 result[count++] = arg;
506 }
507
508 /* calloc has already set last element to NULL*/
509 return result;
510
511oom:
512 free(result);
513 return NULL;
514}
515
516const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
517{
518 return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0);
519}
db27c8d7 520
025ed0f3
SH
521/*
522 * fopen_cloexec: must be called with process_lock() held
523 * if it is needed.
524 */
db27c8d7
CS
525FILE *fopen_cloexec(const char *path, const char *mode)
526{
527 int open_mode = 0;
528 int step = 0;
529 int fd;
530 int saved_errno = 0;
531 FILE *ret;
532
533 if (!strncmp(mode, "r+", 2)) {
534 open_mode = O_RDWR;
535 step = 2;
536 } else if (!strncmp(mode, "r", 1)) {
537 open_mode = O_RDONLY;
538 step = 1;
539 } else if (!strncmp(mode, "w+", 2)) {
540 open_mode = O_RDWR | O_TRUNC | O_CREAT;
541 step = 2;
542 } else if (!strncmp(mode, "w", 1)) {
543 open_mode = O_WRONLY | O_TRUNC | O_CREAT;
544 step = 1;
545 } else if (!strncmp(mode, "a+", 2)) {
546 open_mode = O_RDWR | O_CREAT | O_APPEND;
547 step = 2;
548 } else if (!strncmp(mode, "a", 1)) {
549 open_mode = O_WRONLY | O_CREAT | O_APPEND;
550 step = 1;
551 }
552 for (; mode[step]; step++)
553 if (mode[step] == 'x')
554 open_mode |= O_EXCL;
555 open_mode |= O_CLOEXEC;
556
82371fdd 557 fd = open(path, open_mode, 0666);
db27c8d7
CS
558 if (fd < 0)
559 return NULL;
560
561 ret = fdopen(fd, mode);
562 saved_errno = errno;
563 if (!ret)
564 close(fd);
565 errno = saved_errno;
566 return ret;
567}
502657d5
CS
568
569char *lxc_string_replace(const char *needle, const char *replacement, const char *haystack)
570{
571 ssize_t len = -1, saved_len = -1;
572 char *result = NULL;
573 size_t replacement_len = strlen(replacement);
574 size_t needle_len = strlen(needle);
575
576 /* should be executed exactly twice */
577 while (len == -1 || result == NULL) {
578 char *p;
579 char *last_p;
580 ssize_t part_len;
581
582 if (len != -1) {
583 result = calloc(1, len + 1);
584 if (!result)
585 return NULL;
586 saved_len = len;
587 }
588
589 len = 0;
590
591 for (last_p = (char *)haystack, p = strstr(last_p, needle); p; last_p = p, p = strstr(last_p, needle)) {
592 part_len = (ssize_t)(p - last_p);
593 if (result && part_len > 0)
594 memcpy(&result[len], last_p, part_len);
595 len += part_len;
596 if (result && replacement_len > 0)
597 memcpy(&result[len], replacement, replacement_len);
598 len += replacement_len;
599 p += needle_len;
600 }
601 part_len = strlen(last_p);
602 if (result && part_len > 0)
603 memcpy(&result[len], last_p, part_len);
604 len += part_len;
605 }
606
607 /* make sure we did the same thing twice,
608 * once for calculating length, the other
609 * time for copying data */
610 assert(saved_len == len);
611 /* make sure we didn't overwrite any buffer,
612 * due to calloc the string should be 0-terminated */
613 assert(result[len] == '\0');
614
615 return result;
616}
617
618bool lxc_string_in_array(const char *needle, const char **haystack)
619{
620 for (; haystack && *haystack; haystack++)
621 if (!strcmp(needle, *haystack))
622 return true;
623 return false;
624}
625
626char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix)
627{
628 char *result;
629 char **p;
630 size_t sep_len = strlen(sep);
631 size_t result_len = use_as_prefix * sep_len;
632
633 /* calculate new string length */
634 for (p = (char **)parts; *p; p++)
635 result_len += (p > (char **)parts) * sep_len + strlen(*p);
636
637 result = calloc(result_len + 1, 1);
638 if (!result)
639 return NULL;
640
641 if (use_as_prefix)
642 strcpy(result, sep);
643 for (p = (char **)parts; *p; p++) {
644 if (p > (char **)parts)
645 strcat(result, sep);
646 strcat(result, *p);
647 }
648
649 return result;
650}
651
652char **lxc_normalize_path(const char *path)
653{
654 char **components;
655 char **p;
656 size_t components_len = 0;
657 size_t pos = 0;
658
659 components = lxc_string_split(path, '/');
660 if (!components)
661 return NULL;
662 for (p = components; *p; p++)
663 components_len++;
664
665 /* resolve '.' and '..' */
666 for (pos = 0; pos < components_len; ) {
667 if (!strcmp(components[pos], ".") || (!strcmp(components[pos], "..") && pos == 0)) {
668 /* eat this element */
669 free(components[pos]);
670 memmove(&components[pos], &components[pos+1], sizeof(char *) * (components_len - pos));
671 components_len--;
672 } else if (!strcmp(components[pos], "..")) {
673 /* eat this and the previous element */
674 free(components[pos - 1]);
675 free(components[pos]);
676 memmove(&components[pos-1], &components[pos+1], sizeof(char *) * (components_len - pos));
677 components_len -= 2;
678 pos--;
679 } else {
680 pos++;
681 }
682 }
683
684 return components;
685}
686
24b51482
CS
687char *lxc_append_paths(const char *first, const char *second)
688{
689 size_t len = strlen(first) + strlen(second) + 1;
690 const char *pattern = "%s%s";
691 char *result = NULL;
692
693 if (second[0] != '/') {
694 len += 1;
695 pattern = "%s/%s";
696 }
697
698 result = calloc(1, len);
699 if (!result)
700 return NULL;
701
702 snprintf(result, len, pattern, first, second);
703 return result;
704}
705
502657d5
CS
706bool lxc_string_in_list(const char *needle, const char *haystack, char _sep)
707{
708 char *token, *str, *saveptr = NULL;
709 char sep[2] = { _sep, '\0' };
710
711 if (!haystack || !needle)
712 return 0;
713
714 str = alloca(strlen(haystack)+1);
715 strcpy(str, haystack);
716 for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
717 if (strcmp(needle, token) == 0)
718 return 1;
719 }
720
721 return 0;
722}
723
724char **lxc_string_split(const char *string, char _sep)
725{
726 char *token, *str, *saveptr = NULL;
727 char sep[2] = { _sep, '\0' };
728 char **result = NULL;
729 size_t result_capacity = 0;
730 size_t result_count = 0;
731 int r, saved_errno;
732
733 if (!string)
734 return calloc(1, sizeof(char *));
735
736 str = alloca(strlen(string)+1);
737 strcpy(str, string);
738 for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
739 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
740 if (r < 0)
741 goto error_out;
742 result[result_count] = strdup(token);
743 if (!result[result_count])
744 goto error_out;
745 result_count++;
746 }
747
748 /* if we allocated too much, reduce it */
749 return realloc(result, (result_count + 1) * sizeof(char *));
750error_out:
751 saved_errno = errno;
752 lxc_free_array((void **)result, free);
753 errno = saved_errno;
754 return NULL;
755}
756
757char **lxc_string_split_and_trim(const char *string, char _sep)
758{
759 char *token, *str, *saveptr = NULL;
760 char sep[2] = { _sep, '\0' };
761 char **result = NULL;
762 size_t result_capacity = 0;
763 size_t result_count = 0;
764 int r, saved_errno;
765 size_t i = 0;
766
767 if (!string)
768 return calloc(1, sizeof(char *));
769
770 str = alloca(strlen(string)+1);
771 strcpy(str, string);
772 for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
773 while (token[0] == ' ' || token[0] == '\t')
774 token++;
775 i = strlen(token);
776 while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
777 token[i - 1] = '\0';
778 i--;
779 }
780 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
781 if (r < 0)
782 goto error_out;
783 result[result_count] = strdup(token);
784 if (!result[result_count])
785 goto error_out;
786 result_count++;
787 }
788
789 /* if we allocated too much, reduce it */
790 return realloc(result, (result_count + 1) * sizeof(char *));
791error_out:
792 saved_errno = errno;
793 lxc_free_array((void **)result, free);
794 errno = saved_errno;
795 return NULL;
796}
797
798void lxc_free_array(void **array, lxc_free_fn element_free_fn)
799{
800 void **p;
801 for (p = array; p && *p; p++)
802 element_free_fn(*p);
803 free((void*)array);
804}
805
806int lxc_grow_array(void ***array, size_t* capacity, size_t new_size, size_t capacity_increment)
807{
808 size_t new_capacity;
809 void **new_array;
810
811 /* first time around, catch some trivial mistakes of the user
812 * only initializing one of these */
813 if (!*array || !*capacity) {
814 *array = NULL;
815 *capacity = 0;
816 }
817
818 new_capacity = *capacity;
819 while (new_size + 1 > new_capacity)
820 new_capacity += capacity_increment;
821 if (new_capacity != *capacity) {
822 /* we have to reallocate */
823 new_array = realloc(*array, new_capacity * sizeof(void *));
824 if (!new_array)
825 return -1;
826 memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * sizeof(void *));
827 *array = new_array;
828 *capacity = new_capacity;
829 }
830
831 /* array has sufficient elements */
832 return 0;
833}
834
835size_t lxc_array_len(void **array)
836{
837 void **p;
838 size_t result = 0;
839
840 for (p = array; p && *p; p++)
841 result++;
842
843 return result;
844}
845
846void **lxc_dup_array(void **array, lxc_dup_fn element_dup_fn, lxc_free_fn element_free_fn)
847{
848 size_t l = lxc_array_len(array);
849 void **result = calloc(l + 1, sizeof(void *));
850 void **pp;
851 void *p;
852 int saved_errno = 0;
853
854 if (!result)
855 return NULL;
856
857 for (l = 0, pp = array; pp && *pp; pp++, l++) {
858 p = element_dup_fn(*pp);
859 if (!p) {
860 saved_errno = errno;
861 lxc_free_array(result, element_free_fn);
862 errno = saved_errno;
863 return NULL;
864 }
865 result[l] = p;
866 }
867
868 return result;
869}
0e95426b
CS
870
871int lxc_write_to_file(const char *filename, const void* buf, size_t count, bool add_newline)
872{
873 int fd, saved_errno;
874 ssize_t ret;
875
025ed0f3 876 process_lock();
0e95426b 877 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666);
025ed0f3 878 process_unlock();
0e95426b
CS
879 if (fd < 0)
880 return -1;
881 ret = lxc_write_nointr(fd, buf, count);
882 if (ret < 0)
883 goto out_error;
884 if ((size_t)ret != count)
885 goto out_error;
886 if (add_newline) {
887 ret = lxc_write_nointr(fd, "\n", 1);
888 if (ret != 1)
889 goto out_error;
890 }
025ed0f3 891 process_lock();
0e95426b 892 close(fd);
025ed0f3 893 process_unlock();
0e95426b
CS
894 return 0;
895
896out_error:
897 saved_errno = errno;
025ed0f3 898 process_lock();
0e95426b 899 close(fd);
025ed0f3 900 process_unlock();
0e95426b
CS
901 errno = saved_errno;
902 return -1;
903}
904
905int lxc_read_from_file(const char *filename, void* buf, size_t count)
906{
907 int fd = -1, saved_errno;
908 ssize_t ret;
909
025ed0f3 910 process_lock();
0e95426b 911 fd = open(filename, O_RDONLY | O_CLOEXEC);
025ed0f3 912 process_unlock();
0e95426b
CS
913 if (fd < 0)
914 return -1;
915
916 if (!buf || !count) {
917 char buf2[100];
918 size_t count2 = 0;
919 while ((ret = read(fd, buf2, 100)) > 0)
920 count2 += ret;
921 if (ret >= 0)
922 ret = count2;
923 } else {
924 memset(buf, 0, count);
925 ret = read(fd, buf, count);
926 }
927
928 if (ret < 0)
929 ERROR("read %s: %s", filename, strerror(errno));
930
931 saved_errno = errno;
025ed0f3 932 process_lock();
0e95426b 933 close(fd);
025ed0f3 934 process_unlock();
0e95426b
CS
935 errno = saved_errno;
936 return ret;
937}