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