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