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