]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/confile_utils.c
confile_utils: fix return value & cleanups
[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
153 /* Mark end of range. */
154 *slide = '\0';
155
156 /* Parse range. */
157 if (lxc_safe_ulong(window, &tmp_range) < 0) {
158 ERROR("Failed to parse id mapping range: %s", window);
159 goto on_error;
160 }
161
162 *type = tmp_type;
163 *nsid = tmp_nsid;
164 *hostid = tmp_hostid;
165 *range = tmp_range;
166
167 /* Yay, we survived. */
168 ret = 0;
169
170 on_error:
171 free(dup);
172
173 return ret;
174 }
175
176 bool lxc_config_value_empty(const char *value)
177 {
178 if (value && strlen(value) > 0)
179 return false;
180
181 return true;
182 }
183
184 struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail)
185 {
186 struct lxc_list *newlist;
187 struct lxc_netdev *netdev = NULL;
188
189 /* network does not exist */
190 netdev = malloc(sizeof(*netdev));
191 if (!netdev)
192 return NULL;
193
194 memset(netdev, 0, sizeof(*netdev));
195 lxc_list_init(&netdev->ipv4);
196 lxc_list_init(&netdev->ipv6);
197
198 /* give network a unique index */
199 netdev->idx = idx;
200
201 /* prepare new list */
202 newlist = malloc(sizeof(*newlist));
203 if (!newlist) {
204 free(netdev);
205 return NULL;
206 }
207
208 lxc_list_init(newlist);
209 newlist->elem = netdev;
210
211 if (tail)
212 lxc_list_add_tail(networks, newlist);
213 else
214 lxc_list_add(networks, newlist);
215
216 return netdev;
217 }
218
219 /* Takes care of finding the correct netdev struct in the networks list or
220 * allocates a new one if it couldn't be found.
221 */
222 struct lxc_netdev *lxc_get_netdev_by_idx(struct lxc_conf *conf,
223 unsigned int idx, bool allocate)
224 {
225 struct lxc_netdev *netdev = NULL;
226 struct lxc_list *networks = &conf->network;
227 struct lxc_list *insert = networks;
228
229 /* lookup network */
230 if (!lxc_list_empty(networks)) {
231 lxc_list_for_each(insert, networks) {
232 netdev = insert->elem;
233 if (netdev->idx == idx)
234 return netdev;
235 else if (netdev->idx > idx)
236 break;
237 }
238 }
239
240 if (!allocate)
241 return NULL;
242
243 return lxc_network_add(insert, idx, true);
244 }
245
246 void lxc_log_configured_netdevs(const struct lxc_conf *conf)
247 {
248 struct lxc_netdev *netdev;
249 struct lxc_list *it = (struct lxc_list *)&conf->network;;
250
251 if ((conf->loglevel != LXC_LOG_LEVEL_TRACE) &&
252 (lxc_log_get_level() != LXC_LOG_LEVEL_TRACE))
253 return;
254
255 if (lxc_list_empty(it)) {
256 TRACE("container has no networks configured");
257 return;
258 }
259
260 lxc_list_for_each(it, &conf->network) {
261 struct lxc_list *cur, *next;
262 struct lxc_inetdev *inet4dev;
263 struct lxc_inet6dev *inet6dev;
264 char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN];
265
266 netdev = it->elem;
267
268 TRACE("index: %zd", netdev->idx);
269 TRACE("ifindex: %d", netdev->ifindex);
270
271 switch (netdev->type) {
272 case LXC_NET_VETH:
273 TRACE("type: veth");
274
275 if (netdev->priv.veth_attr.pair[0] != '\0')
276 TRACE("veth pair: %s",
277 netdev->priv.veth_attr.pair);
278
279 if (netdev->priv.veth_attr.veth1[0] != '\0')
280 TRACE("veth1 : %s",
281 netdev->priv.veth_attr.veth1);
282
283 if (netdev->priv.veth_attr.ifindex > 0)
284 TRACE("host side ifindex for veth device: %d",
285 netdev->priv.veth_attr.ifindex);
286 break;
287 case LXC_NET_MACVLAN:
288 TRACE("type: macvlan");
289
290 if (netdev->priv.macvlan_attr.mode > 0) {
291 char *macvlan_mode;
292
293 macvlan_mode = lxc_macvlan_flag_to_mode(
294 netdev->priv.macvlan_attr.mode);
295 TRACE("macvlan mode: %s",
296 macvlan_mode ? macvlan_mode
297 : "(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 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
554 #ifndef HAVE_RAND_R
555 randseed(true);
556 #else
557 unsigned int seed;
558
559 seed = randseed(false);
560 #endif
561 while (*curs != '\0' && *curs != '\n') {
562 if (*curs == 'x' || *curs == 'X') {
563 if (curs - hwaddr == 1) {
564 /* ensure address is unicast */
565 #ifdef HAVE_RAND_R
566 *curs = hex[rand_r(&seed) & 0x0E];
567 } else {
568 *curs = hex[rand_r(&seed) & 0x0F];
569 #else
570 *curs = hex[rand() & 0x0E];
571 } else {
572 *curs = hex[rand() & 0x0F];
573 #endif
574 }
575 }
576 curs++;
577 }
578 }
579
580 bool lxc_config_net_hwaddr(const char *line)
581 {
582 unsigned index;
583 char tmp[7];
584
585 if (strncmp(line, "lxc.net", 7) != 0)
586 return false;
587
588 if (strncmp(line, "lxc.net.hwaddr", 14) == 0)
589 return true;
590
591 if (strncmp(line, "lxc.network.hwaddr", 18) == 0)
592 return true;
593
594 if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 ||
595 sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
596 return strncmp(tmp, "hwaddr", 6) == 0;
597
598 return false;
599 }
600
601 /*
602 * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
603 * file, we expand it in the unexpanded_config, so that after a save_config we
604 * store the hwaddr for re-use.
605 * This is only called when reading the config file, not when executing a
606 * lxc.include.
607 * 'x' and 'X' are substituted in-place.
608 */
609 void update_hwaddr(const char *line)
610 {
611 char *p;
612
613 line += lxc_char_left_gc(line, strlen(line));
614 if (line[0] == '#')
615 return;
616
617 if (!lxc_config_net_hwaddr(line))
618 return;
619
620 /* Let config_net_hwaddr raise the error. */
621 p = strchr(line, '=');
622 if (!p)
623 return;
624 p++;
625
626 while (isblank(*p))
627 p++;
628
629 if (!*p)
630 return;
631
632 rand_complete_hwaddr(p);
633 }
634
635 bool new_hwaddr(char *hwaddr)
636 {
637 int ret;
638
639 (void)randseed(true);
640
641 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
642 rand() % 255, rand() % 255);
643 if (ret < 0 || ret >= 18) {
644 SYSERROR("Failed to call snprintf().");
645 return false;
646 }
647
648 return true;
649 }
650
651 int lxc_get_conf_str(char *retv, int inlen, const char *value)
652 {
653 size_t value_len;
654
655 if (!value)
656 return 0;
657
658 value_len = strlen(value);
659 if (retv && inlen >= value_len + 1)
660 memcpy(retv, value, value_len + 1);
661
662 return value_len;
663 }
664
665 int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
666 {
667 int len;
668 int fulllen = 0;
669
670 if (!retv)
671 inlen = 0;
672 else
673 memset(retv, 0, inlen);
674
675 strprint(retv, inlen, "%d", v);
676
677 return fulllen;
678 }
679
680 int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
681 {
682 int len;
683 int fulllen = 0;
684
685 if (!retv)
686 inlen = 0;
687 else
688 memset(retv, 0, inlen);
689
690 strprint(retv, inlen, "%zu", v);
691
692 return fulllen;
693 }
694
695 int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
696 {
697 int len;
698 int fulllen = 0;
699
700 if (!retv)
701 inlen = 0;
702 else
703 memset(retv, 0, inlen);
704
705 strprint(retv, inlen, "%"PRIu64, v);
706
707 return fulllen;
708 }
709
710 bool parse_limit_value(const char **value, rlim_t *res)
711 {
712 char *endptr = NULL;
713
714 if (strncmp(*value, "unlimited", sizeof("unlimited") - 1) == 0) {
715 *res = RLIM_INFINITY;
716 *value += sizeof("unlimited") - 1;
717 return true;
718 }
719
720 errno = 0;
721 *res = strtoull(*value, &endptr, 10);
722 if (errno || !endptr)
723 return false;
724
725 *value = endptr;
726
727 return true;
728 }
729
730 static int lxc_container_name_to_pid(const char *lxcname_or_pid,
731 const char *lxcpath)
732 {
733 int ret;
734 signed long int pid;
735 char *err = NULL;
736
737 pid = strtol(lxcname_or_pid, &err, 10);
738 if (*err != '\0' || pid < 1) {
739 struct lxc_container *c;
740
741 c = lxc_container_new(lxcname_or_pid, lxcpath);
742 if (!c) {
743 ERROR("\"%s\" is not a valid pid nor a container name",
744 lxcname_or_pid);
745 return -1;
746 }
747
748 if (!c->may_control(c)) {
749 ERROR("Insufficient privileges to control container "
750 "\"%s\"", c->name);
751 lxc_container_put(c);
752 return -1;
753 }
754
755 pid = c->init_pid(c);
756 if (pid < 1) {
757 ERROR("Container \"%s\" is not running", c->name);
758 lxc_container_put(c);
759 return -1;
760 }
761
762 lxc_container_put(c);
763 }
764
765 ret = kill(pid, 0);
766 if (ret < 0) {
767 SYSERROR("Failed to send signal to pid %d", (int)pid);
768 return -1;
769 }
770
771 return pid;
772 }
773
774 int lxc_inherit_namespace(const char *lxcname_or_pid, const char *lxcpath,
775 const char *namespace)
776 {
777 int fd, pid;
778 char *dup, *lastslash;
779
780 lastslash = strrchr(lxcname_or_pid, '/');
781 if (lastslash) {
782 dup = strdup(lxcname_or_pid);
783 if (!dup)
784 return -1;
785
786 dup[lastslash - lxcname_or_pid] = '\0';
787 pid = lxc_container_name_to_pid(lastslash + 1, dup);
788 free(dup);
789 } else {
790 pid = lxc_container_name_to_pid(lxcname_or_pid, lxcpath);
791 }
792
793 if (pid < 0)
794 return -1;
795
796 fd = lxc_preserve_ns(pid, namespace);
797 if (fd < 0)
798 return -1;
799
800 return fd;
801 }
802
803 struct signame {
804 int num;
805 const char *name;
806 };
807
808 static const struct signame signames[] = {
809 { SIGHUP, "HUP" },
810 { SIGINT, "INT" },
811 { SIGQUIT, "QUIT" },
812 { SIGILL, "ILL" },
813 { SIGABRT, "ABRT" },
814 { SIGFPE, "FPE" },
815 { SIGKILL, "KILL" },
816 { SIGSEGV, "SEGV" },
817 { SIGPIPE, "PIPE" },
818 { SIGALRM, "ALRM" },
819 { SIGTERM, "TERM" },
820 { SIGUSR1, "USR1" },
821 { SIGUSR2, "USR2" },
822 { SIGCHLD, "CHLD" },
823 { SIGCONT, "CONT" },
824 { SIGSTOP, "STOP" },
825 { SIGTSTP, "TSTP" },
826 { SIGTTIN, "TTIN" },
827 { SIGTTOU, "TTOU" },
828 #ifdef SIGTRAP
829 { SIGTRAP, "TRAP" },
830 #endif
831 #ifdef SIGIOT
832 { SIGIOT, "IOT" },
833 #endif
834 #ifdef SIGEMT
835 { SIGEMT, "EMT" },
836 #endif
837 #ifdef SIGBUS
838 { SIGBUS, "BUS" },
839 #endif
840 #ifdef SIGSTKFLT
841 { SIGSTKFLT, "STKFLT" },
842 #endif
843 #ifdef SIGCLD
844 { SIGCLD, "CLD" },
845 #endif
846 #ifdef SIGURG
847 { SIGURG, "URG" },
848 #endif
849 #ifdef SIGXCPU
850 { SIGXCPU, "XCPU" },
851 #endif
852 #ifdef SIGXFSZ
853 { SIGXFSZ, "XFSZ" },
854 #endif
855 #ifdef SIGVTALRM
856 { SIGVTALRM, "VTALRM" },
857 #endif
858 #ifdef SIGPROF
859 { SIGPROF, "PROF" },
860 #endif
861 #ifdef SIGWINCH
862 { SIGWINCH, "WINCH" },
863 #endif
864 #ifdef SIGIO
865 { SIGIO, "IO" },
866 #endif
867 #ifdef SIGPOLL
868 { SIGPOLL, "POLL" },
869 #endif
870 #ifdef SIGINFO
871 { SIGINFO, "INFO" },
872 #endif
873 #ifdef SIGLOST
874 { SIGLOST, "LOST" },
875 #endif
876 #ifdef SIGPWR
877 { SIGPWR, "PWR" },
878 #endif
879 #ifdef SIGUNUSED
880 { SIGUNUSED, "UNUSED" },
881 #endif
882 #ifdef SIGSYS
883 { SIGSYS, "SYS" },
884 #endif
885 };
886
887 static int sig_num(const char *sig)
888 {
889 unsigned int signum;
890
891 if (lxc_safe_uint(sig, &signum) < 0)
892 return -1;
893
894 return signum;
895 }
896
897 static int rt_sig_num(const char *signame)
898 {
899 int rtmax = 0, sig_n = 0;
900
901 if (strncasecmp(signame, "max-", 4) == 0)
902 rtmax = 1;
903
904 signame += 4;
905 if (!isdigit(*signame))
906 return -1;
907
908 sig_n = sig_num(signame);
909 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
910 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
911 return -1;
912
913 return sig_n;
914 }
915
916 int sig_parse(const char *signame)
917 {
918 size_t n;
919
920 if (isdigit(*signame)) {
921 return sig_num(signame);
922 } else if (strncasecmp(signame, "sig", 3) == 0) {
923 signame += 3;
924 if (strncasecmp(signame, "rt", 2) == 0)
925 return rt_sig_num(signame + 2);
926
927 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++)
928 if (strcasecmp(signames[n].name, signame) == 0)
929 return signames[n].num;
930 }
931
932 return -1;
933 }