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