]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/conf.c
set rights to lxc-init
[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:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23#define _GNU_SOURCE
24#include <stdio.h>
25#undef _GNU_SOURCE
26#include <stdlib.h>
27#include <errno.h>
28#include <string.h>
29#include <dirent.h>
30#include <mntent.h>
31#include <unistd.h>
b0a33c1e 32#include <pty.h>
0ad19a3f 33
34#include <sys/types.h>
35#include <sys/utsname.h>
36#include <sys/param.h>
37#include <sys/stat.h>
38#include <sys/socket.h>
39#include <sys/mount.h>
40#include <sys/mman.h>
81810dd1
DL
41#include <sys/prctl.h>
42#include <sys/capability.h>
0ad19a3f 43
44#include <arpa/inet.h>
45#include <fcntl.h>
46#include <netinet/in.h>
47#include <net/if.h>
6f4a3756 48#include <libgen.h>
0ad19a3f 49
e5bda9ee 50#include "network.h"
51#include "error.h"
b2718c72 52#include "parse.h"
881450bb 53#include "config.h"
1b09f2c0
DL
54#include "utils.h"
55#include "conf.h"
56#include "log.h"
57#include "lxc.h" /* for lxc_cgroup_set() */
36eb9bde
CLG
58
59lxc_log_define(lxc_conf, lxc);
e5bda9ee 60
0ad19a3f 61#define MAXHWLEN 18
62#define MAXINDEXLEN 20
442cbbe6 63#define MAXMTULEN 16
0ad19a3f 64#define MAXLINELEN 128
65
fdc03323
DL
66#ifndef MS_REC
67#define MS_REC 16384
68#endif
69
c08556c6
DL
70#ifndef MNT_DETACH
71#define MNT_DETACH 2
72#endif
73
b09094da
MN
74#ifndef CAP_SETFCAP
75#define CAP_SETFCAP 31
76#endif
77
78#ifndef CAP_MAC_OVERRIDE
79#define CAP_MAC_OVERRIDE 32
80#endif
81
82#ifndef CAP_MAC_ADMIN
83#define CAP_MAC_ADMIN 33
84#endif
85
86#ifndef PR_CAPBSET_DROP
87#define PR_CAPBSET_DROP 24
88#endif
89
bf601689
MH
90extern int pivot_root(const char * new_root, const char * put_old);
91
82d5ae15 92typedef int (*instanciate_cb)(struct lxc_netdev *);
0ad19a3f 93
998ac676
RT
94struct mount_opt {
95 char *name;
96 int clear;
97 int flag;
98};
99
81810dd1
DL
100struct caps_opt {
101 char *name;
102 int value;
103};
104
82d5ae15
DL
105static int instanciate_veth(struct lxc_netdev *);
106static int instanciate_macvlan(struct lxc_netdev *);
26c39028 107static int instanciate_vlan(struct lxc_netdev *);
82d5ae15
DL
108static int instanciate_phys(struct lxc_netdev *);
109static int instanciate_empty(struct lxc_netdev *);
110
24654103
DL
111static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
112 [LXC_NET_VETH] = instanciate_veth,
113 [LXC_NET_MACVLAN] = instanciate_macvlan,
114 [LXC_NET_VLAN] = instanciate_vlan,
115 [LXC_NET_PHYS] = instanciate_phys,
116 [LXC_NET_EMPTY] = instanciate_empty,
0ad19a3f 117};
118
998ac676
RT
119static struct mount_opt mount_opt[] = {
120 { "defaults", 0, 0 },
121 { "ro", 0, MS_RDONLY },
122 { "rw", 1, MS_RDONLY },
123 { "suid", 1, MS_NOSUID },
124 { "nosuid", 0, MS_NOSUID },
125 { "dev", 1, MS_NODEV },
126 { "nodev", 0, MS_NODEV },
127 { "exec", 1, MS_NOEXEC },
128 { "noexec", 0, MS_NOEXEC },
129 { "sync", 0, MS_SYNCHRONOUS },
130 { "async", 1, MS_SYNCHRONOUS },
131 { "remount", 0, MS_REMOUNT },
132 { "mand", 0, MS_MANDLOCK },
133 { "nomand", 1, MS_MANDLOCK },
134 { "atime", 1, MS_NOATIME },
135 { "noatime", 0, MS_NOATIME },
136 { "diratime", 1, MS_NODIRATIME },
137 { "nodiratime", 0, MS_NODIRATIME },
138 { "bind", 0, MS_BIND },
139 { "rbind", 0, MS_BIND|MS_REC },
140 { NULL, 0, 0 },
141};
142
81810dd1 143static struct caps_opt caps_opt[] = {
1e11be34
DL
144 { "chown", CAP_CHOWN },
145 { "dac_override", CAP_DAC_OVERRIDE },
146 { "dac_read_search", CAP_DAC_READ_SEARCH },
147 { "fowner", CAP_FOWNER },
148 { "fsetid", CAP_FSETID },
81810dd1
DL
149 { "kill", CAP_KILL },
150 { "setgid", CAP_SETGID },
151 { "setuid", CAP_SETUID },
152 { "setpcap", CAP_SETPCAP },
153 { "linux_immutable", CAP_LINUX_IMMUTABLE },
154 { "net_bind_service", CAP_NET_BIND_SERVICE },
155 { "net_broadcast", CAP_NET_BROADCAST },
156 { "net_admin", CAP_NET_ADMIN },
157 { "net_raw", CAP_NET_RAW },
158 { "ipc_lock", CAP_IPC_LOCK },
159 { "ipc_owner", CAP_IPC_OWNER },
160 { "sys_module", CAP_SYS_MODULE },
161 { "sys_rawio", CAP_SYS_RAWIO },
162 { "sys_chroot", CAP_SYS_CHROOT },
163 { "sys_ptrace", CAP_SYS_PTRACE },
164 { "sys_pacct", CAP_SYS_PACCT },
165 { "sys_admin", CAP_SYS_ADMIN },
166 { "sys_boot", CAP_SYS_BOOT },
167 { "sys_nice", CAP_SYS_NICE },
168 { "sys_resource", CAP_SYS_RESOURCE },
169 { "sys_time", CAP_SYS_TIME },
170 { "sys_tty_config", CAP_SYS_TTY_CONFIG },
171 { "mknod", CAP_MKNOD },
172 { "lease", CAP_LEASE },
9527e566 173#ifdef CAP_AUDIT_WRITE
81810dd1 174 { "audit_write", CAP_AUDIT_WRITE },
9527e566
FW
175#endif
176#ifdef CAP_AUDIT_CONTROL
81810dd1 177 { "audit_control", CAP_AUDIT_CONTROL },
9527e566 178#endif
81810dd1
DL
179 { "setfcap", CAP_SETFCAP },
180 { "mac_override", CAP_MAC_OVERRIDE },
181 { "mac_admin", CAP_MAC_ADMIN },
81810dd1
DL
182};
183
5045eedf 184#if 0 /* will be reactivated with image mounting support */
7a7ff0c6 185static int configure_find_fstype_cb(char* buffer, void *data)
78ae2fcc 186{
187 struct cbarg {
188 const char *rootfs;
189 const char *testdir;
190 char *fstype;
191 int mntopt;
192 } *cbarg = data;
193
194 char *fstype;
195
196 /* we don't try 'nodev' entries */
197 if (strstr(buffer, "nodev"))
198 return 0;
199
200 fstype = buffer;
b2718c72 201 fstype += lxc_char_left_gc(fstype, strlen(fstype));
202 fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
78ae2fcc 203
204 if (mount(cbarg->rootfs, cbarg->testdir, fstype, cbarg->mntopt, NULL))
205 return 0;
206
207 /* found ! */
208 umount(cbarg->testdir);
209 strcpy(cbarg->fstype, fstype);
210
211 return 1;
212}
213
214/* find the filesystem type with brute force */
215static int configure_find_fstype(const char *rootfs, char *fstype, int mntopt)
216{
217 int i, found;
78ae2fcc 218
219 struct cbarg {
220 const char *rootfs;
221 const char *testdir;
222 char *fstype;
223 int mntopt;
224 } cbarg = {
225 .rootfs = rootfs,
226 .fstype = fstype,
227 .mntopt = mntopt,
228 };
229
230 /* first we check with /etc/filesystems, in case the modules
231 * are auto-loaded and fall back to the supported kernel fs
232 */
233 char *fsfile[] = {
234 "/etc/filesystems",
235 "/proc/filesystems",
236 };
237
238 cbarg.testdir = tempnam("/tmp", "lxc-");
239 if (!cbarg.testdir) {
36eb9bde 240 SYSERROR("failed to build a temp name");
78ae2fcc 241 return -1;
242 }
243
244 if (mkdir(cbarg.testdir, 0755)) {
36eb9bde 245 SYSERROR("failed to create temporary directory");
78ae2fcc 246 return -1;
247 }
248
249 for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) {
250
b2718c72 251 found = lxc_file_for_each_line(fsfile[i],
252 configure_find_fstype_cb,
2382ecff 253 &cbarg);
78ae2fcc 254
255 if (found < 0) {
36eb9bde 256 SYSERROR("failed to read '%s'", fsfile[i]);
78ae2fcc 257 goto out;
258 }
259
260 if (found)
261 break;
262 }
263
264 if (!found) {
36eb9bde 265 ERROR("failed to determine fs type for '%s'", rootfs);
78ae2fcc 266 goto out;
267 }
268
269out:
270 rmdir(cbarg.testdir);
271 return found - 1;
272}
273
274static int configure_rootfs_dir_cb(const char *rootfs, const char *absrootfs,
275 FILE *f)
276{
fdc03323 277 return fprintf(f, "%s %s none rbind 0 0\n", absrootfs, rootfs);
78ae2fcc 278}
279
280static int configure_rootfs_blk_cb(const char *rootfs, const char *absrootfs,
281 FILE *f)
282{
283 char fstype[MAXPATHLEN];
284
285 if (configure_find_fstype(absrootfs, fstype, 0)) {
36eb9bde 286 ERROR("failed to configure mount for block device '%s'",
78ae2fcc 287 absrootfs);
288 return -1;
289 }
290
291 return fprintf(f, "%s %s %s defaults 0 0\n", absrootfs, rootfs, fstype);
292}
293
eae6543d 294static int configure_rootfs(const char *name, const char *rootfs)
0ad19a3f 295{
296 char path[MAXPATHLEN];
b09ef133 297 char absrootfs[MAXPATHLEN];
9b0f0477 298 char fstab[MAXPATHLEN];
78ae2fcc 299 struct stat s;
9b0f0477 300 FILE *f;
78ae2fcc 301 int i, ret;
302
303 typedef int (*rootfs_cb)(const char *, const char *, FILE *);
304
305 struct rootfs_type {
306 int type;
307 rootfs_cb cb;
308 } rtfs_type[] = {
309 { __S_IFDIR, configure_rootfs_dir_cb },
310 { __S_IFBLK, configure_rootfs_blk_cb },
311 };
0ad19a3f 312
4c8ab83b 313 if (!realpath(rootfs, absrootfs)) {
36eb9bde 314 SYSERROR("failed to get real path for '%s'", rootfs);
4c8ab83b 315 return -1;
316 }
b09ef133 317
4c8ab83b 318 snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name);
b09ef133 319
78ae2fcc 320 if (mkdir(path, 0755)) {
36eb9bde 321 SYSERROR("failed to create the '%s' directory", path);
78ae2fcc 322 return -1;
323 }
324
b09ef133 325 if (access(absrootfs, F_OK)) {
36eb9bde 326 SYSERROR("'%s' is not accessible", absrootfs);
b09ef133 327 return -1;
328 }
329
78ae2fcc 330 if (stat(absrootfs, &s)) {
36eb9bde 331 SYSERROR("failed to stat '%s'", absrootfs);
9b0f0477 332 return -1;
333 }
334
78ae2fcc 335 for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) {
9b0f0477 336
78ae2fcc 337 if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
338 continue;
9b0f0477 339
78ae2fcc 340 snprintf(fstab, MAXPATHLEN, LXCPATH "/%s/fstab", name);
4c8ab83b 341
78ae2fcc 342 f = fopen(fstab, "a+");
343 if (!f) {
36eb9bde 344 SYSERROR("failed to open fstab file");
78ae2fcc 345 return -1;
346 }
9b0f0477 347
78ae2fcc 348 ret = rtfs_type[i].cb(path, absrootfs, f);
9b0f0477 349
78ae2fcc 350 fclose(f);
351
352 if (ret < 0) {
36eb9bde 353 ERROR("failed to add rootfs mount in fstab");
78ae2fcc 354 return -1;
355 }
356
357 snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs/rootfs", name);
358
359 return symlink(absrootfs, path);
360 }
9b0f0477 361
36eb9bde 362 ERROR("unsupported rootfs type for '%s'", absrootfs);
78ae2fcc 363 return -1;
0ad19a3f 364}
5045eedf 365#endif
0ad19a3f 366
4e5440c6 367static int setup_utsname(struct utsname *utsname)
0ad19a3f 368{
4e5440c6
DL
369 if (!utsname)
370 return 0;
0ad19a3f 371
4e5440c6
DL
372 if (sethostname(utsname->nodename, strlen(utsname->nodename))) {
373 SYSERROR("failed to set the hostname to '%s'", utsname->nodename);
0ad19a3f 374 return -1;
375 }
376
4e5440c6 377 INFO("'%s' hostname has been setup", utsname->nodename);
cd54d859 378
0ad19a3f 379 return 0;
380}
381
33fcb7a0
DL
382static int setup_tty(const struct lxc_rootfs *rootfs,
383 const struct lxc_tty_info *tty_info)
b0a33c1e 384{
385 char path[MAXPATHLEN];
386 int i;
387
388 for (i = 0; i < tty_info->nbtty; i++) {
389
390 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
391
52e35957 392 snprintf(path, sizeof(path), "%s/dev/tty%d",
33fcb7a0 393 rootfs->path ? rootfs->path : "", i + 1);
b0a33c1e 394
13954cce 395 /* At this point I can not use the "access" function
b0a33c1e 396 * to check the file is present or not because it fails
397 * with EACCES errno and I don't know why :( */
13954cce 398
b0a33c1e 399 if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
36eb9bde 400 WARN("failed to mount '%s'->'%s'",
52e35957 401 pty_info->name, path);
b0a33c1e 402 continue;
403 }
404 }
405
cd54d859
DL
406 INFO("%d tty(s) has been setup", tty_info->nbtty);
407
b0a33c1e 408 return 0;
409}
410
7a7ff0c6 411static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
bf601689
MH
412{
413 struct lxc_list *mountlist, *listentry, *iterator;
414 char *pivotdir, *mountpoint, *mountentry;
415 int found;
416 void **cbparm;
417
418 mountentry = buffer;
419 cbparm = (void **)data;
420
421 mountlist = cbparm[0];
422 pivotdir = cbparm[1];
423
424 /* parse entry, first field is mountname, ignore */
425 mountpoint = strtok(mountentry, " ");
426 if (!mountpoint)
427 return -1;
428
429 /* second field is mountpoint */
430 mountpoint = strtok(NULL, " ");
431 if (!mountpoint)
432 return -1;
433
434 /* only consider mountpoints below old root fs */
435 if (strncmp(mountpoint, pivotdir, strlen(pivotdir)))
436 return 0;
437
438 /* filter duplicate mountpoints */
439 found = 0;
440 lxc_list_for_each(iterator, mountlist) {
441 if (!strcmp(iterator->elem, mountpoint)) {
442 found = 1;
443 break;
444 }
445 }
446 if (found)
447 return 0;
448
449 /* add entry to list */
450 listentry = malloc(sizeof(*listentry));
451 if (!listentry) {
452 SYSERROR("malloc for mountpoint listentry failed");
453 return -1;
454 }
455
456 listentry->elem = strdup(mountpoint);
457 if (!listentry->elem) {
458 SYSERROR("strdup failed");
459 return -1;
460 }
461 lxc_list_add_tail(mountlist, listentry);
462
463 return 0;
464}
465
cc6f6dd7 466static int umount_oldrootfs(const char *oldrootfs)
bf601689 467{
2382ecff 468 char path[MAXPATHLEN];
bf601689
MH
469 void *cbparm[2];
470 struct lxc_list mountlist, *iterator;
471 int ok, still_mounted, last_still_mounted;
bf601689
MH
472
473 /* read and parse /proc/mounts in old root fs */
474 lxc_list_init(&mountlist);
475
cc6f6dd7
DL
476 /* oldrootfs is on the top tree directory now */
477 snprintf(path, sizeof(path), "/%s", oldrootfs);
bf601689 478 cbparm[0] = &mountlist;
bf601689 479
cc6f6dd7 480 cbparm[1] = strdup(path);
bf601689
MH
481 if (!cbparm[1]) {
482 SYSERROR("strdup failed");
483 return -1;
484 }
485
cc6f6dd7
DL
486 snprintf(path, sizeof(path), "%s/proc/mounts", oldrootfs);
487
488 ok = lxc_file_for_each_line(path,
489 setup_rootfs_pivot_root_cb, &cbparm);
bf601689
MH
490 if (ok < 0) {
491 SYSERROR("failed to read or parse mount list '%s'", path);
492 return -1;
493 }
494
495 /* umount filesystems until none left or list no longer shrinks */
496 still_mounted = 0;
497 do {
498 last_still_mounted = still_mounted;
499 still_mounted = 0;
500
501 lxc_list_for_each(iterator, &mountlist) {
502
c08556c6 503 /* umount normally */
bf601689
MH
504 if (!umount(iterator->elem)) {
505 DEBUG("umounted '%s'", (char *)iterator->elem);
506 lxc_list_del(iterator);
507 continue;
508 }
509
bf601689
MH
510 still_mounted++;
511 }
7df119ee 512
bf601689
MH
513 } while (still_mounted > 0 && still_mounted != last_still_mounted);
514
7df119ee 515
c08556c6
DL
516 lxc_list_for_each(iterator, &mountlist) {
517
518 /* let's try a lazy umount */
519 if (!umount2(iterator->elem, MNT_DETACH)) {
520 INFO("lazy unmount of '%s'", (char *)iterator->elem);
521 continue;
522 }
523
524 /* be more brutal (nfs) */
525 if (!umount2(iterator->elem, MNT_FORCE)) {
526 INFO("forced unmount of '%s'", (char *)iterator->elem);
527 continue;
528 }
529
7df119ee 530 WARN("failed to unmount '%s'", (char *)iterator->elem);
c08556c6 531 }
bf601689 532
cc6f6dd7
DL
533 return 0;
534}
535
536static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
537{
538 char path[MAXPATHLEN];
539 int remove_pivotdir = 0;
540
541 /* change into new root fs */
542 if (chdir(rootfs)) {
543 SYSERROR("can't chdir to new rootfs '%s'", rootfs);
544 return -1;
545 }
546
547 if (!pivotdir)
3103609d 548 pivotdir = "mnt";
cc6f6dd7 549
4f9293b1 550 /* compute the full path to pivotdir under rootfs */
cc6f6dd7
DL
551 snprintf(path, sizeof(path), "%s/%s", rootfs, pivotdir);
552
553 if (access(path, F_OK)) {
554
555 if (mkdir_p(path, 0755)) {
556 SYSERROR("failed to create pivotdir '%s'", path);
557 return -1;
558 }
559
560 remove_pivotdir = 1;
561 DEBUG("created '%s' directory", path);
562 }
563
564 DEBUG("mountpoint for old rootfs is '%s'", path);
565
566 /* pivot_root into our new root fs */
567 if (pivot_root(".", path)) {
568 SYSERROR("pivot_root syscall failed");
bf601689
MH
569 return -1;
570 }
cc6f6dd7
DL
571
572 if (chdir("/")) {
573 SYSERROR("can't chdir to / after pivot_root");
574 return -1;
575 }
576
577 DEBUG("pivot_root syscall to '%s' successful", rootfs);
578
579 /* we switch from absolute path to relative path */
580 if (umount_oldrootfs(pivotdir))
581 return -1;
bf601689 582
c08556c6
DL
583 /* remove temporary mount point, we don't consider the removing
584 * as fatal */
a91d897a
FW
585 if (remove_pivotdir && rmdir(pivotdir))
586 WARN("can't remove mountpoint '%s': %m", pivotdir);
bf601689
MH
587
588 INFO("pivoted to '%s'", rootfs);
cc6f6dd7 589
bf601689
MH
590 return 0;
591}
592
33fcb7a0 593static int setup_rootfs(const struct lxc_rootfs *rootfs)
0ad19a3f 594{
b1789442 595 char *mpath = LXCROOTFSMOUNT;
0ad19a3f 596
33fcb7a0 597 if (!rootfs->path)
c69bd12f 598 return 0;
0ad19a3f 599
b1789442
DL
600 if (rootfs->mount)
601 mpath = rootfs->mount;
602
603 if (access(mpath, F_OK)) {
604 SYSERROR("failed to access to '%s', check it is present",
605 mpath);
606 return -1;
607 }
608
609 if (mount(rootfs->path, mpath, "none", MS_BIND|MS_REC, NULL)) {
610 SYSERROR("failed to mount '%s'->'%s'", rootfs->path, mpath);
c3f0a28c 611 return -1;
612 }
0ad19a3f 613
b1789442 614 DEBUG("mounted '%s' on '%s'", rootfs->path, mpath);
c69bd12f 615
b1789442 616 if (setup_rootfs_pivot_root(mpath, rootfs->pivot)) {
cc6f6dd7 617 ERROR("failed to setup pivot root");
25368b52 618 return -1;
c69bd12f
DL
619 }
620
25368b52 621 return 0;
0ad19a3f 622}
623
d852c78c 624static int setup_pts(int pts)
3c26f34e 625{
d852c78c
DL
626 if (!pts)
627 return 0;
3c26f34e 628
629 if (!access("/dev/pts/ptmx", F_OK) && umount("/dev/pts")) {
36eb9bde 630 SYSERROR("failed to umount 'dev/pts'");
3c26f34e 631 return -1;
632 }
633
2ac29abe 634 if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, "newinstance,ptmxmode=0666")) {
36eb9bde 635 SYSERROR("failed to mount a new instance of '/dev/pts'");
3c26f34e 636 return -1;
637 }
638
3c26f34e 639 if (access("/dev/ptmx", F_OK)) {
640 if (!symlink("/dev/pts/ptmx", "/dev/ptmx"))
641 goto out;
36eb9bde 642 SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'");
3c26f34e 643 return -1;
644 }
645
646 /* fallback here, /dev/pts/ptmx exists just mount bind */
647 if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) {
36eb9bde 648 SYSERROR("mount failed '/dev/pts/ptmx'->'/dev/ptmx'");
3c26f34e 649 return -1;
650 }
cd54d859
DL
651
652 INFO("created new pts instance");
d852c78c 653
3c26f34e 654out:
655 return 0;
656}
657
33fcb7a0
DL
658static int setup_console(const struct lxc_rootfs *rootfs,
659 const struct lxc_console *console)
6e590161 660{
63376d7d
DL
661 char path[MAXPATHLEN];
662 struct stat s;
52e35957 663
63376d7d 664 /* We don't have a rootfs, /dev/console will be shared */
33fcb7a0 665 if (!rootfs->path)
63376d7d 666 return 0;
52e35957 667
33fcb7a0 668 snprintf(path, sizeof(path), "%s/dev/console", rootfs->path);
52e35957 669
63376d7d
DL
670 if (access(path, F_OK)) {
671 WARN("rootfs specified but no console found");
672 return 0;
52e35957
DL
673 }
674
f78a1f32 675 if (console->peer == -1) {
63376d7d 676 INFO("no console output required");
f78a1f32
DL
677 return 0;
678 }
ed502555 679
63376d7d
DL
680 if (stat(path, &s)) {
681 SYSERROR("failed to stat '%s'", path);
682 return -1;
683 }
684
685 if (chmod(console->name, s.st_mode)) {
686 SYSERROR("failed to set mode '0%o' to '%s'",
687 s.st_mode, console->name);
688 return -1;
689 }
13954cce 690
63376d7d
DL
691 if (mount(console->name, path, "none", MS_BIND, 0)) {
692 ERROR("failed to mount '%s' on '%s'", console->name, path);
6e590161 693 return -1;
694 }
695
63376d7d 696 INFO("console has been setup");
cd54d859 697
6e590161 698 return 0;
699}
700
102a5303 701static int setup_cgroup(const char *name, struct lxc_list *cgroups)
576f946d 702{
102a5303
DL
703 struct lxc_list *iterator;
704 struct lxc_cgroup *cg;
88329c69 705 int ret = -1;
6f4a3756 706
102a5303
DL
707 if (lxc_list_empty(cgroups))
708 return 0;
6f4a3756 709
102a5303 710 lxc_list_for_each(iterator, cgroups) {
13954cce 711
102a5303 712 cg = iterator->elem;
6f4a3756 713
102a5303 714 if (lxc_cgroup_set(name, cg->subsystem, cg->value))
88329c69 715 goto out;
6f4a3756 716
102a5303 717 DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
6f4a3756 718 }
13954cce 719
88329c69 720 ret = 0;
cd54d859 721 INFO("cgroup has been setup");
88329c69
MN
722out:
723 return ret;
576f946d 724}
725
998ac676
RT
726static void parse_mntopt(char *opt, unsigned long *flags, char **data)
727{
728 struct mount_opt *mo;
729
730 /* If opt is found in mount_opt, set or clear flags.
731 * Otherwise append it to data. */
732
733 for (mo = &mount_opt[0]; mo->name != NULL; mo++) {
734 if (!strncmp(opt, mo->name, strlen(mo->name))) {
735 if (mo->clear)
736 *flags &= ~mo->flag;
737 else
738 *flags |= mo->flag;
739 return;
740 }
741 }
742
743 if (strlen(*data))
744 strcat(*data, ",");
745 strcat(*data, opt);
746}
747
748static int parse_mntopts(struct mntent *mntent, unsigned long *mntflags,
749 char **mntdata)
750{
751 char *s, *data;
752 char *p, *saveptr = NULL;
753
754 if (!mntent->mnt_opts)
755 return 0;
756
757 s = strdup(mntent->mnt_opts);
758 if (!s) {
36eb9bde 759 SYSERROR("failed to allocate memory");
998ac676
RT
760 return -1;
761 }
762
763 data = malloc(strlen(s) + 1);
764 if (!data) {
36eb9bde 765 SYSERROR("failed to allocate memory");
998ac676
RT
766 free(s);
767 return -1;
768 }
769 *data = 0;
770
771 for (p = strtok_r(s, ",", &saveptr); p != NULL;
772 p = strtok_r(NULL, ",", &saveptr))
773 parse_mntopt(p, mntflags, &data);
774
775 if (*data)
776 *mntdata = data;
777 else
778 free(data);
779 free(s);
780
781 return 0;
782}
783
e7938e9e 784static int mount_file_entries(FILE *file)
0ad19a3f 785{
0ad19a3f 786 struct mntent *mntent;
0ad19a3f 787 int ret = -1;
998ac676
RT
788 unsigned long mntflags;
789 char *mntdata;
0ad19a3f 790
998ac676 791 while ((mntent = getmntent(file))) {
1bc60a65 792
998ac676
RT
793 mntflags = 0;
794 mntdata = NULL;
795 if (parse_mntopts(mntent, &mntflags, &mntdata) < 0) {
36eb9bde 796 ERROR("failed to parse mount option '%s'",
998ac676
RT
797 mntent->mnt_opts);
798 goto out;
799 }
0ad19a3f 800
801 if (mount(mntent->mnt_fsname, mntent->mnt_dir,
e76b8764 802 mntent->mnt_type, mntflags & ~MS_REMOUNT, mntdata)) {
36eb9bde 803 SYSERROR("failed to mount '%s' on '%s'",
0ad19a3f 804 mntent->mnt_fsname, mntent->mnt_dir);
805 goto out;
806 }
998ac676 807
e76b8764
CDC
808 if ((mntflags & MS_REMOUNT) == MS_REMOUNT ||
809 ((mntflags & MS_BIND) == MS_BIND)) {
810
811 DEBUG ("remounting %s on %s to respect bind " \
812 "or remount options",
813 mntent->mnt_fsname, mntent->mnt_dir);
814
815 if (mount(mntent->mnt_fsname, mntent->mnt_dir,
816 mntent->mnt_type,
817 mntflags | MS_REMOUNT, mntdata)) {
818 SYSERROR("failed to mount '%s' on '%s'",
819 mntent->mnt_fsname, mntent->mnt_dir);
820 goto out;
821 }
822 }
823
cd54d859
DL
824 DEBUG("mounted %s on %s, type %s", mntent->mnt_fsname,
825 mntent->mnt_dir, mntent->mnt_type);
826
998ac676 827 free(mntdata);
0ad19a3f 828 }
cd54d859 829
0ad19a3f 830 ret = 0;
cd54d859
DL
831
832 INFO("mount points have been setup");
0ad19a3f 833out:
e7938e9e
MN
834 return ret;
835}
836
837static int setup_mount(const char *fstab)
838{
839 FILE *file;
840 int ret;
841
842 if (!fstab)
843 return 0;
844
845 file = setmntent(fstab, "r");
846 if (!file) {
847 SYSERROR("failed to use '%s'", fstab);
848 return -1;
849 }
850
851 ret = mount_file_entries(file);
852
0ad19a3f 853 endmntent(file);
854 return ret;
855}
856
e7938e9e
MN
857static int setup_mount_entries(struct lxc_list *mount)
858{
859 FILE *file;
860 struct lxc_list *iterator;
861 char *mount_entry;
862 int ret;
863
864 file = tmpfile();
865 if (!file) {
866 ERROR("tmpfile error: %m");
867 return -1;
868 }
869
870 lxc_list_for_each(iterator, mount) {
871 mount_entry = iterator->elem;
1d6b1976 872 fprintf(file, "%s\n", mount_entry);
e7938e9e
MN
873 }
874
875 rewind(file);
876
877 ret = mount_file_entries(file);
878
879 fclose(file);
880 return ret;
881}
882
81810dd1
DL
883static int setup_caps(struct lxc_list *caps)
884{
885 struct lxc_list *iterator;
886 char *drop_entry;
887 int i, capid;
888
889 lxc_list_for_each(iterator, caps) {
890
891 drop_entry = iterator->elem;
892
893 capid = -1;
894
895 for (i = 0; i < sizeof(caps_opt)/sizeof(caps_opt[0]); i++) {
896
897 if (strcmp(drop_entry, caps_opt[i].name))
898 continue;
899
900 capid = caps_opt[i].value;
901 break;
902 }
903
904 if (capid < 0) {
1e11be34
DL
905 ERROR("unknown capability %s", drop_entry);
906 return -1;
81810dd1
DL
907 }
908
909 DEBUG("drop capability '%s' (%d)", drop_entry, capid);
910
911 if (prctl(PR_CAPBSET_DROP, capid, 0, 0, 0)) {
912 SYSERROR("failed to remove %s capability", drop_entry);
913 return -1;
914 }
915
916 }
917
918 DEBUG("capabilities has been setup");
919
920 return 0;
921}
922
0ad19a3f 923static int setup_hw_addr(char *hwaddr, const char *ifname)
924{
925 struct sockaddr sockaddr;
926 struct ifreq ifr;
927 int ret, fd;
928
3cfc0f3a
MN
929 ret = lxc_convert_mac(hwaddr, &sockaddr);
930 if (ret) {
931 ERROR("mac address '%s' conversion failed : %s",
932 hwaddr, strerror(-ret));
0ad19a3f 933 return -1;
934 }
935
936 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
937 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
938
939 fd = socket(AF_INET, SOCK_DGRAM, 0);
940 if (fd < 0) {
3ab87b66 941 ERROR("socket failure : %s", strerror(errno));
0ad19a3f 942 return -1;
943 }
944
945 ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
946 close(fd);
947 if (ret)
3ab87b66 948 ERROR("ioctl failure : %s", strerror(errno));
0ad19a3f 949
cd54d859
DL
950 DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifname);
951
0ad19a3f 952 return ret;
953}
954
82d5ae15 955static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
0ad19a3f 956{
82d5ae15
DL
957 struct lxc_list *iterator;
958 struct lxc_inetdev *inetdev;
3cfc0f3a 959 int err;
0ad19a3f 960
82d5ae15
DL
961 lxc_list_for_each(iterator, ip) {
962
963 inetdev = iterator->elem;
964
0093bb8c
DL
965 err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
966 &inetdev->bcast, inetdev->prefix);
3cfc0f3a
MN
967 if (err) {
968 ERROR("failed to setup_ipv4_addr ifindex %d : %s",
969 ifindex, strerror(-err));
82d5ae15
DL
970 return -1;
971 }
972 }
973
974 return 0;
0ad19a3f 975}
976
82d5ae15 977static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
0ad19a3f 978{
82d5ae15 979 struct lxc_list *iterator;
7fa9074f 980 struct lxc_inet6dev *inet6dev;
3cfc0f3a 981 int err;
0ad19a3f 982
82d5ae15
DL
983 lxc_list_for_each(iterator, ip) {
984
985 inet6dev = iterator->elem;
986
b3df193c 987 err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
0093bb8c
DL
988 &inet6dev->mcast, &inet6dev->acast,
989 inet6dev->prefix);
3cfc0f3a
MN
990 if (err) {
991 ERROR("failed to setup_ipv6_addr ifindex %d : %s",
992 ifindex, strerror(-err));
82d5ae15 993 return -1;
3cfc0f3a 994 }
82d5ae15
DL
995 }
996
997 return 0;
0ad19a3f 998}
999
82d5ae15 1000static int setup_netdev(struct lxc_netdev *netdev)
0ad19a3f 1001{
0ad19a3f 1002 char ifname[IFNAMSIZ];
0ad19a3f 1003 char *current_ifname = ifname;
3cfc0f3a 1004 int err;
0ad19a3f 1005
82d5ae15
DL
1006 /* empty network namespace */
1007 if (!netdev->ifindex) {
1008 if (netdev->flags | IFF_UP) {
3cfc0f3a
MN
1009 err = lxc_device_up("lo");
1010 if (err) {
1011 ERROR("failed to set the loopback up : %s",
1012 strerror(-err));
82d5ae15
DL
1013 return -1;
1014 }
1015 return 0;
1016 }
0ad19a3f 1017 }
13954cce 1018
82d5ae15
DL
1019 /* retrieve the name of the interface */
1020 if (!if_indextoname(netdev->ifindex, current_ifname)) {
36eb9bde 1021 ERROR("no interface corresponding to index '%d'",
82d5ae15 1022 netdev->ifindex);
0ad19a3f 1023 return -1;
1024 }
13954cce 1025
018ef520 1026 /* default: let the system to choose one interface name */
9d083402 1027 if (!netdev->name)
fb6d9b2f
DL
1028 netdev->name = netdev->type == LXC_NET_PHYS ?
1029 netdev->link : "eth%d";
018ef520 1030
82d5ae15 1031 /* rename the interface name */
3cfc0f3a
MN
1032 err = lxc_device_rename(ifname, netdev->name);
1033 if (err) {
1034 ERROR("failed to rename %s->%s : %s", ifname, netdev->name,
1035 strerror(-err));
018ef520
DL
1036 return -1;
1037 }
1038
1039 /* Re-read the name of the interface because its name has changed
1040 * and would be automatically allocated by the system
1041 */
82d5ae15 1042 if (!if_indextoname(netdev->ifindex, current_ifname)) {
018ef520 1043 ERROR("no interface corresponding to index '%d'",
82d5ae15 1044 netdev->ifindex);
018ef520 1045 return -1;
0ad19a3f 1046 }
1047
82d5ae15
DL
1048 /* set a mac address */
1049 if (netdev->hwaddr) {
1050 if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
36eb9bde 1051 ERROR("failed to setup hw address for '%s'",
82d5ae15 1052 current_ifname);
0ad19a3f 1053 return -1;
1054 }
1055 }
1056
82d5ae15
DL
1057 /* setup ipv4 addresses on the interface */
1058 if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
36eb9bde 1059 ERROR("failed to setup ip addresses for '%s'",
0ad19a3f 1060 ifname);
1061 return -1;
1062 }
1063
82d5ae15
DL
1064 /* setup ipv6 addresses on the interface */
1065 if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
36eb9bde 1066 ERROR("failed to setup ipv6 addresses for '%s'",
0ad19a3f 1067 ifname);
1068 return -1;
1069 }
1070
82d5ae15
DL
1071 /* set the network device up */
1072 if (netdev->flags | IFF_UP) {
3cfc0f3a
MN
1073 int err;
1074
1075 err = lxc_device_up(current_ifname);
1076 if (err) {
1077 ERROR("failed to set '%s' up : %s", current_ifname,
1078 strerror(-err));
0ad19a3f 1079 return -1;
1080 }
1081
1082 /* the network is up, make the loopback up too */
3cfc0f3a
MN
1083 err = lxc_device_up("lo");
1084 if (err) {
1085 ERROR("failed to set the loopback up : %s",
1086 strerror(-err));
0ad19a3f 1087 return -1;
1088 }
1089 }
1090
cd54d859
DL
1091 DEBUG("'%s' has been setup", current_ifname);
1092
0ad19a3f 1093 return 0;
1094}
1095
5f4535a3 1096static int setup_network(struct lxc_list *network)
0ad19a3f 1097{
82d5ae15 1098 struct lxc_list *iterator;
82d5ae15 1099 struct lxc_netdev *netdev;
0ad19a3f 1100
5f4535a3 1101 lxc_list_for_each(iterator, network) {
cd54d859 1102
5f4535a3 1103 netdev = iterator->elem;
82d5ae15
DL
1104
1105 if (setup_netdev(netdev)) {
1106 ERROR("failed to setup netdev");
1107 return -1;
1108 }
1109 }
cd54d859 1110
5f4535a3
DL
1111 if (!lxc_list_empty(network))
1112 INFO("network has been setup");
cd54d859
DL
1113
1114 return 0;
0ad19a3f 1115}
1116
7b379ab3 1117struct lxc_conf *lxc_conf_init(void)
089cd8b8 1118{
7b379ab3
MN
1119 struct lxc_conf *new;
1120
1121 new = malloc(sizeof(*new));
1122 if (!new) {
1123 ERROR("lxc_conf_init : %m");
1124 return NULL;
1125 }
1126 memset(new, 0, sizeof(*new));
1127
28a4b0e5 1128 new->console.path = NULL;
63376d7d
DL
1129 new->console.peer = -1;
1130 new->console.master = -1;
1131 new->console.slave = -1;
1132 new->console.name[0] = '\0';
7b379ab3
MN
1133 lxc_list_init(&new->cgroup);
1134 lxc_list_init(&new->network);
1135 lxc_list_init(&new->mount_list);
81810dd1 1136 lxc_list_init(&new->caps);
7b379ab3
MN
1137
1138 return new;
089cd8b8
DL
1139}
1140
82d5ae15 1141static int instanciate_veth(struct lxc_netdev *netdev)
0ad19a3f 1142{
8634bc19 1143 char veth1buf[IFNAMSIZ], *veth1;
0e391e57 1144 char veth2buf[IFNAMSIZ], *veth2;
3cfc0f3a 1145 int err;
13954cce 1146
e892973e
DL
1147 if (netdev->priv.veth_attr.pair)
1148 veth1 = netdev->priv.veth_attr.pair;
8634bc19
MT
1149 else {
1150 snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
0e391e57 1151 veth1 = mktemp(veth1buf);
8634bc19 1152 }
82d5ae15 1153
0e391e57
DL
1154 snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
1155 veth2 = mktemp(veth2buf);
82d5ae15
DL
1156
1157 if (!strlen(veth1) || !strlen(veth2)) {
1158 ERROR("failed to allocate a temporary name");
1159 return -1;
0ad19a3f 1160 }
1161
3cfc0f3a
MN
1162 err = lxc_veth_create(veth1, veth2);
1163 if (err) {
1164 ERROR("failed to create %s-%s : %s", veth1, veth2,
1165 strerror(-err));
6ab9ab6d 1166 return -1;
0ad19a3f 1167 }
13954cce 1168
82d5ae15 1169 if (netdev->mtu) {
3cfc0f3a
MN
1170 err = lxc_device_set_mtu(veth1, atoi(netdev->mtu));
1171 if (!err)
1172 err = lxc_device_set_mtu(veth2, atoi(netdev->mtu));
1173 if (err) {
1174 ERROR("failed to set mtu '%s' for %s-%s : %s",
1175 netdev->mtu, veth1, veth2, strerror(-err));
eb14c10a 1176 goto out_delete;
75d09f83
DL
1177 }
1178 }
1179
3cfc0f3a
MN
1180 if (netdev->link) {
1181 err = lxc_bridge_attach(netdev->link, veth1);
1182 if (err) {
1183 ERROR("failed to attach '%s' to the bridge '%s' : %s",
1184 veth1, netdev->link, strerror(-err));
1185 goto out_delete;
1186 }
eb14c10a
DL
1187 }
1188
82d5ae15
DL
1189 netdev->ifindex = if_nametoindex(veth2);
1190 if (!netdev->ifindex) {
36eb9bde 1191 ERROR("failed to retrieve the index for %s", veth2);
eb14c10a
DL
1192 goto out_delete;
1193 }
1194
82d5ae15 1195 if (netdev->flags & IFF_UP) {
3cfc0f3a
MN
1196 err = lxc_device_up(veth1);
1197 if (err) {
1198 ERROR("failed to set %s up : %s", veth1,
1199 strerror(-err));
eb14c10a 1200 goto out_delete;
0ad19a3f 1201 }
1202 }
1203
82d5ae15
DL
1204 DEBUG("instanciated veth '%s/%s', index is '%d'",
1205 veth1, veth2, netdev->ifindex);
1206
6ab9ab6d 1207 return 0;
eb14c10a
DL
1208
1209out_delete:
1210 lxc_device_delete(veth1);
6ab9ab6d 1211 return -1;
13954cce 1212}
d957ae2d 1213
82d5ae15 1214static int instanciate_macvlan(struct lxc_netdev *netdev)
0ad19a3f 1215{
0e391e57 1216 char peerbuf[IFNAMSIZ], *peer;
3cfc0f3a 1217 int err;
d957ae2d
MT
1218
1219 if (!netdev->link) {
1220 ERROR("no link specified for macvlan netdev");
1221 return -1;
1222 }
13954cce 1223
0e391e57 1224 snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
82d5ae15 1225
0e391e57 1226 peer = mktemp(peerbuf);
82d5ae15
DL
1227 if (!strlen(peer)) {
1228 ERROR("failed to make a temporary name");
1229 return -1;
0ad19a3f 1230 }
1231
3cfc0f3a
MN
1232 err = lxc_macvlan_create(netdev->link, peer,
1233 netdev->priv.macvlan_attr.mode);
1234 if (err) {
1235 ERROR("failed to create macvlan interface '%s' on '%s' : %s",
1236 peer, netdev->link, strerror(-err));
d957ae2d 1237 return -1;
0ad19a3f 1238 }
1239
82d5ae15
DL
1240 netdev->ifindex = if_nametoindex(peer);
1241 if (!netdev->ifindex) {
36eb9bde 1242 ERROR("failed to retrieve the index for %s", peer);
d957ae2d
MT
1243 lxc_device_delete(peer);
1244 return -1;
22ebac19 1245 }
1246
e892973e
DL
1247 DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'",
1248 peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
0ad19a3f 1249
d957ae2d 1250 return 0;
0ad19a3f 1251}
1252
26c39028
JHS
1253/* XXX: merge with instanciate_macvlan */
1254static int instanciate_vlan(struct lxc_netdev *netdev)
1255{
1256 char peer[IFNAMSIZ];
3cfc0f3a 1257 int err;
26c39028
JHS
1258
1259 if (!netdev->link) {
1260 ERROR("no link specified for vlan netdev");
1261 return -1;
1262 }
1263
e892973e 1264 snprintf(peer, sizeof(peer), "vlan%d", netdev->priv.vlan_attr.vid);
26c39028 1265
3cfc0f3a
MN
1266 err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
1267 if (err) {
1268 ERROR("failed to create vlan interface '%s' on '%s' : %s",
1269 peer, netdev->link, strerror(-err));
26c39028
JHS
1270 return -1;
1271 }
1272
1273 netdev->ifindex = if_nametoindex(peer);
1274 if (!netdev->ifindex) {
1275 ERROR("failed to retrieve the ifindex for %s", peer);
1276 lxc_device_delete(peer);
1277 return -1;
1278 }
1279
e892973e
DL
1280 DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000",
1281 netdev->ifindex);
1282
26c39028
JHS
1283 return 0;
1284}
1285
82d5ae15 1286static int instanciate_phys(struct lxc_netdev *netdev)
0ad19a3f 1287{
9d083402 1288 netdev->ifindex = if_nametoindex(netdev->link);
82d5ae15 1289 if (!netdev->ifindex) {
9d083402 1290 ERROR("failed to retrieve the index for %s", netdev->link);
0ad19a3f 1291 return -1;
1292 }
1293
82d5ae15 1294 return 0;
0ad19a3f 1295}
1296
82d5ae15 1297static int instanciate_empty(struct lxc_netdev *netdev)
0ad19a3f 1298{
82d5ae15
DL
1299 netdev->ifindex = 0;
1300 return 0;
0ad19a3f 1301}
1302
5f4535a3 1303int lxc_create_network(struct lxc_list *network)
0ad19a3f 1304{
82d5ae15 1305 struct lxc_list *iterator;
82d5ae15 1306 struct lxc_netdev *netdev;
0ad19a3f 1307
5f4535a3 1308 lxc_list_for_each(iterator, network) {
0ad19a3f 1309
5f4535a3 1310 netdev = iterator->elem;
13954cce 1311
24654103 1312 if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) {
82d5ae15 1313 ERROR("invalid network configuration type '%d'",
5f4535a3 1314 netdev->type);
82d5ae15
DL
1315 return -1;
1316 }
0ad19a3f 1317
5f4535a3 1318 if (netdev_conf[netdev->type](netdev)) {
82d5ae15
DL
1319 ERROR("failed to create netdev");
1320 return -1;
1321 }
0ad19a3f 1322 }
1323
1324 return 0;
1325}
1326
7fef7a06
DL
1327void lxc_delete_network(struct lxc_list *network)
1328{
1329 struct lxc_list *iterator;
1330 struct lxc_netdev *netdev;
1331
1332 lxc_list_for_each(iterator, network) {
1333 netdev = iterator->elem;
1334 if (netdev->ifindex > 0)
1335 lxc_device_delete_index(netdev->ifindex);
1336 }
1337}
1338
5f4535a3 1339int lxc_assign_network(struct lxc_list *network, pid_t pid)
0ad19a3f 1340{
82d5ae15 1341 struct lxc_list *iterator;
82d5ae15 1342 struct lxc_netdev *netdev;
3cfc0f3a 1343 int err;
0ad19a3f 1344
5f4535a3 1345 lxc_list_for_each(iterator, network) {
82d5ae15 1346
5f4535a3 1347 netdev = iterator->elem;
82d5ae15 1348
236087a6
DL
1349 /* empty network namespace, nothing to move */
1350 if (!netdev->ifindex)
1351 continue;
1352
3cfc0f3a
MN
1353 err = lxc_device_move(netdev->ifindex, pid);
1354 if (err) {
1355 ERROR("failed to move '%s' to the container : %s",
1356 netdev->link, strerror(-err));
82d5ae15
DL
1357 return -1;
1358 }
1359
9d083402 1360 DEBUG("move '%s' to '%d'", netdev->link, pid);
0ad19a3f 1361 }
1362
1363 return 0;
1364}
1365
5e4a62bf 1366int lxc_create_tty(const char *name, struct lxc_conf *conf)
b0a33c1e 1367{
5e4a62bf 1368 struct lxc_tty_info *tty_info = &conf->tty_info;
985d15b1 1369 int i;
b0a33c1e 1370
5e4a62bf
DL
1371 /* no tty in the configuration */
1372 if (!conf->tty)
b0a33c1e 1373 return 0;
1374
13954cce 1375 tty_info->pty_info =
e4e7d59d 1376 malloc(sizeof(*tty_info->pty_info)*conf->tty);
b0a33c1e 1377 if (!tty_info->pty_info) {
36eb9bde 1378 SYSERROR("failed to allocate pty_info");
985d15b1 1379 return -1;
b0a33c1e 1380 }
1381
985d15b1 1382 for (i = 0; i < conf->tty; i++) {
13954cce 1383
b0a33c1e 1384 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
1385
13954cce 1386 if (openpty(&pty_info->master, &pty_info->slave,
b0a33c1e 1387 pty_info->name, NULL, NULL)) {
36eb9bde 1388 SYSERROR("failed to create pty #%d", i);
985d15b1
MT
1389 tty_info->nbtty = i;
1390 lxc_delete_tty(tty_info);
1391 return -1;
b0a33c1e 1392 }
1393
5332bb84
DL
1394 DEBUG("allocated pty '%s' (%d/%d)",
1395 pty_info->name, pty_info->master, pty_info->slave);
1396
b035ad62
MS
1397 /* Prevent leaking the file descriptors to the container */
1398 fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
1399 fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
1400
b0a33c1e 1401 pty_info->busy = 0;
1402 }
1403
985d15b1 1404 tty_info->nbtty = conf->tty;
1ac470c0
DL
1405
1406 INFO("tty's configured");
1407
985d15b1 1408 return 0;
b0a33c1e 1409}
1410
1411void lxc_delete_tty(struct lxc_tty_info *tty_info)
1412{
1413 int i;
1414
1415 for (i = 0; i < tty_info->nbtty; i++) {
1416 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
1417
1418 close(pty_info->master);
1419 close(pty_info->slave);
1420 }
1421
1422 free(tty_info->pty_info);
1423 tty_info->nbtty = 0;
1424}
1425
571e6ec8 1426int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
0ad19a3f 1427{
571e6ec8 1428 if (setup_utsname(lxc_conf->utsname)) {
36eb9bde 1429 ERROR("failed to setup the utsname for '%s'", name);
95b5ffaf 1430 return -1;
0ad19a3f 1431 }
1432
5f4535a3 1433 if (setup_network(&lxc_conf->network)) {
36eb9bde 1434 ERROR("failed to setup the network for '%s'", name);
95b5ffaf 1435 return -1;
0ad19a3f 1436 }
1437
571e6ec8 1438 if (setup_cgroup(name, &lxc_conf->cgroup)) {
36eb9bde 1439 ERROR("failed to setup the cgroups for '%s'", name);
95b5ffaf 1440 return -1;
0ad19a3f 1441 }
1442
571e6ec8 1443 if (setup_mount(lxc_conf->fstab)) {
36eb9bde 1444 ERROR("failed to setup the mounts for '%s'", name);
95b5ffaf 1445 return -1;
576f946d 1446 }
1447
e7938e9e
MN
1448 if (setup_mount_entries(&lxc_conf->mount_list)) {
1449 ERROR("failed to setup the mount entries for '%s'", name);
1450 return -1;
1451 }
1452
33fcb7a0 1453 if (setup_console(&lxc_conf->rootfs, &lxc_conf->console)) {
36eb9bde 1454 ERROR("failed to setup the console for '%s'", name);
95b5ffaf 1455 return -1;
6e590161 1456 }
1457
33fcb7a0 1458 if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info)) {
36eb9bde 1459 ERROR("failed to setup the ttys for '%s'", name);
95b5ffaf 1460 return -1;
b0a33c1e 1461 }
1462
33fcb7a0 1463 if (setup_rootfs(&lxc_conf->rootfs)) {
36eb9bde 1464 ERROR("failed to set rootfs for '%s'", name);
95b5ffaf 1465 return -1;
ed502555 1466 }
1467
571e6ec8 1468 if (setup_pts(lxc_conf->pts)) {
36eb9bde 1469 ERROR("failed to setup the new pts instance");
95b5ffaf 1470 return -1;
3c26f34e 1471 }
1472
81810dd1
DL
1473 if (setup_caps(&lxc_conf->caps)) {
1474 ERROR("failed to drop capabilities");
1475 return -1;
1476 }
1477
cd54d859
DL
1478 NOTICE("'%s' is setup.", name);
1479
0ad19a3f 1480 return 0;
1481}