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