]> git.proxmox.com Git - mirror_lxc.git/blob - src/lxc/initutils.c
github: Update for main branch
[mirror_lxc.git] / src / lxc / initutils.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 <sys/prctl.h>
28
29 #include "compiler.h"
30 #include "config.h"
31 #include "file_utils.h"
32 #include "initutils.h"
33 #include "log.h"
34 #include "macro.h"
35 #include "memory_utils.h"
36
37 #ifndef HAVE_STRLCPY
38 #include "include/strlcpy.h"
39 #endif
40
41 lxc_log_define(initutils, lxc);
42
43 static char *copy_global_config_value(char *p)
44 {
45 int len = strlen(p);
46 char *retbuf;
47
48 if (len < 1)
49 return NULL;
50
51 if (p[len-1] == '\n') {
52 p[len-1] = '\0';
53 len--;
54 }
55
56 retbuf = malloc(len + 1);
57 if (!retbuf)
58 return NULL;
59
60 (void)strlcpy(retbuf, p, len + 1);
61 return retbuf;
62 }
63
64 const char *lxc_global_config_value(const char *option_name)
65 {
66 static const char * const options[][2] = {
67 { "lxc.bdev.lvm.vg", DEFAULT_VG },
68 { "lxc.bdev.lvm.thin_pool", DEFAULT_THIN_POOL },
69 { "lxc.bdev.zfs.root", DEFAULT_ZFSROOT },
70 { "lxc.bdev.rbd.rbdpool", DEFAULT_RBDPOOL },
71 { "lxc.lxcpath", NULL },
72 { "lxc.default_config", NULL },
73 { "lxc.cgroup.pattern", NULL },
74 { "lxc.cgroup.use", NULL },
75 { NULL, NULL },
76 };
77
78 /* placed in the thread local storage pool for non-bionic targets */
79 #ifdef HAVE_TLS
80 static thread_local const char *values[sizeof(options) / sizeof(options[0])] = {0};
81 #else
82 static const char *values[sizeof(options) / sizeof(options[0])] = {0};
83 #endif
84
85 /* user_config_path is freed as soon as it is used */
86 char *user_config_path = NULL;
87
88 /*
89 * The following variables are freed at bottom unconditionally.
90 * So NULL the value if it is to be returned to the caller
91 */
92 char *user_default_config_path = NULL;
93 char *user_lxc_path = NULL;
94 char *user_cgroup_pattern = NULL;
95
96 if (geteuid() > 0) {
97 const char *user_home = getenv("HOME");
98 if (!user_home)
99 user_home = "/";
100
101 user_config_path = malloc(sizeof(char) * (22 + strlen(user_home)));
102 user_default_config_path = malloc(sizeof(char) * (26 + strlen(user_home)));
103 user_lxc_path = malloc(sizeof(char) * (19 + strlen(user_home)));
104
105 sprintf(user_config_path, "%s/.config/lxc/lxc.conf", user_home);
106 sprintf(user_default_config_path, "%s/.config/lxc/default.conf", user_home);
107 sprintf(user_lxc_path, "%s/.local/share/lxc/", user_home);
108 user_cgroup_pattern = strdup("lxc.payload/%n");
109 }
110 else {
111 user_config_path = strdup(LXC_GLOBAL_CONF);
112 user_default_config_path = strdup(LXC_DEFAULT_CONFIG);
113 user_lxc_path = strdup(LXCPATH);
114 user_cgroup_pattern = strdup(DEFAULT_CGROUP_PATTERN);
115 }
116
117 const char * const (*ptr)[2];
118 size_t i;
119 FILE *fin = NULL;
120
121 for (i = 0, ptr = options; (*ptr)[0]; ptr++, i++) {
122 if (!strcmp(option_name, (*ptr)[0]))
123 break;
124 }
125 if (!(*ptr)[0]) {
126 free(user_config_path);
127 free(user_default_config_path);
128 free(user_lxc_path);
129 free(user_cgroup_pattern);
130 errno = EINVAL;
131 return NULL;
132 }
133
134 if (values[i]) {
135 free(user_config_path);
136 free(user_default_config_path);
137 free(user_lxc_path);
138 free(user_cgroup_pattern);
139 return values[i];
140 }
141
142 fin = fopen_cloexec(user_config_path, "r");
143 free(user_config_path);
144 if (fin) {
145 __do_free char *line = NULL;
146 size_t len = 0;
147 char *slider1, *slider2;
148
149 while (getline(&line, &len, fin) > 0) {
150 if (*line == '#')
151 continue;
152
153 slider1 = strstr(line, option_name);
154 if (!slider1)
155 continue;
156
157 /* see if there was just white space in front
158 * of the option name
159 */
160 for (slider2 = line; slider2 < slider1; slider2++)
161 if (*slider2 != ' ' && *slider2 != '\t')
162 break;
163
164 if (slider2 < slider1)
165 continue;
166
167 slider1 = strchr(slider1, '=');
168 if (!slider1)
169 continue;
170
171 /* see if there was just white space after
172 * the option name
173 */
174 for (slider2 += strlen(option_name); slider2 < slider1;
175 slider2++)
176 if (*slider2 != ' ' && *slider2 != '\t')
177 break;
178
179 if (slider2 < slider1)
180 continue;
181
182 slider1++;
183 while (*slider1 && (*slider1 == ' ' || *slider1 == '\t'))
184 slider1++;
185
186 if (!*slider1)
187 continue;
188
189 if (strcmp(option_name, "lxc.lxcpath") == 0) {
190 free(user_lxc_path);
191 user_lxc_path = copy_global_config_value(slider1);
192 remove_trailing_slashes(user_lxc_path);
193 values[i] = user_lxc_path;
194 user_lxc_path = NULL;
195 goto out;
196 }
197
198 values[i] = copy_global_config_value(slider1);
199 goto out;
200 }
201 }
202
203 /* could not find value, use default */
204 if (strcmp(option_name, "lxc.lxcpath") == 0) {
205 remove_trailing_slashes(user_lxc_path);
206 values[i] = user_lxc_path;
207 user_lxc_path = NULL;
208 }
209 else if (strcmp(option_name, "lxc.default_config") == 0) {
210 values[i] = user_default_config_path;
211 user_default_config_path = NULL;
212 }
213 else if (strcmp(option_name, "lxc.cgroup.pattern") == 0) {
214 values[i] = user_cgroup_pattern;
215 user_cgroup_pattern = NULL;
216 }
217 else
218 values[i] = (*ptr)[1];
219
220 /* special case: if default value is NULL,
221 * and there is no config, don't view that
222 * as an error... */
223 if (!values[i])
224 errno = 0;
225
226 out:
227 if (fin)
228 fclose(fin);
229
230 free(user_cgroup_pattern);
231 free(user_default_config_path);
232 free(user_lxc_path);
233
234 return values[i];
235 }
236
237 /*
238 * Sets the process title to the specified title. Note that this may fail if
239 * the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
240 */
241 int setproctitle(char *title)
242 {
243 __do_fclose FILE *f = NULL;
244 int i, fd, len;
245 char *buf_ptr, *tmp_proctitle;
246 char buf[LXC_LINELEN];
247 int ret = 0;
248 ssize_t bytes_read = 0;
249 static char *proctitle = NULL;
250
251 /*
252 * We don't really need to know all of this stuff, but unfortunately
253 * PR_SET_MM_MAP requires us to set it all at once, so we have to
254 * figure it out anyway.
255 */
256 unsigned long start_data, end_data, start_brk, start_code, end_code,
257 start_stack, arg_start, arg_end, env_start, env_end, brk_val;
258 struct prctl_mm_map prctl_map;
259
260 f = fopen_cloexec("/proc/self/stat", "r");
261 if (!f)
262 return -1;
263
264 fd = fileno(f);
265 if (fd < 0)
266 return -1;
267
268 bytes_read = lxc_read_nointr(fd, buf, sizeof(buf) - 1);
269 if (bytes_read <= 0)
270 return -1;
271
272 buf[bytes_read] = '\0';
273
274 /* Skip the first 25 fields, column 26-28 are start_code, end_code,
275 * and start_stack */
276 buf_ptr = strchr(buf, ' ');
277 for (i = 0; i < 24; i++) {
278 if (!buf_ptr)
279 return -1;
280 buf_ptr = strchr(buf_ptr + 1, ' ');
281 }
282 if (!buf_ptr)
283 return -1;
284
285 i = sscanf(buf_ptr, "%lu %lu %lu", &start_code, &end_code, &start_stack);
286 if (i != 3)
287 return -1;
288
289 /* Skip the next 19 fields, column 45-51 are start_data to arg_end */
290 for (i = 0; i < 19; i++) {
291 if (!buf_ptr)
292 return -1;
293 buf_ptr = strchr(buf_ptr + 1, ' ');
294 }
295
296 if (!buf_ptr)
297 return -1;
298
299 i = sscanf(buf_ptr, "%lu %lu %lu %*u %*u %lu %lu", &start_data,
300 &end_data, &start_brk, &env_start, &env_end);
301 if (i != 5)
302 return -1;
303
304 /* Include the null byte here, because in the calculations below we
305 * want to have room for it. */
306 len = strlen(title) + 1;
307
308 tmp_proctitle = realloc(proctitle, len);
309 if (!tmp_proctitle)
310 return -1;
311
312 proctitle = tmp_proctitle;
313
314 arg_start = (unsigned long)proctitle;
315 arg_end = arg_start + len;
316
317 brk_val = syscall(__NR_brk, 0);
318
319 prctl_map = (struct prctl_mm_map){
320 .start_code = start_code,
321 .end_code = end_code,
322 .start_stack = start_stack,
323 .start_data = start_data,
324 .end_data = end_data,
325 .start_brk = start_brk,
326 .brk = brk_val,
327 .arg_start = arg_start,
328 .arg_end = arg_end,
329 .env_start = env_start,
330 .env_end = env_end,
331 .auxv = NULL,
332 .auxv_size = 0,
333 .exe_fd = -1,
334 };
335
336 ret = prctl(PR_SET_MM, prctl_arg(PR_SET_MM_MAP), prctl_arg(&prctl_map),
337 prctl_arg(sizeof(prctl_map)), prctl_arg(0));
338 if (ret == 0)
339 (void)strlcpy((char *)arg_start, title, len);
340 else
341 SYSWARN("Failed to set cmdline");
342
343 return ret;
344 }