]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile_utils.c
confile_utils: fix return value & cleanups
[mirror_lxc.git] / src / lxc / confile_utils.c
CommitLineData
0b843d35
CB
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
ce2f5ae8
CB
20#include "config.h"
21
f9373e40 22#include <ctype.h>
0b843d35 23#include <stdio.h>
ce2f5ae8 24#include <stdlib.h>
0b843d35 25#include <string.h>
9b0df30f 26#include <arpa/inet.h>
0b843d35 27
663e9916 28#include "conf.h"
ce2f5ae8
CB
29#include "confile.h"
30#include "confile_utils.h"
31#include "error.h"
ce2f5ae8 32#include "list.h"
28d9e29e
CB
33#include "log.h"
34#include "lxccontainer.h"
811ef482 35#include "network.h"
f9373e40 36#include "parse.h"
0b843d35
CB
37#include "utils.h"
38
18cd4b54
DJ
39#ifndef HAVE_STRLCPY
40#include "include/strlcpy.h"
41#endif
42
ac2cecc4 43lxc_log_define(confile_utils, lxc);
ce2f5ae8 44
0b843d35
CB
45int 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. */
a8b1ac78 69 if (*slide != 'u' && *slide != 'g') {
f37d1c22 70 ERROR("Invalid id mapping type: %c", *slide);
0b843d35 71 goto on_error;
a8b1ac78
TA
72 }
73
0b843d35
CB
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
f37d1c22 87 /* Mark beginning of nsid. */
0b843d35
CB
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;
f37d1c22 94 /* Mark end of nsid. */
0b843d35
CB
95 *slide = '\0';
96
f37d1c22 97 /* Parse nsid. */
a8b1ac78 98 if (lxc_safe_ulong(window, &tmp_nsid) < 0) {
f37d1c22 99 ERROR("Failed to parse nsid: %s", window);
0b843d35 100 goto on_error;
a8b1ac78 101 }
0b843d35
CB
102
103 /* Move beyond \0. */
104 slide++;
0b843d35
CB
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;
f37d1c22 120 /* Mark end of nsid. */
0b843d35
CB
121 *slide = '\0';
122
123 /* Parse hostid. */
a8b1ac78 124 if (lxc_safe_ulong(window, &tmp_hostid) < 0) {
f37d1c22 125 ERROR("Failed to parse hostid: %s", window);
0b843d35 126 goto on_error;
a8b1ac78 127 }
0b843d35
CB
128
129 /* Move beyond \0. */
130 slide++;
0b843d35
CB
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
f37d1c22 148 * is no trailing garbage and if there is, error out.
0b843d35
CB
149 */
150 if (*(slide + strspn(slide, " \t\r\n")) != '\0')
151 goto on_error;
29c98ddd 152
0b843d35
CB
153 /* Mark end of range. */
154 *slide = '\0';
155
156 /* Parse range. */
a8b1ac78 157 if (lxc_safe_ulong(window, &tmp_range) < 0) {
f37d1c22 158 ERROR("Failed to parse id mapping range: %s", window);
0b843d35 159 goto on_error;
a8b1ac78 160 }
0b843d35
CB
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
170on_error:
171 free(dup);
172
173 return ret;
174}
663e9916
CB
175
176bool lxc_config_value_empty(const char *value)
177{
178 if (value && strlen(value) > 0)
179 return false;
180
181 return true;
182}
ce2f5ae8 183
c302b476 184struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail)
ce2f5ae8
CB
185{
186 struct lxc_list *newlist;
187 struct lxc_netdev *netdev = NULL;
ce2f5ae8
CB
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
c302b476
CB
211 if (tail)
212 lxc_list_add_tail(networks, newlist);
213 else
214 lxc_list_add(networks, newlist);
29c98ddd 215
ce2f5ae8
CB
216 return netdev;
217}
1ed6ba91 218
c302b476
CB
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 */
222struct 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
1ed6ba91
CB
246void 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) {
9b0df30f
CB
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
1ed6ba91
CB
266 netdev = it->elem;
267
c302b476 268 TRACE("index: %zd", netdev->idx);
7a582518 269 TRACE("ifindex: %d", netdev->ifindex);
29c98ddd 270
1ed6ba91
CB
271 switch (netdev->type) {
272 case LXC_NET_VETH:
273 TRACE("type: veth");
29c98ddd 274
de4855a8 275 if (netdev->priv.veth_attr.pair[0] != '\0')
9b0df30f
CB
276 TRACE("veth pair: %s",
277 netdev->priv.veth_attr.pair);
29c98ddd 278
8ce727fc
CB
279 if (netdev->priv.veth_attr.veth1[0] != '\0')
280 TRACE("veth1 : %s",
281 netdev->priv.veth_attr.veth1);
29c98ddd 282
d952b351
CB
283 if (netdev->priv.veth_attr.ifindex > 0)
284 TRACE("host side ifindex for veth device: %d",
285 netdev->priv.veth_attr.ifindex);
1ed6ba91
CB
286 break;
287 case LXC_NET_MACVLAN:
288 TRACE("type: macvlan");
29c98ddd 289
9b0df30f
CB
290 if (netdev->priv.macvlan_attr.mode > 0) {
291 char *macvlan_mode;
29c98ddd 292
9b0df30f
CB
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 }
1ed6ba91
CB
299 break;
300 case LXC_NET_VLAN:
301 TRACE("type: vlan");
9b0df30f 302 TRACE("vlan id: %d", netdev->priv.vlan_attr.vid);
1ed6ba91
CB
303 break;
304 case LXC_NET_PHYS:
305 TRACE("type: phys");
29c98ddd 306
307 if (netdev->priv.phys_attr.ifindex > 0)
b809f232
CB
308 TRACE("host side ifindex for phys device: %d",
309 netdev->priv.phys_attr.ifindex);
1ed6ba91
CB
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
9b0df30f
CB
322 if (netdev->type != LXC_NET_EMPTY) {
323 TRACE("flags: %s",
324 netdev->flags == IFF_UP ? "up" : "none");
29c98ddd 325
de4855a8 326 if (netdev->link[0] != '\0')
9b0df30f 327 TRACE("link: %s", netdev->link);
29c98ddd 328
de4855a8 329 if (netdev->name[0] != '\0')
9b0df30f 330 TRACE("name: %s", netdev->name);
29c98ddd 331
9b0df30f
CB
332 if (netdev->hwaddr)
333 TRACE("hwaddr: %s", netdev->hwaddr);
29c98ddd 334
9b0df30f
CB
335 if (netdev->mtu)
336 TRACE("mtu: %s", netdev->mtu);
29c98ddd 337
9b0df30f
CB
338 if (netdev->upscript)
339 TRACE("upscript: %s", netdev->upscript);
29c98ddd 340
9b0df30f
CB
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");
29c98ddd 362
9b0df30f
CB
363 if (netdev->ipv6_gateway) {
364 inet_ntop(AF_INET6, netdev->ipv6_gateway,
365 bufinet6, sizeof(bufinet6));
366 TRACE("ipv6 gateway: %s", bufinet6);
367 }
29c98ddd 368
9b0df30f
CB
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 }
1ed6ba91
CB
376 }
377}
519df1c1 378
e5d2fd7c
CB
379static void lxc_free_netdev(struct lxc_netdev *netdev)
380{
381 struct lxc_list *cur, *next;
382
e5d2fd7c
CB
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
519df1c1
CB
405bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx)
406{
e5d2fd7c 407 struct lxc_list *cur, *next;
519df1c1
CB
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
e5d2fd7c 424 lxc_free_netdev(netdev);
519df1c1
CB
425 free(cur);
426
427 return true;
428}
e5d2fd7c 429
c302b476 430void lxc_free_networks(struct lxc_list *networks)
e5d2fd7c
CB
431{
432 struct lxc_list *cur, *next;
433 struct lxc_netdev *netdev;
434
c302b476 435 lxc_list_for_each_safe(cur, networks, next) {
e5d2fd7c
CB
436 netdev = cur->elem;
437 lxc_free_netdev(netdev);
438 free(cur);
439 }
440
441 /* prevent segfaults */
c302b476 442 lxc_list_init(networks);
e5d2fd7c 443}
9b0df30f
CB
444
445static 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
455int 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
470char *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}
f9373e40
CB
483
484int 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) {
29c98ddd 496 SYSERROR("Failed to duplicate string \"%s\"", value);
f9373e40
CB
497 return -1;
498 }
499
500 free(*conf_item);
501 *conf_item = new_value;
502 return 0;
503}
504
505int 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
515int 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
520int config_ip_prefix(struct in_addr *addr)
521{
522 if (IN_CLASSA(addr->s_addr))
523 return 32 - IN_CLASSA_NSHIFT;
29c98ddd 524
f9373e40
CB
525 if (IN_CLASSB(addr->s_addr))
526 return 32 - IN_CLASSB_NSHIFT;
29c98ddd 527
f9373e40
CB
528 if (IN_CLASSC(addr->s_addr))
529 return 32 - IN_CLASSC_NSHIFT;
530
531 return 0;
532}
533
18cd4b54 534int network_ifname(char *valuep, const char *value, size_t size)
f9373e40 535{
18cd4b54
DJ
536 size_t retlen;
537
538 if (!valuep || !value)
539 return -1;
540
541 retlen = strlcpy(valuep, value, size);
29c98ddd 542 if (retlen >= size)
de4855a8 543 ERROR("Network devie name \"%s\" is too long (>= %zu)", value,
18cd4b54 544 size);
de4855a8 545
de4855a8 546 return 0;
f9373e40
CB
547}
548
29c98ddd 549void rand_complete_hwaddr(char *hwaddr)
f9373e40
CB
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 }
f9373e40
CB
578}
579
ce4be612 580bool lxc_config_net_hwaddr(const char *line)
581{
44047b2b
FA
582 unsigned index;
583 char tmp[7];
ce4be612 584
585 if (strncmp(line, "lxc.net", 7) != 0)
586 return false;
29c98ddd 587
44047b2b 588 if (strncmp(line, "lxc.net.hwaddr", 14) == 0)
ce4be612 589 return true;
29c98ddd 590
44047b2b 591 if (strncmp(line, "lxc.network.hwaddr", 18) == 0)
ce4be612 592 return true;
29c98ddd 593
594 if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 ||
595 sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
44047b2b 596 return strncmp(tmp, "hwaddr", 6) == 0;
ce4be612 597
ce4be612 598 return false;
599}
600
f9373e40 601/*
ae1dc8b4 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.
f9373e40
CB
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 */
609void 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
ae1dc8b4 617 if (!lxc_config_net_hwaddr(line))
f9373e40
CB
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
635bool 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}
953fe44f
CB
650
651int lxc_get_conf_str(char *retv, int inlen, const char *value)
652{
d3bdf12c
CB
653 size_t value_len;
654
953fe44f
CB
655 if (!value)
656 return 0;
d3bdf12c
CB
657
658 value_len = strlen(value);
659 if (retv && inlen >= value_len + 1)
660 memcpy(retv, value, value_len + 1);
953fe44f 661
29c98ddd 662 return value_len;
953fe44f
CB
663}
664
665int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
666{
1396b610
DJ
667 int len;
668 int fulllen = 0;
669
953fe44f
CB
670 if (!retv)
671 inlen = 0;
672 else
673 memset(retv, 0, inlen);
674
1396b610
DJ
675 strprint(retv, inlen, "%d", v);
676
677 return fulllen;
953fe44f 678}
240d4b74 679
885766f5
CB
680int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
681{
1396b610
DJ
682 int len;
683 int fulllen = 0;
684
885766f5
CB
685 if (!retv)
686 inlen = 0;
687 else
688 memset(retv, 0, inlen);
689
1396b610
DJ
690 strprint(retv, inlen, "%zu", v);
691
692 return fulllen;
885766f5
CB
693}
694
2ea479c9
CB
695int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
696{
1396b610
DJ
697 int len;
698 int fulllen = 0;
699
2ea479c9
CB
700 if (!retv)
701 inlen = 0;
702 else
703 memset(retv, 0, inlen);
704
1396b610
DJ
705 strprint(retv, inlen, "%"PRIu64, v);
706
707 return fulllen;
2ea479c9
CB
708}
709
71460831 710bool parse_limit_value(const char **value, rlim_t *res)
240d4b74 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;
71460831 721 *res = strtoull(*value, &endptr, 10);
240d4b74 722 if (errno || !endptr)
723 return false;
29c98ddd 724
240d4b74 725 *value = endptr;
726
727 return true;
728}
28d9e29e
CB
729
730static 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) {
6d1400b5 767 SYSERROR("Failed to send signal to pid %d", (int)pid);
29c98ddd 768 return -1;
28d9e29e
CB
769 }
770
771 return pid;
772}
773
774int 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)
29c98ddd 784 return -1;
28d9e29e 785
71649566
L
786 dup[lastslash - lxcname_or_pid] = '\0';
787 pid = lxc_container_name_to_pid(lastslash + 1, dup);
28d9e29e
CB
788 free(dup);
789 } else {
790 pid = lxc_container_name_to_pid(lxcname_or_pid, lxcpath);
791 }
792
793 if (pid < 0)
29c98ddd 794 return -1;
28d9e29e
CB
795
796 fd = lxc_preserve_ns(pid, namespace);
797 if (fd < 0)
29c98ddd 798 return -1;
28d9e29e
CB
799
800 return fd;
801}
f6e32eb0
CB
802
803struct signame {
804 int num;
805 const char *name;
806};
807
808static 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
887static 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
897static int rt_sig_num(const char *signame)
898{
899 int rtmax = 0, sig_n = 0;
900
29c98ddd 901 if (strncasecmp(signame, "max-", 4) == 0)
f6e32eb0 902 rtmax = 1;
f6e32eb0
CB
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
916int 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);
29c98ddd 926
927 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++)
f6e32eb0
CB
928 if (strcasecmp(signames[n].name, signame) == 0)
929 return signames[n].num;
f6e32eb0
CB
930 }
931
932 return -1;
933}