]>
Commit | Line | Data |
---|---|---|
cb698658 | 1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
9afe19d6 | 7 | * Daniel Lezcano <daniel.lezcano at free.fr> |
cb698658 | 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 | |
250b1eec | 21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
cb698658 | 22 | */ |
9994d140 | 23 | |
d38dd64a CB |
24 | #ifndef _GNU_SOURCE |
25 | #define _GNU_SOURCE 1 | |
26 | #endif | |
cb698658 | 27 | #include <dirent.h> |
9994d140 | 28 | #include <errno.h> |
d38dd64a | 29 | #include <stdio.h> |
9994d140 CB |
30 | #include <stdlib.h> |
31 | #include <string.h> | |
32 | #include <sys/mman.h> | |
7c4d9466 | 33 | #include <sys/sendfile.h> |
cb698658 | 34 | |
d38dd64a | 35 | #include "config.h" |
7c4d9466 | 36 | #include "file_utils.h" |
d38dd64a | 37 | #include "log.h" |
7c4d9466 | 38 | #include "macro.h" |
cb698658 | 39 | #include "parse.h" |
7c4d9466 | 40 | #include "syscall_wrappers.h" |
6a44839f | 41 | #include "utils.h" |
36eb9bde | 42 | |
ac2cecc4 | 43 | lxc_log_define(parse, lxc); |
cb698658 | 44 | |
9994d140 CB |
45 | void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd, |
46 | off_t offset) | |
47 | { | |
48 | void *tmp = NULL, *overlap = NULL; | |
49 | ||
50 | /* We establish an anonymous mapping that is one byte larger than the | |
51 | * underlying file. The pages handed to us are zero filled. */ | |
52 | tmp = mmap(addr, length + 1, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
53 | if (tmp == MAP_FAILED) | |
54 | return tmp; | |
55 | ||
56 | /* Now we establish a fixed-address mapping starting at the address we | |
57 | * received from our anonymous mapping and replace all bytes excluding | |
58 | * the additional \0-byte with the file. This allows us to use normal | |
59 | * string-handling functions. */ | |
60 | overlap = mmap(tmp, length, prot, MAP_FIXED | flags, fd, offset); | |
61 | if (overlap == MAP_FAILED) | |
62 | munmap(tmp, length + 1); | |
63 | ||
64 | return overlap; | |
65 | } | |
66 | ||
67 | int lxc_strmunmap(void *addr, size_t length) | |
68 | { | |
69 | return munmap(addr, length + 1); | |
70 | } | |
71 | ||
872c1f04 | 72 | int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback, void *data) |
9994d140 | 73 | { |
7c4d9466 | 74 | int saved_errno; |
9c3f0f02 | 75 | ssize_t ret = -1, bytes_sent; |
7c4d9466 CB |
76 | char *line; |
77 | int fd = -1, memfd = -1; | |
78 | char *buf = NULL; | |
79 | ||
80 | memfd = memfd_create(".lxc_config_file", MFD_CLOEXEC); | |
81 | if (memfd < 0) { | |
82 | char template[] = P_tmpdir "/.lxc_config_file_XXXXXX"; | |
83 | ||
84 | if (errno != ENOSYS) { | |
85 | SYSERROR("Failed to create memory file"); | |
86 | goto on_error; | |
87 | } | |
88 | ||
89 | TRACE("Failed to create in-memory file. Falling back to " | |
90 | "temporary file"); | |
91 | memfd = lxc_make_tmpfile(template, true); | |
92 | if (memfd < 0) { | |
93 | SYSERROR("Failed to create temporary file \"%s\"", template); | |
94 | goto on_error; | |
95 | } | |
96 | } | |
9994d140 CB |
97 | |
98 | fd = open(file, O_RDONLY | O_CLOEXEC); | |
872c1f04 | 99 | if (fd < 0) { |
7c4d9466 | 100 | SYSERROR("Failed to open file \"%s\"", file); |
22c8ac96 | 101 | goto on_error; |
872c1f04 | 102 | } |
9994d140 | 103 | |
7c4d9466 CB |
104 | /* sendfile() handles up to 2GB. No config file should be that big. */ |
105 | bytes_sent = lxc_sendfile_nointr(memfd, fd, NULL, LXC_SENDFILE_MAX); | |
106 | if (bytes_sent < 0) { | |
107 | SYSERROR("Failed to sendfile \"%s\"", file); | |
108 | goto on_error; | |
109 | } | |
110 | ||
111 | ret = lxc_write_nointr(memfd, "\0", 1); | |
9994d140 | 112 | if (ret < 0) { |
7c4d9466 CB |
113 | SYSERROR("Failed to append zero byte"); |
114 | goto on_error; | |
9994d140 | 115 | } |
7c4d9466 | 116 | bytes_sent++; |
9994d140 | 117 | |
7c4d9466 CB |
118 | ret = lseek(memfd, 0, SEEK_SET); |
119 | if (ret < 0) { | |
120 | SYSERROR("Failed to lseek"); | |
121 | goto on_error; | |
122 | } | |
9994d140 | 123 | |
872c1f04 | 124 | ret = -1; |
7c4d9466 CB |
125 | buf = mmap(NULL, bytes_sent, PROT_READ | PROT_WRITE, |
126 | MAP_SHARED | MAP_POPULATE, memfd, 0); | |
9994d140 | 127 | if (buf == MAP_FAILED) { |
7c4d9466 CB |
128 | buf = NULL; |
129 | SYSERROR("Failed to mmap"); | |
872c1f04 | 130 | goto on_error; |
9994d140 CB |
131 | } |
132 | ||
7c4d9466 | 133 | ret = 0; |
8336d7be | 134 | lxc_iterate_parts(line, buf, "\r\n\0") { |
9994d140 CB |
135 | ret = callback(line, data); |
136 | if (ret) { | |
137 | /* Callback rv > 0 means stop here callback rv < 0 means | |
138 | * error. | |
139 | */ | |
140 | if (ret < 0) | |
872c1f04 | 141 | ERROR("Failed to parse config file \"%s\" at " |
7c4d9466 | 142 | "line \"%s\"", file, line); |
9994d140 CB |
143 | break; |
144 | } | |
145 | } | |
146 | ||
872c1f04 | 147 | on_error: |
7c4d9466 CB |
148 | saved_errno = errno; |
149 | if (fd >= 0) | |
150 | close(fd); | |
151 | if (memfd >= 0) | |
152 | close(memfd); | |
153 | if (buf && munmap(buf, bytes_sent)) { | |
154 | SYSERROR("Failed to unmap"); | |
576fb366 CB |
155 | if (ret == 0) |
156 | ret = -1; | |
157 | } | |
872c1f04 CB |
158 | errno = saved_errno; |
159 | ||
44dec7ef | 160 | return ret; |
9994d140 CB |
161 | } |
162 | ||
2382ecff | 163 | int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data) |
cb698658 | 164 | { |
165 | FILE *f; | |
4fcc0112 | 166 | int err = 0; |
2382ecff CC |
167 | char *line = NULL; |
168 | size_t len = 0; | |
cb698658 | 169 | |
170 | f = fopen(file, "r"); | |
171 | if (!f) { | |
f6665080 | 172 | SYSERROR("Failed to open \"%s\"", file); |
cb698658 | 173 | return -1; |
174 | } | |
175 | ||
2382ecff CC |
176 | while (getline(&line, &len, f) != -1) { |
177 | err = callback(line, data); | |
48e2f384 | 178 | if (err) { |
1a0e70ac CB |
179 | /* Callback rv > 0 means stop here callback rv < 0 means |
180 | * error. | |
181 | */ | |
8daccdb4 | 182 | if (err < 0) |
f6665080 | 183 | ERROR("Failed to parse config: \"%s\"", line); |
2382ecff | 184 | break; |
48e2f384 | 185 | } |
cb698658 | 186 | } |
2382ecff | 187 | |
f10fad2f | 188 | free(line); |
cb698658 | 189 | fclose(f); |
190 | return err; | |
191 | } |