]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/confile_legacy.c
lxc-start: remove unnecessary checks
[mirror_lxc.git] / src / lxc / confile_legacy.c
1 /*
2 * lxc: linux Container library
3 * (C) Copyright IBM Corp. 2007, 2008
4 *
5 * Authors:
6 * Daniel Lezcano <daniel.lezcano at free.fr>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22 #define _GNU_SOURCE
23 #define __STDC_FORMAT_MACROS /* Required for PRIu64 to work. */
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <ctype.h>
31 #include <inttypes.h> /* Required for PRIu64 to work. */
32 #include <signal.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35 #include <sys/param.h>
36 #include <sys/utsname.h>
37 #include <arpa/inet.h>
38 #include <netinet/in.h>
39 #include <net/if.h>
40 #include <time.h>
41 #include <dirent.h>
42 #include <syslog.h>
43
44 #include "parse.h"
45 #include "config.h"
46 #include "confile.h"
47 #include "confile_utils.h"
48 #include "confile_legacy.h"
49 #include "utils.h"
50 #include "log.h"
51 #include "conf.h"
52 #include "network.h"
53 #include "lxcseccomp.h"
54 #include "storage.h"
55
56 #if HAVE_IFADDRS_H
57 #include <ifaddrs.h>
58 #else
59 #include <../include/ifaddrs.h>
60 #endif
61
62 lxc_log_define(lxc_confile_legacy, lxc);
63
64 /*
65 * Config entry is something like "lxc.network.0.ipv4" the key 'lxc.network.'
66 * was found. So we make sure next comes an integer, find the right callback
67 * (by rewriting the key), and call it.
68 */
69 int set_config_network_legacy_nic(const char *key, const char *value,
70 struct lxc_conf *lxc_conf, void *data)
71 {
72 char *copy = strdup(key), *p;
73 int ret = -1;
74 struct lxc_config_t *config;
75
76 if (!copy) {
77 SYSERROR("failed to allocate memory");
78 return -1;
79 }
80 /*
81 * Ok we know that to get here we've got "lxc.network."
82 * and it isn't any of the other network entries. So
83 * after the second . Should come an integer (# of defined
84 * nic) followed by a valid entry.
85 */
86 if (*(key + 12) < '0' || *(key + 12) > '9')
87 goto out;
88
89 p = strchr(key + 12, '.');
90 if (!p)
91 goto out;
92
93 strcpy(copy + 12, p + 1);
94 config = lxc_get_config(copy);
95 if (!config) {
96 ERROR("unknown key %s", key);
97 goto out;
98 }
99 ret = config->set(key, value, lxc_conf, NULL);
100
101 out:
102 free(copy);
103 return ret;
104 }
105
106 static void lxc_remove_nic(struct lxc_list *it)
107 {
108 struct lxc_netdev *netdev = it->elem;
109 struct lxc_list *it2,*next;
110
111 lxc_list_del(it);
112
113 free(netdev->upscript);
114 free(netdev->downscript);
115 free(netdev->hwaddr);
116 free(netdev->mtu);
117 free(netdev->ipv4_gateway);
118 free(netdev->ipv6_gateway);
119 lxc_list_for_each_safe(it2, &netdev->ipv4, next) {
120 lxc_list_del(it2);
121 free(it2->elem);
122 free(it2);
123 }
124 lxc_list_for_each_safe(it2, &netdev->ipv6, next) {
125 lxc_list_del(it2);
126 free(it2->elem);
127 free(it2);
128 }
129 free(netdev);
130 free(it);
131 }
132
133 static int lxc_clear_config_network(struct lxc_conf *c)
134 {
135 struct lxc_list *it,*next;
136 lxc_list_for_each_safe(it, &c->network, next) {
137 lxc_remove_nic(it);
138 }
139 return 0;
140 }
141
142 int set_config_network_legacy(const char *key, const char *value,
143 struct lxc_conf *lxc_conf, void *data)
144 {
145 if (!lxc_config_value_empty(value)) {
146 ERROR("lxc.network must not have a value");
147 return -1;
148 }
149
150 return lxc_clear_config_network(lxc_conf);
151 }
152
153 int set_config_network_legacy_type(const char *key, const char *value,
154 struct lxc_conf *lxc_conf, void *data)
155 {
156 struct lxc_list *network = &lxc_conf->network;
157 struct lxc_netdev *netdev, *prevnetdev;
158 struct lxc_list *list;
159
160 if (lxc_config_value_empty(value))
161 return lxc_clear_config_network(lxc_conf);
162
163 netdev = malloc(sizeof(*netdev));
164 if (!netdev) {
165 SYSERROR("failed to allocate memory");
166 return -1;
167 }
168
169 memset(netdev, 0, sizeof(*netdev));
170 lxc_list_init(&netdev->ipv4);
171 lxc_list_init(&netdev->ipv6);
172
173 list = malloc(sizeof(*list));
174 if (!list) {
175 SYSERROR("failed to allocate memory");
176 free(netdev);
177 return -1;
178 }
179
180 lxc_list_init(list);
181 list->elem = netdev;
182
183 /* We maintain a negative count for legacy networks. */
184 netdev->idx = -1;
185 if (!lxc_list_empty(network)) {
186 prevnetdev = lxc_list_last_elem(network);
187 netdev->idx = prevnetdev->idx;
188 if (netdev->idx == INT_MIN) {
189 ERROR("number of requested networks would underflow "
190 "counter");
191 free(netdev);
192 free(list);
193 return -1;
194 }
195 netdev->idx--;
196 }
197
198 lxc_list_add_tail(network, list);
199
200 if (!strcmp(value, "veth"))
201 netdev->type = LXC_NET_VETH;
202 else if (!strcmp(value, "macvlan")) {
203 netdev->type = LXC_NET_MACVLAN;
204 lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, "private");
205 } else if (!strcmp(value, "vlan"))
206 netdev->type = LXC_NET_VLAN;
207 else if (!strcmp(value, "phys"))
208 netdev->type = LXC_NET_PHYS;
209 else if (!strcmp(value, "empty"))
210 netdev->type = LXC_NET_EMPTY;
211 else if (!strcmp(value, "none"))
212 netdev->type = LXC_NET_NONE;
213 else {
214 ERROR("invalid network type %s", value);
215 return -1;
216 }
217 return 0;
218 }
219
220 /*
221 * If you have p="lxc.network.0.link", pass it p+12
222 * to get back '0' (the index of the nic).
223 */
224 static int get_network_netdev_idx(const char *key)
225 {
226 int ret, idx;
227
228 if (*key < '0' || *key > '9')
229 return EINVAL;
230
231 ret = sscanf(key, "%d", &idx);
232 if (ret != 1)
233 return EINVAL;
234
235 /* Since we've implemented the new network parser legacy networks are
236 * recorded using a negative index starting from -1. To preserve the old
237 * behavior we need this function to return the appropriate negative
238 * index.
239 */
240 return -(++idx);
241 }
242
243 /*
244 * If you have p="lxc.network.0", pass this p+12 and it will return
245 * the netdev of the first configured nic.
246 */
247 static struct lxc_netdev *get_netdev_from_key(const char *key,
248 struct lxc_list *network)
249 {
250 int idx;
251 struct lxc_list *it;
252 struct lxc_netdev *netdev = NULL;
253
254 idx = get_network_netdev_idx(key);
255 if (idx == EINVAL)
256 return NULL;
257
258 lxc_list_for_each(it, network) {
259 netdev = it->elem;
260 if (idx == netdev->idx)
261 return netdev;
262 }
263
264 return NULL;
265 }
266
267 int lxc_list_nicconfigs_legacy(struct lxc_conf *c, const char *key, char *retv,
268 int inlen)
269 {
270 struct lxc_netdev *netdev;
271 int len;
272 int fulllen = 0;
273
274 netdev = get_netdev_from_key(key + 12, &c->network);
275 if (!netdev)
276 return -1;
277
278 if (!retv)
279 inlen = 0;
280 else
281 memset(retv, 0, inlen);
282
283 strprint(retv, inlen, "type\n");
284 strprint(retv, inlen, "script.up\n");
285 strprint(retv, inlen, "script.down\n");
286 if (netdev->type != LXC_NET_EMPTY) {
287 strprint(retv, inlen, "flags\n");
288 strprint(retv, inlen, "link\n");
289 strprint(retv, inlen, "name\n");
290 strprint(retv, inlen, "hwaddr\n");
291 strprint(retv, inlen, "mtu\n");
292 strprint(retv, inlen, "ipv6\n");
293 strprint(retv, inlen, "ipv6.gateway\n");
294 strprint(retv, inlen, "ipv4\n");
295 strprint(retv, inlen, "ipv4.gateway\n");
296 }
297
298 switch (netdev->type) {
299 case LXC_NET_VETH:
300 strprint(retv, inlen, "veth.pair\n");
301 break;
302 case LXC_NET_MACVLAN:
303 strprint(retv, inlen, "macvlan.mode\n");
304 break;
305 case LXC_NET_VLAN:
306 strprint(retv, inlen, "vlan.id\n");
307 break;
308 case LXC_NET_PHYS:
309 break;
310 }
311
312 return fulllen;
313 }
314
315 static struct lxc_netdev *network_netdev(const char *key, const char *value,
316 struct lxc_list *network)
317 {
318 struct lxc_netdev *netdev = NULL;
319
320 if (lxc_list_empty(network)) {
321 ERROR("network is not created for '%s' = '%s' option", key,
322 value);
323 return NULL;
324 }
325
326 if (get_network_netdev_idx(key + 12) == EINVAL)
327 netdev = lxc_list_last_elem(network);
328 else
329 netdev = get_netdev_from_key(key + 12, network);
330
331 if (!netdev) {
332 ERROR("no network device defined for '%s' = '%s' option", key,
333 value);
334 return NULL;
335 }
336
337 return netdev;
338 }
339
340 int set_config_network_legacy_flags(const char *key, const char *value,
341 struct lxc_conf *lxc_conf, void *data)
342 {
343 struct lxc_netdev *netdev;
344
345 netdev = network_netdev(key, value, &lxc_conf->network);
346 if (!netdev)
347 return -1;
348
349 netdev->flags |= IFF_UP;
350
351 return 0;
352 }
353
354 static int create_matched_ifnames(const char *value, struct lxc_conf *lxc_conf,
355 struct lxc_netdev *netdev)
356 {
357 struct ifaddrs *ifaddr, *ifa;
358 int n;
359 int ret = 0;
360 const char *type_key = "lxc.network.type";
361 const char *link_key = "lxc.network.link";
362 const char *tmpvalue = "phys";
363
364 if (getifaddrs(&ifaddr) == -1) {
365 SYSERROR("Get network interfaces failed");
366 return -1;
367 }
368
369 for (ifa = ifaddr, n = 0; ifa != NULL; ifa = ifa->ifa_next, n++) {
370 if (!ifa->ifa_addr)
371 continue;
372 if (ifa->ifa_addr->sa_family != AF_PACKET)
373 continue;
374
375 if (!strncmp(value, ifa->ifa_name, strlen(value) - 1)) {
376 ret = set_config_network_legacy_type(type_key, tmpvalue,
377 lxc_conf, netdev);
378 if (!ret) {
379 ret = set_config_network_legacy_link(
380 link_key, ifa->ifa_name, lxc_conf, netdev);
381 if (ret) {
382 ERROR("failed to create matched ifnames");
383 break;
384 }
385 } else {
386 ERROR("failed to create matched ifnames");
387 break;
388 }
389 }
390 }
391
392 freeifaddrs(ifaddr);
393 ifaddr = NULL;
394
395 return ret;
396 }
397
398 int set_config_network_legacy_link(const char *key, const char *value,
399 struct lxc_conf *lxc_conf, void *data)
400 {
401 struct lxc_netdev *netdev;
402 struct lxc_list *it;
403 int ret = 0;
404
405 netdev = network_netdev(key, value, &lxc_conf->network);
406 if (!netdev)
407 return -1;
408
409 if (value[strlen(value) - 1] == '+' && netdev->type == LXC_NET_PHYS) {
410 /* Get the last network list and remove it. */
411 it = lxc_conf->network.prev;
412 if (((struct lxc_netdev *)(it->elem))->type != LXC_NET_PHYS) {
413 ERROR("lxc config cannot support string pattern "
414 "matching for this link type");
415 return -1;
416 }
417
418 lxc_list_del(it);
419 free(it);
420 ret = create_matched_ifnames(value, lxc_conf, NULL);
421 } else {
422 ret = network_ifname(netdev->link, value);
423 }
424
425 return ret;
426 }
427
428 int set_config_network_legacy_name(const char *key, const char *value,
429 struct lxc_conf *lxc_conf, void *data)
430 {
431 struct lxc_netdev *netdev;
432
433 netdev = network_netdev(key, value, &lxc_conf->network);
434 if (!netdev)
435 return -1;
436
437 return network_ifname(netdev->name, value);
438 }
439
440 int set_config_network_legacy_veth_pair(const char *key, const char *value,
441 struct lxc_conf *lxc_conf, void *data)
442 {
443 struct lxc_netdev *netdev;
444
445 netdev = network_netdev(key, value, &lxc_conf->network);
446 if (!netdev)
447 return -1;
448
449 if (netdev->type != LXC_NET_VETH) {
450 ERROR("Invalid veth pair for a non-veth netdev");
451 return -1;
452 }
453
454 return network_ifname(netdev->priv.veth_attr.pair, value);
455 }
456
457 int set_config_network_legacy_macvlan_mode(const char *key, const char *value,
458 struct lxc_conf *lxc_conf,
459 void *data)
460 {
461 struct lxc_netdev *netdev;
462
463 netdev = network_netdev(key, value, &lxc_conf->network);
464 if (!netdev)
465 return -1;
466
467 if (netdev->type != LXC_NET_MACVLAN) {
468 ERROR("Invalid macvlan.mode for a non-macvlan netdev");
469 return -1;
470 }
471
472 return lxc_macvlan_mode_to_flag(&netdev->priv.macvlan_attr.mode, value);
473 }
474
475 int set_config_network_legacy_hwaddr(const char *key, const char *value,
476 struct lxc_conf *lxc_conf, void *data)
477 {
478 struct lxc_netdev *netdev;
479 char *new_value;
480
481 new_value = strdup(value);
482 if (!new_value) {
483 SYSERROR("failed to strdup \"%s\"", value);
484 return -1;
485 }
486 rand_complete_hwaddr(new_value);
487
488 netdev = network_netdev(key, new_value, &lxc_conf->network);
489 if (!netdev) {
490 free(new_value);
491 return -1;
492 };
493
494 if (lxc_config_value_empty(new_value)) {
495 free(new_value);
496 netdev->hwaddr = NULL;
497 return 0;
498 }
499
500 netdev->hwaddr = new_value;
501 return 0;
502 }
503
504 int set_config_network_legacy_vlan_id(const char *key, const char *value,
505 struct lxc_conf *lxc_conf, void *data)
506 {
507 struct lxc_netdev *netdev;
508
509 netdev = network_netdev(key, value, &lxc_conf->network);
510 if (!netdev)
511 return -1;
512
513 if (netdev->type != LXC_NET_VLAN) {
514 ERROR("Invalid vlan.id for a non-macvlan netdev");
515 return -1;
516 }
517
518 if (get_u16(&netdev->priv.vlan_attr.vid, value, 0))
519 return -1;
520
521 return 0;
522 }
523
524 int set_config_network_legacy_mtu(const char *key, const char *value,
525 struct lxc_conf *lxc_conf, void *data)
526 {
527 struct lxc_netdev *netdev;
528
529 netdev = network_netdev(key, value, &lxc_conf->network);
530 if (!netdev)
531 return -1;
532
533 return set_config_string_item(&netdev->mtu, value);
534 }
535
536 int set_config_network_legacy_ipv4(const char *key, const char *value,
537 struct lxc_conf *lxc_conf, void *data)
538 {
539 struct lxc_netdev *netdev;
540 struct lxc_inetdev *inetdev;
541 struct lxc_list *list;
542 char *cursor, *slash;
543 char *addr = NULL, *bcast = NULL, *prefix = NULL;
544
545 if (lxc_config_value_empty(value))
546 return clr_config_network_legacy_item(key, lxc_conf, NULL);
547
548 netdev = network_netdev(key, value, &lxc_conf->network);
549 if (!netdev)
550 return -1;
551
552 inetdev = malloc(sizeof(*inetdev));
553 if (!inetdev) {
554 SYSERROR("failed to allocate ipv4 address");
555 return -1;
556 }
557 memset(inetdev, 0, sizeof(*inetdev));
558
559 list = malloc(sizeof(*list));
560 if (!list) {
561 SYSERROR("failed to allocate memory");
562 free(inetdev);
563 return -1;
564 }
565
566 lxc_list_init(list);
567 list->elem = inetdev;
568
569 addr = strdup(value);
570 if (!addr) {
571 ERROR("no address specified");
572 free(inetdev);
573 free(list);
574 return -1;
575 }
576
577 cursor = strstr(addr, " ");
578 if (cursor) {
579 *cursor = '\0';
580 bcast = cursor + 1;
581 }
582
583 slash = strstr(addr, "/");
584 if (slash) {
585 *slash = '\0';
586 prefix = slash + 1;
587 }
588
589 if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
590 SYSERROR("invalid ipv4 address: %s", value);
591 free(inetdev);
592 free(addr);
593 free(list);
594 return -1;
595 }
596
597 if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) {
598 SYSERROR("invalid ipv4 broadcast address: %s", value);
599 free(inetdev);
600 free(list);
601 free(addr);
602 return -1;
603 }
604
605 /* No prefix specified, determine it from the network class. */
606 if (prefix) {
607 if (lxc_safe_uint(prefix, &inetdev->prefix) < 0)
608 return -1;
609 } else {
610 inetdev->prefix = config_ip_prefix(&inetdev->addr);
611 }
612
613 /* If no broadcast address, let compute one from the
614 * prefix and address.
615 */
616 if (!bcast) {
617 inetdev->bcast.s_addr = inetdev->addr.s_addr;
618 inetdev->bcast.s_addr |=
619 htonl(INADDR_BROADCAST >> inetdev->prefix);
620 }
621
622 lxc_list_add_tail(&netdev->ipv4, list);
623
624 free(addr);
625 return 0;
626 }
627
628 int set_config_network_legacy_ipv4_gateway(const char *key, const char *value,
629 struct lxc_conf *lxc_conf,
630 void *data)
631 {
632 struct lxc_netdev *netdev;
633
634 netdev = network_netdev(key, value, &lxc_conf->network);
635 if (!netdev)
636 return -1;
637
638 free(netdev->ipv4_gateway);
639
640 if (lxc_config_value_empty(value)) {
641 netdev->ipv4_gateway = NULL;
642 } else if (!strcmp(value, "auto")) {
643 netdev->ipv4_gateway = NULL;
644 netdev->ipv4_gateway_auto = true;
645 } else {
646 struct in_addr *gw;
647
648 gw = malloc(sizeof(*gw));
649 if (!gw) {
650 SYSERROR("failed to allocate ipv4 gateway address");
651 return -1;
652 }
653
654 if (!inet_pton(AF_INET, value, gw)) {
655 SYSERROR("invalid ipv4 gateway address: %s", value);
656 free(gw);
657 return -1;
658 }
659
660 netdev->ipv4_gateway = gw;
661 netdev->ipv4_gateway_auto = false;
662 }
663
664 return 0;
665 }
666
667 int set_config_network_legacy_ipv6(const char *key, const char *value,
668 struct lxc_conf *lxc_conf, void *data)
669 {
670 struct lxc_netdev *netdev;
671 struct lxc_inet6dev *inet6dev;
672 struct lxc_list *list;
673 char *slash, *valdup, *netmask;
674
675 if (lxc_config_value_empty(value))
676 return clr_config_network_legacy_item(key, lxc_conf, NULL);
677
678 netdev = network_netdev(key, value, &lxc_conf->network);
679 if (!netdev)
680 return -1;
681
682 inet6dev = malloc(sizeof(*inet6dev));
683 if (!inet6dev) {
684 SYSERROR("failed to allocate ipv6 address");
685 return -1;
686 }
687 memset(inet6dev, 0, sizeof(*inet6dev));
688
689 list = malloc(sizeof(*list));
690 if (!list) {
691 SYSERROR("failed to allocate memory");
692 free(inet6dev);
693 return -1;
694 }
695
696 lxc_list_init(list);
697 list->elem = inet6dev;
698
699 valdup = strdup(value);
700 if (!valdup) {
701 ERROR("no address specified");
702 free(list);
703 free(inet6dev);
704 return -1;
705 }
706
707 inet6dev->prefix = 64;
708 slash = strstr(valdup, "/");
709 if (slash) {
710 *slash = '\0';
711 netmask = slash + 1;
712 if (lxc_safe_uint(netmask, &inet6dev->prefix) < 0)
713 return -1;
714 }
715
716 if (!inet_pton(AF_INET6, valdup, &inet6dev->addr)) {
717 SYSERROR("invalid ipv6 address: %s", valdup);
718 free(list);
719 free(inet6dev);
720 free(valdup);
721 return -1;
722 }
723
724 lxc_list_add_tail(&netdev->ipv6, list);
725
726 free(valdup);
727 return 0;
728 }
729
730 int set_config_network_legacy_ipv6_gateway(const char *key, const char *value,
731 struct lxc_conf *lxc_conf,
732 void *data)
733 {
734 struct lxc_netdev *netdev;
735
736 netdev = network_netdev(key, value, &lxc_conf->network);
737 if (!netdev)
738 return -1;
739
740 free(netdev->ipv6_gateway);
741
742 if (lxc_config_value_empty(value)) {
743 netdev->ipv6_gateway = NULL;
744 } else if (!strcmp(value, "auto")) {
745 netdev->ipv6_gateway = NULL;
746 netdev->ipv6_gateway_auto = true;
747 } else {
748 struct in6_addr *gw;
749
750 gw = malloc(sizeof(*gw));
751 if (!gw) {
752 SYSERROR("failed to allocate ipv6 gateway address");
753 return -1;
754 }
755
756 if (!inet_pton(AF_INET6, value, gw)) {
757 SYSERROR("invalid ipv6 gateway address: %s", value);
758 free(gw);
759 return -1;
760 }
761
762 netdev->ipv6_gateway = gw;
763 netdev->ipv6_gateway_auto = false;
764 }
765
766 return 0;
767 }
768
769 int set_config_network_legacy_script_up(const char *key, const char *value,
770 struct lxc_conf *lxc_conf, void *data)
771 {
772 struct lxc_netdev *netdev;
773
774 netdev = network_netdev(key, value, &lxc_conf->network);
775 if (!netdev)
776 return -1;
777
778 return set_config_string_item(&netdev->upscript, value);
779 }
780
781 int set_config_network_legacy_script_down(const char *key, const char *value,
782 struct lxc_conf *lxc_conf, void *data)
783 {
784 struct lxc_netdev *netdev;
785
786 netdev = network_netdev(key, value, &lxc_conf->network);
787 if (!netdev)
788 return -1;
789
790 return set_config_string_item(&netdev->downscript, value);
791 }
792
793 int get_config_network_legacy(const char *key, char *retv, int inlen,
794 struct lxc_conf *c, void *data)
795 {
796 int len, fulllen = 0;
797 struct lxc_list *it;
798
799 if (!retv)
800 inlen = 0;
801 else
802 memset(retv, 0, inlen);
803
804 lxc_list_for_each(it, &c->network) {
805 struct lxc_netdev *n = it->elem;
806 const char *t = lxc_net_type_to_str(n->type);
807 strprint(retv, inlen, "%s\n", t ? t : "(invalid)");
808 }
809
810 return fulllen;
811 }
812
813 /*
814 * lxc.network.0.XXX, where XXX can be: name, type, link, flags, type,
815 * macvlan.mode, veth.pair, vlan, ipv4, ipv6, script.up, hwaddr, mtu,
816 * ipv4.gateway, ipv6.gateway. ipvX.gateway can return 'auto' instead
817 * of an address. ipv4 and ipv6 return lists (newline-separated).
818 * things like veth.pair return '' if invalid (i.e. if called for vlan
819 * type).
820 */
821 int get_config_network_legacy_item(const char *key, char *retv, int inlen,
822 struct lxc_conf *c, void *data)
823 {
824 char *p1;
825 int len, fulllen = 0;
826 struct lxc_netdev *netdev;
827
828 if (!retv)
829 inlen = 0;
830 else
831 memset(retv, 0, inlen);
832
833 if (!strncmp(key, "lxc.network.", 12))
834 key += 12;
835 else
836 return -1;
837
838 p1 = strchr(key, '.');
839 if (!p1 || *(p1 + 1) == '\0')
840 return -1;
841 p1++;
842
843 netdev = get_netdev_from_key(key, &c->network);
844 if (!netdev)
845 return -1;
846 if (strcmp(p1, "name") == 0) {
847 if (netdev->name[0] != '\0')
848 strprint(retv, inlen, "%s", netdev->name);
849 } else if (strcmp(p1, "type") == 0) {
850 strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type));
851 } else if (strcmp(p1, "link") == 0) {
852 if (netdev->link[0] != '\0')
853 strprint(retv, inlen, "%s", netdev->link);
854 } else if (strcmp(p1, "flags") == 0) {
855 if (netdev->flags & IFF_UP)
856 strprint(retv, inlen, "up");
857 } else if (strcmp(p1, "script.up") == 0) {
858 if (netdev->upscript)
859 strprint(retv, inlen, "%s", netdev->upscript);
860 } else if (strcmp(p1, "script.down") == 0) {
861 if (netdev->downscript)
862 strprint(retv, inlen, "%s", netdev->downscript);
863 } else if (strcmp(p1, "hwaddr") == 0) {
864 if (netdev->hwaddr)
865 strprint(retv, inlen, "%s", netdev->hwaddr);
866 } else if (strcmp(p1, "mtu") == 0) {
867 if (netdev->mtu)
868 strprint(retv, inlen, "%s", netdev->mtu);
869 } else if (strcmp(p1, "macvlan.mode") == 0) {
870 if (netdev->type == LXC_NET_MACVLAN) {
871 const char *mode;
872 switch (netdev->priv.macvlan_attr.mode) {
873 case MACVLAN_MODE_PRIVATE:
874 mode = "private";
875 break;
876 case MACVLAN_MODE_VEPA:
877 mode = "vepa";
878 break;
879 case MACVLAN_MODE_BRIDGE:
880 mode = "bridge";
881 break;
882 case MACVLAN_MODE_PASSTHRU:
883 mode = "passthru";
884 break;
885 default:
886 mode = "(invalid)";
887 break;
888 }
889 strprint(retv, inlen, "%s", mode);
890 }
891 } else if (strcmp(p1, "veth.pair") == 0) {
892 if (netdev->type == LXC_NET_VETH) {
893 strprint(retv, inlen, "%s",
894 netdev->priv.veth_attr.pair[0] != '\0'
895 ? netdev->priv.veth_attr.pair
896 : netdev->priv.veth_attr.veth1);
897 }
898 } else if (strcmp(p1, "vlan") == 0) {
899 if (netdev->type == LXC_NET_VLAN) {
900 strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid);
901 }
902 } else if (strcmp(p1, "ipv4.gateway") == 0) {
903 if (netdev->ipv4_gateway_auto) {
904 strprint(retv, inlen, "auto");
905 } else if (netdev->ipv4_gateway) {
906 char buf[INET_ADDRSTRLEN];
907 inet_ntop(AF_INET, netdev->ipv4_gateway, buf,
908 sizeof(buf));
909 strprint(retv, inlen, "%s", buf);
910 }
911 } else if (strcmp(p1, "ipv4") == 0) {
912 struct lxc_list *it2;
913 lxc_list_for_each(it2, &netdev->ipv4) {
914 struct lxc_inetdev *i = it2->elem;
915 char buf[INET_ADDRSTRLEN];
916 inet_ntop(AF_INET, &i->addr, buf, sizeof(buf));
917 strprint(retv, inlen, "%s/%u\n", buf, i->prefix);
918 }
919 } else if (strcmp(p1, "ipv6.gateway") == 0) {
920 if (netdev->ipv6_gateway_auto) {
921 strprint(retv, inlen, "auto");
922 } else if (netdev->ipv6_gateway) {
923 char buf[INET6_ADDRSTRLEN];
924 inet_ntop(AF_INET6, netdev->ipv6_gateway, buf,
925 sizeof(buf));
926 strprint(retv, inlen, "%s", buf);
927 }
928 } else if (strcmp(p1, "ipv6") == 0) {
929 struct lxc_list *it2;
930 lxc_list_for_each(it2, &netdev->ipv6) {
931 struct lxc_inet6dev *i = it2->elem;
932 char buf[INET6_ADDRSTRLEN];
933 inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf));
934 strprint(retv, inlen, "%s/%u\n", buf, i->prefix);
935 }
936 }
937 return fulllen;
938 }
939
940 /* we get passed in something like '0', '0.ipv4' or '1.ipv6' */
941 static int lxc_clear_nic(struct lxc_conf *c, const char *key)
942 {
943 char *p1;
944 int idx;
945 struct lxc_list *it = NULL;
946 struct lxc_netdev *netdev = NULL;
947
948 if (lxc_list_empty(&c->network)) {
949 ERROR("network is not created for %s", key);
950 return -1;
951 }
952
953 if ((idx = get_network_netdev_idx(key)) == EINVAL)
954 netdev = lxc_list_last_elem(&c->network);
955 else {
956 lxc_list_for_each(it, &c->network) {
957 netdev = it->elem;
958 if (idx == netdev->idx)
959 break;
960 netdev = NULL;
961 }
962 }
963 if (!netdev)
964 return -1;
965
966 p1 = strchr(key, '.');
967 if (!p1 || *(p1+1) == '\0')
968 p1 = NULL;
969
970 if (!p1 && it) {
971 lxc_remove_nic(it);
972 } else if (strcmp(p1, ".ipv4") == 0) {
973 struct lxc_list *it2,*next;
974 lxc_list_for_each_safe(it2, &netdev->ipv4, next) {
975 lxc_list_del(it2);
976 free(it2->elem);
977 free(it2);
978 }
979 } else if (strcmp(p1, ".ipv6") == 0) {
980 struct lxc_list *it2,*next;
981 lxc_list_for_each_safe(it2, &netdev->ipv6, next) {
982 lxc_list_del(it2);
983 free(it2->elem);
984 free(it2);
985 }
986 }
987 else return -1;
988
989 return 0;
990 }
991
992 inline int clr_config_network_legacy_item(const char *key, struct lxc_conf *c,
993 void *data)
994 {
995 return lxc_clear_nic(c, key + 12);
996 }
997
998 inline int clr_config_network_legacy(const char *key, struct lxc_conf *c, void *data)
999 {
1000 return lxc_clear_config_network(c);
1001 }
1002
1003 inline int clr_config_lsm_aa_profile(const char *key, struct lxc_conf *c,
1004 void *data)
1005 {
1006 free(c->lsm_aa_profile);
1007 c->lsm_aa_profile = NULL;
1008 return 0;
1009 }
1010
1011 inline int clr_config_lsm_aa_incomplete(const char *key, struct lxc_conf *c,
1012 void *data)
1013 {
1014 c->lsm_aa_allow_incomplete = 0;
1015 return 0;
1016 }
1017
1018 int get_config_lsm_aa_profile(const char *key, char *retv, int inlen,
1019 struct lxc_conf *c, void *data)
1020 {
1021 return lxc_get_conf_str(retv, inlen, c->lsm_aa_profile);
1022 }
1023
1024 int get_config_lsm_aa_incomplete(const char *key, char *retv, int inlen,
1025 struct lxc_conf *c, void *data)
1026 {
1027 return lxc_get_conf_int(c, retv, inlen,
1028 c->lsm_aa_allow_incomplete);
1029 }
1030
1031 int set_config_lsm_aa_profile(const char *key, const char *value,
1032 struct lxc_conf *lxc_conf, void *data)
1033 {
1034 return set_config_string_item(&lxc_conf->lsm_aa_profile, value);
1035 }
1036
1037 int set_config_lsm_aa_incomplete(const char *key, const char *value,
1038 struct lxc_conf *lxc_conf, void *data)
1039 {
1040 /* Set config value to default. */
1041 if (lxc_config_value_empty(value)) {
1042 lxc_conf->lsm_aa_allow_incomplete = 0;
1043 return 0;
1044 }
1045
1046 /* Parse new config value. */
1047 if (lxc_safe_uint(value, &lxc_conf->lsm_aa_allow_incomplete) < 0)
1048 return -1;
1049
1050 if (lxc_conf->lsm_aa_allow_incomplete > 1) {
1051 ERROR("Wrong value for lxc.lsm_aa_allow_incomplete. Can only "
1052 "be set to 0 or 1");
1053 return -1;
1054 }
1055
1056 return 0;
1057 }
1058
1059 int set_config_lsm_se_context(const char *key, const char *value,
1060 struct lxc_conf *lxc_conf, void *data)
1061 {
1062 return set_config_string_item(&lxc_conf->lsm_se_context, value);
1063 }
1064
1065 int get_config_lsm_se_context(const char *key, char *retv, int inlen,
1066 struct lxc_conf *c, void *data)
1067 {
1068 return lxc_get_conf_str(retv, inlen, c->lsm_se_context);
1069 }
1070
1071 inline int clr_config_lsm_se_context(const char *key, struct lxc_conf *c,
1072 void *data)
1073 {
1074 free(c->lsm_se_context);
1075 c->lsm_se_context = NULL;
1076 return 0;
1077 }
1078
1079 extern int set_config_limit(const char *key, const char *value,
1080 struct lxc_conf *lxc_conf, void *data)
1081 {
1082 struct lxc_list *iter;
1083 struct rlimit limit;
1084 rlim_t limit_value;
1085 struct lxc_list *limlist = NULL;
1086 struct lxc_limit *limelem = NULL;
1087
1088 if (lxc_config_value_empty(value))
1089 return lxc_clear_limits(lxc_conf, key);
1090
1091 if (strncmp(key, "lxc.limit.", sizeof("lxc.limit.") - 1) != 0)
1092 return -1;
1093
1094 key += sizeof("lxc.limit.") - 1;
1095
1096 /* soft limit comes first in the value */
1097 if (!parse_limit_value(&value, &limit_value))
1098 return -1;
1099 limit.rlim_cur = limit_value;
1100
1101 /* skip spaces and a colon */
1102 while (isspace(*value))
1103 ++value;
1104
1105 if (*value == ':')
1106 ++value;
1107 else if (*value) /* any other character is an error here */
1108 return -1;
1109
1110 while (isspace(*value))
1111 ++value;
1112
1113 /* optional hard limit */
1114 if (*value) {
1115 if (!parse_limit_value(&value, &limit_value))
1116 return -1;
1117 limit.rlim_max = limit_value;
1118
1119 /* check for trailing garbage */
1120 while (isspace(*value))
1121 ++value;
1122
1123 if (*value)
1124 return -1;
1125 } else {
1126 /* a single value sets both hard and soft limit */
1127 limit.rlim_max = limit.rlim_cur;
1128 }
1129
1130 /* find existing list element */
1131 lxc_list_for_each(iter, &lxc_conf->limits)
1132 {
1133 limelem = iter->elem;
1134 if (!strcmp(key, limelem->resource)) {
1135 limelem->limit = limit;
1136 return 0;
1137 }
1138 }
1139
1140 /* allocate list element */
1141 limlist = malloc(sizeof(*limlist));
1142 if (!limlist)
1143 goto out;
1144
1145 limelem = malloc(sizeof(*limelem));
1146 if (!limelem)
1147 goto out;
1148 memset(limelem, 0, sizeof(*limelem));
1149
1150 limelem->resource = strdup(key);
1151 if (!limelem->resource)
1152 goto out;
1153 limelem->limit = limit;
1154
1155 limlist->elem = limelem;
1156
1157 lxc_list_add_tail(&lxc_conf->limits, limlist);
1158
1159 return 0;
1160
1161 out:
1162 free(limlist);
1163 if (limelem) {
1164 free(limelem->resource);
1165 free(limelem);
1166 }
1167 return -1;
1168 }
1169
1170 /*
1171 * If you ask for a specific value, i.e. lxc.limit.nofile, then just the value
1172 * will be printed. If you ask for 'lxc.limit', then all limit entries will be
1173 * printed, in 'lxc.limit.resource = value' format.
1174 */
1175 extern int get_config_limit(const char *key, char *retv, int inlen,
1176 struct lxc_conf *c, void *data)
1177 {
1178 int fulllen = 0, len;
1179 bool get_all = false;
1180 struct lxc_list *it;
1181
1182 if (!retv)
1183 inlen = 0;
1184 else
1185 memset(retv, 0, inlen);
1186
1187 if (!strcmp(key, "lxc.limit"))
1188 get_all = true;
1189 else if (strncmp(key, "lxc.limit.", 10) == 0)
1190 key += 10;
1191 else
1192 return -1;
1193
1194 lxc_list_for_each(it, &c->limits) {
1195 char buf[LXC_NUMSTRLEN64 * 2 + 2]; /* 2 colon separated 64 bit
1196 integers or the word
1197 'unlimited' */
1198 int partlen;
1199 struct lxc_limit *lim = it->elem;
1200
1201 if (lim->limit.rlim_cur == RLIM_INFINITY) {
1202 memcpy(buf, "unlimited", sizeof("unlimited"));
1203 partlen = sizeof("unlimited") - 1;
1204 } else {
1205 partlen = sprintf(buf, "%" PRIu64,
1206 (uint64_t)lim->limit.rlim_cur);
1207 }
1208 if (lim->limit.rlim_cur != lim->limit.rlim_max) {
1209 if (lim->limit.rlim_max == RLIM_INFINITY) {
1210 memcpy(buf + partlen, ":unlimited",
1211 sizeof(":unlimited"));
1212 } else {
1213 sprintf(buf + partlen, ":%" PRIu64,
1214 (uint64_t)lim->limit.rlim_max);
1215 }
1216 }
1217
1218 if (get_all) {
1219 strprint(retv, inlen, "lxc.limit.%s = %s\n",
1220 lim->resource, buf);
1221 } else if (strcmp(lim->resource, key) == 0) {
1222 strprint(retv, inlen, "%s", buf);
1223 }
1224 }
1225
1226 return fulllen;
1227 }
1228
1229 extern int clr_config_limit(const char *key, struct lxc_conf *c,
1230 void *data)
1231 {
1232 return lxc_clear_limits(c, key);
1233 }