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