]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile_utils.c
lxc/log: Adds error_log_errno macro
[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
d38dd64a
CB
20#ifndef _GNU_SOURCE
21#define _GNU_SOURCE 1
22#endif
23#include <arpa/inet.h>
f9373e40 24#include <ctype.h>
0b843d35 25#include <stdio.h>
ce2f5ae8 26#include <stdlib.h>
0b843d35
CB
27#include <string.h>
28
663e9916 29#include "conf.h"
d38dd64a 30#include "config.h"
ce2f5ae8
CB
31#include "confile.h"
32#include "confile_utils.h"
33#include "error.h"
ce2f5ae8 34#include "list.h"
28d9e29e
CB
35#include "log.h"
36#include "lxccontainer.h"
7b15813c 37#include "macro.h"
811ef482 38#include "network.h"
f9373e40 39#include "parse.h"
0b843d35
CB
40#include "utils.h"
41
18cd4b54
DJ
42#ifndef HAVE_STRLCPY
43#include "include/strlcpy.h"
44#endif
45
ac2cecc4 46lxc_log_define(confile_utils, lxc);
ce2f5ae8 47
0b843d35
CB
48int 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. */
a8b1ac78 72 if (*slide != 'u' && *slide != 'g') {
f37d1c22 73 ERROR("Invalid id mapping type: %c", *slide);
0b843d35 74 goto on_error;
a8b1ac78
TA
75 }
76
0b843d35
CB
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
f37d1c22 90 /* Mark beginning of nsid. */
0b843d35
CB
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;
f37d1c22 97 /* Mark end of nsid. */
0b843d35
CB
98 *slide = '\0';
99
f37d1c22 100 /* Parse nsid. */
a8b1ac78 101 if (lxc_safe_ulong(window, &tmp_nsid) < 0) {
f37d1c22 102 ERROR("Failed to parse nsid: %s", window);
0b843d35 103 goto on_error;
a8b1ac78 104 }
0b843d35
CB
105
106 /* Move beyond \0. */
107 slide++;
0b843d35
CB
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;
f37d1c22 123 /* Mark end of nsid. */
0b843d35
CB
124 *slide = '\0';
125
126 /* Parse hostid. */
a8b1ac78 127 if (lxc_safe_ulong(window, &tmp_hostid) < 0) {
f37d1c22 128 ERROR("Failed to parse hostid: %s", window);
0b843d35 129 goto on_error;
a8b1ac78 130 }
0b843d35
CB
131
132 /* Move beyond \0. */
133 slide++;
0b843d35
CB
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
f37d1c22 151 * is no trailing garbage and if there is, error out.
0b843d35
CB
152 */
153 if (*(slide + strspn(slide, " \t\r\n")) != '\0')
154 goto on_error;
29c98ddd 155
0b843d35
CB
156 /* Mark end of range. */
157 *slide = '\0';
158
159 /* Parse range. */
a8b1ac78 160 if (lxc_safe_ulong(window, &tmp_range) < 0) {
f37d1c22 161 ERROR("Failed to parse id mapping range: %s", window);
0b843d35 162 goto on_error;
a8b1ac78 163 }
0b843d35
CB
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
173on_error:
174 free(dup);
175
176 return ret;
177}
663e9916
CB
178
179bool lxc_config_value_empty(const char *value)
180{
181 if (value && strlen(value) > 0)
182 return false;
183
184 return true;
185}
ce2f5ae8 186
c302b476 187struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail)
ce2f5ae8
CB
188{
189 struct lxc_list *newlist;
190 struct lxc_netdev *netdev = NULL;
ce2f5ae8
CB
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
c302b476
CB
214 if (tail)
215 lxc_list_add_tail(networks, newlist);
216 else
217 lxc_list_add(networks, newlist);
29c98ddd 218
ce2f5ae8
CB
219 return netdev;
220}
1ed6ba91 221
c302b476
CB
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 */
225struct 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
1ed6ba91
CB
249void 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) {
9b0df30f
CB
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
1ed6ba91
CB
269 netdev = it->elem;
270
c302b476 271 TRACE("index: %zd", netdev->idx);
7a582518 272 TRACE("ifindex: %d", netdev->ifindex);
29c98ddd 273
1ed6ba91
CB
274 switch (netdev->type) {
275 case LXC_NET_VETH:
276 TRACE("type: veth");
29c98ddd 277
de4855a8 278 if (netdev->priv.veth_attr.pair[0] != '\0')
9b0df30f
CB
279 TRACE("veth pair: %s",
280 netdev->priv.veth_attr.pair);
29c98ddd 281
8ce727fc
CB
282 if (netdev->priv.veth_attr.veth1[0] != '\0')
283 TRACE("veth1 : %s",
284 netdev->priv.veth_attr.veth1);
29c98ddd 285
d952b351
CB
286 if (netdev->priv.veth_attr.ifindex > 0)
287 TRACE("host side ifindex for veth device: %d",
288 netdev->priv.veth_attr.ifindex);
1ed6ba91
CB
289 break;
290 case LXC_NET_MACVLAN:
291 TRACE("type: macvlan");
29c98ddd 292
9b0df30f 293 if (netdev->priv.macvlan_attr.mode > 0) {
7b15813c 294 char *mode;
29c98ddd 295
7b15813c 296 mode = lxc_macvlan_flag_to_mode(
9b0df30f
CB
297 netdev->priv.macvlan_attr.mode);
298 TRACE("macvlan mode: %s",
7b15813c 299 mode ? mode : "(invalid mode)");
9b0df30f 300 }
1ed6ba91 301 break;
c9f52382 302 case LXC_NET_IPVLAN:
303 TRACE("type: ipvlan");
304
305 char *mode;
306 mode = lxc_ipvlan_flag_to_mode(netdev->priv.ipvlan_attr.mode);
307 TRACE("ipvlan mode: %s", mode ? mode : "(invalid mode)");
308
309 char *isolation;
310 isolation = lxc_ipvlan_flag_to_isolation(netdev->priv.ipvlan_attr.isolation);
311 TRACE("ipvlan isolation: %s", isolation ? isolation : "(invalid isolation)");
312 break;
1ed6ba91
CB
313 case LXC_NET_VLAN:
314 TRACE("type: vlan");
9b0df30f 315 TRACE("vlan id: %d", netdev->priv.vlan_attr.vid);
1ed6ba91
CB
316 break;
317 case LXC_NET_PHYS:
318 TRACE("type: phys");
29c98ddd 319
320 if (netdev->priv.phys_attr.ifindex > 0)
b809f232
CB
321 TRACE("host side ifindex for phys device: %d",
322 netdev->priv.phys_attr.ifindex);
1ed6ba91
CB
323 break;
324 case LXC_NET_EMPTY:
325 TRACE("type: empty");
326 break;
327 case LXC_NET_NONE:
328 TRACE("type: none");
329 break;
330 default:
d4a7da46 331 ERROR("Invalid network type %d", netdev->type);
1ed6ba91
CB
332 return;
333 }
334
9b0df30f
CB
335 if (netdev->type != LXC_NET_EMPTY) {
336 TRACE("flags: %s",
337 netdev->flags == IFF_UP ? "up" : "none");
29c98ddd 338
de4855a8 339 if (netdev->link[0] != '\0')
9b0df30f 340 TRACE("link: %s", netdev->link);
29c98ddd 341
6509154d 342 /* l2proxy only used when link is specified */
343 if (netdev->link[0] != '\0')
344 TRACE("l2proxy: %s", netdev->l2proxy ? "true" : "false");
345
de4855a8 346 if (netdev->name[0] != '\0')
9b0df30f 347 TRACE("name: %s", netdev->name);
29c98ddd 348
9b0df30f
CB
349 if (netdev->hwaddr)
350 TRACE("hwaddr: %s", netdev->hwaddr);
29c98ddd 351
9b0df30f
CB
352 if (netdev->mtu)
353 TRACE("mtu: %s", netdev->mtu);
29c98ddd 354
9b0df30f
CB
355 if (netdev->upscript)
356 TRACE("upscript: %s", netdev->upscript);
29c98ddd 357
9b0df30f
CB
358 if (netdev->downscript)
359 TRACE("downscript: %s", netdev->downscript);
360
361 TRACE("ipv4 gateway auto: %s",
362 netdev->ipv4_gateway_auto ? "true" : "false");
363
a2f9a670 364 TRACE("ipv4 gateway dev: %s",
365 netdev->ipv4_gateway_dev ? "true" : "false");
366
9b0df30f
CB
367 if (netdev->ipv4_gateway) {
368 inet_ntop(AF_INET, netdev->ipv4_gateway,
369 bufinet4, sizeof(bufinet4));
370 TRACE("ipv4 gateway: %s", bufinet4);
371 }
372
373 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
374 inet4dev = cur->elem;
375 inet_ntop(AF_INET, &inet4dev->addr, bufinet4,
376 sizeof(bufinet4));
377 TRACE("ipv4 addr: %s", bufinet4);
378 }
379
380 TRACE("ipv6 gateway auto: %s",
381 netdev->ipv6_gateway_auto ? "true" : "false");
29c98ddd 382
a2f9a670 383 TRACE("ipv6 gateway dev: %s",
384 netdev->ipv6_gateway_dev ? "true" : "false");
385
9b0df30f
CB
386 if (netdev->ipv6_gateway) {
387 inet_ntop(AF_INET6, netdev->ipv6_gateway,
388 bufinet6, sizeof(bufinet6));
389 TRACE("ipv6 gateway: %s", bufinet6);
390 }
29c98ddd 391
9b0df30f
CB
392 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
393 inet6dev = cur->elem;
394 inet_ntop(AF_INET6, &inet6dev->addr, bufinet6,
395 sizeof(bufinet6));
396 TRACE("ipv6 addr: %s", bufinet6);
397 }
d4a7da46 398
399 if (netdev->type == LXC_NET_VETH) {
400 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
401 inet4dev = cur->elem;
402 if (!inet_ntop(AF_INET, &inet4dev->addr, bufinet4, sizeof(bufinet4))) {
403 ERROR("Invalid ipv4 veth route");
404 return;
405 }
406
407 TRACE("ipv4 veth route: %s/%u", bufinet4, inet4dev->prefix);
408 }
409
410 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
411 inet6dev = cur->elem;
412 if (!inet_ntop(AF_INET6, &inet6dev->addr, bufinet6, sizeof(bufinet6))) {
413 ERROR("Invalid ipv6 veth route");
414 return;
415 }
416
417 TRACE("ipv6 veth route: %s/%u", bufinet6, inet6dev->prefix);
418 }
419 }
9b0df30f 420 }
1ed6ba91
CB
421 }
422}
519df1c1 423
e5d2fd7c
CB
424static void lxc_free_netdev(struct lxc_netdev *netdev)
425{
426 struct lxc_list *cur, *next;
427
e5d2fd7c
CB
428 free(netdev->upscript);
429 free(netdev->downscript);
430 free(netdev->hwaddr);
431 free(netdev->mtu);
432
433 free(netdev->ipv4_gateway);
434 lxc_list_for_each_safe(cur, &netdev->ipv4, next) {
435 lxc_list_del(cur);
436 free(cur->elem);
437 free(cur);
438 }
439
440 free(netdev->ipv6_gateway);
441 lxc_list_for_each_safe(cur, &netdev->ipv6, next) {
442 lxc_list_del(cur);
443 free(cur->elem);
444 free(cur);
445 }
446
d4a7da46 447 if (netdev->type == LXC_NET_VETH) {
448 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv4_routes, next) {
449 lxc_list_del(cur);
450 free(cur->elem);
451 free(cur);
452 }
453
454 lxc_list_for_each_safe(cur, &netdev->priv.veth_attr.ipv6_routes, next) {
455 lxc_list_del(cur);
456 free(cur->elem);
457 free(cur);
458 }
459 }
460
e5d2fd7c
CB
461 free(netdev);
462}
463
519df1c1
CB
464bool lxc_remove_nic_by_idx(struct lxc_conf *conf, unsigned int idx)
465{
e5d2fd7c 466 struct lxc_list *cur, *next;
519df1c1
CB
467 struct lxc_netdev *netdev;
468 bool found = false;
469
470 lxc_list_for_each_safe(cur, &conf->network, next) {
471 netdev = cur->elem;
472 if (netdev->idx != idx)
473 continue;
474
475 lxc_list_del(cur);
476 found = true;
477 break;
478 }
479
480 if (!found)
481 return false;
482
e5d2fd7c 483 lxc_free_netdev(netdev);
519df1c1
CB
484 free(cur);
485
486 return true;
487}
e5d2fd7c 488
c302b476 489void lxc_free_networks(struct lxc_list *networks)
e5d2fd7c
CB
490{
491 struct lxc_list *cur, *next;
492 struct lxc_netdev *netdev;
493
c302b476 494 lxc_list_for_each_safe(cur, networks, next) {
e5d2fd7c
CB
495 netdev = cur->elem;
496 lxc_free_netdev(netdev);
497 free(cur);
498 }
499
500 /* prevent segfaults */
c302b476 501 lxc_list_init(networks);
e5d2fd7c 502}
9b0df30f 503
7b15813c 504static struct lxc_macvlan_mode {
9b0df30f
CB
505 char *name;
506 int mode;
507} macvlan_mode[] = {
508 { "private", MACVLAN_MODE_PRIVATE },
509 { "vepa", MACVLAN_MODE_VEPA },
510 { "bridge", MACVLAN_MODE_BRIDGE },
511 { "passthru", MACVLAN_MODE_PASSTHRU },
512};
513
514int lxc_macvlan_mode_to_flag(int *mode, const char *value)
515{
516 size_t i;
517
518 for (i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
519 if (strcmp(macvlan_mode[i].name, value))
520 continue;
521
522 *mode = macvlan_mode[i].mode;
523 return 0;
524 }
525
526 return -1;
527}
528
529char *lxc_macvlan_flag_to_mode(int mode)
530{
531 size_t i;
532
533 for (i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
b56680fd 534 if (macvlan_mode[i].mode != mode)
9b0df30f
CB
535 continue;
536
537 return macvlan_mode[i].name;
538 }
539
540 return NULL;
541}
f9373e40 542
c9f52382 543static struct lxc_ipvlan_mode {
544 char *name;
545 int mode;
546} ipvlan_mode[] = {
547 { "l3", IPVLAN_MODE_L3 },
548 { "l3s", IPVLAN_MODE_L3S },
549 { "l2", IPVLAN_MODE_L2 },
550};
551
552int lxc_ipvlan_mode_to_flag(int *mode, const char *value)
553{
554 for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
555 if (strcmp(ipvlan_mode[i].name, value) != 0)
556 continue;
557
558 *mode = ipvlan_mode[i].mode;
559 return 0;
560 }
561
562 return -1;
563}
564
565char *lxc_ipvlan_flag_to_mode(int mode)
566{
567 for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
568 if (ipvlan_mode[i].mode != mode)
569 continue;
570
571 return ipvlan_mode[i].name;
572 }
573
574 return NULL;
575}
576
577static struct lxc_ipvlan_isolation {
578 char *name;
579 int flag;
580} ipvlan_isolation[] = {
581 { "bridge", IPVLAN_ISOLATION_BRIDGE },
582 { "private", IPVLAN_ISOLATION_PRIVATE },
583 { "vepa", IPVLAN_ISOLATION_VEPA },
584};
585
586int lxc_ipvlan_isolation_to_flag(int *flag, const char *value)
587{
588 for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
589 if (strcmp(ipvlan_isolation[i].name, value) != 0)
590 continue;
591
592 *flag = ipvlan_isolation[i].flag;
593 return 0;
594 }
595
596 return -1;
597}
598
599char *lxc_ipvlan_flag_to_isolation(int flag)
600{
601 for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
602 if (ipvlan_isolation[i].flag != flag)
603 continue;
604
605 return ipvlan_isolation[i].name;
606 }
607
608 return NULL;
609}
610
f9373e40
CB
611int set_config_string_item(char **conf_item, const char *value)
612{
613 char *new_value;
614
615 if (lxc_config_value_empty(value)) {
616 free(*conf_item);
617 *conf_item = NULL;
618 return 0;
619 }
620
621 new_value = strdup(value);
622 if (!new_value) {
29c98ddd 623 SYSERROR("Failed to duplicate string \"%s\"", value);
f9373e40
CB
624 return -1;
625 }
626
627 free(*conf_item);
628 *conf_item = new_value;
629 return 0;
630}
631
632int set_config_string_item_max(char **conf_item, const char *value, size_t max)
633{
634 if (strlen(value) >= max) {
635 ERROR("%s is too long (>= %lu)", value, (unsigned long)max);
636 return -1;
637 }
638
639 return set_config_string_item(conf_item, value);
640}
641
642int set_config_path_item(char **conf_item, const char *value)
643{
644 return set_config_string_item_max(conf_item, value, PATH_MAX);
645}
646
647int config_ip_prefix(struct in_addr *addr)
648{
649 if (IN_CLASSA(addr->s_addr))
650 return 32 - IN_CLASSA_NSHIFT;
29c98ddd 651
f9373e40
CB
652 if (IN_CLASSB(addr->s_addr))
653 return 32 - IN_CLASSB_NSHIFT;
29c98ddd 654
f9373e40
CB
655 if (IN_CLASSC(addr->s_addr))
656 return 32 - IN_CLASSC_NSHIFT;
657
658 return 0;
659}
660
18cd4b54 661int network_ifname(char *valuep, const char *value, size_t size)
f9373e40 662{
18cd4b54
DJ
663 size_t retlen;
664
665 if (!valuep || !value)
666 return -1;
667
668 retlen = strlcpy(valuep, value, size);
29c98ddd 669 if (retlen >= size)
9005a3ff 670 ERROR("Network device name \"%s\" is too long (>= %zu)", value,
18cd4b54 671 size);
de4855a8 672
de4855a8 673 return 0;
f9373e40
CB
674}
675
3db41a6c
CB
676bool lxc_config_net_is_hwaddr(const char *line)
677{
678 unsigned index;
679 char tmp[7];
680
681 if (strncmp(line, "lxc.net", 7) != 0)
682 return false;
683
684 if (strncmp(line, "lxc.net.hwaddr", 14) == 0)
685 return true;
686
687 if (strncmp(line, "lxc.network.hwaddr", 18) == 0)
688 return true;
689
690 if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 ||
691 sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
692 return strncmp(tmp, "hwaddr", 6) == 0;
693
694 return false;
695}
696
29c98ddd 697void rand_complete_hwaddr(char *hwaddr)
f9373e40
CB
698{
699 const char hex[] = "0123456789abcdef";
700 char *curs = hwaddr;
280cc35f 701#ifdef HAVE_RAND_R
f9373e40
CB
702 unsigned int seed;
703
704 seed = randseed(false);
280cc35f 705#else
706
707 (void)randseed(true);
f9373e40 708#endif
280cc35f 709
f9373e40
CB
710 while (*curs != '\0' && *curs != '\n') {
711 if (*curs == 'x' || *curs == 'X') {
712 if (curs - hwaddr == 1) {
713 /* ensure address is unicast */
714#ifdef HAVE_RAND_R
715 *curs = hex[rand_r(&seed) & 0x0E];
716 } else {
717 *curs = hex[rand_r(&seed) & 0x0F];
718#else
719 *curs = hex[rand() & 0x0E];
720 } else {
721 *curs = hex[rand() & 0x0F];
722#endif
723 }
724 }
725 curs++;
726 }
f9373e40
CB
727}
728
f9373e40
CB
729bool new_hwaddr(char *hwaddr)
730{
731 int ret;
280cc35f 732#ifdef HAVE_RAND_R
733 unsigned int seed;
734
735 seed = randseed(false);
736
737 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand_r(&seed) % 255,
738 rand_r(&seed) % 255, rand_r(&seed) % 255);
739#else
f9373e40
CB
740
741 (void)randseed(true);
742
743 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
744 rand() % 255, rand() % 255);
280cc35f 745#endif
f9373e40 746 if (ret < 0 || ret >= 18) {
280cc35f 747 SYSERROR("Failed to call snprintf()");
f9373e40
CB
748 return false;
749 }
750
751 return true;
752}
953fe44f
CB
753
754int lxc_get_conf_str(char *retv, int inlen, const char *value)
755{
d3bdf12c
CB
756 size_t value_len;
757
953fe44f
CB
758 if (!value)
759 return 0;
d3bdf12c
CB
760
761 value_len = strlen(value);
762 if (retv && inlen >= value_len + 1)
763 memcpy(retv, value, value_len + 1);
953fe44f 764
29c98ddd 765 return value_len;
953fe44f
CB
766}
767
6e54330c
CB
768int lxc_get_conf_bool(struct lxc_conf *c, char *retv, int inlen, bool v)
769{
770 int len;
771 int fulllen = 0;
772
773 if (!retv)
774 inlen = 0;
775 else
776 memset(retv, 0, inlen);
777
778 strprint(retv, inlen, "%d", v);
779
780 return fulllen;
781}
782
953fe44f
CB
783int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
784{
1396b610
DJ
785 int len;
786 int fulllen = 0;
787
953fe44f
CB
788 if (!retv)
789 inlen = 0;
790 else
791 memset(retv, 0, inlen);
792
1396b610
DJ
793 strprint(retv, inlen, "%d", v);
794
795 return fulllen;
953fe44f 796}
f7662514 797
885766f5
CB
798int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
799{
1396b610
DJ
800 int len;
801 int fulllen = 0;
802
885766f5
CB
803 if (!retv)
804 inlen = 0;
805 else
806 memset(retv, 0, inlen);
807
1396b610
DJ
808 strprint(retv, inlen, "%zu", v);
809
810 return fulllen;
885766f5
CB
811}
812
2ea479c9
CB
813int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
814{
1396b610
DJ
815 int len;
816 int fulllen = 0;
817
2ea479c9
CB
818 if (!retv)
819 inlen = 0;
820 else
821 memset(retv, 0, inlen);
822
1396b610
DJ
823 strprint(retv, inlen, "%"PRIu64, v);
824
825 return fulllen;
2ea479c9
CB
826}
827
28d9e29e
CB
828static int lxc_container_name_to_pid(const char *lxcname_or_pid,
829 const char *lxcpath)
830{
831 int ret;
832 signed long int pid;
833 char *err = NULL;
834
835 pid = strtol(lxcname_or_pid, &err, 10);
836 if (*err != '\0' || pid < 1) {
837 struct lxc_container *c;
838
839 c = lxc_container_new(lxcname_or_pid, lxcpath);
840 if (!c) {
841 ERROR("\"%s\" is not a valid pid nor a container name",
842 lxcname_or_pid);
843 return -1;
844 }
845
846 if (!c->may_control(c)) {
847 ERROR("Insufficient privileges to control container "
848 "\"%s\"", c->name);
849 lxc_container_put(c);
850 return -1;
851 }
852
853 pid = c->init_pid(c);
854 if (pid < 1) {
855 ERROR("Container \"%s\" is not running", c->name);
856 lxc_container_put(c);
857 return -1;
858 }
859
860 lxc_container_put(c);
861 }
862
863 ret = kill(pid, 0);
864 if (ret < 0) {
6d1400b5 865 SYSERROR("Failed to send signal to pid %d", (int)pid);
29c98ddd 866 return -1;
28d9e29e
CB
867 }
868
869 return pid;
870}
871
39e6fd36 872int lxc_inherit_namespace(const char *nsfd_path, const char *lxcpath,
28d9e29e
CB
873 const char *namespace)
874{
875 int fd, pid;
876 char *dup, *lastslash;
877
39e6fd36
SH
878 if (nsfd_path[0] == '/') {
879 return open(nsfd_path, O_RDONLY | O_CLOEXEC);
880 }
881
882 lastslash = strrchr(nsfd_path, '/');
28d9e29e 883 if (lastslash) {
39e6fd36 884 dup = strdup(nsfd_path);
28d9e29e 885 if (!dup)
29c98ddd 886 return -1;
28d9e29e 887
39e6fd36 888 dup[lastslash - nsfd_path] = '\0';
71649566 889 pid = lxc_container_name_to_pid(lastslash + 1, dup);
28d9e29e
CB
890 free(dup);
891 } else {
39e6fd36 892 pid = lxc_container_name_to_pid(nsfd_path, lxcpath);
28d9e29e
CB
893 }
894
895 if (pid < 0)
29c98ddd 896 return -1;
28d9e29e
CB
897
898 fd = lxc_preserve_ns(pid, namespace);
899 if (fd < 0)
29c98ddd 900 return -1;
28d9e29e
CB
901
902 return fd;
903}
f6e32eb0
CB
904
905struct signame {
906 int num;
907 const char *name;
908};
909
910static const struct signame signames[] = {
911 { SIGHUP, "HUP" },
912 { SIGINT, "INT" },
913 { SIGQUIT, "QUIT" },
914 { SIGILL, "ILL" },
915 { SIGABRT, "ABRT" },
916 { SIGFPE, "FPE" },
917 { SIGKILL, "KILL" },
918 { SIGSEGV, "SEGV" },
919 { SIGPIPE, "PIPE" },
920 { SIGALRM, "ALRM" },
921 { SIGTERM, "TERM" },
922 { SIGUSR1, "USR1" },
923 { SIGUSR2, "USR2" },
924 { SIGCHLD, "CHLD" },
925 { SIGCONT, "CONT" },
926 { SIGSTOP, "STOP" },
927 { SIGTSTP, "TSTP" },
928 { SIGTTIN, "TTIN" },
929 { SIGTTOU, "TTOU" },
930#ifdef SIGTRAP
931 { SIGTRAP, "TRAP" },
932#endif
933#ifdef SIGIOT
934 { SIGIOT, "IOT" },
935#endif
936#ifdef SIGEMT
937 { SIGEMT, "EMT" },
938#endif
939#ifdef SIGBUS
940 { SIGBUS, "BUS" },
941#endif
942#ifdef SIGSTKFLT
943 { SIGSTKFLT, "STKFLT" },
944#endif
945#ifdef SIGCLD
946 { SIGCLD, "CLD" },
947#endif
948#ifdef SIGURG
949 { SIGURG, "URG" },
950#endif
951#ifdef SIGXCPU
952 { SIGXCPU, "XCPU" },
953#endif
954#ifdef SIGXFSZ
955 { SIGXFSZ, "XFSZ" },
956#endif
957#ifdef SIGVTALRM
958 { SIGVTALRM, "VTALRM" },
959#endif
960#ifdef SIGPROF
961 { SIGPROF, "PROF" },
962#endif
963#ifdef SIGWINCH
964 { SIGWINCH, "WINCH" },
965#endif
966#ifdef SIGIO
967 { SIGIO, "IO" },
968#endif
969#ifdef SIGPOLL
970 { SIGPOLL, "POLL" },
971#endif
972#ifdef SIGINFO
973 { SIGINFO, "INFO" },
974#endif
975#ifdef SIGLOST
976 { SIGLOST, "LOST" },
977#endif
978#ifdef SIGPWR
979 { SIGPWR, "PWR" },
980#endif
981#ifdef SIGUNUSED
982 { SIGUNUSED, "UNUSED" },
983#endif
984#ifdef SIGSYS
985 { SIGSYS, "SYS" },
986#endif
987};
988
989static int sig_num(const char *sig)
990{
991 unsigned int signum;
992
993 if (lxc_safe_uint(sig, &signum) < 0)
994 return -1;
995
996 return signum;
997}
998
999static int rt_sig_num(const char *signame)
1000{
1001 int rtmax = 0, sig_n = 0;
1002
29c98ddd 1003 if (strncasecmp(signame, "max-", 4) == 0)
f6e32eb0 1004 rtmax = 1;
f6e32eb0
CB
1005
1006 signame += 4;
1007 if (!isdigit(*signame))
1008 return -1;
1009
1010 sig_n = sig_num(signame);
1011 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
1012 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
1013 return -1;
1014
1015 return sig_n;
1016}
1017
1018int sig_parse(const char *signame)
1019{
1020 size_t n;
1021
1022 if (isdigit(*signame)) {
1023 return sig_num(signame);
1024 } else if (strncasecmp(signame, "sig", 3) == 0) {
1025 signame += 3;
1026 if (strncasecmp(signame, "rt", 2) == 0)
1027 return rt_sig_num(signame + 2);
29c98ddd 1028
1029 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++)
f6e32eb0
CB
1030 if (strcasecmp(signames[n].name, signame) == 0)
1031 return signames[n].num;
f6e32eb0
CB
1032 }
1033
1034 return -1;
1035}