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