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