]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/confile_utils.c
3 * Copyright © 2017 Christian Brauner <christian.brauner@ubuntu.com>.
4 * Copyright © 2017 Canonical Ltd.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2, as
8 * published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 #include <arpa/inet.h>
30 #include "confile_utils.h"
37 lxc_log_define(lxc_confile_utils
, lxc
);
39 int parse_idmaps(const char *idmap
, char *type
, unsigned long *nsid
,
40 unsigned long *hostid
, unsigned long *range
)
43 unsigned long tmp_hostid
, tmp_nsid
, tmp_range
;
48 /* Duplicate string. */
53 /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
58 slide
+= strspn(slide
, " \t\r");
59 if (slide
!= window
&& *slide
== '\0')
63 if (*slide
!= 'u' && *slide
!= 'g')
68 /* move beyond type */
72 /* Validate that only whitespace follows. */
73 slide
+= strspn(slide
, " \t\r");
74 /* There must be whitespace. */
78 /* Mark beginning of nsuid. */
80 /* Validate that non-whitespace follows. */
81 slide
+= strcspn(slide
, " \t\r");
82 /* There must be non-whitespace. */
83 if (slide
== window
|| *slide
== '\0')
85 /* Mark end of nsuid. */
89 if (lxc_safe_ulong(window
, &tmp_nsid
) < 0)
96 /* Validate that only whitespace follows. */
97 slide
+= strspn(slide
, " \t\r");
98 /* If there was only one whitespace then we whiped it with our \0 above.
99 * So only ensure that we're not at the end of the string.
104 /* Mark beginning of hostid. */
106 /* Validate that non-whitespace follows. */
107 slide
+= strcspn(slide
, " \t\r");
108 /* There must be non-whitespace. */
109 if (slide
== window
|| *slide
== '\0')
111 /* Mark end of nsuid. */
115 if (lxc_safe_ulong(window
, &tmp_hostid
) < 0)
118 /* Move beyond \0. */
122 /* Validate that only whitespace follows. */
123 slide
+= strspn(slide
, " \t\r");
124 /* If there was only one whitespace then we whiped it with our \0 above.
125 * So only ensure that we're not at the end of the string.
130 /* Mark beginning of range. */
132 /* Validate that non-whitespace follows. */
133 slide
+= strcspn(slide
, " \t\r");
134 /* There must be non-whitespace. */
138 /* The range is the last valid entry we expect. So make sure that there
139 * is not trailing garbage and if there is, error out.
141 if (*(slide
+ strspn(slide
, " \t\r\n")) != '\0')
143 /* Mark end of range. */
147 if (lxc_safe_ulong(window
, &tmp_range
) < 0)
152 *hostid
= tmp_hostid
;
155 /* Yay, we survived. */
164 bool lxc_config_value_empty(const char *value
)
166 if (value
&& strlen(value
) > 0)
172 struct lxc_netdev
*lxc_network_add(struct lxc_list
*networks
, int idx
, bool tail
)
174 struct lxc_list
*newlist
;
175 struct lxc_netdev
*netdev
= NULL
;
177 /* network does not exist */
178 netdev
= malloc(sizeof(*netdev
));
182 memset(netdev
, 0, sizeof(*netdev
));
183 lxc_list_init(&netdev
->ipv4
);
184 lxc_list_init(&netdev
->ipv6
);
186 /* give network a unique index */
189 /* prepare new list */
190 newlist
= malloc(sizeof(*newlist
));
196 lxc_list_init(newlist
);
197 newlist
->elem
= netdev
;
200 lxc_list_add_tail(networks
, newlist
);
202 lxc_list_add(networks
, newlist
);
206 /* Takes care of finding the correct netdev struct in the networks list or
207 * allocates a new one if it couldn't be found.
209 struct lxc_netdev
*lxc_get_netdev_by_idx(struct lxc_conf
*conf
,
210 unsigned int idx
, bool allocate
)
212 struct lxc_netdev
*netdev
= NULL
;
213 struct lxc_list
*networks
= &conf
->network
;
214 struct lxc_list
*insert
= networks
;
217 if (!lxc_list_empty(networks
)) {
218 lxc_list_for_each(insert
, networks
) {
219 netdev
= insert
->elem
;
220 if (netdev
->idx
== idx
)
222 else if (netdev
->idx
> idx
)
230 return lxc_network_add(insert
, idx
, true);
233 void lxc_log_configured_netdevs(const struct lxc_conf
*conf
)
235 struct lxc_netdev
*netdev
;
236 struct lxc_list
*it
= (struct lxc_list
*)&conf
->network
;;
238 if ((conf
->loglevel
!= LXC_LOG_LEVEL_TRACE
) &&
239 (lxc_log_get_level() != LXC_LOG_LEVEL_TRACE
))
242 if (lxc_list_empty(it
)) {
243 TRACE("container has no networks configured");
247 lxc_list_for_each(it
, &conf
->network
) {
248 struct lxc_list
*cur
, *next
;
249 struct lxc_inetdev
*inet4dev
;
250 struct lxc_inet6dev
*inet6dev
;
251 char bufinet4
[INET_ADDRSTRLEN
], bufinet6
[INET6_ADDRSTRLEN
];
255 TRACE("index: %zd", netdev
->idx
);
256 switch (netdev
->type
) {
259 if (netdev
->priv
.veth_attr
.pair
)
260 TRACE("veth pair: %s",
261 netdev
->priv
.veth_attr
.pair
);
263 case LXC_NET_MACVLAN
:
264 TRACE("type: macvlan");
265 if (netdev
->priv
.macvlan_attr
.mode
> 0) {
267 macvlan_mode
= lxc_macvlan_flag_to_mode(
268 netdev
->priv
.macvlan_attr
.mode
);
269 TRACE("macvlan mode: %s",
270 macvlan_mode
? macvlan_mode
276 TRACE("vlan id: %d", netdev
->priv
.vlan_attr
.vid
);
282 TRACE("type: empty");
288 ERROR("invalid network type %d", netdev
->type
);
292 if (netdev
->type
!= LXC_NET_EMPTY
) {
294 netdev
->flags
== IFF_UP
? "up" : "none");
296 TRACE("link: %s", netdev
->link
);
298 TRACE("name: %s", netdev
->name
);
300 TRACE("hwaddr: %s", netdev
->hwaddr
);
302 TRACE("mtu: %s", netdev
->mtu
);
303 if (netdev
->upscript
)
304 TRACE("upscript: %s", netdev
->upscript
);
305 if (netdev
->downscript
)
306 TRACE("downscript: %s", netdev
->downscript
);
308 TRACE("ipv4 gateway auto: %s",
309 netdev
->ipv4_gateway_auto
? "true" : "false");
311 if (netdev
->ipv4_gateway
) {
312 inet_ntop(AF_INET
, netdev
->ipv4_gateway
,
313 bufinet4
, sizeof(bufinet4
));
314 TRACE("ipv4 gateway: %s", bufinet4
);
317 lxc_list_for_each_safe(cur
, &netdev
->ipv4
, next
) {
318 inet4dev
= cur
->elem
;
319 inet_ntop(AF_INET
, &inet4dev
->addr
, bufinet4
,
321 TRACE("ipv4 addr: %s", bufinet4
);
324 TRACE("ipv6 gateway auto: %s",
325 netdev
->ipv6_gateway_auto
? "true" : "false");
326 if (netdev
->ipv6_gateway
) {
327 inet_ntop(AF_INET6
, netdev
->ipv6_gateway
,
328 bufinet6
, sizeof(bufinet6
));
329 TRACE("ipv6 gateway: %s", bufinet6
);
331 lxc_list_for_each_safe(cur
, &netdev
->ipv6
, next
) {
332 inet6dev
= cur
->elem
;
333 inet_ntop(AF_INET6
, &inet6dev
->addr
, bufinet6
,
335 TRACE("ipv6 addr: %s", bufinet6
);
341 static void lxc_free_netdev(struct lxc_netdev
*netdev
)
343 struct lxc_list
*cur
, *next
;
347 if (netdev
->type
== LXC_NET_VETH
)
348 free(netdev
->priv
.veth_attr
.pair
);
349 free(netdev
->upscript
);
350 free(netdev
->downscript
);
351 free(netdev
->hwaddr
);
354 free(netdev
->ipv4_gateway
);
355 lxc_list_for_each_safe(cur
, &netdev
->ipv4
, next
) {
361 free(netdev
->ipv6_gateway
);
362 lxc_list_for_each_safe(cur
, &netdev
->ipv6
, next
) {
371 bool lxc_remove_nic_by_idx(struct lxc_conf
*conf
, unsigned int idx
)
373 struct lxc_list
*cur
, *next
;
374 struct lxc_netdev
*netdev
;
377 lxc_list_for_each_safe(cur
, &conf
->network
, next
) {
379 if (netdev
->idx
!= idx
)
390 lxc_free_netdev(netdev
);
396 void lxc_free_networks(struct lxc_list
*networks
)
398 struct lxc_list
*cur
, *next
;
399 struct lxc_netdev
*netdev
;
401 lxc_list_for_each_safe(cur
, networks
, next
) {
403 lxc_free_netdev(netdev
);
407 /* prevent segfaults */
408 lxc_list_init(networks
);
411 static struct macvlan_mode
{
415 { "private", MACVLAN_MODE_PRIVATE
},
416 { "vepa", MACVLAN_MODE_VEPA
},
417 { "bridge", MACVLAN_MODE_BRIDGE
},
418 { "passthru", MACVLAN_MODE_PASSTHRU
},
421 int lxc_macvlan_mode_to_flag(int *mode
, const char *value
)
425 for (i
= 0; i
< sizeof(macvlan_mode
) / sizeof(macvlan_mode
[0]); i
++) {
426 if (strcmp(macvlan_mode
[i
].name
, value
))
429 *mode
= macvlan_mode
[i
].mode
;
436 char *lxc_macvlan_flag_to_mode(int mode
)
440 for (i
= 0; i
< sizeof(macvlan_mode
) / sizeof(macvlan_mode
[0]); i
++) {
441 if (macvlan_mode
[i
].mode
== mode
)
444 return macvlan_mode
[i
].name
;
450 int set_config_string_item(char **conf_item
, const char *value
)
454 if (lxc_config_value_empty(value
)) {
460 new_value
= strdup(value
);
462 SYSERROR("failed to duplicate string \"%s\"", value
);
467 *conf_item
= new_value
;
471 int set_config_string_item_max(char **conf_item
, const char *value
, size_t max
)
473 if (strlen(value
) >= max
) {
474 ERROR("%s is too long (>= %lu)", value
, (unsigned long)max
);
478 return set_config_string_item(conf_item
, value
);
481 int set_config_path_item(char **conf_item
, const char *value
)
483 return set_config_string_item_max(conf_item
, value
, PATH_MAX
);
486 int config_ip_prefix(struct in_addr
*addr
)
488 if (IN_CLASSA(addr
->s_addr
))
489 return 32 - IN_CLASSA_NSHIFT
;
490 if (IN_CLASSB(addr
->s_addr
))
491 return 32 - IN_CLASSB_NSHIFT
;
492 if (IN_CLASSC(addr
->s_addr
))
493 return 32 - IN_CLASSC_NSHIFT
;
498 int network_ifname(char **valuep
, const char *value
)
500 return set_config_string_item_max(valuep
, value
, IFNAMSIZ
);
503 int rand_complete_hwaddr(char *hwaddr
)
505 const char hex
[] = "0123456789abcdef";
513 seed
= randseed(false);
515 while (*curs
!= '\0' && *curs
!= '\n') {
516 if (*curs
== 'x' || *curs
== 'X') {
517 if (curs
- hwaddr
== 1) {
518 /* ensure address is unicast */
520 *curs
= hex
[rand_r(&seed
) & 0x0E];
522 *curs
= hex
[rand_r(&seed
) & 0x0F];
524 *curs
= hex
[rand() & 0x0E];
526 *curs
= hex
[rand() & 0x0F];
535 bool lxc_config_net_hwaddr(const char *line
)
539 if (strncmp(line
, "lxc.net", 7) != 0)
541 if (strncmp(line
, "lxc.network.hwaddr", 18) == 0)
544 /* We have to dup the line, if line is something like
545 * "lxc.net.[i].xxx = xxxxx ", we need to remove
546 * '[i]' and compare its key with 'lxc.net.hwaddr'*/
549 SYSERROR("failed to allocate memory");
552 if (*(copy
+ 8) >= '0' && *(copy
+ 8) <= '9') {
553 p
= strchr(copy
+ 8, '.');
558 /* strlen("hwaddr") = 6 */
559 strncpy(copy
+ 8, p
+ 1, 6);
562 if (strncmp(copy
, "lxc.net.hwaddr", 14) == 0) {
568 /* We have to dup the line second time, if line is something like
569 * "lxc.network.[i].xxx = xxxxx ", we need to remove
570 * '[i]' and compare its key with 'lxc.network.hwaddr'*/
573 SYSERROR("failed to allocate memory");
576 if (*(copy
+ 12) >= '0' && *(copy
+ 12) <= '9') {
577 p
= strchr(copy
+ 12, '.');
582 /* strlen("hwaddr") = 6 */
583 strncpy(copy
+ 12, p
+ 1, 6);
586 if (strncmp(copy
, "lxc.network.hwaddr", 18) == 0) {
596 * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
597 * file, we expand it in the unexpanded_config, so that after a save_config we
598 * store the hwaddr for re-use.
599 * This is only called when reading the config file, not when executing a
601 * 'x' and 'X' are substituted in-place.
603 void update_hwaddr(const char *line
)
607 line
+= lxc_char_left_gc(line
, strlen(line
));
611 if (!lxc_config_net_hwaddr(line
))
614 /* Let config_net_hwaddr raise the error. */
615 p
= strchr(line
, '=');
626 rand_complete_hwaddr(p
);
629 bool new_hwaddr(char *hwaddr
)
633 (void)randseed(true);
635 ret
= snprintf(hwaddr
, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
636 rand() % 255, rand() % 255);
637 if (ret
< 0 || ret
>= 18) {
638 SYSERROR("Failed to call snprintf().");
645 int lxc_get_conf_str(char *retv
, int inlen
, const char *value
)
649 if (retv
&& inlen
>= strlen(value
) + 1)
650 strncpy(retv
, value
, strlen(value
) + 1);
652 return strlen(value
);
655 int lxc_get_conf_int(struct lxc_conf
*c
, char *retv
, int inlen
, int v
)
660 memset(retv
, 0, inlen
);
662 return snprintf(retv
, inlen
, "%d", v
);
665 bool parse_limit_value(const char **value
, unsigned long *res
)
669 if (strncmp(*value
, "unlimited", sizeof("unlimited") - 1) == 0) {
670 *res
= RLIM_INFINITY
;
671 *value
+= sizeof("unlimited") - 1;
676 *res
= strtoul(*value
, &endptr
, 10);
677 if (errno
|| !endptr
)