]>
Commit | Line | Data |
---|---|---|
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> | |
41 | ||
42 | #include <arpa/inet.h> | |
43 | #include <fcntl.h> | |
44 | #include <netinet/in.h> | |
45 | #include <net/if.h> | |
6f4a3756 | 46 | #include <libgen.h> |
0ad19a3f | 47 | |
e5bda9ee | 48 | #include "network.h" |
49 | #include "error.h" | |
b2718c72 | 50 | #include "parse.h" |
881450bb | 51 | #include "config.h" |
e5bda9ee | 52 | |
00b3c2e2 | 53 | #include <lxc/conf.h> |
36eb9bde | 54 | #include <lxc/log.h> |
00b3c2e2 | 55 | #include <lxc/lxc.h> /* for lxc_cgroup_set() */ |
36eb9bde CLG |
56 | |
57 | lxc_log_define(lxc_conf, lxc); | |
e5bda9ee | 58 | |
0ad19a3f | 59 | #define MAXHWLEN 18 |
60 | #define MAXINDEXLEN 20 | |
442cbbe6 | 61 | #define MAXMTULEN 16 |
0ad19a3f | 62 | #define MAXLINELEN 128 |
63 | ||
fdc03323 DL |
64 | #ifndef MS_REC |
65 | #define MS_REC 16384 | |
66 | #endif | |
67 | ||
82d5ae15 | 68 | typedef int (*instanciate_cb)(struct lxc_netdev *); |
0ad19a3f | 69 | |
998ac676 RT |
70 | struct mount_opt { |
71 | char *name; | |
72 | int clear; | |
73 | int flag; | |
74 | }; | |
75 | ||
82d5ae15 DL |
76 | static int instanciate_veth(struct lxc_netdev *); |
77 | static int instanciate_macvlan(struct lxc_netdev *); | |
26c39028 | 78 | static int instanciate_vlan(struct lxc_netdev *); |
82d5ae15 DL |
79 | static int instanciate_phys(struct lxc_netdev *); |
80 | static int instanciate_empty(struct lxc_netdev *); | |
81 | ||
82 | static instanciate_cb netdev_conf[MAXCONFTYPE + 1] = { | |
83 | [VETH] = instanciate_veth, | |
84 | [MACVLAN] = instanciate_macvlan, | |
26c39028 | 85 | [VLAN] = instanciate_vlan, |
82d5ae15 DL |
86 | [PHYS] = instanciate_phys, |
87 | [EMPTY] = instanciate_empty, | |
0ad19a3f | 88 | }; |
89 | ||
998ac676 RT |
90 | static struct mount_opt mount_opt[] = { |
91 | { "defaults", 0, 0 }, | |
92 | { "ro", 0, MS_RDONLY }, | |
93 | { "rw", 1, MS_RDONLY }, | |
94 | { "suid", 1, MS_NOSUID }, | |
95 | { "nosuid", 0, MS_NOSUID }, | |
96 | { "dev", 1, MS_NODEV }, | |
97 | { "nodev", 0, MS_NODEV }, | |
98 | { "exec", 1, MS_NOEXEC }, | |
99 | { "noexec", 0, MS_NOEXEC }, | |
100 | { "sync", 0, MS_SYNCHRONOUS }, | |
101 | { "async", 1, MS_SYNCHRONOUS }, | |
102 | { "remount", 0, MS_REMOUNT }, | |
103 | { "mand", 0, MS_MANDLOCK }, | |
104 | { "nomand", 1, MS_MANDLOCK }, | |
105 | { "atime", 1, MS_NOATIME }, | |
106 | { "noatime", 0, MS_NOATIME }, | |
107 | { "diratime", 1, MS_NODIRATIME }, | |
108 | { "nodiratime", 0, MS_NODIRATIME }, | |
109 | { "bind", 0, MS_BIND }, | |
110 | { "rbind", 0, MS_BIND|MS_REC }, | |
111 | { NULL, 0, 0 }, | |
112 | }; | |
113 | ||
78ae2fcc | 114 | static int configure_find_fstype_cb(void* buffer, void *data) |
115 | { | |
116 | struct cbarg { | |
117 | const char *rootfs; | |
118 | const char *testdir; | |
119 | char *fstype; | |
120 | int mntopt; | |
121 | } *cbarg = data; | |
122 | ||
123 | char *fstype; | |
124 | ||
125 | /* we don't try 'nodev' entries */ | |
126 | if (strstr(buffer, "nodev")) | |
127 | return 0; | |
128 | ||
129 | fstype = buffer; | |
b2718c72 | 130 | fstype += lxc_char_left_gc(fstype, strlen(fstype)); |
131 | fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0'; | |
78ae2fcc | 132 | |
133 | if (mount(cbarg->rootfs, cbarg->testdir, fstype, cbarg->mntopt, NULL)) | |
134 | return 0; | |
135 | ||
136 | /* found ! */ | |
137 | umount(cbarg->testdir); | |
138 | strcpy(cbarg->fstype, fstype); | |
139 | ||
140 | return 1; | |
141 | } | |
142 | ||
143 | /* find the filesystem type with brute force */ | |
144 | static int configure_find_fstype(const char *rootfs, char *fstype, int mntopt) | |
145 | { | |
146 | int i, found; | |
147 | char buffer[MAXPATHLEN]; | |
148 | ||
149 | struct cbarg { | |
150 | const char *rootfs; | |
151 | const char *testdir; | |
152 | char *fstype; | |
153 | int mntopt; | |
154 | } cbarg = { | |
155 | .rootfs = rootfs, | |
156 | .fstype = fstype, | |
157 | .mntopt = mntopt, | |
158 | }; | |
159 | ||
160 | /* first we check with /etc/filesystems, in case the modules | |
161 | * are auto-loaded and fall back to the supported kernel fs | |
162 | */ | |
163 | char *fsfile[] = { | |
164 | "/etc/filesystems", | |
165 | "/proc/filesystems", | |
166 | }; | |
167 | ||
168 | cbarg.testdir = tempnam("/tmp", "lxc-"); | |
169 | if (!cbarg.testdir) { | |
36eb9bde | 170 | SYSERROR("failed to build a temp name"); |
78ae2fcc | 171 | return -1; |
172 | } | |
173 | ||
174 | if (mkdir(cbarg.testdir, 0755)) { | |
36eb9bde | 175 | SYSERROR("failed to create temporary directory"); |
78ae2fcc | 176 | return -1; |
177 | } | |
178 | ||
179 | for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) { | |
180 | ||
b2718c72 | 181 | found = lxc_file_for_each_line(fsfile[i], |
182 | configure_find_fstype_cb, | |
183 | buffer, sizeof(buffer), &cbarg); | |
78ae2fcc | 184 | |
185 | if (found < 0) { | |
36eb9bde | 186 | SYSERROR("failed to read '%s'", fsfile[i]); |
78ae2fcc | 187 | goto out; |
188 | } | |
189 | ||
190 | if (found) | |
191 | break; | |
192 | } | |
193 | ||
194 | if (!found) { | |
36eb9bde | 195 | ERROR("failed to determine fs type for '%s'", rootfs); |
78ae2fcc | 196 | goto out; |
197 | } | |
198 | ||
199 | out: | |
200 | rmdir(cbarg.testdir); | |
201 | return found - 1; | |
202 | } | |
203 | ||
204 | static int configure_rootfs_dir_cb(const char *rootfs, const char *absrootfs, | |
205 | FILE *f) | |
206 | { | |
fdc03323 | 207 | return fprintf(f, "%s %s none rbind 0 0\n", absrootfs, rootfs); |
78ae2fcc | 208 | } |
209 | ||
210 | static int configure_rootfs_blk_cb(const char *rootfs, const char *absrootfs, | |
211 | FILE *f) | |
212 | { | |
213 | char fstype[MAXPATHLEN]; | |
214 | ||
215 | if (configure_find_fstype(absrootfs, fstype, 0)) { | |
36eb9bde | 216 | ERROR("failed to configure mount for block device '%s'", |
78ae2fcc | 217 | absrootfs); |
218 | return -1; | |
219 | } | |
220 | ||
221 | return fprintf(f, "%s %s %s defaults 0 0\n", absrootfs, rootfs, fstype); | |
222 | } | |
223 | ||
eae6543d | 224 | static int configure_rootfs(const char *name, const char *rootfs) |
0ad19a3f | 225 | { |
226 | char path[MAXPATHLEN]; | |
b09ef133 | 227 | char absrootfs[MAXPATHLEN]; |
9b0f0477 | 228 | char fstab[MAXPATHLEN]; |
78ae2fcc | 229 | struct stat s; |
9b0f0477 | 230 | FILE *f; |
78ae2fcc | 231 | int i, ret; |
232 | ||
233 | typedef int (*rootfs_cb)(const char *, const char *, FILE *); | |
234 | ||
235 | struct rootfs_type { | |
236 | int type; | |
237 | rootfs_cb cb; | |
238 | } rtfs_type[] = { | |
239 | { __S_IFDIR, configure_rootfs_dir_cb }, | |
240 | { __S_IFBLK, configure_rootfs_blk_cb }, | |
241 | }; | |
0ad19a3f | 242 | |
4c8ab83b | 243 | if (!realpath(rootfs, absrootfs)) { |
36eb9bde | 244 | SYSERROR("failed to get real path for '%s'", rootfs); |
4c8ab83b | 245 | return -1; |
246 | } | |
b09ef133 | 247 | |
4c8ab83b | 248 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name); |
b09ef133 | 249 | |
78ae2fcc | 250 | if (mkdir(path, 0755)) { |
36eb9bde | 251 | SYSERROR("failed to create the '%s' directory", path); |
78ae2fcc | 252 | return -1; |
253 | } | |
254 | ||
b09ef133 | 255 | if (access(absrootfs, F_OK)) { |
36eb9bde | 256 | SYSERROR("'%s' is not accessible", absrootfs); |
b09ef133 | 257 | return -1; |
258 | } | |
259 | ||
78ae2fcc | 260 | if (stat(absrootfs, &s)) { |
36eb9bde | 261 | SYSERROR("failed to stat '%s'", absrootfs); |
9b0f0477 | 262 | return -1; |
263 | } | |
264 | ||
78ae2fcc | 265 | for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) { |
9b0f0477 | 266 | |
78ae2fcc | 267 | if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type)) |
268 | continue; | |
9b0f0477 | 269 | |
78ae2fcc | 270 | snprintf(fstab, MAXPATHLEN, LXCPATH "/%s/fstab", name); |
4c8ab83b | 271 | |
78ae2fcc | 272 | f = fopen(fstab, "a+"); |
273 | if (!f) { | |
36eb9bde | 274 | SYSERROR("failed to open fstab file"); |
78ae2fcc | 275 | return -1; |
276 | } | |
9b0f0477 | 277 | |
78ae2fcc | 278 | ret = rtfs_type[i].cb(path, absrootfs, f); |
9b0f0477 | 279 | |
78ae2fcc | 280 | fclose(f); |
281 | ||
282 | if (ret < 0) { | |
36eb9bde | 283 | ERROR("failed to add rootfs mount in fstab"); |
78ae2fcc | 284 | return -1; |
285 | } | |
286 | ||
287 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs/rootfs", name); | |
288 | ||
289 | return symlink(absrootfs, path); | |
290 | } | |
9b0f0477 | 291 | |
36eb9bde | 292 | ERROR("unsupported rootfs type for '%s'", absrootfs); |
78ae2fcc | 293 | return -1; |
0ad19a3f | 294 | } |
295 | ||
4e5440c6 | 296 | static int setup_utsname(struct utsname *utsname) |
0ad19a3f | 297 | { |
4e5440c6 DL |
298 | if (!utsname) |
299 | return 0; | |
0ad19a3f | 300 | |
4e5440c6 DL |
301 | if (sethostname(utsname->nodename, strlen(utsname->nodename))) { |
302 | SYSERROR("failed to set the hostname to '%s'", utsname->nodename); | |
0ad19a3f | 303 | return -1; |
304 | } | |
305 | ||
4e5440c6 | 306 | INFO("'%s' hostname has been setup", utsname->nodename); |
cd54d859 | 307 | |
0ad19a3f | 308 | return 0; |
309 | } | |
310 | ||
52e35957 | 311 | static int setup_tty(const char *rootfs, const struct lxc_tty_info *tty_info) |
b0a33c1e | 312 | { |
313 | char path[MAXPATHLEN]; | |
314 | int i; | |
315 | ||
316 | for (i = 0; i < tty_info->nbtty; i++) { | |
317 | ||
318 | struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; | |
319 | ||
52e35957 DL |
320 | snprintf(path, sizeof(path), "%s/dev/tty%d", |
321 | rootfs ? rootfs : "", i + 1); | |
b0a33c1e | 322 | |
13954cce | 323 | /* At this point I can not use the "access" function |
b0a33c1e | 324 | * to check the file is present or not because it fails |
325 | * with EACCES errno and I don't know why :( */ | |
13954cce | 326 | |
b0a33c1e | 327 | if (mount(pty_info->name, path, "none", MS_BIND, 0)) { |
36eb9bde | 328 | WARN("failed to mount '%s'->'%s'", |
52e35957 | 329 | pty_info->name, path); |
b0a33c1e | 330 | continue; |
331 | } | |
332 | } | |
333 | ||
cd54d859 DL |
334 | INFO("%d tty(s) has been setup", tty_info->nbtty); |
335 | ||
b0a33c1e | 336 | return 0; |
337 | } | |
338 | ||
c69bd12f | 339 | static int setup_rootfs(const char *rootfs) |
0ad19a3f | 340 | { |
c69bd12f DL |
341 | char *tmpname; |
342 | int ret = -1; | |
0ad19a3f | 343 | |
c69bd12f DL |
344 | if (!rootfs) |
345 | return 0; | |
0ad19a3f | 346 | |
c69bd12f DL |
347 | tmpname = tempnam("/tmp", "lxc-rootfs"); |
348 | if (!tmpname) { | |
349 | SYSERROR("failed to generate temporary name"); | |
c3f0a28c | 350 | return -1; |
351 | } | |
0ad19a3f | 352 | |
c69bd12f DL |
353 | if (mkdir(tmpname, 0700)) { |
354 | SYSERROR("failed to create temporary directory '%s'", tmpname); | |
355 | return -1; | |
356 | } | |
357 | ||
358 | if (mount(rootfs, tmpname, "none", MS_BIND|MS_REC, NULL)) { | |
359 | SYSERROR("failed to mount '%s'->'%s'", rootfs, tmpname); | |
360 | goto out; | |
361 | } | |
362 | ||
363 | if (chroot(tmpname)) { | |
364 | SYSERROR("failed to set chroot %s", tmpname); | |
365 | goto out; | |
366 | } | |
367 | ||
c3f0a28c | 368 | if (chdir(getenv("HOME")) && chdir("/")) { |
36eb9bde | 369 | SYSERROR("failed to change to home directory"); |
c69bd12f | 370 | goto out; |
0ad19a3f | 371 | } |
372 | ||
c69bd12f | 373 | INFO("chrooted to '%s'", rootfs); |
cd54d859 | 374 | |
c69bd12f DL |
375 | ret = 0; |
376 | out: | |
377 | rmdir(tmpname); | |
378 | return ret; | |
0ad19a3f | 379 | } |
380 | ||
d852c78c | 381 | static int setup_pts(int pts) |
3c26f34e | 382 | { |
d852c78c DL |
383 | if (!pts) |
384 | return 0; | |
3c26f34e | 385 | |
386 | if (!access("/dev/pts/ptmx", F_OK) && umount("/dev/pts")) { | |
36eb9bde | 387 | SYSERROR("failed to umount 'dev/pts'"); |
3c26f34e | 388 | return -1; |
389 | } | |
390 | ||
d852c78c | 391 | if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, "newinstance")) { |
36eb9bde | 392 | SYSERROR("failed to mount a new instance of '/dev/pts'"); |
3c26f34e | 393 | return -1; |
394 | } | |
395 | ||
396 | if (chmod("/dev/pts/ptmx", 0666)) { | |
36eb9bde | 397 | SYSERROR("failed to set permission for '/dev/pts/ptmx'"); |
3c26f34e | 398 | return -1; |
399 | } | |
400 | ||
401 | if (access("/dev/ptmx", F_OK)) { | |
402 | if (!symlink("/dev/pts/ptmx", "/dev/ptmx")) | |
403 | goto out; | |
36eb9bde | 404 | SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'"); |
3c26f34e | 405 | return -1; |
406 | } | |
407 | ||
408 | /* fallback here, /dev/pts/ptmx exists just mount bind */ | |
409 | if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) { | |
36eb9bde | 410 | SYSERROR("mount failed '/dev/pts/ptmx'->'/dev/ptmx'"); |
3c26f34e | 411 | return -1; |
412 | } | |
cd54d859 DL |
413 | |
414 | INFO("created new pts instance"); | |
d852c78c | 415 | |
3c26f34e | 416 | out: |
417 | return 0; | |
418 | } | |
419 | ||
52e35957 | 420 | static int setup_console(const char *rootfs, const char *tty) |
6e590161 | 421 | { |
ed502555 | 422 | char console[MAXPATHLEN]; |
423 | ||
52e35957 DL |
424 | snprintf(console, sizeof(console), "%s/dev/console", |
425 | rootfs ? rootfs : ""); | |
426 | ||
427 | /* we have the rootfs with /dev/console but no tty | |
428 | * to be used as console, let's remap /dev/console | |
429 | * to /dev/null to avoid to log to the system console | |
430 | */ | |
431 | if (rootfs && !tty[0]) { | |
432 | ||
433 | if (!access(console, F_OK)) { | |
434 | ||
435 | if (mount("/dev/null", console, "none", MS_BIND, 0)) { | |
436 | SYSERROR("failed to mount '/dev/null'->'%s'", | |
437 | console); | |
438 | return -1; | |
439 | } | |
440 | } | |
441 | } | |
442 | ||
443 | if (!tty[0]) | |
444 | return 0; | |
ed502555 | 445 | |
446 | if (access(console, R_OK|W_OK)) | |
6e590161 | 447 | return 0; |
13954cce | 448 | |
ed502555 | 449 | if (mount(tty, console, "none", MS_BIND, 0)) { |
36eb9bde | 450 | ERROR("failed to mount the console"); |
6e590161 | 451 | return -1; |
452 | } | |
453 | ||
cd54d859 DL |
454 | INFO("console '%s' mounted to '%s'", tty, console); |
455 | ||
6e590161 | 456 | return 0; |
457 | } | |
458 | ||
102a5303 | 459 | static int setup_cgroup(const char *name, struct lxc_list *cgroups) |
576f946d | 460 | { |
102a5303 DL |
461 | struct lxc_list *iterator; |
462 | struct lxc_cgroup *cg; | |
88329c69 | 463 | int ret = -1; |
6f4a3756 | 464 | |
102a5303 DL |
465 | if (lxc_list_empty(cgroups)) |
466 | return 0; | |
6f4a3756 | 467 | |
102a5303 | 468 | lxc_list_for_each(iterator, cgroups) { |
13954cce | 469 | |
102a5303 | 470 | cg = iterator->elem; |
6f4a3756 | 471 | |
102a5303 | 472 | if (lxc_cgroup_set(name, cg->subsystem, cg->value)) |
88329c69 | 473 | goto out; |
6f4a3756 | 474 | |
102a5303 | 475 | DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value); |
6f4a3756 | 476 | } |
13954cce | 477 | |
88329c69 | 478 | ret = 0; |
cd54d859 | 479 | INFO("cgroup has been setup"); |
88329c69 MN |
480 | out: |
481 | return ret; | |
576f946d | 482 | } |
483 | ||
998ac676 RT |
484 | static void parse_mntopt(char *opt, unsigned long *flags, char **data) |
485 | { | |
486 | struct mount_opt *mo; | |
487 | ||
488 | /* If opt is found in mount_opt, set or clear flags. | |
489 | * Otherwise append it to data. */ | |
490 | ||
491 | for (mo = &mount_opt[0]; mo->name != NULL; mo++) { | |
492 | if (!strncmp(opt, mo->name, strlen(mo->name))) { | |
493 | if (mo->clear) | |
494 | *flags &= ~mo->flag; | |
495 | else | |
496 | *flags |= mo->flag; | |
497 | return; | |
498 | } | |
499 | } | |
500 | ||
501 | if (strlen(*data)) | |
502 | strcat(*data, ","); | |
503 | strcat(*data, opt); | |
504 | } | |
505 | ||
506 | static int parse_mntopts(struct mntent *mntent, unsigned long *mntflags, | |
507 | char **mntdata) | |
508 | { | |
509 | char *s, *data; | |
510 | char *p, *saveptr = NULL; | |
511 | ||
512 | if (!mntent->mnt_opts) | |
513 | return 0; | |
514 | ||
515 | s = strdup(mntent->mnt_opts); | |
516 | if (!s) { | |
36eb9bde | 517 | SYSERROR("failed to allocate memory"); |
998ac676 RT |
518 | return -1; |
519 | } | |
520 | ||
521 | data = malloc(strlen(s) + 1); | |
522 | if (!data) { | |
36eb9bde | 523 | SYSERROR("failed to allocate memory"); |
998ac676 RT |
524 | free(s); |
525 | return -1; | |
526 | } | |
527 | *data = 0; | |
528 | ||
529 | for (p = strtok_r(s, ",", &saveptr); p != NULL; | |
530 | p = strtok_r(NULL, ",", &saveptr)) | |
531 | parse_mntopt(p, mntflags, &data); | |
532 | ||
533 | if (*data) | |
534 | *mntdata = data; | |
535 | else | |
536 | free(data); | |
537 | free(s); | |
538 | ||
539 | return 0; | |
540 | } | |
541 | ||
e7938e9e | 542 | static int mount_file_entries(FILE *file) |
0ad19a3f | 543 | { |
0ad19a3f | 544 | struct mntent *mntent; |
0ad19a3f | 545 | int ret = -1; |
998ac676 RT |
546 | unsigned long mntflags; |
547 | char *mntdata; | |
0ad19a3f | 548 | |
998ac676 | 549 | while ((mntent = getmntent(file))) { |
1bc60a65 | 550 | |
998ac676 RT |
551 | mntflags = 0; |
552 | mntdata = NULL; | |
553 | if (parse_mntopts(mntent, &mntflags, &mntdata) < 0) { | |
36eb9bde | 554 | ERROR("failed to parse mount option '%s'", |
998ac676 RT |
555 | mntent->mnt_opts); |
556 | goto out; | |
557 | } | |
0ad19a3f | 558 | |
559 | if (mount(mntent->mnt_fsname, mntent->mnt_dir, | |
998ac676 | 560 | mntent->mnt_type, mntflags, mntdata)) { |
36eb9bde | 561 | SYSERROR("failed to mount '%s' on '%s'", |
0ad19a3f | 562 | mntent->mnt_fsname, mntent->mnt_dir); |
563 | goto out; | |
564 | } | |
998ac676 | 565 | |
cd54d859 DL |
566 | DEBUG("mounted %s on %s, type %s", mntent->mnt_fsname, |
567 | mntent->mnt_dir, mntent->mnt_type); | |
568 | ||
998ac676 | 569 | free(mntdata); |
0ad19a3f | 570 | } |
cd54d859 | 571 | |
0ad19a3f | 572 | ret = 0; |
cd54d859 DL |
573 | |
574 | INFO("mount points have been setup"); | |
0ad19a3f | 575 | out: |
e7938e9e MN |
576 | return ret; |
577 | } | |
578 | ||
579 | static int setup_mount(const char *fstab) | |
580 | { | |
581 | FILE *file; | |
582 | int ret; | |
583 | ||
584 | if (!fstab) | |
585 | return 0; | |
586 | ||
587 | file = setmntent(fstab, "r"); | |
588 | if (!file) { | |
589 | SYSERROR("failed to use '%s'", fstab); | |
590 | return -1; | |
591 | } | |
592 | ||
593 | ret = mount_file_entries(file); | |
594 | ||
0ad19a3f | 595 | endmntent(file); |
596 | return ret; | |
597 | } | |
598 | ||
e7938e9e MN |
599 | static int setup_mount_entries(struct lxc_list *mount) |
600 | { | |
601 | FILE *file; | |
602 | struct lxc_list *iterator; | |
603 | char *mount_entry; | |
604 | int ret; | |
605 | ||
606 | file = tmpfile(); | |
607 | if (!file) { | |
608 | ERROR("tmpfile error: %m"); | |
609 | return -1; | |
610 | } | |
611 | ||
612 | lxc_list_for_each(iterator, mount) { | |
613 | mount_entry = iterator->elem; | |
614 | fprintf(file, "%s", mount_entry); | |
615 | } | |
616 | ||
617 | rewind(file); | |
618 | ||
619 | ret = mount_file_entries(file); | |
620 | ||
621 | fclose(file); | |
622 | return ret; | |
623 | } | |
624 | ||
0ad19a3f | 625 | static int setup_hw_addr(char *hwaddr, const char *ifname) |
626 | { | |
627 | struct sockaddr sockaddr; | |
628 | struct ifreq ifr; | |
629 | int ret, fd; | |
630 | ||
631 | if (lxc_convert_mac(hwaddr, &sockaddr)) { | |
3ab87b66 | 632 | ERROR("conversion has failed"); |
0ad19a3f | 633 | return -1; |
634 | } | |
635 | ||
636 | memcpy(ifr.ifr_name, ifname, IFNAMSIZ); | |
637 | memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr)); | |
638 | ||
639 | fd = socket(AF_INET, SOCK_DGRAM, 0); | |
640 | if (fd < 0) { | |
3ab87b66 | 641 | ERROR("socket failure : %s", strerror(errno)); |
0ad19a3f | 642 | return -1; |
643 | } | |
644 | ||
645 | ret = ioctl(fd, SIOCSIFHWADDR, &ifr); | |
646 | close(fd); | |
647 | if (ret) | |
3ab87b66 | 648 | ERROR("ioctl failure : %s", strerror(errno)); |
0ad19a3f | 649 | |
cd54d859 DL |
650 | DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifname); |
651 | ||
0ad19a3f | 652 | return ret; |
653 | } | |
654 | ||
82d5ae15 | 655 | static int setup_ipv4_addr(struct lxc_list *ip, int ifindex) |
0ad19a3f | 656 | { |
82d5ae15 DL |
657 | struct lxc_list *iterator; |
658 | struct lxc_inetdev *inetdev; | |
0ad19a3f | 659 | |
82d5ae15 DL |
660 | lxc_list_for_each(iterator, ip) { |
661 | ||
662 | inetdev = iterator->elem; | |
663 | ||
4bf1968d DL |
664 | if (lxc_ip_addr_add(AF_INET, ifindex, |
665 | &inetdev->addr, inetdev->prefix)) { | |
82d5ae15 DL |
666 | return -1; |
667 | } | |
668 | } | |
669 | ||
670 | return 0; | |
0ad19a3f | 671 | } |
672 | ||
82d5ae15 | 673 | static int setup_ipv6_addr(struct lxc_list *ip, int ifindex) |
0ad19a3f | 674 | { |
82d5ae15 | 675 | struct lxc_list *iterator; |
7fa9074f | 676 | struct lxc_inet6dev *inet6dev; |
0ad19a3f | 677 | |
82d5ae15 DL |
678 | lxc_list_for_each(iterator, ip) { |
679 | ||
680 | inet6dev = iterator->elem; | |
681 | ||
4bf1968d DL |
682 | if (lxc_ip_addr_add(AF_INET6, ifindex, |
683 | & inet6dev->addr, inet6dev->prefix)) | |
82d5ae15 | 684 | return -1; |
82d5ae15 DL |
685 | } |
686 | ||
687 | return 0; | |
0ad19a3f | 688 | } |
689 | ||
82d5ae15 | 690 | static int setup_netdev(struct lxc_netdev *netdev) |
0ad19a3f | 691 | { |
0ad19a3f | 692 | char ifname[IFNAMSIZ]; |
0ad19a3f | 693 | char *current_ifname = ifname; |
0ad19a3f | 694 | |
82d5ae15 DL |
695 | /* empty network namespace */ |
696 | if (!netdev->ifindex) { | |
697 | if (netdev->flags | IFF_UP) { | |
698 | if (lxc_device_up("lo")) { | |
699 | ERROR("failed to set the loopback up"); | |
700 | return -1; | |
701 | } | |
702 | return 0; | |
703 | } | |
0ad19a3f | 704 | } |
13954cce | 705 | |
82d5ae15 DL |
706 | /* retrieve the name of the interface */ |
707 | if (!if_indextoname(netdev->ifindex, current_ifname)) { | |
36eb9bde | 708 | ERROR("no interface corresponding to index '%d'", |
82d5ae15 | 709 | netdev->ifindex); |
0ad19a3f | 710 | return -1; |
711 | } | |
13954cce | 712 | |
018ef520 | 713 | /* default: let the system to choose one interface name */ |
9d083402 MT |
714 | if (!netdev->name) |
715 | netdev->name = "eth%d"; | |
018ef520 | 716 | |
82d5ae15 | 717 | /* rename the interface name */ |
9d083402 | 718 | if (lxc_device_rename(ifname, netdev->name)) { |
018ef520 DL |
719 | ERROR("failed to rename %s->%s", ifname, current_ifname); |
720 | return -1; | |
721 | } | |
722 | ||
723 | /* Re-read the name of the interface because its name has changed | |
724 | * and would be automatically allocated by the system | |
725 | */ | |
82d5ae15 | 726 | if (!if_indextoname(netdev->ifindex, current_ifname)) { |
018ef520 | 727 | ERROR("no interface corresponding to index '%d'", |
82d5ae15 | 728 | netdev->ifindex); |
018ef520 | 729 | return -1; |
0ad19a3f | 730 | } |
731 | ||
82d5ae15 DL |
732 | /* set a mac address */ |
733 | if (netdev->hwaddr) { | |
734 | if (setup_hw_addr(netdev->hwaddr, current_ifname)) { | |
36eb9bde | 735 | ERROR("failed to setup hw address for '%s'", |
82d5ae15 | 736 | current_ifname); |
0ad19a3f | 737 | return -1; |
738 | } | |
739 | } | |
740 | ||
82d5ae15 DL |
741 | /* setup ipv4 addresses on the interface */ |
742 | if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) { | |
36eb9bde | 743 | ERROR("failed to setup ip addresses for '%s'", |
0ad19a3f | 744 | ifname); |
745 | return -1; | |
746 | } | |
747 | ||
82d5ae15 DL |
748 | /* setup ipv6 addresses on the interface */ |
749 | if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) { | |
36eb9bde | 750 | ERROR("failed to setup ipv6 addresses for '%s'", |
0ad19a3f | 751 | ifname); |
752 | return -1; | |
753 | } | |
754 | ||
82d5ae15 DL |
755 | /* set the network device up */ |
756 | if (netdev->flags | IFF_UP) { | |
497353b6 | 757 | if (lxc_device_up(current_ifname)) { |
36eb9bde | 758 | ERROR("failed to set '%s' up", current_ifname); |
0ad19a3f | 759 | return -1; |
760 | } | |
761 | ||
762 | /* the network is up, make the loopback up too */ | |
497353b6 | 763 | if (lxc_device_up("lo")) { |
36eb9bde | 764 | ERROR("failed to set the loopback up"); |
0ad19a3f | 765 | return -1; |
766 | } | |
767 | } | |
768 | ||
cd54d859 DL |
769 | DEBUG("'%s' has been setup", current_ifname); |
770 | ||
0ad19a3f | 771 | return 0; |
772 | } | |
773 | ||
5f4535a3 | 774 | static int setup_network(struct lxc_list *network) |
0ad19a3f | 775 | { |
82d5ae15 | 776 | struct lxc_list *iterator; |
82d5ae15 | 777 | struct lxc_netdev *netdev; |
0ad19a3f | 778 | |
5f4535a3 | 779 | lxc_list_for_each(iterator, network) { |
cd54d859 | 780 | |
5f4535a3 | 781 | netdev = iterator->elem; |
82d5ae15 DL |
782 | |
783 | if (setup_netdev(netdev)) { | |
784 | ERROR("failed to setup netdev"); | |
785 | return -1; | |
786 | } | |
787 | } | |
cd54d859 | 788 | |
5f4535a3 DL |
789 | if (!lxc_list_empty(network)) |
790 | INFO("network has been setup"); | |
cd54d859 DL |
791 | |
792 | return 0; | |
0ad19a3f | 793 | } |
794 | ||
795 | int conf_has(const char *name, const char *info) | |
796 | { | |
b09ef133 | 797 | int ret = 0; |
0ad19a3f | 798 | char path[MAXPATHLEN]; |
799 | struct stat st; | |
800 | ||
801 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/%s", name, info); | |
802 | ||
b09ef133 | 803 | if (!stat(path, &st) || !lstat(path, &st)) { |
0ad19a3f | 804 | ret = 1; |
805 | goto out; | |
806 | } | |
807 | ||
808 | if (errno == ENOENT) { | |
809 | ret = 0; | |
810 | goto out; | |
811 | } | |
812 | ||
36eb9bde | 813 | SYSERROR("failed to stat %s info", info); |
0ad19a3f | 814 | out: |
815 | return ret; | |
816 | } | |
817 | ||
089cd8b8 DL |
818 | int lxc_conf_init(struct lxc_conf *conf) |
819 | { | |
820 | conf->rootfs = NULL; | |
821 | conf->fstab = NULL; | |
822 | conf->utsname = NULL; | |
823 | conf->tty = 0; | |
824 | conf->pts = 0; | |
571e6ec8 | 825 | conf->console[0] = '\0'; |
089cd8b8 | 826 | lxc_list_init(&conf->cgroup); |
5f4535a3 | 827 | lxc_list_init(&conf->network); |
e7938e9e | 828 | lxc_list_init(&conf->mount_list); |
089cd8b8 DL |
829 | return 0; |
830 | } | |
831 | ||
82d5ae15 | 832 | static int instanciate_veth(struct lxc_netdev *netdev) |
0ad19a3f | 833 | { |
8634bc19 | 834 | char veth1buf[IFNAMSIZ], *veth1; |
82d5ae15 | 835 | char veth2[IFNAMSIZ]; |
13954cce | 836 | |
8634bc19 MT |
837 | if (netdev->pair) |
838 | veth1 = netdev->pair; | |
839 | else { | |
840 | snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX"); | |
841 | mktemp(veth1buf); | |
842 | veth1 = veth1buf; | |
843 | } | |
82d5ae15 | 844 | |
8634bc19 | 845 | snprintf(veth2, sizeof(veth2), "vethXXXXXX"); |
82d5ae15 DL |
846 | mktemp(veth2); |
847 | ||
848 | if (!strlen(veth1) || !strlen(veth2)) { | |
849 | ERROR("failed to allocate a temporary name"); | |
850 | return -1; | |
0ad19a3f | 851 | } |
852 | ||
eb14c10a | 853 | if (lxc_veth_create(veth1, veth2)) { |
734915ac | 854 | ERROR("failed to create %s-%s", veth1, veth2); |
6ab9ab6d | 855 | return -1; |
0ad19a3f | 856 | } |
13954cce | 857 | |
82d5ae15 | 858 | if (netdev->mtu) { |
6ab9ab6d MT |
859 | if (lxc_device_set_mtu(veth1, atoi(netdev->mtu)) || |
860 | lxc_device_set_mtu(veth2, atoi(netdev->mtu))) { | |
861 | ERROR("failed to set mtu '%s' for %s-%s", | |
862 | netdev->mtu, veth1, veth2); | |
eb14c10a | 863 | goto out_delete; |
75d09f83 DL |
864 | } |
865 | } | |
866 | ||
734915ac | 867 | if (netdev->link && lxc_bridge_attach(netdev->link, veth1)) { |
36eb9bde | 868 | ERROR("failed to attach '%s' to the bridge '%s'", |
9d083402 | 869 | veth1, netdev->link); |
eb14c10a DL |
870 | goto out_delete; |
871 | } | |
872 | ||
82d5ae15 DL |
873 | netdev->ifindex = if_nametoindex(veth2); |
874 | if (!netdev->ifindex) { | |
36eb9bde | 875 | ERROR("failed to retrieve the index for %s", veth2); |
eb14c10a DL |
876 | goto out_delete; |
877 | } | |
878 | ||
82d5ae15 | 879 | if (netdev->flags & IFF_UP) { |
497353b6 | 880 | if (lxc_device_up(veth1)) { |
36eb9bde | 881 | ERROR("failed to set %s up", veth1); |
eb14c10a | 882 | goto out_delete; |
0ad19a3f | 883 | } |
884 | } | |
885 | ||
82d5ae15 DL |
886 | DEBUG("instanciated veth '%s/%s', index is '%d'", |
887 | veth1, veth2, netdev->ifindex); | |
888 | ||
6ab9ab6d | 889 | return 0; |
eb14c10a DL |
890 | |
891 | out_delete: | |
892 | lxc_device_delete(veth1); | |
6ab9ab6d | 893 | return -1; |
13954cce | 894 | } |
d957ae2d | 895 | |
82d5ae15 | 896 | static int instanciate_macvlan(struct lxc_netdev *netdev) |
0ad19a3f | 897 | { |
82d5ae15 | 898 | char peer[IFNAMSIZ]; |
d957ae2d MT |
899 | |
900 | if (!netdev->link) { | |
901 | ERROR("no link specified for macvlan netdev"); | |
902 | return -1; | |
903 | } | |
13954cce | 904 | |
82d5ae15 | 905 | snprintf(peer, sizeof(peer), "mcXXXXXX"); |
22ebac19 | 906 | |
82d5ae15 DL |
907 | mktemp(peer); |
908 | ||
909 | if (!strlen(peer)) { | |
910 | ERROR("failed to make a temporary name"); | |
911 | return -1; | |
0ad19a3f | 912 | } |
913 | ||
9d083402 | 914 | if (lxc_macvlan_create(netdev->link, peer)) { |
36eb9bde | 915 | ERROR("failed to create macvlan interface '%s' on '%s'", |
9d083402 | 916 | peer, netdev->link); |
d957ae2d | 917 | return -1; |
0ad19a3f | 918 | } |
919 | ||
82d5ae15 DL |
920 | netdev->ifindex = if_nametoindex(peer); |
921 | if (!netdev->ifindex) { | |
36eb9bde | 922 | ERROR("failed to retrieve the index for %s", peer); |
d957ae2d MT |
923 | lxc_device_delete(peer); |
924 | return -1; | |
22ebac19 | 925 | } |
926 | ||
82d5ae15 | 927 | DEBUG("instanciated macvlan '%s', index is '%d'", peer, netdev->ifindex); |
0ad19a3f | 928 | |
d957ae2d | 929 | return 0; |
0ad19a3f | 930 | } |
931 | ||
26c39028 JHS |
932 | /* XXX: merge with instanciate_macvlan */ |
933 | static int instanciate_vlan(struct lxc_netdev *netdev) | |
934 | { | |
935 | char peer[IFNAMSIZ]; | |
936 | ||
937 | if (!netdev->link) { | |
938 | ERROR("no link specified for vlan netdev"); | |
939 | return -1; | |
940 | } | |
941 | ||
942 | snprintf(peer, sizeof(peer), "vlan%d",netdev->vlan_attr.vid); | |
943 | ||
944 | if (lxc_vlan_create(netdev->link, peer, netdev->vlan_attr.vid)) { | |
945 | ERROR("failed to create vlan interface '%s' on '%s'", | |
946 | peer, netdev->link); | |
947 | return -1; | |
948 | } | |
949 | ||
950 | netdev->ifindex = if_nametoindex(peer); | |
951 | if (!netdev->ifindex) { | |
952 | ERROR("failed to retrieve the ifindex for %s", peer); | |
953 | lxc_device_delete(peer); | |
954 | return -1; | |
955 | } | |
956 | ||
957 | DEBUG("instanciated vlan '%s', ifindex is '%d'", "vlan1000", netdev->ifindex); | |
958 | return 0; | |
959 | } | |
960 | ||
82d5ae15 | 961 | static int instanciate_phys(struct lxc_netdev *netdev) |
0ad19a3f | 962 | { |
9d083402 | 963 | netdev->ifindex = if_nametoindex(netdev->link); |
82d5ae15 | 964 | if (!netdev->ifindex) { |
9d083402 | 965 | ERROR("failed to retrieve the index for %s", netdev->link); |
0ad19a3f | 966 | return -1; |
967 | } | |
968 | ||
82d5ae15 | 969 | return 0; |
0ad19a3f | 970 | } |
971 | ||
82d5ae15 | 972 | static int instanciate_empty(struct lxc_netdev *netdev) |
0ad19a3f | 973 | { |
82d5ae15 DL |
974 | netdev->ifindex = 0; |
975 | return 0; | |
0ad19a3f | 976 | } |
977 | ||
5f4535a3 | 978 | int lxc_create_network(struct lxc_list *network) |
0ad19a3f | 979 | { |
82d5ae15 | 980 | struct lxc_list *iterator; |
82d5ae15 | 981 | struct lxc_netdev *netdev; |
0ad19a3f | 982 | |
5f4535a3 | 983 | lxc_list_for_each(iterator, network) { |
0ad19a3f | 984 | |
5f4535a3 | 985 | netdev = iterator->elem; |
13954cce | 986 | |
5f4535a3 | 987 | if (netdev->type < 0 || netdev->type > MAXCONFTYPE) { |
82d5ae15 | 988 | ERROR("invalid network configuration type '%d'", |
5f4535a3 | 989 | netdev->type); |
82d5ae15 DL |
990 | return -1; |
991 | } | |
0ad19a3f | 992 | |
5f4535a3 | 993 | if (netdev_conf[netdev->type](netdev)) { |
82d5ae15 DL |
994 | ERROR("failed to create netdev"); |
995 | return -1; | |
996 | } | |
0ad19a3f | 997 | } |
998 | ||
999 | return 0; | |
1000 | } | |
1001 | ||
5f4535a3 | 1002 | int lxc_assign_network(struct lxc_list *network, pid_t pid) |
0ad19a3f | 1003 | { |
82d5ae15 | 1004 | struct lxc_list *iterator; |
82d5ae15 | 1005 | struct lxc_netdev *netdev; |
0ad19a3f | 1006 | |
5f4535a3 | 1007 | lxc_list_for_each(iterator, network) { |
82d5ae15 | 1008 | |
5f4535a3 | 1009 | netdev = iterator->elem; |
82d5ae15 DL |
1010 | |
1011 | if (lxc_device_move(netdev->ifindex, pid)) { | |
1012 | ERROR("failed to move '%s' to the container", | |
9d083402 | 1013 | netdev->link); |
82d5ae15 DL |
1014 | return -1; |
1015 | } | |
1016 | ||
9d083402 | 1017 | DEBUG("move '%s' to '%d'", netdev->link, pid); |
0ad19a3f | 1018 | } |
1019 | ||
1020 | return 0; | |
1021 | } | |
1022 | ||
5e4a62bf | 1023 | int lxc_create_tty(const char *name, struct lxc_conf *conf) |
b0a33c1e | 1024 | { |
5e4a62bf | 1025 | struct lxc_tty_info *tty_info = &conf->tty_info; |
985d15b1 | 1026 | int i; |
b0a33c1e | 1027 | |
5e4a62bf DL |
1028 | /* no tty in the configuration */ |
1029 | if (!conf->tty) | |
b0a33c1e | 1030 | return 0; |
1031 | ||
13954cce | 1032 | tty_info->pty_info = |
e4e7d59d | 1033 | malloc(sizeof(*tty_info->pty_info)*conf->tty); |
b0a33c1e | 1034 | if (!tty_info->pty_info) { |
36eb9bde | 1035 | SYSERROR("failed to allocate pty_info"); |
985d15b1 | 1036 | return -1; |
b0a33c1e | 1037 | } |
1038 | ||
985d15b1 | 1039 | for (i = 0; i < conf->tty; i++) { |
13954cce | 1040 | |
b0a33c1e | 1041 | struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; |
1042 | ||
13954cce | 1043 | if (openpty(&pty_info->master, &pty_info->slave, |
b0a33c1e | 1044 | pty_info->name, NULL, NULL)) { |
36eb9bde | 1045 | SYSERROR("failed to create pty #%d", i); |
985d15b1 MT |
1046 | tty_info->nbtty = i; |
1047 | lxc_delete_tty(tty_info); | |
1048 | return -1; | |
b0a33c1e | 1049 | } |
1050 | ||
b035ad62 MS |
1051 | /* Prevent leaking the file descriptors to the container */ |
1052 | fcntl(pty_info->master, F_SETFD, FD_CLOEXEC); | |
1053 | fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC); | |
1054 | ||
b0a33c1e | 1055 | pty_info->busy = 0; |
1056 | } | |
1057 | ||
985d15b1 | 1058 | tty_info->nbtty = conf->tty; |
1ac470c0 DL |
1059 | |
1060 | INFO("tty's configured"); | |
1061 | ||
985d15b1 | 1062 | return 0; |
b0a33c1e | 1063 | } |
1064 | ||
1065 | void lxc_delete_tty(struct lxc_tty_info *tty_info) | |
1066 | { | |
1067 | int i; | |
1068 | ||
1069 | for (i = 0; i < tty_info->nbtty; i++) { | |
1070 | struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; | |
1071 | ||
1072 | close(pty_info->master); | |
1073 | close(pty_info->slave); | |
1074 | } | |
1075 | ||
1076 | free(tty_info->pty_info); | |
1077 | tty_info->nbtty = 0; | |
1078 | } | |
1079 | ||
571e6ec8 | 1080 | int lxc_setup(const char *name, struct lxc_conf *lxc_conf) |
0ad19a3f | 1081 | { |
571e6ec8 | 1082 | if (setup_utsname(lxc_conf->utsname)) { |
36eb9bde | 1083 | ERROR("failed to setup the utsname for '%s'", name); |
95b5ffaf | 1084 | return -1; |
0ad19a3f | 1085 | } |
1086 | ||
5f4535a3 | 1087 | if (setup_network(&lxc_conf->network)) { |
36eb9bde | 1088 | ERROR("failed to setup the network for '%s'", name); |
95b5ffaf | 1089 | return -1; |
0ad19a3f | 1090 | } |
1091 | ||
571e6ec8 | 1092 | if (setup_cgroup(name, &lxc_conf->cgroup)) { |
36eb9bde | 1093 | ERROR("failed to setup the cgroups for '%s'", name); |
95b5ffaf | 1094 | return -1; |
0ad19a3f | 1095 | } |
1096 | ||
571e6ec8 | 1097 | if (setup_mount(lxc_conf->fstab)) { |
36eb9bde | 1098 | ERROR("failed to setup the mounts for '%s'", name); |
95b5ffaf | 1099 | return -1; |
576f946d | 1100 | } |
1101 | ||
e7938e9e MN |
1102 | if (setup_mount_entries(&lxc_conf->mount_list)) { |
1103 | ERROR("failed to setup the mount entries for '%s'", name); | |
1104 | return -1; | |
1105 | } | |
1106 | ||
571e6ec8 | 1107 | if (setup_console(lxc_conf->rootfs, lxc_conf->console)) { |
36eb9bde | 1108 | ERROR("failed to setup the console for '%s'", name); |
95b5ffaf | 1109 | return -1; |
6e590161 | 1110 | } |
1111 | ||
571e6ec8 | 1112 | if (setup_tty(lxc_conf->rootfs, &lxc_conf->tty_info)) { |
36eb9bde | 1113 | ERROR("failed to setup the ttys for '%s'", name); |
95b5ffaf | 1114 | return -1; |
b0a33c1e | 1115 | } |
1116 | ||
571e6ec8 | 1117 | if (setup_rootfs(lxc_conf->rootfs)) { |
36eb9bde | 1118 | ERROR("failed to set rootfs for '%s'", name); |
95b5ffaf | 1119 | return -1; |
ed502555 | 1120 | } |
1121 | ||
571e6ec8 | 1122 | if (setup_pts(lxc_conf->pts)) { |
36eb9bde | 1123 | ERROR("failed to setup the new pts instance"); |
95b5ffaf | 1124 | return -1; |
3c26f34e | 1125 | } |
1126 | ||
cd54d859 DL |
1127 | NOTICE("'%s' is setup.", name); |
1128 | ||
0ad19a3f | 1129 | return 0; |
1130 | } |