]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/confile_utils.c
conf: introduce lxc.rootfs.managed
[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 #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_bool(struct lxc_conf *c, char *retv, int inlen, bool 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_int(struct lxc_conf *c, char *retv, int inlen, int 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, "%d", v);
701
702 return fulllen;
703 }
704
705 int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_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, "%zu", v);
716
717 return fulllen;
718 }
719
720 int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
721 {
722 int len;
723 int fulllen = 0;
724
725 if (!retv)
726 inlen = 0;
727 else
728 memset(retv, 0, inlen);
729
730 strprint(retv, inlen, "%"PRIu64, v);
731
732 return fulllen;
733 }
734
735 bool parse_limit_value(const char **value, rlim_t *res)
736 {
737 char *endptr = NULL;
738
739 if (strncmp(*value, "unlimited", sizeof("unlimited") - 1) == 0) {
740 *res = RLIM_INFINITY;
741 *value += sizeof("unlimited") - 1;
742 return true;
743 }
744
745 errno = 0;
746 *res = strtoull(*value, &endptr, 10);
747 if (errno || !endptr)
748 return false;
749
750 *value = endptr;
751
752 return true;
753 }
754
755 static int lxc_container_name_to_pid(const char *lxcname_or_pid,
756 const char *lxcpath)
757 {
758 int ret;
759 signed long int pid;
760 char *err = NULL;
761
762 pid = strtol(lxcname_or_pid, &err, 10);
763 if (*err != '\0' || pid < 1) {
764 struct lxc_container *c;
765
766 c = lxc_container_new(lxcname_or_pid, lxcpath);
767 if (!c) {
768 ERROR("\"%s\" is not a valid pid nor a container name",
769 lxcname_or_pid);
770 return -1;
771 }
772
773 if (!c->may_control(c)) {
774 ERROR("Insufficient privileges to control container "
775 "\"%s\"", c->name);
776 lxc_container_put(c);
777 return -1;
778 }
779
780 pid = c->init_pid(c);
781 if (pid < 1) {
782 ERROR("Container \"%s\" is not running", c->name);
783 lxc_container_put(c);
784 return -1;
785 }
786
787 lxc_container_put(c);
788 }
789
790 ret = kill(pid, 0);
791 if (ret < 0) {
792 SYSERROR("Failed to send signal to pid %d", (int)pid);
793 return -1;
794 }
795
796 return pid;
797 }
798
799 int lxc_inherit_namespace(const char *lxcname_or_pid, const char *lxcpath,
800 const char *namespace)
801 {
802 int fd, pid;
803 char *dup, *lastslash;
804
805 lastslash = strrchr(lxcname_or_pid, '/');
806 if (lastslash) {
807 dup = strdup(lxcname_or_pid);
808 if (!dup)
809 return -1;
810
811 dup[lastslash - lxcname_or_pid] = '\0';
812 pid = lxc_container_name_to_pid(lastslash + 1, dup);
813 free(dup);
814 } else {
815 pid = lxc_container_name_to_pid(lxcname_or_pid, lxcpath);
816 }
817
818 if (pid < 0)
819 return -1;
820
821 fd = lxc_preserve_ns(pid, namespace);
822 if (fd < 0)
823 return -1;
824
825 return fd;
826 }
827
828 struct signame {
829 int num;
830 const char *name;
831 };
832
833 static const struct signame signames[] = {
834 { SIGHUP, "HUP" },
835 { SIGINT, "INT" },
836 { SIGQUIT, "QUIT" },
837 { SIGILL, "ILL" },
838 { SIGABRT, "ABRT" },
839 { SIGFPE, "FPE" },
840 { SIGKILL, "KILL" },
841 { SIGSEGV, "SEGV" },
842 { SIGPIPE, "PIPE" },
843 { SIGALRM, "ALRM" },
844 { SIGTERM, "TERM" },
845 { SIGUSR1, "USR1" },
846 { SIGUSR2, "USR2" },
847 { SIGCHLD, "CHLD" },
848 { SIGCONT, "CONT" },
849 { SIGSTOP, "STOP" },
850 { SIGTSTP, "TSTP" },
851 { SIGTTIN, "TTIN" },
852 { SIGTTOU, "TTOU" },
853 #ifdef SIGTRAP
854 { SIGTRAP, "TRAP" },
855 #endif
856 #ifdef SIGIOT
857 { SIGIOT, "IOT" },
858 #endif
859 #ifdef SIGEMT
860 { SIGEMT, "EMT" },
861 #endif
862 #ifdef SIGBUS
863 { SIGBUS, "BUS" },
864 #endif
865 #ifdef SIGSTKFLT
866 { SIGSTKFLT, "STKFLT" },
867 #endif
868 #ifdef SIGCLD
869 { SIGCLD, "CLD" },
870 #endif
871 #ifdef SIGURG
872 { SIGURG, "URG" },
873 #endif
874 #ifdef SIGXCPU
875 { SIGXCPU, "XCPU" },
876 #endif
877 #ifdef SIGXFSZ
878 { SIGXFSZ, "XFSZ" },
879 #endif
880 #ifdef SIGVTALRM
881 { SIGVTALRM, "VTALRM" },
882 #endif
883 #ifdef SIGPROF
884 { SIGPROF, "PROF" },
885 #endif
886 #ifdef SIGWINCH
887 { SIGWINCH, "WINCH" },
888 #endif
889 #ifdef SIGIO
890 { SIGIO, "IO" },
891 #endif
892 #ifdef SIGPOLL
893 { SIGPOLL, "POLL" },
894 #endif
895 #ifdef SIGINFO
896 { SIGINFO, "INFO" },
897 #endif
898 #ifdef SIGLOST
899 { SIGLOST, "LOST" },
900 #endif
901 #ifdef SIGPWR
902 { SIGPWR, "PWR" },
903 #endif
904 #ifdef SIGUNUSED
905 { SIGUNUSED, "UNUSED" },
906 #endif
907 #ifdef SIGSYS
908 { SIGSYS, "SYS" },
909 #endif
910 };
911
912 static int sig_num(const char *sig)
913 {
914 unsigned int signum;
915
916 if (lxc_safe_uint(sig, &signum) < 0)
917 return -1;
918
919 return signum;
920 }
921
922 static int rt_sig_num(const char *signame)
923 {
924 int rtmax = 0, sig_n = 0;
925
926 if (strncasecmp(signame, "max-", 4) == 0)
927 rtmax = 1;
928
929 signame += 4;
930 if (!isdigit(*signame))
931 return -1;
932
933 sig_n = sig_num(signame);
934 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
935 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
936 return -1;
937
938 return sig_n;
939 }
940
941 int sig_parse(const char *signame)
942 {
943 size_t n;
944
945 if (isdigit(*signame)) {
946 return sig_num(signame);
947 } else if (strncasecmp(signame, "sig", 3) == 0) {
948 signame += 3;
949 if (strncasecmp(signame, "rt", 2) == 0)
950 return rt_sig_num(signame + 2);
951
952 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++)
953 if (strcasecmp(signames[n].name, signame) == 0)
954 return signames[n].num;
955 }
956
957 return -1;
958 }