]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/confile_utils.c
pam_cgfs: remove dependency from cap & log
[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_VLAN:
303 TRACE("type: vlan");
304 TRACE("vlan id: %d", netdev->priv.vlan_attr.vid);
305 break;
306 case LXC_NET_PHYS:
307 TRACE("type: phys");
308
309 if (netdev->priv.phys_attr.ifindex > 0)
310 TRACE("host side ifindex for phys device: %d",
311 netdev->priv.phys_attr.ifindex);
312 break;
313 case LXC_NET_EMPTY:
314 TRACE("type: empty");
315 break;
316 case LXC_NET_NONE:
317 TRACE("type: none");
318 break;
319 default:
320 ERROR("invalid network type %d", netdev->type);
321 return;
322 }
323
324 if (netdev->type != LXC_NET_EMPTY) {
325 TRACE("flags: %s",
326 netdev->flags == IFF_UP ? "up" : "none");
327
328 if (netdev->link[0] != '\0')
329 TRACE("link: %s", netdev->link);
330
331 if (netdev->name[0] != '\0')
332 TRACE("name: %s", netdev->name);
333
334 if (netdev->hwaddr)
335 TRACE("hwaddr: %s", netdev->hwaddr);
336
337 if (netdev->mtu)
338 TRACE("mtu: %s", netdev->mtu);
339
340 if (netdev->upscript)
341 TRACE("upscript: %s", netdev->upscript);
342
343 if (netdev->downscript)
344 TRACE("downscript: %s", netdev->downscript);
345
346 TRACE("ipv4 gateway auto: %s",
347 netdev->ipv4_gateway_auto ? "true" : "false");
348
349 if (netdev->ipv4_gateway) {
350 inet_ntop(AF_INET, netdev->ipv4_gateway,
351 bufinet4, sizeof(bufinet4));
352 TRACE("ipv4 gateway: %s", bufinet4);
353 }
354
355 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
356 inet4dev = cur->elem;
357 inet_ntop(AF_INET, &inet4dev->addr, bufinet4,
358 sizeof(bufinet4));
359 TRACE("ipv4 addr: %s", bufinet4);
360 }
361
362 TRACE("ipv6 gateway auto: %s",
363 netdev->ipv6_gateway_auto ? "true" : "false");
364
365 if (netdev->ipv6_gateway) {
366 inet_ntop(AF_INET6, netdev->ipv6_gateway,
367 bufinet6, sizeof(bufinet6));
368 TRACE("ipv6 gateway: %s", bufinet6);
369 }
370
371 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
372 inet6dev = cur->elem;
373 inet_ntop(AF_INET6, &inet6dev->addr, bufinet6,
374 sizeof(bufinet6));
375 TRACE("ipv6 addr: %s", bufinet6);
376 }
377 }
378 }
379 }
380
381 static void lxc_free_netdev(struct lxc_netdev *netdev)
382 {
383 struct lxc_list *cur, *next;
384
385 free(netdev->upscript);
386 free(netdev->downscript);
387 free(netdev->hwaddr);
388 free(netdev->mtu);
389
390 free(netdev->ipv4_gateway);
391 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
392 lxc_list_del(cur);
393 free(cur->elem);
394 free(cur);
395 }
396
397 free(netdev->ipv6_gateway);
398 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
399 lxc_list_del(cur);
400 free(cur->elem);
401 free(cur);
402 }
403
404 free(netdev);
405 }
406
407 bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx)
408 {
409 struct lxc_list *cur, *next;
410 struct lxc_netdev *netdev;
411 bool found = false;
412
413 lxc_list_for_each_safe(cur, &conf->network, next) {
414 netdev = cur->elem;
415 if (netdev->idx != idx)
416 continue;
417
418 lxc_list_del(cur);
419 found = true;
420 break;
421 }
422
423 if (!found)
424 return false;
425
426 lxc_free_netdev(netdev);
427 free(cur);
428
429 return true;
430 }
431
432 void lxc_free_networks(struct lxc_list *networks)
433 {
434 struct lxc_list *cur, *next;
435 struct lxc_netdev *netdev;
436
437 lxc_list_for_each_safe(cur, networks, next) {
438 netdev = cur->elem;
439 lxc_free_netdev(netdev);
440 free(cur);
441 }
442
443 /* prevent segfaults */
444 lxc_list_init(networks);
445 }
446
447 static struct lxc_macvlan_mode {
448 char *name;
449 int mode;
450 } macvlan_mode[] = {
451 { "private", MACVLAN_MODE_PRIVATE },
452 { "vepa", MACVLAN_MODE_VEPA },
453 { "bridge", MACVLAN_MODE_BRIDGE },
454 { "passthru", MACVLAN_MODE_PASSTHRU },
455 };
456
457 int lxc_macvlan_mode_to_flag(int *mode, const char *value)
458 {
459 size_t i;
460
461 for (i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
462 if (strcmp(macvlan_mode[i].name, value))
463 continue;
464
465 *mode = macvlan_mode[i].mode;
466 return 0;
467 }
468
469 return -1;
470 }
471
472 char *lxc_macvlan_flag_to_mode(int mode)
473 {
474 size_t i;
475
476 for (i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
477 if (macvlan_mode[i].mode == mode)
478 continue;
479
480 return macvlan_mode[i].name;
481 }
482
483 return NULL;
484 }
485
486 int set_config_string_item(char **conf_item, const char *value)
487 {
488 char *new_value;
489
490 if (lxc_config_value_empty(value)) {
491 free(*conf_item);
492 *conf_item = NULL;
493 return 0;
494 }
495
496 new_value = strdup(value);
497 if (!new_value) {
498 SYSERROR("Failed to duplicate string \"%s\"", value);
499 return -1;
500 }
501
502 free(*conf_item);
503 *conf_item = new_value;
504 return 0;
505 }
506
507 int set_config_string_item_max(char **conf_item, const char *value, size_t max)
508 {
509 if (strlen(value) >= max) {
510 ERROR("%s is too long (>= %lu)", value, (unsigned long)max);
511 return -1;
512 }
513
514 return set_config_string_item(conf_item, value);
515 }
516
517 int set_config_path_item(char **conf_item, const char *value)
518 {
519 return set_config_string_item_max(conf_item, value, PATH_MAX);
520 }
521
522 int config_ip_prefix(struct in_addr *addr)
523 {
524 if (IN_CLASSA(addr->s_addr))
525 return 32 - IN_CLASSA_NSHIFT;
526
527 if (IN_CLASSB(addr->s_addr))
528 return 32 - IN_CLASSB_NSHIFT;
529
530 if (IN_CLASSC(addr->s_addr))
531 return 32 - IN_CLASSC_NSHIFT;
532
533 return 0;
534 }
535
536 int network_ifname(char *valuep, const char *value, size_t size)
537 {
538 size_t retlen;
539
540 if (!valuep || !value)
541 return -1;
542
543 retlen = strlcpy(valuep, value, size);
544 if (retlen >= size)
545 ERROR("Network device name \"%s\" is too long (>= %zu)", value,
546 size);
547
548 return 0;
549 }
550
551 void rand_complete_hwaddr(char *hwaddr)
552 {
553 const char hex[] = "0123456789abcdef";
554 char *curs = hwaddr;
555 #ifdef HAVE_RAND_R
556 unsigned int seed;
557
558 seed = randseed(false);
559 #else
560
561 (void)randseed(true);
562 #endif
563
564 while (*curs != '\0' && *curs != '\n') {
565 if (*curs == 'x' || *curs == 'X') {
566 if (curs - hwaddr == 1) {
567 /* ensure address is unicast */
568 #ifdef HAVE_RAND_R
569 *curs = hex[rand_r(&seed) & 0x0E];
570 } else {
571 *curs = hex[rand_r(&seed) & 0x0F];
572 #else
573 *curs = hex[rand() & 0x0E];
574 } else {
575 *curs = hex[rand() & 0x0F];
576 #endif
577 }
578 }
579 curs++;
580 }
581 }
582
583 bool lxc_config_net_hwaddr(const char *line)
584 {
585 unsigned index;
586 char tmp[7];
587
588 if (strncmp(line, "lxc.net", 7) != 0)
589 return false;
590
591 if (strncmp(line, "lxc.net.hwaddr", 14) == 0)
592 return true;
593
594 if (strncmp(line, "lxc.network.hwaddr", 18) == 0)
595 return true;
596
597 if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 ||
598 sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
599 return strncmp(tmp, "hwaddr", 6) == 0;
600
601 return false;
602 }
603
604 /*
605 * If we find a lxc.net.[i].hwaddr or lxc.network.hwaddr in the original config
606 * file, we expand it in the unexpanded_config, so that after a save_config we
607 * store the hwaddr for re-use.
608 * This is only called when reading the config file, not when executing a
609 * lxc.include.
610 * 'x' and 'X' are substituted in-place.
611 */
612 void update_hwaddr(const char *line)
613 {
614 char *p;
615
616 line += lxc_char_left_gc(line, strlen(line));
617 if (line[0] == '#')
618 return;
619
620 if (!lxc_config_net_hwaddr(line))
621 return;
622
623 /* Let config_net_hwaddr raise the error. */
624 p = strchr(line, '=');
625 if (!p)
626 return;
627 p++;
628
629 while (isblank(*p))
630 p++;
631
632 if (!*p)
633 return;
634
635 rand_complete_hwaddr(p);
636 }
637
638 bool new_hwaddr(char *hwaddr)
639 {
640 int ret;
641 #ifdef HAVE_RAND_R
642 unsigned int seed;
643
644 seed = randseed(false);
645
646 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand_r(&seed) % 255,
647 rand_r(&seed) % 255, rand_r(&seed) % 255);
648 #else
649
650 (void)randseed(true);
651
652 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
653 rand() % 255, rand() % 255);
654 #endif
655 if (ret < 0 || ret >= 18) {
656 SYSERROR("Failed to call snprintf()");
657 return false;
658 }
659
660 return true;
661 }
662
663 int lxc_get_conf_str(char *retv, int inlen, const char *value)
664 {
665 size_t value_len;
666
667 if (!value)
668 return 0;
669
670 value_len = strlen(value);
671 if (retv && inlen >= value_len + 1)
672 memcpy(retv, value, value_len + 1);
673
674 return value_len;
675 }
676
677 int lxc_get_conf_bool(struct lxc_conf *c, char *retv, int inlen, bool v)
678 {
679 int len;
680 int fulllen = 0;
681
682 if (!retv)
683 inlen = 0;
684 else
685 memset(retv, 0, inlen);
686
687 strprint(retv, inlen, "%d", v);
688
689 return fulllen;
690 }
691
692 int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
693 {
694 int len;
695 int fulllen = 0;
696
697 if (!retv)
698 inlen = 0;
699 else
700 memset(retv, 0, inlen);
701
702 strprint(retv, inlen, "%d", v);
703
704 return fulllen;
705 }
706
707 int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
708 {
709 int len;
710 int fulllen = 0;
711
712 if (!retv)
713 inlen = 0;
714 else
715 memset(retv, 0, inlen);
716
717 strprint(retv, inlen, "%zu", v);
718
719 return fulllen;
720 }
721
722 int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
723 {
724 int len;
725 int fulllen = 0;
726
727 if (!retv)
728 inlen = 0;
729 else
730 memset(retv, 0, inlen);
731
732 strprint(retv, inlen, "%"PRIu64, v);
733
734 return fulllen;
735 }
736
737 bool parse_limit_value(const char **value, rlim_t *res)
738 {
739 char *endptr = NULL;
740
741 if (strncmp(*value, "unlimited", STRLITERALLEN("unlimited")) == 0) {
742 *res = RLIM_INFINITY;
743 *value += STRLITERALLEN("unlimited");
744 return true;
745 }
746
747 errno = 0;
748 *res = strtoull(*value, &endptr, 10);
749 if (errno || !endptr)
750 return false;
751
752 *value = endptr;
753
754 return true;
755 }
756
757 static int lxc_container_name_to_pid(const char *lxcname_or_pid,
758 const char *lxcpath)
759 {
760 int ret;
761 signed long int pid;
762 char *err = NULL;
763
764 pid = strtol(lxcname_or_pid, &err, 10);
765 if (*err != '\0' || pid < 1) {
766 struct lxc_container *c;
767
768 c = lxc_container_new(lxcname_or_pid, lxcpath);
769 if (!c) {
770 ERROR("\"%s\" is not a valid pid nor a container name",
771 lxcname_or_pid);
772 return -1;
773 }
774
775 if (!c->may_control(c)) {
776 ERROR("Insufficient privileges to control container "
777 "\"%s\"", c->name);
778 lxc_container_put(c);
779 return -1;
780 }
781
782 pid = c->init_pid(c);
783 if (pid < 1) {
784 ERROR("Container \"%s\" is not running", c->name);
785 lxc_container_put(c);
786 return -1;
787 }
788
789 lxc_container_put(c);
790 }
791
792 ret = kill(pid, 0);
793 if (ret < 0) {
794 SYSERROR("Failed to send signal to pid %d", (int)pid);
795 return -1;
796 }
797
798 return pid;
799 }
800
801 int lxc_inherit_namespace(const char *lxcname_or_pid, const char *lxcpath,
802 const char *namespace)
803 {
804 int fd, pid;
805 char *dup, *lastslash;
806
807 lastslash = strrchr(lxcname_or_pid, '/');
808 if (lastslash) {
809 dup = strdup(lxcname_or_pid);
810 if (!dup)
811 return -1;
812
813 dup[lastslash - lxcname_or_pid] = '\0';
814 pid = lxc_container_name_to_pid(lastslash + 1, dup);
815 free(dup);
816 } else {
817 pid = lxc_container_name_to_pid(lxcname_or_pid, lxcpath);
818 }
819
820 if (pid < 0)
821 return -1;
822
823 fd = lxc_preserve_ns(pid, namespace);
824 if (fd < 0)
825 return -1;
826
827 return fd;
828 }
829
830 struct signame {
831 int num;
832 const char *name;
833 };
834
835 static const struct signame signames[] = {
836 { SIGHUP, "HUP" },
837 { SIGINT, "INT" },
838 { SIGQUIT, "QUIT" },
839 { SIGILL, "ILL" },
840 { SIGABRT, "ABRT" },
841 { SIGFPE, "FPE" },
842 { SIGKILL, "KILL" },
843 { SIGSEGV, "SEGV" },
844 { SIGPIPE, "PIPE" },
845 { SIGALRM, "ALRM" },
846 { SIGTERM, "TERM" },
847 { SIGUSR1, "USR1" },
848 { SIGUSR2, "USR2" },
849 { SIGCHLD, "CHLD" },
850 { SIGCONT, "CONT" },
851 { SIGSTOP, "STOP" },
852 { SIGTSTP, "TSTP" },
853 { SIGTTIN, "TTIN" },
854 { SIGTTOU, "TTOU" },
855 #ifdef SIGTRAP
856 { SIGTRAP, "TRAP" },
857 #endif
858 #ifdef SIGIOT
859 { SIGIOT, "IOT" },
860 #endif
861 #ifdef SIGEMT
862 { SIGEMT, "EMT" },
863 #endif
864 #ifdef SIGBUS
865 { SIGBUS, "BUS" },
866 #endif
867 #ifdef SIGSTKFLT
868 { SIGSTKFLT, "STKFLT" },
869 #endif
870 #ifdef SIGCLD
871 { SIGCLD, "CLD" },
872 #endif
873 #ifdef SIGURG
874 { SIGURG, "URG" },
875 #endif
876 #ifdef SIGXCPU
877 { SIGXCPU, "XCPU" },
878 #endif
879 #ifdef SIGXFSZ
880 { SIGXFSZ, "XFSZ" },
881 #endif
882 #ifdef SIGVTALRM
883 { SIGVTALRM, "VTALRM" },
884 #endif
885 #ifdef SIGPROF
886 { SIGPROF, "PROF" },
887 #endif
888 #ifdef SIGWINCH
889 { SIGWINCH, "WINCH" },
890 #endif
891 #ifdef SIGIO
892 { SIGIO, "IO" },
893 #endif
894 #ifdef SIGPOLL
895 { SIGPOLL, "POLL" },
896 #endif
897 #ifdef SIGINFO
898 { SIGINFO, "INFO" },
899 #endif
900 #ifdef SIGLOST
901 { SIGLOST, "LOST" },
902 #endif
903 #ifdef SIGPWR
904 { SIGPWR, "PWR" },
905 #endif
906 #ifdef SIGUNUSED
907 { SIGUNUSED, "UNUSED" },
908 #endif
909 #ifdef SIGSYS
910 { SIGSYS, "SYS" },
911 #endif
912 };
913
914 static int sig_num(const char *sig)
915 {
916 unsigned int signum;
917
918 if (lxc_safe_uint(sig, &signum) < 0)
919 return -1;
920
921 return signum;
922 }
923
924 static int rt_sig_num(const char *signame)
925 {
926 int rtmax = 0, sig_n = 0;
927
928 if (strncasecmp(signame, "max-", 4) == 0)
929 rtmax = 1;
930
931 signame += 4;
932 if (!isdigit(*signame))
933 return -1;
934
935 sig_n = sig_num(signame);
936 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
937 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
938 return -1;
939
940 return sig_n;
941 }
942
943 int sig_parse(const char *signame)
944 {
945 size_t n;
946
947 if (isdigit(*signame)) {
948 return sig_num(signame);
949 } else if (strncasecmp(signame, "sig", 3) == 0) {
950 signame += 3;
951 if (strncasecmp(signame, "rt", 2) == 0)
952 return rt_sig_num(signame + 2);
953
954 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++)
955 if (strcasecmp(signames[n].name, signame) == 0)
956 return signames[n].num;
957 }
958
959 return -1;
960 }