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