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