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