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