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