]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/lxc_config.c
From: Daniel Lezcano <daniel.lezcano@free.fr>
[mirror_lxc.git] / src / lxc / lxc_config.c
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
35 #include <lxc/lxc.h>
36
37 typedef int (*file_cb)(char* buffer, void *data);
38 typedef int (*config_cb)(const char *, char *, struct lxc_conf *);
39
40 static int config_tty(const char *, char *, struct lxc_conf *);
41 static int config_cgroup(const char *, char *, struct lxc_conf *);
42 static int config_mount(const char *, char *, struct lxc_conf *);
43 static int config_rootfs(const char *, char *, struct lxc_conf *);
44 static int config_utsname(const char *, char *, struct lxc_conf *);
45 static int config_network_type(const char *, char *, struct lxc_conf *);
46 static int config_network_flags(const char *, char *, struct lxc_conf *);
47 static int config_network_link(const char *, char *, struct lxc_conf *);
48 static int config_network_name(const char *, char *, struct lxc_conf *);
49 static int config_network_hwaddr(const char *, char *, struct lxc_conf *);
50 static int config_network_ipv4(const char *, char *, struct lxc_conf *);
51 static int config_network_ipv6(const char *, char *, struct lxc_conf *);
52
53 struct config {
54 char *name;
55 config_cb cb;
56 };
57
58 static struct config config[] = {
59
60 { "lxc.tty", config_tty },
61 { "lxc.cgroup", config_cgroup },
62 { "lxc.mount", config_mount },
63 { "lxc.rootfs", config_rootfs },
64 { "lxc.utsname", config_utsname },
65 { "lxc.network.type", config_network_type },
66 { "lxc.network.flags", config_network_flags },
67 { "lxc.network.link", config_network_link },
68 { "lxc.network.name", config_network_name },
69 { "lxc.network.hwaddr", config_network_hwaddr },
70 { "lxc.network.ipv4", config_network_ipv4 },
71 { "lxc.network.ipv6", config_network_ipv6 },
72 };
73
74 static const size_t config_size = sizeof(config)/sizeof(struct config);
75
76 static struct config *getconfig(const char *key)
77 {
78 int i;
79
80 for (i = 0; i < config_size; i++)
81 if (!strncmp(config[i].name, key,
82 strlen(config[i].name)))
83 return &config[i];
84 return NULL;
85 }
86
87 static int is_line_empty(char *line)
88 {
89 int i;
90 size_t len = strlen(line);
91
92 for (i = 0; i < len; i++)
93 if (line[i] != ' ' && line[i] != '\t' &&
94 line[i] != '\n' && line[i] != '\r' &&
95 line[i] != '\f' && line[i] != '\0')
96 return 0;
97 return 1;
98 }
99
100 static int char_left_gc(char *buffer, size_t len)
101 {
102 int i;
103 for (i = 0; i < len; i++) {
104 if (buffer[i] == ' ' ||
105 buffer[i] == '\t')
106 continue;
107 return i;
108 }
109 return 0;
110 }
111
112 static int char_right_gc(char *buffer, size_t len)
113 {
114 int i;
115 for (i = len - 1; i >= 0; i--) {
116 if (buffer[i] == ' ' ||
117 buffer[i] == '\t' ||
118 buffer[i] == '\n' ||
119 buffer[i] == '\0')
120 continue;
121 return i + 1;
122 }
123 return 0;
124 }
125
126 static int config_network_type(const char *key, char *value, struct lxc_conf *lxc_conf)
127 {
128 struct lxc_list *networks = &lxc_conf->networks;
129 struct lxc_network *network;
130 struct lxc_netdev *netdev;
131 struct lxc_list *list;
132 struct lxc_list *ndlist;
133
134 network = malloc(sizeof(*network));
135 if (!network) {
136 lxc_log_syserror("failed to allocate memory");
137 return -1;
138 }
139
140 lxc_list_init(&network->netdev);
141
142 netdev = malloc(sizeof(*netdev));
143 if (!netdev) {
144 lxc_log_syserror("failed to allocate memory");
145 return -1;
146 }
147
148 lxc_list_init(&netdev->ipv4);
149 lxc_list_init(&netdev->ipv6);
150 lxc_list_init(&netdev->route4);
151 lxc_list_init(&netdev->route6);
152
153 ndlist = malloc(sizeof(*ndlist));
154 if (!ndlist) {
155 lxc_log_syserror("failed to allocate memory");
156 return -1;
157 }
158
159 ndlist->elem = netdev;
160
161 lxc_list_add(&network->netdev, ndlist);
162
163 list = malloc(sizeof(*list));
164 if (!list) {
165 lxc_log_syserror("failed to allocate memory");
166 return -1;
167 }
168
169 lxc_list_init(list);
170 list->elem = network;
171
172 lxc_list_add(networks, list);
173
174 if (!strcmp(value, "veth"))
175 network->type = VETH;
176 else if (!strcmp(value, "macvlan"))
177 network->type = MACVLAN;
178 else if (!strcmp(value, "phys"))
179 network->type = PHYS;
180 else if (!strcmp(value, "empty"))
181 network->type = EMPTY;
182 else {
183 lxc_log_error("invalid network type %s", value);
184 return -1;
185 }
186 return 0;
187 }
188
189 static int config_network_flags(const char *key, char *value, struct lxc_conf *lxc_conf)
190 {
191 struct lxc_list *networks = &lxc_conf->networks;
192 struct lxc_network *network;
193 struct lxc_netdev *netdev;
194
195 if (lxc_list_empty(networks)) {
196 lxc_log_error("network is not created for '%s' option", value);
197 return -1;
198 }
199
200 network = lxc_list_first_elem(networks);
201 if (!network) {
202 lxc_log_error("no network defined for '%s' option", value);
203 return -1;
204 }
205
206 netdev = lxc_list_first_elem(&network->netdev);
207 netdev->flags |= IFF_UP;
208 return 0;
209 }
210
211 static int config_network_link(const char *key, char *value, struct lxc_conf *lxc_conf)
212 {
213 struct lxc_list *networks = &lxc_conf->networks;
214 struct lxc_network *network;
215 struct lxc_netdev *netdev;
216
217 if (lxc_list_empty(networks)) {
218 lxc_log_error("network is not created for %s", value);
219 return -1;
220 }
221
222 network = lxc_list_first_elem(networks);
223 if (!network) {
224 lxc_log_error("no network defined for %s", value);
225 return -1;
226 }
227
228 if (strlen(value) > IFNAMSIZ) {
229 lxc_log_error("invalid interface name: %s", value);
230 return -1;
231 }
232
233 netdev = lxc_list_first_elem(&network->netdev);
234 netdev->ifname = strdup(value);
235 return 0;
236 }
237
238 static int config_network_name(const char *key, char *value, struct lxc_conf *lxc_conf)
239 {
240 struct lxc_list *networks = &lxc_conf->networks;
241 struct lxc_network *network;
242 struct lxc_netdev *netdev;
243
244 if (lxc_list_empty(networks)) {
245 lxc_log_error("network is not created for %s", value);
246 return -1;
247 }
248
249 network = lxc_list_first_elem(networks);
250 if (!network) {
251 lxc_log_error("no network defined for %s", value);
252 return -1;
253 }
254
255 if (strlen(value) > IFNAMSIZ) {
256 lxc_log_error("invalid interface name: %s", value);
257 return -1;
258 }
259
260 netdev = lxc_list_first_elem(&network->netdev);
261 netdev->newname = strdup(value);
262 return 0;
263 }
264
265 static int config_network_hwaddr(const char *key, char *value, struct lxc_conf *lxc_conf)
266 {
267 struct lxc_list *networks = &lxc_conf->networks;
268 struct lxc_network *network;
269 struct lxc_netdev *netdev;
270
271 if (lxc_list_empty(networks)) {
272 lxc_log_error("network is not created for %s", value);
273 return -1;
274 }
275
276 network = lxc_list_first_elem(networks);
277 if (!network) {
278 lxc_log_error("no network defined for %s", value);
279 return -1;
280 }
281
282 netdev = lxc_list_first_elem(&network->netdev);
283 netdev->hwaddr = strdup(value);
284 return 0;
285 }
286
287 static int config_network_ipv4(const char *key, char *value, struct lxc_conf *lxc_conf)
288 {
289 struct lxc_list *networks = &lxc_conf->networks;
290 struct lxc_network *network;
291 struct lxc_inetdev *inetdev;
292 struct lxc_netdev *netdev;
293 struct lxc_list *list;
294 char *cursor, *slash, *addr = NULL, *bcast = NULL, *prefix = NULL;
295
296 if (lxc_list_empty(networks)) {
297 lxc_log_error("network is not created for '%s'", value);
298 return -1;
299 }
300
301 network = lxc_list_first_elem(networks);
302 if (!network) {
303 lxc_log_error("no network defined for '%s'", value);
304 return -1;
305 }
306
307 netdev = lxc_list_first_elem(&network->netdev);
308 if (!netdev) {
309 lxc_log_error("no netdev defined for '%s'", value);
310 }
311
312 inetdev = malloc(sizeof(*inetdev));
313 if (!inetdev) {
314 lxc_log_syserror("failed to allocate ipv4 address");
315 return -1;
316 }
317 memset(inetdev, 0, sizeof(*inetdev));
318
319 list = malloc(sizeof(*list));
320 if (!list) {
321 lxc_log_syserror("failed to allocate memory");
322 return -1;
323 }
324
325 lxc_list_init(list);
326 list->elem = inetdev;
327
328 addr = value;
329
330 cursor = strstr(addr, " ");
331 if (cursor) {
332 *cursor = '\0';
333 bcast = cursor + 1;
334 }
335
336 slash = strstr(addr, "/");
337 if (slash) {
338 *slash = '\0';
339 prefix = slash + 1;
340 }
341
342 if (!addr) {
343 lxc_log_error("no address specified");
344 return -1;
345 }
346
347 if (!inet_pton(AF_INET, addr, &inetdev->addr)) {
348 lxc_log_syserror("invalid ipv4 address: %s", value);
349 return -1;
350 }
351
352 if (bcast)
353 if (!inet_pton(AF_INET, bcast, &inetdev->bcast)) {
354 lxc_log_syserror("invalid ipv4 address: %s", value);
355 return -1;
356 }
357
358 if (prefix)
359 inetdev->prefix = atoi(prefix);
360
361 lxc_list_add(&netdev->ipv4, list);
362
363 return 0;
364 }
365
366 static int config_network_ipv6(const char *key, char *value, struct lxc_conf *lxc_conf)
367 {
368 struct lxc_list *networks = &lxc_conf->networks;
369 struct lxc_network *network;
370 struct lxc_netdev *netdev;
371 struct lxc_inet6dev *inet6dev;
372 struct lxc_list *list;
373 char *slash;
374 char *netmask;
375
376 if (lxc_list_empty(networks)) {
377 lxc_log_error("network is not created for %s", value);
378 return -1;
379 }
380
381 network = lxc_list_first_elem(networks);
382 if (!network) {
383 lxc_log_error("no network defined for %s", value);
384 return -1;
385 }
386
387 inet6dev = malloc(sizeof(*inet6dev));
388 if (!inet6dev) {
389 lxc_log_syserror("failed to allocate ipv6 address");
390 return -1;
391 }
392 memset(inet6dev, 0, sizeof(*inet6dev));
393
394 list = malloc(sizeof(*list));
395 if (!list) {
396 lxc_log_syserror("failed to allocate memory");
397 return -1;
398 }
399
400 lxc_list_init(list);
401 list->elem = inet6dev;
402
403 slash = strstr(value, "/");
404 if (slash) {
405 *slash = '\0';
406 netmask = slash + 1;
407 inet6dev->prefix = atoi(netmask);
408 }
409
410 if (!inet_pton(AF_INET6, value, &inet6dev->addr)) {
411 lxc_log_syserror("invalid ipv6 address: %s", value);
412 return -1;
413 }
414
415
416 netdev = lxc_list_first_elem(&network->netdev);
417 lxc_list_add(&netdev->ipv6, list);
418
419 return 0;
420 }
421
422 static int config_tty(const char *key, char *value, struct lxc_conf *lxc_conf)
423 {
424 int nbtty = atoi(value);
425
426 lxc_conf->tty = nbtty;
427
428 return 0;
429 }
430
431 static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf)
432 {
433 char *token = "lxc.cgroup.";
434 char *subkey;
435 struct lxc_list *cglist;
436 struct lxc_cgroup *cgelem;
437
438 subkey = strstr(key, token);
439
440 if (!subkey)
441 return -1;
442
443 if (!strlen(subkey))
444 return -1;
445
446 if (strlen(subkey) == strlen(token))
447 return -1;
448
449 subkey += strlen(token);
450
451 cglist = malloc(sizeof(*cglist));
452 if (!cglist)
453 return -1;
454
455 cgelem = malloc(sizeof(*cgelem));
456 if (!cgelem) {
457 free(cglist);
458 return -1;
459 }
460
461 cgelem->subsystem = strdup(subkey);
462 cgelem->value = strdup(value);
463 cglist->elem = cgelem;
464
465 lxc_list_add_tail(&lxc_conf->cgroup, cglist);
466
467 return 0;
468 }
469
470 static int config_mount(const char *key, char *value, struct lxc_conf *lxc_conf)
471 {
472 if (strlen(value) >= MAXPATHLEN) {
473 lxc_log_error("%s path is too long", value);
474 return -1;
475 }
476
477 lxc_conf->fstab = strdup(value);
478 if (!lxc_conf->fstab) {
479 lxc_log_syserror("failed to duplicate string %s", value);
480 return -1;
481 }
482
483 return 0;
484 }
485
486 static int config_rootfs(const char *key, char *value, struct lxc_conf *lxc_conf)
487 {
488 if (strlen(value) >= MAXPATHLEN) {
489 lxc_log_error("%s path is too long", value);
490 return -1;
491 }
492
493 lxc_conf->rootfs = strdup(value);
494 if (!lxc_conf->rootfs) {
495 lxc_log_syserror("failed to duplicate string %s", value);
496 return -1;
497 }
498
499 return 0;
500 }
501
502 static int config_utsname(const char *key, char *value, struct lxc_conf *lxc_conf)
503 {
504 struct utsname *utsname;
505
506 utsname = malloc(sizeof(*utsname));
507 if (!utsname) {
508 lxc_log_syserror("failed to allocate memory");
509 return -1;
510 }
511
512 if (strlen(value) >= sizeof(utsname->nodename)) {
513 lxc_log_error("node name '%s' is too long",
514 utsname->nodename);
515 return -1;
516 }
517
518 strcpy(utsname->nodename, value);
519 lxc_conf->utsname = utsname;
520
521 return 0;
522 }
523
524 static int parse_line(char *buffer, void *data)
525 {
526 struct config *config;
527 char *dot;
528 char *key;
529 char *value;
530
531 if (is_line_empty(buffer))
532 return 0;
533
534 buffer += char_left_gc(buffer, strlen(buffer));
535 if (buffer[0] == '#')
536 return 0;
537
538 dot = strstr(buffer, "=");
539 if (!dot) {
540 lxc_log_error("invalid configuration line: %s", buffer);
541 return -1;
542 }
543
544 *dot = '\0';
545 value = dot + 1;
546
547 key = buffer;
548 key[char_right_gc(key, strlen(key))] = '\0';
549
550 value += char_left_gc(value, strlen(value));
551 value[char_right_gc(value, strlen(value))] = '\0';
552
553 config = getconfig(key);
554 if (!config) {
555 lxc_log_error("unknow key %s", key);
556 return -1;
557 }
558
559 return config->cb(key, value, data);
560 }
561
562 static int file_for_each_line(const char *file, file_cb callback, void *data)
563 {
564 char buffer[MAXPATHLEN];
565 size_t len = sizeof(buffer);
566 FILE *f;
567 int err = -1;
568
569 f = fopen(file, "r");
570 if (!f) {
571 lxc_log_syserror("failed to open %s", file);
572 return -1;
573 }
574
575 while (fgets(buffer, len, f))
576 if (callback(buffer, data))
577 goto out;
578 err = 0;
579 out:
580 fclose(f);
581 return err;
582 }
583
584 int lxc_config_read(const char *file, struct lxc_conf *conf)
585 {
586 return file_for_each_line(file, parse_line, conf);
587 }
588
589 int lxc_config_init(struct lxc_conf *conf)
590 {
591 conf->rootfs = NULL;
592 conf->fstab = NULL;
593 conf->utsname = NULL;
594 conf->tty = 0;
595 lxc_list_init(&conf->cgroup);
596 lxc_list_init(&conf->networks);
597 return 0;
598 }