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