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