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