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