]>
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> |
e5bda9ee | 53 | |
0ad19a3f | 54 | #define MAXHWLEN 18 |
55 | #define MAXINDEXLEN 20 | |
56 | #define MAXLINELEN 128 | |
57 | ||
fdc03323 DL |
58 | #ifndef MS_REC |
59 | #define MS_REC 16384 | |
60 | #endif | |
61 | ||
6f4a3756 | 62 | typedef int (*instanciate_cb)(const char *directory, |
0ad19a3f | 63 | const char *file, pid_t pid); |
64 | ||
0ad19a3f | 65 | struct netdev_conf { |
66 | const char *type; | |
67 | instanciate_cb cb; | |
68 | int count; | |
69 | }; | |
70 | ||
71 | static int instanciate_veth(const char *, const char *, pid_t); | |
72 | static int instanciate_macvlan(const char *, const char *, pid_t); | |
73 | static int instanciate_phys(const char *, const char *, pid_t); | |
74 | static int instanciate_empty(const char *, const char *, pid_t); | |
6f4a3756 | 75 | static int unconfigure_cgroup(const char *name); |
0ad19a3f | 76 | |
77 | static struct netdev_conf netdev_conf[MAXCONFTYPE + 1] = { | |
78 | [VETH] = { "veth", instanciate_veth, 0 }, | |
79 | [MACVLAN] = { "macvlan", instanciate_macvlan, 0, }, | |
80 | [PHYS] = { "phys", instanciate_phys, 0, }, | |
81 | [EMPTY] = { "empty", instanciate_empty, 0, }, | |
82 | }; | |
83 | ||
0ad19a3f | 84 | static int write_info(const char *path, const char *file, const char *info) |
85 | { | |
86 | int fd, err = -1; | |
22ebac19 | 87 | char f[MAXPATHLEN]; |
0ad19a3f | 88 | |
22ebac19 | 89 | snprintf(f, MAXPATHLEN, "%s/%s", path, file); |
0ad19a3f | 90 | fd = creat(f, 0755); |
91 | if (fd < 0) | |
92 | goto out; | |
93 | ||
94 | if (write(fd, info, strlen(info)) < 0 || | |
95 | write(fd, "\n", strlen("\n") + 1) < 0) | |
96 | goto out_write; | |
97 | err = 0; | |
98 | out: | |
99 | close(fd); | |
0ad19a3f | 100 | return err; |
101 | ||
102 | out_write: | |
103 | unlink(f); | |
104 | goto out; | |
105 | } | |
106 | ||
107 | static int read_info(const char *path, const char *file, char *info, size_t len) | |
108 | { | |
109 | int fd, ret = -1; | |
22ebac19 | 110 | char f[MAXPATHLEN], *token; |
0ad19a3f | 111 | |
22ebac19 | 112 | snprintf(f, MAXPATHLEN, "%s/%s", path, file); |
0ad19a3f | 113 | fd = open(f, O_RDONLY); |
114 | if (fd < 0) { | |
115 | if (errno == ENOENT) | |
116 | ret = 1; | |
117 | goto out; | |
118 | } | |
119 | ||
120 | ret = read(fd, info, len); | |
121 | if (ret < 0) | |
122 | goto out; | |
123 | ||
124 | token = strstr(info, "\n"); | |
125 | if (token) | |
126 | *token = '\0'; | |
127 | ret = 0; | |
128 | out: | |
129 | close(fd); | |
0ad19a3f | 130 | return ret; |
131 | } | |
132 | ||
133 | static int delete_info(const char *path, const char *file) | |
134 | { | |
22ebac19 | 135 | char info[MAXPATHLEN]; |
0ad19a3f | 136 | int ret; |
137 | ||
22ebac19 | 138 | snprintf(info, MAXPATHLEN, "%s/%s", path, file); |
0ad19a3f | 139 | ret = unlink(info); |
0ad19a3f | 140 | |
141 | return ret; | |
142 | } | |
143 | ||
144 | static int configure_ip4addr(int fd, struct lxc_inetdev *in) | |
145 | { | |
146 | char addr[INET6_ADDRSTRLEN]; | |
147 | char bcast[INET_ADDRSTRLEN]; | |
22ebac19 | 148 | char line[MAXLINELEN]; |
0ad19a3f | 149 | int err = -1; |
150 | ||
151 | if (!inet_ntop(AF_INET, &in->addr, addr, sizeof(addr))) { | |
152 | lxc_log_syserror("failed to convert ipv4 address"); | |
153 | goto err; | |
154 | } | |
155 | ||
156 | if (!inet_ntop(AF_INET, &in->bcast, bcast, sizeof(bcast))) { | |
157 | lxc_log_syserror("failed to convert ipv4 broadcast"); | |
158 | goto err; | |
159 | } | |
160 | ||
161 | if (in->prefix) | |
22ebac19 | 162 | snprintf(line, MAXLINELEN, "%s/%d %s\n", addr, in->prefix, bcast); |
0ad19a3f | 163 | else |
22ebac19 | 164 | snprintf(line, MAXLINELEN, "%s %s\n", addr, bcast); |
0ad19a3f | 165 | |
166 | if (write(fd, line, strlen(line)) < 0) { | |
167 | lxc_log_syserror("failed to write address info"); | |
168 | goto err; | |
169 | } | |
170 | ||
171 | err = 0; | |
172 | err: | |
0ad19a3f | 173 | return err; |
174 | } | |
175 | ||
176 | static int configure_ip6addr(int fd, struct lxc_inet6dev *in6) | |
177 | { | |
178 | char addr[INET6_ADDRSTRLEN]; | |
22ebac19 | 179 | char line[MAXLINELEN]; |
0ad19a3f | 180 | int err = -1; |
181 | ||
182 | if (!inet_ntop(AF_INET6, &in6->addr, addr, sizeof(addr))) { | |
183 | lxc_log_syserror("failed to convert ipv4 address"); | |
184 | goto err; | |
185 | } | |
186 | ||
22ebac19 | 187 | snprintf(line, MAXLINELEN, "%s/%d\n", addr, in6->prefix?in6->prefix:64); |
0ad19a3f | 188 | |
189 | if (write(fd, line, strlen(line)) < 0) { | |
190 | lxc_log_syserror("failed to write address info"); | |
191 | goto err; | |
192 | } | |
193 | ||
194 | err = 0; | |
195 | err: | |
0ad19a3f | 196 | return err; |
197 | } | |
198 | ||
199 | static int configure_ip_address(const char *path, struct lxc_list *ip, int family) | |
200 | { | |
201 | char file[MAXPATHLEN]; | |
202 | struct lxc_list *iterator; | |
203 | int fd, err = -1; | |
204 | ||
205 | if (mkdir(path, 0755)) { | |
206 | lxc_log_syserror("failed to create directory %s", path); | |
207 | return -1; | |
208 | } | |
209 | ||
210 | snprintf(file, MAXPATHLEN, "%s/addresses", path); | |
211 | fd = creat(file, 0755); | |
212 | if (fd < 0) { | |
213 | lxc_log_syserror("failed to create %s file", file); | |
214 | goto err; | |
215 | } | |
216 | ||
217 | lxc_list_for_each(iterator, ip) { | |
218 | err = family == AF_INET? | |
219 | configure_ip4addr(fd, iterator->elem): | |
220 | configure_ip6addr(fd, iterator->elem); | |
221 | if (err) | |
222 | goto err; | |
223 | } | |
224 | out: | |
225 | close(fd); | |
226 | return err; | |
227 | err: | |
228 | unlink(file); | |
229 | rmdir(path); | |
230 | goto out; | |
231 | } | |
232 | ||
233 | static int configure_netdev(const char *path, struct lxc_netdev *netdev) | |
234 | { | |
235 | int err = -1; | |
236 | char dir[MAXPATHLEN]; | |
237 | ||
238 | if (mkdir(path, 0755)) { | |
239 | lxc_log_syserror("failed to create %s directory", path); | |
240 | return -1; | |
241 | } | |
242 | ||
243 | if (netdev->ifname) { | |
244 | if (write_info(path, "link", netdev->ifname)) | |
245 | goto out_link; | |
246 | } | |
247 | ||
248 | if (netdev->newname) { | |
249 | if (write_info(path, "name", netdev->newname)) | |
250 | goto out_newname; | |
251 | } | |
252 | ||
253 | if (netdev->hwaddr) { | |
254 | if (write_info(path, "hwaddr", netdev->hwaddr)) | |
255 | goto out_up; | |
256 | } | |
257 | ||
258 | if (netdev->flags & IFF_UP) { | |
259 | if (write_info(path, "up", "")) | |
260 | goto out_hwaddr; | |
261 | } | |
262 | ||
263 | if (!lxc_list_empty(&netdev->ipv4)) { | |
264 | snprintf(dir, MAXPATHLEN, "%s/ipv4", path); | |
265 | if (configure_ip_address(dir, &netdev->ipv4, AF_INET)) | |
266 | goto out_ipv4; | |
267 | } | |
268 | ||
269 | if (!lxc_list_empty(&netdev->ipv6)) { | |
270 | snprintf(dir, MAXPATHLEN, "%s/ipv6", path); | |
271 | if (configure_ip_address(dir, &netdev->ipv6, AF_INET6)) | |
272 | goto out_ipv6; | |
273 | } | |
274 | err = 0; | |
275 | out: | |
276 | return err; | |
277 | out_ipv6: | |
278 | delete_info(path, "ipv4"); | |
279 | out_ipv4: | |
280 | delete_info(path, "up"); | |
281 | out_hwaddr: | |
282 | delete_info(path, "hwaddr"); | |
283 | out_up: | |
284 | delete_info(path, "name"); | |
285 | out_newname: | |
286 | delete_info(path, "link"); | |
287 | out_link: | |
288 | rmdir(path); | |
289 | goto out; | |
290 | } | |
291 | ||
292 | static int configure_utsname(const char *name, struct utsname *utsname) | |
293 | { | |
294 | char path[MAXPATHLEN]; | |
295 | ||
296 | snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); | |
297 | ||
298 | if (write_info(path, "utsname", utsname->nodename)) { | |
299 | lxc_log_error("failed to write the utsname info"); | |
300 | return -1; | |
301 | } | |
302 | ||
303 | return 0; | |
304 | } | |
305 | ||
306 | static int configure_network(const char *name, struct lxc_list *network) | |
307 | { | |
308 | struct lxc_list *iterator; | |
309 | struct lxc_network *n; | |
310 | char networkpath[MAXPATHLEN]; | |
311 | char path[MAXPATHLEN]; | |
312 | int err = -1; | |
313 | ||
314 | if (lxc_list_empty(network)) | |
315 | return 0; | |
316 | ||
317 | snprintf(networkpath, MAXPATHLEN, LXCPATH "/%s/network", name); | |
318 | if (mkdir(networkpath, 0755)) { | |
319 | lxc_log_syserror("failed to create %s directory", networkpath); | |
320 | goto out; | |
321 | } | |
322 | ||
323 | lxc_list_for_each(iterator, network) { | |
324 | ||
325 | n = iterator->elem; | |
326 | ||
327 | if (n->type < 0 || n->type > MAXCONFTYPE) { | |
328 | lxc_log_error("invalid network configuration type '%d'", | |
329 | n->type); | |
330 | goto out; | |
331 | } | |
332 | ||
333 | snprintf(path, MAXPATHLEN, "%s/%s%d", networkpath, | |
334 | netdev_conf[n->type].type, | |
335 | netdev_conf[n->type].count++); | |
336 | ||
337 | if (configure_netdev(path, lxc_list_first_elem(&n->netdev))) { | |
338 | lxc_log_error("failed to configure network type %s", | |
339 | netdev_conf[n->type].type); | |
340 | goto out; | |
341 | } | |
342 | } | |
343 | ||
344 | err = 0; | |
345 | out: | |
346 | return err; | |
347 | } | |
348 | ||
576f946d | 349 | static int configure_cgroup(const char *name, struct lxc_list *cgroup) |
0ad19a3f | 350 | { |
576f946d | 351 | char path[MAXPATHLEN]; |
352 | struct lxc_list *iterator; | |
353 | struct lxc_cgroup *cg; | |
6f4a3756 | 354 | FILE *file; |
576f946d | 355 | |
356 | if (lxc_list_empty(cgroup)) | |
357 | return 0; | |
358 | ||
359 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/cgroup", name); | |
360 | ||
6f4a3756 | 361 | file = fopen(path, "w+"); |
362 | if (!file) { | |
363 | lxc_log_syserror("failed to open '%s'", path); | |
576f946d | 364 | return -1; |
365 | } | |
366 | ||
367 | lxc_list_for_each(iterator, cgroup) { | |
368 | cg = iterator->elem; | |
6f4a3756 | 369 | fprintf(file, "%s=%s\n", cg->subsystem, cg->value); |
576f946d | 370 | } |
371 | ||
6f4a3756 | 372 | fclose(file); |
373 | ||
0ad19a3f | 374 | return 0; |
375 | } | |
376 | ||
b0a33c1e | 377 | static int configure_tty(const char *name, int tty) |
378 | { | |
379 | char path[MAXPATHLEN]; | |
380 | char *nbtty; | |
381 | int ret; | |
382 | ||
383 | if (asprintf(&nbtty, "%d", tty) < 0) { | |
384 | lxc_log_error("failed to convert tty number"); | |
385 | return -1; | |
386 | } | |
387 | ||
388 | snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); | |
389 | ||
390 | ret = write_info(path, "tty", nbtty); | |
391 | if (ret) | |
392 | lxc_log_error("failed to write the tty info"); | |
393 | ||
394 | free(nbtty); | |
395 | ||
396 | return ret; | |
397 | } | |
398 | ||
78ae2fcc | 399 | static int configure_find_fstype_cb(void* buffer, void *data) |
400 | { | |
401 | struct cbarg { | |
402 | const char *rootfs; | |
403 | const char *testdir; | |
404 | char *fstype; | |
405 | int mntopt; | |
406 | } *cbarg = data; | |
407 | ||
408 | char *fstype; | |
409 | ||
410 | /* we don't try 'nodev' entries */ | |
411 | if (strstr(buffer, "nodev")) | |
412 | return 0; | |
413 | ||
414 | fstype = buffer; | |
b2718c72 | 415 | fstype += lxc_char_left_gc(fstype, strlen(fstype)); |
416 | fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0'; | |
78ae2fcc | 417 | |
418 | if (mount(cbarg->rootfs, cbarg->testdir, fstype, cbarg->mntopt, NULL)) | |
419 | return 0; | |
420 | ||
421 | /* found ! */ | |
422 | umount(cbarg->testdir); | |
423 | strcpy(cbarg->fstype, fstype); | |
424 | ||
425 | return 1; | |
426 | } | |
427 | ||
428 | /* find the filesystem type with brute force */ | |
429 | static int configure_find_fstype(const char *rootfs, char *fstype, int mntopt) | |
430 | { | |
431 | int i, found; | |
432 | char buffer[MAXPATHLEN]; | |
433 | ||
434 | struct cbarg { | |
435 | const char *rootfs; | |
436 | const char *testdir; | |
437 | char *fstype; | |
438 | int mntopt; | |
439 | } cbarg = { | |
440 | .rootfs = rootfs, | |
441 | .fstype = fstype, | |
442 | .mntopt = mntopt, | |
443 | }; | |
444 | ||
445 | /* first we check with /etc/filesystems, in case the modules | |
446 | * are auto-loaded and fall back to the supported kernel fs | |
447 | */ | |
448 | char *fsfile[] = { | |
449 | "/etc/filesystems", | |
450 | "/proc/filesystems", | |
451 | }; | |
452 | ||
453 | cbarg.testdir = tempnam("/tmp", "lxc-"); | |
454 | if (!cbarg.testdir) { | |
455 | lxc_log_syserror("failed to build a temp name"); | |
456 | return -1; | |
457 | } | |
458 | ||
459 | if (mkdir(cbarg.testdir, 0755)) { | |
460 | lxc_log_syserror("failed to create temporary directory"); | |
461 | return -1; | |
462 | } | |
463 | ||
464 | for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) { | |
465 | ||
b2718c72 | 466 | found = lxc_file_for_each_line(fsfile[i], |
467 | configure_find_fstype_cb, | |
468 | buffer, sizeof(buffer), &cbarg); | |
78ae2fcc | 469 | |
470 | if (found < 0) { | |
471 | lxc_log_syserror("failed to read '%s'", fsfile[i]); | |
472 | goto out; | |
473 | } | |
474 | ||
475 | if (found) | |
476 | break; | |
477 | } | |
478 | ||
479 | if (!found) { | |
480 | lxc_log_error("failed to determine fs type for '%s'", rootfs); | |
481 | goto out; | |
482 | } | |
483 | ||
484 | out: | |
485 | rmdir(cbarg.testdir); | |
486 | return found - 1; | |
487 | } | |
488 | ||
489 | static int configure_rootfs_dir_cb(const char *rootfs, const char *absrootfs, | |
490 | FILE *f) | |
491 | { | |
fdc03323 | 492 | return fprintf(f, "%s %s none rbind 0 0\n", absrootfs, rootfs); |
78ae2fcc | 493 | } |
494 | ||
495 | static int configure_rootfs_blk_cb(const char *rootfs, const char *absrootfs, | |
496 | FILE *f) | |
497 | { | |
498 | char fstype[MAXPATHLEN]; | |
499 | ||
500 | if (configure_find_fstype(absrootfs, fstype, 0)) { | |
501 | lxc_log_error("failed to configure mount for block device '%s'", | |
502 | absrootfs); | |
503 | return -1; | |
504 | } | |
505 | ||
506 | return fprintf(f, "%s %s %s defaults 0 0\n", absrootfs, rootfs, fstype); | |
507 | } | |
508 | ||
eae6543d | 509 | static int configure_rootfs(const char *name, const char *rootfs) |
0ad19a3f | 510 | { |
511 | char path[MAXPATHLEN]; | |
b09ef133 | 512 | char absrootfs[MAXPATHLEN]; |
9b0f0477 | 513 | char fstab[MAXPATHLEN]; |
78ae2fcc | 514 | struct stat s; |
9b0f0477 | 515 | FILE *f; |
78ae2fcc | 516 | int i, ret; |
517 | ||
518 | typedef int (*rootfs_cb)(const char *, const char *, FILE *); | |
519 | ||
520 | struct rootfs_type { | |
521 | int type; | |
522 | rootfs_cb cb; | |
523 | } rtfs_type[] = { | |
524 | { __S_IFDIR, configure_rootfs_dir_cb }, | |
525 | { __S_IFBLK, configure_rootfs_blk_cb }, | |
526 | }; | |
0ad19a3f | 527 | |
4c8ab83b | 528 | if (!realpath(rootfs, absrootfs)) { |
529 | lxc_log_syserror("failed to get real path for '%s'", rootfs); | |
530 | return -1; | |
531 | } | |
b09ef133 | 532 | |
4c8ab83b | 533 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name); |
b09ef133 | 534 | |
78ae2fcc | 535 | if (mkdir(path, 0755)) { |
536 | lxc_log_syserror("failed to create the '%s' directory", path); | |
537 | return -1; | |
538 | } | |
539 | ||
b09ef133 | 540 | if (access(absrootfs, F_OK)) { |
541 | lxc_log_syserror("'%s' is not accessible", absrootfs); | |
542 | return -1; | |
543 | } | |
544 | ||
78ae2fcc | 545 | if (stat(absrootfs, &s)) { |
546 | lxc_log_syserror("failed to stat '%s'", absrootfs); | |
9b0f0477 | 547 | return -1; |
548 | } | |
549 | ||
78ae2fcc | 550 | for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) { |
9b0f0477 | 551 | |
78ae2fcc | 552 | if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type)) |
553 | continue; | |
9b0f0477 | 554 | |
78ae2fcc | 555 | snprintf(fstab, MAXPATHLEN, LXCPATH "/%s/fstab", name); |
4c8ab83b | 556 | |
78ae2fcc | 557 | f = fopen(fstab, "a+"); |
558 | if (!f) { | |
559 | lxc_log_syserror("failed to open fstab file"); | |
560 | return -1; | |
561 | } | |
9b0f0477 | 562 | |
78ae2fcc | 563 | ret = rtfs_type[i].cb(path, absrootfs, f); |
9b0f0477 | 564 | |
78ae2fcc | 565 | fclose(f); |
566 | ||
567 | if (ret < 0) { | |
568 | lxc_log_error("failed to add rootfs mount in fstab"); | |
569 | return -1; | |
570 | } | |
571 | ||
572 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs/rootfs", name); | |
573 | ||
574 | return symlink(absrootfs, path); | |
575 | } | |
9b0f0477 | 576 | |
78ae2fcc | 577 | lxc_log_error("unsupported rootfs type for '%s'", absrootfs); |
578 | return -1; | |
0ad19a3f | 579 | } |
580 | ||
10db618d | 581 | static int configure_pts(const char *name, int pts) |
582 | { | |
583 | char path[MAXPATHLEN]; | |
584 | char *maxpts; | |
585 | int ret; | |
586 | ||
587 | if (asprintf(&maxpts, "%d", pts) < 0) { | |
588 | lxc_log_error("failed to convert max pts number"); | |
589 | return -1; | |
590 | } | |
591 | ||
592 | snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); | |
593 | ||
594 | ret = write_info(path, "pts", maxpts); | |
595 | if (ret) | |
596 | lxc_log_error("failed to write the pts info"); | |
597 | ||
598 | free(maxpts); | |
599 | ||
600 | return ret; | |
601 | } | |
602 | ||
0ad19a3f | 603 | static int configure_mount(const char *name, const char *fstab) |
604 | { | |
22ebac19 | 605 | char path[MAXPATHLEN]; |
0ad19a3f | 606 | struct stat stat; |
607 | int infd, outfd; | |
608 | void *src, *dst; | |
609 | char c = '\0'; | |
610 | int ret = -1; | |
611 | ||
22ebac19 | 612 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/fstab", name); |
0ad19a3f | 613 | |
614 | outfd = open(path, O_RDWR|O_CREAT|O_EXCL, 0640); | |
615 | if (outfd < 0) { | |
616 | lxc_log_syserror("failed to creat '%s'", path); | |
617 | goto out; | |
618 | } | |
619 | ||
620 | infd = open(fstab, O_RDONLY); | |
621 | if (infd < 0) { | |
622 | lxc_log_syserror("failed to open '%s'", fstab); | |
22ebac19 | 623 | goto out_open; |
0ad19a3f | 624 | } |
625 | ||
626 | if (fstat(infd, &stat)) { | |
627 | lxc_log_syserror("failed to stat '%s'", fstab); | |
22ebac19 | 628 | goto out_open2; |
0ad19a3f | 629 | } |
630 | ||
631 | if (lseek(outfd, stat.st_size - 1, SEEK_SET) < 0) { | |
632 | lxc_log_syserror("failed to seek dest file '%s'", path); | |
22ebac19 | 633 | goto out_open2; |
0ad19a3f | 634 | } |
635 | ||
636 | /* fixup length */ | |
637 | if (write(outfd, &c, 1) < 0) { | |
638 | lxc_log_syserror("failed to write to '%s'", path); | |
22ebac19 | 639 | goto out_open2; |
0ad19a3f | 640 | } |
641 | ||
642 | src = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, infd, 0L); | |
643 | if (src == MAP_FAILED) { | |
644 | lxc_log_syserror("failed to mmap '%s'", fstab); | |
22ebac19 | 645 | goto out_open2; |
0ad19a3f | 646 | } |
647 | ||
648 | dst = mmap(NULL, stat.st_size, PROT_WRITE, MAP_SHARED, outfd, 0L); | |
649 | if (dst == MAP_FAILED) { | |
650 | lxc_log_syserror("failed to mmap '%s'", path); | |
22ebac19 | 651 | goto out_mmap; |
0ad19a3f | 652 | } |
653 | ||
654 | memcpy(dst, src, stat.st_size); | |
655 | ||
656 | munmap(src, stat.st_size); | |
657 | munmap(dst, stat.st_size); | |
658 | ||
659 | ret = 0; | |
660 | out: | |
0ad19a3f | 661 | return ret; |
22ebac19 | 662 | |
663 | out_mmap: | |
664 | munmap(src, stat.st_size); | |
665 | out_open2: | |
666 | close(infd); | |
667 | out_open: | |
668 | unlink(path); | |
669 | close(outfd); | |
670 | goto out; | |
0ad19a3f | 671 | } |
672 | ||
6f4a3756 | 673 | static int unconfigure_ip_addresses(const char *directory) |
0ad19a3f | 674 | { |
675 | char path[MAXPATHLEN]; | |
676 | ||
6f4a3756 | 677 | snprintf(path, MAXPATHLEN, "%s/ipv4", directory); |
0ad19a3f | 678 | delete_info(path, "addresses"); |
679 | rmdir(path); | |
680 | ||
6f4a3756 | 681 | snprintf(path, MAXPATHLEN, "%s/ipv6", directory); |
0ad19a3f | 682 | delete_info(path, "addresses"); |
683 | rmdir(path); | |
684 | ||
685 | return 0; | |
686 | } | |
687 | ||
6f4a3756 | 688 | static int unconfigure_network_cb(const char *name, const char *directory, |
0ad19a3f | 689 | const char *file, void *data) |
690 | { | |
691 | char path[MAXPATHLEN]; | |
692 | ||
6f4a3756 | 693 | snprintf(path, MAXPATHLEN, "%s/%s", directory, file); |
b09ef133 | 694 | delete_info(path, "ifindex"); |
0ad19a3f | 695 | delete_info(path, "name"); |
696 | delete_info(path, "addr"); | |
697 | delete_info(path, "link"); | |
698 | delete_info(path, "hwaddr"); | |
699 | delete_info(path, "up"); | |
700 | unconfigure_ip_addresses(path); | |
701 | rmdir(path); | |
702 | ||
703 | return 0; | |
704 | } | |
705 | ||
706 | static int unconfigure_network(const char *name) | |
707 | { | |
6f4a3756 | 708 | char directory[MAXPATHLEN]; |
0ad19a3f | 709 | |
6f4a3756 | 710 | snprintf(directory, MAXPATHLEN, LXCPATH "/%s/network", name); |
b2718c72 | 711 | lxc_dir_for_each(name, directory, unconfigure_network_cb, NULL); |
6f4a3756 | 712 | rmdir(directory); |
0ad19a3f | 713 | |
714 | return 0; | |
715 | } | |
716 | ||
6f4a3756 | 717 | static int unconfigure_cgroup_cb(const char *name, const char *directory, |
576f946d | 718 | const char *file, void *data) |
719 | { | |
6f4a3756 | 720 | return delete_info(directory, file); |
576f946d | 721 | } |
722 | ||
0ad19a3f | 723 | static int unconfigure_cgroup(const char *name) |
724 | { | |
6f4a3756 | 725 | char filename[MAXPATHLEN]; |
726 | struct stat s; | |
b09ef133 | 727 | |
6f4a3756 | 728 | snprintf(filename, MAXPATHLEN, LXCPATH "/%s/cgroup", name); |
729 | ||
730 | if (stat(filename, &s)) { | |
731 | lxc_log_syserror("failed to stat '%s'", filename); | |
732 | return -1; | |
733 | } | |
734 | ||
735 | if (S_ISDIR(s.st_mode)) { | |
736 | /* old cgroup configuration */ | |
b2718c72 | 737 | lxc_dir_for_each(name, filename, unconfigure_cgroup_cb, NULL); |
6f4a3756 | 738 | rmdir(filename); |
739 | } else { | |
740 | unlink(filename); | |
741 | } | |
b09ef133 | 742 | |
0ad19a3f | 743 | return 0; |
744 | } | |
745 | ||
eae6543d | 746 | static int unconfigure_rootfs(const char *name) |
0ad19a3f | 747 | { |
748 | char path[MAXPATHLEN]; | |
749 | ||
9b0f0477 | 750 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name); |
751 | ||
752 | #warning deprecated code to be removed in the next version | |
753 | ||
754 | /* ugly but for backward compatibily, */ | |
eae6543d | 755 | delete_info(path, "rootfs"); |
9b0f0477 | 756 | rmdir(path); |
757 | unlink(path); | |
0ad19a3f | 758 | |
759 | return 0; | |
760 | } | |
761 | ||
10db618d | 762 | static int unconfigure_pts(const char *name) |
763 | { | |
764 | char path[MAXPATHLEN]; | |
765 | ||
766 | snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); | |
767 | delete_info(path, "pts"); | |
768 | ||
769 | return 0; | |
770 | } | |
771 | ||
79cf945c | 772 | static int unconfigure_tty(const char *name) |
773 | { | |
774 | char path[MAXPATHLEN]; | |
775 | ||
776 | snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); | |
777 | delete_info(path, "tty"); | |
778 | ||
779 | return 0; | |
780 | } | |
781 | ||
0ad19a3f | 782 | static int unconfigure_mount(const char *name) |
783 | { | |
784 | char path[MAXPATHLEN]; | |
785 | ||
786 | snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); | |
787 | delete_info(path, "fstab"); | |
788 | ||
789 | return 0; | |
790 | } | |
791 | ||
792 | static int unconfigure_utsname(const char *name) | |
793 | { | |
794 | char path[MAXPATHLEN]; | |
795 | ||
796 | snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); | |
797 | delete_info(path, "utsname"); | |
798 | ||
799 | return 0; | |
800 | } | |
801 | ||
802 | static int setup_utsname(const char *name) | |
803 | { | |
804 | int ret; | |
805 | char path[MAXPATHLEN]; | |
806 | struct utsname utsname; | |
807 | ||
808 | snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); | |
809 | ||
810 | ret = read_info(path, "utsname", utsname.nodename, | |
811 | sizeof(utsname.nodename)); | |
812 | if (ret < 0) { | |
813 | lxc_log_syserror("failed to read utsname info"); | |
814 | return -1; | |
815 | } | |
816 | ||
817 | if (!ret && sethostname(utsname.nodename, strlen(utsname.nodename))) { | |
818 | lxc_log_syserror("failed to set the hostname to '%s'", | |
819 | utsname.nodename); | |
820 | return -1; | |
821 | } | |
822 | ||
823 | return 0; | |
824 | } | |
825 | ||
b0a33c1e | 826 | static int setup_tty(const char *name, const struct lxc_tty_info *tty_info) |
827 | { | |
828 | char path[MAXPATHLEN]; | |
829 | int i; | |
830 | ||
831 | for (i = 0; i < tty_info->nbtty; i++) { | |
832 | ||
833 | struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; | |
834 | ||
79cf945c | 835 | if (conf_has_rootfs(name)) |
836 | snprintf(path, MAXPATHLEN, | |
837 | LXCPATH "/%s/rootfs/dev/tty%d", name, i + 1); | |
838 | else | |
839 | snprintf(path, MAXPATHLEN, "/dev/tty%d", i + 1); | |
b0a33c1e | 840 | |
841 | /* At this point I can not use the "access" function | |
842 | * to check the file is present or not because it fails | |
843 | * with EACCES errno and I don't know why :( */ | |
844 | ||
845 | if (mount(pty_info->name, path, "none", MS_BIND, 0)) { | |
846 | lxc_log_warning("failed to mount '%s'->'%s'", | |
847 | pty_info->name, path); | |
848 | continue; | |
849 | } | |
850 | } | |
851 | ||
852 | return 0; | |
853 | } | |
854 | ||
eae6543d | 855 | static int setup_rootfs(const char *name) |
0ad19a3f | 856 | { |
c3f0a28c | 857 | char path[MAXPATHLEN]; |
0ad19a3f | 858 | |
eae6543d | 859 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name); |
0ad19a3f | 860 | |
c3f0a28c | 861 | if (chroot(path)) { |
862 | lxc_log_syserror("failed to set chroot %s", path); | |
863 | return -1; | |
864 | } | |
0ad19a3f | 865 | |
c3f0a28c | 866 | if (chdir(getenv("HOME")) && chdir("/")) { |
867 | lxc_log_syserror("failed to change to home directory"); | |
868 | return -1; | |
0ad19a3f | 869 | } |
870 | ||
871 | return 0; | |
872 | } | |
873 | ||
3c26f34e | 874 | static int setup_pts(const char *name) |
875 | { | |
876 | char mountname[MAXPATHLEN]; | |
877 | ||
878 | if (!access("/dev/pts/ptmx", F_OK) && umount("/dev/pts")) { | |
879 | lxc_log_syserror("failed to umount 'dev/pts'"); | |
880 | return -1; | |
881 | } | |
882 | ||
883 | snprintf(mountname, MAXPATHLEN, "%spts", name); | |
884 | ||
885 | if (mount(mountname, "/dev/pts", "devpts", MS_MGC_VAL, "newinstance")) { | |
886 | lxc_log_syserror("failed to mount a new instance of '/dev/pts'"); | |
887 | return -1; | |
888 | } | |
889 | ||
890 | if (chmod("/dev/pts/ptmx", 0666)) { | |
891 | lxc_log_syserror("failed to set permission for '/dev/pts/ptmx'"); | |
892 | return -1; | |
893 | } | |
894 | ||
895 | if (access("/dev/ptmx", F_OK)) { | |
896 | if (!symlink("/dev/pts/ptmx", "/dev/ptmx")) | |
897 | goto out; | |
898 | lxc_log_syserror("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'"); | |
899 | return -1; | |
900 | } | |
901 | ||
902 | /* fallback here, /dev/pts/ptmx exists just mount bind */ | |
903 | if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) { | |
904 | lxc_log_syserror("mount failed '/dev/pts/ptmx'->'/dev/ptmx'"); | |
905 | return -1; | |
906 | } | |
907 | out: | |
908 | return 0; | |
909 | } | |
910 | ||
6e590161 | 911 | static int setup_console(const char *name, const char *tty) |
912 | { | |
ed502555 | 913 | char console[MAXPATHLEN]; |
914 | ||
915 | snprintf(console, MAXPATHLEN, LXCPATH "/%s/rootfs/dev/console", name); | |
916 | ||
917 | if (access(console, R_OK|W_OK)) | |
6e590161 | 918 | return 0; |
919 | ||
ed502555 | 920 | if (mount(tty, console, "none", MS_BIND, 0)) { |
6e590161 | 921 | lxc_log_error("failed to mount the console"); |
922 | return -1; | |
923 | } | |
924 | ||
925 | return 0; | |
926 | } | |
927 | ||
6f4a3756 | 928 | static int setup_cgroup_cb(void* buffer, void *data) |
576f946d | 929 | { |
6f4a3756 | 930 | char *key = buffer, *value; |
e7aa295e | 931 | char *name = data; |
932 | int ret; | |
6f4a3756 | 933 | |
934 | value = strchr(key, '='); | |
935 | if (!value) | |
936 | return -1; | |
937 | ||
938 | *value = '\0'; | |
939 | value += 1; | |
940 | ||
e7aa295e | 941 | ret = lxc_cgroup_set(name, key, value); |
942 | if (ret) | |
943 | lxc_log_syserror("failed to set cgroup '%s' = '%s' for '%s'", | |
944 | key, value, name); | |
945 | return ret; | |
576f946d | 946 | } |
947 | ||
6f4a3756 | 948 | static int setup_convert_cgroup_cb(const char *name, const char *directory, |
949 | const char *file, void *data) | |
950 | { | |
951 | FILE *f = data; | |
952 | char line[MAXPATHLEN]; | |
953 | ||
954 | if (read_info(directory, file, line, MAXPATHLEN)) { | |
955 | lxc_log_error("failed to read %s", file); | |
956 | return -1; | |
957 | } | |
958 | ||
959 | fprintf(f, "%s=%s\n", file, line); | |
960 | ||
961 | return 0; | |
962 | } | |
963 | ||
964 | static int setup_convert_cgroup(const char *name, char *directory) | |
965 | { | |
966 | char filename[MAXPATHLEN]; | |
967 | FILE *file; | |
968 | int ret; | |
969 | ||
970 | snprintf(filename, MAXPATHLEN, LXCPATH "/%s/cgroup.new", name); | |
971 | ||
972 | file = fopen(filename, "w+"); | |
973 | if (!file) | |
974 | return -1; | |
975 | ||
b2718c72 | 976 | ret = lxc_dir_for_each(name, directory, setup_convert_cgroup_cb, file); |
6f4a3756 | 977 | if (ret) |
978 | goto out_error; | |
979 | ||
980 | ret = unconfigure_cgroup(name); | |
981 | if (ret) | |
982 | goto out_error; | |
983 | ||
984 | ret = rename(filename, directory); | |
985 | if (ret) | |
986 | goto out_error; | |
987 | out: | |
988 | fclose(file); | |
989 | return ret; | |
990 | ||
991 | out_error: | |
992 | unlink(filename); | |
993 | goto out; | |
994 | } | |
995 | ||
576f946d | 996 | static int setup_cgroup(const char *name) |
997 | { | |
6f4a3756 | 998 | char filename[MAXPATHLEN]; |
999 | char line[MAXPATHLEN]; | |
1000 | struct stat s; | |
1001 | ||
1002 | snprintf(filename, MAXPATHLEN, LXCPATH "/%s/cgroup", name); | |
1003 | ||
1004 | if (stat(filename, &s)) { | |
1005 | lxc_log_syserror("failed to stat '%s'", filename); | |
1006 | return -1; | |
1007 | } | |
1008 | ||
1009 | if (S_ISDIR(s.st_mode)) { | |
1010 | if (setup_convert_cgroup(name, filename)) { | |
1011 | lxc_log_error("failed to convert old cgroup configuration"); | |
1012 | return -1; | |
1013 | } | |
1014 | } | |
1015 | ||
b2718c72 | 1016 | return lxc_file_for_each_line(filename, setup_cgroup_cb, |
1017 | line, MAXPATHLEN, (void *)name); | |
576f946d | 1018 | } |
1019 | ||
0ad19a3f | 1020 | static int setup_mount(const char *name) |
1021 | { | |
1022 | char path[MAXPATHLEN]; | |
1023 | struct mntent *mntent; | |
1024 | FILE *file; | |
1025 | int ret = -1; | |
1026 | unsigned long mntflags = 0; | |
1027 | ||
1028 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/fstab", name); | |
1029 | ||
1030 | file = setmntent(path, "r"); | |
1031 | if (!file) { | |
1032 | if (errno == ENOENT) | |
1033 | return 0; | |
1034 | lxc_log_syserror("failed to open '%s'", path); | |
1035 | goto out; | |
1036 | } | |
1037 | ||
1038 | while((mntent = getmntent(file))) { | |
1039 | ||
1040 | if (hasmntopt(mntent, "bind")) | |
1041 | mntflags |= MS_BIND; | |
fdc03323 DL |
1042 | if (hasmntopt(mntent, "rbind")) |
1043 | mntflags |= MS_BIND|MS_REC; | |
4bbb9c57 | 1044 | if (hasmntopt(mntent, "ro")) |
1045 | mntflags |= MS_RDONLY; | |
1046 | if (hasmntopt(mntent, "noexec")) | |
1047 | mntflags |= MS_NOEXEC; | |
0ad19a3f | 1048 | |
1049 | if (mount(mntent->mnt_fsname, mntent->mnt_dir, | |
1050 | mntent->mnt_type, mntflags, NULL)) { | |
1051 | lxc_log_syserror("failed to mount '%s' on '%s'", | |
1052 | mntent->mnt_fsname, mntent->mnt_dir); | |
1053 | goto out; | |
1054 | } | |
1055 | } | |
1056 | ret = 0; | |
1057 | out: | |
1058 | endmntent(file); | |
1059 | return ret; | |
1060 | } | |
1061 | ||
1062 | static int setup_ipv4_addr_cb(void *buffer, void *data) | |
1063 | { | |
1064 | char *ifname = data; | |
1065 | char *cursor, *slash, *addr, *bcast = NULL, *prefix = NULL; | |
1066 | int p = 24; | |
1067 | ||
1068 | addr = buffer; | |
1069 | cursor = strstr(addr, " "); | |
1070 | if (cursor) { | |
1071 | *cursor = '\0'; | |
1072 | bcast = cursor + 1; | |
1073 | cursor = strstr(bcast, "\n"); | |
1074 | if (cursor) | |
1075 | *cursor = '\0'; | |
1076 | } | |
1077 | ||
1078 | slash = strstr(addr, "/"); | |
1079 | if (slash) { | |
1080 | *slash = '\0'; | |
1081 | prefix = slash + 1; | |
1082 | } | |
1083 | ||
1084 | if (prefix) | |
1085 | p = atoi(prefix); | |
1086 | ||
1087 | if (ip_addr_add(ifname, addr, p, bcast)) { | |
1088 | lxc_log_error("failed to set %s to addr %s/%d %s", ifname, | |
1089 | addr, p, bcast?bcast:""); | |
1090 | return -1; | |
1091 | } | |
1092 | ||
1093 | return 0; | |
1094 | } | |
1095 | ||
1096 | static int setup_ipv6_addr_cb(void *buffer, void *data) | |
1097 | { | |
1098 | char *ifname = data; | |
1099 | char *cursor, *slash, *addr, *bcast = NULL, *prefix = NULL; | |
1100 | int p = 24; | |
1101 | ||
1102 | addr = buffer; | |
1103 | cursor = strstr(addr, " "); | |
1104 | if (cursor) { | |
1105 | *cursor = '\0'; | |
1106 | bcast = cursor + 1; | |
1107 | cursor = strstr(bcast, "\n"); | |
1108 | if (cursor) | |
1109 | *cursor = '\0'; | |
1110 | } | |
1111 | ||
1112 | slash = strstr(addr, "/"); | |
1113 | if (slash) { | |
1114 | *slash = '\0'; | |
1115 | prefix = slash + 1; | |
1116 | } | |
1117 | ||
1118 | if (prefix) | |
1119 | p = atoi(prefix); | |
1120 | ||
1121 | if (ip6_addr_add(ifname, addr, p, bcast)) { | |
1122 | lxc_log_error("failed to set %s to addr %s/%d %s", ifname, | |
1123 | addr, p, bcast?bcast:""); | |
1124 | return -1; | |
1125 | } | |
1126 | ||
1127 | return 0; | |
1128 | } | |
1129 | ||
1130 | static int setup_hw_addr(char *hwaddr, const char *ifname) | |
1131 | { | |
1132 | struct sockaddr sockaddr; | |
1133 | struct ifreq ifr; | |
1134 | int ret, fd; | |
1135 | ||
1136 | if (lxc_convert_mac(hwaddr, &sockaddr)) { | |
1137 | fprintf(stderr, "conversion has failed\n"); | |
1138 | return -1; | |
1139 | } | |
1140 | ||
1141 | memcpy(ifr.ifr_name, ifname, IFNAMSIZ); | |
1142 | memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr)); | |
1143 | ||
1144 | fd = socket(AF_INET, SOCK_DGRAM, 0); | |
1145 | if (fd < 0) { | |
1146 | perror("socket"); | |
1147 | return -1; | |
1148 | } | |
1149 | ||
1150 | ret = ioctl(fd, SIOCSIFHWADDR, &ifr); | |
1151 | close(fd); | |
1152 | if (ret) | |
1153 | perror("ioctl"); | |
1154 | ||
1155 | return ret; | |
1156 | } | |
1157 | ||
6f4a3756 | 1158 | static int setup_ip_addr(const char *directory, const char *ifname) |
0ad19a3f | 1159 | { |
1160 | char path[MAXPATHLEN], line[MAXLINELEN]; | |
1161 | struct stat s; | |
1162 | int ret = 0; | |
1163 | ||
6f4a3756 | 1164 | snprintf(path, MAXPATHLEN, "%s/ipv4/addresses", directory); |
0ad19a3f | 1165 | if (!stat(path, &s)) |
b2718c72 | 1166 | ret = lxc_file_for_each_line(path, setup_ipv4_addr_cb, |
1167 | line, MAXPATHLEN, (void*)ifname); | |
0ad19a3f | 1168 | return ret; |
1169 | } | |
1170 | ||
6f4a3756 | 1171 | static int setup_ip6_addr(const char *directory, const char *ifname) |
0ad19a3f | 1172 | { |
1173 | char path[MAXPATHLEN], line[MAXLINELEN]; | |
1174 | struct stat s; | |
1175 | int ret = 0; | |
1176 | ||
6f4a3756 | 1177 | snprintf(path, MAXLINELEN, "%s/ipv6/addresses", directory); |
0ad19a3f | 1178 | if (!stat(path, &s)) |
b2718c72 | 1179 | ret = lxc_file_for_each_line(path, setup_ipv6_addr_cb, |
1180 | line, MAXPATHLEN, (void*)ifname); | |
0ad19a3f | 1181 | return ret; |
1182 | } | |
1183 | ||
6f4a3756 | 1184 | static int setup_network_cb(const char *name, const char *directory, |
0ad19a3f | 1185 | const char *file, void *data) |
1186 | { | |
1187 | char path[MAXPATHLEN]; | |
1188 | char strindex[MAXINDEXLEN]; | |
1189 | char ifname[IFNAMSIZ]; | |
1190 | char newname[IFNAMSIZ]; | |
1191 | char hwaddr[MAXHWLEN]; | |
1192 | char *current_ifname = ifname; | |
1193 | int ifindex; | |
1194 | ||
6f4a3756 | 1195 | snprintf(path, MAXPATHLEN, "%s/%s", directory, file); |
0ad19a3f | 1196 | |
1197 | if (read_info(path, "ifindex", strindex, sizeof(strindex))) { | |
1198 | lxc_log_error("failed to read ifindex info"); | |
1199 | return -1; | |
1200 | } | |
1201 | ||
1202 | ifindex = atoi(strindex); | |
1203 | if (!ifindex) { | |
1204 | if (!read_info(path, "up", strindex, sizeof(strindex))) | |
1205 | if (device_up("lo")) { | |
1206 | lxc_log_error("failed to set the loopback up"); | |
1207 | return -1; | |
1208 | } | |
1209 | return 0; | |
1210 | } | |
1211 | ||
1212 | if (!if_indextoname(ifindex, current_ifname)) { | |
1213 | lxc_log_error("no interface corresponding to index '%d'", | |
1214 | ifindex); | |
1215 | return -1; | |
1216 | } | |
1217 | ||
1218 | if (!read_info(path, "name", newname, sizeof(newname))) { | |
1219 | if (device_rename(ifname, newname)) { | |
1220 | lxc_log_error("failed to rename %s->%s", | |
1221 | ifname, newname); | |
1222 | return -1; | |
1223 | } | |
1224 | current_ifname = newname; | |
1225 | } | |
1226 | ||
1227 | if (!read_info(path, "hwaddr", hwaddr, sizeof(hwaddr))) { | |
1228 | if (setup_hw_addr(hwaddr, current_ifname)) { | |
1229 | lxc_log_error("failed to setup hw address for '%s'", | |
1230 | current_ifname); | |
1231 | return -1; | |
1232 | } | |
1233 | } | |
1234 | ||
1235 | if (setup_ip_addr(path, current_ifname)) { | |
1236 | lxc_log_error("failed to setup ip addresses for '%s'", | |
1237 | ifname); | |
1238 | return -1; | |
1239 | } | |
1240 | ||
1241 | if (setup_ip6_addr(path, current_ifname)) { | |
1242 | lxc_log_error("failed to setup ipv6 addresses for '%s'", | |
1243 | ifname); | |
1244 | return -1; | |
1245 | } | |
1246 | ||
1247 | if (!read_info(path, "up", strindex, sizeof(strindex))) { | |
1248 | if (device_up(current_ifname)) { | |
1249 | lxc_log_error("failed to set '%s' up", current_ifname); | |
1250 | return -1; | |
1251 | } | |
1252 | ||
1253 | /* the network is up, make the loopback up too */ | |
1254 | if (device_up("lo")) { | |
1255 | lxc_log_error("failed to set the loopback up"); | |
1256 | return -1; | |
1257 | } | |
1258 | } | |
1259 | ||
1260 | return 0; | |
1261 | } | |
1262 | ||
1263 | static int setup_network(const char *name) | |
1264 | { | |
6f4a3756 | 1265 | char directory[MAXPATHLEN]; |
0ad19a3f | 1266 | |
6f4a3756 | 1267 | snprintf(directory, MAXPATHLEN, LXCPATH "/%s/network", name); |
b2718c72 | 1268 | return lxc_dir_for_each(name, directory, setup_network_cb, NULL); |
0ad19a3f | 1269 | } |
1270 | ||
1271 | int conf_has(const char *name, const char *info) | |
1272 | { | |
b09ef133 | 1273 | int ret = 0; |
0ad19a3f | 1274 | char path[MAXPATHLEN]; |
1275 | struct stat st; | |
1276 | ||
1277 | snprintf(path, MAXPATHLEN, LXCPATH "/%s/%s", name, info); | |
1278 | ||
b09ef133 | 1279 | if (!stat(path, &st) || !lstat(path, &st)) { |
0ad19a3f | 1280 | ret = 1; |
1281 | goto out; | |
1282 | } | |
1283 | ||
1284 | if (errno == ENOENT) { | |
1285 | ret = 0; | |
1286 | goto out; | |
1287 | } | |
1288 | ||
1289 | lxc_log_syserror("failed to stat %s info", info); | |
1290 | out: | |
1291 | return ret; | |
1292 | } | |
1293 | ||
1294 | int lxc_configure(const char *name, struct lxc_conf *conf) | |
1295 | { | |
1296 | if (!conf) | |
1297 | return 0; | |
1298 | ||
1299 | if (conf->utsname && configure_utsname(name, conf->utsname)) { | |
1300 | lxc_log_error("failed to configure the utsname"); | |
e5bda9ee | 1301 | return -LXC_ERROR_CONF_UTSNAME; |
0ad19a3f | 1302 | } |
1303 | ||
576f946d | 1304 | if (configure_cgroup(name, &conf->cgroup)) { |
1305 | lxc_log_error("failed to configure the control group"); | |
e5bda9ee | 1306 | return -LXC_ERROR_CONF_CGROUP; |
0ad19a3f | 1307 | } |
1308 | ||
576f946d | 1309 | if (configure_network(name, &conf->networks)) { |
1310 | lxc_log_error("failed to configure the network"); | |
e5bda9ee | 1311 | return -LXC_ERROR_CONF_NETWORK; |
0ad19a3f | 1312 | } |
1313 | ||
b0a33c1e | 1314 | if (conf->tty && configure_tty(name, conf->tty)) { |
1315 | lxc_log_error("failed to configure the tty"); | |
1316 | return -LXC_ERROR_CONF_TTY; | |
1317 | } | |
1318 | ||
0ad19a3f | 1319 | if (conf->fstab && configure_mount(name, conf->fstab)) { |
1320 | lxc_log_error("failed to configure the mount points"); | |
e5bda9ee | 1321 | return -LXC_ERROR_CONF_MOUNT; |
0ad19a3f | 1322 | } |
1323 | ||
9b0f0477 | 1324 | if (conf->rootfs && configure_rootfs(name, conf->rootfs)) { |
1325 | lxc_log_error("failed to configure the rootfs"); | |
1326 | return -LXC_ERROR_CONF_ROOTFS; | |
1327 | } | |
1328 | ||
10db618d | 1329 | if (conf->pts && configure_pts(name, conf->pts)) { |
1330 | lxc_log_error("failed to configure a new pts instance"); | |
1331 | return -LXC_ERROR_CONF_PTS; | |
1332 | } | |
1333 | ||
0ad19a3f | 1334 | return 0; |
1335 | } | |
1336 | ||
1337 | int lxc_unconfigure(const char *name) | |
1338 | { | |
1339 | if (conf_has_utsname(name) && unconfigure_utsname(name)) | |
1340 | lxc_log_error("failed to cleanup utsname"); | |
1341 | ||
1342 | if (conf_has_network(name) && unconfigure_network(name)) | |
1343 | lxc_log_error("failed to cleanup the network"); | |
1344 | ||
576f946d | 1345 | if (conf_has_cgroup(name) && unconfigure_cgroup(name)) |
0ad19a3f | 1346 | lxc_log_error("failed to cleanup cgroup"); |
1347 | ||
79cf945c | 1348 | if (conf_has_tty(name) && unconfigure_tty(name)) |
10db618d | 1349 | lxc_log_error("failed to cleanup tty"); |
79cf945c | 1350 | |
eae6543d | 1351 | if (conf_has_rootfs(name) && unconfigure_rootfs(name)) |
1352 | lxc_log_error("failed to cleanup rootfs"); | |
0ad19a3f | 1353 | |
1354 | if (conf_has_fstab(name) && unconfigure_mount(name)) | |
1355 | lxc_log_error("failed to cleanup mount"); | |
1356 | ||
10db618d | 1357 | if (conf_has_pts(name) && unconfigure_pts(name)) |
1358 | lxc_log_error("failed to cleanup pts"); | |
1359 | ||
0ad19a3f | 1360 | return 0; |
1361 | } | |
1362 | ||
6f4a3756 | 1363 | static int instanciate_veth(const char *directory, const char *file, pid_t pid) |
0ad19a3f | 1364 | { |
1365 | char *path = NULL, *strindex = NULL, *veth1 = NULL, *veth2 = NULL; | |
1366 | char bridge[IFNAMSIZ]; | |
1367 | int ifindex, ret = -1; | |
1368 | ||
22ebac19 | 1369 | if (!asprintf(&veth1, "%s_%d", file, pid) || |
1370 | !asprintf(&veth2, "%s~%d", file, pid) || | |
6f4a3756 | 1371 | !asprintf(&path, "%s/%s", directory, file)) { |
22ebac19 | 1372 | lxc_log_syserror("failed to allocate memory"); |
1373 | goto out; | |
1374 | } | |
0ad19a3f | 1375 | |
1376 | if (read_info(path, "link", bridge, IFNAMSIZ)) { | |
1377 | lxc_log_error("failed to read bridge info"); | |
1378 | goto out; | |
1379 | } | |
1380 | ||
1381 | if (lxc_configure_veth(veth1, veth2, bridge)) { | |
1382 | lxc_log_error("failed to create %s-%s/%s", veth1, veth2, bridge); | |
1383 | goto out; | |
1384 | } | |
1385 | ||
1386 | ifindex = if_nametoindex(veth2); | |
1387 | if (!ifindex) { | |
1388 | lxc_log_error("failed to retrieve the index for %s", veth2); | |
1389 | goto out; | |
1390 | } | |
1391 | ||
22ebac19 | 1392 | if (!asprintf(&strindex, "%d", ifindex)) { |
1393 | lxc_log_syserror("failed to allocate memory"); | |
1394 | goto out; | |
1395 | } | |
1396 | ||
0ad19a3f | 1397 | if (write_info(path, "ifindex", strindex)) { |
1398 | lxc_log_error("failed to write interface index to %s", path); | |
1399 | goto out; | |
1400 | } | |
1401 | ||
1402 | if (!read_info(path, "up", strindex, sizeof(strindex))) { | |
1403 | if (device_up(veth1)) { | |
1404 | lxc_log_error("failed to set %s up", veth1); | |
1405 | goto out; | |
1406 | } | |
1407 | } | |
1408 | ||
1409 | ret = 0; | |
1410 | out: | |
1411 | free(path); | |
1412 | free(strindex); | |
1413 | free(veth1); | |
1414 | free(veth2); | |
1415 | return ret; | |
1416 | } | |
6f4a3756 | 1417 | static int instanciate_macvlan(const char *directory, const char *file, pid_t pid) |
0ad19a3f | 1418 | { |
1419 | char path[MAXPATHLEN], *strindex = NULL, *peer = NULL; | |
1420 | char link[IFNAMSIZ]; | |
1421 | int ifindex, ret = -1; | |
1422 | ||
22ebac19 | 1423 | if (!asprintf(&peer, "%s~%d", file, pid)) { |
1424 | lxc_log_syserror("failed to allocate memory"); | |
1425 | return -1; | |
1426 | } | |
1427 | ||
6f4a3756 | 1428 | snprintf(path, MAXPATHLEN, "%s/%s", directory, file); |
0ad19a3f | 1429 | if (read_info(path, "link", link, IFNAMSIZ)) { |
1430 | lxc_log_error("failed to read bridge info"); | |
1431 | goto out; | |
1432 | } | |
1433 | ||
1434 | if (lxc_configure_macvlan(link, peer)) { | |
1435 | lxc_log_error("failed to create macvlan interface %s", peer); | |
1436 | goto out; | |
1437 | } | |
1438 | ||
1439 | ifindex = if_nametoindex(peer); | |
1440 | if (!ifindex) { | |
1441 | lxc_log_error("failed to retrieve the index for %s", peer); | |
1442 | goto out; | |
1443 | } | |
1444 | ||
22ebac19 | 1445 | if (!asprintf(&strindex, "%d", ifindex)) { |
1446 | lxc_log_syserror("failed to allocate memory"); | |
1447 | return -1; | |
1448 | } | |
1449 | ||
0ad19a3f | 1450 | if (write_info(path, "ifindex", strindex)) { |
1451 | lxc_log_error("failed to write interface index to %s", path); | |
1452 | goto out; | |
1453 | } | |
1454 | ||
1455 | ret = 0; | |
1456 | out: | |
1457 | free(strindex); | |
1458 | free(peer); | |
1459 | return ret; | |
1460 | } | |
1461 | ||
6f4a3756 | 1462 | static int instanciate_phys(const char *directory, const char *file, pid_t pid) |
0ad19a3f | 1463 | { |
1464 | char path[MAXPATHLEN], *strindex = NULL; | |
1465 | char link[IFNAMSIZ]; | |
1466 | int ifindex, ret = -1; | |
1467 | ||
6f4a3756 | 1468 | snprintf(path, MAXPATHLEN, "%s/%s", directory, file); |
0ad19a3f | 1469 | if (read_info(path, "link", link, IFNAMSIZ)) { |
1470 | lxc_log_error("failed to read link info"); | |
1471 | goto out; | |
1472 | } | |
1473 | ||
1474 | ifindex = if_nametoindex(link); | |
1475 | if (!ifindex) { | |
1476 | lxc_log_error("failed to retrieve the index for %s", link); | |
1477 | goto out; | |
1478 | } | |
1479 | ||
22ebac19 | 1480 | if (!asprintf(&strindex, "%d", ifindex)) { |
1481 | lxc_log_syserror("failed to allocate memory"); | |
1482 | return -1; | |
1483 | } | |
1484 | ||
0ad19a3f | 1485 | if (write_info(path, "ifindex", strindex)) { |
1486 | lxc_log_error("failed to write interface index to %s", path); | |
1487 | goto out; | |
1488 | } | |
1489 | ||
1490 | ret = 0; | |
1491 | out: | |
1492 | free(strindex); | |
1493 | return ret; | |
1494 | } | |
1495 | ||
6f4a3756 | 1496 | static int instanciate_empty(const char *directory, const char *file, pid_t pid) |
0ad19a3f | 1497 | { |
1498 | char path[MAXPATHLEN], *strindex = NULL; | |
1499 | int ret = -1; | |
1500 | ||
6f4a3756 | 1501 | snprintf(path, MAXPATHLEN, "%s/%s", directory, file); |
0ad19a3f | 1502 | if (!asprintf(&strindex, "%d", 0)) { |
1503 | lxc_log_error("not enough memory"); | |
1504 | return -1; | |
1505 | } | |
1506 | ||
1507 | if (write_info(path, "ifindex", strindex)) { | |
1508 | lxc_log_error("failed to write interface index to %s", path); | |
1509 | goto out; | |
1510 | } | |
1511 | ||
1512 | ret = 0; | |
1513 | out: | |
1514 | free(strindex); | |
1515 | return ret; | |
1516 | } | |
1517 | ||
6f4a3756 | 1518 | static int instanciate_netdev_cb(const char *name, const char *directory, |
0ad19a3f | 1519 | const char *file, void *data) |
1520 | { | |
1521 | pid_t *pid = data; | |
1522 | ||
1523 | if (!strncmp("veth", file, strlen("veth"))) | |
6f4a3756 | 1524 | return instanciate_veth(directory, file, *pid); |
0ad19a3f | 1525 | else if (!strncmp("macvlan", file, strlen("macvlan"))) |
6f4a3756 | 1526 | return instanciate_macvlan(directory, file, *pid); |
0ad19a3f | 1527 | else if (!strncmp("phys", file, strlen("phys"))) |
6f4a3756 | 1528 | return instanciate_phys(directory, file, *pid); |
0ad19a3f | 1529 | else if (!strncmp("empty", file, strlen("empty"))) |
6f4a3756 | 1530 | return instanciate_empty(directory, file, *pid); |
0ad19a3f | 1531 | |
1532 | return -1; | |
1533 | } | |
1534 | ||
1535 | static int instanciate_netdev(const char *name, pid_t pid) | |
1536 | { | |
6f4a3756 | 1537 | char directory[MAXPATHLEN]; |
0ad19a3f | 1538 | |
6f4a3756 | 1539 | snprintf(directory, MAXPATHLEN, LXCPATH "/%s/network", name); |
b2718c72 | 1540 | return lxc_dir_for_each(name, directory, instanciate_netdev_cb, &pid); |
0ad19a3f | 1541 | } |
1542 | ||
6f4a3756 | 1543 | static int move_netdev_cb(const char *name, const char *directory, |
0ad19a3f | 1544 | const char *file, void *data) |
1545 | { | |
1546 | char path[MAXPATHLEN], ifname[IFNAMSIZ], strindex[MAXINDEXLEN]; | |
1547 | pid_t *pid = data; | |
1548 | int ifindex; | |
1549 | ||
6f4a3756 | 1550 | snprintf(path, MAXPATHLEN, "%s/%s", directory, file); |
0ad19a3f | 1551 | if (read_info(path, "ifindex", strindex, MAXINDEXLEN) < 0) { |
1552 | lxc_log_error("failed to read index to from %s", path); | |
1553 | return -1; | |
1554 | } | |
1555 | ||
1556 | ifindex = atoi(strindex); | |
1557 | if (!ifindex) | |
1558 | return 0; | |
1559 | ||
1560 | if (!if_indextoname(ifindex, ifname)) { | |
1561 | lxc_log_error("interface with index %d does not exist", | |
1562 | ifindex); | |
1563 | return -1; | |
1564 | } | |
1565 | ||
1566 | if (device_move(ifname, *pid)) { | |
1567 | lxc_log_error("failed to move %s to %d", ifname, *pid); | |
1568 | return -1; | |
1569 | } | |
1570 | ||
1571 | return 0; | |
1572 | } | |
1573 | ||
1574 | static int move_netdev(const char *name, pid_t pid) | |
1575 | { | |
6f4a3756 | 1576 | char directory[MAXPATHLEN]; |
1577 | snprintf(directory, MAXPATHLEN, LXCPATH "/%s/network", name); | |
b2718c72 | 1578 | return lxc_dir_for_each(name, directory, move_netdev_cb, &pid); |
0ad19a3f | 1579 | } |
1580 | ||
1581 | int conf_create_network(const char *name, pid_t pid) | |
1582 | { | |
1583 | if (instanciate_netdev(name, pid)) { | |
1584 | lxc_log_error("failed to instantiate the network devices"); | |
1585 | return -1; | |
1586 | } | |
1587 | ||
1588 | if (move_netdev(name, pid)) { | |
1589 | lxc_log_error("failed to move the netdev to the container"); | |
1590 | return -1; | |
1591 | } | |
1592 | ||
1593 | return 0; | |
1594 | } | |
1595 | ||
b2718c72 | 1596 | #ifdef NETWORK_DESTROY |
6f4a3756 | 1597 | static int delete_netdev_cb(const char *name, const char *directory, |
0ad19a3f | 1598 | const char *file, void *data) |
1599 | { | |
1600 | char strindex[MAXINDEXLEN]; | |
1601 | char path[MAXPATHLEN]; | |
1602 | char ifname[IFNAMSIZ]; | |
1603 | int i, ifindex; | |
1604 | ||
6f4a3756 | 1605 | snprintf(path, MAXPATHLEN, "%s/%s", directory, file); |
0ad19a3f | 1606 | |
1607 | if (read_info(path, "ifindex", strindex, MAXINDEXLEN)) { | |
1608 | lxc_log_error("failed to read ifindex info"); | |
1609 | return -1; | |
1610 | } | |
1611 | ||
1612 | ifindex = atoi(strindex); | |
1613 | if (!ifindex) | |
1614 | return 0; | |
1615 | ||
1616 | /* TODO : temporary code - needs wait on namespace */ | |
1617 | for (i = 0; i < 120; i++) { | |
1618 | if (if_indextoname(ifindex, ifname)) | |
1619 | break; | |
1620 | if (!i) | |
1621 | printf("waiting for interface #%d to come back\n", ifindex); | |
1622 | else | |
1623 | printf("."); fflush(stdout); | |
1624 | sleep(1); | |
1625 | } | |
1626 | ||
1627 | /* do not delete a physical network device */ | |
1628 | if (strncmp("phys", file, strlen("phys"))) | |
1629 | if (device_delete(ifname)) { | |
1630 | lxc_log_error("failed to remove the netdev %s", ifname); | |
1631 | } | |
1632 | ||
1633 | delete_info(path, "ifindex"); | |
1634 | ||
1635 | return 0; | |
1636 | } | |
b2718c72 | 1637 | #endif |
0ad19a3f | 1638 | |
b2718c72 | 1639 | int conf_destroy_network(const char *name) |
0ad19a3f | 1640 | { |
b2718c72 | 1641 | #ifdef NETWORK_DESTROY |
6f4a3756 | 1642 | char directory[MAXPATHLEN]; |
0ad19a3f | 1643 | |
6f4a3756 | 1644 | snprintf(directory, MAXPATHLEN, LXCPATH "/%s/network", name); |
0ad19a3f | 1645 | |
b2718c72 | 1646 | if (lxc_dir_for_each(name, directory, delete_netdev_cb, NULL)) { |
0ad19a3f | 1647 | lxc_log_error("failed to remove the network devices"); |
1648 | return -1; | |
1649 | } | |
6e590161 | 1650 | #endif |
0ad19a3f | 1651 | return 0; |
1652 | } | |
1653 | ||
b0a33c1e | 1654 | int lxc_create_tty(const char *name, struct lxc_tty_info *tty_info) |
1655 | { | |
1656 | char path[MAXPATHLEN]; | |
1657 | char tty[4]; | |
1658 | int i, ret = -1; | |
1659 | ||
1660 | tty_info->nbtty = 0; | |
1661 | ||
1662 | if (!conf_has_tty(name)) | |
1663 | return 0; | |
1664 | ||
b0a33c1e | 1665 | snprintf(path, MAXPATHLEN, LXCPATH "/%s", name); |
1666 | ||
1667 | if (read_info(path, "tty", tty, sizeof(tty)) < 0) { | |
1668 | lxc_log_syserror("failed to read tty info"); | |
1669 | goto out; | |
1670 | } | |
1671 | ||
1672 | tty_info->nbtty = atoi(tty); | |
1673 | tty_info->pty_info = | |
1674 | malloc(sizeof(*tty_info->pty_info)*tty_info->nbtty); | |
1675 | ||
1676 | if (!tty_info->pty_info) { | |
1677 | lxc_log_syserror("failed to allocate pty_info"); | |
1678 | goto out; | |
1679 | } | |
1680 | ||
1681 | for (i = 0; i < tty_info->nbtty; i++) { | |
1682 | ||
1683 | struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; | |
1684 | ||
1685 | if (openpty(&pty_info->master, &pty_info->slave, | |
1686 | pty_info->name, NULL, NULL)) { | |
1687 | lxc_log_syserror("failed to create pty #%d", i); | |
1688 | goto out_free; | |
1689 | } | |
1690 | ||
1691 | pty_info->busy = 0; | |
1692 | } | |
1693 | ||
1694 | ret = 0; | |
1695 | out: | |
1696 | return ret; | |
1697 | ||
1698 | out_free: | |
1699 | free(tty_info->pty_info); | |
1700 | goto out; | |
1701 | } | |
1702 | ||
1703 | void lxc_delete_tty(struct lxc_tty_info *tty_info) | |
1704 | { | |
1705 | int i; | |
1706 | ||
1707 | for (i = 0; i < tty_info->nbtty; i++) { | |
1708 | struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; | |
1709 | ||
1710 | close(pty_info->master); | |
1711 | close(pty_info->slave); | |
1712 | } | |
1713 | ||
1714 | free(tty_info->pty_info); | |
1715 | tty_info->nbtty = 0; | |
1716 | } | |
1717 | ||
3c26f34e | 1718 | enum { utsname, network, cgroup, fstab, console, tty, rootfs, pts }; |
db4aa207 | 1719 | |
1720 | static int conf_is_set(long flags, int subsystem) | |
1721 | { | |
1722 | return flags & (1 << subsystem); | |
1723 | } | |
1724 | ||
1725 | static void conf_set_flag(long *flags, int subsystem) | |
1726 | { | |
1727 | *flags |= 1 << subsystem; | |
1728 | } | |
1729 | ||
1730 | static long make_conf_flagset(const char *name, const char *cons, | |
1731 | const struct lxc_tty_info *tty_info) | |
1732 | { | |
1733 | long flags = 0; | |
1734 | ||
1735 | if (conf_has_utsname(name)) | |
1736 | conf_set_flag(&flags, utsname); | |
1737 | ||
1738 | if (conf_has_network(name)) | |
1739 | conf_set_flag(&flags, network); | |
1740 | ||
1741 | if (conf_has_cgroup(name)) | |
1742 | conf_set_flag(&flags, cgroup); | |
1743 | ||
1744 | if (conf_has_fstab(name)) | |
1745 | conf_set_flag(&flags, fstab); | |
1746 | ||
1747 | if (conf_has_rootfs(name)) | |
1748 | conf_set_flag(&flags, rootfs); | |
1749 | ||
3c26f34e | 1750 | if (conf_has_pts(name)) |
1751 | conf_set_flag(&flags, pts); | |
1752 | ||
db4aa207 | 1753 | if (tty_info->nbtty) |
1754 | conf_set_flag(&flags, tty); | |
1755 | ||
1756 | if (cons[0]) | |
1757 | conf_set_flag(&flags, console); | |
1758 | ||
1759 | return flags; | |
1760 | } | |
1761 | ||
1762 | int lxc_setup(const char *name, const char *cons, | |
b0a33c1e | 1763 | const struct lxc_tty_info *tty_info) |
1764 | ||
0ad19a3f | 1765 | { |
db4aa207 | 1766 | /* store the conf flags set otherwise conf_has will not |
1767 | * work after chrooting */ | |
1768 | long flags = make_conf_flagset(name, cons, tty_info); | |
1769 | ||
1770 | if (conf_is_set(flags, utsname) && setup_utsname(name)) { | |
0ad19a3f | 1771 | lxc_log_error("failed to setup the utsname for '%s'", name); |
e5bda9ee | 1772 | return -LXC_ERROR_SETUP_UTSNAME; |
0ad19a3f | 1773 | } |
1774 | ||
db4aa207 | 1775 | if (conf_is_set(flags, network) && setup_network(name)) { |
0ad19a3f | 1776 | lxc_log_error("failed to setup the network for '%s'", name); |
e5bda9ee | 1777 | return -LXC_ERROR_SETUP_NETWORK; |
0ad19a3f | 1778 | } |
1779 | ||
db4aa207 | 1780 | if (conf_is_set(flags, cgroup) && setup_cgroup(name)) { |
8c6c9475 | 1781 | lxc_log_error("failed to setup the cgroups for '%s'", name); |
e5bda9ee | 1782 | return -LXC_ERROR_SETUP_CGROUP; |
0ad19a3f | 1783 | } |
1784 | ||
db4aa207 | 1785 | if (conf_is_set(flags, fstab) && setup_mount(name)) { |
6e590161 | 1786 | lxc_log_error("failed to setup the mounts for '%s'", name); |
e5bda9ee | 1787 | return -LXC_ERROR_SETUP_MOUNT; |
576f946d | 1788 | } |
1789 | ||
db4aa207 | 1790 | if (conf_is_set(flags, console) && setup_console(name, cons)) { |
6e590161 | 1791 | lxc_log_error("failed to setup the console for '%s'", name); |
1792 | return -LXC_ERROR_SETUP_CONSOLE; | |
1793 | } | |
1794 | ||
db4aa207 | 1795 | if (conf_is_set(flags, tty) && setup_tty(name, tty_info)) { |
b0a33c1e | 1796 | lxc_log_error("failed to setup the ttys for '%s'", name); |
1797 | return -LXC_ERROR_SETUP_TTY; | |
1798 | } | |
1799 | ||
db4aa207 | 1800 | if (conf_is_set(flags, rootfs) && setup_rootfs(name)) { |
ed502555 | 1801 | lxc_log_error("failed to set rootfs for '%s'", name); |
1802 | return -LXC_ERROR_SETUP_ROOTFS; | |
1803 | } | |
1804 | ||
3c26f34e | 1805 | if (conf_is_set(flags, pts) && setup_pts(name)) { |
1806 | lxc_log_error("failed to setup the new pts instance"); | |
1807 | return -LXC_ERROR_SETUP_PTS; | |
1808 | } | |
1809 | ||
0ad19a3f | 1810 | return 0; |
1811 | } |