]>
Commit | Line | Data |
---|---|---|
c2cc9f0a | 1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
7 | * Daniel Lezcano <dlezcano at fr.ibm.com> | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | */ | |
23 | #include <stdio.h> | |
24 | #include <stdlib.h> | |
25 | #include <string.h> | |
26 | #include <unistd.h> | |
27 | #include <errno.h> | |
28 | #include <sys/types.h> | |
29 | #include <sys/param.h> | |
30 | #include <sys/utsname.h> | |
31 | #include <arpa/inet.h> | |
32 | #include <netinet/in.h> | |
33 | #include <net/if.h> | |
34 | ||
b2718c72 | 35 | #include "parse.h" |
26c39028 | 36 | #include "utils.h" |
c2cc9f0a | 37 | |
36eb9bde | 38 | #include <lxc/log.h> |
00b3c2e2 | 39 | #include <lxc/conf.h> |
36eb9bde CLG |
40 | |
41 | lxc_log_define(lxc_confile, lxc); | |
576f946d | 42 | |
10db618d | 43 | static int config_pts(const char *, char *, struct lxc_conf *); |
b0a33c1e | 44 | static int config_tty(const char *, char *, struct lxc_conf *); |
576f946d | 45 | static int config_cgroup(const char *, char *, struct lxc_conf *); |
46 | static int config_mount(const char *, char *, struct lxc_conf *); | |
47 | static int config_rootfs(const char *, char *, struct lxc_conf *); | |
48 | static int config_utsname(const char *, char *, struct lxc_conf *); | |
49 | static int config_network_type(const char *, char *, struct lxc_conf *); | |
50 | static int config_network_flags(const char *, char *, struct lxc_conf *); | |
51 | static int config_network_link(const char *, char *, struct lxc_conf *); | |
52 | static int config_network_name(const char *, char *, struct lxc_conf *); | |
e892973e DL |
53 | static int config_network_veth_pair(const char *, char *, struct lxc_conf *); |
54 | static int config_network_macvlan_mode(const char *, char *, struct lxc_conf *); | |
576f946d | 55 | static int config_network_hwaddr(const char *, char *, struct lxc_conf *); |
e892973e | 56 | static int config_network_vlan_id(const char *, char *, struct lxc_conf *); |
442cbbe6 | 57 | static int config_network_mtu(const char *, char *, struct lxc_conf *); |
576f946d | 58 | static int config_network_ipv4(const char *, char *, struct lxc_conf *); |
59 | static int config_network_ipv6(const char *, char *, struct lxc_conf *); | |
c2cc9f0a | 60 | |
b2718c72 | 61 | typedef int (*config_cb)(const char *, char *, struct lxc_conf *); |
62 | ||
c2cc9f0a | 63 | struct config { |
64 | char *name; | |
c2cc9f0a | 65 | config_cb cb; |
66 | }; | |
67 | ||
576f946d | 68 | static struct config config[] = { |
69 | ||
e892973e DL |
70 | { "lxc.pts", config_pts }, |
71 | { "lxc.tty", config_tty }, | |
72 | { "lxc.cgroup", config_cgroup }, | |
73 | { "lxc.mount", config_mount }, | |
74 | { "lxc.rootfs", config_rootfs }, | |
75 | { "lxc.utsname", config_utsname }, | |
76 | { "lxc.network.type", config_network_type }, | |
77 | { "lxc.network.flags", config_network_flags }, | |
78 | { "lxc.network.link", config_network_link }, | |
79 | { "lxc.network.name", config_network_name }, | |
80 | { "lxc.network.macvlan.mode", config_network_macvlan_mode }, | |
81 | { "lxc.network.veth.pair", config_network_veth_pair }, | |
82 | { "lxc.network.hwaddr", config_network_hwaddr }, | |
83 | { "lxc.network.mtu", config_network_mtu }, | |
84 | { "lxc.network.vlan.id", config_network_vlan_id }, | |
85 | { "lxc.network.ipv4", config_network_ipv4 }, | |
86 | { "lxc.network.ipv6", config_network_ipv6 }, | |
c2cc9f0a | 87 | }; |
88 | ||
89 | static const size_t config_size = sizeof(config)/sizeof(struct config); | |
90 | ||
91 | static struct config *getconfig(const char *key) | |
92 | { | |
93 | int i; | |
94 | ||
95 | for (i = 0; i < config_size; i++) | |
a871ff6b | 96 | if (!strncmp(config[i].name, key, |
c2cc9f0a | 97 | strlen(config[i].name))) |
98 | return &config[i]; | |
99 | return NULL; | |
100 | } | |
101 | ||
e892973e DL |
102 | static int config_network_type(const char *key, char *value, |
103 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 104 | { |
5f4535a3 | 105 | struct lxc_list *network = &lxc_conf->network; |
c2cc9f0a | 106 | struct lxc_netdev *netdev; |
107 | struct lxc_list *list; | |
c2cc9f0a | 108 | |
109 | netdev = malloc(sizeof(*netdev)); | |
110 | if (!netdev) { | |
36eb9bde | 111 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 112 | return -1; |
113 | } | |
114 | ||
82d5ae15 | 115 | memset(netdev, 0, sizeof(*netdev)); |
c2cc9f0a | 116 | lxc_list_init(&netdev->ipv4); |
117 | lxc_list_init(&netdev->ipv6); | |
c2cc9f0a | 118 | |
119 | list = malloc(sizeof(*list)); | |
120 | if (!list) { | |
36eb9bde | 121 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 122 | return -1; |
123 | } | |
124 | ||
125 | lxc_list_init(list); | |
5f4535a3 | 126 | list->elem = netdev; |
c2cc9f0a | 127 | |
5f4535a3 | 128 | lxc_list_add(network, list); |
a871ff6b | 129 | |
c2cc9f0a | 130 | if (!strcmp(value, "veth")) |
5f4535a3 | 131 | netdev->type = VETH; |
c2cc9f0a | 132 | else if (!strcmp(value, "macvlan")) |
5f4535a3 | 133 | netdev->type = MACVLAN; |
26c39028 JHS |
134 | else if (!strcmp(value, "vlan")) |
135 | netdev->type = VLAN; | |
c2cc9f0a | 136 | else if (!strcmp(value, "phys")) |
5f4535a3 | 137 | netdev->type = PHYS; |
5f58350a | 138 | else if (!strcmp(value, "empty")) |
5f4535a3 | 139 | netdev->type = EMPTY; |
c2cc9f0a | 140 | else { |
36eb9bde | 141 | ERROR("invalid network type %s", value); |
c2cc9f0a | 142 | return -1; |
143 | } | |
144 | return 0; | |
145 | } | |
146 | ||
a059591e DL |
147 | static int config_ip_prefix(struct in_addr *addr) |
148 | { | |
149 | if (IN_CLASSA(addr->s_addr)) | |
150 | return 32 - IN_CLASSA_NSHIFT; | |
151 | if (IN_CLASSB(addr->s_addr)) | |
152 | return 32 - IN_CLASSB_NSHIFT; | |
153 | if (IN_CLASSC(addr->s_addr)) | |
154 | return 32 - IN_CLASSC_NSHIFT; | |
155 | ||
156 | return 0; | |
157 | } | |
158 | ||
16950ecb DL |
159 | static struct lxc_netdev *network_netdev(const char *key, const char *value, |
160 | struct lxc_list *network) | |
c2cc9f0a | 161 | { |
c2cc9f0a | 162 | struct lxc_netdev *netdev; |
163 | ||
5f4535a3 | 164 | if (lxc_list_empty(network)) { |
16950ecb DL |
165 | ERROR("network is not created for '%s' = '%s' option", |
166 | key, value); | |
33c945e0 | 167 | return NULL; |
c2cc9f0a | 168 | } |
169 | ||
5f4535a3 DL |
170 | netdev = lxc_list_first_elem(network); |
171 | if (!netdev) { | |
16950ecb DL |
172 | ERROR("no network device defined for '%s' = '%s' option", |
173 | key, value); | |
33c945e0 | 174 | return NULL; |
c2cc9f0a | 175 | } |
176 | ||
33c945e0 | 177 | return netdev; |
c2cc9f0a | 178 | } |
179 | ||
33c945e0 | 180 | static int network_ifname(char **valuep, char *value) |
c2cc9f0a | 181 | { |
c2cc9f0a | 182 | if (strlen(value) > IFNAMSIZ) { |
36eb9bde | 183 | ERROR("invalid interface name: %s", value); |
c2cc9f0a | 184 | return -1; |
185 | } | |
186 | ||
33c945e0 | 187 | *valuep = strdup(value); |
16950ecb DL |
188 | if (!*valuep) { |
189 | ERROR("failed to dup string '%s'", value); | |
190 | return -1; | |
191 | } | |
33c945e0 | 192 | |
c2cc9f0a | 193 | return 0; |
194 | } | |
195 | ||
e892973e DL |
196 | #ifndef MACVLAN_MODE_PRIVATE |
197 | # define MACVLAN_MODE_PRIVATE 1 | |
198 | #endif | |
199 | ||
200 | #ifndef MACVLAN_MODE_VEPA | |
201 | # define MACVLAN_MODE_VEPA 2 | |
202 | #endif | |
203 | ||
204 | #ifndef MACVLAN_MODE_BRIDGE | |
205 | # define MACVLAN_MODE_BRIDGE 4 | |
206 | #endif | |
207 | ||
208 | static int macvlan_mode(int *valuep, char *value) | |
209 | { | |
210 | struct mc_mode { | |
211 | char *name; | |
212 | int mode; | |
213 | } m[] = { | |
214 | { "private", MACVLAN_MODE_PRIVATE }, | |
215 | { "vepa", MACVLAN_MODE_VEPA }, | |
216 | { "bridge", MACVLAN_MODE_BRIDGE }, | |
217 | }; | |
218 | ||
219 | int i; | |
220 | ||
221 | for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) { | |
222 | if (strcmp(m[i].name, value)) | |
223 | continue; | |
224 | ||
225 | *valuep = m[i].mode; | |
226 | return 0; | |
227 | } | |
228 | ||
229 | return -1; | |
230 | } | |
231 | ||
33c945e0 MT |
232 | static int config_network_flags(const char *key, char *value, |
233 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 234 | { |
c2cc9f0a | 235 | struct lxc_netdev *netdev; |
236 | ||
16950ecb | 237 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 238 | if (!netdev) |
c2cc9f0a | 239 | return -1; |
c2cc9f0a | 240 | |
33c945e0 | 241 | netdev->flags |= IFF_UP; |
c2cc9f0a | 242 | |
33c945e0 MT |
243 | return 0; |
244 | } | |
245 | ||
246 | static int config_network_link(const char *key, char *value, | |
247 | struct lxc_conf *lxc_conf) | |
248 | { | |
249 | struct lxc_netdev *netdev; | |
250 | ||
16950ecb | 251 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 252 | if (!netdev) |
c2cc9f0a | 253 | return -1; |
c2cc9f0a | 254 | |
33c945e0 | 255 | return network_ifname(&netdev->link, value); |
c2cc9f0a | 256 | } |
257 | ||
33c945e0 MT |
258 | static int config_network_name(const char *key, char *value, |
259 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 260 | { |
c2cc9f0a | 261 | struct lxc_netdev *netdev; |
262 | ||
16950ecb | 263 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 264 | if (!netdev) |
c2cc9f0a | 265 | return -1; |
c2cc9f0a | 266 | |
33c945e0 MT |
267 | return network_ifname(&netdev->name, value); |
268 | } | |
269 | ||
e892973e DL |
270 | static int config_network_veth_pair(const char *key, char *value, |
271 | struct lxc_conf *lxc_conf) | |
272 | { | |
273 | struct lxc_netdev *netdev; | |
274 | ||
275 | netdev = network_netdev(key, value, &lxc_conf->network); | |
276 | if (!netdev) | |
277 | return -1; | |
278 | ||
279 | return network_ifname(&netdev->priv.veth_attr.pair, value); | |
280 | } | |
281 | ||
282 | static int config_network_macvlan_mode(const char *key, char *value, | |
283 | struct lxc_conf *lxc_conf) | |
8634bc19 MT |
284 | { |
285 | struct lxc_netdev *netdev; | |
286 | ||
287 | netdev = network_netdev(key, value, &lxc_conf->network); | |
288 | if (!netdev) | |
289 | return -1; | |
290 | ||
e892973e | 291 | return macvlan_mode(&netdev->priv.macvlan_attr.mode, value); |
8634bc19 MT |
292 | } |
293 | ||
33c945e0 MT |
294 | static int config_network_hwaddr(const char *key, char *value, |
295 | struct lxc_conf *lxc_conf) | |
296 | { | |
297 | struct lxc_netdev *netdev; | |
298 | ||
16950ecb | 299 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 300 | if (!netdev) |
c2cc9f0a | 301 | return -1; |
c2cc9f0a | 302 | |
c2cc9f0a | 303 | netdev->hwaddr = strdup(value); |
16950ecb DL |
304 | if (!netdev->hwaddr) { |
305 | SYSERROR("failed to dup string '%s'", value); | |
306 | return -1; | |
307 | } | |
33c945e0 | 308 | |
c2cc9f0a | 309 | return 0; |
310 | } | |
311 | ||
e892973e | 312 | static int config_network_vlan_id(const char *key, char *value, |
26c39028 JHS |
313 | struct lxc_conf *lxc_conf) |
314 | { | |
315 | struct lxc_netdev *netdev; | |
316 | ||
317 | netdev = network_netdev(key, value, &lxc_conf->network); | |
318 | if (!netdev) | |
319 | return -1; | |
320 | ||
f6cc1de1 | 321 | if (get_u16(&netdev->priv.vlan_attr.vid, value, 0)) |
26c39028 JHS |
322 | return -1; |
323 | ||
324 | return 0; | |
325 | } | |
326 | ||
33c945e0 MT |
327 | static int config_network_mtu(const char *key, char *value, |
328 | struct lxc_conf *lxc_conf) | |
442cbbe6 | 329 | { |
442cbbe6 TR |
330 | struct lxc_netdev *netdev; |
331 | ||
16950ecb | 332 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 333 | if (!netdev) |
442cbbe6 | 334 | return -1; |
442cbbe6 | 335 | |
442cbbe6 | 336 | netdev->mtu = strdup(value); |
16950ecb DL |
337 | if (!netdev->mtu) { |
338 | SYSERROR("failed to dup string '%s'", value); | |
339 | return -1; | |
340 | } | |
33c945e0 | 341 | |
442cbbe6 TR |
342 | return 0; |
343 | } | |
344 | ||
33c945e0 MT |
345 | static int config_network_ipv4(const char *key, char *value, |
346 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 347 | { |
c2cc9f0a | 348 | struct lxc_netdev *netdev; |
33c945e0 | 349 | struct lxc_inetdev *inetdev; |
c2cc9f0a | 350 | struct lxc_list *list; |
351 | char *cursor, *slash, *addr = NULL, *bcast = NULL, *prefix = NULL; | |
352 | ||
16950ecb | 353 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 354 | if (!netdev) |
c2cc9f0a | 355 | return -1; |
c2cc9f0a | 356 | |
357 | inetdev = malloc(sizeof(*inetdev)); | |
358 | if (!inetdev) { | |
36eb9bde | 359 | SYSERROR("failed to allocate ipv4 address"); |
c2cc9f0a | 360 | return -1; |
361 | } | |
362 | memset(inetdev, 0, sizeof(*inetdev)); | |
363 | ||
364 | list = malloc(sizeof(*list)); | |
365 | if (!list) { | |
36eb9bde | 366 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 367 | return -1; |
368 | } | |
369 | ||
370 | lxc_list_init(list); | |
371 | list->elem = inetdev; | |
372 | ||
373 | addr = value; | |
374 | ||
375 | cursor = strstr(addr, " "); | |
376 | if (cursor) { | |
377 | *cursor = '\0'; | |
378 | bcast = cursor + 1; | |
379 | } | |
380 | ||
381 | slash = strstr(addr, "/"); | |
382 | if (slash) { | |
383 | *slash = '\0'; | |
384 | prefix = slash + 1; | |
385 | } | |
386 | ||
387 | if (!addr) { | |
36eb9bde | 388 | ERROR("no address specified"); |
c2cc9f0a | 389 | return -1; |
390 | } | |
391 | ||
392 | if (!inet_pton(AF_INET, addr, &inetdev->addr)) { | |
36eb9bde | 393 | SYSERROR("invalid ipv4 address: %s", value); |
c2cc9f0a | 394 | return -1; |
395 | } | |
396 | ||
397 | if (bcast) | |
398 | if (!inet_pton(AF_INET, bcast, &inetdev->bcast)) { | |
36eb9bde | 399 | SYSERROR("invalid ipv4 address: %s", value); |
c2cc9f0a | 400 | return -1; |
401 | } | |
402 | ||
a059591e DL |
403 | /* no prefix specified, determine it from the network class */ |
404 | inetdev->prefix = prefix ? atoi(prefix) : | |
405 | config_ip_prefix(&inetdev->addr); | |
406 | ||
c2cc9f0a | 407 | |
408 | lxc_list_add(&netdev->ipv4, list); | |
409 | ||
410 | return 0; | |
411 | } | |
412 | ||
e892973e DL |
413 | static int config_network_ipv6(const char *key, char *value, |
414 | struct lxc_conf *lxc_conf) | |
c2cc9f0a | 415 | { |
c2cc9f0a | 416 | struct lxc_netdev *netdev; |
417 | struct lxc_inet6dev *inet6dev; | |
418 | struct lxc_list *list; | |
419 | char *slash; | |
420 | char *netmask; | |
421 | ||
16950ecb | 422 | netdev = network_netdev(key, value, &lxc_conf->network); |
33c945e0 | 423 | if (!netdev) |
c2cc9f0a | 424 | return -1; |
c2cc9f0a | 425 | |
426 | inet6dev = malloc(sizeof(*inet6dev)); | |
427 | if (!inet6dev) { | |
36eb9bde | 428 | SYSERROR("failed to allocate ipv6 address"); |
c2cc9f0a | 429 | return -1; |
430 | } | |
431 | memset(inet6dev, 0, sizeof(*inet6dev)); | |
432 | ||
433 | list = malloc(sizeof(*list)); | |
434 | if (!list) { | |
36eb9bde | 435 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 436 | return -1; |
437 | } | |
438 | ||
439 | lxc_list_init(list); | |
440 | list->elem = inet6dev; | |
441 | ||
a059591e | 442 | inet6dev->prefix = 64; |
c2cc9f0a | 443 | slash = strstr(value, "/"); |
444 | if (slash) { | |
445 | *slash = '\0'; | |
446 | netmask = slash + 1; | |
447 | inet6dev->prefix = atoi(netmask); | |
448 | } | |
449 | ||
450 | if (!inet_pton(AF_INET6, value, &inet6dev->addr)) { | |
36eb9bde | 451 | SYSERROR("invalid ipv6 address: %s", value); |
c2cc9f0a | 452 | return -1; |
453 | } | |
454 | ||
c2cc9f0a | 455 | lxc_list_add(&netdev->ipv6, list); |
456 | ||
457 | return 0; | |
458 | } | |
459 | ||
10db618d | 460 | static int config_pts(const char *key, char *value, struct lxc_conf *lxc_conf) |
461 | { | |
462 | int maxpts = atoi(value); | |
463 | ||
464 | lxc_conf->pts = maxpts; | |
465 | ||
466 | return 0; | |
467 | } | |
468 | ||
b0a33c1e | 469 | static int config_tty(const char *key, char *value, struct lxc_conf *lxc_conf) |
470 | { | |
471 | int nbtty = atoi(value); | |
472 | ||
473 | lxc_conf->tty = nbtty; | |
474 | ||
475 | return 0; | |
476 | } | |
477 | ||
576f946d | 478 | static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf) |
479 | { | |
480 | char *token = "lxc.cgroup."; | |
481 | char *subkey; | |
482 | struct lxc_list *cglist; | |
483 | struct lxc_cgroup *cgelem; | |
484 | ||
485 | subkey = strstr(key, token); | |
486 | ||
487 | if (!subkey) | |
488 | return -1; | |
489 | ||
490 | if (!strlen(subkey)) | |
491 | return -1; | |
492 | ||
493 | if (strlen(subkey) == strlen(token)) | |
494 | return -1; | |
a871ff6b | 495 | |
576f946d | 496 | subkey += strlen(token); |
497 | ||
498 | cglist = malloc(sizeof(*cglist)); | |
499 | if (!cglist) | |
500 | return -1; | |
501 | ||
502 | cgelem = malloc(sizeof(*cgelem)); | |
503 | if (!cgelem) { | |
504 | free(cglist); | |
505 | return -1; | |
506 | } | |
507 | ||
508 | cgelem->subsystem = strdup(subkey); | |
509 | cgelem->value = strdup(value); | |
510 | cglist->elem = cgelem; | |
511 | ||
94d12f0a | 512 | lxc_list_add_tail(&lxc_conf->cgroup, cglist); |
576f946d | 513 | |
514 | return 0; | |
515 | } | |
516 | ||
e7938e9e | 517 | static int config_fstab(const char *key, char *value, struct lxc_conf *lxc_conf) |
c2cc9f0a | 518 | { |
519 | if (strlen(value) >= MAXPATHLEN) { | |
36eb9bde | 520 | ERROR("%s path is too long", value); |
c2cc9f0a | 521 | return -1; |
522 | } | |
523 | ||
524 | lxc_conf->fstab = strdup(value); | |
525 | if (!lxc_conf->fstab) { | |
36eb9bde | 526 | SYSERROR("failed to duplicate string %s", value); |
c2cc9f0a | 527 | return -1; |
528 | } | |
529 | ||
530 | return 0; | |
531 | } | |
532 | ||
e7938e9e MN |
533 | static int config_mount(const char *key, char *value, struct lxc_conf *lxc_conf) |
534 | { | |
535 | char *fstab_token = "lxc.mount"; | |
536 | char *token = "lxc.mount.entry"; | |
537 | char *subkey; | |
538 | char *mntelem; | |
539 | struct lxc_list *mntlist; | |
540 | ||
541 | subkey = strstr(key, token); | |
542 | ||
543 | if (!subkey) { | |
544 | subkey = strstr(key, fstab_token); | |
545 | ||
546 | if (!subkey) | |
547 | return -1; | |
548 | ||
549 | return config_fstab(key, value, lxc_conf); | |
550 | } | |
551 | ||
552 | if (!strlen(subkey)) | |
553 | return -1; | |
554 | ||
555 | mntlist = malloc(sizeof(*mntlist)); | |
556 | if (!mntlist) | |
557 | return -1; | |
558 | ||
559 | mntelem = strdup(value); | |
560 | mntlist->elem = mntelem; | |
561 | ||
562 | lxc_list_add_tail(&lxc_conf->mount_list, mntlist); | |
563 | ||
564 | return 0; | |
565 | } | |
566 | ||
576f946d | 567 | static int config_rootfs(const char *key, char *value, struct lxc_conf *lxc_conf) |
c2cc9f0a | 568 | { |
569 | if (strlen(value) >= MAXPATHLEN) { | |
36eb9bde | 570 | ERROR("%s path is too long", value); |
c2cc9f0a | 571 | return -1; |
572 | } | |
573 | ||
eae6543d | 574 | lxc_conf->rootfs = strdup(value); |
575 | if (!lxc_conf->rootfs) { | |
36eb9bde | 576 | SYSERROR("failed to duplicate string %s", value); |
c2cc9f0a | 577 | return -1; |
578 | } | |
579 | ||
580 | return 0; | |
581 | } | |
582 | ||
576f946d | 583 | static int config_utsname(const char *key, char *value, struct lxc_conf *lxc_conf) |
c2cc9f0a | 584 | { |
585 | struct utsname *utsname; | |
586 | ||
587 | utsname = malloc(sizeof(*utsname)); | |
588 | if (!utsname) { | |
36eb9bde | 589 | SYSERROR("failed to allocate memory"); |
c2cc9f0a | 590 | return -1; |
591 | } | |
592 | ||
593 | if (strlen(value) >= sizeof(utsname->nodename)) { | |
36eb9bde | 594 | ERROR("node name '%s' is too long", |
c2cc9f0a | 595 | utsname->nodename); |
596 | return -1; | |
597 | } | |
598 | ||
599 | strcpy(utsname->nodename, value); | |
600 | lxc_conf->utsname = utsname; | |
601 | ||
602 | return 0; | |
603 | } | |
604 | ||
b2718c72 | 605 | static int parse_line(void *buffer, void *data) |
c2cc9f0a | 606 | { |
607 | struct config *config; | |
b2718c72 | 608 | char *line = buffer; |
c2cc9f0a | 609 | char *dot; |
610 | char *key; | |
611 | char *value; | |
612 | ||
b2718c72 | 613 | if (lxc_is_line_empty(line)) |
c2cc9f0a | 614 | return 0; |
615 | ||
b2718c72 | 616 | line += lxc_char_left_gc(line, strlen(line)); |
617 | if (line[0] == '#') | |
c2cc9f0a | 618 | return 0; |
619 | ||
b2718c72 | 620 | dot = strstr(line, "="); |
c2cc9f0a | 621 | if (!dot) { |
36eb9bde | 622 | ERROR("invalid configuration line: %s", line); |
c2cc9f0a | 623 | return -1; |
624 | } | |
a871ff6b | 625 | |
c2cc9f0a | 626 | *dot = '\0'; |
627 | value = dot + 1; | |
628 | ||
b2718c72 | 629 | key = line; |
630 | key[lxc_char_right_gc(key, strlen(key))] = '\0'; | |
c2cc9f0a | 631 | |
b2718c72 | 632 | value += lxc_char_left_gc(value, strlen(value)); |
633 | value[lxc_char_right_gc(value, strlen(value))] = '\0'; | |
c2cc9f0a | 634 | |
635 | config = getconfig(key); | |
636 | if (!config) { | |
36eb9bde | 637 | ERROR("unknow key %s", key); |
c2cc9f0a | 638 | return -1; |
639 | } | |
640 | ||
576f946d | 641 | return config->cb(key, value, data); |
c2cc9f0a | 642 | } |
643 | ||
b2718c72 | 644 | int lxc_config_read(const char *file, struct lxc_conf *conf) |
c2cc9f0a | 645 | { |
646 | char buffer[MAXPATHLEN]; | |
c2cc9f0a | 647 | |
b2718c72 | 648 | return lxc_file_for_each_line(file, parse_line, buffer, |
649 | sizeof(buffer), conf); | |
c2cc9f0a | 650 | } |