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