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