]> git.proxmox.com Git - mirror_lxc.git/blame - src/lxc/confile_utils.c
confile_utils: cleanup lxc_veth_flag_to_mode()
[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"
28d9e29e
CB
18#include "log.h"
19#include "lxccontainer.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
18cd4b54
DJ
26#ifndef HAVE_STRLCPY
27#include "include/strlcpy.h"
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
c302b476 161struct lxc_netdev *lxc_network_add(struct lxc_list *networks, int idx, bool tail)
ce2f5ae8 162{
1e323af6
CB
163 __do_free struct lxc_list *newlist = NULL;
164 __do_free struct lxc_netdev *netdev = NULL;
ce2f5ae8
CB
165
166 /* network does not exist */
167 netdev = malloc(sizeof(*netdev));
168 if (!netdev)
1e323af6 169 return ret_set_errno(NULL, ENOMEM);
ce2f5ae8
CB
170
171 memset(netdev, 0, sizeof(*netdev));
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 */
179 newlist = malloc(sizeof(*newlist));
1e323af6
CB
180 if (!newlist)
181 return ret_set_errno(NULL, ENOMEM);
ce2f5ae8
CB
182
183 lxc_list_init(newlist);
184 newlist->elem = netdev;
185
c302b476
CB
186 if (tail)
187 lxc_list_add_tail(networks, newlist);
188 else
189 lxc_list_add(networks, newlist);
1e323af6 190 move_ptr(newlist);
29c98ddd 191
1e323af6 192 return move_ptr(netdev);
ce2f5ae8 193}
1ed6ba91 194
c302b476
CB
195/* Takes care of finding the correct netdev struct in the networks list or
196 * allocates a new one if it couldn't be found.
197 */
198struct lxc_netdev *lxc_get_netdev_by_idx(struct lxc_conf *conf,
199 unsigned int idx, bool allocate)
200{
201 struct lxc_netdev *netdev = NULL;
202 struct lxc_list *networks = &conf->network;
203 struct lxc_list *insert = networks;
204
205 /* lookup network */
206 if (!lxc_list_empty(networks)) {
207 lxc_list_for_each(insert, networks) {
208 netdev = insert->elem;
209 if (netdev->idx == idx)
210 return netdev;
211 else if (netdev->idx > idx)
212 break;
213 }
214 }
215
216 if (!allocate)
2a655c0d 217 return ret_set_errno(NULL, EINVAL);
c302b476
CB
218
219 return lxc_network_add(insert, idx, true);
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
227 if ((conf->loglevel != LXC_LOG_LEVEL_TRACE) &&
228 (lxc_log_get_level() != LXC_LOG_LEVEL_TRACE))
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
CB
468 free(cur);
469 return true;
519df1c1
CB
470 }
471
06db6101 472 return false;
519df1c1 473}
e5d2fd7c 474
c302b476 475void lxc_free_networks(struct lxc_list *networks)
e5d2fd7c
CB
476{
477 struct lxc_list *cur, *next;
e5d2fd7c 478
89d66b41
CB
479 lxc_list_for_each_safe (cur, networks, next) {
480 struct lxc_netdev *netdev = cur->elem;
e5d2fd7c
CB
481 netdev = cur->elem;
482 lxc_free_netdev(netdev);
483 free(cur);
484 }
485
486 /* prevent segfaults */
c302b476 487 lxc_list_init(networks);
e5d2fd7c 488}
9b0df30f 489
3f0ed090
TP
490static struct lxc_veth_mode {
491 char *name;
492 int mode;
493} veth_mode[] = {
ecf953c5
CB
494 { "bridge", VETH_MODE_BRIDGE },
495 { "router", VETH_MODE_ROUTER },
3f0ed090
TP
496};
497
498int lxc_veth_mode_to_flag(int *mode, const char *value)
499{
500 for (size_t i = 0; i < sizeof(veth_mode) / sizeof(veth_mode[0]); i++) {
501 if (strcmp(veth_mode[i].name, value) != 0)
502 continue;
503
504 *mode = veth_mode[i].mode;
505 return 0;
506 }
507
9e75cf7a 508 return ret_errno(EINVAL);
3f0ed090
TP
509}
510
756cadb6
CB
511char *lxc_veth_flag_to_mode(int mode)
512{
513 for (size_t i = 0; i < sizeof(veth_mode) / sizeof(veth_mode[0]); i++) {
514 if (veth_mode[i].mode != mode)
515 continue;
516
517 return veth_mode[i].name;
518 }
519
97ea2c2d 520 return ret_set_errno(NULL, EINVAL);
756cadb6
CB
521}
522
7b15813c 523static struct lxc_macvlan_mode {
9b0df30f
CB
524 char *name;
525 int mode;
526} macvlan_mode[] = {
527 { "private", MACVLAN_MODE_PRIVATE },
528 { "vepa", MACVLAN_MODE_VEPA },
529 { "bridge", MACVLAN_MODE_BRIDGE },
530 { "passthru", MACVLAN_MODE_PASSTHRU },
531};
532
533int lxc_macvlan_mode_to_flag(int *mode, const char *value)
534{
535 size_t i;
536
537 for (i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
538 if (strcmp(macvlan_mode[i].name, value))
539 continue;
540
541 *mode = macvlan_mode[i].mode;
542 return 0;
543 }
544
545 return -1;
546}
547
548char *lxc_macvlan_flag_to_mode(int mode)
549{
550 size_t i;
551
552 for (i = 0; i < sizeof(macvlan_mode) / sizeof(macvlan_mode[0]); i++) {
b56680fd 553 if (macvlan_mode[i].mode != mode)
9b0df30f
CB
554 continue;
555
556 return macvlan_mode[i].name;
557 }
558
559 return NULL;
560}
f9373e40 561
c9f52382 562static struct lxc_ipvlan_mode {
563 char *name;
564 int mode;
565} ipvlan_mode[] = {
566 { "l3", IPVLAN_MODE_L3 },
567 { "l3s", IPVLAN_MODE_L3S },
568 { "l2", IPVLAN_MODE_L2 },
569};
570
571int lxc_ipvlan_mode_to_flag(int *mode, const char *value)
572{
573 for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
574 if (strcmp(ipvlan_mode[i].name, value) != 0)
575 continue;
576
577 *mode = ipvlan_mode[i].mode;
578 return 0;
579 }
580
581 return -1;
582}
583
584char *lxc_ipvlan_flag_to_mode(int mode)
585{
586 for (size_t i = 0; i < sizeof(ipvlan_mode) / sizeof(ipvlan_mode[0]); i++) {
587 if (ipvlan_mode[i].mode != mode)
588 continue;
589
590 return ipvlan_mode[i].name;
591 }
592
593 return NULL;
594}
595
596static struct lxc_ipvlan_isolation {
597 char *name;
598 int flag;
599} ipvlan_isolation[] = {
600 { "bridge", IPVLAN_ISOLATION_BRIDGE },
601 { "private", IPVLAN_ISOLATION_PRIVATE },
602 { "vepa", IPVLAN_ISOLATION_VEPA },
603};
604
605int lxc_ipvlan_isolation_to_flag(int *flag, const char *value)
606{
607 for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
608 if (strcmp(ipvlan_isolation[i].name, value) != 0)
609 continue;
610
611 *flag = ipvlan_isolation[i].flag;
612 return 0;
613 }
614
615 return -1;
616}
617
618char *lxc_ipvlan_flag_to_isolation(int flag)
619{
620 for (size_t i = 0; i < sizeof(ipvlan_isolation) / sizeof(ipvlan_isolation[0]); i++) {
621 if (ipvlan_isolation[i].flag != flag)
622 continue;
623
624 return ipvlan_isolation[i].name;
625 }
626
627 return NULL;
628}
629
f9373e40
CB
630int set_config_string_item(char **conf_item, const char *value)
631{
632 char *new_value;
633
634 if (lxc_config_value_empty(value)) {
635 free(*conf_item);
636 *conf_item = NULL;
637 return 0;
638 }
639
640 new_value = strdup(value);
641 if (!new_value) {
29c98ddd 642 SYSERROR("Failed to duplicate string \"%s\"", value);
f9373e40
CB
643 return -1;
644 }
645
646 free(*conf_item);
647 *conf_item = new_value;
648 return 0;
649}
650
651int set_config_string_item_max(char **conf_item, const char *value, size_t max)
652{
653 if (strlen(value) >= max) {
654 ERROR("%s is too long (>= %lu)", value, (unsigned long)max);
655 return -1;
656 }
657
658 return set_config_string_item(conf_item, value);
659}
660
661int set_config_path_item(char **conf_item, const char *value)
662{
663 return set_config_string_item_max(conf_item, value, PATH_MAX);
664}
665
8f818a84
MB
666int set_config_bool_item(bool *conf_item, const char *value, bool empty_conf_action)
667{
668 unsigned int val = 0;
669
670 if (lxc_config_value_empty(value)) {
671 *conf_item = empty_conf_action;
672 return 0;
673 }
674
675 if (lxc_safe_uint(value, &val) < 0)
676 return -EINVAL;
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
687 return -EINVAL;
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)
709 return -1;
710
711 retlen = strlcpy(valuep, value, size);
29c98ddd 712 if (retlen >= size)
9005a3ff 713 ERROR("Network device name \"%s\" is too long (>= %zu)", value,
18cd4b54 714 size);
de4855a8 715
de4855a8 716 return 0;
f9373e40
CB
717}
718
3db41a6c
CB
719bool lxc_config_net_is_hwaddr(const char *line)
720{
721 unsigned index;
722 char tmp[7];
723
724 if (strncmp(line, "lxc.net", 7) != 0)
725 return false;
726
727 if (strncmp(line, "lxc.net.hwaddr", 14) == 0)
728 return true;
729
730 if (strncmp(line, "lxc.network.hwaddr", 18) == 0)
731 return true;
732
733 if (sscanf(line, "lxc.net.%u.%6s", &index, tmp) == 2 ||
734 sscanf(line, "lxc.network.%u.%6s", &index, tmp) == 2)
735 return strncmp(tmp, "hwaddr", 6) == 0;
736
737 return false;
738}
739
29c98ddd 740void rand_complete_hwaddr(char *hwaddr)
f9373e40
CB
741{
742 const char hex[] = "0123456789abcdef";
743 char *curs = hwaddr;
280cc35f 744#ifdef HAVE_RAND_R
f9373e40
CB
745 unsigned int seed;
746
747 seed = randseed(false);
280cc35f 748#else
749
750 (void)randseed(true);
f9373e40 751#endif
280cc35f 752
f9373e40
CB
753 while (*curs != '\0' && *curs != '\n') {
754 if (*curs == 'x' || *curs == 'X') {
755 if (curs - hwaddr == 1) {
756 /* ensure address is unicast */
757#ifdef HAVE_RAND_R
758 *curs = hex[rand_r(&seed) & 0x0E];
759 } else {
760 *curs = hex[rand_r(&seed) & 0x0F];
761#else
762 *curs = hex[rand() & 0x0E];
763 } else {
764 *curs = hex[rand() & 0x0F];
765#endif
766 }
767 }
768 curs++;
769 }
f9373e40
CB
770}
771
f9373e40
CB
772bool new_hwaddr(char *hwaddr)
773{
774 int ret;
280cc35f 775#ifdef HAVE_RAND_R
776 unsigned int seed;
777
778 seed = randseed(false);
779
780 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand_r(&seed) % 255,
781 rand_r(&seed) % 255, rand_r(&seed) % 255);
782#else
f9373e40
CB
783
784 (void)randseed(true);
785
786 ret = snprintf(hwaddr, 18, "00:16:3e:%02x:%02x:%02x", rand() % 255,
787 rand() % 255, rand() % 255);
280cc35f 788#endif
f9373e40 789 if (ret < 0 || ret >= 18) {
280cc35f 790 SYSERROR("Failed to call snprintf()");
f9373e40
CB
791 return false;
792 }
793
794 return true;
795}
953fe44f
CB
796
797int lxc_get_conf_str(char *retv, int inlen, const char *value)
798{
d3bdf12c
CB
799 size_t value_len;
800
953fe44f
CB
801 if (!value)
802 return 0;
d3bdf12c
CB
803
804 value_len = strlen(value);
805 if (retv && inlen >= value_len + 1)
806 memcpy(retv, value, value_len + 1);
953fe44f 807
29c98ddd 808 return value_len;
953fe44f
CB
809}
810
6e54330c
CB
811int lxc_get_conf_bool(struct lxc_conf *c, char *retv, int inlen, bool v)
812{
813 int len;
814 int fulllen = 0;
815
816 if (!retv)
817 inlen = 0;
818 else
819 memset(retv, 0, inlen);
820
821 strprint(retv, inlen, "%d", v);
822
823 return fulllen;
824}
825
953fe44f
CB
826int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v)
827{
1396b610
DJ
828 int len;
829 int fulllen = 0;
830
953fe44f
CB
831 if (!retv)
832 inlen = 0;
833 else
834 memset(retv, 0, inlen);
835
1396b610
DJ
836 strprint(retv, inlen, "%d", v);
837
838 return fulllen;
953fe44f 839}
f7662514 840
885766f5
CB
841int lxc_get_conf_size_t(struct lxc_conf *c, char *retv, int inlen, size_t v)
842{
1396b610
DJ
843 int len;
844 int fulllen = 0;
845
885766f5
CB
846 if (!retv)
847 inlen = 0;
848 else
849 memset(retv, 0, inlen);
850
1396b610
DJ
851 strprint(retv, inlen, "%zu", v);
852
853 return fulllen;
885766f5
CB
854}
855
2ea479c9
CB
856int lxc_get_conf_uint64(struct lxc_conf *c, char *retv, int inlen, uint64_t v)
857{
1396b610
DJ
858 int len;
859 int fulllen = 0;
860
2ea479c9
CB
861 if (!retv)
862 inlen = 0;
863 else
864 memset(retv, 0, inlen);
865
1396b610
DJ
866 strprint(retv, inlen, "%"PRIu64, v);
867
868 return fulllen;
2ea479c9
CB
869}
870
28d9e29e
CB
871static int lxc_container_name_to_pid(const char *lxcname_or_pid,
872 const char *lxcpath)
873{
874 int ret;
875 signed long int pid;
876 char *err = NULL;
877
878 pid = strtol(lxcname_or_pid, &err, 10);
879 if (*err != '\0' || pid < 1) {
880 struct lxc_container *c;
881
882 c = lxc_container_new(lxcname_or_pid, lxcpath);
883 if (!c) {
884 ERROR("\"%s\" is not a valid pid nor a container name",
885 lxcname_or_pid);
886 return -1;
887 }
888
889 if (!c->may_control(c)) {
890 ERROR("Insufficient privileges to control container "
891 "\"%s\"", c->name);
892 lxc_container_put(c);
893 return -1;
894 }
895
896 pid = c->init_pid(c);
897 if (pid < 1) {
898 ERROR("Container \"%s\" is not running", c->name);
899 lxc_container_put(c);
900 return -1;
901 }
902
903 lxc_container_put(c);
904 }
905
906 ret = kill(pid, 0);
907 if (ret < 0) {
6d1400b5 908 SYSERROR("Failed to send signal to pid %d", (int)pid);
29c98ddd 909 return -1;
28d9e29e
CB
910 }
911
912 return pid;
913}
914
39e6fd36 915int lxc_inherit_namespace(const char *nsfd_path, const char *lxcpath,
28d9e29e
CB
916 const char *namespace)
917{
918 int fd, pid;
919 char *dup, *lastslash;
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)
29c98ddd 929 return -1;
28d9e29e 930
39e6fd36 931 dup[lastslash - nsfd_path] = '\0';
71649566 932 pid = lxc_container_name_to_pid(lastslash + 1, dup);
28d9e29e
CB
933 free(dup);
934 } else {
39e6fd36 935 pid = lxc_container_name_to_pid(nsfd_path, lxcpath);
28d9e29e
CB
936 }
937
938 if (pid < 0)
29c98ddd 939 return -1;
28d9e29e
CB
940
941 fd = lxc_preserve_ns(pid, namespace);
942 if (fd < 0)
29c98ddd 943 return -1;
28d9e29e
CB
944
945 return fd;
946}
f6e32eb0
CB
947
948struct signame {
949 int num;
950 const char *name;
951};
952
953static const struct signame signames[] = {
954 { SIGHUP, "HUP" },
955 { SIGINT, "INT" },
956 { SIGQUIT, "QUIT" },
957 { SIGILL, "ILL" },
958 { SIGABRT, "ABRT" },
959 { SIGFPE, "FPE" },
960 { SIGKILL, "KILL" },
961 { SIGSEGV, "SEGV" },
962 { SIGPIPE, "PIPE" },
963 { SIGALRM, "ALRM" },
964 { SIGTERM, "TERM" },
965 { SIGUSR1, "USR1" },
966 { SIGUSR2, "USR2" },
967 { SIGCHLD, "CHLD" },
968 { SIGCONT, "CONT" },
969 { SIGSTOP, "STOP" },
970 { SIGTSTP, "TSTP" },
971 { SIGTTIN, "TTIN" },
972 { SIGTTOU, "TTOU" },
973#ifdef SIGTRAP
974 { SIGTRAP, "TRAP" },
975#endif
976#ifdef SIGIOT
977 { SIGIOT, "IOT" },
978#endif
979#ifdef SIGEMT
980 { SIGEMT, "EMT" },
981#endif
982#ifdef SIGBUS
983 { SIGBUS, "BUS" },
984#endif
985#ifdef SIGSTKFLT
986 { SIGSTKFLT, "STKFLT" },
987#endif
988#ifdef SIGCLD
989 { SIGCLD, "CLD" },
990#endif
991#ifdef SIGURG
992 { SIGURG, "URG" },
993#endif
994#ifdef SIGXCPU
995 { SIGXCPU, "XCPU" },
996#endif
997#ifdef SIGXFSZ
998 { SIGXFSZ, "XFSZ" },
999#endif
1000#ifdef SIGVTALRM
1001 { SIGVTALRM, "VTALRM" },
1002#endif
1003#ifdef SIGPROF
1004 { SIGPROF, "PROF" },
1005#endif
1006#ifdef SIGWINCH
1007 { SIGWINCH, "WINCH" },
1008#endif
1009#ifdef SIGIO
1010 { SIGIO, "IO" },
1011#endif
1012#ifdef SIGPOLL
1013 { SIGPOLL, "POLL" },
1014#endif
1015#ifdef SIGINFO
1016 { SIGINFO, "INFO" },
1017#endif
1018#ifdef SIGLOST
1019 { SIGLOST, "LOST" },
1020#endif
1021#ifdef SIGPWR
1022 { SIGPWR, "PWR" },
1023#endif
1024#ifdef SIGUNUSED
1025 { SIGUNUSED, "UNUSED" },
1026#endif
1027#ifdef SIGSYS
1028 { SIGSYS, "SYS" },
1029#endif
1030};
1031
1032static int sig_num(const char *sig)
1033{
1034 unsigned int signum;
1035
1036 if (lxc_safe_uint(sig, &signum) < 0)
1037 return -1;
1038
1039 return signum;
1040}
1041
1042static int rt_sig_num(const char *signame)
1043{
1044 int rtmax = 0, sig_n = 0;
1045
29c98ddd 1046 if (strncasecmp(signame, "max-", 4) == 0)
f6e32eb0 1047 rtmax = 1;
f6e32eb0
CB
1048
1049 signame += 4;
1050 if (!isdigit(*signame))
1051 return -1;
1052
1053 sig_n = sig_num(signame);
1054 sig_n = rtmax ? SIGRTMAX - sig_n : SIGRTMIN + sig_n;
1055 if (sig_n > SIGRTMAX || sig_n < SIGRTMIN)
1056 return -1;
1057
1058 return sig_n;
1059}
1060
1061int sig_parse(const char *signame)
1062{
1063 size_t n;
1064
1065 if (isdigit(*signame)) {
1066 return sig_num(signame);
1067 } else if (strncasecmp(signame, "sig", 3) == 0) {
1068 signame += 3;
1069 if (strncasecmp(signame, "rt", 2) == 0)
1070 return rt_sig_num(signame + 2);
29c98ddd 1071
1072 for (n = 0; n < sizeof(signames) / sizeof((signames)[0]); n++)
f6e32eb0
CB
1073 if (strcasecmp(signames[n].name, signame) == 0)
1074 return signames[n].num;
f6e32eb0
CB
1075 }
1076
1077 return -1;
1078}