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