]> git.proxmox.com Git - mirror_lxc.git/blame_incremental - src/lxc/confile_utils.c
rename functions which clash with libsystemd's
[mirror_lxc.git] / src / lxc / confile_utils.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include "config.h"
4
5#include <arpa/inet.h>
6#include <ctype.h>
7#include <stdio.h>
8#include <stdlib.h>
9#include <string.h>
10
11#include "lxc.h"
12
13#include "conf.h"
14#include "confile.h"
15#include "confile_utils.h"
16#include "error.h"
17#include "list.h"
18#include "lxc.h"
19#include "log.h"
20#include "macro.h"
21#include "memory_utils.h"
22#include "network.h"
23#include "parse.h"
24#include "utils.h"
25
26#if !HAVE_STRLCPY
27#include "strlcpy.h"
28#endif
29
30lxc_log_define(confile_utils, lxc);
31
32int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
33 unsigned long *hostid, unsigned long *range)
34{
35 __do_free char *dup = NULL;
36 int ret = -1;
37 unsigned long tmp_hostid, tmp_nsid, tmp_range;
38 char tmp_type;
39 char *window, *slide;
40
41 /* Duplicate string. */
42 dup = strdup(idmap);
43 if (!dup)
44 return ret_errno(ENOMEM);
45
46 /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
47
48 /* align */
49 slide = window = dup;
50 /* skip whitespace */
51 slide += strspn(slide, " \t\r");
52 if (slide != window && *slide == '\0')
53 return ret_errno(EINVAL);
54
55 /* Validate type. */
56 if (*slide != 'u' && *slide != 'g')
57 return log_error_errno(-EINVAL, EINVAL, "Invalid id mapping type: %c", *slide);
58
59 /* Assign type. */
60 tmp_type = *slide;
61
62 /* move beyond type */
63 slide++;
64 /* align */
65 window = slide;
66 /* Validate that only whitespace follows. */
67 slide += strspn(slide, " \t\r");
68 /* There must be whitespace. */
69 if (slide == window)
70 return ret_errno(EINVAL);
71
72 /* Mark beginning of nsid. */
73 window = slide;
74 /* Validate that non-whitespace follows. */
75 slide += strcspn(slide, " \t\r");
76 /* There must be non-whitespace. */
77 if (slide == window || *slide == '\0')
78 return ret_errno(EINVAL);
79 /* Mark end of nsid. */
80 *slide = '\0';
81
82 /* Parse nsid. */
83 ret = lxc_safe_ulong(window, &tmp_nsid);
84 if (ret < 0)
85 return log_error_errno(ret, errno, "Failed to parse nsid: %s", window);
86
87 /* Move beyond \0. */
88 slide++;
89 /* Validate that only whitespace follows. */
90 slide += strspn(slide, " \t\r");
91 /* If there was only one whitespace then we whiped it with our \0 above.
92 * So only ensure that we're not at the end of the string.
93 */
94 if (*slide == '\0')
95 return ret_errno(EINVAL);
96
97 /* Mark beginning of hostid. */
98 window = slide;
99 /* Validate that non-whitespace follows. */
100 slide += strcspn(slide, " \t\r");
101 /* There must be non-whitespace. */
102 if (slide == window || *slide == '\0')
103 return ret_errno(EINVAL);
104 /* Mark end of nsid. */
105 *slide = '\0';
106
107 /* Parse hostid. */
108 ret = lxc_safe_ulong(window, &tmp_hostid);
109 if (ret < 0)
110 return log_error_errno(ret, errno, "Failed to parse hostid: %s", window);
111
112 /* Move beyond \0. */
113 slide++;
114 /* Validate that only whitespace follows. */
115 slide += strspn(slide, " \t\r");
116 /* If there was only one whitespace then we whiped it with our \0 above.
117 * So only ensure that we're not at the end of the string.
118 */
119 if (*slide == '\0')
120 return ret_errno(EINVAL);
121
122 /* Mark beginning of range. */
123 window = slide;
124 /* Validate that non-whitespace follows. */
125 slide += strcspn(slide, " \t\r");
126 /* There must be non-whitespace. */
127 if (slide == window)
128 return ret_errno(EINVAL);
129
130 /* The range is the last valid entry we expect. So make sure that there
131 * is no trailing garbage and if there is, error out.
132 */
133 if (*(slide + strspn(slide, " \t\r\n")) != '\0')
134 return ret_errno(EINVAL);
135
136 /* Mark end of range. */
137 *slide = '\0';
138
139 /* Parse range. */
140 ret = lxc_safe_ulong(window, &tmp_range);
141 if (ret < 0)
142 return log_error_errno(ret, errno, "Failed to parse id mapping range: %s", window);
143
144 *type = tmp_type;
145 *nsid = tmp_nsid;
146 *hostid = tmp_hostid;
147 *range = tmp_range;
148
149 /* Yay, we survived. */
150 return 0;
151}
152
153bool lxc_config_value_empty(const char *value)
154{
155 if (value && strlen(value) > 0)
156 return false;
157
158 return true;
159}
160
161static struct lxc_netdev *lxc_network_add(struct list_head *head, int idx, bool tail)
162{
163 __do_free struct lxc_netdev *netdev = NULL;
164
165 /* network does not exist */
166 netdev = zalloc(sizeof(*netdev));
167 if (!netdev)
168 return ret_set_errno(NULL, ENOMEM);
169
170 INIT_LIST_HEAD(&netdev->ipv4_addresses);
171 INIT_LIST_HEAD(&netdev->ipv6_addresses);
172
173 /* give network a unique index */
174 netdev->idx = idx;
175
176 if (tail)
177 list_add_tail(&netdev->head, head);
178 else
179 list_add(&netdev->head, head);
180
181 return move_ptr(netdev);
182}
183
184/* Takes care of finding the correct netdev struct in the networks list or
185 * allocates a new one if it couldn't be found.
186 */
187struct lxc_netdev *lxc_get_netdev_by_idx(struct lxc_conf *conf,
188 unsigned int idx, bool allocate)
189{
190 struct list_head *netdevs = &conf->netdevs;
191 struct list_head *head = netdevs;
192 struct lxc_netdev *netdev;
193
194 /* lookup network */
195 if (!list_empty(netdevs)) {
196 list_for_each_entry(netdev, netdevs, head) {
197 /* found network device */
198 if (netdev->idx == idx)
199 return netdev;
200
201 if (netdev->idx > idx) {
202 head = &netdev->head;
203 break;
204 }
205 }
206 }
207
208 if (allocate)
209 return lxc_network_add(head, idx, true);
210
211 return NULL;
212}
213
214void lxc_log_configured_netdevs(const struct lxc_conf *conf)
215{
216 struct lxc_netdev *netdev;
217 const struct list_head *netdevs = &conf->netdevs;
218
219 if (!lxc_log_trace())
220 return;
221
222 if (list_empty(netdevs)) {
223 TRACE("container has no networks configured");
224 return;
225 }
226
227 list_for_each_entry(netdev, netdevs, head) {
228 struct lxc_list *cur, *next;
229 struct lxc_inetdev *inet4dev;
230 struct lxc_inet6dev *inet6dev;
231 char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN];
232
233 TRACE("index: %zd", netdev->idx);
234 TRACE("ifindex: %d", netdev->ifindex);
235
236 switch (netdev->type) {
237 case LXC_NET_VETH:
238 TRACE("type: veth");
239 TRACE("veth mode: %d", netdev->priv.veth_attr.mode);
240
241 if (netdev->priv.veth_attr.pair[0] != '\0')
242 TRACE("veth pair: %s",
243 netdev->priv.veth_attr.pair);
244
245 if (netdev->priv.veth_attr.veth1[0] != '\0')
246 TRACE("veth1 : %s",
247 netdev->priv.veth_attr.veth1);
248
249 if (netdev->priv.veth_attr.ifindex > 0)
250 TRACE("host side ifindex for veth device: %d",
251 netdev->priv.veth_attr.ifindex);
252
253 if (netdev->priv.veth_attr.vlan_id_set)
254 TRACE("veth vlan id: %d", netdev->priv.veth_attr.vlan_id);
255
256 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
257 unsigned short vlan_tagged_id = PTR_TO_USHORT(cur->elem);
258 TRACE("veth vlan tagged id: %u", vlan_tagged_id);
259 }
260
261 break;
262 case LXC_NET_MACVLAN:
263 TRACE("type: macvlan");
264
265 if (netdev->priv.macvlan_attr.mode > 0) {
266 char *mode;
267
268 mode = lxc_macvlan_flag_to_mode(
269 netdev->priv.macvlan_attr.mode);
270 TRACE("macvlan mode: %s",
271 mode ? mode : "(invalid mode)");
272 }
273 break;
274 case LXC_NET_IPVLAN:
275 TRACE("type: ipvlan");
276
277 char *mode;
278 mode = lxc_ipvlan_flag_to_mode(netdev->priv.ipvlan_attr.mode);
279 TRACE("ipvlan mode: %s", mode ? mode : "(invalid mode)");
280
281 char *isolation;
282 isolation = lxc_ipvlan_flag_to_isolation(netdev->priv.ipvlan_attr.isolation);
283 TRACE("ipvlan isolation: %s", isolation ? isolation : "(invalid isolation)");
284 break;
285 case LXC_NET_VLAN:
286 TRACE("type: vlan");
287 TRACE("vlan id: %d", netdev->priv.vlan_attr.vid);
288 break;
289 case LXC_NET_PHYS:
290 TRACE("type: phys");
291
292 if (netdev->priv.phys_attr.ifindex > 0)
293 TRACE("host side ifindex for phys device: %d",
294 netdev->priv.phys_attr.ifindex);
295 break;
296 case LXC_NET_EMPTY:
297 TRACE("type: empty");
298 break;
299 case LXC_NET_NONE:
300 TRACE("type: none");
301 break;
302 default:
303 ERROR("Invalid network type %d", netdev->type);
304 return;
305 }
306
307 if (netdev->type != LXC_NET_EMPTY) {
308 TRACE("flags: %s",
309 netdev->flags == IFF_UP ? "up" : "none");
310
311 if (netdev->link[0] != '\0')
312 TRACE("link: %s", netdev->link);
313
314 /* l2proxy only used when link is specified */
315 if (netdev->link[0] != '\0')
316 TRACE("l2proxy: %s", netdev->l2proxy ? "true" : "false");
317
318 if (netdev->name[0] != '\0')
319 TRACE("name: %s", netdev->name);
320
321 if (netdev->hwaddr)
322 TRACE("hwaddr: %s", netdev->hwaddr);
323
324 if (netdev->mtu)
325 TRACE("mtu: %s", netdev->mtu);
326
327 if (netdev->upscript)
328 TRACE("upscript: %s", netdev->upscript);
329
330 if (netdev->downscript)
331 TRACE("downscript: %s", netdev->downscript);
332
333 TRACE("ipv4 gateway auto: %s",
334 netdev->ipv4_gateway_auto ? "true" : "false");
335
336 TRACE("ipv4 gateway dev: %s",
337 netdev->ipv4_gateway_dev ? "true" : "false");
338
339 if (netdev->ipv4_gateway) {
340 inet_ntop(AF_INET, netdev->ipv4_gateway,
341 bufinet4, sizeof(bufinet4));
342 TRACE("ipv4 gateway: %s", bufinet4);
343 }
344
345 list_for_each_entry(inet4dev, &netdev->ipv4_addresses, head) {
346 inet_ntop(AF_INET, &inet4dev->addr, bufinet4,
347 sizeof(bufinet4));
348 TRACE("ipv4 addr: %s", bufinet4);
349 }
350
351 TRACE("ipv6 gateway auto: %s",
352 netdev->ipv6_gateway_auto ? "true" : "false");
353
354 TRACE("ipv6 gateway dev: %s",
355 netdev->ipv6_gateway_dev ? "true" : "false");
356
357 if (netdev->ipv6_gateway) {
358 inet_ntop(AF_INET6, netdev->ipv6_gateway,
359 bufinet6, sizeof(bufinet6));
360 TRACE("ipv6 gateway: %s", bufinet6);
361 }
362
363 list_for_each_entry(inet6dev, &netdev->ipv6_addresses, head) {
364 inet_ntop(AF_INET6, &inet6dev->addr, bufinet6,
365 sizeof(bufinet6));
366 TRACE("ipv6 addr: %s", bufinet6);
367 }
368
369 if (netdev->type == LXC_NET_VETH) {
370 list_for_each_entry(inet4dev, &netdev->priv.veth_attr.ipv4_routes, head) {
371 if (!inet_ntop(AF_INET, &inet4dev->addr, bufinet4, sizeof(bufinet4))) {
372 ERROR("Invalid ipv4 veth route");
373 return;
374 }
375
376 TRACE("ipv4 veth route: %s/%u", bufinet4, inet4dev->prefix);
377 }
378
379 list_for_each_entry(inet6dev, &netdev->priv.veth_attr.ipv6_routes, head) {
380 if (!inet_ntop(AF_INET6, &inet6dev->addr, bufinet6, sizeof(bufinet6))) {
381 ERROR("Invalid ipv6 veth route");
382 return;
383 }
384
385 TRACE("ipv6 veth route: %s/%u", bufinet6, inet6dev->prefix);
386 }
387 }
388 }
389 }
390}
391
392void lxc_clear_netdev(struct lxc_netdev *netdev)
393{
394 struct lxc_list *cur, *next;
395 struct list_head head;
396 struct lxc_inetdev *inetdev, *ninetdev;
397 struct lxc_inet6dev *inet6dev, *ninet6dev;
398 ssize_t idx;
399
400 if (!netdev)
401 return;
402
403 idx = netdev->idx;
404
405 free_disarm(netdev->upscript);
406 free_disarm(netdev->downscript);
407 free_disarm(netdev->hwaddr);
408 free_disarm(netdev->mtu);
409
410 free_disarm(netdev->ipv4_gateway);
411 list_for_each_entry_safe(inetdev, ninetdev, &netdev->ipv4_addresses, head) {
412 list_del(&inetdev->head);
413 free(inetdev);
414 }
415
416 free_disarm(netdev->ipv6_gateway);
417 list_for_each_entry_safe(inet6dev, ninet6dev, &netdev->ipv6_addresses, head) {
418 list_del(&inet6dev->head);
419 free(inet6dev);
420 }
421
422 if (netdev->type == LXC_NET_VETH) {
423 list_for_each_entry_safe(inetdev, ninetdev, &netdev->priv.veth_attr.ipv4_routes, head) {
424 list_del(&inetdev->head);
425 free(inetdev);
426 }
427
428 list_for_each_entry_safe(inet6dev, ninet6dev, &netdev->priv.veth_attr.ipv6_routes, head) {
429 list_del(&inet6dev->head);
430 free(inet6dev);
431 }
432
433 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.vlan_tagged_ids, next) {
434 lxc_list_del(cur);
435 free(cur);
436 }
437 }
438
439 head = netdev->head;
440 memset(netdev, 0, sizeof(struct lxc_netdev));
441 netdev->head = head;
442 INIT_LIST_HEAD(&netdev->ipv4_addresses);
443 INIT_LIST_HEAD(&netdev->ipv6_addresses);
444 netdev->type = -1;
445 netdev->idx = idx;
446}
447
448static void lxc_free_netdev(struct lxc_netdev *netdev)
449{
450 if (netdev) {
451 lxc_clear_netdev(netdev);
452 free(netdev);
453 }
454}
455
456bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx)
457{
458 struct lxc_netdev *netdev;
459
460 if (list_empty(&conf->netdevs))
461 return false;
462
463 list_for_each_entry(netdev, &conf->netdevs, head) {
464 if (netdev->idx != idx)
465 continue;
466
467 list_del(&netdev->head);
468 lxc_free_netdev(netdev);
469 return true;
470 }
471
472 return false;
473}
474
475void lxc_free_networks(struct lxc_conf *conf)
476{
477 struct lxc_netdev *netdev, *n;
478
479 if (list_empty(&conf->netdevs))
480 return;
481
482 list_for_each_entry_safe(netdev, n, &conf->netdevs, head) {
483 list_del(&netdev->head);
484 lxc_free_netdev(netdev);
485 }
486
487 /* prevent segfaults */
488 INIT_LIST_HEAD(&conf->netdevs);
489}
490
491static struct lxc_veth_mode {
492 char *name;
493 int mode;
494} veth_mode[] = {
495 { "bridge", VETH_MODE_BRIDGE },
496 { "router", VETH_MODE_ROUTER },
497};
498
499int lxc_veth_mode_to_flag(int *mode, const char *value)
500{
501 for (size_t i = 0; i < sizeof(veth_mode) / sizeof(veth_mode[0]); i++) {
502 if (!strequal(veth_mode[i].name, value))
503 continue;
504
505 *mode = veth_mode[i].mode;
506 return 0;
507 }
508
509 return ret_errno(EINVAL);
510}
511
512char *lxc_veth_flag_to_mode(int mode)
513{
514 for (size_t i = 0; i < sizeof(veth_mode) / sizeof(veth_mode[0]); i++) {
515 if (veth_mode[i].mode != mode)
516 continue;
517
518 return veth_mode[i].name;
519 }
520
521 return ret_set_errno(NULL, EINVAL);
522}
523
524static struct lxc_macvlan_mode {
525 char *name;
526 int mode;
527} macvlan_mode[] = {
528 { "private", MACVLAN_MODE_PRIVATE },
529 { "vepa", MACVLAN_MODE_VEPA },
530 { "bridge", MACVLAN_MODE_BRIDGE },
531 { "passthru", MACVLAN_MODE_PASSTHRU },
532};
533
534int lxc_macvlan_mode_to_flag(int *mode, const char *value)
535{
536 for (size_t i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
537 if (!strequal(macvlan_mode[i].name, value))
538 continue;
539
540 *mode = macvlan_mode[i].mode;
541 return 0;
542 }
543
544 return ret_errno(EINVAL);
545}
546
547char *lxc_macvlan_flag_to_mode(int mode)
548{
549 for (size_t i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
550 if (macvlan_mode[i].mode != mode)
551 continue;
552
553 return macvlan_mode[i].name;
554 }
555
556 return ret_set_errno(NULL, EINVAL);
557}
558
559static struct lxc_ipvlan_mode {
560 char *name;
561 int mode;
562} ipvlan_mode[] = {
563 { "l3", IPVLAN_MODE_L3 },
564 { "l3s", IPVLAN_MODE_L3S },
565 { "l2", IPVLAN_MODE_L2 },
566};
567
568int lxc_ipvlan_mode_to_flag(int *mode, const char *value)
569{
570 for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
571 if (!strequal(ipvlan_mode[i].name, value))
572 continue;
573
574 *mode = ipvlan_mode[i].mode;
575 return 0;
576 }
577
578 return ret_errno(EINVAL);
579}
580
581char *lxc_ipvlan_flag_to_mode(int mode)
582{
583 for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
584 if (ipvlan_mode[i].mode != mode)
585 continue;
586
587 return ipvlan_mode[i].name;
588 }
589
590 return ret_set_errno(NULL, EINVAL);
591}
592
593static struct lxc_ipvlan_isolation {
594 char *name;
595 int flag;
596} ipvlan_isolation[] = {
597 { "bridge", IPVLAN_ISOLATION_BRIDGE },
598 { "private", IPVLAN_ISOLATION_PRIVATE },
599 { "vepa", IPVLAN_ISOLATION_VEPA },
600};
601
602int lxc_ipvlan_isolation_to_flag(int *flag, const char *value)
603{
604 for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
605 if (!strequal(ipvlan_isolation[i].name, value))
606 continue;
607
608 *flag = ipvlan_isolation[i].flag;
609 return 0;
610 }
611
612 return ret_errno(EINVAL);
613}
614
615char *lxc_ipvlan_flag_to_isolation(int flag)
616{
617 for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
618 if (ipvlan_isolation[i].flag != flag)
619 continue;
620
621 return ipvlan_isolation[i].name;
622 }
623
624 return ret_set_errno(NULL, EINVAL);
625}
626
627int set_config_string_item(char **conf_item, const char *value)
628{
629 char *new_value;
630
631 if (lxc_config_value_empty(value)) {
632 free_disarm(*conf_item);
633 return 0;
634 }
635
636 new_value = strdup(value);
637 if (!new_value)
638 return log_error_errno(-ENOMEM, ENOMEM, "Failed to duplicate string \"%s\"", value);
639
640 free_move_ptr(*conf_item, new_value);
641 return 0;
642}
643
644int set_config_string_item_max(char **conf_item, const char *value, size_t max)
645{
646 if (strlen(value) >= max)
647 return log_error_errno(-ENAMETOOLONG, ENAMETOOLONG, "%s is too long (>= %lu)", value, (unsigned long)max);
648
649 return set_config_string_item(conf_item, value);
650}
651
652int set_config_path_item(char **conf_item, const char *value)
653{
654 __do_free char *valdup = NULL;
655
656 valdup = lxc_path_simplify(value);
657 if (!valdup)
658 return -ENOMEM;
659
660 return set_config_string_item_max(conf_item, valdup, PATH_MAX);
661}
662
663int set_config_bool_item(bool *conf_item, const char *value, bool empty_conf_action)
664{
665 int ret;
666 unsigned int val = 0;
667
668 if (lxc_config_value_empty(value)) {
669 *conf_item = empty_conf_action;
670 return 0;
671 }
672
673 ret = lxc_safe_uint(value, &val);
674 if (ret < 0)
675 return ret;
676
677 switch (val) {
678 case 0:
679 *conf_item = false;
680 return 0;
681 case 1:
682 *conf_item = true;
683 return 0;
684 }
685
686 return ret_errno(EINVAL);
687}
688
689int config_ip_prefix(struct in_addr *addr)
690{
691 if (IN_CLASSA(addr->s_addr))
692 return 32 - IN_CLASSA_NSHIFT;
693
694 if (IN_CLASSB(addr->s_addr))
695 return 32 - IN_CLASSB_NSHIFT;
696
697 if (IN_CLASSC(addr->s_addr))
698 return 32 - IN_CLASSC_NSHIFT;
699
700 return 0;
701}
702
703int network_ifname(char *valuep, const char *value, size_t size)
704{
705 size_t retlen;
706
707 if (!valuep || !value)
708 return ret_errno(EINVAL);
709
710 retlen = strlcpy(valuep, value, size);
711 if (retlen >= size)
712 ERROR("Network device name \"%s\" is too long (>= %zu)", value, size);
713
714 return 0;
715}
716
717bool lxc_config_net_is_hwaddr(const char *line)
718{
719 unsigned index;
720 char tmp[7];
721
722 if (!strnequal(line, "lxc.net", 7))
723 return false;
724
725 if (strnequal(line, "lxc.net.hwaddr", 14))
726 return true;
727
728 if (strnequal(line, "lxc.network.hwaddr", 18))
729 return true;
730
731 if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 ||
732 sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
733 return strnequal(tmp, "hwaddr", 6);
734
735 return false;
736}
737
738void rand_complete_hwaddr(char *hwaddr)
739{
740 const char hex[] = "0123456789abcdef";
741 char *curs = hwaddr;
742#ifdef HAVE_RAND_R
743 unsigned int seed;
744
745 seed = randseed(false);
746#else
747
748 (void)randseed(true);
749#endif
750
751 while (*curs != '\0' && *curs != '\n') {
752 if (*curs == 'x' || *curs == 'X') {
753 if (curs - hwaddr == 1) {
754 /* ensure address is unicast */
755#ifdef HAVE_RAND_R
756 *curs = hex[rand_r(&seed) & 0x0E];
757 } else {
758 *curs = hex[rand_r(&seed) & 0x0F];
759#else
760 *curs = hex[rand() & 0x0E];
761 } else {
762 *curs = hex[rand() & 0x0F];
763#endif
764 }
765 }
766 curs++;
767 }
768}
769
770bool new_hwaddr(char *hwaddr)
771{
772 int ret;
773#ifdef HAVE_RAND_R
774 unsigned int seed;
775
776 seed = randseed(false);
777
778 ret = strnprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand_r(&seed) % 255,
779 rand_r(&seed) % 255, rand_r(&seed) % 255);
780#else
781
782 (void)randseed(true);
783
784 ret = strnprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
785 rand() % 255, rand() % 255);
786#endif
787 if (ret < 0)
788 return log_error_errno(false, EIO, "Failed to call strnprintf()");
789
790 return true;
791}
792
793int lxc_get_conf_str(char *retv, int inlen, const char *value)
794{
795 size_t value_len;
796
797 if (!value)
798 return 0;
799
800 value_len = strlen(value);
801 if (retv && (size_t)inlen >= value_len + 1)
802 memcpy(retv, value, value_len + 1);
803
804 return value_len;
805}
806
807int lxc_get_conf_bool(struct lxc_conf *c, char *retv, int inlen, bool v)
808{
809 int len;
810 int fulllen = 0;
811
812 if (!retv)
813 inlen = 0;
814 else
815 memset(retv, 0, inlen);
816
817 strprint(retv, inlen, "%d", v);
818
819 return fulllen;
820}
821
822int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
823{
824 int len;
825 int fulllen = 0;
826
827 if (!retv)
828 inlen = 0;
829 else
830 memset(retv, 0, inlen);
831
832 strprint(retv, inlen, "%d", v);
833
834 return fulllen;
835}
836
837int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
838{
839 int len;
840 int fulllen = 0;
841
842 if (!retv)
843 inlen = 0;
844 else
845 memset(retv, 0, inlen);
846
847 strprint(retv, inlen, "%zu", v);
848
849 return fulllen;
850}
851
852int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
853{
854 int len;
855 int fulllen = 0;
856
857 if (!retv)
858 inlen = 0;
859 else
860 memset(retv, 0, inlen);
861
862 strprint(retv, inlen, "%"PRIu64, v);
863
864 return fulllen;
865}
866
867static int lxc_container_name_to_pid(const char *lxcname_or_pid,
868 const char *lxcpath)
869{
870 int ret;
871 signed long int pid;
872 char *err = NULL;
873
874 pid = strtol(lxcname_or_pid, &err, 10);
875 if (*err != '\0' || pid < 1) {
876 __put_lxc_container struct lxc_container *c = NULL;
877
878 c = lxc_container_new(lxcname_or_pid, lxcpath);
879 if (!c)
880 return log_error_errno(-EINVAL, EINVAL, "\"%s\" is not a valid pid nor a container name", lxcname_or_pid);
881
882 if (!c->may_control(c))
883 return log_error_errno(-EPERM, EPERM, "Insufficient privileges to control container \"%s\"", c->name);
884
885 pid = c->init_pid(c);
886 if (pid < 1)
887 return log_error_errno(-EINVAL, EINVAL, "Container \"%s\" is not running", c->name);
888
889 }
890
891 ret = kill(pid, 0);
892 if (ret < 0)
893 return log_error_errno(-errno, errno, "Failed to send signal to pid %d", (int)pid);
894
895 return pid;
896}
897
898int lxc_inherit_namespace(const char *nsfd_path, const char *lxcpath,
899 const char *namespace)
900{
901 __do_free char *dup = NULL;
902 int fd, pid;
903 char *lastslash;
904
905 if (nsfd_path[0] == '/') {
906 return open(nsfd_path, O_RDONLY | O_CLOEXEC);
907 }
908
909 lastslash = strrchr(nsfd_path, '/');
910 if (lastslash) {
911 dup = strdup(nsfd_path);
912 if (!dup)
913 return ret_errno(ENOMEM);
914
915 dup[lastslash - nsfd_path] = '\0';
916 lxcpath = lastslash + 1;
917 nsfd_path = lastslash + 1;
918 }
919
920 pid = lxc_container_name_to_pid(nsfd_path, lxcpath);
921 if (pid < 0)
922 return pid;
923
924 fd = lxc_preserve_ns(pid, namespace);
925 if (fd < 0)
926 return -errno;
927
928 return fd;
929}
930
931struct signame {
932 int num;
933 const char *name;
934};
935
936static const struct signame signames[] = {
937 { SIGHUP, "HUP" },
938 { SIGINT, "INT" },
939 { SIGQUIT, "QUIT" },
940 { SIGILL, "ILL" },
941 { SIGABRT, "ABRT" },
942 { SIGFPE, "FPE" },
943 { SIGKILL, "KILL" },
944 { SIGSEGV, "SEGV" },
945 { SIGPIPE, "PIPE" },
946 { SIGALRM, "ALRM" },
947 { SIGTERM, "TERM" },
948 { SIGUSR1, "USR1" },
949 { SIGUSR2, "USR2" },
950 { SIGCHLD, "CHLD" },
951 { SIGCONT, "CONT" },
952 { SIGSTOP, "STOP" },
953 { SIGTSTP, "TSTP" },
954 { SIGTTIN, "TTIN" },
955 { SIGTTOU, "TTOU" },
956#ifdef SIGTRAP
957 { SIGTRAP, "TRAP" },
958#endif
959#ifdef SIGIOT
960 { SIGIOT, "IOT" },
961#endif
962#ifdef SIGEMT
963 { SIGEMT, "EMT" },
964#endif
965#ifdef SIGBUS
966 { SIGBUS, "BUS" },
967#endif
968#ifdef SIGSTKFLT
969 { SIGSTKFLT, "STKFLT" },
970#endif
971#ifdef SIGCLD
972 { SIGCLD, "CLD" },
973#endif
974#ifdef SIGURG
975 { SIGURG, "URG" },
976#endif
977#ifdef SIGXCPU
978 { SIGXCPU, "XCPU" },
979#endif
980#ifdef SIGXFSZ
981 { SIGXFSZ, "XFSZ" },
982#endif
983#ifdef SIGVTALRM
984 { SIGVTALRM, "VTALRM" },
985#endif
986#ifdef SIGPROF
987 { SIGPROF, "PROF" },
988#endif
989#ifdef SIGWINCH
990 { SIGWINCH, "WINCH" },
991#endif
992#ifdef SIGIO
993 { SIGIO, "IO" },
994#endif
995#ifdef SIGPOLL
996 { SIGPOLL, "POLL" },
997#endif
998#ifdef SIGINFO
999 { SIGINFO, "INFO" },
1000#endif
1001#ifdef SIGLOST
1002 { SIGLOST, "LOST" },
1003#endif
1004#ifdef SIGPWR
1005 { SIGPWR, "PWR" },
1006#endif
1007#ifdef SIGUNUSED
1008 { SIGUNUSED, "UNUSED" },
1009#endif
1010#ifdef SIGSYS
1011 { SIGSYS, "SYS" },
1012#endif
1013};
1014
1015static int sig_num(const char *sig)
1016{
1017 int ret;
1018 unsigned int signum;
1019
1020 ret = lxc_safe_uint(sig, &signum);
1021 if (ret < 0)
1022 return ret;
1023
1024 return signum;
1025}
1026
1027static int rt_sig_num(const char *signame)
1028{
1029 bool rtmax;
1030 int sig_n = 0;
1031
1032 if (is_empty_string(signame))
1033 return ret_errno(EINVAL);
1034
1035 if (strncasecmp(signame, "max-", STRLITERALLEN("max-")) == 0) {
1036 rtmax = true;
1037 signame += STRLITERALLEN("max-");
1038 } else if (strncasecmp(signame, "min+", STRLITERALLEN("min+")) == 0) {
1039 rtmax = false;
1040 signame += STRLITERALLEN("min+");
1041 } else {
1042 return ret_errno(EINVAL);
1043 }
1044
1045 if (is_empty_string(signame) || !isdigit(*signame))
1046 return ret_errno(EINVAL);
1047
1048 sig_n = sig_num(signame);
1049 if (sig_n < 0 || sig_n > SIGRTMAX - SIGRTMIN)
1050 return ret_errno(EINVAL);
1051
1052 if (rtmax)
1053 sig_n = SIGRTMAX - sig_n;
1054 else
1055 sig_n = SIGRTMIN + sig_n;
1056
1057 return sig_n;
1058}
1059
1060int sig_parse(const char *signame)
1061{
1062 if (isdigit(*signame))
1063 return sig_num(signame);
1064
1065 if (strncasecmp(signame, "sig", STRLITERALLEN("sig")) == 0) {
1066 signame += STRLITERALLEN("sig");
1067 if (strncasecmp(signame, "rt", STRLITERALLEN("rt")) == 0)
1068 return rt_sig_num(signame + STRLITERALLEN("rt"));
1069
1070 for (size_t n = 0; n < ARRAY_SIZE(signames); n++)
1071 if (strcasecmp(signames[n].name, signame) == 0)
1072 return signames[n].num;
1073 }
1074
1075 return ret_errno(EINVAL);
1076}