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