]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/parse.c
Merge pull request #3966 from denisfa/improve-bash-completion-ext
[mirror_lxc.git] / src / lxc / parse.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include "config.h"
4
5 #include <dirent.h>
6 #include <errno.h>
7 #include <limits.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/mman.h>
12 #include <sys/sendfile.h>
13
14 #include "file_utils.h"
15 #include "log.h"
16 #include "macro.h"
17 #include "parse.h"
18 #include "syscall_wrappers.h"
19 #include "utils.h"
20
21 lxc_log_define(parse, lxc);
22
23 void *lxc_strmmap(void *addr, size_t length, int prot, int flags, int fd,
24 off_t offset)
25 {
26 void *tmp = NULL, *overlap = NULL;
27
28 /* We establish an anonymous mapping that is one byte larger than the
29 * underlying file. The pages handed to us are zero filled. */
30 tmp = mmap(addr, length + 1, PROT_READ, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
31 if (tmp == MAP_FAILED)
32 return tmp;
33
34 /* Now we establish a fixed-address mapping starting at the address we
35 * received from our anonymous mapping and replace all bytes excluding
36 * the additional \0-byte with the file. This allows us to use normal
37 * string-handling functions. */
38 overlap = mmap(tmp, length, prot, MAP_FIXED | flags, fd, offset);
39 if (overlap == MAP_FAILED)
40 munmap(tmp, length + 1);
41
42 return overlap;
43 }
44
45 int lxc_strmunmap(void *addr, size_t length)
46 {
47 return munmap(addr, length + 1);
48 }
49
50 int lxc_file_for_each_line_mmap(const char *file, lxc_file_cb callback, void *data)
51 {
52 __do_close int fd = -EBADF, memfd = -EBADF;
53 ssize_t ret = -1;
54 char *buf = NULL;
55 struct stat st = {};
56 ssize_t bytes;
57 char *line;
58
59 memfd = memfd_create(".lxc_config_file", MFD_CLOEXEC);
60 if (memfd < 0) {
61 char template[] = P_tmpdir "/.lxc_config_file_XXXXXX";
62
63 if (errno != ENOSYS) {
64 SYSERROR("Failed to create memory file");
65 goto on_error;
66 }
67
68 TRACE("Failed to create in-memory file. Falling back to temporary file");
69 memfd = lxc_make_tmpfile(template, true);
70 if (memfd < 0) {
71 SYSERROR("Failed to create temporary file \"%s\"", template);
72 goto on_error;
73 }
74 }
75
76 fd = open(file, O_RDONLY | O_CLOEXEC);
77 if (fd < 0) {
78 SYSERROR("Failed to open file \"%s\"", file);
79 goto on_error;
80 }
81
82 ret = fstat(fd, &st);
83 if (ret) {
84 SYSERROR("Failed to stat file \"%s\"", file);
85 goto on_error;
86 }
87
88 if (st.st_size > INT_MAX) {
89 SYSERROR("Excessively large config file \"%s\"", file);
90 goto on_error;
91 }
92
93
94 bytes = __fd_to_fd(fd, memfd);
95 if (bytes < 0) {
96 SYSERROR("Failed to copy config file \"%s\"", file);
97 goto on_error;
98 }
99
100 ret = lxc_write_nointr(memfd, "\0", 1);
101 if (ret < 0) {
102 SYSERROR("Failed to append zero byte");
103 goto on_error;
104 }
105 bytes++;
106
107 ret = lseek(memfd, 0, SEEK_SET);
108 if (ret < 0) {
109 SYSERROR("Failed to lseek");
110 goto on_error;
111 }
112
113 ret = -1;
114 buf = mmap(NULL, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_POPULATE, memfd, 0);
115 if (buf == MAP_FAILED) {
116 buf = NULL;
117 SYSERROR("Failed to mmap");
118 goto on_error;
119 }
120
121 ret = 0;
122 lxc_iterate_parts(line, buf, "\r\n\0") {
123 ret = callback(line, data);
124 if (ret) {
125 /* Callback rv > 0 means stop here callback rv < 0 means
126 * error.
127 */
128 if (ret < 0)
129 ERROR("Failed to parse config file \"%s\" at line \"%s\"",
130 file, line);
131 break;
132 }
133 }
134
135 on_error:
136 if (buf && munmap(buf, bytes)) {
137 SYSERROR("Failed to unmap");
138 if (ret == 0)
139 ret = -1;
140 }
141
142 return ret;
143 }
144
145 int lxc_file_for_each_line(const char *file, lxc_file_cb callback, void *data)
146 {
147 __do_fclose FILE *f = NULL;
148 __do_free char *line = NULL;
149 int err = 0;
150 size_t len = 0;
151
152 f = fopen(file, "re");
153 if (!f) {
154 SYSERROR("Failed to open \"%s\"", file);
155 return -1;
156 }
157
158 while (getline(&line, &len, f) != -1) {
159 err = callback(line, data);
160 if (err) {
161 /* Callback rv > 0 means stop here callback rv < 0 means
162 * error.
163 */
164 if (err < 0)
165 ERROR("Failed to parse config: \"%s\"", line);
166 break;
167 }
168 }
169
170 return err;
171 }