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