]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/lxc_conf.c
Change freezer to stick with the cgroup freezer fs API, replace "RUNNING" by "THAWED"
[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>
45
b113348e 46#include <lxc/lxc.h>
0ad19a3f 47#include <network.h>
48
49#define MAXHWLEN 18
50#define MAXINDEXLEN 20
51#define MAXLINELEN 128
52
53typedef int (*instanciate_cb)(const char *dirname,
54 const char *file, pid_t pid);
55
56typedef int (*dir_cb)(const char *name, const char *dirname,
57 const char *file, void *data);
58
59typedef int (*file_cb)(void* buffer, void *data);
60
61struct netdev_conf {
62 const char *type;
63 instanciate_cb cb;
64 int count;
65};
66
67static int instanciate_veth(const char *, const char *, pid_t);
68static int instanciate_macvlan(const char *, const char *, pid_t);
69static int instanciate_phys(const char *, const char *, pid_t);
70static int instanciate_empty(const char *, const char *, pid_t);
71
72static struct netdev_conf netdev_conf[MAXCONFTYPE + 1] = {
73 [VETH] = { "veth", instanciate_veth, 0 },
74 [MACVLAN] = { "macvlan", instanciate_macvlan, 0, },
75 [PHYS] = { "phys", instanciate_phys, 0, },
76 [EMPTY] = { "empty", instanciate_empty, 0, },
77};
78
79static int dir_filter(const struct dirent *dirent)
80{
81 if (!strcmp(dirent->d_name, ".") ||
82 !strcmp(dirent->d_name, ".."))
83 return 0;
84 return 1;
85}
86
87static int dir_for_each(const char *name, const char *dirname,
88 dir_cb callback, void *data)
89{
90 struct dirent **namelist;
91 int n;
92
93 n = scandir(dirname, &namelist, dir_filter, alphasort);
94 if (n < 0) {
95 lxc_log_syserror("failed to scan %s directory", dirname);
96 return -1;
97 }
98
99 while (n--) {
100 if (callback(name, dirname, namelist[n]->d_name, data)) {
101 lxc_log_error("callback failed");
102 free(namelist[n]);
103 return -1;
104 }
105 free(namelist[n]);
106 }
107
108 return 0;
109}
110
111static int file_for_each_line(const char *file, file_cb callback,
112 void *buffer, size_t len, void* data)
113{
114 FILE *f;
115 int err = -1;
116
117 f = fopen(file, "r");
118 if (!f) {
119 lxc_log_syserror("failed to open %s", file);
120 return -1;
121 }
122
123 while (fgets(buffer, len, f))
124 if (callback(buffer, data))
125 goto out;
126 err = 0;
127out:
128 fclose(f);
129 return err;
130}
131
132static int write_info(const char *path, const char *file, const char *info)
133{
134 int fd, err = -1;
135 char *f;
136
137 asprintf(&f, "%s/%s", path, file);
138 fd = creat(f, 0755);
139 if (fd < 0)
140 goto out;
141
142 if (write(fd, info, strlen(info)) < 0 ||
143 write(fd, "\n", strlen("\n") + 1) < 0)
144 goto out_write;
145 err = 0;
146out:
147 close(fd);
148 free(f);
149 return err;
150
151out_write:
152 unlink(f);
153 goto out;
154}
155
156static int read_info(const char *path, const char *file, char *info, size_t len)
157{
158 int fd, ret = -1;
159 char *f, *token;
160
161 asprintf(&f, "%s/%s", path, file);
162 fd = open(f, O_RDONLY);
163 if (fd < 0) {
164 if (errno == ENOENT)
165 ret = 1;
166 goto out;
167 }
168
169 ret = read(fd, info, len);
170 if (ret < 0)
171 goto out;
172
173 token = strstr(info, "\n");
174 if (token)
175 *token = '\0';
176 ret = 0;
177out:
178 close(fd);
179 free(f);
180 return ret;
181}
182
183static int delete_info(const char *path, const char *file)
184{
185 char *info;
186 int ret;
187
188 asprintf(&info, "%s/%s", path, file);
189 ret = unlink(info);
190 free(info);
191
192 return ret;
193}
194
195static int configure_ip4addr(int fd, struct lxc_inetdev *in)
196{
197 char addr[INET6_ADDRSTRLEN];
198 char bcast[INET_ADDRSTRLEN];
199 char *line = NULL;
200 int err = -1;
201
202 if (!inet_ntop(AF_INET, &in->addr, addr, sizeof(addr))) {
203 lxc_log_syserror("failed to convert ipv4 address");
204 goto err;
205 }
206
207 if (!inet_ntop(AF_INET, &in->bcast, bcast, sizeof(bcast))) {
208 lxc_log_syserror("failed to convert ipv4 broadcast");
209 goto err;
210 }
211
212 if (in->prefix)
213 asprintf(&line, "%s/%d %s\n", addr, in->prefix, bcast);
214 else
215 asprintf(&line, "%s %s\n", addr, bcast);
216
217 if (write(fd, line, strlen(line)) < 0) {
218 lxc_log_syserror("failed to write address info");
219 goto err;
220 }
221
222 err = 0;
223err:
224 free(line);
225 return err;
226}
227
228static int configure_ip6addr(int fd, struct lxc_inet6dev *in6)
229{
230 char addr[INET6_ADDRSTRLEN];
231 char *line = NULL;
232 int err = -1;
233
234 if (!inet_ntop(AF_INET6, &in6->addr, addr, sizeof(addr))) {
235 lxc_log_syserror("failed to convert ipv4 address");
236 goto err;
237 }
238
239 asprintf(&line, "%s/%d\n", addr, in6->prefix?in6->prefix:64);
240
241 if (write(fd, line, strlen(line)) < 0) {
242 lxc_log_syserror("failed to write address info");
243 goto err;
244 }
245
246 err = 0;
247err:
248 free(line);
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
402static int configure_cgroup(const char *name, struct lxc_cgroup *cgroup)
403{
404 return 0;
405}
406
eae6543d 407static int configure_rootfs(const char *name, const char *rootfs)
0ad19a3f 408{
409 char path[MAXPATHLEN];
b09ef133 410 char absrootfs[MAXPATHLEN];
411 char *pwd;
0ad19a3f 412
eae6543d 413 snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name);
0ad19a3f 414
b09ef133 415 pwd = get_current_dir_name();
416
417 snprintf(absrootfs, MAXPATHLEN, "%s/%s", pwd, rootfs);
418
419 free(pwd);
420
421 if (access(absrootfs, F_OK)) {
422 lxc_log_syserror("'%s' is not accessible", absrootfs);
423 return -1;
424 }
425
426 return symlink(absrootfs, path);
0ad19a3f 427
428}
429
430static int configure_mount(const char *name, const char *fstab)
431{
432 char *path;
433 struct stat stat;
434 int infd, outfd;
435 void *src, *dst;
436 char c = '\0';
437 int ret = -1;
438
439 asprintf(&path, LXCPATH "/%s/fstab", name);
440
441 outfd = open(path, O_RDWR|O_CREAT|O_EXCL, 0640);
442 if (outfd < 0) {
443 lxc_log_syserror("failed to creat '%s'", path);
444 goto out;
445 }
446
447 infd = open(fstab, O_RDONLY);
448 if (infd < 0) {
449 lxc_log_syserror("failed to open '%s'", fstab);
450 goto out;
451 }
452
453 if (fstat(infd, &stat)) {
454 lxc_log_syserror("failed to stat '%s'", fstab);
455 goto out;
456 }
457
458 if (lseek(outfd, stat.st_size - 1, SEEK_SET) < 0) {
459 lxc_log_syserror("failed to seek dest file '%s'", path);
460 goto out;
461 }
462
463 /* fixup length */
464 if (write(outfd, &c, 1) < 0) {
465 lxc_log_syserror("failed to write to '%s'", path);
466 goto out;
467 }
468
469 src = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, infd, 0L);
470 if (src == MAP_FAILED) {
471 lxc_log_syserror("failed to mmap '%s'", fstab);
472 goto out;
473 }
474
475 dst = mmap(NULL, stat.st_size, PROT_WRITE, MAP_SHARED, outfd, 0L);
476 if (dst == MAP_FAILED) {
477 lxc_log_syserror("failed to mmap '%s'", path);
478 goto out;
479 }
480
481 memcpy(dst, src, stat.st_size);
482
483 munmap(src, stat.st_size);
484 munmap(dst, stat.st_size);
485
486 ret = 0;
487out:
488 free(path);
489 return ret;
490}
491
492static int unconfigure_ip_addresses(const char *dirname)
493{
494 char path[MAXPATHLEN];
495
496 snprintf(path, MAXPATHLEN, "%s/ipv4", dirname);
497 delete_info(path, "addresses");
498 rmdir(path);
499
500 snprintf(path, MAXPATHLEN, "%s/ipv6", dirname);
501 delete_info(path, "addresses");
502 rmdir(path);
503
504 return 0;
505}
506
507static int unconfigure_network_cb(const char *name, const char *dirname,
508 const char *file, void *data)
509{
510 char path[MAXPATHLEN];
511
512 snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
b09ef133 513 delete_info(path, "ifindex");
0ad19a3f 514 delete_info(path, "name");
515 delete_info(path, "addr");
516 delete_info(path, "link");
517 delete_info(path, "hwaddr");
518 delete_info(path, "up");
519 unconfigure_ip_addresses(path);
520 rmdir(path);
521
522 return 0;
523}
524
525static int unconfigure_network(const char *name)
526{
527 char dirname[MAXPATHLEN];
528
529 snprintf(dirname, MAXPATHLEN, LXCPATH "/%s/network", name);
530 dir_for_each(name, dirname, unconfigure_network_cb, NULL);
531 rmdir(dirname);
532
533 return 0;
534}
535
536static int unconfigure_cgroup(const char *name)
537{
b09ef133 538 char path[MAXPATHLEN];
539
540 snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
541 delete_info(path, "nsgroup");
542
0ad19a3f 543 return 0;
544}
545
eae6543d 546static int unconfigure_rootfs(const char *name)
0ad19a3f 547{
548 char path[MAXPATHLEN];
549
550 snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
eae6543d 551 delete_info(path, "rootfs");
0ad19a3f 552
553 return 0;
554}
555
556static int unconfigure_mount(const char *name)
557{
558 char path[MAXPATHLEN];
559
560 snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
561 delete_info(path, "fstab");
562
563 return 0;
564}
565
566static int unconfigure_utsname(const char *name)
567{
568 char path[MAXPATHLEN];
569
570 snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
571 delete_info(path, "utsname");
572
573 return 0;
574}
575
576static int setup_utsname(const char *name)
577{
578 int ret;
579 char path[MAXPATHLEN];
580 struct utsname utsname;
581
582 snprintf(path, MAXPATHLEN, LXCPATH "/%s", name);
583
584 ret = read_info(path, "utsname", utsname.nodename,
585 sizeof(utsname.nodename));
586 if (ret < 0) {
587 lxc_log_syserror("failed to read utsname info");
588 return -1;
589 }
590
591 if (!ret && sethostname(utsname.nodename, strlen(utsname.nodename))) {
592 lxc_log_syserror("failed to set the hostname to '%s'",
593 utsname.nodename);
594 return -1;
595 }
596
597 return 0;
598}
599
eae6543d 600static int setup_rootfs(const char *name)
0ad19a3f 601{
602 char path[MAXPATHLEN], chrt[MAXPATHLEN];
603
eae6543d 604 snprintf(path, MAXPATHLEN, LXCPATH "/%s/rootfs", name);
0ad19a3f 605
606 if (readlink(path, chrt, MAXPATHLEN) > 0) {
607
608 if (chroot(chrt)) {
609 lxc_log_syserror("failed to set chroot %s", path);
610 return -1;
611 }
612
613 if (chdir(getenv("HOME")) && chdir("/")) {
614 lxc_log_syserror("failed to change to home directory");
615 return -1;
616 }
617 }
618
619 return 0;
620}
621
622static int setup_mount(const char *name)
623{
624 char path[MAXPATHLEN];
625 struct mntent *mntent;
626 FILE *file;
627 int ret = -1;
628 unsigned long mntflags = 0;
629
630 snprintf(path, MAXPATHLEN, LXCPATH "/%s/fstab", name);
631
632 file = setmntent(path, "r");
633 if (!file) {
634 if (errno == ENOENT)
635 return 0;
636 lxc_log_syserror("failed to open '%s'", path);
637 goto out;
638 }
639
640 while((mntent = getmntent(file))) {
641
642 if (hasmntopt(mntent, "bind"))
643 mntflags |= MS_BIND;
644
645 if (mount(mntent->mnt_fsname, mntent->mnt_dir,
646 mntent->mnt_type, mntflags, NULL)) {
647 lxc_log_syserror("failed to mount '%s' on '%s'",
648 mntent->mnt_fsname, mntent->mnt_dir);
649 goto out;
650 }
651 }
652 ret = 0;
653out:
654 endmntent(file);
655 return ret;
656}
657
658static int setup_ipv4_addr_cb(void *buffer, void *data)
659{
660 char *ifname = data;
661 char *cursor, *slash, *addr, *bcast = NULL, *prefix = NULL;
662 int p = 24;
663
664 addr = buffer;
665 cursor = strstr(addr, " ");
666 if (cursor) {
667 *cursor = '\0';
668 bcast = cursor + 1;
669 cursor = strstr(bcast, "\n");
670 if (cursor)
671 *cursor = '\0';
672 }
673
674 slash = strstr(addr, "/");
675 if (slash) {
676 *slash = '\0';
677 prefix = slash + 1;
678 }
679
680 if (prefix)
681 p = atoi(prefix);
682
683 if (ip_addr_add(ifname, addr, p, bcast)) {
684 lxc_log_error("failed to set %s to addr %s/%d %s", ifname,
685 addr, p, bcast?bcast:"");
686 return -1;
687 }
688
689 return 0;
690}
691
692static int setup_ipv6_addr_cb(void *buffer, void *data)
693{
694 char *ifname = data;
695 char *cursor, *slash, *addr, *bcast = NULL, *prefix = NULL;
696 int p = 24;
697
698 addr = buffer;
699 cursor = strstr(addr, " ");
700 if (cursor) {
701 *cursor = '\0';
702 bcast = cursor + 1;
703 cursor = strstr(bcast, "\n");
704 if (cursor)
705 *cursor = '\0';
706 }
707
708 slash = strstr(addr, "/");
709 if (slash) {
710 *slash = '\0';
711 prefix = slash + 1;
712 }
713
714 if (prefix)
715 p = atoi(prefix);
716
717 if (ip6_addr_add(ifname, addr, p, bcast)) {
718 lxc_log_error("failed to set %s to addr %s/%d %s", ifname,
719 addr, p, bcast?bcast:"");
720 return -1;
721 }
722
723 return 0;
724}
725
726static int setup_hw_addr(char *hwaddr, const char *ifname)
727{
728 struct sockaddr sockaddr;
729 struct ifreq ifr;
730 int ret, fd;
731
732 if (lxc_convert_mac(hwaddr, &sockaddr)) {
733 fprintf(stderr, "conversion has failed\n");
734 return -1;
735 }
736
737 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
738 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
739
740 fd = socket(AF_INET, SOCK_DGRAM, 0);
741 if (fd < 0) {
742 perror("socket");
743 return -1;
744 }
745
746 ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
747 close(fd);
748 if (ret)
749 perror("ioctl");
750
751 return ret;
752}
753
754static int setup_ip_addr(const char *dirname, const char *ifname)
755{
756 char path[MAXPATHLEN], line[MAXLINELEN];
757 struct stat s;
758 int ret = 0;
759
760 snprintf(path, MAXPATHLEN, "%s/ipv4/addresses", dirname);
761 if (!stat(path, &s))
762 ret = file_for_each_line(path, setup_ipv4_addr_cb,
763 line, MAXPATHLEN, (void*)ifname);
764 return ret;
765}
766
767static int setup_ip6_addr(const char *dirname, const char *ifname)
768{
769 char path[MAXPATHLEN], line[MAXLINELEN];
770 struct stat s;
771 int ret = 0;
772
773 snprintf(path, MAXLINELEN, "%s/ipv6/addresses", dirname);
774 if (!stat(path, &s))
775 ret = file_for_each_line(path, setup_ipv6_addr_cb,
776 line, MAXPATHLEN, (void*)ifname);
777 return ret;
778}
779
780static int setup_network_cb(const char *name, const char *dirname,
781 const char *file, void *data)
782{
783 char path[MAXPATHLEN];
784 char strindex[MAXINDEXLEN];
785 char ifname[IFNAMSIZ];
786 char newname[IFNAMSIZ];
787 char hwaddr[MAXHWLEN];
788 char *current_ifname = ifname;
789 int ifindex;
790
791 snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
792
793 if (read_info(path, "ifindex", strindex, sizeof(strindex))) {
794 lxc_log_error("failed to read ifindex info");
795 return -1;
796 }
797
798 ifindex = atoi(strindex);
799 if (!ifindex) {
800 if (!read_info(path, "up", strindex, sizeof(strindex)))
801 if (device_up("lo")) {
802 lxc_log_error("failed to set the loopback up");
803 return -1;
804 }
805 return 0;
806 }
807
808 if (!if_indextoname(ifindex, current_ifname)) {
809 lxc_log_error("no interface corresponding to index '%d'",
810 ifindex);
811 return -1;
812 }
813
814 if (!read_info(path, "name", newname, sizeof(newname))) {
815 if (device_rename(ifname, newname)) {
816 lxc_log_error("failed to rename %s->%s",
817 ifname, newname);
818 return -1;
819 }
820 current_ifname = newname;
821 }
822
823 if (!read_info(path, "hwaddr", hwaddr, sizeof(hwaddr))) {
824 if (setup_hw_addr(hwaddr, current_ifname)) {
825 lxc_log_error("failed to setup hw address for '%s'",
826 current_ifname);
827 return -1;
828 }
829 }
830
831 if (setup_ip_addr(path, current_ifname)) {
832 lxc_log_error("failed to setup ip addresses for '%s'",
833 ifname);
834 return -1;
835 }
836
837 if (setup_ip6_addr(path, current_ifname)) {
838 lxc_log_error("failed to setup ipv6 addresses for '%s'",
839 ifname);
840 return -1;
841 }
842
843 if (!read_info(path, "up", strindex, sizeof(strindex))) {
844 if (device_up(current_ifname)) {
845 lxc_log_error("failed to set '%s' up", current_ifname);
846 return -1;
847 }
848
849 /* the network is up, make the loopback up too */
850 if (device_up("lo")) {
851 lxc_log_error("failed to set the loopback up");
852 return -1;
853 }
854 }
855
856 return 0;
857}
858
859static int setup_network(const char *name)
860{
861 char dirname[MAXPATHLEN];
862
863 snprintf(dirname, MAXPATHLEN, LXCPATH "/%s/network", name);
864 return dir_for_each(name, dirname, setup_network_cb, NULL);
865}
866
867int conf_has(const char *name, const char *info)
868{
b09ef133 869 int ret = 0;
0ad19a3f 870 char path[MAXPATHLEN];
871 struct stat st;
872
873 snprintf(path, MAXPATHLEN, LXCPATH "/%s/%s", name, info);
874
b09ef133 875 if (!stat(path, &st) || !lstat(path, &st)) {
0ad19a3f 876 ret = 1;
877 goto out;
878 }
879
880 if (errno == ENOENT) {
881 ret = 0;
882 goto out;
883 }
884
885 lxc_log_syserror("failed to stat %s info", info);
886out:
887 return ret;
888}
889
890int lxc_configure(const char *name, struct lxc_conf *conf)
891{
892 if (!conf)
893 return 0;
894
895 if (conf->utsname && configure_utsname(name, conf->utsname)) {
896 lxc_log_error("failed to configure the utsname");
897 return -1;
898 }
899
900 if (configure_network(name, &conf->networks)) {
901 lxc_log_error("failed to configure the network");
902 return -1;
903 }
904
905 if (conf->cgroup && configure_cgroup(name, conf->cgroup)) {
906 lxc_log_error("failed to configure the control group");
907 return -1;
908 }
909
eae6543d 910 if (conf->rootfs && configure_rootfs(name, conf->rootfs)) {
911 lxc_log_error("failed to configure the rootfs");
0ad19a3f 912 return -1;
913 }
914
915 if (conf->fstab && configure_mount(name, conf->fstab)) {
916 lxc_log_error("failed to configure the mount points");
917 return -1;
918 }
919
920 return 0;
921}
922
923int lxc_unconfigure(const char *name)
924{
925 if (conf_has_utsname(name) && unconfigure_utsname(name))
926 lxc_log_error("failed to cleanup utsname");
927
928 if (conf_has_network(name) && unconfigure_network(name))
929 lxc_log_error("failed to cleanup the network");
930
931 if (unconfigure_cgroup(name))
932 lxc_log_error("failed to cleanup cgroup");
933
eae6543d 934 if (conf_has_rootfs(name) && unconfigure_rootfs(name))
935 lxc_log_error("failed to cleanup rootfs");
0ad19a3f 936
937 if (conf_has_fstab(name) && unconfigure_mount(name))
938 lxc_log_error("failed to cleanup mount");
939
940 return 0;
941}
942
943static int instanciate_veth(const char *dirname, const char *file, pid_t pid)
944{
945 char *path = NULL, *strindex = NULL, *veth1 = NULL, *veth2 = NULL;
946 char bridge[IFNAMSIZ];
947 int ifindex, ret = -1;
948
949 asprintf(&veth1, "%s_%d", file, pid);
950 asprintf(&veth2, "%s~%d", file, pid);
951 asprintf(&path, "%s/%s", dirname, file);
952
953 if (read_info(path, "link", bridge, IFNAMSIZ)) {
954 lxc_log_error("failed to read bridge info");
955 goto out;
956 }
957
958 if (lxc_configure_veth(veth1, veth2, bridge)) {
959 lxc_log_error("failed to create %s-%s/%s", veth1, veth2, bridge);
960 goto out;
961 }
962
963 ifindex = if_nametoindex(veth2);
964 if (!ifindex) {
965 lxc_log_error("failed to retrieve the index for %s", veth2);
966 goto out;
967 }
968
969 asprintf(&strindex, "%d", ifindex);
970 if (write_info(path, "ifindex", strindex)) {
971 lxc_log_error("failed to write interface index to %s", path);
972 goto out;
973 }
974
975 if (!read_info(path, "up", strindex, sizeof(strindex))) {
976 if (device_up(veth1)) {
977 lxc_log_error("failed to set %s up", veth1);
978 goto out;
979 }
980 }
981
982 ret = 0;
983out:
984 free(path);
985 free(strindex);
986 free(veth1);
987 free(veth2);
988 return ret;
989}
990static int instanciate_macvlan(const char *dirname, const char *file, pid_t pid)
991{
992 char path[MAXPATHLEN], *strindex = NULL, *peer = NULL;
993 char link[IFNAMSIZ];
994 int ifindex, ret = -1;
995
996 asprintf(&peer, "%s~%d", file, pid);
997 snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
998 if (read_info(path, "link", link, IFNAMSIZ)) {
999 lxc_log_error("failed to read bridge info");
1000 goto out;
1001 }
1002
1003 if (lxc_configure_macvlan(link, peer)) {
1004 lxc_log_error("failed to create macvlan interface %s", peer);
1005 goto out;
1006 }
1007
1008 ifindex = if_nametoindex(peer);
1009 if (!ifindex) {
1010 lxc_log_error("failed to retrieve the index for %s", peer);
1011 goto out;
1012 }
1013
1014 asprintf(&strindex, "%d", ifindex);
1015 if (write_info(path, "ifindex", strindex)) {
1016 lxc_log_error("failed to write interface index to %s", path);
1017 goto out;
1018 }
1019
1020 ret = 0;
1021out:
1022 free(strindex);
1023 free(peer);
1024 return ret;
1025}
1026
1027static int instanciate_phys(const char *dirname, const char *file, pid_t pid)
1028{
1029 char path[MAXPATHLEN], *strindex = NULL;
1030 char link[IFNAMSIZ];
1031 int ifindex, ret = -1;
1032
1033 snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
1034 if (read_info(path, "link", link, IFNAMSIZ)) {
1035 lxc_log_error("failed to read link info");
1036 goto out;
1037 }
1038
1039 ifindex = if_nametoindex(link);
1040 if (!ifindex) {
1041 lxc_log_error("failed to retrieve the index for %s", link);
1042 goto out;
1043 }
1044
1045 asprintf(&strindex, "%d", ifindex);
1046 if (write_info(path, "ifindex", strindex)) {
1047 lxc_log_error("failed to write interface index to %s", path);
1048 goto out;
1049 }
1050
1051 ret = 0;
1052out:
1053 free(strindex);
1054 return ret;
1055}
1056
1057static int instanciate_empty(const char *dirname, const char *file, pid_t pid)
1058{
1059 char path[MAXPATHLEN], *strindex = NULL;
1060 int ret = -1;
1061
1062 snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
1063 if (!asprintf(&strindex, "%d", 0)) {
1064 lxc_log_error("not enough memory");
1065 return -1;
1066 }
1067
1068 if (write_info(path, "ifindex", strindex)) {
1069 lxc_log_error("failed to write interface index to %s", path);
1070 goto out;
1071 }
1072
1073 ret = 0;
1074out:
1075 free(strindex);
1076 return ret;
1077}
1078
1079static int instanciate_netdev_cb(const char *name, const char *dirname,
1080 const char *file, void *data)
1081{
1082 pid_t *pid = data;
1083
1084 if (!strncmp("veth", file, strlen("veth")))
1085 return instanciate_veth(dirname, file, *pid);
1086 else if (!strncmp("macvlan", file, strlen("macvlan")))
1087 return instanciate_macvlan(dirname, file, *pid);
1088 else if (!strncmp("phys", file, strlen("phys")))
1089 return instanciate_phys(dirname, file, *pid);
1090 else if (!strncmp("empty", file, strlen("empty")))
1091 return instanciate_empty(dirname, file, *pid);
1092
1093 return -1;
1094}
1095
1096static int instanciate_netdev(const char *name, pid_t pid)
1097{
1098 char *dirname;
1099 int ret;
1100
1101 asprintf(&dirname, LXCPATH "/%s/network", name);
1102 ret = dir_for_each(name, dirname, instanciate_netdev_cb, &pid);
1103 free(dirname);
1104
1105 return ret;
1106}
1107
1108static int move_netdev_cb(const char *name, const char *dirname,
1109 const char *file, void *data)
1110{
1111 char path[MAXPATHLEN], ifname[IFNAMSIZ], strindex[MAXINDEXLEN];
1112 pid_t *pid = data;
1113 int ifindex;
1114
1115 snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
1116 if (read_info(path, "ifindex", strindex, MAXINDEXLEN) < 0) {
1117 lxc_log_error("failed to read index to from %s", path);
1118 return -1;
1119 }
1120
1121 ifindex = atoi(strindex);
1122 if (!ifindex)
1123 return 0;
1124
1125 if (!if_indextoname(ifindex, ifname)) {
1126 lxc_log_error("interface with index %d does not exist",
1127 ifindex);
1128 return -1;
1129 }
1130
1131 if (device_move(ifname, *pid)) {
1132 lxc_log_error("failed to move %s to %d", ifname, *pid);
1133 return -1;
1134 }
1135
1136 return 0;
1137}
1138
1139static int move_netdev(const char *name, pid_t pid)
1140{
1141 char *dirname;
1142 int ret;
1143
1144 asprintf(&dirname, LXCPATH "/%s/network", name);
1145 ret = dir_for_each(name, dirname, move_netdev_cb, &pid);
1146 free(dirname);
1147
1148 return ret;
1149}
1150
1151int conf_create_network(const char *name, pid_t pid)
1152{
1153 if (instanciate_netdev(name, pid)) {
1154 lxc_log_error("failed to instantiate the network devices");
1155 return -1;
1156 }
1157
1158 if (move_netdev(name, pid)) {
1159 lxc_log_error("failed to move the netdev to the container");
1160 return -1;
1161 }
1162
1163 return 0;
1164}
1165
1166static int delete_netdev_cb(const char *name, const char *dirname,
1167 const char *file, void *data)
1168{
1169 char strindex[MAXINDEXLEN];
1170 char path[MAXPATHLEN];
1171 char ifname[IFNAMSIZ];
1172 int i, ifindex;
1173
1174 snprintf(path, MAXPATHLEN, "%s/%s", dirname, file);
1175
1176 if (read_info(path, "ifindex", strindex, MAXINDEXLEN)) {
1177 lxc_log_error("failed to read ifindex info");
1178 return -1;
1179 }
1180
1181 ifindex = atoi(strindex);
1182 if (!ifindex)
1183 return 0;
1184
1185 /* TODO : temporary code - needs wait on namespace */
1186 for (i = 0; i < 120; i++) {
1187 if (if_indextoname(ifindex, ifname))
1188 break;
1189 if (!i)
1190 printf("waiting for interface #%d to come back\n", ifindex);
1191 else
1192 printf("."); fflush(stdout);
1193 sleep(1);
1194 }
1195
1196 /* do not delete a physical network device */
1197 if (strncmp("phys", file, strlen("phys")))
1198 if (device_delete(ifname)) {
1199 lxc_log_error("failed to remove the netdev %s", ifname);
1200 }
1201
1202 delete_info(path, "ifindex");
1203
1204 return 0;
1205}
1206
1207static int delete_netdev(const char *name)
1208{
1209 char *dirname;
1210 int ret;
1211
1212 asprintf(&dirname, LXCPATH "/%s/network", name);
1213 ret = dir_for_each(name, dirname, delete_netdev_cb, NULL);
1214 free(dirname);
1215
1216 return ret;
1217}
1218
1219int conf_destroy_network(const char *name)
1220{
1221 if (delete_netdev(name)) {
1222 lxc_log_error("failed to remove the network devices");
1223 return -1;
1224 }
1225
1226 return 0;
1227}
1228
1229int lxc_setup(const char *name)
1230{
1231 if (conf_has_utsname(name) && setup_utsname(name)) {
1232 lxc_log_error("failed to setup the utsname for '%s'", name);
1233 return -1;
1234 }
1235
1236 if (conf_has_network(name) && setup_network(name)) {
1237 lxc_log_error("failed to setup the network for '%s'", name);
1238 return -1;
1239 }
1240
1241 if (conf_has_fstab(name) && setup_mount(name)) {
1242 lxc_log_error("failed to setup the mount points for '%s'", name);
1243 return -1;
1244 }
1245
eae6543d 1246 if (conf_has_rootfs(name) && setup_rootfs(name)) {
1247 lxc_log_error("failed to set rootfs for '%s'", name);
0ad19a3f 1248 return -1;
1249 }
1250
1251 return 0;
1252}