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