]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/confile_utils.c
confile_utils: cleanup rt_sig_num()
[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 "lxc.h"
19 #include "log.h"
20 #include "lxccontainer.h"
21 #include "macro.h"
22 #include "memory_utils.h"
23 #include "network.h"
24 #include "parse.h"
25 #include "utils.h"
26
27 #ifndef HAVE_STRLCPY
28 #include "include/strlcpy.h"
29 #endif
30
31 lxc_log_define(confile_utils, lxc);
32
33 int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
34 unsigned long *hostid, unsigned long *range)
35 {
36 __do_free char *dup = NULL;
37 int ret = -1;
38 unsigned long tmp_hostid, tmp_nsid, tmp_range;
39 char tmp_type;
40 char *window, *slide;
41
42 /* Duplicate string. */
43 dup = strdup(idmap);
44 if (!dup)
45 return ret_errno(ENOMEM);
46
47 /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
48
49 /* align */
50 slide = window = dup;
51 /* skip whitespace */
52 slide += strspn(slide, " \t\r");
53 if (slide != window && *slide == '\0')
54 return ret_errno(EINVAL);
55
56 /* Validate type. */
57 if (*slide != 'u' && *slide != 'g')
58 return log_error_errno(-EINVAL, EINVAL, "Invalid id mapping type: %c", *slide);
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 return ret_errno(EINVAL);
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 return ret_errno(EINVAL);
80 /* Mark end of nsid. */
81 *slide = '\0';
82
83 /* Parse nsid. */
84 ret = lxc_safe_ulong(window, &tmp_nsid);
85 if (ret < 0)
86 return log_error_errno(ret, errno, "Failed to parse nsid: %s", window);
87
88 /* Move beyond \0. */
89 slide++;
90 /* Validate that only whitespace follows. */
91 slide += strspn(slide, " \t\r");
92 /* If there was only one whitespace then we whiped it with our \0 above.
93 * So only ensure that we're not at the end of the string.
94 */
95 if (*slide == '\0')
96 return ret_errno(EINVAL);
97
98 /* Mark beginning of hostid. */
99 window = slide;
100 /* Validate that non-whitespace follows. */
101 slide += strcspn(slide, " \t\r");
102 /* There must be non-whitespace. */
103 if (slide == window || *slide == '\0')
104 return ret_errno(EINVAL);
105 /* Mark end of nsid. */
106 *slide = '\0';
107
108 /* Parse hostid. */
109 ret = lxc_safe_ulong(window, &tmp_hostid);
110 if (ret < 0)
111 return log_error_errno(ret, errno, "Failed to parse hostid: %s", window);
112
113 /* Move beyond \0. */
114 slide++;
115 /* Validate that only whitespace follows. */
116 slide += strspn(slide, " \t\r");
117 /* If there was only one whitespace then we whiped it with our \0 above.
118 * So only ensure that we're not at the end of the string.
119 */
120 if (*slide == '\0')
121 return ret_errno(EINVAL);
122
123 /* Mark beginning of range. */
124 window = slide;
125 /* Validate that non-whitespace follows. */
126 slide += strcspn(slide, " \t\r");
127 /* There must be non-whitespace. */
128 if (slide == window)
129 return ret_errno(EINVAL);
130
131 /* The range is the last valid entry we expect. So make sure that there
132 * is no trailing garbage and if there is, error out.
133 */
134 if (*(slide + strspn(slide, " \t\r\n")) != '\0')
135 return ret_errno(EINVAL);
136
137 /* Mark end of range. */
138 *slide = '\0';
139
140 /* Parse range. */
141 ret = lxc_safe_ulong(window, &tmp_range);
142 if (ret < 0)
143 return log_error_errno(ret, errno, "Failed to parse id mapping range: %s", window);
144
145 *type = tmp_type;
146 *nsid = tmp_nsid;
147 *hostid = tmp_hostid;
148 *range = tmp_range;
149
150 /* Yay, we survived. */
151 return 0;
152 }
153
154 bool lxc_config_value_empty(const char *value)
155 {
156 if (value && strlen(value) > 0)
157 return false;
158
159 return true;
160 }
161
162 struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail)
163 {
164 __do_free struct lxc_list *newlist = NULL;
165 __do_free struct lxc_netdev *netdev = NULL;
166
167 /* network does not exist */
168 netdev = malloc(sizeof(*netdev));
169 if (!netdev)
170 return ret_set_errno(NULL, ENOMEM);
171
172 memset(netdev, 0, sizeof(*netdev));
173 lxc_list_init(&netdev->ipv4);
174 lxc_list_init(&netdev->ipv6);
175
176 /* give network a unique index */
177 netdev->idx = idx;
178
179 /* prepare new list */
180 newlist = malloc(sizeof(*newlist));
181 if (!newlist)
182 return ret_set_errno(NULL, ENOMEM);
183
184 lxc_list_init(newlist);
185 newlist->elem = netdev;
186
187 if (tail)
188 lxc_list_add_tail(networks, newlist);
189 else
190 lxc_list_add(networks, newlist);
191 move_ptr(newlist);
192
193 return move_ptr(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 */
199 struct 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 ret_set_errno(NULL, EINVAL);
219
220 return lxc_network_add(insert, idx, true);
221 }
222
223 void 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
408 static void lxc_free_netdev(struct lxc_netdev *netdev)
409 {
410 struct lxc_list *cur, *next;
411
412 if (!netdev)
413 return;
414
415 free(netdev->upscript);
416 free(netdev->downscript);
417 free(netdev->hwaddr);
418 free(netdev->mtu);
419
420 free(netdev->ipv4_gateway);
421 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
422 lxc_list_del(cur);
423 free(cur->elem);
424 free(cur);
425 }
426
427 free(netdev->ipv6_gateway);
428 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
429 lxc_list_del(cur);
430 free(cur->elem);
431 free(cur);
432 }
433
434 if (netdev->type == LXC_NET_VETH) {
435 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
436 lxc_list_del(cur);
437 free(cur->elem);
438 free(cur);
439 }
440
441 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_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.vlan_tagged_ids, next) {
448 lxc_list_del(cur);
449 free(cur);
450 }
451 }
452
453 free(netdev);
454 }
455
456 define_cleanup_function(struct lxc_netdev *, lxc_free_netdev);
457
458 bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx)
459 {
460 call_cleaner(lxc_free_netdev) struct lxc_netdev *netdev = NULL;
461 struct lxc_list *cur, *next;
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 free(cur);
470 return true;
471 }
472
473 return false;
474 }
475
476 void lxc_free_networks(struct lxc_list *networks)
477 {
478 struct lxc_list *cur, *next;
479
480 lxc_list_for_each_safe (cur, networks, next) {
481 struct lxc_netdev *netdev = cur->elem;
482 netdev = cur->elem;
483 lxc_free_netdev(netdev);
484 free(cur);
485 }
486
487 /* prevent segfaults */
488 lxc_list_init(networks);
489 }
490
491 static 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
499 int 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 (strcmp(veth_mode[i].name, value) != 0)
503 continue;
504
505 *mode = veth_mode[i].mode;
506 return 0;
507 }
508
509 return ret_errno(EINVAL);
510 }
511
512 char *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
524 static 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
534 int 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 (strcmp(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
547 char *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
559 static 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
568 int 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 (strcmp(ipvlan_mode[i].name, value) != 0)
572 continue;
573
574 *mode = ipvlan_mode[i].mode;
575 return 0;
576 }
577
578 return ret_errno(EINVAL);
579 }
580
581 char *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
593 static 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
602 int 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 (strcmp(ipvlan_isolation[i].name, value) != 0)
606 continue;
607
608 *flag = ipvlan_isolation[i].flag;
609 return 0;
610 }
611
612 return ret_errno(EINVAL);
613 }
614
615 char *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
627 int 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
644 int 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
652 int set_config_path_item(char **conf_item, const char *value)
653 {
654 return set_config_string_item_max(conf_item, value, PATH_MAX);
655 }
656
657 int set_config_bool_item(bool *conf_item, const char *value, bool empty_conf_action)
658 {
659 int ret;
660 unsigned int val = 0;
661
662 if (lxc_config_value_empty(value)) {
663 *conf_item = empty_conf_action;
664 return 0;
665 }
666
667 ret = lxc_safe_uint(value, &val);
668 if (ret < 0)
669 return ret;
670
671 switch (val) {
672 case 0:
673 *conf_item = false;
674 return 0;
675 case 1:
676 *conf_item = true;
677 return 0;
678 }
679
680 return ret_errno(EINVAL);
681 }
682
683 int config_ip_prefix(struct in_addr *addr)
684 {
685 if (IN_CLASSA(addr->s_addr))
686 return 32 - IN_CLASSA_NSHIFT;
687
688 if (IN_CLASSB(addr->s_addr))
689 return 32 - IN_CLASSB_NSHIFT;
690
691 if (IN_CLASSC(addr->s_addr))
692 return 32 - IN_CLASSC_NSHIFT;
693
694 return 0;
695 }
696
697 int network_ifname(char *valuep, const char *value, size_t size)
698 {
699 size_t retlen;
700
701 if (!valuep || !value)
702 return ret_errno(EINVAL);
703
704 retlen = strlcpy(valuep, value, size);
705 if (retlen >= size)
706 ERROR("Network device name \"%s\" is too long (>= %zu)", value, size);
707
708 return 0;
709 }
710
711 bool lxc_config_net_is_hwaddr(const char *line)
712 {
713 unsigned index;
714 char tmp[7];
715
716 if (strncmp(line, "lxc.net", 7) != 0)
717 return false;
718
719 if (strncmp(line, "lxc.net.hwaddr", 14) == 0)
720 return true;
721
722 if (strncmp(line, "lxc.network.hwaddr", 18) == 0)
723 return true;
724
725 if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 ||
726 sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
727 return strncmp(tmp, "hwaddr", 6) == 0;
728
729 return false;
730 }
731
732 void rand_complete_hwaddr(char *hwaddr)
733 {
734 const char hex[] = "0123456789abcdef";
735 char *curs = hwaddr;
736 #ifdef HAVE_RAND_R
737 unsigned int seed;
738
739 seed = randseed(false);
740 #else
741
742 (void)randseed(true);
743 #endif
744
745 while (*curs != '\0' && *curs != '\n') {
746 if (*curs == 'x' || *curs == 'X') {
747 if (curs - hwaddr == 1) {
748 /* ensure address is unicast */
749 #ifdef HAVE_RAND_R
750 *curs = hex[rand_r(&seed) & 0x0E];
751 } else {
752 *curs = hex[rand_r(&seed) & 0x0F];
753 #else
754 *curs = hex[rand() & 0x0E];
755 } else {
756 *curs = hex[rand() & 0x0F];
757 #endif
758 }
759 }
760 curs++;
761 }
762 }
763
764 bool new_hwaddr(char *hwaddr)
765 {
766 int ret;
767 #ifdef HAVE_RAND_R
768 unsigned int seed;
769
770 seed = randseed(false);
771
772 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand_r(&seed) % 255,
773 rand_r(&seed) % 255, rand_r(&seed) % 255);
774 #else
775
776 (void)randseed(true);
777
778 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
779 rand() % 255, rand() % 255);
780 #endif
781 if (ret < 0 || ret >= 18) {
782 return log_error_errno(false, EIO, "Failed to call snprintf()");
783 }
784
785 return true;
786 }
787
788 int lxc_get_conf_str(char *retv, int inlen, const char *value)
789 {
790 size_t value_len;
791
792 if (!value)
793 return 0;
794
795 value_len = strlen(value);
796 if (retv && inlen >= value_len + 1)
797 memcpy(retv, value, value_len + 1);
798
799 return value_len;
800 }
801
802 int lxc_get_conf_bool(struct lxc_conf *c, char *retv, int inlen, bool v)
803 {
804 int len;
805 int fulllen = 0;
806
807 if (!retv)
808 inlen = 0;
809 else
810 memset(retv, 0, inlen);
811
812 strprint(retv, inlen, "%d", v);
813
814 return fulllen;
815 }
816
817 int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
818 {
819 int len;
820 int fulllen = 0;
821
822 if (!retv)
823 inlen = 0;
824 else
825 memset(retv, 0, inlen);
826
827 strprint(retv, inlen, "%d", v);
828
829 return fulllen;
830 }
831
832 int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
833 {
834 int len;
835 int fulllen = 0;
836
837 if (!retv)
838 inlen = 0;
839 else
840 memset(retv, 0, inlen);
841
842 strprint(retv, inlen, "%zu", v);
843
844 return fulllen;
845 }
846
847 int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
848 {
849 int len;
850 int fulllen = 0;
851
852 if (!retv)
853 inlen = 0;
854 else
855 memset(retv, 0, inlen);
856
857 strprint(retv, inlen, "%"PRIu64, v);
858
859 return fulllen;
860 }
861
862 static int lxc_container_name_to_pid(const char *lxcname_or_pid,
863 const char *lxcpath)
864 {
865 int ret;
866 signed long int pid;
867 char *err = NULL;
868
869 pid = strtol(lxcname_or_pid, &err, 10);
870 if (*err != '\0' || pid < 1) {
871 __put_lxc_container struct lxc_container *c = NULL;
872
873 c = lxc_container_new(lxcname_or_pid, lxcpath);
874 if (!c)
875 return log_error_errno(-EINVAL, EINVAL, "\"%s\" is not a valid pid nor a container name", lxcname_or_pid);
876
877 if (!c->may_control(c))
878 return log_error_errno(-EPERM, EPERM, "Insufficient privileges to control container \"%s\"", c->name);
879
880 pid = c->init_pid(c);
881 if (pid < 1)
882 return log_error_errno(-EINVAL, EINVAL, "Container \"%s\" is not running", c->name);
883
884 }
885
886 ret = kill(pid, 0);
887 if (ret < 0)
888 return log_error_errno(-errno, errno, "Failed to send signal to pid %d", (int)pid);
889
890 return pid;
891 }
892
893 int lxc_inherit_namespace(const char *nsfd_path, const char *lxcpath,
894 const char *namespace)
895 {
896 __do_free char *dup = NULL;
897 int fd, pid;
898 char *lastslash;
899
900 if (nsfd_path[0] == '/') {
901 return open(nsfd_path, O_RDONLY | O_CLOEXEC);
902 }
903
904 lastslash = strrchr(nsfd_path, '/');
905 if (lastslash) {
906 dup = strdup(nsfd_path);
907 if (!dup)
908 return ret_errno(ENOMEM);
909
910 dup[lastslash - nsfd_path] = '\0';
911 lxcpath = lastslash + 1;
912 nsfd_path = lastslash + 1;
913 }
914
915 pid = lxc_container_name_to_pid(nsfd_path, lxcpath);
916 if (pid < 0)
917 return pid;
918
919 fd = lxc_preserve_ns(pid, namespace);
920 if (fd < 0)
921 return -errno;
922
923 return fd;
924 }
925
926 struct signame {
927 int num;
928 const char *name;
929 };
930
931 static const struct signame signames[] = {
932 { SIGHUP, "HUP" },
933 { SIGINT, "INT" },
934 { SIGQUIT, "QUIT" },
935 { SIGILL, "ILL" },
936 { SIGABRT, "ABRT" },
937 { SIGFPE, "FPE" },
938 { SIGKILL, "KILL" },
939 { SIGSEGV, "SEGV" },
940 { SIGPIPE, "PIPE" },
941 { SIGALRM, "ALRM" },
942 { SIGTERM, "TERM" },
943 { SIGUSR1, "USR1" },
944 { SIGUSR2, "USR2" },
945 { SIGCHLD, "CHLD" },
946 { SIGCONT, "CONT" },
947 { SIGSTOP, "STOP" },
948 { SIGTSTP, "TSTP" },
949 { SIGTTIN, "TTIN" },
950 { SIGTTOU, "TTOU" },
951 #ifdef SIGTRAP
952 { SIGTRAP, "TRAP" },
953 #endif
954 #ifdef SIGIOT
955 { SIGIOT, "IOT" },
956 #endif
957 #ifdef SIGEMT
958 { SIGEMT, "EMT" },
959 #endif
960 #ifdef SIGBUS
961 { SIGBUS, "BUS" },
962 #endif
963 #ifdef SIGSTKFLT
964 { SIGSTKFLT, "STKFLT" },
965 #endif
966 #ifdef SIGCLD
967 { SIGCLD, "CLD" },
968 #endif
969 #ifdef SIGURG
970 { SIGURG, "URG" },
971 #endif
972 #ifdef SIGXCPU
973 { SIGXCPU, "XCPU" },
974 #endif
975 #ifdef SIGXFSZ
976 { SIGXFSZ, "XFSZ" },
977 #endif
978 #ifdef SIGVTALRM
979 { SIGVTALRM, "VTALRM" },
980 #endif
981 #ifdef SIGPROF
982 { SIGPROF, "PROF" },
983 #endif
984 #ifdef SIGWINCH
985 { SIGWINCH, "WINCH" },
986 #endif
987 #ifdef SIGIO
988 { SIGIO, "IO" },
989 #endif
990 #ifdef SIGPOLL
991 { SIGPOLL, "POLL" },
992 #endif
993 #ifdef SIGINFO
994 { SIGINFO, "INFO" },
995 #endif
996 #ifdef SIGLOST
997 { SIGLOST, "LOST" },
998 #endif
999 #ifdef SIGPWR
1000 { SIGPWR, "PWR" },
1001 #endif
1002 #ifdef SIGUNUSED
1003 { SIGUNUSED, "UNUSED" },
1004 #endif
1005 #ifdef SIGSYS
1006 { SIGSYS, "SYS" },
1007 #endif
1008 };
1009
1010 static int sig_num(const char *sig)
1011 {
1012 int ret;
1013 unsigned int signum;
1014
1015 ret = lxc_safe_uint(sig, &signum);
1016 if (ret < 0)
1017 return ret;
1018
1019 return signum;
1020 }
1021
1022 static int rt_sig_num(const char *signame)
1023 {
1024 int rtmax = 0, sig_n = 0;
1025
1026 if (strncasecmp(signame, "max-", 4) == 0)
1027 rtmax = 1;
1028
1029 signame += 4;
1030 if (!isdigit(*signame))
1031 return ret_errno(EINVAL);
1032
1033 sig_n = sig_num(signame);
1034 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
1035 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
1036 return ret_errno(EINVAL);
1037
1038 return sig_n;
1039 }
1040
1041 int sig_parse(const char *signame)
1042 {
1043 size_t n;
1044
1045 if (isdigit(*signame)) {
1046 return sig_num(signame);
1047 } else if (strncasecmp(signame, "sig", 3) == 0) {
1048 signame += 3;
1049 if (strncasecmp(signame, "rt", 2) == 0)
1050 return rt_sig_num(signame + 2);
1051
1052 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++)
1053 if (strcasecmp(signames[n].name, signame) == 0)
1054 return signames[n].num;
1055 }
1056
1057 return -1;
1058 }