]>
git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/confile_utils.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
15 #include "confile_utils.h"
19 #include "lxccontainer.h"
26 #include "include/strlcpy.h"
29 lxc_log_define(confile_utils
, lxc
);
31 int parse_idmaps(const char *idmap
, char *type
, unsigned long *nsid
,
32 unsigned long *hostid
, unsigned long *range
)
35 unsigned long tmp_hostid
, tmp_nsid
, tmp_range
;
40 /* Duplicate string. */
45 /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
50 slide
+= strspn(slide
, " \t\r");
51 if (slide
!= window
&& *slide
== '\0')
55 if (*slide
!= 'u' && *slide
!= 'g') {
56 ERROR("Invalid id mapping type: %c", *slide
);
63 /* move beyond type */
67 /* Validate that only whitespace follows. */
68 slide
+= strspn(slide
, " \t\r");
69 /* There must be whitespace. */
73 /* Mark beginning of nsid. */
75 /* Validate that non-whitespace follows. */
76 slide
+= strcspn(slide
, " \t\r");
77 /* There must be non-whitespace. */
78 if (slide
== window
|| *slide
== '\0')
80 /* Mark end of nsid. */
84 if (lxc_safe_ulong(window
, &tmp_nsid
) < 0) {
85 ERROR("Failed to parse nsid: %s", window
);
91 /* Validate that only whitespace follows. */
92 slide
+= strspn(slide
, " \t\r");
93 /* If there was only one whitespace then we whiped it with our \0 above.
94 * So only ensure that we're not at the end of the string.
99 /* Mark beginning of hostid. */
101 /* Validate that non-whitespace follows. */
102 slide
+= strcspn(slide
, " \t\r");
103 /* There must be non-whitespace. */
104 if (slide
== window
|| *slide
== '\0')
106 /* Mark end of nsid. */
110 if (lxc_safe_ulong(window
, &tmp_hostid
) < 0) {
111 ERROR("Failed to parse hostid: %s", window
);
115 /* Move beyond \0. */
117 /* Validate that only whitespace follows. */
118 slide
+= strspn(slide
, " \t\r");
119 /* If there was only one whitespace then we whiped it with our \0 above.
120 * So only ensure that we're not at the end of the string.
125 /* Mark beginning of range. */
127 /* Validate that non-whitespace follows. */
128 slide
+= strcspn(slide
, " \t\r");
129 /* There must be non-whitespace. */
133 /* The range is the last valid entry we expect. So make sure that there
134 * is no trailing garbage and if there is, error out.
136 if (*(slide
+ strspn(slide
, " \t\r\n")) != '\0')
139 /* Mark end of range. */
143 if (lxc_safe_ulong(window
, &tmp_range
) < 0) {
144 ERROR("Failed to parse id mapping range: %s", window
);
150 *hostid
= tmp_hostid
;
153 /* Yay, we survived. */
162 bool lxc_config_value_empty(const char *value
)
164 if (value
&& strlen(value
) > 0)
170 struct lxc_netdev
*lxc_network_add(struct lxc_list
*networks
, int idx
, bool tail
)
172 struct lxc_list
*newlist
;
173 struct lxc_netdev
*netdev
= NULL
;
175 /* network does not exist */
176 netdev
= malloc(sizeof(*netdev
));
180 memset(netdev
, 0, sizeof(*netdev
));
181 lxc_list_init(&netdev
->ipv4
);
182 lxc_list_init(&netdev
->ipv6
);
184 /* give network a unique index */
187 /* prepare new list */
188 newlist
= malloc(sizeof(*newlist
));
194 lxc_list_init(newlist
);
195 newlist
->elem
= netdev
;
198 lxc_list_add_tail(networks
, newlist
);
200 lxc_list_add(networks
, newlist
);
205 /* Takes care of finding the correct netdev struct in the networks list or
206 * allocates a new one if it couldn't be found.
208 struct lxc_netdev
*lxc_get_netdev_by_idx(struct lxc_conf
*conf
,
209 unsigned int idx
, bool allocate
)
211 struct lxc_netdev
*netdev
= NULL
;
212 struct lxc_list
*networks
= &conf
->network
;
213 struct lxc_list
*insert
= networks
;
216 if (!lxc_list_empty(networks
)) {
217 lxc_list_for_each(insert
, networks
) {
218 netdev
= insert
->elem
;
219 if (netdev
->idx
== idx
)
221 else if (netdev
->idx
> idx
)
229 return lxc_network_add(insert
, idx
, true);
232 void lxc_log_configured_netdevs(const struct lxc_conf
*conf
)
234 struct lxc_netdev
*netdev
;
235 struct lxc_list
*it
= (struct lxc_list
*)&conf
->network
;;
237 if ((conf
->loglevel
!= LXC_LOG_LEVEL_TRACE
) &&
238 (lxc_log_get_level() != LXC_LOG_LEVEL_TRACE
))
241 if (lxc_list_empty(it
)) {
242 TRACE("container has no networks configured");
246 lxc_list_for_each(it
, &conf
->network
) {
247 struct lxc_list
*cur
, *next
;
248 struct lxc_inetdev
*inet4dev
;
249 struct lxc_inet6dev
*inet6dev
;
250 char bufinet4
[INET_ADDRSTRLEN
], bufinet6
[INET6_ADDRSTRLEN
];
254 TRACE("index: %zd", netdev
->idx
);
255 TRACE("ifindex: %d", netdev
->ifindex
);
257 switch (netdev
->type
) {
260 TRACE("veth mode: %d", netdev
->priv
.veth_attr
.mode
);
262 if (netdev
->priv
.veth_attr
.pair
[0] != '\0')
263 TRACE("veth pair: %s",
264 netdev
->priv
.veth_attr
.pair
);
266 if (netdev
->priv
.veth_attr
.veth1
[0] != '\0')
268 netdev
->priv
.veth_attr
.veth1
);
270 if (netdev
->priv
.veth_attr
.ifindex
> 0)
271 TRACE("host side ifindex for veth device: %d",
272 netdev
->priv
.veth_attr
.ifindex
);
274 if (netdev
->priv
.veth_attr
.vlan_id_set
)
275 TRACE("veth vlan id: %d", netdev
->priv
.veth_attr
.vlan_id
);
277 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.vlan_tagged_ids
, next
) {
278 unsigned short vlan_tagged_id
= PTR_TO_USHORT(cur
->elem
);
279 TRACE("veth vlan tagged id: %u", vlan_tagged_id
);
283 case LXC_NET_MACVLAN
:
284 TRACE("type: macvlan");
286 if (netdev
->priv
.macvlan_attr
.mode
> 0) {
289 mode
= lxc_macvlan_flag_to_mode(
290 netdev
->priv
.macvlan_attr
.mode
);
291 TRACE("macvlan mode: %s",
292 mode
? mode
: "(invalid mode)");
296 TRACE("type: ipvlan");
299 mode
= lxc_ipvlan_flag_to_mode(netdev
->priv
.ipvlan_attr
.mode
);
300 TRACE("ipvlan mode: %s", mode
? mode
: "(invalid mode)");
303 isolation
= lxc_ipvlan_flag_to_isolation(netdev
->priv
.ipvlan_attr
.isolation
);
304 TRACE("ipvlan isolation: %s", isolation
? isolation
: "(invalid isolation)");
308 TRACE("vlan id: %d", netdev
->priv
.vlan_attr
.vid
);
313 if (netdev
->priv
.phys_attr
.ifindex
> 0)
314 TRACE("host side ifindex for phys device: %d",
315 netdev
->priv
.phys_attr
.ifindex
);
318 TRACE("type: empty");
324 ERROR("Invalid network type %d", netdev
->type
);
328 if (netdev
->type
!= LXC_NET_EMPTY
) {
330 netdev
->flags
== IFF_UP
? "up" : "none");
332 if (netdev
->link
[0] != '\0')
333 TRACE("link: %s", netdev
->link
);
335 /* l2proxy only used when link is specified */
336 if (netdev
->link
[0] != '\0')
337 TRACE("l2proxy: %s", netdev
->l2proxy
? "true" : "false");
339 if (netdev
->name
[0] != '\0')
340 TRACE("name: %s", netdev
->name
);
343 TRACE("hwaddr: %s", netdev
->hwaddr
);
346 TRACE("mtu: %s", netdev
->mtu
);
348 if (netdev
->upscript
)
349 TRACE("upscript: %s", netdev
->upscript
);
351 if (netdev
->downscript
)
352 TRACE("downscript: %s", netdev
->downscript
);
354 TRACE("ipv4 gateway auto: %s",
355 netdev
->ipv4_gateway_auto
? "true" : "false");
357 TRACE("ipv4 gateway dev: %s",
358 netdev
->ipv4_gateway_dev
? "true" : "false");
360 if (netdev
->ipv4_gateway
) {
361 inet_ntop(AF_INET
, netdev
->ipv4_gateway
,
362 bufinet4
, sizeof(bufinet4
));
363 TRACE("ipv4 gateway: %s", bufinet4
);
366 lxc_list_for_each_safe(cur
, &netdev
->ipv4
, next
) {
367 inet4dev
= cur
->elem
;
368 inet_ntop(AF_INET
, &inet4dev
->addr
, bufinet4
,
370 TRACE("ipv4 addr: %s", bufinet4
);
373 TRACE("ipv6 gateway auto: %s",
374 netdev
->ipv6_gateway_auto
? "true" : "false");
376 TRACE("ipv6 gateway dev: %s",
377 netdev
->ipv6_gateway_dev
? "true" : "false");
379 if (netdev
->ipv6_gateway
) {
380 inet_ntop(AF_INET6
, netdev
->ipv6_gateway
,
381 bufinet6
, sizeof(bufinet6
));
382 TRACE("ipv6 gateway: %s", bufinet6
);
385 lxc_list_for_each_safe(cur
, &netdev
->ipv6
, next
) {
386 inet6dev
= cur
->elem
;
387 inet_ntop(AF_INET6
, &inet6dev
->addr
, bufinet6
,
389 TRACE("ipv6 addr: %s", bufinet6
);
392 if (netdev
->type
== LXC_NET_VETH
) {
393 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.ipv4_routes
, next
) {
394 inet4dev
= cur
->elem
;
395 if (!inet_ntop(AF_INET
, &inet4dev
->addr
, bufinet4
, sizeof(bufinet4
))) {
396 ERROR("Invalid ipv4 veth route");
400 TRACE("ipv4 veth route: %s/%u", bufinet4
, inet4dev
->prefix
);
403 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.ipv6_routes
, next
) {
404 inet6dev
= cur
->elem
;
405 if (!inet_ntop(AF_INET6
, &inet6dev
->addr
, bufinet6
, sizeof(bufinet6
))) {
406 ERROR("Invalid ipv6 veth route");
410 TRACE("ipv6 veth route: %s/%u", bufinet6
, inet6dev
->prefix
);
417 static void lxc_free_netdev(struct lxc_netdev
*netdev
)
419 struct lxc_list
*cur
, *next
;
421 free(netdev
->upscript
);
422 free(netdev
->downscript
);
423 free(netdev
->hwaddr
);
426 free(netdev
->ipv4_gateway
);
427 lxc_list_for_each_safe(cur
, &netdev
->ipv4
, next
) {
433 free(netdev
->ipv6_gateway
);
434 lxc_list_for_each_safe(cur
, &netdev
->ipv6
, next
) {
440 if (netdev
->type
== LXC_NET_VETH
) {
441 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.ipv4_routes
, next
) {
447 lxc_list_for_each_safe(cur
, &netdev
->priv
.veth_attr
.ipv6_routes
, next
) {
457 bool lxc_remove_nic_by_idx(struct lxc_conf
*conf
, unsigned int idx
)
459 struct lxc_list
*cur
, *next
;
460 struct lxc_netdev
*netdev
;
463 lxc_list_for_each_safe(cur
, &conf
->network
, next
) {
465 if (netdev
->idx
!= idx
)
476 lxc_free_netdev(netdev
);
482 void lxc_free_networks(struct lxc_list
*networks
)
484 struct lxc_list
*cur
, *next
;
485 struct lxc_netdev
*netdev
;
487 lxc_list_for_each_safe(cur
, networks
, next
) {
489 lxc_free_netdev(netdev
);
493 /* prevent segfaults */
494 lxc_list_init(networks
);
498 static struct lxc_veth_mode
{
502 { "bridge", VETH_MODE_BRIDGE
},
503 { "router", VETH_MODE_ROUTER
},
506 int lxc_veth_mode_to_flag(int *mode
, const char *value
)
508 for (size_t i
= 0; i
< sizeof(veth_mode
) / sizeof(veth_mode
[0]); i
++) {
509 if (strcmp(veth_mode
[i
].name
, value
) != 0)
512 *mode
= veth_mode
[i
].mode
;
516 return ret_set_errno(-1, EINVAL
);
519 char *lxc_veth_flag_to_mode(int mode
)
521 for (size_t i
= 0; i
< sizeof(veth_mode
) / sizeof(veth_mode
[0]); i
++) {
522 if (veth_mode
[i
].mode
!= mode
)
525 return veth_mode
[i
].name
;
531 static struct lxc_macvlan_mode
{
535 { "private", MACVLAN_MODE_PRIVATE
},
536 { "vepa", MACVLAN_MODE_VEPA
},
537 { "bridge", MACVLAN_MODE_BRIDGE
},
538 { "passthru", MACVLAN_MODE_PASSTHRU
},
541 int lxc_macvlan_mode_to_flag(int *mode
, const char *value
)
545 for (i
= 0; i
< sizeof(macvlan_mode
) / sizeof(macvlan_mode
[0]); i
++) {
546 if (strcmp(macvlan_mode
[i
].name
, value
))
549 *mode
= macvlan_mode
[i
].mode
;
556 char *lxc_macvlan_flag_to_mode(int mode
)
560 for (i
= 0; i
< sizeof(macvlan_mode
) / sizeof(macvlan_mode
[0]); i
++) {
561 if (macvlan_mode
[i
].mode
!= mode
)
564 return macvlan_mode
[i
].name
;
570 static struct lxc_ipvlan_mode
{
574 { "l3", IPVLAN_MODE_L3
},
575 { "l3s", IPVLAN_MODE_L3S
},
576 { "l2", IPVLAN_MODE_L2
},
579 int lxc_ipvlan_mode_to_flag(int *mode
, const char *value
)
581 for (size_t i
= 0; i
< sizeof(ipvlan_mode
) / sizeof(ipvlan_mode
[0]); i
++) {
582 if (strcmp(ipvlan_mode
[i
].name
, value
) != 0)
585 *mode
= ipvlan_mode
[i
].mode
;
592 char *lxc_ipvlan_flag_to_mode(int mode
)
594 for (size_t i
= 0; i
< sizeof(ipvlan_mode
) / sizeof(ipvlan_mode
[0]); i
++) {
595 if (ipvlan_mode
[i
].mode
!= mode
)
598 return ipvlan_mode
[i
].name
;
604 static struct lxc_ipvlan_isolation
{
607 } ipvlan_isolation
[] = {
608 { "bridge", IPVLAN_ISOLATION_BRIDGE
},
609 { "private", IPVLAN_ISOLATION_PRIVATE
},
610 { "vepa", IPVLAN_ISOLATION_VEPA
},
613 int lxc_ipvlan_isolation_to_flag(int *flag
, const char *value
)
615 for (size_t i
= 0; i
< sizeof(ipvlan_isolation
) / sizeof(ipvlan_isolation
[0]); i
++) {
616 if (strcmp(ipvlan_isolation
[i
].name
, value
) != 0)
619 *flag
= ipvlan_isolation
[i
].flag
;
626 char *lxc_ipvlan_flag_to_isolation(int flag
)
628 for (size_t i
= 0; i
< sizeof(ipvlan_isolation
) / sizeof(ipvlan_isolation
[0]); i
++) {
629 if (ipvlan_isolation
[i
].flag
!= flag
)
632 return ipvlan_isolation
[i
].name
;
638 int set_config_string_item(char **conf_item
, const char *value
)
642 if (lxc_config_value_empty(value
)) {
648 new_value
= strdup(value
);
650 SYSERROR("Failed to duplicate string \"%s\"", value
);
655 *conf_item
= new_value
;
659 int set_config_string_item_max(char **conf_item
, const char *value
, size_t max
)
661 if (strlen(value
) >= max
) {
662 ERROR("%s is too long (>= %lu)", value
, (unsigned long)max
);
666 return set_config_string_item(conf_item
, value
);
669 int set_config_path_item(char **conf_item
, const char *value
)
671 return set_config_string_item_max(conf_item
, value
, PATH_MAX
);
674 int set_config_bool_item(bool *conf_item
, const char *value
, bool empty_conf_action
)
676 unsigned int val
= 0;
678 if (lxc_config_value_empty(value
)) {
679 *conf_item
= empty_conf_action
;
683 if (lxc_safe_uint(value
, &val
) < 0)
698 int config_ip_prefix(struct in_addr
*addr
)
700 if (IN_CLASSA(addr
->s_addr
))
701 return 32 - IN_CLASSA_NSHIFT
;
703 if (IN_CLASSB(addr
->s_addr
))
704 return 32 - IN_CLASSB_NSHIFT
;
706 if (IN_CLASSC(addr
->s_addr
))
707 return 32 - IN_CLASSC_NSHIFT
;
712 int network_ifname(char *valuep
, const char *value
, size_t size
)
716 if (!valuep
|| !value
)
719 retlen
= strlcpy(valuep
, value
, size
);
721 ERROR("Network device name \"%s\" is too long (>= %zu)", value
,
727 bool lxc_config_net_is_hwaddr(const char *line
)
732 if (strncmp(line
, "lxc.net", 7) != 0)
735 if (strncmp(line
, "lxc.net.hwaddr", 14) == 0)
738 if (strncmp(line
, "lxc.network.hwaddr", 18) == 0)
741 if (sscanf(line
, "lxc.net.%u.%6s", &index
, tmp
) == 2 ||
742 sscanf(line
, "lxc.network.%u.%6s", &index
, tmp
) == 2)
743 return strncmp(tmp
, "hwaddr", 6) == 0;
748 void rand_complete_hwaddr(char *hwaddr
)
750 const char hex
[] = "0123456789abcdef";
755 seed
= randseed(false);
758 (void)randseed(true);
761 while (*curs
!= '\0' && *curs
!= '\n') {
762 if (*curs
== 'x' || *curs
== 'X') {
763 if (curs
- hwaddr
== 1) {
764 /* ensure address is unicast */
766 *curs
= hex
[rand_r(&seed
) & 0x0E];
768 *curs
= hex
[rand_r(&seed
) & 0x0F];
770 *curs
= hex
[rand() & 0x0E];
772 *curs
= hex
[rand() & 0x0F];
780 bool new_hwaddr(char *hwaddr
)
786 seed
= randseed(false);
788 ret
= snprintf(hwaddr
, 18, "00:16:3e:%02x:%02x:%02x", rand_r(&seed
) % 255,
789 rand_r(&seed
) % 255, rand_r(&seed
) % 255);
792 (void)randseed(true);
794 ret
= snprintf(hwaddr
, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
795 rand() % 255, rand() % 255);
797 if (ret
< 0 || ret
>= 18) {
798 SYSERROR("Failed to call snprintf()");
805 int lxc_get_conf_str(char *retv
, int inlen
, const char *value
)
812 value_len
= strlen(value
);
813 if (retv
&& inlen
>= value_len
+ 1)
814 memcpy(retv
, value
, value_len
+ 1);
819 int lxc_get_conf_bool(struct lxc_conf
*c
, char *retv
, int inlen
, bool v
)
827 memset(retv
, 0, inlen
);
829 strprint(retv
, inlen
, "%d", v
);
834 int lxc_get_conf_int(struct lxc_conf
*c
, char *retv
, int inlen
, int v
)
842 memset(retv
, 0, inlen
);
844 strprint(retv
, inlen
, "%d", v
);
849 int lxc_get_conf_size_t(struct lxc_conf
*c
, char *retv
, int inlen
, size_t v
)
857 memset(retv
, 0, inlen
);
859 strprint(retv
, inlen
, "%zu", v
);
864 int lxc_get_conf_uint64(struct lxc_conf
*c
, char *retv
, int inlen
, uint64_t v
)
872 memset(retv
, 0, inlen
);
874 strprint(retv
, inlen
, "%"PRIu64
, v
);
879 static int lxc_container_name_to_pid(const char *lxcname_or_pid
,
886 pid
= strtol(lxcname_or_pid
, &err
, 10);
887 if (*err
!= '\0' || pid
< 1) {
888 struct lxc_container
*c
;
890 c
= lxc_container_new(lxcname_or_pid
, lxcpath
);
892 ERROR("\"%s\" is not a valid pid nor a container name",
897 if (!c
->may_control(c
)) {
898 ERROR("Insufficient privileges to control container "
900 lxc_container_put(c
);
904 pid
= c
->init_pid(c
);
906 ERROR("Container \"%s\" is not running", c
->name
);
907 lxc_container_put(c
);
911 lxc_container_put(c
);
916 SYSERROR("Failed to send signal to pid %d", (int)pid
);
923 int lxc_inherit_namespace(const char *nsfd_path
, const char *lxcpath
,
924 const char *namespace)
927 char *dup
, *lastslash
;
929 if (nsfd_path
[0] == '/') {
930 return open(nsfd_path
, O_RDONLY
| O_CLOEXEC
);
933 lastslash
= strrchr(nsfd_path
, '/');
935 dup
= strdup(nsfd_path
);
939 dup
[lastslash
- nsfd_path
] = '\0';
940 pid
= lxc_container_name_to_pid(lastslash
+ 1, dup
);
943 pid
= lxc_container_name_to_pid(nsfd_path
, lxcpath
);
949 fd
= lxc_preserve_ns(pid
, namespace);
961 static const struct signame signames
[] = {
994 { SIGSTKFLT
, "STKFLT" },
1003 { SIGXCPU
, "XCPU" },
1006 { SIGXFSZ
, "XFSZ" },
1009 { SIGVTALRM
, "VTALRM" },
1012 { SIGPROF
, "PROF" },
1015 { SIGWINCH
, "WINCH" },
1021 { SIGPOLL
, "POLL" },
1024 { SIGINFO
, "INFO" },
1027 { SIGLOST
, "LOST" },
1033 { SIGUNUSED
, "UNUSED" },
1040 static int sig_num(const char *sig
)
1042 unsigned int signum
;
1044 if (lxc_safe_uint(sig
, &signum
) < 0)
1050 static int rt_sig_num(const char *signame
)
1052 int rtmax
= 0, sig_n
= 0;
1054 if (strncasecmp(signame
, "max-", 4) == 0)
1058 if (!isdigit(*signame
))
1061 sig_n
= sig_num(signame
);
1062 sig_n
= rtmax
? SIGRTMAX
- sig_n
: SIGRTMIN
+ sig_n
;
1063 if (sig_n
> SIGRTMAX
|| sig_n
< SIGRTMIN
)
1069 int sig_parse(const char *signame
)
1073 if (isdigit(*signame
)) {
1074 return sig_num(signame
);
1075 } else if (strncasecmp(signame
, "sig", 3) == 0) {
1077 if (strncasecmp(signame
, "rt", 2) == 0)
1078 return rt_sig_num(signame
+ 2);
1080 for (n
= 0; n
< sizeof(signames
) / sizeof((signames
)[0]); n
++)
1081 if (strcasecmp(signames
[n
].name
, signame
) == 0)
1082 return signames
[n
].num
;