]>
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"
34 #include "lxccontainer.h"
39 lxc_log_define(lxc_confile_utils
, lxc
);
41 int parse_idmaps(const char *idmap
, char *type
, unsigned long *nsid
,
42 unsigned long *hostid
, unsigned long *range
)
45 unsigned long tmp_hostid
, tmp_nsid
, tmp_range
;
50 /* Duplicate string. */
55 /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
60 slide
+= strspn(slide
, " \t\r");
61 if (slide
!= window
&& *slide
== '\0')
65 if (*slide
!= 'u' && *slide
!= 'g') {
66 ERROR("invalid mapping type: %c", *slide
);
73 /* move beyond type */
77 /* Validate that only whitespace follows. */
78 slide
+= strspn(slide
, " \t\r");
79 /* There must be whitespace. */
83 /* Mark beginning of nsuid. */
85 /* Validate that non-whitespace follows. */
86 slide
+= strcspn(slide
, " \t\r");
87 /* There must be non-whitespace. */
88 if (slide
== window
|| *slide
== '\0')
90 /* Mark end of nsuid. */
94 if (lxc_safe_ulong(window
, &tmp_nsid
) < 0) {
95 ERROR("couldn't parse nsuid: %s", window
);
101 /* Validate that only whitespace follows. */
102 slide
+= strspn(slide
, " \t\r");
103 /* If there was only one whitespace then we whiped it with our \0 above.
104 * So only ensure that we're not at the end of the string.
109 /* Mark beginning of hostid. */
111 /* Validate that non-whitespace follows. */
112 slide
+= strcspn(slide
, " \t\r");
113 /* There must be non-whitespace. */
114 if (slide
== window
|| *slide
== '\0')
116 /* Mark end of nsuid. */
120 if (lxc_safe_ulong(window
, &tmp_hostid
) < 0) {
121 ERROR("couldn't parse hostid: %s", window
);
125 /* Move beyond \0. */
127 /* Validate that only whitespace follows. */
128 slide
+= strspn(slide
, " \t\r");
129 /* If there was only one whitespace then we whiped it with our \0 above.
130 * So only ensure that we're not at the end of the string.
135 /* Mark beginning of range. */
137 /* Validate that non-whitespace follows. */
138 slide
+= strcspn(slide
, " \t\r");
139 /* There must be non-whitespace. */
143 /* The range is the last valid entry we expect. So make sure that there
144 * is not trailing garbage and if there is, error out.
146 if (*(slide
+ strspn(slide
, " \t\r\n")) != '\0')
148 /* Mark end of range. */
152 if (lxc_safe_ulong(window
, &tmp_range
) < 0) {
153 ERROR("couldn't parse range: %s", window
);
159 *hostid
= tmp_hostid
;
162 /* Yay, we survived. */
171 bool lxc_config_value_empty(const char *value
)
173 if (value
&& strlen(value
) > 0)
179 struct lxc_netdev
*lxc_network_add(struct lxc_list
*networks
, int idx
, bool tail
)
181 struct lxc_list
*newlist
;
182 struct lxc_netdev
*netdev
= NULL
;
184 /* network does not exist */
185 netdev
= malloc(sizeof(*netdev
));
189 memset(netdev
, 0, sizeof(*netdev
));
190 lxc_list_init(&netdev
->ipv4
);
191 lxc_list_init(&netdev
->ipv6
);
193 /* give network a unique index */
196 /* prepare new list */
197 newlist
= malloc(sizeof(*newlist
));
203 lxc_list_init(newlist
);
204 newlist
->elem
= netdev
;
207 lxc_list_add_tail(networks
, newlist
);
209 lxc_list_add(networks
, newlist
);
213 /* Takes care of finding the correct netdev struct in the networks list or
214 * allocates a new one if it couldn't be found.
216 struct lxc_netdev
*lxc_get_netdev_by_idx(struct lxc_conf
*conf
,
217 unsigned int idx
, bool allocate
)
219 struct lxc_netdev
*netdev
= NULL
;
220 struct lxc_list
*networks
= &conf
->network
;
221 struct lxc_list
*insert
= networks
;
224 if (!lxc_list_empty(networks
)) {
225 lxc_list_for_each(insert
, networks
) {
226 netdev
= insert
->elem
;
227 if (netdev
->idx
== idx
)
229 else if (netdev
->idx
> idx
)
237 return lxc_network_add(insert
, idx
, true);
240 void lxc_log_configured_netdevs(const struct lxc_conf
*conf
)
242 struct lxc_netdev
*netdev
;
243 struct lxc_list
*it
= (struct lxc_list
*)&conf
->network
;;
245 if ((conf
->loglevel
!= LXC_LOG_LEVEL_TRACE
) &&
246 (lxc_log_get_level() != LXC_LOG_LEVEL_TRACE
))
249 if (lxc_list_empty(it
)) {
250 TRACE("container has no networks configured");
254 lxc_list_for_each(it
, &conf
->network
) {
255 struct lxc_list
*cur
, *next
;
256 struct lxc_inetdev
*inet4dev
;
257 struct lxc_inet6dev
*inet6dev
;
258 char bufinet4
[INET_ADDRSTRLEN
], bufinet6
[INET6_ADDRSTRLEN
];
262 TRACE("index: %zd", netdev
->idx
);
263 TRACE("ifindex: %d", netdev
->ifindex
);
264 switch (netdev
->type
) {
267 if (netdev
->priv
.veth_attr
.pair
[0] != '\0')
268 TRACE("veth pair: %s",
269 netdev
->priv
.veth_attr
.pair
);
270 if (netdev
->priv
.veth_attr
.veth1
[0] != '\0')
272 netdev
->priv
.veth_attr
.veth1
);
273 if (netdev
->priv
.veth_attr
.ifindex
> 0)
274 TRACE("host side ifindex for veth device: %d",
275 netdev
->priv
.veth_attr
.ifindex
);
277 case LXC_NET_MACVLAN
:
278 TRACE("type: macvlan");
279 if (netdev
->priv
.macvlan_attr
.mode
> 0) {
281 macvlan_mode
= lxc_macvlan_flag_to_mode(
282 netdev
->priv
.macvlan_attr
.mode
);
283 TRACE("macvlan mode: %s",
284 macvlan_mode
? macvlan_mode
290 TRACE("vlan id: %d", netdev
->priv
.vlan_attr
.vid
);
294 if (netdev
->priv
.phys_attr
.ifindex
> 0) {
295 TRACE("host side ifindex for phys device: %d",
296 netdev
->priv
.phys_attr
.ifindex
);
300 TRACE("type: empty");
306 ERROR("invalid network type %d", netdev
->type
);
310 if (netdev
->type
!= LXC_NET_EMPTY
) {
312 netdev
->flags
== IFF_UP
? "up" : "none");
313 if (netdev
->link
[0] != '\0')
314 TRACE("link: %s", netdev
->link
);
315 if (netdev
->name
[0] != '\0')
316 TRACE("name: %s", netdev
->name
);
318 TRACE("hwaddr: %s", netdev
->hwaddr
);
320 TRACE("mtu: %s", netdev
->mtu
);
321 if (netdev
->upscript
)
322 TRACE("upscript: %s", netdev
->upscript
);
323 if (netdev
->downscript
)
324 TRACE("downscript: %s", netdev
->downscript
);
326 TRACE("ipv4 gateway auto: %s",
327 netdev
->ipv4_gateway_auto
? "true" : "false");
329 if (netdev
->ipv4_gateway
) {
330 inet_ntop(AF_INET
, netdev
->ipv4_gateway
,
331 bufinet4
, sizeof(bufinet4
));
332 TRACE("ipv4 gateway: %s", bufinet4
);
335 lxc_list_for_each_safe(cur
, &netdev
->ipv4
, next
) {
336 inet4dev
= cur
->elem
;
337 inet_ntop(AF_INET
, &inet4dev
->addr
, bufinet4
,
339 TRACE("ipv4 addr: %s", bufinet4
);
342 TRACE("ipv6 gateway auto: %s",
343 netdev
->ipv6_gateway_auto
? "true" : "false");
344 if (netdev
->ipv6_gateway
) {
345 inet_ntop(AF_INET6
, netdev
->ipv6_gateway
,
346 bufinet6
, sizeof(bufinet6
));
347 TRACE("ipv6 gateway: %s", bufinet6
);
349 lxc_list_for_each_safe(cur
, &netdev
->ipv6
, next
) {
350 inet6dev
= cur
->elem
;
351 inet_ntop(AF_INET6
, &inet6dev
->addr
, bufinet6
,
353 TRACE("ipv6 addr: %s", bufinet6
);
359 static void lxc_free_netdev(struct lxc_netdev
*netdev
)
361 struct lxc_list
*cur
, *next
;
363 free(netdev
->upscript
);
364 free(netdev
->downscript
);
365 free(netdev
->hwaddr
);
368 free(netdev
->ipv4_gateway
);
369 lxc_list_for_each_safe(cur
, &netdev
->ipv4
, next
) {
375 free(netdev
->ipv6_gateway
);
376 lxc_list_for_each_safe(cur
, &netdev
->ipv6
, next
) {
385 bool lxc_remove_nic_by_idx(struct lxc_conf
*conf
, unsigned int idx
)
387 struct lxc_list
*cur
, *next
;
388 struct lxc_netdev
*netdev
;
391 lxc_list_for_each_safe(cur
, &conf
->network
, next
) {
393 if (netdev
->idx
!= idx
)
404 lxc_free_netdev(netdev
);
410 void lxc_free_networks(struct lxc_list
*networks
)
412 struct lxc_list
*cur
, *next
;
413 struct lxc_netdev
*netdev
;
415 lxc_list_for_each_safe(cur
, networks
, next
) {
417 lxc_free_netdev(netdev
);
421 /* prevent segfaults */
422 lxc_list_init(networks
);
425 static struct macvlan_mode
{
429 { "private", MACVLAN_MODE_PRIVATE
},
430 { "vepa", MACVLAN_MODE_VEPA
},
431 { "bridge", MACVLAN_MODE_BRIDGE
},
432 { "passthru", MACVLAN_MODE_PASSTHRU
},
435 int lxc_macvlan_mode_to_flag(int *mode
, const char *value
)
439 for (i
= 0; i
< sizeof(macvlan_mode
) / sizeof(macvlan_mode
[0]); i
++) {
440 if (strcmp(macvlan_mode
[i
].name
, value
))
443 *mode
= macvlan_mode
[i
].mode
;
450 char *lxc_macvlan_flag_to_mode(int mode
)
454 for (i
= 0; i
< sizeof(macvlan_mode
) / sizeof(macvlan_mode
[0]); i
++) {
455 if (macvlan_mode
[i
].mode
== mode
)
458 return macvlan_mode
[i
].name
;
464 int set_config_string_item(char **conf_item
, const char *value
)
468 if (lxc_config_value_empty(value
)) {
474 new_value
= strdup(value
);
476 SYSERROR("failed to duplicate string \"%s\"", value
);
481 *conf_item
= new_value
;
485 int set_config_string_item_max(char **conf_item
, const char *value
, size_t max
)
487 if (strlen(value
) >= max
) {
488 ERROR("%s is too long (>= %lu)", value
, (unsigned long)max
);
492 return set_config_string_item(conf_item
, value
);
495 int set_config_path_item(char **conf_item
, const char *value
)
497 return set_config_string_item_max(conf_item
, value
, PATH_MAX
);
500 int config_ip_prefix(struct in_addr
*addr
)
502 if (IN_CLASSA(addr
->s_addr
))
503 return 32 - IN_CLASSA_NSHIFT
;
504 if (IN_CLASSB(addr
->s_addr
))
505 return 32 - IN_CLASSB_NSHIFT
;
506 if (IN_CLASSC(addr
->s_addr
))
507 return 32 - IN_CLASSC_NSHIFT
;
512 int network_ifname(char *valuep
, const char *value
)
514 if (strlen(value
) >= IFNAMSIZ
) {
515 ERROR("Network devie name \"%s\" is too long (>= %zu)", value
,
519 strcpy(valuep
, value
);
523 int rand_complete_hwaddr(char *hwaddr
)
525 const char hex
[] = "0123456789abcdef";
533 seed
= randseed(false);
535 while (*curs
!= '\0' && *curs
!= '\n') {
536 if (*curs
== 'x' || *curs
== 'X') {
537 if (curs
- hwaddr
== 1) {
538 /* ensure address is unicast */
540 *curs
= hex
[rand_r(&seed
) & 0x0E];
542 *curs
= hex
[rand_r(&seed
) & 0x0F];
544 *curs
= hex
[rand() & 0x0E];
546 *curs
= hex
[rand() & 0x0F];
555 bool lxc_config_net_hwaddr(const char *line
)
560 if (strncmp(line
, "lxc.net", 7) != 0)
562 if (strncmp(line
, "lxc.net.hwaddr", 14) == 0)
564 if (strncmp(line
, "lxc.network.hwaddr", 18) == 0)
566 if (sscanf(line
, "lxc.net.%u.%6s", &index
, tmp
) == 2 || sscanf(line
, "lxc.network.%u.%6s", &index
, tmp
) == 2)
567 return strncmp(tmp
, "hwaddr", 6) == 0;
573 * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
574 * file, we expand it in the unexpanded_config, so that after a save_config we
575 * store the hwaddr for re-use.
576 * This is only called when reading the config file, not when executing a
578 * 'x' and 'X' are substituted in-place.
580 void update_hwaddr(const char *line
)
584 line
+= lxc_char_left_gc(line
, strlen(line
));
588 if (!lxc_config_net_hwaddr(line
))
591 /* Let config_net_hwaddr raise the error. */
592 p
= strchr(line
, '=');
603 rand_complete_hwaddr(p
);
606 bool new_hwaddr(char *hwaddr
)
610 (void)randseed(true);
612 ret
= snprintf(hwaddr
, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
613 rand() % 255, rand() % 255);
614 if (ret
< 0 || ret
>= 18) {
615 SYSERROR("Failed to call snprintf().");
622 int lxc_get_conf_str(char *retv
, int inlen
, const char *value
)
626 if (retv
&& inlen
>= strlen(value
) + 1)
627 strncpy(retv
, value
, strlen(value
) + 1);
629 return strlen(value
);
632 int lxc_get_conf_int(struct lxc_conf
*c
, char *retv
, int inlen
, int v
)
637 memset(retv
, 0, inlen
);
639 return snprintf(retv
, inlen
, "%d", v
);
642 int lxc_get_conf_uint64(struct lxc_conf
*c
, char *retv
, int inlen
, uint64_t v
)
647 memset(retv
, 0, inlen
);
649 return snprintf(retv
, inlen
, "%"PRIu64
, v
);
652 bool parse_limit_value(const char **value
, rlim_t
*res
)
656 if (strncmp(*value
, "unlimited", sizeof("unlimited") - 1) == 0) {
657 *res
= RLIM_INFINITY
;
658 *value
+= sizeof("unlimited") - 1;
663 *res
= strtoull(*value
, &endptr
, 10);
664 if (errno
|| !endptr
)
671 static int lxc_container_name_to_pid(const char *lxcname_or_pid
,
678 pid
= strtol(lxcname_or_pid
, &err
, 10);
679 if (*err
!= '\0' || pid
< 1) {
680 struct lxc_container
*c
;
682 c
= lxc_container_new(lxcname_or_pid
, lxcpath
);
684 ERROR("\"%s\" is not a valid pid nor a container name",
689 if (!c
->may_control(c
)) {
690 ERROR("Insufficient privileges to control container "
692 lxc_container_put(c
);
696 pid
= c
->init_pid(c
);
698 ERROR("Container \"%s\" is not running", c
->name
);
699 lxc_container_put(c
);
703 lxc_container_put(c
);
708 ERROR("%s - Failed to send signal to pid %d", strerror(errno
),
716 int lxc_inherit_namespace(const char *lxcname_or_pid
, const char *lxcpath
,
717 const char *namespace)
720 char *dup
, *lastslash
;
722 lastslash
= strrchr(lxcname_or_pid
, '/');
724 dup
= strdup(lxcname_or_pid
);
728 dup
[lastslash
- lxcname_or_pid
] = '\0';
729 pid
= lxc_container_name_to_pid(lastslash
+ 1, dup
);
732 pid
= lxc_container_name_to_pid(lxcname_or_pid
, lxcpath
);
738 fd
= lxc_preserve_ns(pid
, namespace);