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