]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/utils.c
change version to 1.1.0 in configure.ac
[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
3ce74686 43#include "utils.h"
e3642c43 44#include "log.h"
025ed0f3 45#include "lxclock.h"
51d0854c 46#include "namespace.h"
e3642c43
DL
47
48lxc_log_define(lxc_utils, lxc);
49
18aa217b
SH
50static int _recursive_rmdir_onedev(char *dirname, dev_t pdev,
51 const char *exclude, int level)
60bf62d4
SH
52{
53 struct dirent dirent, *direntp;
54 DIR *dir;
55 int ret, failed=0;
56 char pathname[MAXPATHLEN];
18aa217b 57 bool hadexclude = false;
60bf62d4
SH
58
59 dir = opendir(dirname);
60 if (!dir) {
61 ERROR("%s: failed to open %s", __func__, dirname);
4355ab5f 62 return -1;
60bf62d4
SH
63 }
64
65 while (!readdir_r(dir, &dirent, &direntp)) {
66 struct stat mystat;
67 int rc;
68
69 if (!direntp)
70 break;
71
72 if (!strcmp(direntp->d_name, ".") ||
73 !strcmp(direntp->d_name, ".."))
74 continue;
75
76 rc = snprintf(pathname, MAXPATHLEN, "%s/%s", dirname, direntp->d_name);
77 if (rc < 0 || rc >= MAXPATHLEN) {
78 ERROR("pathname too long");
79 failed=1;
80 continue;
81 }
18aa217b
SH
82
83 if (!level && exclude && !strcmp(direntp->d_name, exclude)) {
84 ret = rmdir(pathname);
85 if (ret < 0) {
86 switch(errno) {
87 case ENOTEMPTY:
88 INFO("Not deleting snapshots");
89 hadexclude = true;
90 break;
91 case ENOTDIR:
92 ret = unlink(pathname);
93 if (ret)
94 INFO("%s: failed to remove %s", __func__, pathname);
95 break;
96 default:
97 SYSERROR("%s: failed to rmdir %s", __func__, pathname);
98 failed = 1;
99 break;
100 }
101 }
102 continue;
103 }
104
60bf62d4
SH
105 ret = lstat(pathname, &mystat);
106 if (ret) {
107 ERROR("%s: failed to stat %s", __func__, pathname);
108 failed=1;
109 continue;
110 }
111 if (mystat.st_dev != pdev)
112 continue;
113 if (S_ISDIR(mystat.st_mode)) {
18aa217b 114 if (_recursive_rmdir_onedev(pathname, pdev, exclude, level+1) < 0)
60bf62d4
SH
115 failed=1;
116 } else {
117 if (unlink(pathname) < 0) {
118 ERROR("%s: failed to delete %s", __func__, pathname);
119 failed=1;
120 }
121 }
122 }
123
124 if (rmdir(dirname) < 0) {
18aa217b
SH
125 if (!hadexclude) {
126 ERROR("%s: failed to delete %s", __func__, dirname);
127 failed=1;
128 }
60bf62d4
SH
129 }
130
025ed0f3 131 ret = closedir(dir);
025ed0f3 132 if (ret) {
60bf62d4
SH
133 ERROR("%s: failed to close directory %s", __func__, dirname);
134 failed=1;
135 }
136
4355ab5f 137 return failed ? -1 : 0;
60bf62d4
SH
138}
139
4355ab5f 140/* returns 0 on success, -1 if there were any failures */
18aa217b 141extern int lxc_rmdir_onedev(char *path, const char *exclude)
60bf62d4
SH
142{
143 struct stat mystat;
144
145 if (lstat(path, &mystat) < 0) {
146 ERROR("%s: failed to stat %s", __func__, path);
4355ab5f 147 return -1;
60bf62d4
SH
148 }
149
18aa217b 150 return _recursive_rmdir_onedev(path, mystat.st_dev, exclude, 0);
60bf62d4
SH
151}
152
6e4bb2e0
MN
153static int mount_fs(const char *source, const char *target, const char *type)
154{
155 /* the umount may fail */
156 if (umount(target))
157 WARN("failed to unmount %s : %s", target, strerror(errno));
158
159 if (mount(source, target, type, 0, NULL)) {
160 ERROR("failed to mount %s : %s", target, strerror(errno));
161 return -1;
162 }
163
164 DEBUG("'%s' mounted on '%s'", source, target);
165
166 return 0;
167}
168
ea0da529 169extern void lxc_setup_fs(void)
6e4bb2e0
MN
170{
171 if (mount_fs("proc", "/proc", "proc"))
ea0da529 172 INFO("failed to remount proc");
6e4bb2e0 173
721d262c 174 /* if we can't mount /dev/shm, continue anyway */
6e4bb2e0 175 if (mount_fs("shmfs", "/dev/shm", "tmpfs"))
3283db09 176 INFO("failed to mount /dev/shm");
6e4bb2e0
MN
177
178 /* If we were able to mount /dev/shm, then /dev exists */
b91b1cd7 179 /* Sure, but it's read-only per config :) */
6e4bb2e0 180 if (access("/dev/mqueue", F_OK) && mkdir("/dev/mqueue", 0666)) {
b91b1cd7 181 DEBUG("failed to create '/dev/mqueue'");
ea0da529 182 return;
6e4bb2e0
MN
183 }
184
5d4d3ebb 185 /* continue even without posix message queue support */
6e4bb2e0 186 if (mount_fs("mqueue", "/dev/mqueue", "mqueue"))
5d4d3ebb 187 INFO("failed to mount /dev/mqueue");
6e4bb2e0 188}
9ddaf3bf
JHS
189
190/* borrowed from iproute2 */
7c11d57a 191extern int get_u16(unsigned short *val, const char *arg, int base)
9ddaf3bf
JHS
192{
193 unsigned long res;
194 char *ptr;
195
196 if (!arg || !*arg)
197 return -1;
198
09bbd745 199 errno = 0;
9ddaf3bf 200 res = strtoul(arg, &ptr, base);
09bbd745 201 if (!ptr || ptr == arg || *ptr || res > 0xFFFF || errno != 0)
9ddaf3bf
JHS
202 return -1;
203
204 *val = res;
205
206 return 0;
207}
208
3ce74686 209extern int mkdir_p(const char *dir, mode_t mode)
1b09f2c0 210{
3ce74686
SH
211 const char *tmp = dir;
212 const char *orig = dir;
860fc865
RW
213 char *makeme;
214
215 do {
216 dir = tmp + strspn(tmp, "/");
217 tmp = dir + strcspn(dir, "/");
d74325c4 218 makeme = strndup(orig, dir - orig);
860fc865
RW
219 if (*makeme) {
220 if (mkdir(makeme, mode) && errno != EEXIST) {
959aee9c 221 SYSERROR("failed to create directory '%s'", makeme);
d74325c4 222 free(makeme);
860fc865
RW
223 return -1;
224 }
225 }
d74325c4 226 free(makeme);
860fc865 227 } while(tmp != dir);
1b09f2c0 228
98663823 229 return 0;
1b09f2c0 230}
2a59a681 231
89cd7793
QH
232extern void remove_trailing_slashes(char *p)
233{
234 int l = strlen(p);
235 while (--l >= 0 && (p[l] == '/' || p[l] == '\n'))
236 p[l] = '\0';
237}
238
d0386d66 239static char *copy_global_config_value(char *p)
2a59a681
SH
240{
241 int len = strlen(p);
242 char *retbuf;
243
244 if (len < 1)
245 return NULL;
246 if (p[len-1] == '\n') {
247 p[len-1] = '\0';
248 len--;
249 }
250 retbuf = malloc(len+1);
251 if (!retbuf)
252 return NULL;
253 strcpy(retbuf, p);
254 return retbuf;
255}
256
31a95fec 257#define DEFAULT_VG "lxc"
055af165 258#define DEFAULT_THIN_POOL "lxc"
31a95fec 259#define DEFAULT_ZFSROOT "lxc"
67e571de 260
593e8478 261const char *lxc_global_config_value(const char *option_name)
31a95fec 262{
74a3920a 263 static const char * const options[][2] = {
2e59ba02
SG
264 { "lxc.bdev.lvm.vg", DEFAULT_VG },
265 { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL },
266 { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT },
267 { "lxc.lxcpath", NULL },
268 { "lxc.default_config", NULL },
5e1c5795 269 { "lxc.cgroup.pattern", NULL },
2e59ba02 270 { "lxc.cgroup.use", NULL },
d0386d66
CS
271 { NULL, NULL },
272 };
4878dac4 273
93c379f0 274 /* placed in the thread local storage pool for non-bionic targets */
babbea4b
ÇO
275#ifdef HAVE_TLS
276 static __thread const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
277#else
91664352 278 static const char *values[sizeof(options) / sizeof(options[0])] = { 0 };
babbea4b 279#endif
48921d92
SH
280
281 /* user_config_path is freed as soon as it is used */
4878dac4 282 char *user_config_path = NULL;
48921d92
SH
283
284 /*
285 * The following variables are freed at bottom unconditionally.
286 * So NULL the value if it is to be returned to the caller
287 */
9e8be781 288 char *user_default_config_path = NULL;
4878dac4 289 char *user_lxc_path = NULL;
5e1c5795 290 char *user_cgroup_pattern = NULL;
4878dac4
SG
291
292 if (geteuid() > 0) {
6ed46d9e
AM
293 const char *user_home = getenv("HOME");
294 if (!user_home)
e99facec 295 user_home = "/";
4878dac4
SG
296
297 user_config_path = malloc(sizeof(char) * (22 + strlen(user_home)));
9e8be781 298 user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home)));
4878dac4
SG
299 user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home)));
300
301 sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home);
9e8be781 302 sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home);
4878dac4 303 sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home);
5e1c5795 304 user_cgroup_pattern = strdup("%n");
4878dac4
SG
305 }
306 else {
307 user_config_path = strdup(LXC_GLOBAL_CONF);
9e8be781 308 user_default_config_path = strdup(LXC_DEFAULT_CONFIG);
4878dac4 309 user_lxc_path = strdup(LXCPATH);
5e1c5795 310 user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN);
4878dac4
SG
311 }
312
74a3920a 313 const char * const (*ptr)[2];
d0386d66
CS
314 size_t i;
315 char buf[1024], *p, *p2;
316 FILE *fin = NULL;
317
318 for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
319 if (!strcmp(option_name, (*ptr)[0]))
320 break;
321 }
322 if (!(*ptr)[0]) {
4878dac4 323 free(user_config_path);
9e8be781 324 free(user_default_config_path);
4878dac4 325 free(user_lxc_path);
5e1c5795 326 free(user_cgroup_pattern);
d0386d66
CS
327 errno = EINVAL;
328 return NULL;
329 }
052616eb 330
052616eb 331 if (values[i]) {
4878dac4 332 free(user_config_path);
9e8be781 333 free(user_default_config_path);
4878dac4 334 free(user_lxc_path);
5e1c5795 335 free(user_cgroup_pattern);
babbea4b 336 return values[i];
052616eb 337 }
31a95fec 338
4878dac4
SG
339 fin = fopen_cloexec(user_config_path, "r");
340 free(user_config_path);
31a95fec
SH
341 if (fin) {
342 while (fgets(buf, 1024, fin)) {
343 if (buf[0] == '#')
344 continue;
d0386d66 345 p = strstr(buf, option_name);
31a95fec
SH
346 if (!p)
347 continue;
d0386d66
CS
348 /* see if there was just white space in front
349 * of the option name
350 */
351 for (p2 = buf; p2 < p; p2++) {
352 if (*p2 != ' ' && *p2 != '\t')
353 break;
354 }
355 if (p2 < p)
356 continue;
31a95fec
SH
357 p = strchr(p, '=');
358 if (!p)
359 continue;
d0386d66
CS
360 /* see if there was just white space after
361 * the option name
362 */
363 for (p2 += strlen(option_name); p2 < p; p2++) {
364 if (*p2 != ' ' && *p2 != '\t')
365 break;
366 }
367 if (p2 < p)
368 continue;
31a95fec
SH
369 p++;
370 while (*p && (*p == ' ' || *p == '\t')) p++;
371 if (!*p)
372 continue;
f407c5e4 373
f407c5e4
SG
374 if (strcmp(option_name, "lxc.lxcpath") == 0) {
375 free(user_lxc_path);
376 user_lxc_path = copy_global_config_value(p);
377 remove_trailing_slashes(user_lxc_path);
378 values[i] = user_lxc_path;
a1c9a9c9 379 user_lxc_path = NULL;
f407c5e4
SG
380 goto out;
381 }
382
383 values[i] = copy_global_config_value(p);
31a95fec
SH
384 goto out;
385 }
386 }
d0386d66 387 /* could not find value, use default */
9e8be781 388 if (strcmp(option_name, "lxc.lxcpath") == 0) {
f407c5e4 389 remove_trailing_slashes(user_lxc_path);
4878dac4 390 values[i] = user_lxc_path;
48921d92 391 user_lxc_path = NULL;
9e8be781
SG
392 }
393 else if (strcmp(option_name, "lxc.default_config") == 0) {
394 values[i] = user_default_config_path;
48921d92 395 user_default_config_path = NULL;
5e1c5795
KY
396 }
397 else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) {
398 values[i] = user_cgroup_pattern;
48921d92 399 user_cgroup_pattern = NULL;
9e8be781 400 }
48921d92 401 else
4878dac4 402 values[i] = (*ptr)[1];
48921d92 403
d0386d66
CS
404 /* special case: if default value is NULL,
405 * and there is no config, don't view that
406 * as an error... */
407 if (!values[i])
408 errno = 0;
31a95fec
SH
409
410out:
411 if (fin)
412 fclose(fin);
41f68357 413
48921d92
SH
414 free(user_cgroup_pattern);
415 free(user_default_config_path);
416 free(user_lxc_path);
417
babbea4b 418 return values[i];
31a95fec
SH
419}
420
44b9ae4b 421char *get_rundir()
9e60f51d 422{
97a696c6
SG
423 char *rundir;
424 const char *homedir;
9e60f51d 425
d6470e71 426 if (geteuid() == 0) {
c580b8d2 427 rundir = strdup(RUNTIME_PATH);
d6470e71
SG
428 return rundir;
429 }
97a696c6
SG
430
431 rundir = getenv("XDG_RUNTIME_DIR");
44b9ae4b
SG
432 if (rundir) {
433 rundir = strdup(rundir);
434 return rundir;
435 }
97a696c6 436
44b9ae4b
SG
437 INFO("XDG_RUNTIME_DIR isn't set in the environment.");
438 homedir = getenv("HOME");
439 if (!homedir) {
440 ERROR("HOME isn't set in the environment.");
441 return NULL;
97a696c6
SG
442 }
443
44b9ae4b
SG
444 rundir = malloc(sizeof(char) * (17 + strlen(homedir)));
445 sprintf(rundir, "%s/.cache/lxc/run/", homedir);
446
9e60f51d
DE
447 return rundir;
448}
449
9be53773
SH
450int wait_for_pid(pid_t pid)
451{
452 int status, ret;
453
454again:
455 ret = waitpid(pid, &status, 0);
456 if (ret == -1) {
71b9b8ed 457 if (errno == EINTR)
9be53773
SH
458 goto again;
459 return -1;
460 }
461 if (ret != pid)
462 goto again;
463 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0)
464 return -1;
465 return 0;
466}
c797a220
CS
467
468int lxc_wait_for_pid_status(pid_t pid)
469{
470 int status, ret;
471
472again:
473 ret = waitpid(pid, &status, 0);
474 if (ret == -1) {
475 if (errno == EINTR)
476 goto again;
477 return -1;
478 }
479 if (ret != pid)
480 goto again;
481 return status;
482}
92f023dc 483
650468bb 484ssize_t lxc_write_nointr(int fd, const void* buf, size_t count)
92f023dc 485{
650468bb 486 ssize_t ret;
92f023dc
CS
487again:
488 ret = write(fd, buf, count);
489 if (ret < 0 && errno == EINTR)
490 goto again;
491 return ret;
492}
493
650468bb 494ssize_t lxc_read_nointr(int fd, void* buf, size_t count)
92f023dc 495{
650468bb 496 ssize_t ret;
92f023dc
CS
497again:
498 ret = read(fd, buf, count);
499 if (ret < 0 && errno == EINTR)
500 goto again;
501 return ret;
502}
503
650468bb 504ssize_t lxc_read_nointr_expect(int fd, void* buf, size_t count, const void* expected_buf)
92f023dc 505{
650468bb 506 ssize_t ret;
92f023dc
CS
507 ret = lxc_read_nointr(fd, buf, count);
508 if (ret <= 0)
509 return ret;
650468bb 510 if ((size_t)ret != count)
92f023dc
CS
511 return -1;
512 if (expected_buf && memcmp(buf, expected_buf, count) != 0) {
513 errno = EINVAL;
514 return -1;
515 }
516 return ret;
517}
3ce74686
SH
518
519#if HAVE_LIBGNUTLS
520#include <gnutls/gnutls.h>
521#include <gnutls/crypto.h>
41246cee
DE
522
523__attribute__((constructor))
524static void gnutls_lxc_init(void)
525{
526 gnutls_global_init();
527}
528
3ce74686
SH
529int sha1sum_file(char *fnam, unsigned char *digest)
530{
531 char *buf;
532 int ret;
533 FILE *f;
534 long flen;
535
536 if (!fnam)
537 return -1;
025ed0f3 538 f = fopen_cloexec(fnam, "r");
7be677a8 539 if (!f) {
3ce74686
SH
540 SYSERROR("Error opening template");
541 return -1;
542 }
543 if (fseek(f, 0, SEEK_END) < 0) {
544 SYSERROR("Error seeking to end of template");
dd1d77f9 545 fclose(f);
3ce74686
SH
546 return -1;
547 }
548 if ((flen = ftell(f)) < 0) {
549 SYSERROR("Error telling size of template");
dd1d77f9 550 fclose(f);
3ce74686
SH
551 return -1;
552 }
553 if (fseek(f, 0, SEEK_SET) < 0) {
554 SYSERROR("Error seeking to start of template");
dd1d77f9 555 fclose(f);
3ce74686
SH
556 return -1;
557 }
558 if ((buf = malloc(flen+1)) == NULL) {
559 SYSERROR("Out of memory");
dd1d77f9 560 fclose(f);
3ce74686
SH
561 return -1;
562 }
563 if (fread(buf, 1, flen, f) != flen) {
564 SYSERROR("Failure reading template");
565 free(buf);
dd1d77f9 566 fclose(f);
3ce74686
SH
567 return -1;
568 }
dd1d77f9 569 if (fclose(f) < 0) {
3ce74686
SH
570 SYSERROR("Failre closing template");
571 free(buf);
572 return -1;
573 }
574 buf[flen] = '\0';
575 ret = gnutls_hash_fast(GNUTLS_DIG_SHA1, buf, flen, (void *)digest);
576 free(buf);
577 return ret;
578}
579#endif
61a1d519
CS
580
581char** lxc_va_arg_list_to_argv(va_list ap, size_t skip, int do_strdup)
582{
583 va_list ap2;
584 size_t count = 1 + skip;
585 char **result;
586
587 /* first determine size of argument list, we don't want to reallocate
588 * constantly...
589 */
590 va_copy(ap2, ap);
591 while (1) {
592 char* arg = va_arg(ap2, char*);
593 if (!arg)
594 break;
595 count++;
596 }
597 va_end(ap2);
598
599 result = calloc(count, sizeof(char*));
600 if (!result)
601 return NULL;
602 count = skip;
603 while (1) {
604 char* arg = va_arg(ap, char*);
605 if (!arg)
606 break;
607 arg = do_strdup ? strdup(arg) : arg;
608 if (!arg)
609 goto oom;
610 result[count++] = arg;
611 }
612
613 /* calloc has already set last element to NULL*/
614 return result;
615
616oom:
617 free(result);
618 return NULL;
619}
620
621const char** lxc_va_arg_list_to_argv_const(va_list ap, size_t skip)
622{
623 return (const char**)lxc_va_arg_list_to_argv(ap, skip, 0);
624}
db27c8d7
CS
625
626FILE *fopen_cloexec(const char *path, const char *mode)
627{
628 int open_mode = 0;
629 int step = 0;
630 int fd;
631 int saved_errno = 0;
632 FILE *ret;
633
634 if (!strncmp(mode, "r+", 2)) {
635 open_mode = O_RDWR;
636 step = 2;
637 } else if (!strncmp(mode, "r", 1)) {
638 open_mode = O_RDONLY;
639 step = 1;
640 } else if (!strncmp(mode, "w+", 2)) {
641 open_mode = O_RDWR | O_TRUNC | O_CREAT;
642 step = 2;
643 } else if (!strncmp(mode, "w", 1)) {
644 open_mode = O_WRONLY | O_TRUNC | O_CREAT;
645 step = 1;
646 } else if (!strncmp(mode, "a+", 2)) {
647 open_mode = O_RDWR | O_CREAT | O_APPEND;
648 step = 2;
649 } else if (!strncmp(mode, "a", 1)) {
650 open_mode = O_WRONLY | O_CREAT | O_APPEND;
651 step = 1;
652 }
653 for (; mode[step]; step++)
654 if (mode[step] == 'x')
655 open_mode |= O_EXCL;
656 open_mode |= O_CLOEXEC;
657
82371fdd 658 fd = open(path, open_mode, 0666);
db27c8d7
CS
659 if (fd < 0)
660 return NULL;
661
662 ret = fdopen(fd, mode);
663 saved_errno = errno;
664 if (!ret)
665 close(fd);
666 errno = saved_errno;
667 return ret;
668}
502657d5 669
ebec9176
AM
670extern struct lxc_popen_FILE *lxc_popen(const char *command)
671{
672 struct lxc_popen_FILE *fp = NULL;
673 int parent_end = -1, child_end = -1;
674 int pipe_fds[2];
675 pid_t child_pid;
676
677 int r = pipe2(pipe_fds, O_CLOEXEC);
678
679 if (r < 0) {
680 ERROR("pipe2 failure");
681 return NULL;
682 }
683
684 parent_end = pipe_fds[0];
685 child_end = pipe_fds[1];
686
687 child_pid = fork();
688
689 if (child_pid == 0) {
690 /* child */
691 int child_std_end = STDOUT_FILENO;
692
693 if (child_end != child_std_end) {
694 /* dup2() doesn't dup close-on-exec flag */
695 dup2(child_end, child_std_end);
696
697 /* it's safe not to close child_end here
698 * as it's marked close-on-exec anyway
699 */
700 } else {
701 /*
702 * The descriptor is already the one we will use.
703 * But it must not be marked close-on-exec.
704 * Undo the effects.
705 */
57d2be54
SG
706 if (fcntl(child_end, F_SETFD, 0) != 0) {
707 SYSERROR("Failed to remove FD_CLOEXEC from fd.");
708 exit(127);
709 }
ebec9176
AM
710 }
711
712 /*
713 * Unblock signals.
714 * This is the main/only reason
715 * why we do our lousy popen() emulation.
716 */
717 {
718 sigset_t mask;
719 sigfillset(&mask);
720 sigprocmask(SIG_UNBLOCK, &mask, NULL);
721 }
722
723 execl("/bin/sh", "sh", "-c", command, (char *) NULL);
724 exit(127);
725 }
726
727 /* parent */
728
729 close(child_end);
730 child_end = -1;
731
732 if (child_pid < 0) {
733 ERROR("fork failure");
734 goto error;
735 }
736
737 fp = calloc(1, sizeof(*fp));
738 if (!fp) {
739 ERROR("failed to allocate memory");
740 goto error;
741 }
742
743 fp->f = fdopen(parent_end, "r");
744 if (!fp->f) {
745 ERROR("fdopen failure");
746 goto error;
747 }
748
749 fp->child_pid = child_pid;
750
751 return fp;
752
753error:
754
755 if (fp) {
756 if (fp->f) {
757 fclose(fp->f);
758 parent_end = -1; /* so we do not close it second time */
759 }
760
761 free(fp);
762 }
763
ebec9176
AM
764 if (parent_end != -1)
765 close(parent_end);
766
767 return NULL;
768}
769
ebec9176
AM
770extern int lxc_pclose(struct lxc_popen_FILE *fp)
771{
772 FILE *f = NULL;
773 pid_t child_pid = 0;
774 int wstatus = 0;
775 pid_t wait_pid;
776
777 if (fp) {
778 f = fp->f;
779 child_pid = fp->child_pid;
780 /* free memory (we still need to close file stream) */
781 free(fp);
782 fp = NULL;
783 }
784
785 if (!f || fclose(f)) {
786 ERROR("fclose failure");
787 return -1;
788 }
789
790 do {
791 wait_pid = waitpid(child_pid, &wstatus, 0);
792 } while (wait_pid == -1 && errno == EINTR);
793
794 if (wait_pid == -1) {
795 ERROR("waitpid failure");
796 return -1;
797 }
798
799 return wstatus;
800}
801
502657d5
CS
802char *lxc_string_replace(const char *needle, const char *replacement, const char *haystack)
803{
804 ssize_t len = -1, saved_len = -1;
805 char *result = NULL;
806 size_t replacement_len = strlen(replacement);
807 size_t needle_len = strlen(needle);
808
809 /* should be executed exactly twice */
810 while (len == -1 || result == NULL) {
811 char *p;
812 char *last_p;
813 ssize_t part_len;
814
815 if (len != -1) {
816 result = calloc(1, len + 1);
817 if (!result)
818 return NULL;
819 saved_len = len;
820 }
821
822 len = 0;
823
824 for (last_p = (char *)haystack, p = strstr(last_p, needle); p; last_p = p, p = strstr(last_p, needle)) {
825 part_len = (ssize_t)(p - last_p);
826 if (result && part_len > 0)
827 memcpy(&result[len], last_p, part_len);
828 len += part_len;
829 if (result && replacement_len > 0)
830 memcpy(&result[len], replacement, replacement_len);
831 len += replacement_len;
832 p += needle_len;
833 }
834 part_len = strlen(last_p);
835 if (result && part_len > 0)
836 memcpy(&result[len], last_p, part_len);
837 len += part_len;
838 }
839
840 /* make sure we did the same thing twice,
841 * once for calculating length, the other
842 * time for copying data */
843 assert(saved_len == len);
844 /* make sure we didn't overwrite any buffer,
845 * due to calloc the string should be 0-terminated */
846 assert(result[len] == '\0');
847
848 return result;
849}
850
851bool lxc_string_in_array(const char *needle, const char **haystack)
852{
853 for (; haystack && *haystack; haystack++)
854 if (!strcmp(needle, *haystack))
855 return true;
856 return false;
857}
858
859char *lxc_string_join(const char *sep, const char **parts, bool use_as_prefix)
860{
861 char *result;
862 char **p;
863 size_t sep_len = strlen(sep);
864 size_t result_len = use_as_prefix * sep_len;
865
866 /* calculate new string length */
867 for (p = (char **)parts; *p; p++)
868 result_len += (p > (char **)parts) * sep_len + strlen(*p);
869
870 result = calloc(result_len + 1, 1);
871 if (!result)
872 return NULL;
873
874 if (use_as_prefix)
875 strcpy(result, sep);
876 for (p = (char **)parts; *p; p++) {
877 if (p > (char **)parts)
878 strcat(result, sep);
879 strcat(result, *p);
880 }
881
882 return result;
883}
884
885char **lxc_normalize_path(const char *path)
886{
887 char **components;
888 char **p;
889 size_t components_len = 0;
890 size_t pos = 0;
891
892 components = lxc_string_split(path, '/');
893 if (!components)
894 return NULL;
895 for (p = components; *p; p++)
896 components_len++;
897
898 /* resolve '.' and '..' */
899 for (pos = 0; pos < components_len; ) {
900 if (!strcmp(components[pos], ".") || (!strcmp(components[pos], "..") && pos == 0)) {
901 /* eat this element */
902 free(components[pos]);
903 memmove(&components[pos], &components[pos+1], sizeof(char *) * (components_len - pos));
904 components_len--;
905 } else if (!strcmp(components[pos], "..")) {
906 /* eat this and the previous element */
907 free(components[pos - 1]);
908 free(components[pos]);
909 memmove(&components[pos-1], &components[pos+1], sizeof(char *) * (components_len - pos));
910 components_len -= 2;
911 pos--;
912 } else {
913 pos++;
914 }
915 }
916
917 return components;
918}
919
24b51482
CS
920char *lxc_append_paths(const char *first, const char *second)
921{
922 size_t len = strlen(first) + strlen(second) + 1;
923 const char *pattern = "%s%s";
924 char *result = NULL;
925
926 if (second[0] != '/') {
927 len += 1;
928 pattern = "%s/%s";
929 }
930
931 result = calloc(1, len);
932 if (!result)
933 return NULL;
934
935 snprintf(result, len, pattern, first, second);
936 return result;
937}
938
502657d5
CS
939bool lxc_string_in_list(const char *needle, const char *haystack, char _sep)
940{
941 char *token, *str, *saveptr = NULL;
942 char sep[2] = { _sep, '\0' };
943
944 if (!haystack || !needle)
945 return 0;
946
947 str = alloca(strlen(haystack)+1);
948 strcpy(str, haystack);
949 for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
950 if (strcmp(needle, token) == 0)
951 return 1;
952 }
953
954 return 0;
955}
956
957char **lxc_string_split(const char *string, char _sep)
958{
959 char *token, *str, *saveptr = NULL;
960 char sep[2] = { _sep, '\0' };
961 char **result = NULL;
962 size_t result_capacity = 0;
963 size_t result_count = 0;
964 int r, saved_errno;
965
966 if (!string)
967 return calloc(1, sizeof(char *));
968
969 str = alloca(strlen(string)+1);
970 strcpy(str, string);
971 for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
972 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
973 if (r < 0)
974 goto error_out;
975 result[result_count] = strdup(token);
976 if (!result[result_count])
977 goto error_out;
978 result_count++;
979 }
980
981 /* if we allocated too much, reduce it */
982 return realloc(result, (result_count + 1) * sizeof(char *));
983error_out:
984 saved_errno = errno;
985 lxc_free_array((void **)result, free);
986 errno = saved_errno;
987 return NULL;
988}
989
990char **lxc_string_split_and_trim(const char *string, char _sep)
991{
992 char *token, *str, *saveptr = NULL;
993 char sep[2] = { _sep, '\0' };
994 char **result = NULL;
995 size_t result_capacity = 0;
996 size_t result_count = 0;
997 int r, saved_errno;
998 size_t i = 0;
999
1000 if (!string)
1001 return calloc(1, sizeof(char *));
1002
1003 str = alloca(strlen(string)+1);
1004 strcpy(str, string);
1005 for (; (token = strtok_r(str, sep, &saveptr)); str = NULL) {
1006 while (token[0] == ' ' || token[0] == '\t')
1007 token++;
1008 i = strlen(token);
1009 while (i > 0 && (token[i - 1] == ' ' || token[i - 1] == '\t')) {
1010 token[i - 1] = '\0';
1011 i--;
1012 }
1013 r = lxc_grow_array((void ***)&result, &result_capacity, result_count + 1, 16);
1014 if (r < 0)
1015 goto error_out;
1016 result[result_count] = strdup(token);
1017 if (!result[result_count])
1018 goto error_out;
1019 result_count++;
1020 }
1021
1022 /* if we allocated too much, reduce it */
1023 return realloc(result, (result_count + 1) * sizeof(char *));
1024error_out:
1025 saved_errno = errno;
1026 lxc_free_array((void **)result, free);
1027 errno = saved_errno;
1028 return NULL;
1029}
1030
1031void lxc_free_array(void **array, lxc_free_fn element_free_fn)
1032{
1033 void **p;
1034 for (p = array; p && *p; p++)
1035 element_free_fn(*p);
1036 free((void*)array);
1037}
1038
1039int lxc_grow_array(void ***array, size_t* capacity, size_t new_size, size_t capacity_increment)
1040{
1041 size_t new_capacity;
1042 void **new_array;
1043
1044 /* first time around, catch some trivial mistakes of the user
1045 * only initializing one of these */
1046 if (!*array || !*capacity) {
1047 *array = NULL;
1048 *capacity = 0;
1049 }
1050
1051 new_capacity = *capacity;
1052 while (new_size + 1 > new_capacity)
1053 new_capacity += capacity_increment;
1054 if (new_capacity != *capacity) {
1055 /* we have to reallocate */
1056 new_array = realloc(*array, new_capacity * sizeof(void *));
1057 if (!new_array)
1058 return -1;
1059 memset(&new_array[*capacity], 0, (new_capacity - (*capacity)) * sizeof(void *));
1060 *array = new_array;
1061 *capacity = new_capacity;
1062 }
1063
1064 /* array has sufficient elements */
1065 return 0;
1066}
1067
1068size_t lxc_array_len(void **array)
1069{
1070 void **p;
1071 size_t result = 0;
1072
1073 for (p = array; p && *p; p++)
1074 result++;
1075
1076 return result;
1077}
1078
0e95426b
CS
1079int lxc_write_to_file(const char *filename, const void* buf, size_t count, bool add_newline)
1080{
1081 int fd, saved_errno;
1082 ssize_t ret;
1083
1084 fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, 0666);
1085 if (fd < 0)
1086 return -1;
1087 ret = lxc_write_nointr(fd, buf, count);
1088 if (ret < 0)
799f29ab 1089 goto out_error;
0e95426b
CS
1090 if ((size_t)ret != count)
1091 goto out_error;
1092 if (add_newline) {
1093 ret = lxc_write_nointr(fd, "\n", 1);
1094 if (ret != 1)
1095 goto out_error;
1096 }
1097 close(fd);
1098 return 0;
1099
1100out_error:
1101 saved_errno = errno;
1102 close(fd);
1103 errno = saved_errno;
1104 return -1;
1105}
1106
1107int lxc_read_from_file(const char *filename, void* buf, size_t count)
1108{
1109 int fd = -1, saved_errno;
1110 ssize_t ret;
1111
1112 fd = open(filename, O_RDONLY | O_CLOEXEC);
1113 if (fd < 0)
1114 return -1;
1115
1116 if (!buf || !count) {
1117 char buf2[100];
1118 size_t count2 = 0;
1119 while ((ret = read(fd, buf2, 100)) > 0)
1120 count2 += ret;
1121 if (ret >= 0)
1122 ret = count2;
1123 } else {
1124 memset(buf, 0, count);
1125 ret = read(fd, buf, count);
1126 }
1127
1128 if (ret < 0)
1129 ERROR("read %s: %s", filename, strerror(errno));
1130
1131 saved_errno = errno;
1132 close(fd);
1133 errno = saved_errno;
1134 return ret;
1135}
799f29ab
ÇO
1136
1137void **lxc_append_null_to_array(void **array, size_t count)
1138{
1139 void **temp;
1140
1141 /* Append NULL to the array */
1142 if (count) {
1143 temp = realloc(array, (count + 1) * sizeof(*array));
1144 if (!temp) {
1145 int i;
1146 for (i = 0; i < count; i++)
1147 free(array[i]);
1148 free(array);
1149 return NULL;
1150 }
1151 array = temp;
1152 array[count] = NULL;
1153 }
1154 return array;
1155}
508c263e
SH
1156
1157int randseed(bool srand_it)
1158{
1159 /*
1160 srand pre-seed function based on /dev/urandom
1161 */
1162 unsigned int seed=time(NULL)+getpid();
1163
1164 FILE *f;
1165 f = fopen("/dev/urandom", "r");
1166 if (f) {
1167 int ret = fread(&seed, sizeof(seed), 1, f);
1168 if (ret != 1)
1169 DEBUG("unable to fread /dev/urandom, %s, fallback to time+pid rand seed", strerror(errno));
1170 fclose(f);
1171 }
1172
1173 if (srand_it)
1174 srand(seed);
1175
1176 return seed;
1177}
5d897655
SH
1178
1179uid_t get_ns_uid(uid_t orig)
1180{
1181 char *line = NULL;
1182 size_t sz = 0;
1183 uid_t nsid, hostid, range;
1184 FILE *f = fopen("/proc/self/uid_map", "r");
1185 if (!f)
1186 return 0;
1187
1188 while (getline(&line, &sz, f) != -1) {
1189 if (sscanf(line, "%u %u %u", &nsid, &hostid, &range) != 3)
1190 continue;
1191 if (hostid <= orig && hostid + range > orig) {
1192 nsid += orig - hostid;
1193 goto found;
1194 }
1195 }
1196
1197 nsid = 0;
1198found:
1199 fclose(f);
1200 free(line);
1201 return nsid;
1202}
c476bdce
SH
1203
1204bool dir_exists(const char *path)
1205{
1206 struct stat sb;
1207 int ret;
1208
1209 ret = stat(path, &sb);
1210 if (ret < 0)
1211 // could be something other than eexist, just say no
1212 return false;
1213 return S_ISDIR(sb.st_mode);
1214}
93c379f0
ÇO
1215
1216/* Note we don't use SHA-1 here as we don't want to depend on HAVE_GNUTLS.
1217 * FNV has good anti collision properties and we're not worried
1218 * about pre-image resistance or one-way-ness, we're just trying to make
1219 * the name unique in the 108 bytes of space we have.
1220 */
1221uint64_t fnv_64a_buf(void *buf, size_t len, uint64_t hval)
1222{
1223 unsigned char *bp;
1224
1225 for(bp = buf; bp < (unsigned char *)buf + len; bp++)
1226 {
1227 /* xor the bottom with the current octet */
1228 hval ^= (uint64_t)*bp;
1229
1230 /* gcc optimised:
1231 * multiply by the 64 bit FNV magic prime mod 2^64
1232 */
1233 hval += (hval << 1) + (hval << 4) + (hval << 5) +
1234 (hval << 7) + (hval << 8) + (hval << 40);
1235 }
1236
1237 return hval;
1238}
2c6f3fc9
SH
1239
1240/*
1241 * Detect whether / is mounted MS_SHARED. The only way I know of to
1242 * check that is through /proc/self/mountinfo.
1243 * I'm only checking for /. If the container rootfs or mount location
1244 * is MS_SHARED, but not '/', then you're out of luck - figuring that
1245 * out would be too much work to be worth it.
1246 */
1247#define LINELEN 4096
1248int detect_shared_rootfs(void)
1249{
1250 char buf[LINELEN], *p;
1251 FILE *f;
1252 int i;
1253 char *p2;
1254
1255 f = fopen("/proc/self/mountinfo", "r");
1256 if (!f)
1257 return 0;
1258 while (fgets(buf, LINELEN, f)) {
1259 for (p = buf, i=0; p && i < 4; i++)
b7f954bb 1260 p = strchr(p+1, ' ');
2c6f3fc9
SH
1261 if (!p)
1262 continue;
b7f954bb 1263 p2 = strchr(p+1, ' ');
2c6f3fc9
SH
1264 if (!p2)
1265 continue;
1266 *p2 = '\0';
1267 if (strcmp(p+1, "/") == 0) {
1268 // this is '/'. is it shared?
b7f954bb 1269 p = strchr(p2+1, ' ');
2c6f3fc9
SH
1270 if (p && strstr(p, "shared:")) {
1271 fclose(f);
1272 return 1;
1273 }
1274 }
1275 }
1276 fclose(f);
1277 return 0;
1278}
0e6e3a41 1279
51d0854c
DY
1280bool switch_to_ns(pid_t pid, const char *ns) {
1281 int fd, ret;
1282 char nspath[MAXPATHLEN];
1283
1284 /* Switch to new ns */
1285 ret = snprintf(nspath, MAXPATHLEN, "/proc/%d/ns/%s", pid, ns);
1286 if (ret < 0 || ret >= MAXPATHLEN)
1287 return false;
1288
1289 fd = open(nspath, O_RDONLY);
1290 if (fd < 0) {
1291 SYSERROR("failed to open %s", nspath);
1292 return false;
1293 }
1294
1295 ret = setns(fd, 0);
1296 if (ret) {
1297 SYSERROR("failed to set process %d to %s of %d.", pid, ns, fd);
1298 close(fd);
1299 return false;
1300 }
1301 close(fd);
1302 return true;
1303}
1304
b7f954bb
SH
1305/*
1306 * looking at fs/proc_namespace.c, it appears we can
1307 * actually expect the rootfs entry to very specifically contain
1308 * " - rootfs rootfs "
1309 * IIUC, so long as we've chrooted so that rootfs is not our root,
1310 * the rootfs entry should always be skipped in mountinfo contents.
1311 */
1312int detect_ramfs_rootfs(void)
1313{
1314 char buf[LINELEN], *p;
1315 FILE *f;
1316 int i;
1317 char *p2;
1318
1319 f = fopen("/proc/self/mountinfo", "r");
1320 if (!f)
1321 return 0;
1322 while (fgets(buf, LINELEN, f)) {
1323 for (p = buf, i=0; p && i < 4; i++)
1324 p = strchr(p+1, ' ');
1325 if (!p)
1326 continue;
1327 p2 = strchr(p+1, ' ');
1328 if (!p2)
1329 continue;
1330 *p2 = '\0';
1331 if (strcmp(p+1, "/") == 0) {
1332 // this is '/'. is it the ramfs?
1333 p = strchr(p2+1, '-');
1334 if (p && strncmp(p, "- rootfs rootfs ", 16) == 0) {
1335 fclose(f);
1336 return 1;
1337 }
1338 }
1339 }
1340 fclose(f);
1341 return 0;
1342}
1343
9d9c111c 1344char *on_path(char *cmd, const char *rootfs) {
0e6e3a41
SG
1345 char *path = NULL;
1346 char *entry = NULL;
1347 char *saveptr = NULL;
1348 char cmdpath[MAXPATHLEN];
1349 int ret;
1350
1351 path = getenv("PATH");
1352 if (!path)
8afb3e61 1353 return NULL;
0e6e3a41
SG
1354
1355 path = strdup(path);
1356 if (!path)
8afb3e61 1357 return NULL;
0e6e3a41
SG
1358
1359 entry = strtok_r(path, ":", &saveptr);
1360 while (entry) {
9d9c111c
SH
1361 if (rootfs)
1362 ret = snprintf(cmdpath, MAXPATHLEN, "%s/%s/%s", rootfs, entry, cmd);
1363 else
1364 ret = snprintf(cmdpath, MAXPATHLEN, "%s/%s", entry, cmd);
0e6e3a41
SG
1365
1366 if (ret < 0 || ret >= MAXPATHLEN)
1367 goto next_loop;
1368
1369 if (access(cmdpath, X_OK) == 0) {
1370 free(path);
8afb3e61 1371 return strdup(cmdpath);
0e6e3a41
SG
1372 }
1373
1374next_loop:
b707e368 1375 entry = strtok_r(NULL, ":", &saveptr);
0e6e3a41
SG
1376 }
1377
1378 free(path);
8afb3e61 1379 return NULL;
0e6e3a41 1380}
76a26f55
SH
1381
1382bool file_exists(const char *f)
1383{
1384 struct stat statbuf;
1385
1386 return stat(f, &statbuf) == 0;
1387}
9d9c111c
SH
1388
1389/* historically lxc-init has been under /usr/lib/lxc and under
1390 * /usr/lib/$ARCH/lxc. It now lives as $prefix/sbin/init.lxc.
1391 */
1392char *choose_init(const char *rootfs)
1393{
1394 char *retv = NULL;
370ec268
SF
1395 const char *empty = "",
1396 *tmp;
9d9c111c
SH
1397 int ret, env_set = 0;
1398 struct stat mystat;
1399
1400 if (!getenv("PATH")) {
1401 if (setenv("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 0))
1402 SYSERROR("Failed to setenv");
1403 env_set = 1;
1404 }
1405
1406 retv = on_path("init.lxc", rootfs);
1407
1408 if (env_set) {
1409 if (unsetenv("PATH"))
1410 SYSERROR("Failed to unsetenv");
1411 }
1412
1413 if (retv)
1414 return retv;
1415
1416 retv = malloc(PATH_MAX);
1417 if (!retv)
1418 return NULL;
1419
1420 if (rootfs)
370ec268 1421 tmp = rootfs;
9d9c111c 1422 else
370ec268
SF
1423 tmp = empty;
1424
1425 ret = snprintf(retv, PATH_MAX, "%s/%s/%s", tmp, SBINDIR, "/init.lxc");
9d9c111c
SH
1426 if (ret < 0 || ret >= PATH_MAX) {
1427 ERROR("pathname too long");
1428 goto out1;
1429 }
1430
1431 ret = stat(retv, &mystat);
1432 if (ret == 0)
1433 return retv;
1434
370ec268 1435 ret = snprintf(retv, PATH_MAX, "%s/%s/%s", tmp, LXCINITDIR, "/lxc/lxc-init");
9d9c111c
SH
1436 if (ret < 0 || ret >= PATH_MAX) {
1437 ERROR("pathname too long");
1438 goto out1;
1439 }
1440
1441 ret = stat(retv, &mystat);
1442 if (ret == 0)
1443 return retv;
1444
370ec268 1445 ret = snprintf(retv, PATH_MAX, "%s/usr/lib/lxc/lxc-init", tmp);
9d9c111c
SH
1446 if (ret < 0 || ret >= PATH_MAX) {
1447 ERROR("pathname too long");
1448 goto out1;
1449 }
1450 ret = stat(retv, &mystat);
1451 if (ret == 0)
1452 return retv;
1453
370ec268 1454 ret = snprintf(retv, PATH_MAX, "%s/sbin/lxc-init", tmp);
9d9c111c
SH
1455 if (ret < 0 || ret >= PATH_MAX) {
1456 ERROR("pathname too long");
1457 goto out1;
1458 }
1459 ret = stat(retv, &mystat);
1460 if (ret == 0)
1461 return retv;
1462
1463 /*
1464 * Last resort, look for the statically compiled init.lxc which we
1465 * hopefully bind-mounted in.
1466 * If we are called during container setup, and we get to this point,
1467 * then the init.lxc.static from the host will need to be bind-mounted
1468 * in. So we return NULL here to indicate that.
1469 */
1470 if (rootfs)
1471 goto out1;
1472
1473 ret = snprintf(retv, PATH_MAX, "/init.lxc.static");
1474 if (ret < 0 || ret >= PATH_MAX) {
1475 WARN("Nonsense - name /lxc.init.static too long");
1476 goto out1;
1477 }
1478 ret = stat(retv, &mystat);
1479 if (ret == 0)
1480 return retv;
1481
1482out1:
1483 free(retv);
1484 return NULL;
1485}
735f2c6e
TA
1486
1487int print_to_file(const char *file, const char *content)
1488{
1489 FILE *f;
1490 int ret = 0;
1491
1492 f = fopen(file, "w");
1493 if (!f)
1494 return -1;
1495 if (fprintf(f, "%s", content) != strlen(content))
1496 ret = -1;
1497 fclose(f);
1498 return ret;
1499}
e1daebd9
SH
1500
1501int is_dir(const char *path)
1502{
1503 struct stat statbuf;
1504 int ret = stat(path, &statbuf);
1505 if (ret == 0 && S_ISDIR(statbuf.st_mode))
1506 return 1;
1507 return 0;
1508}
6010a416
SG
1509
1510/*
1511 * Given the '-t' template option to lxc-create, figure out what to
1512 * do. If the template is a full executable path, use that. If it
1513 * is something like 'sshd', then return $templatepath/lxc-sshd.
1514 * On success return the template, on error return NULL.
1515 */
1516char *get_template_path(const char *t)
1517{
1518 int ret, len;
1519 char *tpath;
1520
1521 if (t[0] == '/' && access(t, X_OK) == 0) {
1522 tpath = strdup(t);
1523 return tpath;
1524 }
1525
1526 len = strlen(LXCTEMPLATEDIR) + strlen(t) + strlen("/lxc-") + 1;
1527 tpath = malloc(len);
1528 if (!tpath)
1529 return NULL;
1530 ret = snprintf(tpath, len, "%s/lxc-%s", LXCTEMPLATEDIR, t);
1531 if (ret < 0 || ret >= len) {
1532 free(tpath);
1533 return NULL;
1534 }
1535 if (access(tpath, X_OK) < 0) {
1536 SYSERROR("bad template: %s", t);
1537 free(tpath);
1538 return NULL;
1539 }
1540
1541 return tpath;
1542}