]>
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.
23 #include <arpa/inet.h>
32 #include "confile_utils.h"
36 #include "lxccontainer.h"
43 #include "include/strlcpy.h"
46 lxc_log_define(confile_utils
, lxc
);
48 int parse_idmaps(const char *idmap
, char *type
, unsigned long *nsid
,
49 unsigned long *hostid
, unsigned long *range
)
52 unsigned long tmp_hostid
, tmp_nsid
, tmp_range
;
57 /* Duplicate string. */
62 /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
67 slide
+= strspn(slide
, " \t\r");
68 if (slide
!= window
&& *slide
== '\0')
72 if (*slide
!= 'u' && *slide
!= 'g') {
73 ERROR("Invalid id mapping type: %c", *slide
);
80 /* move beyond type */
84 /* Validate that only whitespace follows. */
85 slide
+= strspn(slide
, " \t\r");
86 /* There must be whitespace. */
90 /* Mark beginning of nsid. */
92 /* Validate that non-whitespace follows. */
93 slide
+= strcspn(slide
, " \t\r");
94 /* There must be non-whitespace. */
95 if (slide
== window
|| *slide
== '\0')
97 /* Mark end of nsid. */
101 if (lxc_safe_ulong(window
, &tmp_nsid
) < 0) {
102 ERROR("Failed to parse nsid: %s", window
);
106 /* Move beyond \0. */
108 /* Validate that only whitespace follows. */
109 slide
+= strspn(slide
, " \t\r");
110 /* If there was only one whitespace then we whiped it with our \0 above.
111 * So only ensure that we're not at the end of the string.
116 /* Mark beginning of hostid. */
118 /* Validate that non-whitespace follows. */
119 slide
+= strcspn(slide
, " \t\r");
120 /* There must be non-whitespace. */
121 if (slide
== window
|| *slide
== '\0')
123 /* Mark end of nsid. */
127 if (lxc_safe_ulong(window
, &tmp_hostid
) < 0) {
128 ERROR("Failed to parse hostid: %s", window
);
132 /* Move beyond \0. */
134 /* Validate that only whitespace follows. */
135 slide
+= strspn(slide
, " \t\r");
136 /* If there was only one whitespace then we whiped it with our \0 above.
137 * So only ensure that we're not at the end of the string.
142 /* Mark beginning of range. */
144 /* Validate that non-whitespace follows. */
145 slide
+= strcspn(slide
, " \t\r");
146 /* There must be non-whitespace. */
150 /* The range is the last valid entry we expect. So make sure that there
151 * is no trailing garbage and if there is, error out.
153 if (*(slide
+ strspn(slide
, " \t\r\n")) != '\0')
156 /* Mark end of range. */
160 if (lxc_safe_ulong(window
, &tmp_range
) < 0) {
161 ERROR("Failed to parse id mapping range: %s", window
);
167 *hostid
= tmp_hostid
;
170 /* Yay, we survived. */
179 bool lxc_config_value_empty(const char *value
)
181 if (value
&& strlen(value
) > 0)
187 struct lxc_netdev
*lxc_network_add(struct lxc_list
*networks
, int idx
, bool tail
)
189 struct lxc_list
*newlist
;
190 struct lxc_netdev
*netdev
= NULL
;
192 /* network does not exist */
193 netdev
= malloc(sizeof(*netdev
));
197 memset(netdev
, 0, sizeof(*netdev
));
198 lxc_list_init(&netdev
->ipv4
);
199 lxc_list_init(&netdev
->ipv6
);
201 /* give network a unique index */
204 /* prepare new list */
205 newlist
= malloc(sizeof(*newlist
));
211 lxc_list_init(newlist
);
212 newlist
->elem
= netdev
;
215 lxc_list_add_tail(networks
, newlist
);
217 lxc_list_add(networks
, newlist
);
222 /* Takes care of finding the correct netdev struct in the networks list or
223 * allocates a new one if it couldn't be found.
225 struct lxc_netdev
*lxc_get_netdev_by_idx(struct lxc_conf
*conf
,
226 unsigned int idx
, bool allocate
)
228 struct lxc_netdev
*netdev
= NULL
;
229 struct lxc_list
*networks
= &conf
->network
;
230 struct lxc_list
*insert
= networks
;
233 if (!lxc_list_empty(networks
)) {
234 lxc_list_for_each(insert
, networks
) {
235 netdev
= insert
->elem
;
236 if (netdev
->idx
== idx
)
238 else if (netdev
->idx
> idx
)
246 return lxc_network_add(insert
, idx
, true);
249 void lxc_log_configured_netdevs(const struct lxc_conf
*conf
)
251 struct lxc_netdev
*netdev
;
252 struct lxc_list
*it
= (struct lxc_list
*)&conf
->network
;;
254 if ((conf
->loglevel
!= LXC_LOG_LEVEL_TRACE
) &&
255 (lxc_log_get_level() != LXC_LOG_LEVEL_TRACE
))
258 if (lxc_list_empty(it
)) {
259 TRACE("container has no networks configured");
263 lxc_list_for_each(it
, &conf
->network
) {
264 struct lxc_list
*cur
, *next
;
265 struct lxc_inetdev
*inet4dev
;
266 struct lxc_inet6dev
*inet6dev
;
267 char bufinet4
[INET_ADDRSTRLEN
], bufinet6
[INET6_ADDRSTRLEN
];
271 TRACE("index: %zd", netdev
->idx
);
272 TRACE("ifindex: %d", netdev
->ifindex
);
274 switch (netdev
->type
) {
278 if (netdev
->priv
.veth_attr
.pair
[0] != '\0')
279 TRACE("veth pair: %s",
280 netdev
->priv
.veth_attr
.pair
);
282 if (netdev
->priv
.veth_attr
.veth1
[0] != '\0')
284 netdev
->priv
.veth_attr
.veth1
);
286 if (netdev
->priv
.veth_attr
.ifindex
> 0)
287 TRACE("host side ifindex for veth device: %d",
288 netdev
->priv
.veth_attr
.ifindex
);
290 case LXC_NET_MACVLAN
:
291 TRACE("type: macvlan");
293 if (netdev
->priv
.macvlan_attr
.mode
> 0) {
296 mode
= lxc_macvlan_flag_to_mode(
297 netdev
->priv
.macvlan_attr
.mode
);
298 TRACE("macvlan mode: %s",
299 mode
? mode
: "(invalid mode)");
304 TRACE("vlan id: %d", netdev
->priv
.vlan_attr
.vid
);
309 if (netdev
->priv
.phys_attr
.ifindex
> 0)
310 TRACE("host side ifindex for phys device: %d",
311 netdev
->priv
.phys_attr
.ifindex
);
314 TRACE("type: empty");
320 ERROR("invalid network type %d", netdev
->type
);
324 if (netdev
->type
!= LXC_NET_EMPTY
) {
326 netdev
->flags
== IFF_UP
? "up" : "none");
328 if (netdev
->link
[0] != '\0')
329 TRACE("link: %s", netdev
->link
);
331 if (netdev
->name
[0] != '\0')
332 TRACE("name: %s", netdev
->name
);
335 TRACE("hwaddr: %s", netdev
->hwaddr
);
338 TRACE("mtu: %s", netdev
->mtu
);
340 if (netdev
->upscript
)
341 TRACE("upscript: %s", netdev
->upscript
);
343 if (netdev
->downscript
)
344 TRACE("downscript: %s", netdev
->downscript
);
346 TRACE("ipv4 gateway auto: %s",
347 netdev
->ipv4_gateway_auto
? "true" : "false");
349 if (netdev
->ipv4_gateway
) {
350 inet_ntop(AF_INET
, netdev
->ipv4_gateway
,
351 bufinet4
, sizeof(bufinet4
));
352 TRACE("ipv4 gateway: %s", bufinet4
);
355 lxc_list_for_each_safe(cur
, &netdev
->ipv4
, next
) {
356 inet4dev
= cur
->elem
;
357 inet_ntop(AF_INET
, &inet4dev
->addr
, bufinet4
,
359 TRACE("ipv4 addr: %s", bufinet4
);
362 TRACE("ipv6 gateway auto: %s",
363 netdev
->ipv6_gateway_auto
? "true" : "false");
365 if (netdev
->ipv6_gateway
) {
366 inet_ntop(AF_INET6
, netdev
->ipv6_gateway
,
367 bufinet6
, sizeof(bufinet6
));
368 TRACE("ipv6 gateway: %s", bufinet6
);
371 lxc_list_for_each_safe(cur
, &netdev
->ipv6
, next
) {
372 inet6dev
= cur
->elem
;
373 inet_ntop(AF_INET6
, &inet6dev
->addr
, bufinet6
,
375 TRACE("ipv6 addr: %s", bufinet6
);
381 static void lxc_free_netdev(struct lxc_netdev
*netdev
)
383 struct lxc_list
*cur
, *next
;
385 free(netdev
->upscript
);
386 free(netdev
->downscript
);
387 free(netdev
->hwaddr
);
390 free(netdev
->ipv4_gateway
);
391 lxc_list_for_each_safe(cur
, &netdev
->ipv4
, next
) {
397 free(netdev
->ipv6_gateway
);
398 lxc_list_for_each_safe(cur
, &netdev
->ipv6
, next
) {
407 bool lxc_remove_nic_by_idx(struct lxc_conf
*conf
, unsigned int idx
)
409 struct lxc_list
*cur
, *next
;
410 struct lxc_netdev
*netdev
;
413 lxc_list_for_each_safe(cur
, &conf
->network
, next
) {
415 if (netdev
->idx
!= idx
)
426 lxc_free_netdev(netdev
);
432 void lxc_free_networks(struct lxc_list
*networks
)
434 struct lxc_list
*cur
, *next
;
435 struct lxc_netdev
*netdev
;
437 lxc_list_for_each_safe(cur
, networks
, next
) {
439 lxc_free_netdev(netdev
);
443 /* prevent segfaults */
444 lxc_list_init(networks
);
447 static struct lxc_macvlan_mode
{
451 { "private", MACVLAN_MODE_PRIVATE
},
452 { "vepa", MACVLAN_MODE_VEPA
},
453 { "bridge", MACVLAN_MODE_BRIDGE
},
454 { "passthru", MACVLAN_MODE_PASSTHRU
},
457 int lxc_macvlan_mode_to_flag(int *mode
, const char *value
)
461 for (i
= 0; i
< sizeof(macvlan_mode
) / sizeof(macvlan_mode
[0]); i
++) {
462 if (strcmp(macvlan_mode
[i
].name
, value
))
465 *mode
= macvlan_mode
[i
].mode
;
472 char *lxc_macvlan_flag_to_mode(int mode
)
476 for (i
= 0; i
< sizeof(macvlan_mode
) / sizeof(macvlan_mode
[0]); i
++) {
477 if (macvlan_mode
[i
].mode
== mode
)
480 return macvlan_mode
[i
].name
;
486 int set_config_string_item(char **conf_item
, const char *value
)
490 if (lxc_config_value_empty(value
)) {
496 new_value
= strdup(value
);
498 SYSERROR("Failed to duplicate string \"%s\"", value
);
503 *conf_item
= new_value
;
507 int set_config_string_item_max(char **conf_item
, const char *value
, size_t max
)
509 if (strlen(value
) >= max
) {
510 ERROR("%s is too long (>= %lu)", value
, (unsigned long)max
);
514 return set_config_string_item(conf_item
, value
);
517 int set_config_path_item(char **conf_item
, const char *value
)
519 return set_config_string_item_max(conf_item
, value
, PATH_MAX
);
522 int config_ip_prefix(struct in_addr
*addr
)
524 if (IN_CLASSA(addr
->s_addr
))
525 return 32 - IN_CLASSA_NSHIFT
;
527 if (IN_CLASSB(addr
->s_addr
))
528 return 32 - IN_CLASSB_NSHIFT
;
530 if (IN_CLASSC(addr
->s_addr
))
531 return 32 - IN_CLASSC_NSHIFT
;
536 int network_ifname(char *valuep
, const char *value
, size_t size
)
540 if (!valuep
|| !value
)
543 retlen
= strlcpy(valuep
, value
, size
);
545 ERROR("Network device name \"%s\" is too long (>= %zu)", value
,
551 bool lxc_config_net_is_hwaddr(const char *line
)
556 if (strncmp(line
, "lxc.net", 7) != 0)
559 if (strncmp(line
, "lxc.net.hwaddr", 14) == 0)
562 if (strncmp(line
, "lxc.network.hwaddr", 18) == 0)
565 if (sscanf(line
, "lxc.net.%u.%6s", &index
, tmp
) == 2 ||
566 sscanf(line
, "lxc.network.%u.%6s", &index
, tmp
) == 2)
567 return strncmp(tmp
, "hwaddr", 6) == 0;
572 void rand_complete_hwaddr(char *hwaddr
)
574 const char hex
[] = "0123456789abcdef";
579 seed
= randseed(false);
582 (void)randseed(true);
585 while (*curs
!= '\0' && *curs
!= '\n') {
586 if (*curs
== 'x' || *curs
== 'X') {
587 if (curs
- hwaddr
== 1) {
588 /* ensure address is unicast */
590 *curs
= hex
[rand_r(&seed
) & 0x0E];
592 *curs
= hex
[rand_r(&seed
) & 0x0F];
594 *curs
= hex
[rand() & 0x0E];
596 *curs
= hex
[rand() & 0x0F];
604 bool new_hwaddr(char *hwaddr
)
610 seed
= randseed(false);
612 ret
= snprintf(hwaddr
, 18, "00:16:3e:%02x:%02x:%02x", rand_r(&seed
) % 255,
613 rand_r(&seed
) % 255, rand_r(&seed
) % 255);
616 (void)randseed(true);
618 ret
= snprintf(hwaddr
, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
619 rand() % 255, rand() % 255);
621 if (ret
< 0 || ret
>= 18) {
622 SYSERROR("Failed to call snprintf()");
629 int lxc_get_conf_str(char *retv
, int inlen
, const char *value
)
636 value_len
= strlen(value
);
637 if (retv
&& inlen
>= value_len
+ 1)
638 memcpy(retv
, value
, value_len
+ 1);
643 int lxc_get_conf_bool(struct lxc_conf
*c
, char *retv
, int inlen
, bool v
)
651 memset(retv
, 0, inlen
);
653 strprint(retv
, inlen
, "%d", v
);
658 int lxc_get_conf_int(struct lxc_conf
*c
, char *retv
, int inlen
, int v
)
666 memset(retv
, 0, inlen
);
668 strprint(retv
, inlen
, "%d", v
);
673 int lxc_get_conf_size_t(struct lxc_conf
*c
, char *retv
, int inlen
, size_t v
)
681 memset(retv
, 0, inlen
);
683 strprint(retv
, inlen
, "%zu", v
);
688 int lxc_get_conf_uint64(struct lxc_conf
*c
, char *retv
, int inlen
, uint64_t v
)
696 memset(retv
, 0, inlen
);
698 strprint(retv
, inlen
, "%"PRIu64
, v
);
703 static int lxc_container_name_to_pid(const char *lxcname_or_pid
,
710 pid
= strtol(lxcname_or_pid
, &err
, 10);
711 if (*err
!= '\0' || pid
< 1) {
712 struct lxc_container
*c
;
714 c
= lxc_container_new(lxcname_or_pid
, lxcpath
);
716 ERROR("\"%s\" is not a valid pid nor a container name",
721 if (!c
->may_control(c
)) {
722 ERROR("Insufficient privileges to control container "
724 lxc_container_put(c
);
728 pid
= c
->init_pid(c
);
730 ERROR("Container \"%s\" is not running", c
->name
);
731 lxc_container_put(c
);
735 lxc_container_put(c
);
740 SYSERROR("Failed to send signal to pid %d", (int)pid
);
747 int lxc_inherit_namespace(const char *lxcname_or_pid
, const char *lxcpath
,
748 const char *namespace)
751 char *dup
, *lastslash
;
753 lastslash
= strrchr(lxcname_or_pid
, '/');
755 dup
= strdup(lxcname_or_pid
);
759 dup
[lastslash
- lxcname_or_pid
] = '\0';
760 pid
= lxc_container_name_to_pid(lastslash
+ 1, dup
);
763 pid
= lxc_container_name_to_pid(lxcname_or_pid
, lxcpath
);
769 fd
= lxc_preserve_ns(pid
, namespace);
781 static const struct signame signames
[] = {
814 { SIGSTKFLT
, "STKFLT" },
829 { SIGVTALRM
, "VTALRM" },
835 { SIGWINCH
, "WINCH" },
853 { SIGUNUSED
, "UNUSED" },
860 static int sig_num(const char *sig
)
864 if (lxc_safe_uint(sig
, &signum
) < 0)
870 static int rt_sig_num(const char *signame
)
872 int rtmax
= 0, sig_n
= 0;
874 if (strncasecmp(signame
, "max-", 4) == 0)
878 if (!isdigit(*signame
))
881 sig_n
= sig_num(signame
);
882 sig_n
= rtmax
? SIGRTMAX
- sig_n
: SIGRTMIN
+ sig_n
;
883 if (sig_n
> SIGRTMAX
|| sig_n
< SIGRTMIN
)
889 int sig_parse(const char *signame
)
893 if (isdigit(*signame
)) {
894 return sig_num(signame
);
895 } else if (strncasecmp(signame
, "sig", 3) == 0) {
897 if (strncasecmp(signame
, "rt", 2) == 0)
898 return rt_sig_num(signame
+ 2);
900 for (n
= 0; n
< sizeof(signames
) / sizeof((signames
)[0]); n
++)
901 if (strcasecmp(signames
[n
].name
, signame
) == 0)
902 return signames
[n
].num
;