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