]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile_utils.c
macro: add macvlan properties
[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"
7b15813c 35#include "macro.h"
811ef482 36#include "network.h"
f9373e40 37#include "parse.h"
0b843d35
CB
38#include "utils.h"
39
18cd4b54
DJ
40#ifndef HAVE_STRLCPY
41#include "include/strlcpy.h"
42#endif
43
ac2cecc4 44lxc_log_define(confile_utils, lxc);
ce2f5ae8 45
0b843d35
CB
46int parse_idmaps(const char *idmap, char *type, unsigned long *nsid,
47 unsigned long *hostid, unsigned long *range)
48{
49 int ret = -1;
50 unsigned long tmp_hostid, tmp_nsid, tmp_range;
51 char tmp_type;
52 char *window, *slide;
53 char *dup = NULL;
54
55 /* Duplicate string. */
56 dup = strdup(idmap);
57 if (!dup)
58 goto on_error;
59
60 /* A prototypical idmap entry would be: "u 1000 1000000 65536" */
61
62 /* align */
63 slide = window = dup;
64 /* skip whitespace */
65 slide += strspn(slide, " \t\r");
66 if (slide != window && *slide == '\0')
67 goto on_error;
68
69 /* Validate type. */
a8b1ac78 70 if (*slide != 'u' && *slide != 'g') {
f37d1c22 71 ERROR("Invalid id mapping type: %c", *slide);
0b843d35 72 goto on_error;
a8b1ac78
TA
73 }
74
0b843d35
CB
75 /* Assign type. */
76 tmp_type = *slide;
77
78 /* move beyond type */
79 slide++;
80 /* align */
81 window = slide;
82 /* Validate that only whitespace follows. */
83 slide += strspn(slide, " \t\r");
84 /* There must be whitespace. */
85 if (slide == window)
86 goto on_error;
87
f37d1c22 88 /* Mark beginning of nsid. */
0b843d35
CB
89 window = slide;
90 /* Validate that non-whitespace follows. */
91 slide += strcspn(slide, " \t\r");
92 /* There must be non-whitespace. */
93 if (slide == window || *slide == '\0')
94 goto on_error;
f37d1c22 95 /* Mark end of nsid. */
0b843d35
CB
96 *slide = '\0';
97
f37d1c22 98 /* Parse nsid. */
a8b1ac78 99 if (lxc_safe_ulong(window, &tmp_nsid) < 0) {
f37d1c22 100 ERROR("Failed to parse nsid: %s", window);
0b843d35 101 goto on_error;
a8b1ac78 102 }
0b843d35
CB
103
104 /* Move beyond \0. */
105 slide++;
0b843d35
CB
106 /* Validate that only whitespace follows. */
107 slide += strspn(slide, " \t\r");
108 /* If there was only one whitespace then we whiped it with our \0 above.
109 * So only ensure that we're not at the end of the string.
110 */
111 if (*slide == '\0')
112 goto on_error;
113
114 /* Mark beginning of hostid. */
115 window = slide;
116 /* Validate that non-whitespace follows. */
117 slide += strcspn(slide, " \t\r");
118 /* There must be non-whitespace. */
119 if (slide == window || *slide == '\0')
120 goto on_error;
f37d1c22 121 /* Mark end of nsid. */
0b843d35
CB
122 *slide = '\0';
123
124 /* Parse hostid. */
a8b1ac78 125 if (lxc_safe_ulong(window, &tmp_hostid) < 0) {
f37d1c22 126 ERROR("Failed to parse hostid: %s", window);
0b843d35 127 goto on_error;
a8b1ac78 128 }
0b843d35
CB
129
130 /* Move beyond \0. */
131 slide++;
0b843d35
CB
132 /* Validate that only whitespace follows. */
133 slide += strspn(slide, " \t\r");
134 /* If there was only one whitespace then we whiped it with our \0 above.
135 * So only ensure that we're not at the end of the string.
136 */
137 if (*slide == '\0')
138 goto on_error;
139
140 /* Mark beginning of range. */
141 window = slide;
142 /* Validate that non-whitespace follows. */
143 slide += strcspn(slide, " \t\r");
144 /* There must be non-whitespace. */
145 if (slide == window)
146 goto on_error;
147
148 /* The range is the last valid entry we expect. So make sure that there
f37d1c22 149 * is no trailing garbage and if there is, error out.
0b843d35
CB
150 */
151 if (*(slide + strspn(slide, " \t\r\n")) != '\0')
152 goto on_error;
29c98ddd 153
0b843d35
CB
154 /* Mark end of range. */
155 *slide = '\0';
156
157 /* Parse range. */
a8b1ac78 158 if (lxc_safe_ulong(window, &tmp_range) < 0) {
f37d1c22 159 ERROR("Failed to parse id mapping range: %s", window);
0b843d35 160 goto on_error;
a8b1ac78 161 }
0b843d35
CB
162
163 *type = tmp_type;
164 *nsid = tmp_nsid;
165 *hostid = tmp_hostid;
166 *range = tmp_range;
167
168 /* Yay, we survived. */
169 ret = 0;
170
171on_error:
172 free(dup);
173
174 return ret;
175}
663e9916
CB
176
177bool lxc_config_value_empty(const char *value)
178{
179 if (value && strlen(value) > 0)
180 return false;
181
182 return true;
183}
ce2f5ae8 184
c302b476 185struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail)
ce2f5ae8
CB
186{
187 struct lxc_list *newlist;
188 struct lxc_netdev *netdev = NULL;
ce2f5ae8
CB
189
190 /* network does not exist */
191 netdev = malloc(sizeof(*netdev));
192 if (!netdev)
193 return NULL;
194
195 memset(netdev, 0, sizeof(*netdev));
196 lxc_list_init(&netdev->ipv4);
197 lxc_list_init(&netdev->ipv6);
198
199 /* give network a unique index */
200 netdev->idx = idx;
201
202 /* prepare new list */
203 newlist = malloc(sizeof(*newlist));
204 if (!newlist) {
205 free(netdev);
206 return NULL;
207 }
208
209 lxc_list_init(newlist);
210 newlist->elem = netdev;
211
c302b476
CB
212 if (tail)
213 lxc_list_add_tail(networks, newlist);
214 else
215 lxc_list_add(networks, newlist);
29c98ddd 216
ce2f5ae8
CB
217 return netdev;
218}
1ed6ba91 219
c302b476
CB
220/* Takes care of finding the correct netdev struct in the networks list or
221 * allocates a new one if it couldn't be found.
222 */
223struct lxc_netdev *lxc_get_netdev_by_idx(struct lxc_conf *conf,
224 unsigned int idx, bool allocate)
225{
226 struct lxc_netdev *netdev = NULL;
227 struct lxc_list *networks = &conf->network;
228 struct lxc_list *insert = networks;
229
230 /* lookup network */
231 if (!lxc_list_empty(networks)) {
232 lxc_list_for_each(insert, networks) {
233 netdev = insert->elem;
234 if (netdev->idx == idx)
235 return netdev;
236 else if (netdev->idx > idx)
237 break;
238 }
239 }
240
241 if (!allocate)
242 return NULL;
243
244 return lxc_network_add(insert, idx, true);
245}
246
1ed6ba91
CB
247void lxc_log_configured_netdevs(const struct lxc_conf *conf)
248{
249 struct lxc_netdev *netdev;
250 struct lxc_list *it = (struct lxc_list *)&conf->network;;
251
252 if ((conf->loglevel != LXC_LOG_LEVEL_TRACE) &&
253 (lxc_log_get_level() != LXC_LOG_LEVEL_TRACE))
254 return;
255
256 if (lxc_list_empty(it)) {
257 TRACE("container has no networks configured");
258 return;
259 }
260
261 lxc_list_for_each(it, &conf->network) {
9b0df30f
CB
262 struct lxc_list *cur, *next;
263 struct lxc_inetdev *inet4dev;
264 struct lxc_inet6dev *inet6dev;
265 char bufinet4[INET_ADDRSTRLEN], bufinet6[INET6_ADDRSTRLEN];
266
1ed6ba91
CB
267 netdev = it->elem;
268
c302b476 269 TRACE("index: %zd", netdev->idx);
7a582518 270 TRACE("ifindex: %d", netdev->ifindex);
29c98ddd 271
1ed6ba91
CB
272 switch (netdev->type) {
273 case LXC_NET_VETH:
274 TRACE("type: veth");
29c98ddd 275
de4855a8 276 if (netdev->priv.veth_attr.pair[0] != '\0')
9b0df30f
CB
277 TRACE("veth pair: %s",
278 netdev->priv.veth_attr.pair);
29c98ddd 279
8ce727fc
CB
280 if (netdev->priv.veth_attr.veth1[0] != '\0')
281 TRACE("veth1 : %s",
282 netdev->priv.veth_attr.veth1);
29c98ddd 283
d952b351
CB
284 if (netdev->priv.veth_attr.ifindex > 0)
285 TRACE("host side ifindex for veth device: %d",
286 netdev->priv.veth_attr.ifindex);
1ed6ba91
CB
287 break;
288 case LXC_NET_MACVLAN:
289 TRACE("type: macvlan");
29c98ddd 290
9b0df30f 291 if (netdev->priv.macvlan_attr.mode > 0) {
7b15813c 292 char *mode;
29c98ddd 293
7b15813c 294 mode = lxc_macvlan_flag_to_mode(
9b0df30f
CB
295 netdev->priv.macvlan_attr.mode);
296 TRACE("macvlan mode: %s",
7b15813c 297 mode ? mode : "(invalid mode)");
9b0df30f 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 444
7b15813c 445static struct lxc_macvlan_mode {
9b0df30f
CB
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;
280cc35f 553#ifdef HAVE_RAND_R
f9373e40
CB
554 unsigned int seed;
555
556 seed = randseed(false);
280cc35f 557#else
558
559 (void)randseed(true);
f9373e40 560#endif
280cc35f 561
f9373e40
CB
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 }
f9373e40
CB
579}
580
ce4be612 581bool lxc_config_net_hwaddr(const char *line)
582{
44047b2b
FA
583 unsigned index;
584 char tmp[7];
ce4be612 585
586 if (strncmp(line, "lxc.net", 7) != 0)
587 return false;
29c98ddd 588
44047b2b 589 if (strncmp(line, "lxc.net.hwaddr", 14) == 0)
ce4be612 590 return true;
29c98ddd 591
44047b2b 592 if (strncmp(line, "lxc.network.hwaddr", 18) == 0)
ce4be612 593 return true;
29c98ddd 594
595 if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 ||
596 sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
44047b2b 597 return strncmp(tmp, "hwaddr", 6) == 0;
ce4be612 598
ce4be612 599 return false;
600}
601
f9373e40 602/*
ae1dc8b4 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.
f9373e40
CB
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 */
610void 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
ae1dc8b4 618 if (!lxc_config_net_hwaddr(line))
f9373e40
CB
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
636bool new_hwaddr(char *hwaddr)
637{
638 int ret;
280cc35f 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
f9373e40
CB
647
648 (void)randseed(true);
649
650 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
651 rand() % 255, rand() % 255);
280cc35f 652#endif
f9373e40 653 if (ret < 0 || ret >= 18) {
280cc35f 654 SYSERROR("Failed to call snprintf()");
f9373e40
CB
655 return false;
656 }
657
658 return true;
659}
953fe44f
CB
660
661int lxc_get_conf_str(char *retv, int inlen, const char *value)
662{
d3bdf12c
CB
663 size_t value_len;
664
953fe44f
CB
665 if (!value)
666 return 0;
d3bdf12c
CB
667
668 value_len = strlen(value);
669 if (retv && inlen >= value_len + 1)
670 memcpy(retv, value, value_len + 1);
953fe44f 671
29c98ddd 672 return value_len;
953fe44f
CB
673}
674
675int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
676{
1396b610
DJ
677 int len;
678 int fulllen = 0;
679
953fe44f
CB
680 if (!retv)
681 inlen = 0;
682 else
683 memset(retv, 0, inlen);
684
1396b610
DJ
685 strprint(retv, inlen, "%d", v);
686
687 return fulllen;
953fe44f 688}
240d4b74 689
885766f5
CB
690int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
691{
1396b610
DJ
692 int len;
693 int fulllen = 0;
694
885766f5
CB
695 if (!retv)
696 inlen = 0;
697 else
698 memset(retv, 0, inlen);
699
1396b610
DJ
700 strprint(retv, inlen, "%zu", v);
701
702 return fulllen;
885766f5
CB
703}
704
2ea479c9
CB
705int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
706{
1396b610
DJ
707 int len;
708 int fulllen = 0;
709
2ea479c9
CB
710 if (!retv)
711 inlen = 0;
712 else
713 memset(retv, 0, inlen);
714
1396b610
DJ
715 strprint(retv, inlen, "%"PRIu64, v);
716
717 return fulllen;
2ea479c9
CB
718}
719
71460831 720bool parse_limit_value(const char **value, rlim_t *res)
240d4b74 721{
722 char *endptr = NULL;
723
724 if (strncmp(*value, "unlimited", sizeof("unlimited") - 1) == 0) {
725 *res = RLIM_INFINITY;
726 *value += sizeof("unlimited") - 1;
727 return true;
728 }
729
730 errno = 0;
71460831 731 *res = strtoull(*value, &endptr, 10);
240d4b74 732 if (errno || !endptr)
733 return false;
29c98ddd 734
240d4b74 735 *value = endptr;
736
737 return true;
738}
28d9e29e
CB
739
740static int lxc_container_name_to_pid(const char *lxcname_or_pid,
741 const char *lxcpath)
742{
743 int ret;
744 signed long int pid;
745 char *err = NULL;
746
747 pid = strtol(lxcname_or_pid, &err, 10);
748 if (*err != '\0' || pid < 1) {
749 struct lxc_container *c;
750
751 c = lxc_container_new(lxcname_or_pid, lxcpath);
752 if (!c) {
753 ERROR("\"%s\" is not a valid pid nor a container name",
754 lxcname_or_pid);
755 return -1;
756 }
757
758 if (!c->may_control(c)) {
759 ERROR("Insufficient privileges to control container "
760 "\"%s\"", c->name);
761 lxc_container_put(c);
762 return -1;
763 }
764
765 pid = c->init_pid(c);
766 if (pid < 1) {
767 ERROR("Container \"%s\" is not running", c->name);
768 lxc_container_put(c);
769 return -1;
770 }
771
772 lxc_container_put(c);
773 }
774
775 ret = kill(pid, 0);
776 if (ret < 0) {
6d1400b5 777 SYSERROR("Failed to send signal to pid %d", (int)pid);
29c98ddd 778 return -1;
28d9e29e
CB
779 }
780
781 return pid;
782}
783
784int lxc_inherit_namespace(const char *lxcname_or_pid, const char *lxcpath,
785 const char *namespace)
786{
787 int fd, pid;
788 char *dup, *lastslash;
789
790 lastslash = strrchr(lxcname_or_pid, '/');
791 if (lastslash) {
792 dup = strdup(lxcname_or_pid);
793 if (!dup)
29c98ddd 794 return -1;
28d9e29e 795
71649566
L
796 dup[lastslash - lxcname_or_pid] = '\0';
797 pid = lxc_container_name_to_pid(lastslash + 1, dup);
28d9e29e
CB
798 free(dup);
799 } else {
800 pid = lxc_container_name_to_pid(lxcname_or_pid, lxcpath);
801 }
802
803 if (pid < 0)
29c98ddd 804 return -1;
28d9e29e
CB
805
806 fd = lxc_preserve_ns(pid, namespace);
807 if (fd < 0)
29c98ddd 808 return -1;
28d9e29e
CB
809
810 return fd;
811}
f6e32eb0
CB
812
813struct signame {
814 int num;
815 const char *name;
816};
817
818static const struct signame signames[] = {
819 { SIGHUP, "HUP" },
820 { SIGINT, "INT" },
821 { SIGQUIT, "QUIT" },
822 { SIGILL, "ILL" },
823 { SIGABRT, "ABRT" },
824 { SIGFPE, "FPE" },
825 { SIGKILL, "KILL" },
826 { SIGSEGV, "SEGV" },
827 { SIGPIPE, "PIPE" },
828 { SIGALRM, "ALRM" },
829 { SIGTERM, "TERM" },
830 { SIGUSR1, "USR1" },
831 { SIGUSR2, "USR2" },
832 { SIGCHLD, "CHLD" },
833 { SIGCONT, "CONT" },
834 { SIGSTOP, "STOP" },
835 { SIGTSTP, "TSTP" },
836 { SIGTTIN, "TTIN" },
837 { SIGTTOU, "TTOU" },
838#ifdef SIGTRAP
839 { SIGTRAP, "TRAP" },
840#endif
841#ifdef SIGIOT
842 { SIGIOT, "IOT" },
843#endif
844#ifdef SIGEMT
845 { SIGEMT, "EMT" },
846#endif
847#ifdef SIGBUS
848 { SIGBUS, "BUS" },
849#endif
850#ifdef SIGSTKFLT
851 { SIGSTKFLT, "STKFLT" },
852#endif
853#ifdef SIGCLD
854 { SIGCLD, "CLD" },
855#endif
856#ifdef SIGURG
857 { SIGURG, "URG" },
858#endif
859#ifdef SIGXCPU
860 { SIGXCPU, "XCPU" },
861#endif
862#ifdef SIGXFSZ
863 { SIGXFSZ, "XFSZ" },
864#endif
865#ifdef SIGVTALRM
866 { SIGVTALRM, "VTALRM" },
867#endif
868#ifdef SIGPROF
869 { SIGPROF, "PROF" },
870#endif
871#ifdef SIGWINCH
872 { SIGWINCH, "WINCH" },
873#endif
874#ifdef SIGIO
875 { SIGIO, "IO" },
876#endif
877#ifdef SIGPOLL
878 { SIGPOLL, "POLL" },
879#endif
880#ifdef SIGINFO
881 { SIGINFO, "INFO" },
882#endif
883#ifdef SIGLOST
884 { SIGLOST, "LOST" },
885#endif
886#ifdef SIGPWR
887 { SIGPWR, "PWR" },
888#endif
889#ifdef SIGUNUSED
890 { SIGUNUSED, "UNUSED" },
891#endif
892#ifdef SIGSYS
893 { SIGSYS, "SYS" },
894#endif
895};
896
897static int sig_num(const char *sig)
898{
899 unsigned int signum;
900
901 if (lxc_safe_uint(sig, &signum) < 0)
902 return -1;
903
904 return signum;
905}
906
907static int rt_sig_num(const char *signame)
908{
909 int rtmax = 0, sig_n = 0;
910
29c98ddd 911 if (strncasecmp(signame, "max-", 4) == 0)
f6e32eb0 912 rtmax = 1;
f6e32eb0
CB
913
914 signame += 4;
915 if (!isdigit(*signame))
916 return -1;
917
918 sig_n = sig_num(signame);
919 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
920 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
921 return -1;
922
923 return sig_n;
924}
925
926int sig_parse(const char *signame)
927{
928 size_t n;
929
930 if (isdigit(*signame)) {
931 return sig_num(signame);
932 } else if (strncasecmp(signame, "sig", 3) == 0) {
933 signame += 3;
934 if (strncasecmp(signame, "rt", 2) == 0)
935 return rt_sig_num(signame + 2);
29c98ddd 936
937 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++)
f6e32eb0
CB
938 if (strcasecmp(signames[n].name, signame) == 0)
939 return signames[n].num;
f6e32eb0
CB
940 }
941
942 return -1;
943}