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