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