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