]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/conf.c
lxc_create: prepend pretty header to config file (v2)
[mirror_lxc.git] / src / lxc / conf.c
CommitLineData
0ad19a3f 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>
0ad19a3f 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
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23#define _GNU_SOURCE
24#include <stdio.h>
25#undef _GNU_SOURCE
26#include <stdlib.h>
e3b4c4c4 27#include <stdarg.h>
0ad19a3f 28#include <errno.h>
29#include <string.h>
30#include <dirent.h>
0ad19a3f 31#include <unistd.h>
e3b4c4c4 32#include <sys/wait.h>
2d76d1d7 33#include <sys/syscall.h>
e827ff7e
SG
34
35#if HAVE_PTY_H
b0a33c1e 36#include <pty.h>
e827ff7e
SG
37#else
38#include <../include/openpty.h>
39#endif
0ad19a3f 40
b3ecde1e
DL
41#include <linux/loop.h>
42
0ad19a3f 43#include <sys/types.h>
44#include <sys/utsname.h>
45#include <sys/param.h>
46#include <sys/stat.h>
47#include <sys/socket.h>
48#include <sys/mount.h>
49#include <sys/mman.h>
81810dd1 50#include <sys/prctl.h>
0ad19a3f 51
52#include <arpa/inet.h>
53#include <fcntl.h>
54#include <netinet/in.h>
55#include <net/if.h>
6f4a3756 56#include <libgen.h>
0ad19a3f 57
e5bda9ee 58#include "network.h"
59#include "error.h"
b2718c72 60#include "parse.h"
881450bb 61#include "config.h"
1b09f2c0
DL
62#include "utils.h"
63#include "conf.h"
64#include "log.h"
65#include "lxc.h" /* for lxc_cgroup_set() */
d55bc1ad 66#include "caps.h" /* for lxc_caps_last_cap() */
9be53773 67#include "bdev.h"
36eb9bde 68
d0a36f2c
SG
69#if HAVE_APPARMOR
70#include <apparmor.h>
71#endif
72
495d2046
SG
73#if HAVE_SYS_CAPABILITY_H
74#include <sys/capability.h>
75#endif
76
6ff05e18
SG
77#if HAVE_SYS_PERSONALITY_H
78#include <sys/personality.h>
79#endif
80
edaf8b1b
SG
81#if IS_BIONIC
82#include <../include/lxcmntent.h>
83#else
84#include <mntent.h>
85#endif
86
769872f9
SH
87#include "lxcseccomp.h"
88
36eb9bde 89lxc_log_define(lxc_conf, lxc);
e5bda9ee 90
0ad19a3f 91#define MAXHWLEN 18
92#define MAXINDEXLEN 20
442cbbe6 93#define MAXMTULEN 16
0ad19a3f 94#define MAXLINELEN 128
95
495d2046 96#if HAVE_SYS_CAPABILITY_H
b09094da
MN
97#ifndef CAP_SETFCAP
98#define CAP_SETFCAP 31
99#endif
100
101#ifndef CAP_MAC_OVERRIDE
102#define CAP_MAC_OVERRIDE 32
103#endif
104
105#ifndef CAP_MAC_ADMIN
106#define CAP_MAC_ADMIN 33
107#endif
495d2046 108#endif
b09094da
MN
109
110#ifndef PR_CAPBSET_DROP
111#define PR_CAPBSET_DROP 24
112#endif
113
9818cae4
SG
114#ifndef LO_FLAGS_AUTOCLEAR
115#define LO_FLAGS_AUTOCLEAR 4
116#endif
117
2d76d1d7
SG
118/* Define pivot_root() if missing from the C library */
119#ifndef HAVE_PIVOT_ROOT
120static int pivot_root(const char * new_root, const char * put_old)
121{
122#ifdef __NR_pivot_root
123return syscall(__NR_pivot_root, new_root, put_old);
124#else
125errno = ENOSYS;
126return -1;
127#endif
128}
129#else
130extern int pivot_root(const char * new_root, const char * put_old);
131#endif
132
133/* Define sethostname() if missing from the C library */
134#ifndef HAVE_SETHOSTNAME
135static int sethostname(const char * name, size_t len)
136{
137#ifdef __NR_sethostname
138return syscall(__NR_sethostname, name, len);
139#else
140errno = ENOSYS;
141return -1;
142#endif
143}
144#endif
145
72f919c4
SG
146/* Define __S_ISTYPE if missing from the C library */
147#ifndef __S_ISTYPE
148#define __S_ISTYPE(mode, mask) (((mode) & S_IFMT) == (mask))
149#endif
150
72d0e1cb 151char *lxchook_names[NUM_LXC_HOOKS] = {
148e91f5 152 "pre-start", "pre-mount", "mount", "autodev", "start", "post-stop", "clone" };
72d0e1cb 153
e3b4c4c4 154typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
0ad19a3f 155
998ac676
RT
156struct mount_opt {
157 char *name;
158 int clear;
159 int flag;
160};
161
81810dd1
DL
162struct caps_opt {
163 char *name;
164 int value;
165};
166
e3b4c4c4
ST
167static int instanciate_veth(struct lxc_handler *, struct lxc_netdev *);
168static int instanciate_macvlan(struct lxc_handler *, struct lxc_netdev *);
169static int instanciate_vlan(struct lxc_handler *, struct lxc_netdev *);
170static int instanciate_phys(struct lxc_handler *, struct lxc_netdev *);
171static int instanciate_empty(struct lxc_handler *, struct lxc_netdev *);
82d5ae15 172
24654103
DL
173static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
174 [LXC_NET_VETH] = instanciate_veth,
175 [LXC_NET_MACVLAN] = instanciate_macvlan,
176 [LXC_NET_VLAN] = instanciate_vlan,
177 [LXC_NET_PHYS] = instanciate_phys,
178 [LXC_NET_EMPTY] = instanciate_empty,
0ad19a3f 179};
180
74a2b586
JK
181static int shutdown_veth(struct lxc_handler *, struct lxc_netdev *);
182static int shutdown_macvlan(struct lxc_handler *, struct lxc_netdev *);
183static int shutdown_vlan(struct lxc_handler *, struct lxc_netdev *);
184static int shutdown_phys(struct lxc_handler *, struct lxc_netdev *);
185static int shutdown_empty(struct lxc_handler *, struct lxc_netdev *);
186
187static instanciate_cb netdev_deconf[LXC_NET_MAXCONFTYPE + 1] = {
188 [LXC_NET_VETH] = shutdown_veth,
189 [LXC_NET_MACVLAN] = shutdown_macvlan,
190 [LXC_NET_VLAN] = shutdown_vlan,
191 [LXC_NET_PHYS] = shutdown_phys,
192 [LXC_NET_EMPTY] = shutdown_empty,
193};
194
998ac676 195static struct mount_opt mount_opt[] = {
88d413d5
SW
196 { "defaults", 0, 0 },
197 { "ro", 0, MS_RDONLY },
198 { "rw", 1, MS_RDONLY },
199 { "suid", 1, MS_NOSUID },
200 { "nosuid", 0, MS_NOSUID },
201 { "dev", 1, MS_NODEV },
202 { "nodev", 0, MS_NODEV },
203 { "exec", 1, MS_NOEXEC },
204 { "noexec", 0, MS_NOEXEC },
205 { "sync", 0, MS_SYNCHRONOUS },
206 { "async", 1, MS_SYNCHRONOUS },
207 { "dirsync", 0, MS_DIRSYNC },
208 { "remount", 0, MS_REMOUNT },
209 { "mand", 0, MS_MANDLOCK },
210 { "nomand", 1, MS_MANDLOCK },
211 { "atime", 1, MS_NOATIME },
212 { "noatime", 0, MS_NOATIME },
213 { "diratime", 1, MS_NODIRATIME },
214 { "nodiratime", 0, MS_NODIRATIME },
215 { "bind", 0, MS_BIND },
216 { "rbind", 0, MS_BIND|MS_REC },
217 { "relatime", 0, MS_RELATIME },
218 { "norelatime", 1, MS_RELATIME },
219 { "strictatime", 0, MS_STRICTATIME },
220 { "nostrictatime", 1, MS_STRICTATIME },
221 { NULL, 0, 0 },
998ac676
RT
222};
223
495d2046 224#if HAVE_SYS_CAPABILITY_H
81810dd1 225static struct caps_opt caps_opt[] = {
a6afdde9 226 { "chown", CAP_CHOWN },
1e11be34
DL
227 { "dac_override", CAP_DAC_OVERRIDE },
228 { "dac_read_search", CAP_DAC_READ_SEARCH },
229 { "fowner", CAP_FOWNER },
230 { "fsetid", CAP_FSETID },
81810dd1
DL
231 { "kill", CAP_KILL },
232 { "setgid", CAP_SETGID },
233 { "setuid", CAP_SETUID },
234 { "setpcap", CAP_SETPCAP },
235 { "linux_immutable", CAP_LINUX_IMMUTABLE },
236 { "net_bind_service", CAP_NET_BIND_SERVICE },
237 { "net_broadcast", CAP_NET_BROADCAST },
238 { "net_admin", CAP_NET_ADMIN },
239 { "net_raw", CAP_NET_RAW },
240 { "ipc_lock", CAP_IPC_LOCK },
241 { "ipc_owner", CAP_IPC_OWNER },
242 { "sys_module", CAP_SYS_MODULE },
243 { "sys_rawio", CAP_SYS_RAWIO },
244 { "sys_chroot", CAP_SYS_CHROOT },
245 { "sys_ptrace", CAP_SYS_PTRACE },
246 { "sys_pacct", CAP_SYS_PACCT },
247 { "sys_admin", CAP_SYS_ADMIN },
248 { "sys_boot", CAP_SYS_BOOT },
249 { "sys_nice", CAP_SYS_NICE },
250 { "sys_resource", CAP_SYS_RESOURCE },
251 { "sys_time", CAP_SYS_TIME },
252 { "sys_tty_config", CAP_SYS_TTY_CONFIG },
253 { "mknod", CAP_MKNOD },
254 { "lease", CAP_LEASE },
9527e566 255#ifdef CAP_AUDIT_WRITE
81810dd1 256 { "audit_write", CAP_AUDIT_WRITE },
9527e566
FW
257#endif
258#ifdef CAP_AUDIT_CONTROL
81810dd1 259 { "audit_control", CAP_AUDIT_CONTROL },
9527e566 260#endif
81810dd1
DL
261 { "setfcap", CAP_SETFCAP },
262 { "mac_override", CAP_MAC_OVERRIDE },
263 { "mac_admin", CAP_MAC_ADMIN },
5170c716
CS
264#ifdef CAP_SYSLOG
265 { "syslog", CAP_SYSLOG },
266#endif
267#ifdef CAP_WAKE_ALARM
268 { "wake_alarm", CAP_WAKE_ALARM },
269#endif
81810dd1 270};
495d2046
SG
271#else
272static struct caps_opt caps_opt[] = {};
273#endif
81810dd1 274
91c3830e
SH
275static int run_buffer(char *buffer)
276{
277 FILE *f;
278 char *output;
8e7da691 279 int ret;
91c3830e
SH
280
281 f = popen(buffer, "r");
282 if (!f) {
283 SYSERROR("popen failed");
284 return -1;
285 }
286
287 output = malloc(LXC_LOG_BUFFER_SIZE);
288 if (!output) {
289 ERROR("failed to allocate memory for script output");
00b6be44 290 pclose(f);
91c3830e
SH
291 return -1;
292 }
293
294 while(fgets(output, LXC_LOG_BUFFER_SIZE, f))
295 DEBUG("script output: %s", output);
296
297 free(output);
298
8e7da691
DE
299 ret = pclose(f);
300 if (ret == -1) {
91c3830e
SH
301 SYSERROR("Script exited on error");
302 return -1;
8e7da691
DE
303 } else if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) {
304 ERROR("Script exited with status %d", WEXITSTATUS(ret));
305 return -1;
306 } else if (WIFSIGNALED(ret)) {
307 ERROR("Script terminated by signal %d (%s)", WTERMSIG(ret),
308 strsignal(WTERMSIG(ret)));
309 return -1;
91c3830e
SH
310 }
311
312 return 0;
313}
314
148e91f5 315static int run_script_argv(const char *name, const char *section,
283678ed
SH
316 const char *script, const char *hook, const char *lxcpath,
317 char **argsin)
148e91f5
SH
318{
319 int ret, i;
320 char *buffer;
321 size_t size = 0;
322
323 INFO("Executing script '%s' for container '%s', config section '%s'",
324 script, name, section);
325
326 for (i=0; argsin && argsin[i]; i++)
327 size += strlen(argsin[i]) + 1;
328
329 size += strlen(hook) + 1;
330
331 size += strlen(script);
332 size += strlen(name);
333 size += strlen(section);
334 size += 3;
335
336 if (size > INT_MAX)
337 return -1;
338
339 buffer = alloca(size);
340 if (!buffer) {
341 ERROR("failed to allocate memory");
342 return -1;
343 }
344
345 ret = snprintf(buffer, size, "%s %s %s %s", script, name, section, hook);
346 if (ret < 0 || ret >= size) {
347 ERROR("Script name too long");
348 return -1;
349 }
350
351 for (i=0; argsin && argsin[i]; i++) {
352 int len = size-ret;
353 int rc;
354 rc = snprintf(buffer + ret, len, " %s", argsin[i]);
355 if (rc < 0 || rc >= len) {
356 ERROR("Script args too long");
357 return -1;
358 }
359 ret += rc;
360 }
361
362 return run_buffer(buffer);
363}
364
751d9dcd
DL
365static int run_script(const char *name, const char *section,
366 const char *script, ...)
e3b4c4c4 367{
abbfd20b 368 int ret;
91c3830e 369 char *buffer, *p;
abbfd20b
DL
370 size_t size = 0;
371 va_list ap;
751d9dcd
DL
372
373 INFO("Executing script '%s' for container '%s', config section '%s'",
374 script, name, section);
e3b4c4c4 375
abbfd20b
DL
376 va_start(ap, script);
377 while ((p = va_arg(ap, char *)))
95642a10 378 size += strlen(p) + 1;
abbfd20b
DL
379 va_end(ap);
380
381 size += strlen(script);
382 size += strlen(name);
383 size += strlen(section);
95642a10 384 size += 3;
abbfd20b 385
95642a10
MS
386 if (size > INT_MAX)
387 return -1;
388
389 buffer = alloca(size);
abbfd20b
DL
390 if (!buffer) {
391 ERROR("failed to allocate memory");
751d9dcd
DL
392 return -1;
393 }
394
9ba8130c
SH
395 ret = snprintf(buffer, size, "%s %s %s", script, name, section);
396 if (ret < 0 || ret >= size) {
397 ERROR("Script name too long");
9ba8130c
SH
398 return -1;
399 }
751d9dcd 400
abbfd20b 401 va_start(ap, script);
9ba8130c
SH
402 while ((p = va_arg(ap, char *))) {
403 int len = size-ret;
404 int rc;
405 rc = snprintf(buffer + ret, len, " %s", p);
406 if (rc < 0 || rc >= len) {
9ba8130c
SH
407 ERROR("Script args too long");
408 return -1;
409 }
410 ret += rc;
411 }
abbfd20b 412 va_end(ap);
751d9dcd 413
91c3830e 414 return run_buffer(buffer);
e3b4c4c4
ST
415}
416
a6afdde9 417static int find_fstype_cb(char* buffer, void *data)
78ae2fcc 418{
419 struct cbarg {
420 const char *rootfs;
a6afdde9 421 const char *target;
78ae2fcc 422 int mntopt;
423 } *cbarg = data;
424
425 char *fstype;
426
427 /* we don't try 'nodev' entries */
428 if (strstr(buffer, "nodev"))
429 return 0;
430
431 fstype = buffer;
b2718c72 432 fstype += lxc_char_left_gc(fstype, strlen(fstype));
433 fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
78ae2fcc 434
a6afdde9
DL
435 DEBUG("trying to mount '%s'->'%s' with fstype '%s'",
436 cbarg->rootfs, cbarg->target, fstype);
437
438 if (mount(cbarg->rootfs, cbarg->target, fstype, cbarg->mntopt, NULL)) {
439 DEBUG("mount failed with error: %s", strerror(errno));
78ae2fcc 440 return 0;
a6afdde9 441 }
78ae2fcc 442
a6afdde9
DL
443 INFO("mounted '%s' on '%s', with fstype '%s'",
444 cbarg->rootfs, cbarg->target, fstype);
78ae2fcc 445
446 return 1;
447}
448
2656d231 449static int mount_unknow_fs(const char *rootfs, const char *target, int mntopt)
78ae2fcc 450{
a6afdde9 451 int i;
78ae2fcc 452
453 struct cbarg {
454 const char *rootfs;
a6afdde9 455 const char *target;
78ae2fcc 456 int mntopt;
457 } cbarg = {
458 .rootfs = rootfs,
a6afdde9 459 .target = target,
78ae2fcc 460 .mntopt = mntopt,
461 };
462
a6afdde9
DL
463 /*
464 * find the filesystem type with brute force:
465 * first we check with /etc/filesystems, in case the modules
78ae2fcc 466 * are auto-loaded and fall back to the supported kernel fs
467 */
468 char *fsfile[] = {
469 "/etc/filesystems",
470 "/proc/filesystems",
471 };
472
a6afdde9
DL
473 for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) {
474
475 int ret;
476
477 if (access(fsfile[i], F_OK))
478 continue;
479
480 ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
481 if (ret < 0) {
482 ERROR("failed to parse '%s'", fsfile[i]);
483 return -1;
484 }
485
486 if (ret)
487 return 0;
78ae2fcc 488 }
489
a6afdde9
DL
490 ERROR("failed to determine fs type for '%s'", rootfs);
491 return -1;
492}
493
2656d231 494static int mount_rootfs_dir(const char *rootfs, const char *target)
a6afdde9
DL
495{
496 return mount(rootfs, target, "none", MS_BIND | MS_REC, NULL);
497}
498
499static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
500{
501 int rfd;
502 int ret = -1;
503
504 rfd = open(rootfs, O_RDWR);
505 if (rfd < 0) {
506 SYSERROR("failed to open '%s'", rootfs);
78ae2fcc 507 return -1;
508 }
509
a6afdde9 510 memset(loinfo, 0, sizeof(*loinfo));
78ae2fcc 511
a6afdde9 512 loinfo->lo_flags = LO_FLAGS_AUTOCLEAR;
78ae2fcc 513
a6afdde9
DL
514 if (ioctl(fd, LOOP_SET_FD, rfd)) {
515 SYSERROR("failed to LOOP_SET_FD");
516 goto out;
78ae2fcc 517 }
518
a6afdde9
DL
519 if (ioctl(fd, LOOP_SET_STATUS64, loinfo)) {
520 SYSERROR("failed to LOOP_SET_STATUS64");
78ae2fcc 521 goto out;
522 }
523
a6afdde9 524 ret = 0;
78ae2fcc 525out:
a6afdde9 526 close(rfd);
78ae2fcc 527
a6afdde9 528 return ret;
78ae2fcc 529}
530
2656d231 531static int mount_rootfs_file(const char *rootfs, const char *target)
78ae2fcc 532{
a6afdde9
DL
533 struct dirent dirent, *direntp;
534 struct loop_info64 loinfo;
9ba8130c 535 int ret = -1, fd = -1, rc;
a6afdde9
DL
536 DIR *dir;
537 char path[MAXPATHLEN];
78ae2fcc 538
a6afdde9
DL
539 dir = opendir("/dev");
540 if (!dir) {
541 SYSERROR("failed to open '/dev'");
78ae2fcc 542 return -1;
543 }
544
a6afdde9
DL
545 while (!readdir_r(dir, &dirent, &direntp)) {
546
547 if (!direntp)
548 break;
549
550 if (!strcmp(direntp->d_name, "."))
551 continue;
552
553 if (!strcmp(direntp->d_name, ".."))
554 continue;
555
556 if (strncmp(direntp->d_name, "loop", 4))
557 continue;
558
9ba8130c
SH
559 rc = snprintf(path, MAXPATHLEN, "/dev/%s", direntp->d_name);
560 if (rc < 0 || rc >= MAXPATHLEN)
561 continue;
562
a6afdde9
DL
563 fd = open(path, O_RDWR);
564 if (fd < 0)
565 continue;
566
567 if (ioctl(fd, LOOP_GET_STATUS64, &loinfo) == 0) {
568 close(fd);
569 continue;
570 }
571
572 if (errno != ENXIO) {
573 WARN("unexpected error for ioctl on '%s': %m",
574 direntp->d_name);
00b6be44 575 close(fd);
a6afdde9
DL
576 continue;
577 }
578
579 DEBUG("found '%s' free lodev", path);
580
581 ret = setup_lodev(rootfs, fd, &loinfo);
582 if (!ret)
2656d231 583 ret = mount_unknow_fs(path, target, 0);
a6afdde9
DL
584 close(fd);
585
586 break;
587 }
588
589 if (closedir(dir))
590 WARN("failed to close directory");
591
592 return ret;
78ae2fcc 593}
594
2656d231 595static int mount_rootfs_block(const char *rootfs, const char *target)
a6afdde9 596{
2656d231 597 return mount_unknow_fs(rootfs, target, 0);
a6afdde9
DL
598}
599
0c547523
SH
600/*
601 * pin_rootfs
602 * if rootfs is a directory, then open ${rootfs}.hold for writing for the
603 * duration of the container run, to prevent the container from marking the
604 * underlying fs readonly on shutdown.
605 * return -1 on error.
606 * return -2 if nothing needed to be pinned.
607 * return an open fd (>=0) if we pinned it.
608 */
609int pin_rootfs(const char *rootfs)
610{
611 char absrootfs[MAXPATHLEN];
612 char absrootfspin[MAXPATHLEN];
613 struct stat s;
614 int ret, fd;
615
e99ee0de 616 if (rootfs == NULL || strlen(rootfs) == 0)
0d03360a 617 return -2;
e99ee0de 618
0c547523 619 if (!realpath(rootfs, absrootfs)) {
9be53773
SH
620 INFO("failed to get real path for '%s', not pinning", rootfs);
621 return -2;
0c547523
SH
622 }
623
624 if (access(absrootfs, F_OK)) {
625 SYSERROR("'%s' is not accessible", absrootfs);
626 return -1;
627 }
628
629 if (stat(absrootfs, &s)) {
630 SYSERROR("failed to stat '%s'", absrootfs);
631 return -1;
632 }
633
72f919c4 634 if (!S_ISDIR(s.st_mode))
0c547523
SH
635 return -2;
636
637 ret = snprintf(absrootfspin, MAXPATHLEN, "%s%s", absrootfs, ".hold");
638 if (ret >= MAXPATHLEN) {
639 SYSERROR("pathname too long for rootfs hold file");
640 return -1;
641 }
642
643 fd = open(absrootfspin, O_CREAT | O_RDWR, S_IWUSR|S_IRUSR);
644 INFO("opened %s as fd %d\n", absrootfspin, fd);
645 return fd;
646}
647
2656d231 648static int mount_rootfs(const char *rootfs, const char *target)
0ad19a3f 649{
b09ef133 650 char absrootfs[MAXPATHLEN];
78ae2fcc 651 struct stat s;
a6afdde9 652 int i;
78ae2fcc 653
a6afdde9 654 typedef int (*rootfs_cb)(const char *, const char *);
78ae2fcc 655
656 struct rootfs_type {
657 int type;
658 rootfs_cb cb;
659 } rtfs_type[] = {
2656d231
DL
660 { S_IFDIR, mount_rootfs_dir },
661 { S_IFBLK, mount_rootfs_block },
662 { S_IFREG, mount_rootfs_file },
78ae2fcc 663 };
0ad19a3f 664
4c8ab83b 665 if (!realpath(rootfs, absrootfs)) {
36eb9bde 666 SYSERROR("failed to get real path for '%s'", rootfs);
4c8ab83b 667 return -1;
668 }
b09ef133 669
b09ef133 670 if (access(absrootfs, F_OK)) {
36eb9bde 671 SYSERROR("'%s' is not accessible", absrootfs);
b09ef133 672 return -1;
673 }
674
78ae2fcc 675 if (stat(absrootfs, &s)) {
36eb9bde 676 SYSERROR("failed to stat '%s'", absrootfs);
9b0f0477 677 return -1;
678 }
679
78ae2fcc 680 for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) {
9b0f0477 681
78ae2fcc 682 if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
683 continue;
9b0f0477 684
a6afdde9 685 return rtfs_type[i].cb(absrootfs, target);
78ae2fcc 686 }
9b0f0477 687
36eb9bde 688 ERROR("unsupported rootfs type for '%s'", absrootfs);
78ae2fcc 689 return -1;
0ad19a3f 690}
691
4e5440c6 692static int setup_utsname(struct utsname *utsname)
0ad19a3f 693{
4e5440c6
DL
694 if (!utsname)
695 return 0;
0ad19a3f 696
4e5440c6
DL
697 if (sethostname(utsname->nodename, strlen(utsname->nodename))) {
698 SYSERROR("failed to set the hostname to '%s'", utsname->nodename);
0ad19a3f 699 return -1;
700 }
701
4e5440c6 702 INFO("'%s' hostname has been setup", utsname->nodename);
cd54d859 703
0ad19a3f 704 return 0;
705}
706
33fcb7a0 707static int setup_tty(const struct lxc_rootfs *rootfs,
7c6ef2a2 708 const struct lxc_tty_info *tty_info, char *ttydir)
b0a33c1e 709{
7c6ef2a2
SH
710 char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
711 int i, ret;
b0a33c1e 712
bc9bd0e3
DL
713 if (!rootfs->path)
714 return 0;
715
b0a33c1e 716 for (i = 0; i < tty_info->nbtty; i++) {
717
718 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
719
7c6ef2a2 720 ret = snprintf(path, sizeof(path), "%s/dev/tty%d",
12297168 721 rootfs->mount, i + 1);
7c6ef2a2
SH
722 if (ret >= sizeof(path)) {
723 ERROR("pathname too long for ttys");
724 return -1;
725 }
726 if (ttydir) {
727 /* create dev/lxc/tty%d" */
9ba8130c 728 ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/tty%d",
7c6ef2a2
SH
729 rootfs->mount, ttydir, i + 1);
730 if (ret >= sizeof(lxcpath)) {
731 ERROR("pathname too long for ttys");
732 return -1;
733 }
734 ret = creat(lxcpath, 0660);
735 if (ret==-1 && errno != EEXIST) {
736 SYSERROR("error creating %s\n", lxcpath);
737 return -1;
738 }
4d44e274
SH
739 if (ret >= 0)
740 close(ret);
7c6ef2a2
SH
741 ret = unlink(path);
742 if (ret && errno != ENOENT) {
743 SYSERROR("error unlinking %s\n", path);
744 return -1;
745 }
b0a33c1e 746
7c6ef2a2
SH
747 if (mount(pty_info->name, lxcpath, "none", MS_BIND, 0)) {
748 WARN("failed to mount '%s'->'%s'",
749 pty_info->name, path);
750 continue;
751 }
13954cce 752
9ba8130c
SH
753 ret = snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d", ttydir, i+1);
754 if (ret >= sizeof(lxcpath)) {
755 ERROR("tty pathname too long");
756 return -1;
757 }
7c6ef2a2
SH
758 ret = symlink(lxcpath, path);
759 if (ret) {
760 SYSERROR("failed to create symlink for tty %d\n", i+1);
761 return -1;
762 }
763 } else {
c6883f38
SH
764 /* If we populated /dev, then we need to create /dev/ttyN */
765 if (access(path, F_OK)) {
766 ret = creat(path, 0660);
767 if (ret==-1) {
768 SYSERROR("error creating %s\n", path);
769 /* this isn't fatal, continue */
770 } else
771 close(ret);
772 }
7c6ef2a2
SH
773 if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
774 WARN("failed to mount '%s'->'%s'",
775 pty_info->name, path);
776 continue;
777 }
b0a33c1e 778 }
779 }
780
cd54d859
DL
781 INFO("%d tty(s) has been setup", tty_info->nbtty);
782
b0a33c1e 783 return 0;
784}
785
7a7ff0c6 786static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
bf601689
MH
787{
788 struct lxc_list *mountlist, *listentry, *iterator;
2c7d90ac 789 char *pivotdir, *mountpoint, *mountentry, *saveptr = NULL;
bf601689
MH
790 int found;
791 void **cbparm;
792
793 mountentry = buffer;
794 cbparm = (void **)data;
795
796 mountlist = cbparm[0];
797 pivotdir = cbparm[1];
798
799 /* parse entry, first field is mountname, ignore */
2796cf79 800 mountpoint = strtok_r(mountentry, " ", &saveptr);
bf601689
MH
801 if (!mountpoint)
802 return -1;
803
804 /* second field is mountpoint */
2796cf79 805 mountpoint = strtok_r(NULL, " ", &saveptr);
bf601689
MH
806 if (!mountpoint)
807 return -1;
808
809 /* only consider mountpoints below old root fs */
810 if (strncmp(mountpoint, pivotdir, strlen(pivotdir)))
811 return 0;
812
813 /* filter duplicate mountpoints */
814 found = 0;
815 lxc_list_for_each(iterator, mountlist) {
816 if (!strcmp(iterator->elem, mountpoint)) {
817 found = 1;
818 break;
819 }
820 }
821 if (found)
822 return 0;
823
824 /* add entry to list */
825 listentry = malloc(sizeof(*listentry));
826 if (!listentry) {
827 SYSERROR("malloc for mountpoint listentry failed");
828 return -1;
829 }
830
831 listentry->elem = strdup(mountpoint);
832 if (!listentry->elem) {
833 SYSERROR("strdup failed");
00b6be44 834 free(listentry);
bf601689
MH
835 return -1;
836 }
837 lxc_list_add_tail(mountlist, listentry);
838
839 return 0;
840}
841
cc6f6dd7 842static int umount_oldrootfs(const char *oldrootfs)
bf601689 843{
2382ecff 844 char path[MAXPATHLEN];
bf601689 845 void *cbparm[2];
9ebb03ad 846 struct lxc_list mountlist, *iterator, *next;
bf601689 847 int ok, still_mounted, last_still_mounted;
9ba8130c 848 int rc;
bf601689
MH
849
850 /* read and parse /proc/mounts in old root fs */
851 lxc_list_init(&mountlist);
852
cc6f6dd7 853 /* oldrootfs is on the top tree directory now */
9ba8130c
SH
854 rc = snprintf(path, sizeof(path), "/%s", oldrootfs);
855 if (rc >= sizeof(path)) {
856 ERROR("rootfs name too long");
857 return -1;
858 }
bf601689 859 cbparm[0] = &mountlist;
bf601689 860
cc6f6dd7 861 cbparm[1] = strdup(path);
bf601689
MH
862 if (!cbparm[1]) {
863 SYSERROR("strdup failed");
864 return -1;
865 }
866
9ba8130c
SH
867 rc = snprintf(path, sizeof(path), "%s/proc/mounts", oldrootfs);
868 if (rc >= sizeof(path)) {
869 ERROR("container proc/mounts name too long");
870 return -1;
871 }
cc6f6dd7
DL
872
873 ok = lxc_file_for_each_line(path,
874 setup_rootfs_pivot_root_cb, &cbparm);
bf601689
MH
875 if (ok < 0) {
876 SYSERROR("failed to read or parse mount list '%s'", path);
877 return -1;
878 }
879
880 /* umount filesystems until none left or list no longer shrinks */
881 still_mounted = 0;
882 do {
883 last_still_mounted = still_mounted;
884 still_mounted = 0;
885
9ebb03ad 886 lxc_list_for_each_safe(iterator, &mountlist, next) {
bf601689 887
c08556c6 888 /* umount normally */
bf601689
MH
889 if (!umount(iterator->elem)) {
890 DEBUG("umounted '%s'", (char *)iterator->elem);
891 lxc_list_del(iterator);
892 continue;
893 }
894
bf601689
MH
895 still_mounted++;
896 }
7df119ee 897
bf601689
MH
898 } while (still_mounted > 0 && still_mounted != last_still_mounted);
899
7df119ee 900
c08556c6
DL
901 lxc_list_for_each(iterator, &mountlist) {
902
903 /* let's try a lazy umount */
904 if (!umount2(iterator->elem, MNT_DETACH)) {
905 INFO("lazy unmount of '%s'", (char *)iterator->elem);
906 continue;
907 }
908
909 /* be more brutal (nfs) */
910 if (!umount2(iterator->elem, MNT_FORCE)) {
911 INFO("forced unmount of '%s'", (char *)iterator->elem);
912 continue;
913 }
914
7df119ee 915 WARN("failed to unmount '%s'", (char *)iterator->elem);
c08556c6 916 }
bf601689 917
cc6f6dd7
DL
918 return 0;
919}
920
921static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
922{
923 char path[MAXPATHLEN];
924 int remove_pivotdir = 0;
9ba8130c 925 int rc;
cc6f6dd7
DL
926
927 /* change into new root fs */
928 if (chdir(rootfs)) {
929 SYSERROR("can't chdir to new rootfs '%s'", rootfs);
930 return -1;
931 }
932
933 if (!pivotdir)
30c5d292 934 pivotdir = "lxc_putold";
cc6f6dd7 935
4f9293b1 936 /* compute the full path to pivotdir under rootfs */
9ba8130c
SH
937 rc = snprintf(path, sizeof(path), "%s/%s", rootfs, pivotdir);
938 if (rc >= sizeof(path)) {
939 ERROR("pivot dir name too long");
940 return -1;
941 }
cc6f6dd7
DL
942
943 if (access(path, F_OK)) {
944
945 if (mkdir_p(path, 0755)) {
946 SYSERROR("failed to create pivotdir '%s'", path);
947 return -1;
948 }
949
950 remove_pivotdir = 1;
951 DEBUG("created '%s' directory", path);
952 }
953
954 DEBUG("mountpoint for old rootfs is '%s'", path);
955
956 /* pivot_root into our new root fs */
957 if (pivot_root(".", path)) {
958 SYSERROR("pivot_root syscall failed");
bf601689
MH
959 return -1;
960 }
cc6f6dd7
DL
961
962 if (chdir("/")) {
963 SYSERROR("can't chdir to / after pivot_root");
964 return -1;
965 }
966
967 DEBUG("pivot_root syscall to '%s' successful", rootfs);
968
969 /* we switch from absolute path to relative path */
970 if (umount_oldrootfs(pivotdir))
971 return -1;
bf601689 972
c08556c6
DL
973 /* remove temporary mount point, we don't consider the removing
974 * as fatal */
a91d897a
FW
975 if (remove_pivotdir && rmdir(pivotdir))
976 WARN("can't remove mountpoint '%s': %m", pivotdir);
bf601689 977
bf601689
MH
978 return 0;
979}
980
91c3830e
SH
981/*
982 * Do we want to add options for max size of /dev and a file to
983 * specify which devices to create?
984 */
985static int mount_autodev(char *root)
986{
987 int ret;
988 char path[MAXPATHLEN];
989
990 INFO("Mounting /dev under %s\n", root);
991 ret = snprintf(path, MAXPATHLEN, "%s/dev", root);
992 if (ret < 0 || ret > MAXPATHLEN)
993 return -1;
994 ret = mount("none", path, "tmpfs", 0, "size=100000");
995 if (ret) {
996 SYSERROR("Failed to mount /dev at %s\n", root);
997 return -1;
998 }
999 ret = snprintf(path, MAXPATHLEN, "%s/dev/pts", root);
1000 if (ret < 0 || ret >= MAXPATHLEN)
1001 return -1;
1002 ret = mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
1003 if (ret) {
1004 SYSERROR("Failed to create /dev/pts in container");
1005 return -1;
1006 }
1007
1008 INFO("Mounted /dev under %s\n", root);
1009 return 0;
1010}
1011
c6883f38
SH
1012struct lxc_devs {
1013 char *name;
1014 mode_t mode;
1015 int maj;
1016 int min;
1017};
1018
1019struct lxc_devs lxc_devs[] = {
1020 { "null", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 3 },
1021 { "zero", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 5 },
1022 { "full", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 7 },
1023 { "urandom", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 9 },
1024 { "random", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 1, 8 },
1025 { "tty", S_IFCHR | S_IRWXU | S_IRWXG | S_IRWXO, 5, 0 },
1026 { "console", S_IFCHR | S_IRUSR | S_IWUSR, 5, 1 },
1027};
1028
c6883f38
SH
1029static int setup_autodev(char *root)
1030{
1031 int ret;
1032 struct lxc_devs *d;
1033 char path[MAXPATHLEN];
1034 int i;
3a32201c 1035 mode_t cmask;
c6883f38 1036
91c3830e
SH
1037 INFO("Creating initial consoles under %s/dev\n", root);
1038
c6883f38 1039 ret = snprintf(path, MAXPATHLEN, "%s/dev", root);
91c3830e
SH
1040 if (ret < 0 || ret >= MAXPATHLEN) {
1041 ERROR("Error calculating container /dev location");
c6883f38 1042 return -1;
f7bee6c6 1043 }
91c3830e
SH
1044
1045 INFO("Populating /dev under %s\n", root);
3a32201c 1046 cmask = umask(S_IXUSR | S_IXGRP | S_IXOTH);
c6883f38
SH
1047 for (i = 0; i < sizeof(lxc_devs) / sizeof(lxc_devs[0]); i++) {
1048 d = &lxc_devs[i];
1049 ret = snprintf(path, MAXPATHLEN, "%s/dev/%s", root, d->name);
1050 if (ret < 0 || ret >= MAXPATHLEN)
1051 return -1;
1052 ret = mknod(path, d->mode, makedev(d->maj, d->min));
91c3830e 1053 if (ret && errno != EEXIST) {
c6883f38
SH
1054 SYSERROR("Error creating %s\n", d->name);
1055 return -1;
1056 }
1057 }
3a32201c 1058 umask(cmask);
c6883f38
SH
1059
1060 INFO("Populated /dev under %s\n", root);
1061 return 0;
1062}
1063
cc28d0b0
SH
1064/*
1065 * Detect whether / is mounted MS_SHARED. The only way I know of to
1066 * check that is through /proc/self/mountinfo.
1067 * I'm only checking for /. If the container rootfs or mount location
1068 * is MS_SHARED, but not '/', then you're out of luck - figuring that
1069 * out would be too much work to be worth it.
1070 */
1071#define LINELEN 4096
1072int detect_shared_rootfs(void)
1073{
1074 char buf[LINELEN], *p;
1075 FILE *f;
1076 int i;
1077 char *p2;
1078
1079 f = fopen("/proc/self/mountinfo", "r");
1080 if (!f)
1081 return 0;
1082 while ((p = fgets(buf, LINELEN, f))) {
1083 INFO("looking at .%s.", p);
1084 for (p = buf, i=0; p && i < 4; i++)
1085 p = index(p+1, ' ');
1086 if (!p)
1087 continue;
1088 p2 = index(p+1, ' ');
1089 if (!p2)
1090 continue;
1091 *p2 = '\0';
1092 INFO("now p is .%s.", p);
1093 if (strcmp(p+1, "/") == 0) {
1094 // this is '/'. is it shared?
1095 p = index(p2+1, ' ');
ab81cef0 1096 if (p && strstr(p, "shared:")) {
00b6be44 1097 fclose(f);
cc28d0b0 1098 return 1;
00b6be44 1099 }
cc28d0b0
SH
1100 }
1101 }
1102 fclose(f);
1103 return 0;
1104}
1105
1106/*
1107 * I'll forgive you for asking whether all of this is needed :) The
1108 * answer is yes.
1109 * pivot_root will fail if the new root, the put_old dir, or the parent
1110 * of current->fs->root are MS_SHARED. (parent of current->fs_root may
1111 * or may not be current->fs_root - if we assumed it always was, we could
1112 * just mount --make-rslave /). So,
1113 * 1. mount a tiny tmpfs to be parent of current->fs->root.
1114 * 2. make that MS_SLAVE
1115 * 3. make a 'root' directory under that
1116 * 4. mount --rbind / under the $tinyroot/root.
1117 * 5. make that rslave
1118 * 6. chdir and chroot into $tinyroot/root
1119 * 7. $tinyroot will be unmounted by our parent in start.c
1120 */
1121static int chroot_into_slave(struct lxc_conf *conf)
1122{
1123 char path[MAXPATHLEN];
1124 const char *destpath = conf->rootfs.mount;
1125 int ret;
1126
1127 if (mount(destpath, destpath, NULL, MS_BIND, 0)) {
1128 SYSERROR("failed to mount %s bind", destpath);
1129 return -1;
1130 }
1131 if (mount("", destpath, NULL, MS_SLAVE, 0)) {
1132 SYSERROR("failed to make %s slave", destpath);
1133 return -1;
1134 }
1135 if (mount("none", destpath, "tmpfs", 0, "size=10000")) {
1136 SYSERROR("Failed to mount tmpfs / at %s", destpath);
1137 return -1;
1138 }
1139 ret = snprintf(path, MAXPATHLEN, "%s/root", destpath);
1140 if (ret < 0 || ret >= MAXPATHLEN) {
1141 ERROR("out of memory making root path");
1142 return -1;
1143 }
1144 if (mkdir(path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) {
1145 SYSERROR("Failed to create /dev/pts in container");
1146 return -1;
1147 }
1148 if (mount("/", path, NULL, MS_BIND|MS_REC, 0)) {
1149 SYSERROR("Failed to rbind mount / to %s", path);
1150 return -1;
1151 }
1152 if (mount("", destpath, NULL, MS_SLAVE|MS_REC, 0)) {
1153 SYSERROR("Failed to make tmp-/ at %s rslave", path);
1154 return -1;
1155 }
1156 if (chdir(path)) {
1157 SYSERROR("Failed to chdir into tmp-/");
1158 return -1;
1159 }
1160 if (chroot(path)) {
1161 SYSERROR("Failed to chroot into tmp-/");
1162 return -1;
1163 }
1164 INFO("Chrooted into tmp-/ at %s\n", path);
1165 return 0;
1166}
1167
1168static int setup_rootfs(struct lxc_conf *conf)
0ad19a3f 1169{
cc28d0b0
SH
1170 const struct lxc_rootfs *rootfs = &conf->rootfs;
1171
a0f379bf
DW
1172 if (!rootfs->path) {
1173 if (mount("", "/", NULL, MS_SLAVE|MS_REC, 0)) {
1174 SYSERROR("Failed to make / rslave");
1175 return -1;
1176 }
c69bd12f 1177 return 0;
a0f379bf 1178 }
0ad19a3f 1179
12297168 1180 if (access(rootfs->mount, F_OK)) {
b1789442 1181 SYSERROR("failed to access to '%s', check it is present",
12297168 1182 rootfs->mount);
b1789442
DL
1183 return -1;
1184 }
1185
cc28d0b0
SH
1186 if (detect_shared_rootfs()) {
1187 if (chroot_into_slave(conf)) {
1188 ERROR("Failed to chroot into slave /");
1189 return -1;
1190 }
1191 }
1192
9be53773
SH
1193 // First try mounting rootfs using a bdev
1194 struct bdev *bdev = bdev_init(rootfs->path, rootfs->mount, NULL);
1195 if (bdev && bdev->ops->mount(bdev) == 0) {
1196 DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
1197 return 0;
1198 }
2656d231 1199 if (mount_rootfs(rootfs->path, rootfs->mount)) {
a6afdde9 1200 ERROR("failed to mount rootfs");
c3f0a28c 1201 return -1;
1202 }
0ad19a3f 1203
12297168 1204 DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
c69bd12f 1205
ac778708
DL
1206 return 0;
1207}
1208
1209int setup_pivot_root(const struct lxc_rootfs *rootfs)
1210{
ac778708
DL
1211 if (!rootfs->path)
1212 return 0;
1213
12297168 1214 if (setup_rootfs_pivot_root(rootfs->mount, rootfs->pivot)) {
cc6f6dd7 1215 ERROR("failed to setup pivot root");
25368b52 1216 return -1;
c69bd12f
DL
1217 }
1218
25368b52 1219 return 0;
0ad19a3f 1220}
1221
d852c78c 1222static int setup_pts(int pts)
3c26f34e 1223{
77890c6d
SW
1224 char target[PATH_MAX];
1225
d852c78c
DL
1226 if (!pts)
1227 return 0;
3c26f34e 1228
1229 if (!access("/dev/pts/ptmx", F_OK) && umount("/dev/pts")) {
36eb9bde 1230 SYSERROR("failed to umount 'dev/pts'");
3c26f34e 1231 return -1;
1232 }
1233
a6afdde9
DL
1234 if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,
1235 "newinstance,ptmxmode=0666")) {
36eb9bde 1236 SYSERROR("failed to mount a new instance of '/dev/pts'");
3c26f34e 1237 return -1;
1238 }
1239
3c26f34e 1240 if (access("/dev/ptmx", F_OK)) {
1241 if (!symlink("/dev/pts/ptmx", "/dev/ptmx"))
1242 goto out;
36eb9bde 1243 SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'");
3c26f34e 1244 return -1;
1245 }
1246
77890c6d
SW
1247 if (realpath("/dev/ptmx", target) && !strcmp(target, "/dev/pts/ptmx"))
1248 goto out;
1249
3c26f34e 1250 /* fallback here, /dev/pts/ptmx exists just mount bind */
1251 if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) {
36eb9bde 1252 SYSERROR("mount failed '/dev/pts/ptmx'->'/dev/ptmx'");
3c26f34e 1253 return -1;
1254 }
cd54d859
DL
1255
1256 INFO("created new pts instance");
d852c78c 1257
3c26f34e 1258out:
1259 return 0;
1260}
1261
cccc74b5
DL
1262static int setup_personality(int persona)
1263{
6ff05e18 1264 #if HAVE_SYS_PERSONALITY_H
cccc74b5
DL
1265 if (persona == -1)
1266 return 0;
1267
1268 if (personality(persona) < 0) {
1269 SYSERROR("failed to set personality to '0x%x'", persona);
1270 return -1;
1271 }
1272
1273 INFO("set personality to '0x%x'", persona);
6ff05e18 1274 #endif
cccc74b5
DL
1275
1276 return 0;
1277}
1278
7c6ef2a2 1279static int setup_dev_console(const struct lxc_rootfs *rootfs,
33fcb7a0 1280 const struct lxc_console *console)
6e590161 1281{
63376d7d
DL
1282 char path[MAXPATHLEN];
1283 struct stat s;
7c6ef2a2 1284 int ret;
52e35957 1285
7c6ef2a2
SH
1286 ret = snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
1287 if (ret >= sizeof(path)) {
1288 ERROR("console path too long\n");
1289 return -1;
1290 }
52e35957 1291
63376d7d 1292 if (access(path, F_OK)) {
466978b0 1293 WARN("rootfs specified but no console found at '%s'", path);
63376d7d 1294 return 0;
52e35957
DL
1295 }
1296
b5159817
DE
1297 if (console->master < 0) {
1298 INFO("no console");
f78a1f32
DL
1299 return 0;
1300 }
ed502555 1301
63376d7d
DL
1302 if (stat(path, &s)) {
1303 SYSERROR("failed to stat '%s'", path);
1304 return -1;
1305 }
1306
1307 if (chmod(console->name, s.st_mode)) {
1308 SYSERROR("failed to set mode '0%o' to '%s'",
1309 s.st_mode, console->name);
1310 return -1;
1311 }
13954cce 1312
63376d7d
DL
1313 if (mount(console->name, path, "none", MS_BIND, 0)) {
1314 ERROR("failed to mount '%s' on '%s'", console->name, path);
6e590161 1315 return -1;
1316 }
1317
63376d7d 1318 INFO("console has been setup");
7c6ef2a2
SH
1319 return 0;
1320}
1321
1322static int setup_ttydir_console(const struct lxc_rootfs *rootfs,
1323 const struct lxc_console *console,
1324 char *ttydir)
1325{
1326 char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
1327 int ret;
1328
1329 /* create rootfs/dev/<ttydir> directory */
1330 ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->mount,
1331 ttydir);
1332 if (ret >= sizeof(path))
1333 return -1;
1334 ret = mkdir(path, 0755);
1335 if (ret && errno != EEXIST) {
1336 SYSERROR("failed with errno %d to create %s\n", errno, path);
1337 return -1;
1338 }
1339 INFO("created %s\n", path);
1340
1341 ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/console",
1342 rootfs->mount, ttydir);
1343 if (ret >= sizeof(lxcpath)) {
1344 ERROR("console path too long\n");
1345 return -1;
1346 }
1347
1348 snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
1349 ret = unlink(path);
1350 if (ret && errno != ENOENT) {
1351 SYSERROR("error unlinking %s\n", path);
1352 return -1;
1353 }
1354
1355 ret = creat(lxcpath, 0660);
1356 if (ret==-1 && errno != EEXIST) {
1357 SYSERROR("error %d creating %s\n", errno, lxcpath);
1358 return -1;
1359 }
4d44e274
SH
1360 if (ret >= 0)
1361 close(ret);
7c6ef2a2 1362
b5159817
DE
1363 if (console->master < 0) {
1364 INFO("no console");
7c6ef2a2
SH
1365 return 0;
1366 }
1367
1368 if (mount(console->name, lxcpath, "none", MS_BIND, 0)) {
1369 ERROR("failed to mount '%s' on '%s'", console->name, lxcpath);
1370 return -1;
1371 }
1372
1373 /* create symlink from rootfs/dev/console to 'lxc/console' */
9ba8130c
SH
1374 ret = snprintf(lxcpath, sizeof(lxcpath), "%s/console", ttydir);
1375 if (ret >= sizeof(lxcpath)) {
1376 ERROR("lxc/console path too long");
1377 return -1;
1378 }
7c6ef2a2
SH
1379 ret = symlink(lxcpath, path);
1380 if (ret) {
1381 SYSERROR("failed to create symlink for console");
1382 return -1;
1383 }
1384
1385 INFO("console has been setup on %s", lxcpath);
cd54d859 1386
6e590161 1387 return 0;
1388}
1389
7c6ef2a2
SH
1390static int setup_console(const struct lxc_rootfs *rootfs,
1391 const struct lxc_console *console,
1392 char *ttydir)
1393{
1394 /* We don't have a rootfs, /dev/console will be shared */
1395 if (!rootfs->path)
1396 return 0;
1397 if (!ttydir)
1398 return setup_dev_console(rootfs, console);
1399
1400 return setup_ttydir_console(rootfs, console, ttydir);
1401}
1402
1bd051a6
SH
1403static int setup_kmsg(const struct lxc_rootfs *rootfs,
1404 const struct lxc_console *console)
1405{
1406 char kpath[MAXPATHLEN];
1407 int ret;
1408
222fea5a
DE
1409 if (!rootfs->path)
1410 return 0;
1bd051a6
SH
1411 ret = snprintf(kpath, sizeof(kpath), "%s/dev/kmsg", rootfs->mount);
1412 if (ret < 0 || ret >= sizeof(kpath))
1413 return -1;
1414
1415 ret = unlink(kpath);
1416 if (ret && errno != ENOENT) {
1417 SYSERROR("error unlinking %s\n", kpath);
1418 return -1;
1419 }
1420
1421 ret = symlink("console", kpath);
1422 if (ret) {
1423 SYSERROR("failed to create symlink for kmsg");
1424 return -1;
1425 }
1426
1427 return 0;
1428}
1429
6031a6e5
DE
1430static int _setup_cgroup(const char *cgpath, struct lxc_list *cgroups,
1431 int devices)
576f946d 1432{
102a5303
DL
1433 struct lxc_list *iterator;
1434 struct lxc_cgroup *cg;
88329c69 1435 int ret = -1;
6f4a3756 1436
102a5303
DL
1437 if (lxc_list_empty(cgroups))
1438 return 0;
6f4a3756 1439
102a5303 1440 lxc_list_for_each(iterator, cgroups) {
102a5303 1441 cg = iterator->elem;
6f4a3756 1442
6031a6e5
DE
1443 if (devices == !strncmp("devices", cg->subsystem, 7)) {
1444 if (lxc_cgroup_set_bypath(cgpath, cg->subsystem,
1445 cg->value)) {
1446 ERROR("Error setting %s to %s for %s\n",
1447 cg->subsystem, cg->value, cgpath);
1448 goto out;
1449 }
ae5c8b8e 1450 }
6f4a3756 1451
102a5303 1452 DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
6f4a3756 1453 }
13954cce 1454
88329c69 1455 ret = 0;
cd54d859 1456 INFO("cgroup has been setup");
88329c69
MN
1457out:
1458 return ret;
576f946d 1459}
1460
6031a6e5
DE
1461int setup_cgroup_devices(const char *cgpath, struct lxc_list *cgroups)
1462{
1463 return _setup_cgroup(cgpath, cgroups, 1);
1464}
1465
1466int setup_cgroup(const char *cgpath, struct lxc_list *cgroups)
1467{
1468 return _setup_cgroup(cgpath, cgroups, 0);
1469}
1470
998ac676
RT
1471static void parse_mntopt(char *opt, unsigned long *flags, char **data)
1472{
1473 struct mount_opt *mo;
1474
1475 /* If opt is found in mount_opt, set or clear flags.
1476 * Otherwise append it to data. */
1477
1478 for (mo = &mount_opt[0]; mo->name != NULL; mo++) {
1479 if (!strncmp(opt, mo->name, strlen(mo->name))) {
1480 if (mo->clear)
1481 *flags &= ~mo->flag;
1482 else
1483 *flags |= mo->flag;
1484 return;
1485 }
1486 }
1487
1488 if (strlen(*data))
1489 strcat(*data, ",");
1490 strcat(*data, opt);
1491}
1492
911324ef 1493static int parse_mntopts(const char *mntopts, unsigned long *mntflags,
998ac676
RT
1494 char **mntdata)
1495{
1496 char *s, *data;
1497 char *p, *saveptr = NULL;
1498
911324ef 1499 *mntdata = NULL;
91656ce5 1500 *mntflags = 0L;
911324ef
DL
1501
1502 if (!mntopts)
998ac676
RT
1503 return 0;
1504
911324ef 1505 s = strdup(mntopts);
998ac676 1506 if (!s) {
36eb9bde 1507 SYSERROR("failed to allocate memory");
998ac676
RT
1508 return -1;
1509 }
1510
1511 data = malloc(strlen(s) + 1);
1512 if (!data) {
36eb9bde 1513 SYSERROR("failed to allocate memory");
998ac676
RT
1514 free(s);
1515 return -1;
1516 }
1517 *data = 0;
1518
1519 for (p = strtok_r(s, ",", &saveptr); p != NULL;
1520 p = strtok_r(NULL, ",", &saveptr))
1521 parse_mntopt(p, mntflags, &data);
1522
1523 if (*data)
1524 *mntdata = data;
1525 else
1526 free(data);
1527 free(s);
1528
1529 return 0;
1530}
1531
911324ef
DL
1532static int mount_entry(const char *fsname, const char *target,
1533 const char *fstype, unsigned long mountflags,
1534 const char *data)
1535{
1536 if (mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data)) {
1537 SYSERROR("failed to mount '%s' on '%s'", fsname, target);
1538 return -1;
1539 }
1540
1541 if ((mountflags & MS_REMOUNT) || (mountflags & MS_BIND)) {
1542
1543 DEBUG("remounting %s on %s to respect bind or remount options",
1544 fsname, target);
1545
1546 if (mount(fsname, target, fstype,
1547 mountflags | MS_REMOUNT, data)) {
1548 SYSERROR("failed to mount '%s' on '%s'",
1549 fsname, target);
1550 return -1;
1551 }
1552 }
1553
1554 DEBUG("mounted '%s' on '%s', type '%s'", fsname, target, fstype);
1555
1556 return 0;
1557}
1558
1559static inline int mount_entry_on_systemfs(struct mntent *mntent)
0ad19a3f 1560{
998ac676
RT
1561 unsigned long mntflags;
1562 char *mntdata;
911324ef
DL
1563 int ret;
1564
1565 if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
1566 ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
1567 return -1;
1568 }
1569
1570 ret = mount_entry(mntent->mnt_fsname, mntent->mnt_dir,
1571 mntent->mnt_type, mntflags, mntdata);
1572
68c152ef
SH
1573 if (hasmntopt(mntent, "optional") != NULL)
1574 ret = 0;
1575
911324ef
DL
1576 free(mntdata);
1577
1578 return ret;
1579}
1580
1581static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
80a881b2
SH
1582 const struct lxc_rootfs *rootfs,
1583 const char *lxc_name)
911324ef 1584{
013bd428 1585 char *aux;
59760f5d 1586 char path[MAXPATHLEN];
911324ef
DL
1587 unsigned long mntflags;
1588 char *mntdata;
80a881b2 1589 int r, ret = 0, offset;
67e571de 1590 const char *lxcpath;
0ad19a3f 1591
911324ef
DL
1592 if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
1593 ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
1594 return -1;
1595 }
1bc60a65 1596
2a59a681
SH
1597 lxcpath = default_lxc_path();
1598 if (!lxcpath) {
1599 ERROR("Out of memory");
1600 return -1;
1601 }
1602
80a881b2 1603 /* if rootfs->path is a blockdev path, allow container fstab to
2a59a681
SH
1604 * use $lxcpath/CN/rootfs as the target prefix */
1605 r = snprintf(path, MAXPATHLEN, "%s/%s/rootfs", lxcpath, lxc_name);
80a881b2
SH
1606 if (r < 0 || r >= MAXPATHLEN)
1607 goto skipvarlib;
1608
1609 aux = strstr(mntent->mnt_dir, path);
1610 if (aux) {
1611 offset = strlen(path);
1612 goto skipabs;
1613 }
1614
1615skipvarlib:
013bd428
DL
1616 aux = strstr(mntent->mnt_dir, rootfs->path);
1617 if (!aux) {
1618 WARN("ignoring mount point '%s'", mntent->mnt_dir);
1619 goto out;
1620 }
80a881b2
SH
1621 offset = strlen(rootfs->path);
1622
1623skipabs:
013bd428 1624
9ba8130c 1625 r = snprintf(path, MAXPATHLEN, "%s/%s", rootfs->mount,
80a881b2
SH
1626 aux + offset);
1627 if (r < 0 || r >= MAXPATHLEN) {
1628 WARN("pathnme too long for '%s'", mntent->mnt_dir);
1629 ret = -1;
1630 goto out;
1631 }
1632
d330fe7b 1633
013bd428 1634 ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
911324ef 1635 mntflags, mntdata);
0ad19a3f 1636
68c152ef
SH
1637 if (hasmntopt(mntent, "optional") != NULL)
1638 ret = 0;
1639
013bd428 1640out:
911324ef
DL
1641 free(mntdata);
1642 return ret;
1643}
d330fe7b 1644
911324ef
DL
1645static int mount_entry_on_relative_rootfs(struct mntent *mntent,
1646 const char *rootfs)
1647{
1648 char path[MAXPATHLEN];
1649 unsigned long mntflags;
1650 char *mntdata;
1651 int ret;
d330fe7b 1652
911324ef
DL
1653 if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
1654 ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
1655 return -1;
1656 }
d330fe7b 1657
911324ef 1658 /* relative to root mount point */
9ba8130c
SH
1659 ret = snprintf(path, sizeof(path), "%s/%s", rootfs, mntent->mnt_dir);
1660 if (ret >= sizeof(path)) {
1661 ERROR("path name too long");
1662 return -1;
1663 }
911324ef
DL
1664
1665 ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
1666 mntflags, mntdata);
1667
68c152ef
SH
1668 if (hasmntopt(mntent, "optional") != NULL)
1669 ret = 0;
1670
911324ef 1671 free(mntdata);
998ac676 1672
911324ef
DL
1673 return ret;
1674}
1675
80a881b2
SH
1676static int mount_file_entries(const struct lxc_rootfs *rootfs, FILE *file,
1677 const char *lxc_name)
911324ef
DL
1678{
1679 struct mntent *mntent;
1680 int ret = -1;
e76b8764 1681
911324ef 1682 while ((mntent = getmntent(file))) {
e76b8764 1683
911324ef
DL
1684 if (!rootfs->path) {
1685 if (mount_entry_on_systemfs(mntent))
e76b8764 1686 goto out;
911324ef 1687 continue;
e76b8764
CDC
1688 }
1689
911324ef
DL
1690 /* We have a separate root, mounts are relative to it */
1691 if (mntent->mnt_dir[0] != '/') {
1692 if (mount_entry_on_relative_rootfs(mntent,
1693 rootfs->mount))
1694 goto out;
1695 continue;
1696 }
cd54d859 1697
80a881b2 1698 if (mount_entry_on_absolute_rootfs(mntent, rootfs, lxc_name))
911324ef 1699 goto out;
0ad19a3f 1700 }
cd54d859 1701
0ad19a3f 1702 ret = 0;
cd54d859
DL
1703
1704 INFO("mount points have been setup");
0ad19a3f 1705out:
e7938e9e
MN
1706 return ret;
1707}
1708
80a881b2
SH
1709static int setup_mount(const struct lxc_rootfs *rootfs, const char *fstab,
1710 const char *lxc_name)
e7938e9e
MN
1711{
1712 FILE *file;
1713 int ret;
1714
1715 if (!fstab)
1716 return 0;
1717
1718 file = setmntent(fstab, "r");
1719 if (!file) {
1720 SYSERROR("failed to use '%s'", fstab);
1721 return -1;
1722 }
1723
80a881b2 1724 ret = mount_file_entries(rootfs, file, lxc_name);
e7938e9e 1725
0ad19a3f 1726 endmntent(file);
1727 return ret;
1728}
1729
80a881b2
SH
1730static int setup_mount_entries(const struct lxc_rootfs *rootfs, struct lxc_list *mount,
1731 const char *lxc_name)
e7938e9e
MN
1732{
1733 FILE *file;
1734 struct lxc_list *iterator;
1735 char *mount_entry;
1736 int ret;
1737
1738 file = tmpfile();
1739 if (!file) {
1740 ERROR("tmpfile error: %m");
1741 return -1;
1742 }
1743
1744 lxc_list_for_each(iterator, mount) {
1745 mount_entry = iterator->elem;
1d6b1976 1746 fprintf(file, "%s\n", mount_entry);
e7938e9e
MN
1747 }
1748
1749 rewind(file);
1750
80a881b2 1751 ret = mount_file_entries(rootfs, file, lxc_name);
e7938e9e
MN
1752
1753 fclose(file);
1754 return ret;
1755}
1756
81810dd1
DL
1757static int setup_caps(struct lxc_list *caps)
1758{
1759 struct lxc_list *iterator;
1760 char *drop_entry;
d55bc1ad 1761 char *ptr;
81810dd1
DL
1762 int i, capid;
1763
1764 lxc_list_for_each(iterator, caps) {
1765
1766 drop_entry = iterator->elem;
1767
1768 capid = -1;
1769
1770 for (i = 0; i < sizeof(caps_opt)/sizeof(caps_opt[0]); i++) {
1771
1772 if (strcmp(drop_entry, caps_opt[i].name))
1773 continue;
1774
1775 capid = caps_opt[i].value;
1776 break;
1777 }
1778
d55bc1ad
CS
1779 if (capid < 0) {
1780 /* try to see if it's numeric, so the user may specify
1781 * capabilities that the running kernel knows about but
1782 * we don't */
1783 capid = strtol(drop_entry, &ptr, 10);
1784 if (!ptr || *ptr != '\0' ||
1785 capid == LONG_MIN || capid == LONG_MAX)
1786 /* not a valid number */
1787 capid = -1;
1788 else if (capid > lxc_caps_last_cap())
1789 /* we have a number but it's not a valid
1790 * capability */
1791 capid = -1;
1792 }
1793
81810dd1 1794 if (capid < 0) {
1e11be34
DL
1795 ERROR("unknown capability %s", drop_entry);
1796 return -1;
81810dd1
DL
1797 }
1798
1799 DEBUG("drop capability '%s' (%d)", drop_entry, capid);
1800
1801 if (prctl(PR_CAPBSET_DROP, capid, 0, 0, 0)) {
1802 SYSERROR("failed to remove %s capability", drop_entry);
1803 return -1;
1804 }
1805
1806 }
1807
1808 DEBUG("capabilities has been setup");
1809
1810 return 0;
1811}
1812
0ad19a3f 1813static int setup_hw_addr(char *hwaddr, const char *ifname)
1814{
1815 struct sockaddr sockaddr;
1816 struct ifreq ifr;
1817 int ret, fd;
1818
3cfc0f3a
MN
1819 ret = lxc_convert_mac(hwaddr, &sockaddr);
1820 if (ret) {
1821 ERROR("mac address '%s' conversion failed : %s",
1822 hwaddr, strerror(-ret));
0ad19a3f 1823 return -1;
1824 }
1825
1826 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
1827 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
1828
1829 fd = socket(AF_INET, SOCK_DGRAM, 0);
1830 if (fd < 0) {
3ab87b66 1831 ERROR("socket failure : %s", strerror(errno));
0ad19a3f 1832 return -1;
1833 }
1834
1835 ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
1836 close(fd);
1837 if (ret)
3ab87b66 1838 ERROR("ioctl failure : %s", strerror(errno));
0ad19a3f 1839
cd54d859
DL
1840 DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifname);
1841
0ad19a3f 1842 return ret;
1843}
1844
82d5ae15 1845static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
0ad19a3f 1846{
82d5ae15
DL
1847 struct lxc_list *iterator;
1848 struct lxc_inetdev *inetdev;
3cfc0f3a 1849 int err;
0ad19a3f 1850
82d5ae15
DL
1851 lxc_list_for_each(iterator, ip) {
1852
1853 inetdev = iterator->elem;
1854
0093bb8c
DL
1855 err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
1856 &inetdev->bcast, inetdev->prefix);
3cfc0f3a
MN
1857 if (err) {
1858 ERROR("failed to setup_ipv4_addr ifindex %d : %s",
1859 ifindex, strerror(-err));
82d5ae15
DL
1860 return -1;
1861 }
1862 }
1863
1864 return 0;
0ad19a3f 1865}
1866
82d5ae15 1867static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
0ad19a3f 1868{
82d5ae15 1869 struct lxc_list *iterator;
7fa9074f 1870 struct lxc_inet6dev *inet6dev;
3cfc0f3a 1871 int err;
0ad19a3f 1872
82d5ae15
DL
1873 lxc_list_for_each(iterator, ip) {
1874
1875 inet6dev = iterator->elem;
1876
b3df193c 1877 err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
0093bb8c
DL
1878 &inet6dev->mcast, &inet6dev->acast,
1879 inet6dev->prefix);
3cfc0f3a
MN
1880 if (err) {
1881 ERROR("failed to setup_ipv6_addr ifindex %d : %s",
1882 ifindex, strerror(-err));
82d5ae15 1883 return -1;
3cfc0f3a 1884 }
82d5ae15
DL
1885 }
1886
1887 return 0;
0ad19a3f 1888}
1889
82d5ae15 1890static int setup_netdev(struct lxc_netdev *netdev)
0ad19a3f 1891{
0ad19a3f 1892 char ifname[IFNAMSIZ];
0ad19a3f 1893 char *current_ifname = ifname;
3cfc0f3a 1894 int err;
0ad19a3f 1895
82d5ae15
DL
1896 /* empty network namespace */
1897 if (!netdev->ifindex) {
b0efbac4 1898 if (netdev->flags & IFF_UP) {
d472214b 1899 err = lxc_netdev_up("lo");
3cfc0f3a
MN
1900 if (err) {
1901 ERROR("failed to set the loopback up : %s",
1902 strerror(-err));
82d5ae15
DL
1903 return -1;
1904 }
82d5ae15 1905 }
7b57e8b6 1906 return 0;
0ad19a3f 1907 }
13954cce 1908
82d5ae15
DL
1909 /* retrieve the name of the interface */
1910 if (!if_indextoname(netdev->ifindex, current_ifname)) {
36eb9bde 1911 ERROR("no interface corresponding to index '%d'",
82d5ae15 1912 netdev->ifindex);
0ad19a3f 1913 return -1;
1914 }
13954cce 1915
018ef520 1916 /* default: let the system to choose one interface name */
9d083402 1917 if (!netdev->name)
fb6d9b2f
DL
1918 netdev->name = netdev->type == LXC_NET_PHYS ?
1919 netdev->link : "eth%d";
018ef520 1920
82d5ae15 1921 /* rename the interface name */
b84f58b9 1922 err = lxc_netdev_rename_by_name(ifname, netdev->name);
3cfc0f3a
MN
1923 if (err) {
1924 ERROR("failed to rename %s->%s : %s", ifname, netdev->name,
1925 strerror(-err));
018ef520
DL
1926 return -1;
1927 }
1928
1929 /* Re-read the name of the interface because its name has changed
1930 * and would be automatically allocated by the system
1931 */
82d5ae15 1932 if (!if_indextoname(netdev->ifindex, current_ifname)) {
018ef520 1933 ERROR("no interface corresponding to index '%d'",
82d5ae15 1934 netdev->ifindex);
018ef520 1935 return -1;
0ad19a3f 1936 }
1937
82d5ae15
DL
1938 /* set a mac address */
1939 if (netdev->hwaddr) {
1940 if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
36eb9bde 1941 ERROR("failed to setup hw address for '%s'",
82d5ae15 1942 current_ifname);
0ad19a3f 1943 return -1;
1944 }
1945 }
1946
82d5ae15
DL
1947 /* setup ipv4 addresses on the interface */
1948 if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
36eb9bde 1949 ERROR("failed to setup ip addresses for '%s'",
0ad19a3f 1950 ifname);
1951 return -1;
1952 }
1953
82d5ae15
DL
1954 /* setup ipv6 addresses on the interface */
1955 if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
36eb9bde 1956 ERROR("failed to setup ipv6 addresses for '%s'",
0ad19a3f 1957 ifname);
1958 return -1;
1959 }
1960
82d5ae15 1961 /* set the network device up */
b0efbac4 1962 if (netdev->flags & IFF_UP) {
3cfc0f3a
MN
1963 int err;
1964
d472214b 1965 err = lxc_netdev_up(current_ifname);
3cfc0f3a
MN
1966 if (err) {
1967 ERROR("failed to set '%s' up : %s", current_ifname,
1968 strerror(-err));
0ad19a3f 1969 return -1;
1970 }
1971
1972 /* the network is up, make the loopback up too */
d472214b 1973 err = lxc_netdev_up("lo");
3cfc0f3a
MN
1974 if (err) {
1975 ERROR("failed to set the loopback up : %s",
1976 strerror(-err));
0ad19a3f 1977 return -1;
1978 }
1979 }
1980
f8fee0e2
MK
1981 /* We can only set up the default routes after bringing
1982 * up the interface, sine bringing up the interface adds
1983 * the link-local routes and we can't add a default
1984 * route if the gateway is not reachable. */
1985
1986 /* setup ipv4 gateway on the interface */
1987 if (netdev->ipv4_gateway) {
1988 if (!(netdev->flags & IFF_UP)) {
1989 ERROR("Cannot add ipv4 gateway for %s when not bringing up the interface", ifname);
1990 return -1;
1991 }
1992
1993 if (lxc_list_empty(&netdev->ipv4)) {
1994 ERROR("Cannot add ipv4 gateway for %s when not assigning an address", ifname);
1995 return -1;
1996 }
1997
1998 err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway);
1999 if (err) {
2000 ERROR("failed to setup ipv4 gateway for '%s': %s",
2001 ifname, strerror(-err));
19a26f82
MK
2002 if (netdev->ipv4_gateway_auto) {
2003 char buf[INET_ADDRSTRLEN];
2004 inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf));
2005 ERROR("tried to set autodetected ipv4 gateway '%s'", buf);
2006 }
f8fee0e2
MK
2007 return -1;
2008 }
2009 }
2010
2011 /* setup ipv6 gateway on the interface */
2012 if (netdev->ipv6_gateway) {
2013 if (!(netdev->flags & IFF_UP)) {
2014 ERROR("Cannot add ipv6 gateway for %s when not bringing up the interface", ifname);
2015 return -1;
2016 }
2017
2018 if (lxc_list_empty(&netdev->ipv6) && !IN6_IS_ADDR_LINKLOCAL(netdev->ipv6_gateway)) {
2019 ERROR("Cannot add ipv6 gateway for %s when not assigning an address", ifname);
2020 return -1;
2021 }
2022
2023 err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway);
2024 if (err) {
2025 ERROR("failed to setup ipv6 gateway for '%s': %s",
2026 ifname, strerror(-err));
19a26f82
MK
2027 if (netdev->ipv6_gateway_auto) {
2028 char buf[INET6_ADDRSTRLEN];
72d0e1cb 2029 inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf));
19a26f82
MK
2030 ERROR("tried to set autodetected ipv6 gateway '%s'", buf);
2031 }
f8fee0e2
MK
2032 return -1;
2033 }
2034 }
2035
cd54d859
DL
2036 DEBUG("'%s' has been setup", current_ifname);
2037
0ad19a3f 2038 return 0;
2039}
2040
5f4535a3 2041static int setup_network(struct lxc_list *network)
0ad19a3f 2042{
82d5ae15 2043 struct lxc_list *iterator;
82d5ae15 2044 struct lxc_netdev *netdev;
0ad19a3f 2045
5f4535a3 2046 lxc_list_for_each(iterator, network) {
cd54d859 2047
5f4535a3 2048 netdev = iterator->elem;
82d5ae15
DL
2049
2050 if (setup_netdev(netdev)) {
2051 ERROR("failed to setup netdev");
2052 return -1;
2053 }
2054 }
cd54d859 2055
5f4535a3
DL
2056 if (!lxc_list_empty(network))
2057 INFO("network has been setup");
cd54d859
DL
2058
2059 return 0;
0ad19a3f 2060}
2061
7b35f3d6
SH
2062void lxc_rename_phys_nics_on_shutdown(struct lxc_conf *conf)
2063{
2064 int i;
2065
2066 INFO("running to reset %d nic names", conf->num_savednics);
2067 for (i=0; i<conf->num_savednics; i++) {
2068 struct saved_nic *s = &conf->saved_nics[i];
2069 INFO("resetting nic %d to %s\n", s->ifindex, s->orig_name);
2070 lxc_netdev_rename_by_index(s->ifindex, s->orig_name);
2071 free(s->orig_name);
2072 }
2073 conf->num_savednics = 0;
2074 free(conf->saved_nics);
2075}
2076
49684c0b
CS
2077static int setup_private_host_hw_addr(char *veth1)
2078{
2079 struct ifreq ifr;
2080 int err;
2081 int sockfd;
2082
2083 sockfd = socket(AF_INET, SOCK_DGRAM, 0);
2084 if (sockfd < 0)
2085 return -errno;
2086
2087 snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1);
2088 err = ioctl(sockfd, SIOCGIFHWADDR, &ifr);
2089 if (err < 0) {
2090 close(sockfd);
2091 return -errno;
2092 }
2093
2094 ifr.ifr_hwaddr.sa_data[0] = 0xfe;
2095 err = ioctl(sockfd, SIOCSIFHWADDR, &ifr);
2096 close(sockfd);
2097 if (err < 0)
2098 return -errno;
2099
7ad84da7
DL
2100 DEBUG("mac address of host interface '%s' changed to private "
2101 "%02x:%02x:%02x:%02x:%02x:%02x", veth1,
2102 ifr.ifr_hwaddr.sa_data[0] & 0xff,
2103 ifr.ifr_hwaddr.sa_data[1] & 0xff,
2104 ifr.ifr_hwaddr.sa_data[2] & 0xff,
2105 ifr.ifr_hwaddr.sa_data[3] & 0xff,
2106 ifr.ifr_hwaddr.sa_data[4] & 0xff,
2107 ifr.ifr_hwaddr.sa_data[5] & 0xff);
49684c0b
CS
2108
2109 return 0;
2110}
2111
ae9242c8
SH
2112static char *default_rootfs_mount = LXCROOTFSMOUNT;
2113
7b379ab3 2114struct lxc_conf *lxc_conf_init(void)
089cd8b8 2115{
7b379ab3 2116 struct lxc_conf *new;
26ddeedd 2117 int i;
7b379ab3
MN
2118
2119 new = malloc(sizeof(*new));
2120 if (!new) {
2121 ERROR("lxc_conf_init : %m");
2122 return NULL;
2123 }
2124 memset(new, 0, sizeof(*new));
2125
cccc74b5 2126 new->personality = -1;
596a818d
DE
2127 new->console.log_path = NULL;
2128 new->console.log_fd = -1;
28a4b0e5 2129 new->console.path = NULL;
63376d7d 2130 new->console.peer = -1;
b5159817
DE
2131 new->console.peerpty.busy = -1;
2132 new->console.peerpty.master = -1;
2133 new->console.peerpty.slave = -1;
63376d7d
DL
2134 new->console.master = -1;
2135 new->console.slave = -1;
2136 new->console.name[0] = '\0';
d2e30e99 2137 new->maincmd_fd = -1;
54c30e29 2138 new->rootfs.mount = strdup(default_rootfs_mount);
53f3f048
SH
2139 if (!new->rootfs.mount) {
2140 ERROR("lxc_conf_init : %m");
2141 free(new);
2142 return NULL;
2143 }
2f3f41d0 2144 new->kmsg = 1;
7b379ab3
MN
2145 lxc_list_init(&new->cgroup);
2146 lxc_list_init(&new->network);
2147 lxc_list_init(&new->mount_list);
81810dd1 2148 lxc_list_init(&new->caps);
f6d3e3e4 2149 lxc_list_init(&new->id_map);
26ddeedd
SH
2150 for (i=0; i<NUM_LXC_HOOKS; i++)
2151 lxc_list_init(&new->hooks[i]);
e075f5d9
SH
2152#if HAVE_APPARMOR
2153 new->aa_profile = NULL;
2154#endif
2155#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
2156 new->lsm_umount_proc = 0;
2157#endif
7b379ab3
MN
2158
2159 return new;
089cd8b8
DL
2160}
2161
e3b4c4c4 2162static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 2163{
8634bc19 2164 char veth1buf[IFNAMSIZ], *veth1;
0e391e57 2165 char veth2buf[IFNAMSIZ], *veth2;
3cfc0f3a 2166 int err;
13954cce 2167
e892973e
DL
2168 if (netdev->priv.veth_attr.pair)
2169 veth1 = netdev->priv.veth_attr.pair;
8634bc19 2170 else {
9ba8130c
SH
2171 err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
2172 if (err >= sizeof(veth1buf)) { /* can't *really* happen, but... */
2173 ERROR("veth1 name too long");
2174 return -1;
2175 }
0e391e57 2176 veth1 = mktemp(veth1buf);
74a2b586
JK
2177 /* store away for deconf */
2178 memcpy(netdev->priv.veth_attr.veth1, veth1, IFNAMSIZ);
8634bc19 2179 }
82d5ae15 2180
0e391e57
DL
2181 snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
2182 veth2 = mktemp(veth2buf);
82d5ae15
DL
2183
2184 if (!strlen(veth1) || !strlen(veth2)) {
2185 ERROR("failed to allocate a temporary name");
2186 return -1;
0ad19a3f 2187 }
2188
3cfc0f3a
MN
2189 err = lxc_veth_create(veth1, veth2);
2190 if (err) {
2191 ERROR("failed to create %s-%s : %s", veth1, veth2,
2192 strerror(-err));
6ab9ab6d 2193 return -1;
0ad19a3f 2194 }
13954cce 2195
49684c0b
CS
2196 /* changing the high byte of the mac address to 0xfe, the bridge interface
2197 * will always keep the host's mac address and not take the mac address
2198 * of a container */
2199 err = setup_private_host_hw_addr(veth1);
2200 if (err) {
2201 ERROR("failed to change mac address of host interface '%s' : %s",
2202 veth1, strerror(-err));
2203 goto out_delete;
2204 }
2205
82d5ae15 2206 if (netdev->mtu) {
d472214b 2207 err = lxc_netdev_set_mtu(veth1, atoi(netdev->mtu));
3cfc0f3a 2208 if (!err)
d472214b 2209 err = lxc_netdev_set_mtu(veth2, atoi(netdev->mtu));
3cfc0f3a
MN
2210 if (err) {
2211 ERROR("failed to set mtu '%s' for %s-%s : %s",
2212 netdev->mtu, veth1, veth2, strerror(-err));
eb14c10a 2213 goto out_delete;
75d09f83
DL
2214 }
2215 }
2216
3cfc0f3a
MN
2217 if (netdev->link) {
2218 err = lxc_bridge_attach(netdev->link, veth1);
2219 if (err) {
2220 ERROR("failed to attach '%s' to the bridge '%s' : %s",
2221 veth1, netdev->link, strerror(-err));
2222 goto out_delete;
2223 }
eb14c10a
DL
2224 }
2225
82d5ae15
DL
2226 netdev->ifindex = if_nametoindex(veth2);
2227 if (!netdev->ifindex) {
36eb9bde 2228 ERROR("failed to retrieve the index for %s", veth2);
eb14c10a
DL
2229 goto out_delete;
2230 }
2231
d472214b 2232 err = lxc_netdev_up(veth1);
6e35af2e
DL
2233 if (err) {
2234 ERROR("failed to set %s up : %s", veth1, strerror(-err));
2235 goto out_delete;
0ad19a3f 2236 }
2237
e3b4c4c4 2238 if (netdev->upscript) {
751d9dcd
DL
2239 err = run_script(handler->name, "net", netdev->upscript, "up",
2240 "veth", veth1, (char*) NULL);
2241 if (err)
e3b4c4c4 2242 goto out_delete;
e3b4c4c4
ST
2243 }
2244
82d5ae15
DL
2245 DEBUG("instanciated veth '%s/%s', index is '%d'",
2246 veth1, veth2, netdev->ifindex);
2247
6ab9ab6d 2248 return 0;
eb14c10a
DL
2249
2250out_delete:
b84f58b9 2251 lxc_netdev_delete_by_name(veth1);
6ab9ab6d 2252 return -1;
13954cce 2253}
d957ae2d 2254
74a2b586
JK
2255static int shutdown_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
2256{
2257 char *veth1;
2258 int err;
2259
2260 if (netdev->priv.veth_attr.pair)
2261 veth1 = netdev->priv.veth_attr.pair;
2262 else
2263 veth1 = netdev->priv.veth_attr.veth1;
2264
2265 if (netdev->downscript) {
2266 err = run_script(handler->name, "net", netdev->downscript,
2267 "down", "veth", veth1, (char*) NULL);
2268 if (err)
2269 return -1;
2270 }
2271 return 0;
2272}
2273
e3b4c4c4 2274static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 2275{
0e391e57 2276 char peerbuf[IFNAMSIZ], *peer;
3cfc0f3a 2277 int err;
d957ae2d
MT
2278
2279 if (!netdev->link) {
2280 ERROR("no link specified for macvlan netdev");
2281 return -1;
2282 }
13954cce 2283
9ba8130c
SH
2284 err = snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
2285 if (err >= sizeof(peerbuf))
2286 return -1;
82d5ae15 2287
0e391e57 2288 peer = mktemp(peerbuf);
82d5ae15
DL
2289 if (!strlen(peer)) {
2290 ERROR("failed to make a temporary name");
2291 return -1;
0ad19a3f 2292 }
2293
3cfc0f3a
MN
2294 err = lxc_macvlan_create(netdev->link, peer,
2295 netdev->priv.macvlan_attr.mode);
2296 if (err) {
2297 ERROR("failed to create macvlan interface '%s' on '%s' : %s",
2298 peer, netdev->link, strerror(-err));
d957ae2d 2299 return -1;
0ad19a3f 2300 }
2301
82d5ae15
DL
2302 netdev->ifindex = if_nametoindex(peer);
2303 if (!netdev->ifindex) {
36eb9bde 2304 ERROR("failed to retrieve the index for %s", peer);
b84f58b9 2305 lxc_netdev_delete_by_name(peer);
d957ae2d 2306 return -1;
22ebac19 2307 }
2308
e3b4c4c4 2309 if (netdev->upscript) {
751d9dcd
DL
2310 err = run_script(handler->name, "net", netdev->upscript, "up",
2311 "macvlan", netdev->link, (char*) NULL);
2312 if (err)
e3b4c4c4 2313 return -1;
e3b4c4c4
ST
2314 }
2315
e892973e
DL
2316 DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'",
2317 peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
0ad19a3f 2318
d957ae2d 2319 return 0;
0ad19a3f 2320}
2321
74a2b586
JK
2322static int shutdown_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
2323{
2324 int err;
2325
2326 if (netdev->downscript) {
2327 err = run_script(handler->name, "net", netdev->downscript,
2328 "down", "macvlan", netdev->link,
2329 (char*) NULL);
2330 if (err)
2331 return -1;
2332 }
2333 return 0;
2334}
2335
26c39028 2336/* XXX: merge with instanciate_macvlan */
e3b4c4c4 2337static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
26c39028
JHS
2338{
2339 char peer[IFNAMSIZ];
3cfc0f3a 2340 int err;
26c39028
JHS
2341
2342 if (!netdev->link) {
2343 ERROR("no link specified for vlan netdev");
2344 return -1;
2345 }
2346
9ba8130c
SH
2347 err = snprintf(peer, sizeof(peer), "vlan%d", netdev->priv.vlan_attr.vid);
2348 if (err >= sizeof(peer)) {
2349 ERROR("peer name too long");
2350 return -1;
2351 }
26c39028 2352
3cfc0f3a
MN
2353 err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
2354 if (err) {
2355 ERROR("failed to create vlan interface '%s' on '%s' : %s",
2356 peer, netdev->link, strerror(-err));
26c39028
JHS
2357 return -1;
2358 }
2359
2360 netdev->ifindex = if_nametoindex(peer);
2361 if (!netdev->ifindex) {
2362 ERROR("failed to retrieve the ifindex for %s", peer);
b84f58b9 2363 lxc_netdev_delete_by_name(peer);
26c39028
JHS
2364 return -1;
2365 }
2366
e892973e
DL
2367 DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000",
2368 netdev->ifindex);
2369
26c39028
JHS
2370 return 0;
2371}
2372
74a2b586
JK
2373static int shutdown_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
2374{
2375 return 0;
2376}
2377
e3b4c4c4 2378static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 2379{
6168e99f
DL
2380 if (!netdev->link) {
2381 ERROR("no link specified for the physical interface");
2382 return -1;
2383 }
2384
9d083402 2385 netdev->ifindex = if_nametoindex(netdev->link);
82d5ae15 2386 if (!netdev->ifindex) {
9d083402 2387 ERROR("failed to retrieve the index for %s", netdev->link);
0ad19a3f 2388 return -1;
2389 }
2390
e3b4c4c4
ST
2391 if (netdev->upscript) {
2392 int err;
751d9dcd
DL
2393 err = run_script(handler->name, "net", netdev->upscript,
2394 "up", "phys", netdev->link, (char*) NULL);
2395 if (err)
e3b4c4c4 2396 return -1;
e3b4c4c4
ST
2397 }
2398
82d5ae15 2399 return 0;
0ad19a3f 2400}
2401
74a2b586
JK
2402static int shutdown_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
2403{
2404 int err;
2405
2406 if (netdev->downscript) {
2407 err = run_script(handler->name, "net", netdev->downscript,
2408 "down", "phys", netdev->link, (char*) NULL);
2409 if (err)
2410 return -1;
2411 }
2412 return 0;
2413}
2414
e3b4c4c4 2415static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
0ad19a3f 2416{
82d5ae15 2417 netdev->ifindex = 0;
e3b4c4c4
ST
2418 if (netdev->upscript) {
2419 int err;
751d9dcd
DL
2420 err = run_script(handler->name, "net", netdev->upscript,
2421 "up", "empty", (char*) NULL);
2422 if (err)
e3b4c4c4 2423 return -1;
e3b4c4c4 2424 }
82d5ae15 2425 return 0;
0ad19a3f 2426}
2427
74a2b586
JK
2428static int shutdown_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
2429{
2430 int err;
2431
2432 if (netdev->downscript) {
2433 err = run_script(handler->name, "net", netdev->downscript,
2434 "down", "empty", (char*) NULL);
2435 if (err)
2436 return -1;
2437 }
2438 return 0;
2439}
2440
e3b4c4c4 2441int lxc_create_network(struct lxc_handler *handler)
0ad19a3f 2442{
e3b4c4c4 2443 struct lxc_list *network = &handler->conf->network;
82d5ae15 2444 struct lxc_list *iterator;
82d5ae15 2445 struct lxc_netdev *netdev;
0ad19a3f 2446
5f4535a3 2447 lxc_list_for_each(iterator, network) {
0ad19a3f 2448
5f4535a3 2449 netdev = iterator->elem;
13954cce 2450
24654103 2451 if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) {
82d5ae15 2452 ERROR("invalid network configuration type '%d'",
5f4535a3 2453 netdev->type);
82d5ae15
DL
2454 return -1;
2455 }
0ad19a3f 2456
e3b4c4c4 2457 if (netdev_conf[netdev->type](handler, netdev)) {
82d5ae15
DL
2458 ERROR("failed to create netdev");
2459 return -1;
2460 }
e3b4c4c4 2461
0ad19a3f 2462 }
2463
2464 return 0;
2465}
2466
74a2b586 2467void lxc_delete_network(struct lxc_handler *handler)
7fef7a06 2468{
74a2b586 2469 struct lxc_list *network = &handler->conf->network;
7fef7a06
DL
2470 struct lxc_list *iterator;
2471 struct lxc_netdev *netdev;
2472
2473 lxc_list_for_each(iterator, network) {
2474 netdev = iterator->elem;
d472214b 2475
74a2b586 2476 if (netdev->ifindex != 0 && netdev->type == LXC_NET_PHYS) {
d8f8e352
DL
2477 if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link))
2478 WARN("failed to rename to the initial name the " \
2479 "netdev '%s'", netdev->link);
d472214b 2480 continue;
d8f8e352 2481 }
d472214b 2482
74a2b586
JK
2483 if (netdev_deconf[netdev->type](handler, netdev)) {
2484 WARN("failed to destroy netdev");
2485 }
2486
d8f8e352
DL
2487 /* Recent kernel remove the virtual interfaces when the network
2488 * namespace is destroyed but in case we did not moved the
2489 * interface to the network namespace, we have to destroy it
2490 */
74a2b586
JK
2491 if (netdev->ifindex != 0 &&
2492 lxc_netdev_delete_by_index(netdev->ifindex))
d8f8e352 2493 WARN("failed to remove interface '%s'", netdev->name);
7fef7a06
DL
2494 }
2495}
2496
5f4535a3 2497int lxc_assign_network(struct lxc_list *network, pid_t pid)
0ad19a3f 2498{
82d5ae15 2499 struct lxc_list *iterator;
82d5ae15 2500 struct lxc_netdev *netdev;
3cfc0f3a 2501 int err;
0ad19a3f 2502
5f4535a3 2503 lxc_list_for_each(iterator, network) {
82d5ae15 2504
5f4535a3 2505 netdev = iterator->elem;
82d5ae15 2506
236087a6
DL
2507 /* empty network namespace, nothing to move */
2508 if (!netdev->ifindex)
2509 continue;
2510
d472214b 2511 err = lxc_netdev_move_by_index(netdev->ifindex, pid);
3cfc0f3a
MN
2512 if (err) {
2513 ERROR("failed to move '%s' to the container : %s",
2514 netdev->link, strerror(-err));
82d5ae15
DL
2515 return -1;
2516 }
2517
c1c75c04 2518 DEBUG("move '%s' to '%d'", netdev->name, pid);
0ad19a3f 2519 }
2520
2521 return 0;
2522}
2523
251d0d2a
DE
2524static int write_id_mapping(enum idtype idtype, pid_t pid, const char *buf,
2525 size_t buf_size)
f6d3e3e4
SH
2526{
2527 char path[PATH_MAX];
e4ccd113 2528 int ret, closeret;
f6d3e3e4
SH
2529 FILE *f;
2530
2531 ret = snprintf(path, PATH_MAX, "/proc/%d/%cid_map", pid, idtype == ID_TYPE_UID ? 'u' : 'g');
2532 if (ret < 0 || ret >= PATH_MAX) {
2533 fprintf(stderr, "%s: path name too long", __func__);
2534 return -E2BIG;
2535 }
2536 f = fopen(path, "w");
2537 if (!f) {
2538 perror("open");
2539 return -EINVAL;
2540 }
251d0d2a 2541 ret = fwrite(buf, buf_size, 1, f);
f6d3e3e4 2542 if (ret < 0)
e4ccd113
SH
2543 SYSERROR("writing id mapping");
2544 closeret = fclose(f);
2545 if (closeret)
2546 SYSERROR("writing id mapping");
2547 return ret < 0 ? ret : closeret;
f6d3e3e4
SH
2548}
2549
2550int lxc_map_ids(struct lxc_list *idmap, pid_t pid)
2551{
2552 struct lxc_list *iterator;
2553 struct id_map *map;
2554 int ret = 0;
251d0d2a 2555 enum idtype type;
4f7521b4 2556 char *buf = NULL, *pos;
251d0d2a
DE
2557
2558 for(type = ID_TYPE_UID; type <= ID_TYPE_GID; type++) {
4f7521b4
SH
2559 int left, fill;
2560
2561 pos = buf;
251d0d2a 2562 lxc_list_for_each(iterator, idmap) {
4f7521b4
SH
2563 /* The kernel only takes <= 4k for writes to /proc/<nr>/[ug]id_map */
2564 if (!buf)
2565 buf = pos = malloc(4096);
2566 if (!buf)
2567 return -ENOMEM;
2568
251d0d2a
DE
2569 map = iterator->elem;
2570 if (map->idtype == type) {
2571 left = 4096 - (pos - buf);
2572 fill = snprintf(pos, left, "%lu %lu %lu\n",
2573 map->nsid, map->hostid, map->range);
2574 if (fill <= 0 || fill >= left)
2575 SYSERROR("snprintf failed, too many mappings");
2576 pos += fill;
2577 }
2578 }
4f7521b4
SH
2579 if (pos == buf) // no mappings were found
2580 continue;
251d0d2a 2581 ret = write_id_mapping(type, pid, buf, pos-buf);
f6d3e3e4
SH
2582 if (ret)
2583 break;
2584 }
251d0d2a 2585
4f7521b4
SH
2586 if (buf)
2587 free(buf);
f6d3e3e4
SH
2588 return ret;
2589}
2590
19a26f82
MK
2591int lxc_find_gateway_addresses(struct lxc_handler *handler)
2592{
2593 struct lxc_list *network = &handler->conf->network;
2594 struct lxc_list *iterator;
2595 struct lxc_netdev *netdev;
2596 int link_index;
2597
2598 lxc_list_for_each(iterator, network) {
2599 netdev = iterator->elem;
2600
2601 if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto)
2602 continue;
2603
2604 if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN) {
2605 ERROR("gateway = auto only supported for "
2606 "veth and macvlan");
2607 return -1;
2608 }
2609
2610 if (!netdev->link) {
2611 ERROR("gateway = auto needs a link interface");
2612 return -1;
2613 }
2614
2615 link_index = if_nametoindex(netdev->link);
2616 if (!link_index)
2617 return -EINVAL;
2618
2619 if (netdev->ipv4_gateway_auto) {
2620 if (lxc_ipv4_addr_get(link_index, &netdev->ipv4_gateway)) {
2621 ERROR("failed to automatically find ipv4 gateway "
2622 "address from link interface '%s'", netdev->link);
2623 return -1;
2624 }
2625 }
2626
2627 if (netdev->ipv6_gateway_auto) {
2628 if (lxc_ipv6_addr_get(link_index, &netdev->ipv6_gateway)) {
2629 ERROR("failed to automatically find ipv6 gateway "
2630 "address from link interface '%s'", netdev->link);
2631 return -1;
2632 }
2633 }
2634 }
2635
2636 return 0;
2637}
2638
5e4a62bf 2639int lxc_create_tty(const char *name, struct lxc_conf *conf)
b0a33c1e 2640{
5e4a62bf 2641 struct lxc_tty_info *tty_info = &conf->tty_info;
985d15b1 2642 int i;
b0a33c1e 2643
5e4a62bf
DL
2644 /* no tty in the configuration */
2645 if (!conf->tty)
b0a33c1e 2646 return 0;
2647
13954cce 2648 tty_info->pty_info =
e4e7d59d 2649 malloc(sizeof(*tty_info->pty_info)*conf->tty);
b0a33c1e 2650 if (!tty_info->pty_info) {
36eb9bde 2651 SYSERROR("failed to allocate pty_info");
985d15b1 2652 return -1;
b0a33c1e 2653 }
2654
985d15b1 2655 for (i = 0; i < conf->tty; i++) {
13954cce 2656
b0a33c1e 2657 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
2658
13954cce 2659 if (openpty(&pty_info->master, &pty_info->slave,
b0a33c1e 2660 pty_info->name, NULL, NULL)) {
36eb9bde 2661 SYSERROR("failed to create pty #%d", i);
985d15b1
MT
2662 tty_info->nbtty = i;
2663 lxc_delete_tty(tty_info);
2664 return -1;
b0a33c1e 2665 }
2666
5332bb84
DL
2667 DEBUG("allocated pty '%s' (%d/%d)",
2668 pty_info->name, pty_info->master, pty_info->slave);
2669
b035ad62
MS
2670 /* Prevent leaking the file descriptors to the container */
2671 fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
2672 fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
2673
b0a33c1e 2674 pty_info->busy = 0;
2675 }
2676
985d15b1 2677 tty_info->nbtty = conf->tty;
1ac470c0
DL
2678
2679 INFO("tty's configured");
2680
985d15b1 2681 return 0;
b0a33c1e 2682}
2683
2684void lxc_delete_tty(struct lxc_tty_info *tty_info)
2685{
2686 int i;
2687
2688 for (i = 0; i < tty_info->nbtty; i++) {
2689 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
2690
2691 close(pty_info->master);
2692 close(pty_info->slave);
2693 }
2694
2695 free(tty_info->pty_info);
2696 tty_info->nbtty = 0;
2697}
2698
f6d3e3e4
SH
2699/*
2700 * given a host uid, return the ns uid if it is mapped.
2701 * if it is not mapped, return the original host id.
2702 */
2703static int shiftid(struct lxc_conf *c, int uid, enum idtype w)
2704{
2705 struct lxc_list *iterator;
2706 struct id_map *map;
2707 int low, high;
2708
2709 lxc_list_for_each(iterator, &c->id_map) {
2710 map = iterator->elem;
2711 if (map->idtype != w)
2712 continue;
2713
2714 low = map->nsid;
2715 high = map->nsid + map->range;
2716 if (uid < low || uid >= high)
2717 continue;
2718
2719 return uid - low + map->hostid;
2720 }
2721
2722 return uid;
2723}
2724
2725/*
2726 * Take a pathname for a file created on the host, and map the uid and gid
2727 * into the container if needed. (Used for ttys)
2728 */
2729static int uid_shift_file(char *path, struct lxc_conf *c)
2730{
2731 struct stat statbuf;
2732 int newuid, newgid;
2733
2734 if (stat(path, &statbuf)) {
2735 SYSERROR("stat(%s)", path);
2736 return -1;
2737 }
2738
2739 newuid = shiftid(c, statbuf.st_uid, ID_TYPE_UID);
2740 newgid = shiftid(c, statbuf.st_gid, ID_TYPE_GID);
2741 if (newuid != statbuf.st_uid || newgid != statbuf.st_gid) {
20087962 2742 DEBUG("chowning %s from %d:%d to %d:%d\n", path, (int)statbuf.st_uid, (int)statbuf.st_gid, newuid, newgid);
f6d3e3e4
SH
2743 if (chown(path, newuid, newgid)) {
2744 SYSERROR("chown(%s)", path);
2745 return -1;
2746 }
2747 }
2748 return 0;
2749}
2750
2751int uid_shift_ttys(int pid, struct lxc_conf *conf)
2752{
2753 int i, ret;
2754 struct lxc_tty_info *tty_info = &conf->tty_info;
2755 char path[MAXPATHLEN];
2756 char *ttydir = conf->ttydir;
2757
2758 if (!conf->rootfs.path)
2759 return 0;
2760 /* first the console */
2761 ret = snprintf(path, sizeof(path), "/proc/%d/root/dev/%s/console", pid, ttydir ? ttydir : "");
2762 if (ret < 0 || ret >= sizeof(path)) {
2763 ERROR("console path too long\n");
2764 return -1;
2765 }
2766 if (uid_shift_file(path, conf)) {
2767 DEBUG("Failed to chown the console %s.\n", path);
2768 return -1;
2769 }
2770 for (i=0; i< tty_info->nbtty; i++) {
2771 ret = snprintf(path, sizeof(path), "/proc/%d/root/dev/%s/tty%d",
2772 pid, ttydir ? ttydir : "", i + 1);
2773 if (ret < 0 || ret >= sizeof(path)) {
2774 ERROR("pathname too long for ttys");
2775 return -1;
2776 }
2777 if (uid_shift_file(path, conf)) {
2778 DEBUG("Failed to chown pty %s.\n", path);
2779 return -1;
2780 }
2781 }
2782
2783 return 0;
2784}
2785
283678ed 2786int lxc_setup(const char *name, struct lxc_conf *lxc_conf, const char *lxcpath)
0ad19a3f 2787{
e075f5d9
SH
2788#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
2789 int mounted;
2790#endif
2791
571e6ec8 2792 if (setup_utsname(lxc_conf->utsname)) {
36eb9bde 2793 ERROR("failed to setup the utsname for '%s'", name);
95b5ffaf 2794 return -1;
0ad19a3f 2795 }
2796
5f4535a3 2797 if (setup_network(&lxc_conf->network)) {
36eb9bde 2798 ERROR("failed to setup the network for '%s'", name);
95b5ffaf 2799 return -1;
0ad19a3f 2800 }
2801
283678ed 2802 if (run_lxc_hooks(name, "pre-mount", lxc_conf, lxcpath, NULL)) {
89eaa05e
SH
2803 ERROR("failed to run pre-mount hooks for container '%s'.", name);
2804 return -1;
2805 }
5ea6163a 2806
cc28d0b0 2807 if (setup_rootfs(lxc_conf)) {
ac778708 2808 ERROR("failed to setup rootfs for '%s'", name);
95b5ffaf 2809 return -1;
0ad19a3f 2810 }
2811
c6883f38 2812 if (lxc_conf->autodev) {
91c3830e
SH
2813 if (mount_autodev(lxc_conf->rootfs.mount)) {
2814 ERROR("failed to mount /dev in the container");
c6883f38
SH
2815 return -1;
2816 }
2817 }
2818
80a881b2 2819 if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name)) {
36eb9bde 2820 ERROR("failed to setup the mounts for '%s'", name);
95b5ffaf 2821 return -1;
576f946d 2822 }
2823
c1dc38c2 2824 if (!lxc_list_empty(&lxc_conf->mount_list) && setup_mount_entries(&lxc_conf->rootfs, &lxc_conf->mount_list, name)) {
e7938e9e
MN
2825 ERROR("failed to setup the mount entries for '%s'", name);
2826 return -1;
2827 }
2828
283678ed 2829 if (run_lxc_hooks(name, "mount", lxc_conf, lxcpath, NULL)) {
773fb9ca
SH
2830 ERROR("failed to run mount hooks for container '%s'.", name);
2831 return -1;
2832 }
2833
91c3830e 2834 if (lxc_conf->autodev) {
283678ed 2835 if (run_lxc_hooks(name, "autodev", lxc_conf, lxcpath, NULL)) {
f7bee6c6
MW
2836 ERROR("failed to run autodev hooks for container '%s'.", name);
2837 return -1;
2838 }
91c3830e
SH
2839 if (setup_autodev(lxc_conf->rootfs.mount)) {
2840 ERROR("failed to populate /dev in the container");
2841 return -1;
2842 }
2843 }
2844
37903589 2845 if (!lxc_conf->is_execute && setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
36eb9bde 2846 ERROR("failed to setup the console for '%s'", name);
95b5ffaf 2847 return -1;
6e590161 2848 }
2849
7e0e1d94
AV
2850 if (lxc_conf->kmsg) {
2851 if (setup_kmsg(&lxc_conf->rootfs, &lxc_conf->console)) // don't fail
2852 ERROR("failed to setup kmsg for '%s'", name);
2853 }
1bd051a6 2854
37903589 2855 if (!lxc_conf->is_execute && setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
36eb9bde 2856 ERROR("failed to setup the ttys for '%s'", name);
95b5ffaf 2857 return -1;
b0a33c1e 2858 }
2859
e075f5d9 2860#if HAVE_APPARMOR /* || HAVE_SMACK || HAVE_SELINUX */
9ac3ffb5
SG
2861 INFO("rootfs path is .%s., mount is .%s.", lxc_conf->rootfs.path,
2862 lxc_conf->rootfs.mount);
6e46cfcb
SH
2863 if (lxc_conf->rootfs.path == NULL || strlen(lxc_conf->rootfs.path) == 0) {
2864 if (mount("proc", "/proc", "proc", 0, NULL)) {
2865 SYSERROR("Failed mounting /proc, proceeding");
2866 mounted = 0;
2867 } else
2868 mounted = 1;
2869 } else
9ac3ffb5 2870 mounted = lsm_mount_proc_if_needed(lxc_conf->rootfs.path, lxc_conf->rootfs.mount);
e075f5d9
SH
2871 if (mounted == -1) {
2872 SYSERROR("failed to mount /proc in the container.");
2873 return -1;
2874 } else if (mounted == 1) {
2875 lxc_conf->lsm_umount_proc = 1;
2876 }
2877#endif
2878
ac778708 2879 if (setup_pivot_root(&lxc_conf->rootfs)) {
36eb9bde 2880 ERROR("failed to set rootfs for '%s'", name);
95b5ffaf 2881 return -1;
ed502555 2882 }
2883
571e6ec8 2884 if (setup_pts(lxc_conf->pts)) {
36eb9bde 2885 ERROR("failed to setup the new pts instance");
95b5ffaf 2886 return -1;
3c26f34e 2887 }
2888
cccc74b5
DL
2889 if (setup_personality(lxc_conf->personality)) {
2890 ERROR("failed to setup personality");
2891 return -1;
2892 }
2893
f6d3e3e4
SH
2894 if (lxc_list_empty(&lxc_conf->id_map)) {
2895 if (setup_caps(&lxc_conf->caps)) {
2896 ERROR("failed to drop capabilities");
2897 return -1;
2898 }
81810dd1
DL
2899 }
2900
cd54d859
DL
2901 NOTICE("'%s' is setup.", name);
2902
0ad19a3f 2903 return 0;
2904}
26ddeedd 2905
283678ed
SH
2906int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf,
2907 const char *lxcpath, char *argv[])
26ddeedd
SH
2908{
2909 int which = -1;
2910 struct lxc_list *it;
2911
2912 if (strcmp(hook, "pre-start") == 0)
2913 which = LXCHOOK_PRESTART;
5ea6163a
SH
2914 else if (strcmp(hook, "pre-mount") == 0)
2915 which = LXCHOOK_PREMOUNT;
26ddeedd
SH
2916 else if (strcmp(hook, "mount") == 0)
2917 which = LXCHOOK_MOUNT;
f7bee6c6
MW
2918 else if (strcmp(hook, "autodev") == 0)
2919 which = LXCHOOK_AUTODEV;
26ddeedd
SH
2920 else if (strcmp(hook, "start") == 0)
2921 which = LXCHOOK_START;
2922 else if (strcmp(hook, "post-stop") == 0)
2923 which = LXCHOOK_POSTSTOP;
148e91f5
SH
2924 else if (strcmp(hook, "clone") == 0)
2925 which = LXCHOOK_CLONE;
26ddeedd
SH
2926 else
2927 return -1;
2928 lxc_list_for_each(it, &conf->hooks[which]) {
2929 int ret;
2930 char *hookname = it->elem;
283678ed 2931 ret = run_script_argv(name, "lxc", hookname, hook, lxcpath, argv);
26ddeedd
SH
2932 if (ret)
2933 return ret;
2934 }
2935 return 0;
2936}
72d0e1cb 2937
427b3a21 2938static void lxc_remove_nic(struct lxc_list *it)
72d0e1cb
SG
2939{
2940 struct lxc_netdev *netdev = it->elem;
9ebb03ad 2941 struct lxc_list *it2,*next;
72d0e1cb
SG
2942
2943 lxc_list_del(it);
2944
2945 if (netdev->link)
2946 free(netdev->link);
2947 if (netdev->name)
2948 free(netdev->name);
2949 if (netdev->upscript)
2950 free(netdev->upscript);
2951 if (netdev->hwaddr)
2952 free(netdev->hwaddr);
2953 if (netdev->mtu)
2954 free(netdev->mtu);
2955 if (netdev->ipv4_gateway)
2956 free(netdev->ipv4_gateway);
2957 if (netdev->ipv6_gateway)
2958 free(netdev->ipv6_gateway);
9ebb03ad 2959 lxc_list_for_each_safe(it2, &netdev->ipv4, next) {
72d0e1cb
SG
2960 lxc_list_del(it2);
2961 free(it2->elem);
2962 free(it2);
2963 }
9ebb03ad 2964 lxc_list_for_each_safe(it2, &netdev->ipv6, next) {
72d0e1cb
SG
2965 lxc_list_del(it2);
2966 free(it2->elem);
2967 free(it2);
2968 }
d95db067 2969 free(netdev);
72d0e1cb
SG
2970 free(it);
2971}
2972
2973/* we get passed in something like '0', '0.ipv4' or '1.ipv6' */
12a50cc6 2974int lxc_clear_nic(struct lxc_conf *c, const char *key)
72d0e1cb
SG
2975{
2976 char *p1;
2977 int ret, idx, i;
2978 struct lxc_list *it;
2979 struct lxc_netdev *netdev;
2980
2981 p1 = index(key, '.');
2982 if (!p1 || *(p1+1) == '\0')
2983 p1 = NULL;
2984
2985 ret = sscanf(key, "%d", &idx);
2986 if (ret != 1) return -1;
2987 if (idx < 0)
2988 return -1;
2989
2990 i = 0;
2991 lxc_list_for_each(it, &c->network) {
2992 if (i == idx)
2993 break;
2994 i++;
2995 }
2996 if (i < idx) // we don't have that many nics defined
2997 return -1;
2998
2999 if (!it || !it->elem)
3000 return -1;
3001
3002 netdev = it->elem;
3003
3004 if (!p1) {
3005 lxc_remove_nic(it);
3006 } else if (strcmp(p1, "ipv4") == 0) {
9ebb03ad
DE
3007 struct lxc_list *it2,*next;
3008 lxc_list_for_each_safe(it2, &netdev->ipv4, next) {
72d0e1cb
SG
3009 lxc_list_del(it2);
3010 free(it2->elem);
3011 free(it2);
3012 }
3013 } else if (strcmp(p1, "ipv6") == 0) {
9ebb03ad
DE
3014 struct lxc_list *it2,*next;
3015 lxc_list_for_each_safe(it2, &netdev->ipv6, next) {
72d0e1cb
SG
3016 lxc_list_del(it2);
3017 free(it2->elem);
3018 free(it2);
3019 }
3020 } else if (strcmp(p1, "link") == 0) {
3021 if (netdev->link) {
3022 free(netdev->link);
3023 netdev->link = NULL;
3024 }
3025 } else if (strcmp(p1, "name") == 0) {
3026 if (netdev->name) {
3027 free(netdev->name);
3028 netdev->name = NULL;
3029 }
3030 } else if (strcmp(p1, "script.up") == 0) {
3031 if (netdev->upscript) {
3032 free(netdev->upscript);
3033 netdev->upscript = NULL;
3034 }
3035 } else if (strcmp(p1, "hwaddr") == 0) {
3036 if (netdev->hwaddr) {
3037 free(netdev->hwaddr);
3038 netdev->hwaddr = NULL;
3039 }
3040 } else if (strcmp(p1, "mtu") == 0) {
3041 if (netdev->mtu) {
3042 free(netdev->mtu);
3043 netdev->mtu = NULL;
3044 }
3045 } else if (strcmp(p1, "ipv4_gateway") == 0) {
3046 if (netdev->ipv4_gateway) {
3047 free(netdev->ipv4_gateway);
3048 netdev->ipv4_gateway = NULL;
3049 }
3050 } else if (strcmp(p1, "ipv6_gateway") == 0) {
3051 if (netdev->ipv6_gateway) {
3052 free(netdev->ipv6_gateway);
3053 netdev->ipv6_gateway = NULL;
3054 }
3055 }
3056 else return -1;
3057
3058 return 0;
3059}
3060
3061int lxc_clear_config_network(struct lxc_conf *c)
3062{
9ebb03ad
DE
3063 struct lxc_list *it,*next;
3064 lxc_list_for_each_safe(it, &c->network, next) {
72d0e1cb
SG
3065 lxc_remove_nic(it);
3066 }
3067 return 0;
3068}
3069
3070int lxc_clear_config_caps(struct lxc_conf *c)
3071{
9ebb03ad 3072 struct lxc_list *it,*next;
72d0e1cb 3073
9ebb03ad 3074 lxc_list_for_each_safe(it, &c->caps, next) {
72d0e1cb
SG
3075 lxc_list_del(it);
3076 free(it->elem);
3077 free(it);
3078 }
3079 return 0;
3080}
3081
12a50cc6 3082int lxc_clear_cgroups(struct lxc_conf *c, const char *key)
72d0e1cb 3083{
9ebb03ad 3084 struct lxc_list *it,*next;
72d0e1cb 3085 bool all = false;
12a50cc6 3086 const char *k = key + 11;
72d0e1cb
SG
3087
3088 if (strcmp(key, "lxc.cgroup") == 0)
3089 all = true;
3090
9ebb03ad 3091 lxc_list_for_each_safe(it, &c->cgroup, next) {
72d0e1cb
SG
3092 struct lxc_cgroup *cg = it->elem;
3093 if (!all && strcmp(cg->subsystem, k) != 0)
3094 continue;
3095 lxc_list_del(it);
3096 free(cg->subsystem);
3097 free(cg->value);
3098 free(cg);
3099 free(it);
3100 }
3101 return 0;
3102}
3103
3104int lxc_clear_mount_entries(struct lxc_conf *c)
3105{
9ebb03ad 3106 struct lxc_list *it,*next;
72d0e1cb 3107
9ebb03ad 3108 lxc_list_for_each_safe(it, &c->mount_list, next) {
72d0e1cb
SG
3109 lxc_list_del(it);
3110 free(it->elem);
3111 free(it);
3112 }
3113 return 0;
3114}
3115
12a50cc6 3116int lxc_clear_hooks(struct lxc_conf *c, const char *key)
72d0e1cb 3117{
9ebb03ad 3118 struct lxc_list *it,*next;
17ed13a3 3119 bool all = false, done = false;
12a50cc6 3120 const char *k = key + 9;
72d0e1cb
SG
3121 int i;
3122
17ed13a3
SH
3123 if (strcmp(key, "lxc.hook") == 0)
3124 all = true;
3125
72d0e1cb 3126 for (i=0; i<NUM_LXC_HOOKS; i++) {
17ed13a3 3127 if (all || strcmp(k, lxchook_names[i]) == 0) {
9ebb03ad 3128 lxc_list_for_each_safe(it, &c->hooks[i], next) {
17ed13a3
SH
3129 lxc_list_del(it);
3130 free(it->elem);
3131 free(it);
3132 }
3133 done = true;
72d0e1cb
SG
3134 }
3135 }
17ed13a3
SH
3136
3137 if (!done) {
3138 ERROR("Invalid hook key: %s", key);
3139 return -1;
3140 }
72d0e1cb
SG
3141 return 0;
3142}
8eb5694b 3143
7b35f3d6
SH
3144void lxc_clear_saved_nics(struct lxc_conf *conf)
3145{
3146 int i;
3147
3148 if (!conf->num_savednics)
3149 return;
3150 for (i=0; i < conf->num_savednics; i++)
3151 free(conf->saved_nics[i].orig_name);
3152 conf->saved_nics = 0;
3153 free(conf->saved_nics);
3154}
3155
8eb5694b
SH
3156void lxc_conf_free(struct lxc_conf *conf)
3157{
3158 if (!conf)
3159 return;
3160 if (conf->console.path)
3161 free(conf->console.path);
54c30e29 3162 if (conf->rootfs.mount)
8eb5694b 3163 free(conf->rootfs.mount);
d95db067
DE
3164 if (conf->rootfs.path)
3165 free(conf->rootfs.path);
3166 if (conf->utsname)
3167 free(conf->utsname);
3168 if (conf->ttydir)
3169 free(conf->ttydir);
3170 if (conf->fstab)
3171 free(conf->fstab);
fc7e8864
WM
3172 if (conf->rcfile)
3173 free(conf->rcfile);
8eb5694b 3174 lxc_clear_config_network(conf);
1f530df6 3175#if HAVE_APPARMOR
8eb5694b
SH
3176 if (conf->aa_profile)
3177 free(conf->aa_profile);
1f530df6 3178#endif
769872f9 3179 lxc_seccomp_free(conf);
8eb5694b
SH
3180 lxc_clear_config_caps(conf);
3181 lxc_clear_cgroups(conf, "lxc.cgroup");
17ed13a3 3182 lxc_clear_hooks(conf, "lxc.hook");
8eb5694b 3183 lxc_clear_mount_entries(conf);
7b35f3d6 3184 lxc_clear_saved_nics(conf);
8eb5694b
SH
3185 free(conf);
3186}