]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/parse.c
Merge pull request #2693 from stgraber/master
[mirror_lxc.git] / src / lxc / parse.c
1 /*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <daniel.lezcano at free.fr>
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #ifndef _GNU_SOURCE
25 #define _GNU_SOURCE 1
26 #endif
27 #include <dirent.h>
28 #include <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <sys/mman.h>
33
34 #include "config.h"
35 #include "log.h"
36 #include "parse.h"
37 #include "utils.h"
38
39 lxc_log_define(parse, lxc);
40
41 void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
42 off_t offset)
43 {
44 void *tmp = NULL, *overlap = NULL;
45
46 /* We establish an anonymous mapping that is one byte larger than the
47 * underlying file. The pages handed to us are zero filled. */
48 tmp = mmap(addr, length + 1, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
49 if (tmp == MAP_FAILED)
50 return tmp;
51
52 /* Now we establish a fixed-address mapping starting at the address we
53 * received from our anonymous mapping and replace all bytes excluding
54 * the additional \0-byte with the file. This allows us to use normal
55 * string-handling functions. */
56 overlap = mmap(tmp, length, prot, MAP_FIXED | flags, fd, offset);
57 if (overlap == MAP_FAILED)
58 munmap(tmp, length + 1);
59
60 return overlap;
61 }
62
63 int lxc_strmunmap(void *addr, size_t length)
64 {
65 return munmap(addr, length + 1);
66 }
67
68 int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback, void *data)
69 {
70 int fd, saved_errno;
71 char *buf, *line;
72 struct stat st;
73 int ret = 0;
74
75 fd = open(file, O_RDONLY | O_CLOEXEC);
76 if (fd < 0) {
77 SYSERROR("Failed to open config file \"%s\"", file);
78 return -1;
79 }
80
81 ret = fstat(fd, &st);
82 if (ret < 0) {
83 SYSERROR("Failed to stat config file \"%s\"", file);
84 goto on_error_fstat;
85 }
86
87 ret = 0;
88 if (st.st_size == 0)
89 goto on_error_fstat;
90
91 ret = -1;
92 buf = lxc_strmmap(NULL, st.st_size, PROT_READ | PROT_WRITE,
93 MAP_PRIVATE | MAP_POPULATE, fd, 0);
94 if (buf == MAP_FAILED) {
95 SYSERROR("Failed to map config file \"%s\"", file);
96 goto on_error;
97 }
98
99 lxc_iterate_parts(line, buf, "\n\0") {
100 ret = callback(line, data);
101 if (ret) {
102 /* Callback rv > 0 means stop here callback rv < 0 means
103 * error.
104 */
105 if (ret < 0)
106 ERROR("Failed to parse config file \"%s\" at "
107 "line \"%s\"",
108 file, line);
109 break;
110 }
111 }
112
113 on_error:
114 if (lxc_strmunmap(buf, st.st_size) < 0) {
115 SYSERROR("Failed to unmap config file \"%s\"", file);
116 if (ret == 0)
117 ret = -1;
118 }
119
120 on_error_fstat:
121 saved_errno = errno;
122 close(fd);
123 errno = saved_errno;
124
125 return ret;
126 }
127
128 int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data)
129 {
130 FILE *f;
131 int err = 0;
132 char *line = NULL;
133 size_t len = 0;
134
135 f = fopen(file, "r");
136 if (!f) {
137 SYSERROR("failed to open %s", file);
138 return -1;
139 }
140
141 while (getline(&line, &len, f) != -1) {
142 err = callback(line, data);
143 if (err) {
144 /* Callback rv > 0 means stop here callback rv < 0 means
145 * error.
146 */
147 if (err < 0)
148 ERROR("Failed to parse config: %s", line);
149 break;
150 }
151 }
152
153 free(line);
154 fclose(f);
155 return err;
156 }