]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/lxc_conf.c
Allow to use /dev/ptmx
[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>
32
33#include <sys/types.h>
34#include <sys/utsname.h>
35#include <sys/param.h>
36#include <sys/stat.h>
37#include <sys/socket.h>
38#include <sys/mount.h>
39#include <sys/mman.h>
40
41#include <arpa/inet.h>
42#include <fcntl.h>
43#include <netinet/in.h>
44#include <net/if.h>
6f4a3756 45#include <libgen.h>
0ad19a3f 46
e5bda9ee 47#include "network.h"
48#include "error.h"
49
b113348e 50#include <lxc/lxc.h>
e5bda9ee 51
0ad19a3f 52
53#define MAXHWLEN 18
54#define MAXINDEXLEN 20
55#define MAXLINELEN 128
56
6f4a3756 57typedef int (*instanciate_cb)(const char *directory,
0ad19a3f 58 const char *file, pid_t pid);
59
6f4a3756 60typedef int (*dir_cb)(const char *name, const char *directory,
0ad19a3f 61 const char *file, void *data);
62
63typedef int (*file_cb)(void* buffer, void *data);
64
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
84static int dir_filter(const struct dirent *dirent)
85{
86 if (!strcmp(dirent->d_name, ".") ||
87 !strcmp(dirent->d_name, ".."))
88 return 0;
89 return 1;
90}
91
6f4a3756 92static int dir_for_each(const char *name, const char *directory,
0ad19a3f 93 dir_cb callback, void *data)
94{
95 struct dirent **namelist;
96 int n;
97
6f4a3756 98 n = scandir(directory, &namelist, dir_filter, alphasort);
0ad19a3f 99 if (n < 0) {
6f4a3756 100 lxc_log_syserror("failed to scan %s directory", directory);
0ad19a3f 101 return -1;
102 }
103
104 while (n--) {
6f4a3756 105 if (callback(name, directory, namelist[n]->d_name, data)) {
0ad19a3f 106 lxc_log_error("callback failed");
107 free(namelist[n]);
108 return -1;
109 }
110 free(namelist[n]);
111 }
112
113 return 0;
114}
115
116static int file_for_each_line(const char *file, file_cb callback,
117 void *buffer, size_t len, void* data)
118{
119 FILE *f;
120 int err = -1;
121
122 f = fopen(file, "r");
123 if (!f) {
124 lxc_log_syserror("failed to open %s", file);
125 return -1;
126 }
127
128 while (fgets(buffer, len, f))
129 if (callback(buffer, data))
130 goto out;
131 err = 0;
132out:
133 fclose(f);
134 return err;
135}
136
137static int write_info(const char *path, const char *file, const char *info)
138{
139 int fd, err = -1;
22ebac19 140 char f[MAXPATHLEN];
0ad19a3f 141
22ebac19 142 snprintf(f, MAXPATHLEN, "%s/%s", path, file);
0ad19a3f 143 fd = creat(f, 0755);
144 if (fd < 0)
145 goto out;
146
147 if (write(fd, info, strlen(info)) < 0 ||
148 write(fd, "\n", strlen("\n") + 1) < 0)
149 goto out_write;
150 err = 0;
151out:
152 close(fd);
0ad19a3f 153 return err;
154
155out_write:
156 unlink(f);
157 goto out;
158}
159
160static int read_info(const char *path, const char *file, char *info, size_t len)
161{
162 int fd, ret = -1;
22ebac19 163 char f[MAXPATHLEN], *token;
0ad19a3f 164
22ebac19 165 snprintf(f, MAXPATHLEN, "%s/%s", path, file);
0ad19a3f 166 fd = open(f, O_RDONLY);
167 if (fd < 0) {
168 if (errno == ENOENT)
169 ret = 1;
170 goto out;
171 }
172
173 ret = read(fd, info, len);
174 if (ret < 0)
175 goto out;
176
177 token = strstr(info, "\n");
178 if (token)
179 *token = '\0';
180 ret = 0;
181out:
182 close(fd);
0ad19a3f 183 return ret;
184}
185
186static int delete_info(const char *path, const char *file)
187{
22ebac19 188 char info[MAXPATHLEN];
0ad19a3f 189 int ret;
190
22ebac19 191 snprintf(info, MAXPATHLEN, "%s/%s", path, file);
0ad19a3f 192 ret = unlink(info);
0ad19a3f 193
194 return ret;
195}
196
197static int configure_ip4addr(int fd, struct lxc_inetdev *in)
198{
199 char addr[INET6_ADDRSTRLEN];
200 char bcast[INET_ADDRSTRLEN];
22ebac19 201 char line[MAXLINELEN];
0ad19a3f 202 int err = -1;
203
204 if (!inet_ntop(AF_INET, &in->addr, addr, sizeof(addr))) {
205 lxc_log_syserror("failed to convert ipv4 address");
206 goto err;
207 }
208
209 if (!inet_ntop(AF_INET, &in->bcast, bcast, sizeof(bcast))) {
210 lxc_log_syserror("failed to convert ipv4 broadcast");
211 goto err;
212 }
213
214 if (in->prefix)
22ebac19 215 snprintf(line, MAXLINELEN, "%s/%d %s\n", addr, in->prefix, bcast);
0ad19a3f 216 else
22ebac19 217 snprintf(line, MAXLINELEN, "%s %s\n", addr, bcast);
0ad19a3f 218
219 if (write(fd, line, strlen(line)) < 0) {
220 lxc_log_syserror("failed to write address info");
221 goto err;
222 }
223
224 err = 0;
225err:
0ad19a3f 226 return err;
227}
228
229static int configure_ip6addr(int fd, struct lxc_inet6dev *in6)
230{
231 char addr[INET6_ADDRSTRLEN];
22ebac19 232 char line[MAXLINELEN];
0ad19a3f 233 int err = -1;
234
235 if (!inet_ntop(AF_INET6, &in6->addr, addr, sizeof(addr))) {
236 lxc_log_syserror("failed to convert ipv4 address");
237 goto err;
238 }
239
22ebac19 240 snprintf(line, MAXLINELEN, "%s/%d\n", addr, in6->prefix?in6->prefix:64);
0ad19a3f 241
242 if (write(fd, line, strlen(line)) < 0) {
243 lxc_log_syserror("failed to write address info");
244 goto err;
245 }
246
247 err = 0;
248err:
0ad19a3f 249 return err;
250}
251
252static int configure_ip_address(const char *path, struct lxc_list *ip, int family)
253{
254 char file[MAXPATHLEN];
255 struct lxc_list *iterator;
256 int fd, err = -1;
257
258 if (mkdir(path, 0755)) {
259 lxc_log_syserror("failed to create directory %s", path);
260 return -1;
261 }
262
263 snprintf(file, MAXPATHLEN, "%s/addresses", path);
264 fd = creat(file, 0755);
265 if (fd < 0) {
266 lxc_log_syserror("failed to create %s file", file);
267 goto err;
268 }
269
270 lxc_list_for_each(iterator, ip) {
271 err = family == AF_INET?
272 configure_ip4addr(fd, iterator->elem):
273 configure_ip6addr(fd, iterator->elem);
274 if (err)
275 goto err;
276 }
277out:
278 close(fd);
279 return err;
280err:
281 unlink(file);
282 rmdir(path);
283 goto out;
284}
285
286static int configure_netdev(const char *path, struct lxc_netdev *netdev)
287{
288 int err = -1;
289 char dir[MAXPATHLEN];
290
291 if (mkdir(path, 0755)) {
292 lxc_log_syserror("failed to create %s directory", path);
293 return -1;
294 }
295
296 if (netdev->ifname) {
297 if (write_info(path, "link", netdev->ifname))
298 goto out_link;
299 }
300
301 if (netdev->newname) {
302 if (write_info(path, "name", netdev->newname))
303 goto out_newname;
304 }
305
306 if (netdev->hwaddr) {
307 if (write_info(path, "hwaddr", netdev->hwaddr))
308 goto out_up;
309 }
310
311 if (netdev->flags & IFF_UP) {
312 if (write_info(path, "up", ""))
313 goto out_hwaddr;
314 }
315
316 if (!lxc_list_empty(&netdev->ipv4)) {
317 snprintf(dir, MAXPATHLEN, "%s/ipv4", path);
318 if (configure_ip_address(dir, &netdev->ipv4, AF_INET))
319 goto out_ipv4;
320 }
321
322 if (!lxc_list_empty(&netdev->ipv6)) {
323 snprintf(dir, MAXPATHLEN, "%s/ipv6", path);
324 if (configure_ip_address(dir, &netdev->ipv6, AF_INET6))
325 goto out_ipv6;
326 }
327 err = 0;
328out:
329 return err;
330out_ipv6:
331 delete_info(path, "ipv4");
332out_ipv4:
333 delete_info(path, "up");
334out_hwaddr:
335 delete_info(path, "hwaddr");
336out_up:
337 delete_info(path, "name");
338out_newname:
339 delete_info(path, "link");
340out_link:
341 rmdir(path);
342 goto out;
343}
344
345static int configure_utsname(const char *name, struct utsname *utsname)
346{
347 char path[MAXPATHLEN];
348
349 snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
350
351 if (write_info(path, "utsname", utsname->nodename)) {
352 lxc_log_error("failed to write the utsname info");
353 return -1;
354 }
355
356 return 0;
357}
358
359static int configure_network(const char *name, struct lxc_list *network)
360{
361 struct lxc_list *iterator;
362 struct lxc_network *n;
363 char networkpath[MAXPATHLEN];
364 char path[MAXPATHLEN];
365 int err = -1;
366
367 if (lxc_list_empty(network))
368 return 0;
369
370 snprintf(networkpath, MAXPATHLEN, LXCPATH "/%s/network", name);
371 if (mkdir(networkpath, 0755)) {
372 lxc_log_syserror("failed to create %s directory", networkpath);
373 goto out;
374 }
375
376 lxc_list_for_each(iterator, network) {
377
378 n = iterator->elem;
379
380 if (n->type < 0 || n->type > MAXCONFTYPE) {
381 lxc_log_error("invalid network configuration type '%d'",
382 n->type);
383 goto out;
384 }
385
386 snprintf(path, MAXPATHLEN, "%s/%s%d", networkpath,
387 netdev_conf[n->type].type,
388 netdev_conf[n->type].count++);
389
390 if (configure_netdev(path, lxc_list_first_elem(&n->netdev))) {
391 lxc_log_error("failed to configure network type %s",
392 netdev_conf[n->type].type);
393 goto out;
394 }
395 }
396
397 err = 0;
398out:
399 return err;
400}
401
576f946d 402static int configure_cgroup(const char *name, struct lxc_list *cgroup)
0ad19a3f 403{
576f946d 404 char path[MAXPATHLEN];
405 struct lxc_list *iterator;
406 struct lxc_cgroup *cg;
6f4a3756 407 FILE *file;
576f946d 408
409 if (lxc_list_empty(cgroup))
410 return 0;
411
412 snprintf(path, MAXPATHLEN, LXCPATH "/%s/cgroup", name);
413
6f4a3756 414 file = fopen(path, "w+");
415 if (!file) {
416 lxc_log_syserror("failed to open '%s'", path);
576f946d 417 return -1;
418 }
419
420 lxc_list_for_each(iterator, cgroup) {
421 cg = iterator->elem;
6f4a3756 422 fprintf(file, "%s=%s\n", cg->subsystem, cg->value);
576f946d 423 }
424
6f4a3756 425 fclose(file);
426
0ad19a3f 427 return 0;
428}
429
eae6543d 430static int configure_rootfs(const char *name, const char *rootfs)
0ad19a3f 431{
432 char path[MAXPATHLEN];
b09ef133 433 char absrootfs[MAXPATHLEN];
434 char *pwd;
0ad19a3f 435
eae6543d 436 snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name);
0ad19a3f 437
b09ef133 438 pwd = get_current_dir_name();
439
440 snprintf(absrootfs, MAXPATHLEN, "%s/%s", pwd, rootfs);
441
442 free(pwd);
443
444 if (access(absrootfs, F_OK)) {
445 lxc_log_syserror("'%s' is not accessible", absrootfs);
446 return -1;
447 }
448
449 return symlink(absrootfs, path);
0ad19a3f 450
451}
452
453static int configure_mount(const char *name, const char *fstab)
454{
22ebac19 455 char path[MAXPATHLEN];
0ad19a3f 456 struct stat stat;
457 int infd, outfd;
458 void *src, *dst;
459 char c = '\0';
460 int ret = -1;
461
22ebac19 462 snprintf(path, MAXPATHLEN, LXCPATH "/%s/fstab", name);
0ad19a3f 463
464 outfd = open(path, O_RDWR|O_CREAT|O_EXCL, 0640);
465 if (outfd < 0) {
466 lxc_log_syserror("failed to creat '%s'", path);
467 goto out;
468 }
469
470 infd = open(fstab, O_RDONLY);
471 if (infd < 0) {
472 lxc_log_syserror("failed to open '%s'", fstab);
22ebac19 473 goto out_open;
0ad19a3f 474 }
475
476 if (fstat(infd, &stat)) {
477 lxc_log_syserror("failed to stat '%s'", fstab);
22ebac19 478 goto out_open2;
0ad19a3f 479 }
480
481 if (lseek(outfd, stat.st_size - 1, SEEK_SET) < 0) {
482 lxc_log_syserror("failed to seek dest file '%s'", path);
22ebac19 483 goto out_open2;
0ad19a3f 484 }
485
486 /* fixup length */
487 if (write(outfd, &c, 1) < 0) {
488 lxc_log_syserror("failed to write to '%s'", path);
22ebac19 489 goto out_open2;
0ad19a3f 490 }
491
492 src = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, infd, 0L);
493 if (src == MAP_FAILED) {
494 lxc_log_syserror("failed to mmap '%s'", fstab);
22ebac19 495 goto out_open2;
0ad19a3f 496 }
497
498 dst = mmap(NULL, stat.st_size, PROT_WRITE, MAP_SHARED, outfd, 0L);
499 if (dst == MAP_FAILED) {
500 lxc_log_syserror("failed to mmap '%s'", path);
22ebac19 501 goto out_mmap;
0ad19a3f 502 }
503
504 memcpy(dst, src, stat.st_size);
505
506 munmap(src, stat.st_size);
507 munmap(dst, stat.st_size);
508
509 ret = 0;
510out:
0ad19a3f 511 return ret;
22ebac19 512
513out_mmap:
514 munmap(src, stat.st_size);
515out_open2:
516 close(infd);
517out_open:
518 unlink(path);
519 close(outfd);
520 goto out;
0ad19a3f 521}
522
6f4a3756 523static int unconfigure_ip_addresses(const char *directory)
0ad19a3f 524{
525 char path[MAXPATHLEN];
526
6f4a3756 527 snprintf(path, MAXPATHLEN, "%s/ipv4", directory);
0ad19a3f 528 delete_info(path, "addresses");
529 rmdir(path);
530
6f4a3756 531 snprintf(path, MAXPATHLEN, "%s/ipv6", directory);
0ad19a3f 532 delete_info(path, "addresses");
533 rmdir(path);
534
535 return 0;
536}
537
6f4a3756 538static int unconfigure_network_cb(const char *name, const char *directory,
0ad19a3f 539 const char *file, void *data)
540{
541 char path[MAXPATHLEN];
542
6f4a3756 543 snprintf(path, MAXPATHLEN, "%s/%s", directory, file);
b09ef133 544 delete_info(path, "ifindex");
0ad19a3f 545 delete_info(path, "name");
546 delete_info(path, "addr");
547 delete_info(path, "link");
548 delete_info(path, "hwaddr");
549 delete_info(path, "up");
550 unconfigure_ip_addresses(path);
551 rmdir(path);
552
553 return 0;
554}
555
556static int unconfigure_network(const char *name)
557{
6f4a3756 558 char directory[MAXPATHLEN];
0ad19a3f 559
6f4a3756 560 snprintf(directory, MAXPATHLEN, LXCPATH "/%s/network", name);
561 dir_for_each(name, directory, unconfigure_network_cb, NULL);
562 rmdir(directory);
0ad19a3f 563
564 return 0;
565}
566
6f4a3756 567static int unconfigure_cgroup_cb(const char *name, const char *directory,
576f946d 568 const char *file, void *data)
569{
6f4a3756 570 return delete_info(directory, file);
576f946d 571}
572
0ad19a3f 573static int unconfigure_cgroup(const char *name)
574{
6f4a3756 575 char filename[MAXPATHLEN];
576 struct stat s;
b09ef133 577
6f4a3756 578 snprintf(filename, MAXPATHLEN, LXCPATH "/%s/cgroup", name);
579
580 if (stat(filename, &s)) {
581 lxc_log_syserror("failed to stat '%s'", filename);
582 return -1;
583 }
584
585 if (S_ISDIR(s.st_mode)) {
586 /* old cgroup configuration */
587 dir_for_each(name, filename, unconfigure_cgroup_cb, NULL);
588 rmdir(filename);
589 } else {
590 unlink(filename);
591 }
b09ef133 592
0ad19a3f 593 return 0;
594}
595
eae6543d 596static int unconfigure_rootfs(const char *name)
0ad19a3f 597{
598 char path[MAXPATHLEN];
599
600 snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
eae6543d 601 delete_info(path, "rootfs");
0ad19a3f 602
603 return 0;
604}
605
606static int unconfigure_mount(const char *name)
607{
608 char path[MAXPATHLEN];
609
610 snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
611 delete_info(path, "fstab");
612
613 return 0;
614}
615
616static int unconfigure_utsname(const char *name)
617{
618 char path[MAXPATHLEN];
619
620 snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
621 delete_info(path, "utsname");
622
623 return 0;
624}
625
626static int setup_utsname(const char *name)
627{
628 int ret;
629 char path[MAXPATHLEN];
630 struct utsname utsname;
631
632 snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
633
634 ret = read_info(path, "utsname", utsname.nodename,
635 sizeof(utsname.nodename));
636 if (ret < 0) {
637 lxc_log_syserror("failed to read utsname info");
638 return -1;
639 }
640
641 if (!ret && sethostname(utsname.nodename, strlen(utsname.nodename))) {
642 lxc_log_syserror("failed to set the hostname to '%s'",
643 utsname.nodename);
644 return -1;
645 }
646
647 return 0;
648}
649
eae6543d 650static int setup_rootfs(const char *name)
0ad19a3f 651{
c3f0a28c 652 char path[MAXPATHLEN];
0ad19a3f 653
eae6543d 654 snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name);
0ad19a3f 655
c3f0a28c 656 if (chroot(path)) {
657 lxc_log_syserror("failed to set chroot %s", path);
658 return -1;
659 }
0ad19a3f 660
c3f0a28c 661 if (chdir(getenv("HOME")) && chdir("/")) {
662 lxc_log_syserror("failed to change to home directory");
663 return -1;
0ad19a3f 664 }
665
666 return 0;
667}
668
6e590161 669static int setup_console(const char *name, const char *tty)
670{
671 if (access("/dev/console", R_OK|W_OK))
672 return 0;
673
674 if (mount(tty, "/dev/console", "none", MS_BIND, 0)) {
675 lxc_log_error("failed to mount the console");
676 return -1;
677 }
678
679 return 0;
680}
681
6f4a3756 682static int setup_cgroup_cb(void* buffer, void *data)
576f946d 683{
6f4a3756 684 char *key = buffer, *value;
e7aa295e 685 char *name = data;
686 int ret;
6f4a3756 687
688 value = strchr(key, '=');
689 if (!value)
690 return -1;
691
692 *value = '\0';
693 value += 1;
694
e7aa295e 695 ret = lxc_cgroup_set(name, key, value);
696 if (ret)
697 lxc_log_syserror("failed to set cgroup '%s' = '%s' for '%s'",
698 key, value, name);
699 return ret;
576f946d 700}
701
6f4a3756 702static int setup_convert_cgroup_cb(const char *name, const char *directory,
703 const char *file, void *data)
704{
705 FILE *f = data;
706 char line[MAXPATHLEN];
707
708 if (read_info(directory, file, line, MAXPATHLEN)) {
709 lxc_log_error("failed to read %s", file);
710 return -1;
711 }
712
713 fprintf(f, "%s=%s\n", file, line);
714
715 return 0;
716}
717
718static int setup_convert_cgroup(const char *name, char *directory)
719{
720 char filename[MAXPATHLEN];
721 FILE *file;
722 int ret;
723
724 snprintf(filename, MAXPATHLEN, LXCPATH "/%s/cgroup.new", name);
725
726 file = fopen(filename, "w+");
727 if (!file)
728 return -1;
729
730 ret = dir_for_each(name, directory, setup_convert_cgroup_cb, file);
731 if (ret)
732 goto out_error;
733
734 ret = unconfigure_cgroup(name);
735 if (ret)
736 goto out_error;
737
738 ret = rename(filename, directory);
739 if (ret)
740 goto out_error;
741out:
742 fclose(file);
743 return ret;
744
745out_error:
746 unlink(filename);
747 goto out;
748}
749
576f946d 750static int setup_cgroup(const char *name)
751{
6f4a3756 752 char filename[MAXPATHLEN];
753 char line[MAXPATHLEN];
754 struct stat s;
755
756 snprintf(filename, MAXPATHLEN, LXCPATH "/%s/cgroup", name);
757
758 if (stat(filename, &s)) {
759 lxc_log_syserror("failed to stat '%s'", filename);
760 return -1;
761 }
762
763 if (S_ISDIR(s.st_mode)) {
764 if (setup_convert_cgroup(name, filename)) {
765 lxc_log_error("failed to convert old cgroup configuration");
766 return -1;
767 }
768 }
769
770 return file_for_each_line(filename, setup_cgroup_cb,
e7aa295e 771 line, MAXPATHLEN, (void *)name);
576f946d 772}
773
0ad19a3f 774static int setup_mount(const char *name)
775{
776 char path[MAXPATHLEN];
777 struct mntent *mntent;
778 FILE *file;
779 int ret = -1;
780 unsigned long mntflags = 0;
781
782 snprintf(path, MAXPATHLEN, LXCPATH "/%s/fstab", name);
783
784 file = setmntent(path, "r");
785 if (!file) {
786 if (errno == ENOENT)
787 return 0;
788 lxc_log_syserror("failed to open '%s'", path);
789 goto out;
790 }
791
792 while((mntent = getmntent(file))) {
793
794 if (hasmntopt(mntent, "bind"))
795 mntflags |= MS_BIND;
4bbb9c57 796 if (hasmntopt(mntent, "ro"))
797 mntflags |= MS_RDONLY;
798 if (hasmntopt(mntent, "noexec"))
799 mntflags |= MS_NOEXEC;
0ad19a3f 800
801 if (mount(mntent->mnt_fsname, mntent->mnt_dir,
802 mntent->mnt_type, mntflags, NULL)) {
803 lxc_log_syserror("failed to mount '%s' on '%s'",
804 mntent->mnt_fsname, mntent->mnt_dir);
805 goto out;
806 }
807 }
808 ret = 0;
809out:
810 endmntent(file);
811 return ret;
812}
813
814static int setup_ipv4_addr_cb(void *buffer, void *data)
815{
816 char *ifname = data;
817 char *cursor, *slash, *addr, *bcast = NULL, *prefix = NULL;
818 int p = 24;
819
820 addr = buffer;
821 cursor = strstr(addr, " ");
822 if (cursor) {
823 *cursor = '\0';
824 bcast = cursor + 1;
825 cursor = strstr(bcast, "\n");
826 if (cursor)
827 *cursor = '\0';
828 }
829
830 slash = strstr(addr, "/");
831 if (slash) {
832 *slash = '\0';
833 prefix = slash + 1;
834 }
835
836 if (prefix)
837 p = atoi(prefix);
838
839 if (ip_addr_add(ifname, addr, p, bcast)) {
840 lxc_log_error("failed to set %s to addr %s/%d %s", ifname,
841 addr, p, bcast?bcast:"");
842 return -1;
843 }
844
845 return 0;
846}
847
848static int setup_ipv6_addr_cb(void *buffer, void *data)
849{
850 char *ifname = data;
851 char *cursor, *slash, *addr, *bcast = NULL, *prefix = NULL;
852 int p = 24;
853
854 addr = buffer;
855 cursor = strstr(addr, " ");
856 if (cursor) {
857 *cursor = '\0';
858 bcast = cursor + 1;
859 cursor = strstr(bcast, "\n");
860 if (cursor)
861 *cursor = '\0';
862 }
863
864 slash = strstr(addr, "/");
865 if (slash) {
866 *slash = '\0';
867 prefix = slash + 1;
868 }
869
870 if (prefix)
871 p = atoi(prefix);
872
873 if (ip6_addr_add(ifname, addr, p, bcast)) {
874 lxc_log_error("failed to set %s to addr %s/%d %s", ifname,
875 addr, p, bcast?bcast:"");
876 return -1;
877 }
878
879 return 0;
880}
881
882static int setup_hw_addr(char *hwaddr, const char *ifname)
883{
884 struct sockaddr sockaddr;
885 struct ifreq ifr;
886 int ret, fd;
887
888 if (lxc_convert_mac(hwaddr, &sockaddr)) {
889 fprintf(stderr, "conversion has failed\n");
890 return -1;
891 }
892
893 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
894 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
895
896 fd = socket(AF_INET, SOCK_DGRAM, 0);
897 if (fd < 0) {
898 perror("socket");
899 return -1;
900 }
901
902 ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
903 close(fd);
904 if (ret)
905 perror("ioctl");
906
907 return ret;
908}
909
6f4a3756 910static int setup_ip_addr(const char *directory, const char *ifname)
0ad19a3f 911{
912 char path[MAXPATHLEN], line[MAXLINELEN];
913 struct stat s;
914 int ret = 0;
915
6f4a3756 916 snprintf(path, MAXPATHLEN, "%s/ipv4/addresses", directory);
0ad19a3f 917 if (!stat(path, &s))
918 ret = file_for_each_line(path, setup_ipv4_addr_cb,
919 line, MAXPATHLEN, (void*)ifname);
920 return ret;
921}
922
6f4a3756 923static int setup_ip6_addr(const char *directory, const char *ifname)
0ad19a3f 924{
925 char path[MAXPATHLEN], line[MAXLINELEN];
926 struct stat s;
927 int ret = 0;
928
6f4a3756 929 snprintf(path, MAXLINELEN, "%s/ipv6/addresses", directory);
0ad19a3f 930 if (!stat(path, &s))
931 ret = file_for_each_line(path, setup_ipv6_addr_cb,
932 line, MAXPATHLEN, (void*)ifname);
933 return ret;
934}
935
6f4a3756 936static int setup_network_cb(const char *name, const char *directory,
0ad19a3f 937 const char *file, void *data)
938{
939 char path[MAXPATHLEN];
940 char strindex[MAXINDEXLEN];
941 char ifname[IFNAMSIZ];
942 char newname[IFNAMSIZ];
943 char hwaddr[MAXHWLEN];
944 char *current_ifname = ifname;
945 int ifindex;
946
6f4a3756 947 snprintf(path, MAXPATHLEN, "%s/%s", directory, file);
0ad19a3f 948
949 if (read_info(path, "ifindex", strindex, sizeof(strindex))) {
950 lxc_log_error("failed to read ifindex info");
951 return -1;
952 }
953
954 ifindex = atoi(strindex);
955 if (!ifindex) {
956 if (!read_info(path, "up", strindex, sizeof(strindex)))
957 if (device_up("lo")) {
958 lxc_log_error("failed to set the loopback up");
959 return -1;
960 }
961 return 0;
962 }
963
964 if (!if_indextoname(ifindex, current_ifname)) {
965 lxc_log_error("no interface corresponding to index '%d'",
966 ifindex);
967 return -1;
968 }
969
970 if (!read_info(path, "name", newname, sizeof(newname))) {
971 if (device_rename(ifname, newname)) {
972 lxc_log_error("failed to rename %s->%s",
973 ifname, newname);
974 return -1;
975 }
976 current_ifname = newname;
977 }
978
979 if (!read_info(path, "hwaddr", hwaddr, sizeof(hwaddr))) {
980 if (setup_hw_addr(hwaddr, current_ifname)) {
981 lxc_log_error("failed to setup hw address for '%s'",
982 current_ifname);
983 return -1;
984 }
985 }
986
987 if (setup_ip_addr(path, current_ifname)) {
988 lxc_log_error("failed to setup ip addresses for '%s'",
989 ifname);
990 return -1;
991 }
992
993 if (setup_ip6_addr(path, current_ifname)) {
994 lxc_log_error("failed to setup ipv6 addresses for '%s'",
995 ifname);
996 return -1;
997 }
998
999 if (!read_info(path, "up", strindex, sizeof(strindex))) {
1000 if (device_up(current_ifname)) {
1001 lxc_log_error("failed to set '%s' up", current_ifname);
1002 return -1;
1003 }
1004
1005 /* the network is up, make the loopback up too */
1006 if (device_up("lo")) {
1007 lxc_log_error("failed to set the loopback up");
1008 return -1;
1009 }
1010 }
1011
1012 return 0;
1013}
1014
1015static int setup_network(const char *name)
1016{
6f4a3756 1017 char directory[MAXPATHLEN];
0ad19a3f 1018
6f4a3756 1019 snprintf(directory, MAXPATHLEN, LXCPATH "/%s/network", name);
1020 return dir_for_each(name, directory, setup_network_cb, NULL);
0ad19a3f 1021}
1022
1023int conf_has(const char *name, const char *info)
1024{
b09ef133 1025 int ret = 0;
0ad19a3f 1026 char path[MAXPATHLEN];
1027 struct stat st;
1028
1029 snprintf(path, MAXPATHLEN, LXCPATH "/%s/%s", name, info);
1030
b09ef133 1031 if (!stat(path, &st) || !lstat(path, &st)) {
0ad19a3f 1032 ret = 1;
1033 goto out;
1034 }
1035
1036 if (errno == ENOENT) {
1037 ret = 0;
1038 goto out;
1039 }
1040
1041 lxc_log_syserror("failed to stat %s info", info);
1042out:
1043 return ret;
1044}
1045
1046int lxc_configure(const char *name, struct lxc_conf *conf)
1047{
1048 if (!conf)
1049 return 0;
1050
1051 if (conf->utsname && configure_utsname(name, conf->utsname)) {
1052 lxc_log_error("failed to configure the utsname");
e5bda9ee 1053 return -LXC_ERROR_CONF_UTSNAME;
0ad19a3f 1054 }
1055
576f946d 1056 if (configure_cgroup(name, &conf->cgroup)) {
1057 lxc_log_error("failed to configure the control group");
e5bda9ee 1058 return -LXC_ERROR_CONF_CGROUP;
0ad19a3f 1059 }
1060
576f946d 1061 if (configure_network(name, &conf->networks)) {
1062 lxc_log_error("failed to configure the network");
e5bda9ee 1063 return -LXC_ERROR_CONF_NETWORK;
0ad19a3f 1064 }
1065
eae6543d 1066 if (conf->rootfs && configure_rootfs(name, conf->rootfs)) {
1067 lxc_log_error("failed to configure the rootfs");
e5bda9ee 1068 return -LXC_ERROR_CONF_ROOTFS;
0ad19a3f 1069 }
1070
1071 if (conf->fstab && configure_mount(name, conf->fstab)) {
1072 lxc_log_error("failed to configure the mount points");
e5bda9ee 1073 return -LXC_ERROR_CONF_MOUNT;
0ad19a3f 1074 }
1075
1076 return 0;
1077}
1078
1079int lxc_unconfigure(const char *name)
1080{
1081 if (conf_has_utsname(name) && unconfigure_utsname(name))
1082 lxc_log_error("failed to cleanup utsname");
1083
1084 if (conf_has_network(name) && unconfigure_network(name))
1085 lxc_log_error("failed to cleanup the network");
1086
576f946d 1087 if (conf_has_cgroup(name) && unconfigure_cgroup(name))
0ad19a3f 1088 lxc_log_error("failed to cleanup cgroup");
1089
eae6543d 1090 if (conf_has_rootfs(name) && unconfigure_rootfs(name))
1091 lxc_log_error("failed to cleanup rootfs");
0ad19a3f 1092
1093 if (conf_has_fstab(name) && unconfigure_mount(name))
1094 lxc_log_error("failed to cleanup mount");
1095
1096 return 0;
1097}
1098
6f4a3756 1099static int instanciate_veth(const char *directory, const char *file, pid_t pid)
0ad19a3f 1100{
1101 char *path = NULL, *strindex = NULL, *veth1 = NULL, *veth2 = NULL;
1102 char bridge[IFNAMSIZ];
1103 int ifindex, ret = -1;
1104
22ebac19 1105 if (!asprintf(&veth1, "%s_%d", file, pid) ||
1106 !asprintf(&veth2, "%s~%d", file, pid) ||
6f4a3756 1107 !asprintf(&path, "%s/%s", directory, file)) {
22ebac19 1108 lxc_log_syserror("failed to allocate memory");
1109 goto out;
1110 }
0ad19a3f 1111
1112 if (read_info(path, "link", bridge, IFNAMSIZ)) {
1113 lxc_log_error("failed to read bridge info");
1114 goto out;
1115 }
1116
1117 if (lxc_configure_veth(veth1, veth2, bridge)) {
1118 lxc_log_error("failed to create %s-%s/%s", veth1, veth2, bridge);
1119 goto out;
1120 }
1121
1122 ifindex = if_nametoindex(veth2);
1123 if (!ifindex) {
1124 lxc_log_error("failed to retrieve the index for %s", veth2);
1125 goto out;
1126 }
1127
22ebac19 1128 if (!asprintf(&strindex, "%d", ifindex)) {
1129 lxc_log_syserror("failed to allocate memory");
1130 goto out;
1131 }
1132
0ad19a3f 1133 if (write_info(path, "ifindex", strindex)) {
1134 lxc_log_error("failed to write interface index to %s", path);
1135 goto out;
1136 }
1137
1138 if (!read_info(path, "up", strindex, sizeof(strindex))) {
1139 if (device_up(veth1)) {
1140 lxc_log_error("failed to set %s up", veth1);
1141 goto out;
1142 }
1143 }
1144
1145 ret = 0;
1146out:
1147 free(path);
1148 free(strindex);
1149 free(veth1);
1150 free(veth2);
1151 return ret;
1152}
6f4a3756 1153static int instanciate_macvlan(const char *directory, const char *file, pid_t pid)
0ad19a3f 1154{
1155 char path[MAXPATHLEN], *strindex = NULL, *peer = NULL;
1156 char link[IFNAMSIZ];
1157 int ifindex, ret = -1;
1158
22ebac19 1159 if (!asprintf(&peer, "%s~%d", file, pid)) {
1160 lxc_log_syserror("failed to allocate memory");
1161 return -1;
1162 }
1163
6f4a3756 1164 snprintf(path, MAXPATHLEN, "%s/%s", directory, file);
0ad19a3f 1165 if (read_info(path, "link", link, IFNAMSIZ)) {
1166 lxc_log_error("failed to read bridge info");
1167 goto out;
1168 }
1169
1170 if (lxc_configure_macvlan(link, peer)) {
1171 lxc_log_error("failed to create macvlan interface %s", peer);
1172 goto out;
1173 }
1174
1175 ifindex = if_nametoindex(peer);
1176 if (!ifindex) {
1177 lxc_log_error("failed to retrieve the index for %s", peer);
1178 goto out;
1179 }
1180
22ebac19 1181 if (!asprintf(&strindex, "%d", ifindex)) {
1182 lxc_log_syserror("failed to allocate memory");
1183 return -1;
1184 }
1185
0ad19a3f 1186 if (write_info(path, "ifindex", strindex)) {
1187 lxc_log_error("failed to write interface index to %s", path);
1188 goto out;
1189 }
1190
1191 ret = 0;
1192out:
1193 free(strindex);
1194 free(peer);
1195 return ret;
1196}
1197
6f4a3756 1198static int instanciate_phys(const char *directory, const char *file, pid_t pid)
0ad19a3f 1199{
1200 char path[MAXPATHLEN], *strindex = NULL;
1201 char link[IFNAMSIZ];
1202 int ifindex, ret = -1;
1203
6f4a3756 1204 snprintf(path, MAXPATHLEN, "%s/%s", directory, file);
0ad19a3f 1205 if (read_info(path, "link", link, IFNAMSIZ)) {
1206 lxc_log_error("failed to read link info");
1207 goto out;
1208 }
1209
1210 ifindex = if_nametoindex(link);
1211 if (!ifindex) {
1212 lxc_log_error("failed to retrieve the index for %s", link);
1213 goto out;
1214 }
1215
22ebac19 1216 if (!asprintf(&strindex, "%d", ifindex)) {
1217 lxc_log_syserror("failed to allocate memory");
1218 return -1;
1219 }
1220
0ad19a3f 1221 if (write_info(path, "ifindex", strindex)) {
1222 lxc_log_error("failed to write interface index to %s", path);
1223 goto out;
1224 }
1225
1226 ret = 0;
1227out:
1228 free(strindex);
1229 return ret;
1230}
1231
6f4a3756 1232static int instanciate_empty(const char *directory, const char *file, pid_t pid)
0ad19a3f 1233{
1234 char path[MAXPATHLEN], *strindex = NULL;
1235 int ret = -1;
1236
6f4a3756 1237 snprintf(path, MAXPATHLEN, "%s/%s", directory, file);
0ad19a3f 1238 if (!asprintf(&strindex, "%d", 0)) {
1239 lxc_log_error("not enough memory");
1240 return -1;
1241 }
1242
1243 if (write_info(path, "ifindex", strindex)) {
1244 lxc_log_error("failed to write interface index to %s", path);
1245 goto out;
1246 }
1247
1248 ret = 0;
1249out:
1250 free(strindex);
1251 return ret;
1252}
1253
6f4a3756 1254static int instanciate_netdev_cb(const char *name, const char *directory,
0ad19a3f 1255 const char *file, void *data)
1256{
1257 pid_t *pid = data;
1258
1259 if (!strncmp("veth", file, strlen("veth")))
6f4a3756 1260 return instanciate_veth(directory, file, *pid);
0ad19a3f 1261 else if (!strncmp("macvlan", file, strlen("macvlan")))
6f4a3756 1262 return instanciate_macvlan(directory, file, *pid);
0ad19a3f 1263 else if (!strncmp("phys", file, strlen("phys")))
6f4a3756 1264 return instanciate_phys(directory, file, *pid);
0ad19a3f 1265 else if (!strncmp("empty", file, strlen("empty")))
6f4a3756 1266 return instanciate_empty(directory, file, *pid);
0ad19a3f 1267
1268 return -1;
1269}
1270
1271static int instanciate_netdev(const char *name, pid_t pid)
1272{
6f4a3756 1273 char directory[MAXPATHLEN];
0ad19a3f 1274
6f4a3756 1275 snprintf(directory, MAXPATHLEN, LXCPATH "/%s/network", name);
1276 return dir_for_each(name, directory, instanciate_netdev_cb, &pid);
0ad19a3f 1277}
1278
6f4a3756 1279static int move_netdev_cb(const char *name, const char *directory,
0ad19a3f 1280 const char *file, void *data)
1281{
1282 char path[MAXPATHLEN], ifname[IFNAMSIZ], strindex[MAXINDEXLEN];
1283 pid_t *pid = data;
1284 int ifindex;
1285
6f4a3756 1286 snprintf(path, MAXPATHLEN, "%s/%s", directory, file);
0ad19a3f 1287 if (read_info(path, "ifindex", strindex, MAXINDEXLEN) < 0) {
1288 lxc_log_error("failed to read index to from %s", path);
1289 return -1;
1290 }
1291
1292 ifindex = atoi(strindex);
1293 if (!ifindex)
1294 return 0;
1295
1296 if (!if_indextoname(ifindex, ifname)) {
1297 lxc_log_error("interface with index %d does not exist",
1298 ifindex);
1299 return -1;
1300 }
1301
1302 if (device_move(ifname, *pid)) {
1303 lxc_log_error("failed to move %s to %d", ifname, *pid);
1304 return -1;
1305 }
1306
1307 return 0;
1308}
1309
1310static int move_netdev(const char *name, pid_t pid)
1311{
6f4a3756 1312 char directory[MAXPATHLEN];
1313 snprintf(directory, MAXPATHLEN, LXCPATH "/%s/network", name);
1314 return dir_for_each(name, directory, move_netdev_cb, &pid);
0ad19a3f 1315}
1316
1317int conf_create_network(const char *name, pid_t pid)
1318{
1319 if (instanciate_netdev(name, pid)) {
1320 lxc_log_error("failed to instantiate the network devices");
1321 return -1;
1322 }
1323
1324 if (move_netdev(name, pid)) {
1325 lxc_log_error("failed to move the netdev to the container");
1326 return -1;
1327 }
1328
1329 return 0;
1330}
1331
6f4a3756 1332static int delete_netdev_cb(const char *name, const char *directory,
0ad19a3f 1333 const char *file, void *data)
1334{
1335 char strindex[MAXINDEXLEN];
1336 char path[MAXPATHLEN];
1337 char ifname[IFNAMSIZ];
1338 int i, ifindex;
1339
6f4a3756 1340 snprintf(path, MAXPATHLEN, "%s/%s", directory, file);
0ad19a3f 1341
1342 if (read_info(path, "ifindex", strindex, MAXINDEXLEN)) {
1343 lxc_log_error("failed to read ifindex info");
1344 return -1;
1345 }
1346
1347 ifindex = atoi(strindex);
1348 if (!ifindex)
1349 return 0;
1350
1351 /* TODO : temporary code - needs wait on namespace */
1352 for (i = 0; i < 120; i++) {
1353 if (if_indextoname(ifindex, ifname))
1354 break;
1355 if (!i)
1356 printf("waiting for interface #%d to come back\n", ifindex);
1357 else
1358 printf("."); fflush(stdout);
1359 sleep(1);
1360 }
1361
1362 /* do not delete a physical network device */
1363 if (strncmp("phys", file, strlen("phys")))
1364 if (device_delete(ifname)) {
1365 lxc_log_error("failed to remove the netdev %s", ifname);
1366 }
1367
1368 delete_info(path, "ifindex");
1369
1370 return 0;
1371}
1372
1373static int delete_netdev(const char *name)
1374{
6f4a3756 1375 char directory[MAXPATHLEN];
0ad19a3f 1376
6f4a3756 1377 snprintf(directory, MAXPATHLEN, LXCPATH "/%s/network", name);
1378 return dir_for_each(name, directory, delete_netdev_cb, NULL);
0ad19a3f 1379}
1380
1381int conf_destroy_network(const char *name)
1382{
6e590161 1383#ifdef NETWORK_DESTROY
0ad19a3f 1384 if (delete_netdev(name)) {
1385 lxc_log_error("failed to remove the network devices");
1386 return -1;
1387 }
6e590161 1388#endif
0ad19a3f 1389 return 0;
1390}
1391
6e590161 1392int lxc_setup(const char *name, const char *tty)
0ad19a3f 1393{
1394 if (conf_has_utsname(name) && setup_utsname(name)) {
1395 lxc_log_error("failed to setup the utsname for '%s'", name);
e5bda9ee 1396 return -LXC_ERROR_SETUP_UTSNAME;
0ad19a3f 1397 }
1398
1399 if (conf_has_network(name) && setup_network(name)) {
1400 lxc_log_error("failed to setup the network for '%s'", name);
e5bda9ee 1401 return -LXC_ERROR_SETUP_NETWORK;
0ad19a3f 1402 }
1403
8c6c9475 1404 if (conf_has_cgroup(name) && setup_cgroup(name)) {
1405 lxc_log_error("failed to setup the cgroups for '%s'", name);
e5bda9ee 1406 return -LXC_ERROR_SETUP_CGROUP;
0ad19a3f 1407 }
1408
8c6c9475 1409 if (conf_has_fstab(name) && setup_mount(name)) {
6e590161 1410 lxc_log_error("failed to setup the mounts for '%s'", name);
e5bda9ee 1411 return -LXC_ERROR_SETUP_MOUNT;
576f946d 1412 }
1413
eae6543d 1414 if (conf_has_rootfs(name) && setup_rootfs(name)) {
1415 lxc_log_error("failed to set rootfs for '%s'", name);
e5bda9ee 1416 return -LXC_ERROR_SETUP_ROOTFS;
0ad19a3f 1417 }
1418
6e590161 1419 if (tty[0] && setup_console(name, tty)) {
1420 lxc_log_error("failed to setup the console for '%s'", name);
1421 return -LXC_ERROR_SETUP_CONSOLE;
1422 }
1423
0ad19a3f 1424 return 0;
1425}