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